aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Utils.ts3
-rw-r--r--src/client/documents/Documents.ts30
-rw-r--r--src/client/util/CurrentUserUtils.ts13
-rw-r--r--src/client/util/DocumentManager.ts44
-rw-r--r--src/client/util/DragManager.ts15
-rw-r--r--src/client/util/DropConverter.ts9
-rw-r--r--src/client/util/HypothesisUtils.ts18
-rw-r--r--src/client/util/Import & Export/DirectoryImportBox.tsx2
-rw-r--r--src/client/util/LinkFollower.ts9
-rw-r--r--src/client/util/LinkManager.ts12
-rw-r--r--src/client/util/Scripting.ts2
-rw-r--r--src/client/util/SearchUtil.ts155
-rw-r--r--src/client/util/SettingsManager.tsx5
-rw-r--r--src/client/views/DashboardView.tsx12
-rw-r--r--src/client/views/DocComponent.tsx141
-rw-r--r--src/client/views/DocumentButtonBar.tsx2
-rw-r--r--src/client/views/DocumentDecorations.tsx31
-rw-r--r--src/client/views/GestureOverlay.tsx3
-rw-r--r--src/client/views/InkControlPtHandles.tsx12
-rw-r--r--src/client/views/InkStrokeProperties.ts3
-rw-r--r--src/client/views/InkTangentHandles.tsx4
-rw-r--r--src/client/views/InkingStroke.tsx19
-rw-r--r--src/client/views/LightboxView.tsx7
-rw-r--r--src/client/views/MainView.tsx86
-rw-r--r--src/client/views/MarqueeAnnotator.tsx15
-rw-r--r--src/client/views/OverlayView.tsx3
-rw-r--r--src/client/views/PreviewCursor.tsx25
-rw-r--r--src/client/views/PropertiesButtons.tsx46
-rw-r--r--src/client/views/PropertiesDocContextSelector.tsx2
-rw-r--r--src/client/views/PropertiesView.tsx8
-rw-r--r--src/client/views/ScriptBox.tsx5
-rw-r--r--src/client/views/SidebarAnnos.tsx9
-rw-r--r--src/client/views/StyleProvider.tsx90
-rw-r--r--src/client/views/TemplateMenu.tsx9
-rw-r--r--src/client/views/collections/CollectionCalendarView.tsx4
-rw-r--r--src/client/views/collections/CollectionCarousel3DView.tsx10
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx13
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx20
-rw-r--r--src/client/views/collections/CollectionMasonryViewFieldRow.tsx2
-rw-r--r--src/client/views/collections/CollectionMenu.tsx28
-rw-r--r--src/client/views/collections/CollectionNoteTakingView.tsx36
-rw-r--r--src/client/views/collections/CollectionNoteTakingViewColumn.tsx6
-rw-r--r--src/client/views/collections/CollectionPileView.tsx2
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx30
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx53
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx2
-rw-r--r--src/client/views/collections/CollectionSubView.tsx33
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx7
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx21
-rw-r--r--src/client/views/collections/CollectionView.tsx19
-rw-r--r--src/client/views/collections/TabDocView.tsx19
-rw-r--r--src/client/views/collections/TreeView.tsx103
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx6
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx6
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx192
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx7
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx6
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx23
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx13
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx14
-rw-r--r--src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx6
-rw-r--r--src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx6
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.scss3
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx17
-rw-r--r--src/client/views/collections/collectionSchema/SchemaRowBox.tsx30
-rw-r--r--src/client/views/collections/collectionSchema/SchemaTableCell.tsx7
-rw-r--r--src/client/views/global/globalScripts.ts4
-rw-r--r--src/client/views/linking/LinkMenu.tsx2
-rw-r--r--src/client/views/linking/LinkMenuGroup.tsx12
-rw-r--r--src/client/views/linking/LinkMenuItem.tsx4
-rw-r--r--src/client/views/linking/LinkPopup.tsx6
-rw-r--r--src/client/views/newlightbox/NewLightboxView.tsx5
-rw-r--r--src/client/views/nodes/AudioBox.tsx23
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx30
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx13
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx49
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx35
-rw-r--r--src/client/views/nodes/DocumentIcon.tsx4
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx44
-rw-r--r--src/client/views/nodes/DocumentView.tsx1371
-rw-r--r--src/client/views/nodes/EquationBox.tsx6
-rw-r--r--src/client/views/nodes/FieldView.tsx113
-rw-r--r--src/client/views/nodes/FontIconBox/FontIconBox.tsx2
-rw-r--r--src/client/views/nodes/FunctionPlotBox.tsx2
-rw-r--r--src/client/views/nodes/ImageBox.tsx35
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx2
-rw-r--r--src/client/views/nodes/KeyValuePair.tsx68
-rw-r--r--src/client/views/nodes/LabelBox.scss5
-rw-r--r--src/client/views/nodes/LabelBox.tsx27
-rw-r--r--src/client/views/nodes/LinkAnchorBox.tsx21
-rw-r--r--src/client/views/nodes/LinkBox.tsx16
-rw-r--r--src/client/views/nodes/LinkDescriptionPopup.tsx31
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx13
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx20
-rw-r--r--src/client/views/nodes/MapBox/MapBox2.tsx12
-rw-r--r--src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx5
-rw-r--r--src/client/views/nodes/MapBox/MapPushpinBox.tsx4
-rw-r--r--src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx30
-rw-r--r--src/client/views/nodes/PDFBox.tsx39
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingBox.tsx12
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx13
-rw-r--r--src/client/views/nodes/ScriptingBox.tsx8
-rw-r--r--src/client/views/nodes/VideoBox.tsx57
-rw-r--r--src/client/views/nodes/WebBox.tsx55
-rw-r--r--src/client/views/nodes/calendarBox/CalendarBox.tsx10
-rw-r--r--src/client/views/nodes/formattedText/DashDocView.tsx8
-rw-r--r--src/client/views/nodes/formattedText/DashFieldView.tsx2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx72
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx3
-rw-r--r--src/client/views/nodes/importBox/ImportElementBox.tsx6
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx49
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx13
-rw-r--r--src/client/views/pdf/PDFViewer.scss1
-rw-r--r--src/client/views/pdf/PDFViewer.tsx29
-rw-r--r--src/client/views/search/SearchBox.tsx8
-rw-r--r--src/client/views/selectedDoc/SelectedDocView.tsx8
-rw-r--r--src/client/views/topbar/TopBar.tsx6
-rw-r--r--src/client/views/webcam/DashWebRTCVideo.tsx16
-rw-r--r--src/fields/Doc.ts57
-rw-r--r--src/mobile/MobileInterface.tsx3
-rw-r--r--src/server/DashStats.ts4
122 files changed, 1918 insertions, 2170 deletions
diff --git a/src/Utils.ts b/src/Utils.ts
index b5c218e01..852083834 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -7,6 +7,7 @@ import { Socket } from '../node_modules/socket.io/dist/index';
import { DocumentType } from './client/documents/DocumentTypes';
import { Colors } from './client/views/global/globalEnums';
import { Message } from './server/Message';
+import { DocumentView } from './client/views/nodes/DocumentView';
export namespace Utils {
export let CLICK_TIME = 300;
@@ -583,7 +584,7 @@ export function returnEmptyDoclist() {
return [] as any[];
}
-export let emptyPath = [];
+export let emptyPath: DocumentView[] = [];
export function emptyFunction() {
return undefined;
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 92a9ddfe8..a0870ba43 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -205,6 +205,7 @@ export class DocumentOptions {
type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection
_type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection
title?: STRt = new StrInfo('title of document', true);
+ title_custom?: BOOLt = new BoolInfo('whether title is a default or has been intentionally set');
caption?: RichTextField;
author?: string; // STRt = new StrInfo('creator of document'); // bcz: don't change this. Otherwise, the userDoc's field Infos will have a FieldInfo assigned to its author field which will render it unreadable
author_date?: DATEt = new DateInfo('date the document was created', true);
@@ -239,16 +240,15 @@ export class DocumentOptions {
layout_hideResizeHandles?: BOOLt = new BoolInfo('whether to hide the resize handles when selected');
layout_hideLinkButton?: BOOLt = new BoolInfo('whether the blue link counter button should be hidden');
layout_hideDecorationTitle?: BOOLt = new BoolInfo('whether to suppress the document decortations title when selected');
+ _layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown');
layout_borderRounding?: string;
_layout_nativeDimEditable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false);
_layout_reflowVertical?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers');
_layout_reflowHorizontal?: BOOLt = new BoolInfo('whether a doc with a native size can be horizonally resized, causing some form of reflow');
layout_boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow
- layout_maxAutoHeight?: NUMt = new NumInfo('maximum height for newly created (eg, from pasting) text documents', false);
_layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents');
_layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document', false);
_layout_currentTimecode?: NUMt = new NumInfo('the current timecode of a time-based document (e.g., current time of a video) value is in seconds', false);
- _layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown');
_layout_centered?: BOOLt = new BoolInfo('whether text should be vertically centered in Doc');
_layout_fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)');
_layout_fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content');
@@ -259,6 +259,7 @@ export class DocumentOptions {
_layout_showCaption?: string; // which field to display in the caption area. leave empty to have no caption
_chromeHidden?: BOOLt = new BoolInfo('whether the editing chrome for a document is hidden');
+ hideClickBehaviors?: BOOLt = new BoolInfo('whether to hide click behaviors in context menu');
_gridGap?: NUMt = new NumInfo('gap between items in masonry view', false);
_xMargin?: NUMt = new NumInfo('gap between left edge of document and start of masonry/stacking layouts', false);
_yMargin?: NUMt = new NumInfo('gap between top edge of dcoument and start of masonry/stacking layouts', false);
@@ -290,16 +291,16 @@ export class DocumentOptions {
dontPlayLinkOnSelect?: BOOLt = new BoolInfo('whether an audio/video should start playing when a link is followed to it.');
openFactoryLocation?: string; // an OpenWhere value to place the factory created document
openFactoryAsDelegate?: boolean; //
- updateContentsScript?: ScriptField; // reactive script invoked when viewing a document that can update contents of a collection (or do anything)
+ onViewMounted?: ScriptField; // reactive script invoked Doc is viewed (used by showBackLinks view to update collection of links to Doc)
toolTip?: string; // tooltip to display on hover
toolType?: string; // type of pen tool
expertMode?: BOOLt = new BoolInfo('something available only in expert (not novice) mode');
- contentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
contextMenuFilters?: List<ScriptField>;
contextMenuScripts?: List<ScriptField>;
contextMenuLabels?: List<string>;
contextMenuIcons?: List<string>;
+ childContentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
childFilters_boolean?: string;
childFilters?: List<string>;
childLimitHeight?: NUMt = new NumInfo('whether to limit the height of collection children. 0 - means height can be no bigger than width', false);
@@ -419,7 +420,7 @@ export class DocumentOptions {
_dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
_dropPropertiesToRemove?: List<string>; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
- dragWhenActive?: BOOLt = new BoolInfo('should document drag when it is active - e.g., pileView, group');
+ dragWhenActive?: BOOLt = new BoolInfo('should document drag when it is active instead of interacting with its contents - e.g., pileView, group');
dragAction?: DROPt = new DAInfo('how to drag document when it is active (e.g., tree, groups)');
dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', false, true);
dragFactory?: DOCt = new DocInfo('document to create when dragging with a suitable onDragStart script', false);
@@ -658,7 +659,7 @@ export namespace Docs {
DocumentType.PRES,
{
layout: { view: PresBox, dataField: defaultDataKey },
- options: { defaultDoubleClick: 'ignore', layout_hideLinkAnchors: true },
+ options: { defaultDoubleClick: 'ignore', hideClickBehaviors: true, layout_hideLinkAnchors: true },
},
],
[
@@ -1455,17 +1456,17 @@ export namespace DocUtils {
TaskCompletionBox.popupY = showPopup[1] - 33;
TaskCompletionBox.taskCompleted = true;
- LinkDescriptionPopup.popupX = showPopup[0];
- LinkDescriptionPopup.popupY = showPopup[1];
- LinkDescriptionPopup.descriptionPopup = true;
+ LinkDescriptionPopup.Instance.popupX = showPopup[0];
+ LinkDescriptionPopup.Instance.popupY = showPopup[1];
+ LinkDescriptionPopup.Instance.display = true;
const rect = document.body.getBoundingClientRect();
- if (LinkDescriptionPopup.popupX + 200 > rect.width) {
- LinkDescriptionPopup.popupX -= 190;
+ if (LinkDescriptionPopup.Instance.popupX + 200 > rect.width) {
+ LinkDescriptionPopup.Instance.popupX -= 190;
TaskCompletionBox.popupX -= 40;
}
- if (LinkDescriptionPopup.popupY + 100 > rect.height) {
- LinkDescriptionPopup.popupY -= 40;
+ if (LinkDescriptionPopup.Instance.popupY + 100 > rect.height) {
+ LinkDescriptionPopup.Instance.popupY -= 40;
TaskCompletionBox.popupY -= 40;
}
@@ -1895,12 +1896,11 @@ export namespace DocUtils {
}
}
- export function GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, noMargins?: boolean, annotationOn?: Doc, maxHeight?: number, backgroundColor?: string) {
+ export function GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, noMargins?: boolean, annotationOn?: Doc, backgroundColor?: string) {
const tbox = Docs.Create.TextDocument('', {
_xMargin: noMargins ? 0 : undefined,
_yMargin: noMargins ? 0 : undefined,
annotationOn,
- layout_maxAutoHeight: maxHeight,
backgroundColor,
_width: width || 200,
_height: 35,
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 4391e87d6..07ee777cd 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -111,7 +111,7 @@ export class CurrentUserUtils {
const tempClicks = DocCast(doc[field]);
const reqdClickOpts:DocumentOptions = {_width: 300, _height:200, isSystem: true};
const reqdTempOpts:{opts:DocumentOptions, script: string}[] = [
- { opts: { title: "Open In Target", targetScriptKey: "onChildClick"}, script: "docCastAsync(documentView?.props.docViewPath().lastElement()?.Document.target).then((target) => target && (target.proto.data = new List([self])))"},
+ { opts: { title: "Open In Target", targetScriptKey: "onChildClick"}, script: "docCastAsync(documentView?.containerViewPath().lastElement()?.Document.target).then((target) => target && (target.proto.data = new List([self])))"},
{ opts: { title: "Open Detail On Right", targetScriptKey: "onChildDoubleClick"}, script: `openDoc(this.doubleClickView.${OpenWhere.addRight})`}];
const reqdClickList = reqdTempOpts.map(opts => {
const allOpts = {...reqdClickOpts, ...opts.opts};
@@ -192,7 +192,7 @@ export class CurrentUserUtils {
{onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", });
};
const labelBox = (opts: DocumentOptions, data?:string) => Docs.Create.LabelDocument({
- textTransform: "unset", letterSpacing: "unset", _singleLine: false, _label_minFontSize: 14, _label_maxFontSize: 24, layout_borderRounding: "5px", _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts
+ textTransform: "unset", letterSpacing: "unset", _singleLine: false, _label_minFontSize: 14, _label_maxFontSize: 14, layout_borderRounding: "5px", _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts
});
const imageBox = (opts: DocumentOptions, url?:string) => Docs.Create.ImageDocument(url ?? "http://www.cs.brown.edu/~bcz/noImage.png", { "icon_nativeWidth": 360 / 4, "icon_nativeHeight": 270 / 4, iconTemplate:DocumentType.IMG, _width: 360 / 4, _height: 270 / 4, _layout_showTitle: "title", ...opts });
const fontBox = (opts:DocumentOptions, data?:string) => Docs.Create.FontIconDocument({ _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, ...opts });
@@ -275,7 +275,7 @@ export class CurrentUserUtils {
{key: "Map", creator: opts => Docs.Create.MapDocument([], opts), opts: { _width: 800, _height: 600, _layout_fitWidth: true, }},
{key: "Screengrab", creator: Docs.Create.ScreenshotDocument, opts: { _width: 400, _height: 200 }},
{key: "WebCam", creator: opts => Docs.Create.WebCamDocument("", opts), opts: { _width: 400, _height: 200, recording:true, isSystem: true, cloneFieldFilter: new List<string>(["isSystem"]) }},
- {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, waitForDoubleClickToClick: 'never'}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}},
+ {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, title_custom: true, waitForDoubleClickToClick: 'never'}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}},
{key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }},
{key: "DataViz", creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts), opts: { _width: 300, _height: 300 }},
{key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeView_HideUnrendered: true}},
@@ -823,7 +823,7 @@ export class CurrentUserUtils {
// When the user views one of these documents, it will be added to the sharing documents 'viewed' list field
// The sharing document also stores the user's color value which helps distinguish shared documents from personal documents
static setupSharedDocs(doc: Doc, sharingDocumentId: string) {
- const dblClkScript = "{scriptContext.openLevel(documentView); addDocToList(documentView.props.treeViewDoc, 'viewed', documentView.Document);}";
+ const dblClkScript = "{scriptContext.openLevel(documentView); addDocToList(getSharingDoc(), 'viewed', documentView.Document);}";
const sharedScripts = { treeView_ChildDoubleClick: dblClkScript, }
const sharedDocOpts:DocumentOptions = {
@@ -835,7 +835,7 @@ export class CurrentUserUtils {
// childContextMenuLabels: new List<string>(["Add to Dashboards",]),
// childContextMenuIcons: new List<string>(["user-plus",]),
"acl-Guest": SharingPermissions.Augment, "_acl-Guest": SharingPermissions.Augment,
- childDragAction: "embed", isSystem: true, contentPointerEvents: "none", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true,
+ childDragAction: "embed", isSystem: true, childContentPointerEvents: "none", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true,
// NOTE: treeView_HideTitle & _layout_showTitle is for a TreeView's editable title, _layout_showTitle is for DocumentViews title bar
_layout_showTitle: "title", treeView_HideTitle: true, ignoreClick: true, _lockedPosition: true, layout_boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true,
layout_explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'"
@@ -1029,4 +1029,5 @@ ScriptingGlobals.add(function IsExploreMode() { return SnappingManager.ExploreMo
ScriptingGlobals.add(function IsNoviceMode() { return Doc.noviceMode; }, "is Dash in novice mode");
ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering");
ScriptingGlobals.add(function importDocument() { return CurrentUserUtils.importDocument(); }, "imports files from device directly into the import sidebar");
-ScriptingGlobals.add(function setInkToolDefaults() { Doc.ActiveTool = InkTool.None; }); \ No newline at end of file
+ScriptingGlobals.add(function setInkToolDefaults() { Doc.ActiveTool = InkTool.None; });
+ScriptingGlobals.add(function getSharingDoc() {return Doc.SharingDoc() }); \ No newline at end of file
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 7fef5cc79..f730d17fe 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -1,6 +1,7 @@
+import { Howl } from 'howler';
import { action, computed, makeObservable, observable, ObservableSet, observe } from 'mobx';
import { Doc, DocListCast, Opt } from '../../fields/Doc';
-import { AclAdmin, AclEdit, Animation } from '../../fields/DocSymbols';
+import { AclAdmin, AclEdit, Animation, DocData } from '../../fields/DocSymbols';
import { Id } from '../../fields/FieldSymbols';
import { listSpec } from '../../fields/Schema';
import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types';
@@ -10,13 +11,13 @@ import { CollectionViewType } from '../documents/DocumentTypes';
import { CollectionDockingView } from '../views/collections/CollectionDockingView';
import { TabDocView } from '../views/collections/TabDocView';
import { LightboxView } from '../views/LightboxView';
-import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView';
+import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView';
+import { FocusViewOptions } from '../views/nodes/FieldView';
import { KeyValueBox } from '../views/nodes/KeyValueBox';
import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox';
import { PresBox } from '../views/nodes/trails';
import { ScriptingGlobals } from './ScriptingGlobals';
import { SelectionManager } from './SelectionManager';
-import { Howl } from 'howler';
export class DocumentManager {
private static _instance: DocumentManager;
@@ -30,7 +31,7 @@ export class DocumentManager {
@observable.shallow public LinkAnchorBoxViews: DocumentView[] = [];
@observable.shallow public LinkedDocumentViews: { a: DocumentView; b: DocumentView; l: Doc }[] = [];
@computed public get DocumentViews() {
- return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox) && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(view.docViewPath)));
+ return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox) && (!LightboxView.LightboxDoc || LightboxView.Contains(view)));
}
public AddDocumentView(dv: DocumentView) {
this._documentViews.add(dv);
@@ -135,7 +136,7 @@ export class DocumentManager {
});
if (toReturn.length === 0) {
DocumentManager.Instance.DocumentViews.forEach(view => {
- if (Doc.GetProto(view.Document)?.[Id] === id) {
+ if (view.Document[DocData]?.[Id] === id) {
toReturn.push(view);
}
});
@@ -153,15 +154,15 @@ export class DocumentManager {
return passes.reduce(
(toReturn, pass) =>
toReturn ??
- docViewArray.filter(view => view.Document === target).find(view => !pass || view._props.docViewPath().lastElement() === preferredCollection) ??
- docViewArray.filter(view => Doc.AreProtosEqual(view.Document, target)).find(view => !pass || view._props.docViewPath().lastElement() === preferredCollection),
+ docViewArray.filter(view => view.Document === target).find(view => !pass || view.containerViewPath?.().lastElement() === preferredCollection) ??
+ docViewArray.filter(view => Doc.AreProtosEqual(view.Document, target)).find(view => !pass || view.containerViewPath?.().lastElement() === preferredCollection),
undefined as Opt<DocumentView>
);
}
public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
const views: DocumentView[] = [];
- DocumentManager.Instance.DocumentViews.forEach(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.Document, toFind) && views.push(view));
+ DocumentManager.Instance.DocumentViews.forEach(view => LightboxView.Contains(view) && Doc.AreProtosEqual(view.Document, toFind) && views.push(view));
return views?.find(view => view.ContentDiv?.getBoundingClientRect().width /*&& view._props.focus !== returnFalse) || views?.find(view => view._props.focus !== returnFalse*/) || (views.length ? views[0] : undefined);
};
public getFirstDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
@@ -179,8 +180,8 @@ export class DocumentManager {
toFindIn;
const toReturn: DocumentView[] = [];
- const docViews = DocumentManager.Instance.DocumentViews.filter(view => !LightboxView.IsLightboxDocView(view.docViewPath));
- const lightViews = DocumentManager.Instance.DocumentViews.filter(view => LightboxView.IsLightboxDocView(view.docViewPath));
+ const docViews = DocumentManager.Instance.DocumentViews.filter(view => !LightboxView.Contains(view));
+ const lightViews = DocumentManager.Instance.DocumentViews.filter(view => LightboxView.Contains(view));
// heuristic to return the "best" documents first:
// choose a document in the lightbox first
@@ -224,7 +225,7 @@ export class DocumentManager {
}
public static removeOverlayViews() {
- DocumentManager._overlayViews?.forEach(action(view => (view.textHtmlOverlay = undefined)));
+ DocumentManager._overlayViews?.forEach(view => view.setTextHtmlOverlay(undefined, undefined));
DocumentManager._overlayViews?.clear();
}
static _overlayViews = new ObservableSet<DocumentView>();
@@ -236,8 +237,8 @@ export class DocumentManager {
// shows a documentView by:
// traverses down through the viewPath of contexts to the view:
// focusing on each context
- public showDocumentView = async (targetDocView: DocumentView, options: DocFocusOptions) => {
- const docViewPath = targetDocView.docViewPath.slice();
+ public showDocumentView = async (targetDocView: DocumentView, options: FocusViewOptions) => {
+ const docViewPath = [...(targetDocView.containerViewPath?.() ?? []), targetDocView];
let rootContextView = docViewPath.shift();
await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined, focused: false })));
if (options.toggleTarget && (!options.didMove || targetDocView.Document.hidden)) targetDocView.Document.hidden = !targetDocView.Document.hidden;
@@ -252,7 +253,7 @@ export class DocumentManager {
// and finally restoring the targetDoc to the viewSpec specified by the last document which may either be the targetDoc, or a viewSpec that describes the targetDoc configuration
public showDocument = async (
targetDoc: Doc, // document to display
- options: DocFocusOptions, // options for how to navigate to target
+ options: FocusViewOptions, // options for how to navigate to target
finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done.
) => {
Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, targetDoc);
@@ -274,7 +275,7 @@ export class DocumentManager {
// even if we found the document view, if the target is a lightbox, we try to open it in the lightbox to preserve lightbox semantics (eg, there's only one active doc in the lightbox)
const target = DocCast(targetDoc.annotationOn, targetDoc);
const contextView = this.getDocumentView(DocCast(target.embedContainer));
- if (contextView?.docView?._componentView?.addDocTab?.(target, OpenWhere.lightbox)) {
+ if (contextView?.ComponentView?.addDocTab?.(target, OpenWhere.lightbox)) {
await new Promise<void>(waitres => setTimeout(() => waitres()));
}
}
@@ -293,7 +294,7 @@ export class DocumentManager {
focusViewsInPath = async (
docView: DocumentView, //
- options: DocFocusOptions,
+ options: FocusViewOptions,
iterator: (docView: DocumentView) => Promise<{ viewSpec: Opt<Doc>; childDocView: Opt<DocumentView>; focused: boolean }>
) => {
let contextView: DocumentView | undefined; // view containing context that contains target
@@ -313,7 +314,7 @@ export class DocumentManager {
};
@action
- restoreDocView(viewSpec: Opt<Doc>, docView: DocumentView, options: DocFocusOptions, contextView: Opt<DocumentView>, targetDoc: Doc) {
+ restoreDocView(viewSpec: Opt<Doc>, docView: DocumentView, options: FocusViewOptions, contextView: Opt<DocumentView>, targetDoc: Doc) {
if (viewSpec && docView) {
//if (docView.ComponentView instanceof FormattedTextBox)
//viewSpec !== docView.Document &&
@@ -327,24 +328,21 @@ export class DocumentManager {
if (options.zoomTextSelections && Doc.UnhighlightTimer && contextView && targetDoc.text_html) {
// if the docView is a text anchor, the contextView is the PDF/Web/Text doc
- contextView.htmlOverlayEffect = options.effect;
- contextView.textHtmlOverlayTime = options.zoomTime;
- contextView.textHtmlOverlay = StrCast(targetDoc.text_html);
+ contextView.setTextHtmlOverlay(StrCast(targetDoc.text_html), options.effect);
DocumentManager._overlayViews.add(contextView);
}
Doc.AddUnHighlightWatcher(() => {
docView.Document[Animation] = undefined;
DocumentManager.removeOverlayViews();
- contextView && (contextView.htmlOverlayEffect = undefined);
});
}
}
}
-export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCentered: true, zoomScale: 0, openLocation: OpenWhere.toggleRight }, containingDoc?: Doc) {
+export function DocFocusOrOpen(doc: Doc, options: FocusViewOptions = { willZoomCentered: true, zoomScale: 0, openLocation: OpenWhere.toggleRight }, containingDoc?: Doc) {
const func = () => {
const cv = DocumentManager.Instance.getDocumentView(containingDoc);
const dv = DocumentManager.Instance.getDocumentView(doc, cv);
- if (dv && (!containingDoc || dv._props.docViewPath().lastElement()?.Document === containingDoc)) {
+ if (dv && (!containingDoc || dv.containerViewPath?.().lastElement()?.Document === containingDoc)) {
DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.Document));
} else {
const container = DocCast(containingDoc ?? doc.embedContainer ?? Doc.BestEmbedding(doc));
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 9ede18ed5..a6ad0f1b3 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -13,6 +13,7 @@ import { ScriptingGlobals } from './ScriptingGlobals';
import { SelectionManager } from './SelectionManager';
import { SnappingManager } from './SnappingManager';
import { UndoManager } from './UndoManager';
+import { DocData } from '../../fields/DocSymbols';
const { default : { contextMenuZindex } } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore
export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'inSame' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
@@ -180,7 +181,7 @@ export namespace DragManager {
}
};
- export function MakeDropTarget(element: HTMLElement, dropFunc: (e: Event, de: DropEvent) => void, doc?: Doc, preDropFunc?: (e: Event, de: DropEvent, targetAction: dropActionType) => void): DragDropDisposer {
+ export function MakeDropTarget(element: HTMLElement, dropFunc: (e: Event, de: DropEvent) => void, doc: Doc, preDropFunc?: (e: Event, de: DropEvent, targetAction: dropActionType) => void): DragDropDisposer {
if ('canDrop' in element.dataset) {
throw new Error("Element is already droppable, can't make it droppable again");
}
@@ -188,13 +189,13 @@ export namespace DragManager {
const handler = (e: Event) => dropFunc(e, (e as CustomEvent<DropEvent>).detail);
const preDropHandler = (e: Event) => {
const de = (e as CustomEvent<DropEvent>).detail;
- (preDropFunc ?? defaultPreDropFunc)(e, de, StrCast(doc?.dropAction) as dropActionType);
+ (preDropFunc ?? defaultPreDropFunc)(e, de, StrCast(doc.dropAction) as dropActionType);
};
element.addEventListener('dashOnDrop', handler);
- doc && element.addEventListener('dashPreDrop', preDropHandler);
+ element.addEventListener('dashPreDrop', preDropHandler);
return () => {
element.removeEventListener('dashOnDrop', handler);
- doc && element.removeEventListener('dashPreDrop', preDropHandler);
+ element.removeEventListener('dashPreDrop', preDropHandler);
delete element.dataset.canDrop;
};
}
@@ -222,7 +223,7 @@ export namespace DragManager {
: docDragData.dropAction === 'add'
? d
: docDragData.dropAction === 'proto'
- ? Doc.GetProto(d)
+ ? d[DocData]
: docDragData.dropAction === 'copy'
? (await Doc.MakeClone(d)).clone
: d
@@ -250,9 +251,9 @@ export namespace DragManager {
export function StartButtonDrag(eles: HTMLElement[], script: string, title: string, vars: { [name: string]: Field }, params: string[], initialize: (button: Doc) => void, downX: number, downY: number, options?: DragOptions) {
const finishDrag = (e: DragCompleteEvent) => {
const bd = Docs.Create.ButtonDocument({ toolTip: title, z: 1, _width: 150, _height: 50, title, onClick: ScriptField.MakeScript(script) });
- params.map(p => Object.keys(vars).indexOf(p) !== -1 && (Doc.GetProto(bd)[p] = new PrefetchProxy(vars[p] as Doc))); // copy all "captured" arguments into document parameterfields
+ params.map(p => Object.keys(vars).indexOf(p) !== -1 && (bd[DocData][p] = new PrefetchProxy(vars[p] as Doc))); // copy all "captured" arguments into document parameterfields
initialize?.(bd);
- Doc.GetProto(bd)['onClick-paramFieldKeys'] = new List<string>(params);
+ bd[DocData]['onClick-paramFieldKeys'] = new List<string>(params);
e.docDragData && (e.docDragData.droppedDocuments = [bd]);
return e;
};
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index 2c371f28e..f62ec8f83 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -1,4 +1,5 @@
import { Doc, DocListCast, Opt } from '../../fields/Doc';
+import { DocData } from '../../fields/DocSymbols';
import { ObjectField } from '../../fields/ObjectField';
import { RichTextField } from '../../fields/RichTextField';
import { listSpec } from '../../fields/Schema';
@@ -12,7 +13,7 @@ import { DragManager } from './DragManager';
import { ScriptingGlobals } from './ScriptingGlobals';
export function MakeTemplate(doc: Doc, first: boolean = true, rename: Opt<string> = undefined, templateField: string = '') {
- if (templateField) Doc.GetProto(doc).title = templateField; /// the title determines which field is being templated
+ if (templateField) doc[DocData].title = templateField; /// the title determines which field is being templated
doc.isTemplateDoc = makeTemplate(doc, first, rename);
return doc;
}
@@ -33,7 +34,7 @@ function makeTemplate(doc: Doc, first: boolean = true, rename: Opt<string> = und
let any = false;
docs.forEach(d => {
if (!StrCast(d.title).startsWith('-')) {
- any = Doc.MakeMetadataFieldTemplate(d, Doc.GetProto(layoutDoc)) || any;
+ any = Doc.MakeMetadataFieldTemplate(d, layoutDoc[DocData]) || any;
} else if (d.type === DocumentType.COL || d.data instanceof RichTextField) {
any = makeTemplate(d, false) || any;
}
@@ -41,12 +42,12 @@ function makeTemplate(doc: Doc, first: boolean = true, rename: Opt<string> = und
if (first) {
if (!docs.length) {
// bcz: feels hacky : if the root level document has items, it's not a field template
- any = Doc.MakeMetadataFieldTemplate(doc, Doc.GetProto(layoutDoc)) || any;
+ any = Doc.MakeMetadataFieldTemplate(doc, layoutDoc[DocData]) || any;
}
}
if (layoutDoc[fieldKey] instanceof RichTextField || layoutDoc[fieldKey] instanceof ImageField) {
if (!StrCast(layoutDoc.title).startsWith('-')) {
- any = Doc.MakeMetadataFieldTemplate(layoutDoc, Doc.GetProto(layoutDoc));
+ any = Doc.MakeMetadataFieldTemplate(layoutDoc, layoutDoc[DocData]);
}
}
rename && (doc.title = rename);
diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts
index f46c2d431..c5f307f44 100644
--- a/src/client/util/HypothesisUtils.ts
+++ b/src/client/util/HypothesisUtils.ts
@@ -30,15 +30,15 @@ export namespace Hypothesis {
if (currentDoc && Cast(currentDoc.data, WebField)?.url.href === uri) return currentDoc; // always check first whether the currently selected doc is the annotation's source, only use Search otherwise
const results: Doc[] = [];
- await SearchUtil.Search('web', true).then(
- action(async (res: SearchUtil.DocSearchResult) => {
- const docs = res.docs;
- const filteredDocs = docs.filter(doc => doc.author === Doc.CurrentUserEmail && doc.type === DocumentType.WEB && doc.data);
- filteredDocs.forEach(doc => {
- uri === Cast(doc.data, WebField)?.url.href && results.push(doc); // TODO check visited sites history?
- });
- })
- );
+ // await SearchUtil.Search('web', true).then(
+ // action(async (res: SearchUtil.DocSearchResult) => {
+ // const docs = res.docs;
+ // const filteredDocs = docs.filter(doc => doc.author === Doc.CurrentUserEmail && doc.type === DocumentType.WEB && doc.data);
+ // filteredDocs.forEach(doc => {
+ // uri === Cast(doc.data, WebField)?.url.href && results.push(doc); // TODO check visited sites history?
+ // });
+ // })
+ // );
const onScreenResults = results.filter(doc => DocumentManager.Instance.getFirstDocumentView(doc));
return onScreenResults.length ? onScreenResults[0] : results.length ? results[0] : undefined; // prioritize results that are currently on the screen
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index b6dbea33a..398ba3c04 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx
@@ -156,7 +156,7 @@
// x: NumCast(doc.x),
// y: NumCast(doc.y) + offset,
// };
-// const parent = this.props.DocumentView?.()._props.docViewPath().lastElement();
+// const parent = this.props.DocumentView?.().containerViewPath().lastElement();
// if (parent?.Document.type === DocumentType.COL) {
// let importContainer: Doc;
// if (docs.length < 50) {
diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts
index 2df4d1ca8..20261859c 100644
--- a/src/client/util/LinkFollower.ts
+++ b/src/client/util/LinkFollower.ts
@@ -1,16 +1,17 @@
-import { action, observable, runInAction } from 'mobx';
+import { action, runInAction } from 'mobx';
import { Doc, DocListCast, Field, FieldResult, Opt } from '../../fields/Doc';
import { ScriptField } from '../../fields/ScriptField';
import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../fields/Types';
import { DocumentType } from '../documents/DocumentTypes';
-import { DocFocusOptions, OpenWhere } from '../views/nodes/DocumentView';
+import { OpenWhere } from '../views/nodes/DocumentView';
+import { FocusViewOptions } from '../views/nodes/FieldView';
import { PresBox } from '../views/nodes/trails';
import { DocumentManager } from './DocumentManager';
import { LinkManager } from './LinkManager';
import { ScriptingGlobals } from './ScriptingGlobals';
import { SelectionManager } from './SelectionManager';
-import { UndoManager } from './UndoManager';
import { SnappingManager } from './SnappingManager';
+import { UndoManager } from './UndoManager';
/*
* link doc:
* - link_anchor_1: doc
@@ -72,7 +73,7 @@ export class LinkFollower {
if (target) {
const doFollow = (canToggle?: boolean) => {
const toggleTarget = canToggle && BoolCast(sourceDoc.followLinkToggle);
- const options: DocFocusOptions = {
+ const options: FocusViewOptions = {
playAudio: BoolCast(srcAnchor.followLinkAudio),
playMedia: BoolCast(srcAnchor.followLinkVideo),
toggleTarget,
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index ccb3c6b98..353f28a92 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -1,7 +1,7 @@
import { action, makeObservable, observable, observe, runInAction } from 'mobx';
import { computedFn } from 'mobx-utils';
import { Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../fields/Doc';
-import { DirectLinks } from '../../fields/DocSymbols';
+import { DirectLinks, DocData } from '../../fields/DocSymbols';
import { FieldLoader } from '../../fields/FieldLoader';
import { List } from '../../fields/List';
import { ProxyField } from '../../fields/Proxy';
@@ -58,8 +58,8 @@ export class LinkManager {
link &&
action(lAnchProtoProtos => {
Doc.AddDocToList(Doc.UserDoc(), 'links', link);
- lAnchs[0] && Doc.GetProto(lAnchs[0])[DirectLinks].add(link);
- lAnchs[1] && Doc.GetProto(lAnchs[1])[DirectLinks].add(link);
+ lAnchs[0] && lAnchs[0][DocData][DirectLinks].add(link);
+ lAnchs[1] && lAnchs[1][DocData][DirectLinks].add(link);
})
)
)
@@ -74,8 +74,8 @@ export class LinkManager {
Promise.all(lAnchs.map(lAnch => PromiseValue(lAnch?.proto as Doc))).then((lAnchProtos: Opt<Doc>[]) =>
Promise.all(lAnchProtos.map(lAnchProto => PromiseValue(lAnchProto?.proto as Doc))).then(
action(lAnchProtoProtos => {
- link && lAnchs[0] && Doc.GetProto(lAnchs[0])[DirectLinks].delete(link);
- link && lAnchs[1] && Doc.GetProto(lAnchs[1])[DirectLinks].delete(link);
+ link && lAnchs[0] && lAnchs[0][DocData][DirectLinks].delete(link);
+ link && lAnchs[1] && lAnchs[1][DocData][DirectLinks].delete(link);
})
)
)
@@ -162,7 +162,7 @@ export class LinkManager {
return this.relatedLinker(anchor);
} // finds all links that contain the given anchor
public getAllDirectLinks(anchor?: Doc): Doc[] {
- return anchor ? Array.from(Doc.GetProto(anchor)[DirectLinks]) : [];
+ return anchor ? Array.from(anchor[DirectLinks]) : [];
} // finds all links that contain the given anchor
relatedLinker = computedFn(function relatedLinker(this: any, anchor: Doc): Doc[] {
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index dbb994dbd..dfaacf318 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -248,7 +248,7 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp
const funcScript = `(function(${paramString})${reqTypes} { ${body} })`;
host.writeFile('file.ts', funcScript);
- if (typecheck && false) host.writeFile('node_modules/typescript/lib/lib.d.ts', typescriptlib);
+ if (typecheck) host.writeFile('node_modules/typescript/lib/lib.d.ts', typescriptlib.default);
const program = ts.createProgram(['file.ts'], {}, host);
const testResult = program.emit();
const outputText = host.readFile('file.js');
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index e51770c25..2cc64f415 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -1,10 +1,7 @@
-import * as rp from 'request-promise';
-import { DocServer } from '../DocServer';
import { Doc, DocListCast, Field, Opt } from '../../fields/Doc';
import { Id } from '../../fields/FieldSymbols';
-import { Utils } from '../../Utils';
-import { DocumentType } from '../documents/DocumentTypes';
import { StrCast } from '../../fields/Types';
+import { DocumentType } from '../documents/DocumentTypes';
export namespace SearchUtil {
export type HighlightingResult = { [id: string]: { [key: string]: string[] } };
@@ -110,154 +107,4 @@ export namespace SearchUtil {
depth++;
}
}
- export interface IdSearchResult {
- ids: string[];
- lines: string[][];
- numFound: number;
- highlighting: HighlightingResult | undefined;
- }
-
- export interface DocSearchResult {
- docs: Doc[];
- lines: string[][];
- numFound: number;
- highlighting: HighlightingResult | undefined;
- }
-
- export interface SearchParams {
- hl?: string;
- 'hl.fl'?: string;
- start?: number;
- rows?: number;
- fq?: string;
- sort?: string;
- allowEmbeddings?: boolean;
- onlyEmbeddings?: boolean;
- facet?: string;
- 'facet.field'?: string;
- }
- export function Search(query: string, returnDocs: true, options?: SearchParams): Promise<DocSearchResult>;
- export function Search(query: string, returnDocs: false, options?: SearchParams): Promise<IdSearchResult>;
- export async function Search(query: string, returnDocs: boolean, options: SearchParams = {}) {
- query = query || '*'; //If we just have a filter query, search for * as the query
- const rpquery = Utils.prepend('/dashsearch');
- let replacedQuery = query.replace(/type_t:([^ )])/g, (substring, arg) => `{!join from=id to=proto_i}*:* AND ${arg}`);
- if (options.onlyEmbeddings) {
- const header = query.match(/_[atnb]?:/) ? replacedQuery : 'DEFAULT:' + replacedQuery;
- replacedQuery = `{!join from=id to=proto_i}* AND ${header}`;
- }
- //console.log("Q: " + replacedQuery + " fq: " + options.fq);
- const gotten = await rp.get(rpquery, { qs: { ...options, q: replacedQuery } });
- const result: IdSearchResult = gotten.startsWith('<') ? { ids: [], docs: [], numFound: 0, lines: [] } : JSON.parse(gotten);
- if (!returnDocs) {
- return result;
- }
-
- const { ids, highlighting } = result;
-
- const txtresult =
- query !== '*' &&
- JSON.parse(
- await rp.get(Utils.prepend('/textsearch'), {
- qs: { ...options, q: query.replace(/^[ \+\?\*\|]*/, '') }, // a leading '+' leads to a server crash since findInFiles doesn't handle regex failures
- })
- );
-
- const fileids = txtresult ? txtresult.ids : [];
- const newIds: string[] = [];
- const newLines: string[][] = [];
- // bcz: we stopped storing fileUpload id's, so this won't find anything
- // if (fileids) {
- // await Promise.all(
- // fileids.map(async (tr: string, i: number) => {
- // const docQuery = 'fileUpload_t:' + tr.substr(0, 7); //If we just have a filter query, search for * as the query
- // const docResult = JSON.parse(await rp.get(Utils.prepend('/dashsearch'), { qs: { ...options, q: docQuery } }));
- // newIds.push(...docResult.ids);
- // newLines.push(...docResult.ids.map((dr: any) => txtresult.lines[i]));
- // })
- // );
- // }
-
- const theDocs: Doc[] = [];
- const theLines: string[][] = [];
- const textDocMap = await DocServer.GetRefFields(newIds);
- const textDocs = newIds.map((id: string) => textDocMap[id]).map(doc => doc as Doc);
- for (let i = 0; i < textDocs.length; i++) {
- const testDoc = textDocs[i];
- if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1) {
- theDocs.push(Doc.GetProto(testDoc));
- theLines.push(newLines[i].map(line => line.replace(query, query.toUpperCase())));
- }
- }
-
- const docMap = await DocServer.GetRefFields(ids);
- const docs = ids.map((id: string) => docMap[id]).map(doc => doc as Doc);
- for (let i = 0; i < ids.length; i++) {
- const testDoc = docs[i];
- if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && (options.allowEmbeddings || testDoc.proto === undefined || theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1)) {
- theDocs.push(testDoc);
- theLines.push([]);
- } else {
- result.numFound--;
- }
- }
-
- return { docs: theDocs, numFound: Math.max(0, result.numFound), highlighting, lines: theLines };
- }
-
- export async function GetEmbeddingsOfDocument(doc: Doc): Promise<Doc[]>;
- export async function GetEmbeddingsOfDocument(doc: Doc, returnDocs: false): Promise<string[]>;
- export async function GetEmbeddingsOfDocument(doc: Doc, returnDocs = true): Promise<Doc[] | string[]> {
- const proto = Doc.GetProto(doc);
- const protoId = proto[Id];
- if (returnDocs) {
- return (await Search('', returnDocs, { fq: `proto_i:"${protoId}"`, allowEmbeddings: true })).docs;
- } else {
- return (await Search('', returnDocs, { fq: `proto_i:"${protoId}"`, allowEmbeddings: true })).ids;
- }
- // return Search(`{!join from=id to=proto_i}id:${protoId}`, true);
- }
-
- export async function GetViewsOfDocument(doc: Doc): Promise<Doc[]> {
- const results = await Search('', true, { fq: `proto_i:"${doc[Id]}"` });
- return results.docs;
- }
-
- export async function GetContextsOfDocument(doc: Doc): Promise<{ contexts: Doc[]; embeddingContexts: Doc[] }> {
- const docContexts = (await Search('', true, { fq: `data_l:"${doc[Id]}"` })).docs;
- const embeddings = await GetEmbeddingsOfDocument(doc, false);
- const embeddingContexts = await Promise.all(embeddings.map(doc => Search('', true, { fq: `data_l:"${doc}"` })));
- const contexts = { contexts: docContexts, embeddingContexts: [] as Doc[] };
- embeddingContexts.forEach(result => contexts.embeddingContexts.push(...result.docs));
- return contexts;
- }
-
- export async function GetContextIdsOfDocument(doc: Doc): Promise<{ contexts: string[]; embeddingContexts: string[] }> {
- const docContexts = (await Search('', false, { fq: `data_l:"${doc[Id]}"` })).ids;
- const embeddings = await GetEmbeddingsOfDocument(doc, false);
- const embeddingContexts = await Promise.all(embeddings.map(doc => Search('', false, { fq: `data_l:"${doc}"` })));
- const contexts = { contexts: docContexts, embeddingContexts: [] as string[] };
- embeddingContexts.forEach(result => contexts.embeddingContexts.push(...result.ids));
- return contexts;
- }
-
- export async function GetAllDocs() {
- const query = '*';
- const response = await rp.get(Utils.prepend('/dashsearch'), {
- qs: { start: 0, rows: 10000, q: query },
- });
- const result: IdSearchResult = JSON.parse(response);
- const { ids, numFound, highlighting } = result;
- const docMap = await DocServer.GetRefFields(ids);
- const docs: Doc[] = [];
- for (const id of ids) {
- const field = docMap[id];
- if (field instanceof Doc) {
- docs.push(field);
- }
- }
- return docs;
- // const docs = ids.map((id: string) => docMap[id]).filter((doc: any) => doc instanceof Doc);
- // return docs as Doc[];
- }
}
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index 0233c4051..5bf9e5b00 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -5,13 +5,13 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import { BsGoogle } from 'react-icons/bs';
import { FaFillDrip, FaPalette } from 'react-icons/fa';
+import { Utils, addStyleSheet, addStyleSheetRule } from '../../Utils';
import { Doc, Opt } from '../../fields/Doc';
import { DashVersion } from '../../fields/DocSymbols';
import { BoolCast, Cast, NumCast, StrCast } from '../../fields/Types';
-import { addStyleSheet, addStyleSheetRule, Utils } from '../../Utils';
-import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
import { DocServer } from '../DocServer';
import { Networking } from '../Network';
+import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
import { GestureOverlay } from '../views/GestureOverlay';
import { MainViewModal } from '../views/MainViewModal';
import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
@@ -47,7 +47,6 @@ export class SettingsManager extends React.Component<{}> {
@observable activeTab = 'Accounts';
@observable public propertiesWidth: number = 0;
- @observable public headerBarHeight: number = 0;
constructor(props: {}) {
super(props);
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 523721b84..472d419fc 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -5,7 +5,7 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import { FaPlus } from 'react-icons/fa';
import { Doc, DocListCast } from '../../fields/Doc';
-import { AclPrivate, DocAcl } from '../../fields/DocSymbols';
+import { AclPrivate, DocAcl, DocData } from '../../fields/DocSymbols';
import { Id } from '../../fields/FieldSymbols';
import { List } from '../../fields/List';
import { PrefetchProxy } from '../../fields/Proxy';
@@ -64,7 +64,7 @@ export class DashboardView extends ObservableReactComponent<{}> {
getDashboards = (whichGroup: DashboardGroup) => {
if (whichGroup === DashboardGroup.MyDashboards) {
- return DocListCast(Doc.MyDashboards.data).filter(dashboard => Doc.GetProto(dashboard).author === Doc.CurrentUserEmail);
+ return DocListCast(Doc.MyDashboards.data).filter(dashboard => dashboard[DocData].author === Doc.CurrentUserEmail);
}
return DocListCast(Doc.MySharedDocs.data_dashboards).filter(doc => doc.dockingConfig);
};
@@ -171,7 +171,7 @@ export class DashboardView extends ObservableReactComponent<{}> {
}
/>
<div className="info">
- <EditableText type={Type.PRIM} color={color} val={StrCast(dashboard.title)} setVal={val => (Doc.GetProto(dashboard).title = val)} />
+ <EditableText type={Type.PRIM} color={color} val={StrCast(dashboard.title)} setVal={val => (dashboard[DocData].title = val)} />
{this.selectedDashboardGroup === DashboardGroup.SharedDashboards && this.isUnviewedSharedDashboard(dashboard) ? <div>unviewed</div> : <div></div>}
<div
className="more"
@@ -353,7 +353,7 @@ export class DashboardView extends ObservableReactComponent<{}> {
},
],
};
- if (dashboard.dockingConfig && dashboard.dockingConfig !== Doc.GetProto(dashboard).dockingConfig) dashboard.dockingConfig = JSON.stringify(reset);
+ if (dashboard.dockingConfig && dashboard.dockingConfig !== dashboard[DocData].dockingConfig) dashboard.dockingConfig = JSON.stringify(reset);
else Doc.SetInPlace(dashboard, 'dockingConfig', JSON.stringify(reset), true);
return reset;
};
@@ -391,9 +391,9 @@ export class DashboardView extends ObservableReactComponent<{}> {
Doc.ActivePresentation = undefined;
};
- public static SetupDashboardCalendars(dashboardDoc: Doc){
+ public static SetupDashboardCalendars(dashboardDoc: Doc) {
// this section is creating the button document itself === myTrails = new Button
-
+
// create a a list of calendars (as a CalendarCollectionDocument) and store it on the new dashboard
const reqdOpts: DocumentOptions = {
title: 'My Calendars',
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index dfc298840..b21b13e4c 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -2,7 +2,7 @@ import { action, computed, makeObservable, observable } from 'mobx';
import * as React from 'react';
import { returnFalse } from '../../Utils';
import { DateField } from '../../fields/DateField';
-import { Doc, DocListCast, Opt } from '../../fields/Doc';
+import { Doc, DocListCast, Field, Opt } from '../../fields/Doc';
import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocData } from '../../fields/DocSymbols';
import { List } from '../../fields/List';
import { GetEffectiveAcl, inheritParentAcls } from '../../fields/util';
@@ -11,25 +11,68 @@ import { DocUtils } from '../documents/Documents';
import { DocumentManager } from '../util/DocumentManager';
import { ObservableReactComponent } from './ObservableReactComponent';
import { CollectionFreeFormView } from './collections/collectionFreeForm';
-import { DocumentView } from './nodes/DocumentView';
-import { Transform } from '../util/Transform';
+import { FieldViewProps, FocusViewOptions } from './nodes/FieldView';
+import { DocumentView, OpenWhere } from './nodes/DocumentView';
+import { PinProps } from './nodes/trails';
+import { RefField } from '../../fields/RefField';
+import { DragManager } from '../util/DragManager';
-/// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView)
+/**
+ * Shared interface among all viewBox'es (ie, react classes that render the contents of a Doc)
+ * Many of these methods only make sense for specific viewBox'es, but they should be written to
+ * be as general as possible
+ */
+export interface ViewBoxInterface {
+ fieldKey?: string;
+ annotationKey?: string;
+ updateIcon?: () => void; // updates the icon representation of the document
+ getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box)
+ restoreView?: (viewSpec: Doc) => boolean;
+ scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: FocusViewOptions) => Opt<number>; // returns the duration of the focus
+ brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number, holdTime: number) => void; // highlight a region of a view (used by freeforms)
+ getView?: (doc: Doc, options: FocusViewOptions) => Promise<Opt<DocumentView>>; // returns a nested DocumentView for the specified doc or undefined
+ addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox
+ addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections)
+ select?: (ctrlKey: boolean, shiftKey: boolean) => void;
+ focus?: (textAnchor: Doc, options: FocusViewOptions) => Opt<number>;
+ isAnyChildContentActive?: () => boolean; // is any child content of the document active
+ onClickScriptDisable?: () => 'never' | 'always'; // disable click scripts : never, always, or undefined = only when selected
+ getKeyFrameEditing?: () => boolean; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
+ setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
+ playFrom?: (time: number, endTime?: number) => void;
+ Pause?: () => void; // pause a media document (eg, audio/video)
+ IsPlaying?: () => boolean; // is a media document playing
+ TogglePause?: (keep?: boolean) => void; // toggle media document playing state
+ setFocus?: () => void; // sets input focus to the componentView
+ setData?: (data: Field | Promise<RefField | undefined>) => boolean;
+ componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element | null;
+ dragStarting?: (snapToDraggedDoc: boolean, showGroupDragTarget: boolean, visited: Set<Doc>) => void;
+ dragConfig?: (dragData: DragManager.DocumentDragData) => void;
+ incrementalRendering?: () => void;
+ infoUI?: () => JSX.Element | null;
+ screenBounds?: () => Opt<{ left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } }>;
+ ptToScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number };
+ ptFromScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number };
+ snapPt?: (pt: { X: number; Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number; Y: number }; distance: number };
+ search?: (str: string, bwd?: boolean, clear?: boolean) => boolean;
+}
+/**
+ * DocComponent returns a React base class used by Doc views with accessors for unpacking he Document,layoutDoc, and dataDoc's
+ * (note: this should not be used for the 'Box' views that render the contents of Doc views)
+ * Example derived views: CollectionFreeFormDocumentView, DocumentView, DocumentViewInternal)
+ * */
export interface DocComponentProps {
Document: Doc;
LayoutTemplate?: () => Opt<Doc>;
LayoutTemplateString?: string;
- ScreenToLocalTransform: () => Transform;
}
export function DocComponent<P extends DocComponentProps>() {
class Component extends ObservableReactComponent<React.PropsWithChildren<P>> {
- constructor(props: any) {
+ constructor(props: P) {
super(props);
makeObservable(this);
}
- ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform();
-
//TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
get Document() {
return this._props.Document;
@@ -40,27 +83,30 @@ export function DocComponent<P extends DocComponentProps>() {
}
// This is the data part of a document -- ie, the data that is constant across all views of the document
@computed get dataDoc() {
- return this._props.Document[DocData] as Doc;
+ return this.Document[DocData];
}
}
return Component;
}
-/// FieldViewBoxProps - a generic base class for field views that are not annotatable (e.g. InkingStroke, ColorBox)
-interface ViewBoxBaseProps {
- Document: Doc;
- TemplateDataDocument?: Doc;
- DocumentView?: () => DocumentView;
- fieldKey: string;
- isSelected: () => boolean;
- isContentActive: () => boolean | undefined;
- ScreenToLocalTransform: () => Transform;
- renderDepth: number;
-}
-export function ViewBoxBaseComponent<P extends ViewBoxBaseProps>() {
+/**
+ * base class for non-annotatable views that render the interior contents of a DocumentView.
+ * this unpacks the Document/layout/data docs as well as the fieldKey being rendered,
+ * and provides accessors for DocumentView and ScreenToLocalBoxXf
+ * Example views include: InkingStroke, FontIconBox, EquationBox, etc
+ */
+export function ViewBoxBaseComponent<P extends FieldViewProps>() {
class Component extends ObservableReactComponent<React.PropsWithChildren<P>> {
+ constructor(props: P) {
+ super(props);
+ makeObservable(this);
+ }
+
ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform();
+ get DocumentView() {
+ return this._props.DocumentView;
+ }
//TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
get Document() {
return this._props.Document;
@@ -81,31 +127,31 @@ export function ViewBoxBaseComponent<P extends ViewBoxBaseProps>() {
return Component;
}
-/// DocAnnotatbleComponent -return a base class for React views of document fields that are annotatable *and* interactive when selected (e.g., pdf, image)
-export interface ViewBoxAnnotatableProps {
- Document: Doc;
- TemplateDataDocument?: Doc;
- fieldKey: string;
- filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
- isContentActive: () => boolean | undefined;
- select: (isCtrlPressed: boolean) => void;
- whenChildContentsActiveChanged: (isActive: boolean) => void;
- ScreenToLocalTransform: () => Transform;
- isSelected: () => boolean;
- renderDepth: number;
- isAnnotationOverlay?: boolean;
-}
-export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>() {
+/**
+ * base class for annotatable views that render the interior contents of a DocumentView
+ * This does what ViewBoxBaseComponent does and additionally provides accessor for the
+ * field key where annotations are stored as well as add/move/remove methods for handing
+ * annotations.
+ * This also provides methods to determine when the contents should be interactive
+ * (respond to pointerEvents) such as when the DocumentView container is selected or a
+ * peer child of the container is selected
+ * Example views include: PDFBox, ImageBox, MapBox, etc
+ */
+export function ViewBoxAnnotatableComponent<P extends FieldViewProps>() {
class Component extends ObservableReactComponent<React.PropsWithChildren<P>> {
- constructor(props: any) {
+ @observable _annotationKeySuffix = () => 'annotations';
+ @observable _isAnyChildContentActive = false;
+
+ constructor(props: P) {
super(props);
makeObservable(this);
}
ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform();
- @observable _annotationKeySuffix = () => 'annotations';
- @observable _isAnyChildContentActive = false;
+ get DocumentView() {
+ return this._props.DocumentView;
+ }
//TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
@computed get Document() {
return this._props.Document;
@@ -123,15 +169,12 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
@computed get fieldKey() {
return this._props.fieldKey;
}
-
- isAnyChildContentActive = () => this._isAnyChildContentActive;
-
@computed public get annotationKey() {
return this.fieldKey + (this._annotationKeySuffix() ? '_' + this._annotationKeySuffix() : '');
}
@action.bound
- removeDocument(doc: Doc | Doc[], annotationKey?: string, leavePushpin?: boolean): boolean {
+ removeDocument(doc: Doc | Doc[], annotationKey?: string, leavePushpin?: boolean, dontAddToRemoved?: boolean): boolean {
const effectiveAcl = GetEffectiveAcl(this.dataDoc);
const indocs = doc instanceof Doc ? [doc] : doc;
const docs = indocs.filter(doc => [AclEdit, AclAdmin].includes(effectiveAcl) || GetEffectiveAcl(doc) === AclAdmin);
@@ -146,9 +189,9 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
toRemove.forEach(doc => {
leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey);
Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
- Doc.RemoveDocFromList(Doc.GetProto(doc), 'proto_embeddings', doc);
+ Doc.RemoveDocFromList(doc[DocData], 'proto_embeddings', doc);
doc.embedContainer = undefined;
- if (recent) {
+ if (recent && !dontAddToRemoved) {
doc.type !== DocumentType.LOADING && Doc.AddDocToList(recent, 'data', doc, undefined, true, true);
}
});
@@ -173,7 +216,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
}
const first = doc instanceof Doc ? doc : doc[0];
if (!first?._dragOnlyWithinContainer && addDocument !== returnFalse) {
- return this.removeDocument(doc, annotationKey, false) && addDocument(doc, annotationKey);
+ return this.removeDocument(doc, annotationKey, false, true) && addDocument(doc, annotationKey);
}
return false;
};
@@ -194,8 +237,8 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
if ([AclAugment, AclEdit, AclAdmin].includes(effectiveAcl)) {
added.forEach(doc => {
doc._dragOnlyWithinContainer = undefined;
- if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.Document;
- else Doc.GetProto(doc).annotationOn = undefined;
+ if (annotationKey ?? this._annotationKeySuffix()) doc[DocData].annotationOn = this.Document;
+ else doc[DocData].annotationOn = undefined;
Doc.SetContainer(doc, this.Document);
inheritParentAcls(targetDataDoc, doc, true);
});
@@ -209,6 +252,8 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
return true;
};
+ isAnyChildContentActive = () => this._isAnyChildContentActive;
+
whenChildContentsActiveChanged = action((isActive: boolean) => this._props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive)));
}
return Component;
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index bb28d9ec9..8a4b42ae0 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -72,7 +72,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
<div
className="documentButtonBar-icon documentButtonBar-follow"
style={{ backgroundColor: followLink ? Colors.LIGHT_BLUE : Colors.DARK_GRAY, color: followLink ? Colors.BLACK : Colors.WHITE }}
- onClick={undoBatch(e => this._props.views().map(view => view?.docView?.toggleFollowLink(undefined, false)))}>
+ onClick={undoBatch(e => this._props.views().map(view => view?.toggleFollowLink(undefined, false)))}>
<div className="documentButtonBar-followTypes">
{followBtn(
true,
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 788e78ed2..5ef62b2c5 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -8,7 +8,7 @@ import { FaUndo } from 'react-icons/fa';
import { Utils, emptyFunction, lightOrDark, numberValue, returnFalse, setupMoveUpEvents } from '../../Utils';
import { DateField } from '../../fields/DateField';
import { Doc, DocListCast, Field, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc';
-import { AclAdmin, AclAugment, AclEdit } from '../../fields/DocSymbols';
+import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols';
import { InkField } from '../../fields/InkField';
import { RichTextField } from '../../fields/RichTextField';
import { ScriptField } from '../../fields/ScriptField';
@@ -101,7 +101,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
{ x: 0, y: 0, r: 0, b: 0 }
: SelectionManager.Views
.filter(dv => dv._props.renderDepth > 0)
- .map(dv => dv.getBounds())
+ .map(dv => dv.getBounds)
.reduce((bounds, rect) => !rect ? bounds
: { x: Math.min(rect.left, bounds.x),
y: Math.min(rect.top, bounds.y),
@@ -203,7 +203,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
const containers = new Set<Doc | undefined>();
SelectionManager.Views.forEach(v => containers.add(DocCast(v.Document.embedContainer)));
if (containers.size > 1) return false;
- const { left, top } = dragDocView.getBounds() || { left: 0, top: 0 };
+ const { left, top } = dragDocView.getBounds || { left: 0, top: 0 };
const dragData = new DragManager.DocumentDragData(
SelectionManager.Views.map(dv => dv.Document),
dragDocView._props.dropAction
@@ -303,7 +303,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
SelectionManager.DeselectAll();
};
- onSelectContainerDocClick = () => SelectionManager.Views?.[0]?._props.docViewPath?.().lastElement()?.select(false);
+ onSelectContainerDocClick = () => SelectionManager.Views?.[0]?.containerViewPath?.().lastElement()?.select(false);
/**
* sets up events when user clicks on the border radius editor
*/
@@ -344,10 +344,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
e,
returnFalse, // don't care about move or up event,
emptyFunction, // just care about whether we get a click event
- e => UndoManager.RunInBatch(
- () => SelectionManager.Docs.forEach(doc =>
- doc._pointerEvents = (doc._lockedPosition = !doc._lockedPosition)? 'none' : undefined ),
- 'toggleBackground' ) // prettier-ignore
+ e => UndoManager.RunInBatch(() => SelectionManager.Docs.forEach(doc => Doc.toggleLockedPosition(doc)), 'toggleBackground')
);
e.stopPropagation();
};
@@ -530,7 +527,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
doc.xPadding = NumCast(doc.xPadding) * scale.x;
doc.yPadding = NumCast(doc.yPadding) * scale.y;
} else {
- const refCent = docView.screenToContentsTransform().transformPoint(refPt[0], refPt[1]); // fixed reference point for resize (ie, a point that doesn't move)
+ const refCent = docView.screenToViewTransform().transformPoint(refPt[0], refPt[1]); // fixed reference point for resize (ie, a point that doesn't move)
const [nwidth, nheight] = [docView.nativeWidth, docView.nativeHeight];
const [initWidth, initHeight] = [NumCast(doc._width, 1), NumCast(doc._height)];
@@ -544,17 +541,17 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
}
if (['right', 'left'].includes(opts.dragHdl) && modifyNativeDim && Doc.NativeWidth(doc)) {
- const setData = Doc.NativeWidth(Doc.GetProto(doc)) === doc.nativeWidth;
+ const setData = Doc.NativeWidth(doc[DocData]) === doc.nativeWidth;
doc.nativeWidth = scale.x * Doc.NativeWidth(doc);
- if (setData) Doc.SetNativeWidth(Doc.GetProto(doc), NumCast(doc.nativeWidth));
+ if (setData) Doc.SetNativeWidth(doc[DocData], NumCast(doc.nativeWidth));
if (doc.layout_reflowVertical && !NumCast(doc.nativeHeight)) {
doc._nativeHeight = (initHeight / initWidth) * nwidth; // initializes the nativeHeight for a PDF
}
}
if (['bottom', 'top'].includes(opts.dragHdl) && modifyNativeDim && Doc.NativeHeight(doc)) {
- const setData = Doc.NativeHeight(Doc.GetProto(doc)) === doc.nativeHeight;
+ const setData = Doc.NativeHeight(doc[DocData]) === doc.nativeHeight;
doc._nativeHeight = scale.y * Doc.NativeHeight(doc);
- if (setData) Doc.SetNativeHeight(Doc.GetProto(doc), NumCast(doc._nativeHeight));
+ if (setData) Doc.SetNativeHeight(doc[DocData], NumCast(doc._nativeHeight));
}
doc._width = Math.max(1, NumCast(doc._width) * scale.x);
@@ -604,7 +601,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
this._inkDragDocs
.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] }))
.forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => {
- Doc.GetProto(doc).data = new InkField(inkPts.map(
+ doc[DocData].data = new InkField(inkPts.map(
(ipt) => ({// (new x — oldx) + newWidth * (oldxpoint /oldWidth)
X: NumCast(doc.x) - x + (NumCast(doc.width) * ipt.X) / width,
Y: NumCast(doc.y) - y + (NumCast(doc.height) * ipt.Y) / height,
@@ -677,7 +674,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
seldocview._props.hideDeleteButton ||
seldocview.Document.hideDeleteButton ||
SelectionManager.Views.some(docView => {
- const collectionAcl = docView._props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView._props.docViewPath().lastElement().dataDoc) : AclEdit;
+ const collectionAcl = docView.containerViewPath?.()?.lastElement() ? GetEffectiveAcl(docView.containerViewPath?.().lastElement().dataDoc) : AclEdit;
return collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.Document) !== AclAdmin;
});
const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => (
@@ -689,7 +686,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
);
const bounds = this.ClippedBounds;
- const useLock = bounds.r - bounds.x > 135 && seldocview.CollectionFreeFormDocumentView;
+ const useLock = bounds.r - bounds.x > 135;
const useRotation = !hideResizers && seldocview.Document.type !== DocumentType.EQUATION && seldocview.CollectionFreeFormDocumentView; // when do we want an object to not rotate?
const rotation = SelectionManager.Views.length == 1 ? seldocview.screenToContentsTransform().inverse().RotateDeg : 0;
@@ -805,7 +802,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
<div key="br" className="documentDecorations-bottomRightResizer" onPointerDown={this.onPointerDown} />
</>
)}
- {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.containerViewPath?.().lastElement() ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectContainerDocClick, 'tap to select containing document')}
{useRounding && (
<div
className="documentDecorations-borderRadius"
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index b1b04237c..86b9f5e40 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -476,10 +476,9 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
isContentActive={returnFalse}
renderDepth={0}
styleProvider={returnEmptyString}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
focus={emptyFunction}
whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
childFiltersByRanges={returnEmptyFilter}
childFilters={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
diff --git a/src/client/views/InkControlPtHandles.tsx b/src/client/views/InkControlPtHandles.tsx
index a5c2d99d2..7dd57e04d 100644
--- a/src/client/views/InkControlPtHandles.tsx
+++ b/src/client/views/InkControlPtHandles.tsx
@@ -27,7 +27,7 @@ export interface InkControlProps {
export class InkControlPtHandles extends React.Component<InkControlProps> {
@observable private _overControl = -1;
get docView() {
- return this.props.inkView.props.docViewPath().lastElement();
+ return this.props.inkView.DocumentView?.();
}
componentDidMount() {
@@ -58,11 +58,11 @@ export class InkControlPtHandles extends React.Component<InkControlProps> {
if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('drag ink ctrl pt');
const inkMoveEnd = ptFromScreen({ X: delta[0], Y: delta[1] });
const inkMoveStart = ptFromScreen({ X: 0, Y: 0 });
- InkStrokeProperties.Instance.moveControlPtHandle(this.docView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex, origInk);
+ this.docView && InkStrokeProperties.Instance.moveControlPtHandle(this.docView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex, origInk);
return false;
}),
action(() => {
- if (this.props.inkView.controlUndo) {
+ if (this.props.inkView.controlUndo && this.docView) {
InkStrokeProperties.Instance.snapControl(this.docView, controlIndex);
}
this.props.inkView.controlUndo?.end();
@@ -78,11 +78,11 @@ export class InkControlPtHandles extends React.Component<InkControlProps> {
} else {
if (brokenIndices?.includes(equivIndex)) {
if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('make smooth');
- InkStrokeProperties.Instance.snapHandleTangent(this.docView, equivIndex, handleIndexA, handleIndexB);
+ this.docView && InkStrokeProperties.Instance.snapHandleTangent(this.docView, equivIndex, handleIndexA, handleIndexB);
}
if (equivIndex !== controlIndex && brokenIndices?.includes(controlIndex)) {
if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('make smooth');
- InkStrokeProperties.Instance.snapHandleTangent(this.docView, controlIndex, handleIndexA, handleIndexB);
+ this.docView && InkStrokeProperties.Instance.snapHandleTangent(this.docView, controlIndex, handleIndexA, handleIndexB);
}
}
this.props.inkView.controlUndo?.end();
@@ -113,7 +113,7 @@ export class InkControlPtHandles extends React.Component<InkControlProps> {
@action
onDelete = (e: KeyboardEvent) => {
if (['-', 'Backspace', 'Delete'].includes(e.key)) {
- InkStrokeProperties.Instance.deletePoints(this.docView, e.shiftKey);
+ this.docView && InkStrokeProperties.Instance.deletePoints(this.docView, e.shiftKey);
e.stopPropagation();
}
};
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index f31ea2994..52ea89cde 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -241,6 +241,7 @@ export class InkStrokeProperties {
*/
@undoBatch
moveControlPtHandle = (inkView: DocumentView, deltaX: number, deltaY: number, controlIndex: number, origInk?: InkData) =>
+ inkView &&
this.applyFunction(inkView, (view: DocumentView, ink: InkData) => {
const order = controlIndex % 4;
const closed = InkingStroke.IsClosed(ink);
@@ -369,7 +370,7 @@ export class InkStrokeProperties {
snapToAllCurves = (screenDragPt: { X: number; Y: number }, inkView: DocumentView, snapData: { nearestPt: { X: number; Y: number }; distance: number }, ink: InkData, controlIndex: number) => {
const containingCollection = inkView.CollectionFreeFormView;
- const containingDocView = containingCollection?.props.DocumentView?.();
+ const containingDocView = containingCollection?.DocumentView?.();
containingCollection?.childDocs
.filter(doc => doc.type === DocumentType.INK)
.forEach(doc => {
diff --git a/src/client/views/InkTangentHandles.tsx b/src/client/views/InkTangentHandles.tsx
index a00c26a07..c20399698 100644
--- a/src/client/views/InkTangentHandles.tsx
+++ b/src/client/views/InkTangentHandles.tsx
@@ -23,7 +23,7 @@ export interface InkHandlesProps {
@observer
export class InkTangentHandles extends React.Component<InkHandlesProps> {
get docView() {
- return this.props.inkView.props.docViewPath().lastElement();
+ return this.props.inkView.DocumentView?.();
}
/**
* Handles the movement of a selected handle point when the user clicks and drags.
@@ -42,7 +42,7 @@ export class InkTangentHandles extends React.Component<InkHandlesProps> {
if (e.altKey) this.onBreakTangent(controlIndex);
const inkMoveEnd = this.props.inkView.ptFromScreen({ X: delta[0], Y: delta[1] });
const inkMoveStart = this.props.inkView.ptFromScreen({ X: 0, Y: 0 });
- InkStrokeProperties.Instance.moveTangentHandle(this.docView, -(inkMoveEnd.X - inkMoveStart.X), -(inkMoveEnd.Y - inkMoveStart.Y), handleIndex, oppositeHandleIndex, controlIndex);
+ this.docView && InkStrokeProperties.Instance.moveTangentHandle(this.docView, -(inkMoveEnd.X - inkMoveStart.X), -(inkMoveEnd.Y - inkMoveStart.Y), handleIndex, oppositeHandleIndex, controlIndex);
return false;
}),
action(() => {
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index c652e8966..92644d3c5 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -34,21 +34,19 @@ import { InteractionUtils } from '../util/InteractionUtils';
import { SnappingManager } from '../util/SnappingManager';
import { UndoManager } from '../util/UndoManager';
import { ContextMenu } from './ContextMenu';
-import { ViewBoxBaseComponent } from './DocComponent';
+import { ViewBoxBaseComponent, ViewBoxInterface } from './DocComponent';
import { Colors } from './global/globalEnums';
import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles';
import './InkStroke.scss';
import { InkStrokeProperties } from './InkStrokeProperties';
import { InkTangentHandles } from './InkTangentHandles';
-import { DocComponentView } from './nodes/DocumentView';
import { FieldView, FieldViewProps } from './nodes/FieldView';
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
import { PinProps, PresBox } from './nodes/trails';
import { StyleProp } from './StyleProvider';
-import { Transform } from '../util/Transform';
const { default: { INK_MASK_SIZE } } = require('./global/globalCssVariables.module.scss'); // prettier-ignore
@observer
-export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
+export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() implements ViewBoxInterface {
static readonly MaskDim = INK_MASK_SIZE; // choose a really big number to make sure mask fits over container (which in theory can be arbitrarily big)
public static LayoutString(fieldStr: string) {
return FieldView.LayoutString(InkingStroke, fieldStr);
@@ -64,7 +62,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
@observable _nearestScrPt?: { X: number; Y: number }; // nearst screen point on the ink stroke ""
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
this._disposers.selfDisper = reaction(
() => this._props.isSelected(), // react to stroke being deselected by turning off ink handles
selected => !selected && (InkStrokeProperties.Instance._controlButton = false)
@@ -122,7 +120,8 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
@action
onPointerDown = (e: React.PointerEvent) => {
this._handledClick = false;
- const inkView = this._props.docViewPath().lastElement();
+ const inkView = this.DocumentView?.();
+ if (!inkView) return;
const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
const screenPts = inkData
.map(point =>
@@ -162,7 +161,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
InkStrokeProperties.Instance._currentPoint = -1;
this._handledClick = true; // mark the double-click pseudo pointerevent so we can block the real mouse event from propagating to DocumentView
if (isEditing) {
- this._nearestT && this._nearestSeg !== undefined && InkStrokeProperties.Instance.addPoints(this._props.docViewPath().lastElement(), this._nearestT, this._nearestSeg, this.inkScaledData().inkData.slice());
+ this._nearestT && this._nearestSeg !== undefined && InkStrokeProperties.Instance.addPoints(inkView, this._nearestT, this._nearestSeg, this.inkScaledData().inkData.slice());
}
}
}),
@@ -331,8 +330,8 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
);
};
- _subContentView: DocComponentView | undefined;
- setSubContentView = (doc: DocComponentView) => (this._subContentView = doc);
+ _subContentView: ViewBoxInterface | undefined;
+ setSubContentView = (doc: ViewBoxInterface) => (this._subContentView = doc);
@computed get fillColor() {
const isInkMask = BoolCast(this.layoutDoc.stroke_isInkMask);
return isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FillColor) ?? 'transparent';
@@ -461,7 +460,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
<FormattedTextBox
{...this._props}
setHeight={undefined}
- setContentView={this.setSubContentView} // this makes the inkingStroke the "dominant" component - ie, it will show the inking UI when selected (not text)
+ setContentViewBox={this.setSubContentView} // this makes the inkingStroke the "dominant" component - ie, it will show the inking UI when selected (not text)
yPadding={10}
xPadding={10}
fieldKey="text"
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index ab3be3d7a..c7ff7ce47 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -34,7 +34,7 @@ const savedKeys = ['freeform_panX', 'freeform_panY', 'freeform_scale', 'layout_s
type LightboxSavedState = { [key: string]: FieldResult; }; // prettier-ignore
@observer
export class LightboxView extends ObservableReactComponent<LightboxViewProps> {
- public static IsLightboxDocView(path: DocumentView[]) { return (path ?? []).includes(LightboxView.Instance?._docView!); } // prettier-ignore
+ public static Contains(view?:DocumentView) { return view && LightboxView.Instance?._docView&& (view.containerViewPath?.() ?? []).concat(view).includes(LightboxView.Instance?._docView); } // prettier-ignore
public static get LightboxDoc() { return LightboxView.Instance?._doc; } // prettier-ignore
static Instance: LightboxView;
private _path: {
@@ -257,7 +257,7 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> {
styleProvider={DefaultStyleProvider}
ScreenToLocalTransform={this.lightboxScreenToLocal}
renderDepth={0}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
@@ -266,8 +266,7 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> {
whenChildContentsActiveChanged={emptyFunction}
addDocTab={this.AddDocTab}
pinToPres={TabDocView.PinDoc}
- bringToFront={emptyFunction}
- onBrowseClick={DocumentView.exploreMode}
+ onBrowseClickScript={DocumentView.exploreMode}
focus={emptyFunction}
/>
</GestureOverlay>
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 35ffab337..eca0aca4c 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -15,6 +15,7 @@ import { DocServer } from '../DocServer';
import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
import { Docs } from '../documents/Documents';
+import { CalendarManager } from '../util/CalendarManager';
import { CaptureManager } from '../util/CaptureManager';
import { DocumentManager } from '../util/DocumentManager';
import { DragManager } from '../util/DragManager';
@@ -31,7 +32,6 @@ import { SnappingManager } from '../util/SnappingManager';
import { Transform } from '../util/Transform';
import { ReportManager } from '../util/reportManager/ReportManager';
import { ComponentDecorations } from './ComponentDecorations';
-import { SchemaCSVPopUp } from './nodes/DataVizBox/SchemaCSVPopUp';
import { ContextMenu } from './ContextMenu';
import { DashboardView } from './DashboardView';
import { DictationOverlay } from './DictationOverlay';
@@ -55,14 +55,14 @@ import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOpti
import { CollectionLinearView } from './collections/collectionLinear';
import { LinkMenu } from './linking/LinkMenu';
import { AudioBox } from './nodes/AudioBox';
+import { SchemaCSVPopUp } from './nodes/DataVizBox/SchemaCSVPopUp';
import { DocButtonState } from './nodes/DocumentLinksButton';
-import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from './nodes/DocumentView';
+import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from './nodes/DocumentView';
import { ImageBox } from './nodes/ImageBox';
import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup';
import { LinkDocPreview, LinkInfo } from './nodes/LinkDocPreview';
+import { DirectionsAnchorMenu } from './nodes/MapBox/DirectionsAnchorMenu';
import { MapAnchorMenu } from './nodes/MapBox/MapAnchorMenu';
-import { MapBox } from './nodes/MapBox/MapBox';
-import { RadialMenu } from './nodes/RadialMenu';
import { TaskCompletionBox } from './nodes/TaskCompletedBox';
import { DashFieldViewMenu } from './nodes/formattedText/DashFieldView';
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
@@ -72,9 +72,8 @@ import { PresBox } from './nodes/trails';
import { AnchorMenu } from './pdf/AnchorMenu';
import { GPTPopup } from './pdf/GPTPopup/GPTPopup';
import { TopBar } from './topbar/TopBar';
+import { DocData } from '../../fields/DocSymbols';
const { default: { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } } = require('./global/globalCssVariables.module.scss'); // prettier-ignore
-import { DirectionsAnchorMenu } from './nodes/MapBox/DirectionsAnchorMenu';
-import { CalendarManager } from '../util/CalendarManager';
const _global = (window /* browser */ || global) /* node */ as any;
@observer
@@ -132,9 +131,19 @@ export class MainView extends ObservableReactComponent<{}> {
@computed public get mainFreeform(): Opt<Doc> {
return (docs => (docs?.length > 1 ? docs[1] : undefined))(DocListCast(this.mainContainer!.data));
}
+ @observable public headerBarHeight: number = 0;
+ headerBarHeightFunc = () => this.headerBarHeight;
+ @action
+ toggleTopBar = () => {
+ if (this.headerBarHeight > 0) {
+ this.headerBarHeight = 0;
+ } else {
+ this.headerBarHeight = 60;
+ }
+ };
headerBarDocWidth = () => this.mainDocViewWidth();
- headerBarDocHeight = () => (this._hideUI ? 0 : SettingsManager.Instance?.headerBarHeight ?? 0);
+ headerBarDocHeight = () => (this._hideUI ? 0 : this.headerBarHeight ?? 0);
topMenuHeight = () => (this._hideUI ? 0 : 35);
topMenuWidth = returnZero; // value is ignored ...
leftMenuWidth = () => (this._hideUI ? 0 : Number(LEFT_MENU_WIDTH.replace('px', '')));
@@ -606,7 +615,7 @@ export class MainView extends ObservableReactComponent<{}> {
Document={this.headerBarDoc}
addDocTab={DocumentViewInternal.addDocTabFunc}
pinToPres={emptyFunction}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
styleProvider={DefaultStyleProvider}
addDocument={this.addHeaderDoc}
removeDocument={this.removeHeaderDoc}
@@ -623,7 +632,6 @@ export class MainView extends ObservableReactComponent<{}> {
renderDepth={0}
focus={emptyFunction}
whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
@@ -632,16 +640,18 @@ export class MainView extends ObservableReactComponent<{}> {
);
}
@computed get mainDocView() {
+ const headerBar = this._hideUI || !this.headerBarDocHeight?.() ? null : this.headerBarDocView;
+ console.log('Header = ' + this._hideUI + ' ' + this.headerBarDocHeight?.() + ' ' + headerBar);
return (
<>
- {this._hideUI || !this.headerBarDocHeight?.() ? null : this.headerBarDocView}
+ {headerBar}
<DocumentView
key="main"
Document={this.mainContainer!}
addDocument={undefined}
addDocTab={DocumentViewInternal.addDocTabFunc}
pinToPres={emptyFunction}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
styleProvider={this._hideUI ? DefaultStyleProvider : undefined}
isContentActive={returnTrue}
removeDocument={undefined}
@@ -650,7 +660,6 @@ export class MainView extends ObservableReactComponent<{}> {
PanelHeight={this.mainDocViewHeight}
focus={emptyFunction}
whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
@@ -735,7 +744,7 @@ export class MainView extends ObservableReactComponent<{}> {
addDocument={undefined}
addDocTab={DocumentViewInternal.addDocTabFunc}
pinToPres={TabDocView.PinDoc}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
styleProvider={this._sidebarContent.proto === Doc.MyDashboards || this._sidebarContent.proto === Doc.MyFilesystem || this._sidebarContent.proto === Doc.MyTrails ? DashboardStyleProvider : DefaultStyleProvider}
removeDocument={returnFalse}
ScreenToLocalTransform={this.mainContainerXf}
@@ -745,7 +754,6 @@ export class MainView extends ObservableReactComponent<{}> {
isContentActive={returnTrue}
focus={emptyFunction}
whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
@@ -769,12 +777,11 @@ export class MainView extends ObservableReactComponent<{}> {
PanelWidth={this.leftMenuWidth}
PanelHeight={this.leftMenuHeight}
renderDepth={0}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
focus={emptyFunction}
styleProvider={DefaultStyleProvider}
isContentActive={returnTrue}
whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
@@ -785,7 +792,7 @@ export class MainView extends ObservableReactComponent<{}> {
@action
selectMenu = (button: Doc) => {
- const title = StrCast(Doc.GetProto(button).title);
+ const title = StrCast(button[DocData].title);
const willOpen = !this._leftMenuFlyoutWidth || this._panelContent !== title;
this.closeFlyout();
if (willOpen) {
@@ -898,16 +905,14 @@ export class MainView extends ObservableReactComponent<{}> {
<div className="mainView-docButtons" style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }} ref={this._docBtnRef}>
<CollectionLinearView
Document={Doc.MyDockedBtns}
+ docViewPath={returnEmptyDocViewList}
fieldKey="data"
dropAction="embed"
- setHeight={returnFalse}
styleProvider={DefaultStyleProvider}
- bringToFront={emptyFunction}
select={emptyFunction}
isAnyChildContentActive={returnFalse}
isContentActive={emptyFunction}
isSelected={returnFalse}
- docViewPath={returnEmptyDoclist}
moveDocument={this.moveButtonDoc}
addDocument={this.addButtonDoc}
addDocTab={DocumentViewInternal.addDocTabFunc}
@@ -969,41 +974,6 @@ export class MainView extends ObservableReactComponent<{}> {
);
}
- @observable mapBoxHackBool = false;
- @computed get mapBoxHack() {
- return this.mapBoxHackBool ? null : (
- <MapBox
- ref={action((r: any) => r && (this.mapBoxHackBool = true))}
- fieldKey="data"
- select={returnFalse}
- isSelected={returnFalse}
- Document={this.headerBarDoc}
- addDocTab={returnFalse}
- pinToPres={emptyFunction}
- docViewPath={returnEmptyDoclist}
- styleProvider={DefaultStyleProvider}
- addDocument={returnFalse}
- removeDocument={returnFalse}
- fitContentsToBox={returnTrue}
- isDocumentActive={returnTrue} // headerBar is always documentActive (ie, the docView gets pointer events)
- isContentActive={returnTrue} // headerBar is awlays contentActive which means its items are always documentActive
- ScreenToLocalTransform={Transform.Identity}
- childHideResizeHandles={true}
- childDragAction="move"
- dontRegisterView={true}
- PanelWidth={this.headerBarDocWidth}
- PanelHeight={this.headerBarDocHeight}
- renderDepth={0}
- focus={emptyFunction}
- whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
- childFilters={returnEmptyFilter}
- childFiltersByRanges={returnEmptyFilter}
- searchFilterDocs={returnEmptyDoclist}
- />
- );
- }
-
render() {
return (
<div
@@ -1036,7 +1006,7 @@ export class MainView extends ObservableReactComponent<{}> {
<DocumentDecorations boundsLeft={this.leftScreenOffsetOfMainDocView} boundsTop={this.topOfSidebarDoc} PanelWidth={this._windowWidth} PanelHeight={this._windowHeight} />
<ComponentDecorations boundsLeft={this.leftScreenOffsetOfMainDocView} boundsTop={this.topOfMainDocContent} />
{this._hideUI ? null : <TopBar />}
- {LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null}
+ <LinkDescriptionPopup />
{DocButtonState.Instance.LinkEditorDocView ? <LinkMenu clearLinkEditor={action(() => (DocButtonState.Instance.LinkEditorDocView = undefined))} docView={DocButtonState.Instance.LinkEditorDocView} /> : null}
{LinkInfo.Instance?.LinkInfo ? <LinkDocPreview {...LinkInfo.Instance.LinkInfo} /> : null}
@@ -1046,7 +1016,7 @@ export class MainView extends ObservableReactComponent<{}> {
default:
case 'dashboard': return (<>
<div key="dashdiv" style={{ position: 'relative', display: this._hideUI || LightboxView.LightboxDoc ? 'none' : undefined, zIndex: 2001 }}>
- <CollectionMenu panelWidth={this.topMenuWidth} panelHeight={this.topMenuHeight} />
+ <CollectionMenu panelWidth={this.topMenuWidth} panelHeight={this.topMenuHeight} toggleTopBar={this.toggleTopBar} topBarHeight={this.headerBarHeightFunc}/>
</div>
{this.mainDashboardArea}
</> );
@@ -1057,7 +1027,6 @@ export class MainView extends ObservableReactComponent<{}> {
<PreviewCursor />
<TaskCompletionBox />
<ContextMenu />
- <RadialMenu />
<AnchorMenu />
<MapAnchorMenu />
<DirectionsAnchorMenu />
@@ -1070,7 +1039,6 @@ export class MainView extends ObservableReactComponent<{}> {
<LightboxView key="lightbox" PanelWidth={this._windowWidth} PanelHeight={this._windowHeight} maxBorder={[200, 50]} />
<CollectionFreeFormLinksView />
<OverlayView />
- {/* {this.mapBoxHack} */}
<GPTPopup key="gptpopup" />
<SchemaCSVPopUp key="schemacsvpopup" />
<GenerativeFill imageEditorOpen={ImageBox.imageEditorOpen} imageEditorSource={ImageBox.imageEditorSource} imageRootDoc={ImageBox.imageRootDoc} addDoc={ImageBox.addDoc} />
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 9d828364d..a4303c3aa 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -66,7 +66,7 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
const savedAnnoMap = savedAnnotations?.values() && Array.from(savedAnnotations?.values()).length ? savedAnnotations : this.props.savedAnnotations();
if (savedAnnoMap.size === 0) return undefined;
const savedAnnos = Array.from(savedAnnoMap.values())[0];
- const doc = this.props.docView().Document;
+ const doc = this.props.Document;
const scale = (this.props.annotationLayerScaling?.() || 1) * NumCast(doc._freeform_scale, 1);
if (savedAnnos.length && (savedAnnos[0] as any).marqueeing) {
const anno = savedAnnos[0];
@@ -118,7 +118,7 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
})
);
- const textRegionAnnoProto = Doc.GetProto(textRegionAnno);
+ const textRegionAnnoProto = textRegionAnno[DocData];
textRegionAnnoProto.y = Math.max(minY, 0);
textRegionAnnoProto.x = Math.max(minX, 0);
textRegionAnnoProto.height = Math.max(maxY, 0) - Math.max(minY, 0);
@@ -198,7 +198,7 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
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.Document.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, 'yellow');
FormattedTextBox.SetSelectOnLoad(target);
return target;
};
@@ -226,9 +226,10 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.docView(), sourceAnchorCreator, targetCreator), e.pageX, e.pageY, {
dragComplete: e => {
if (!e.aborted && e.linkDocument) {
- Doc.GetProto(e.linkDocument).link_relationship = 'cropped image';
- Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.docView().Document.title;
- Doc.GetProto(e.linkDocument).link_displayLine = false;
+ const linkDocData = e.linkDocument[DocData];
+ linkDocData.link_relationship = 'cropped image';
+ linkDocData.title = 'crop: ' + this.props.Document.title;
+ linkDocData.link_displayLine = false;
}
},
});
@@ -256,7 +257,7 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
// configure and show the annotation/link menu if a the drag region is big enough
// copy the temporary marquee to allow for multiple selections (not currently available though).
const copy = document.createElement('div');
- const scale = (this.props.scaling?.() || 1) * NumCast(this.props.docView().Document._freeform_scale, 1);
+ const scale = (this.props.scaling?.() || 1) * NumCast(this.props.Document._freeform_scale, 1);
['border', 'opacity', 'top', 'left', 'width', 'height'].forEach(prop => (copy.style[prop as any] = marqueeStyle[prop as any]));
copy.className = 'marqueeAnnotator-annotationBox';
copy.style.top = parseInt(marqueeStyle.top.toString().replace('px', '')) / scale + this.props.scrollTop + 'px';
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 915c3c18f..20dc6c9fa 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -221,7 +221,6 @@ export class OverlayView extends ObservableReactComponent<{}> {
style={{ top: d.type === DocumentType.PRES ? 0 : undefined, width: NumCast(d._width), height: NumCast(d._height), transform: `translate(${d.overlayX}px, ${d.overlayY}px)` }}>
<DocumentView
Document={d}
- bringToFront={emptyFunction}
addDocument={undefined}
removeDocument={this.removeOverlayDoc}
PanelWidth={d[Width]}
@@ -234,7 +233,7 @@ export class OverlayView extends ObservableReactComponent<{}> {
whenChildContentsActiveChanged={emptyFunction}
focus={emptyFunction}
styleProvider={DefaultStyleProvider}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
addDocTab={DocumentViewInternal.addDocTabFunc}
pinToPres={emptyFunction}
childFilters={returnEmptyFilter}
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index a69a5f5e8..456b753b4 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -60,18 +60,17 @@ export class PreviewCursor extends ObservableReactComponent<{}> {
} else if (re.test(plain)) {
const url = plain;
if (!url.startsWith(window.location.href)) {
- undoBatch(
- () =>
- this._addDocument?.(
- Docs.Create.WebDocument(url, {
- title: url,
- _width: 500,
- _height: 300,
- data_useCors: true,
- x: newPoint[0],
- y: newPoint[1],
- })
- )
+ undoBatch(() =>
+ this._addDocument?.(
+ Docs.Create.WebDocument(url, {
+ title: url,
+ _width: 500,
+ _height: 300,
+ data_useCors: true,
+ x: newPoint[0],
+ y: newPoint[1],
+ })
+ )
)();
} else alert('cannot paste dash into itself');
} else if (plain.startsWith('__DashDocId(') || plain.startsWith('__DashCloneId(')) {
@@ -86,7 +85,7 @@ export class PreviewCursor extends ObservableReactComponent<{}> {
} else {
FormattedTextBox.PasteOnLoad = e;
if (e.clipboardData.getData('dash/pdfAnchor')) e.preventDefault();
- UndoManager.RunInBatch(() => this._addLiveTextDoc?.(DocUtils.GetNewTextDoc('', newPoint[0], newPoint[1], 500, undefined, undefined, undefined, 750)), 'paste');
+ UndoManager.RunInBatch(() => this._addLiveTextDoc?.(DocUtils.GetNewTextDoc('', newPoint[0], newPoint[1], 500, undefined, undefined, undefined)), 'paste');
}
}
//pasting in images
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 5905f8dbc..bba6285c2 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -345,9 +345,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@undoBatch
handlePerspectiveChange = (e: any) => {
this.selectedDoc && (this.selectedDoc._type_collection = e.target.value);
- SelectionManager.Views.filter(dv => dv.docView)
- .map(dv => dv.docView!)
- .forEach(docView => (docView.layoutDoc._type_collection = e.target.value));
+ SelectionManager.Views.forEach(docView => (docView.layoutDoc._type_collection = e.target.value));
};
@computed get onClickVal() {
const linkButton = IsFollowLinkScript(this.selectedDoc.onClick);
@@ -408,28 +406,26 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@undoBatch
@action
handleOptionChange = (onClick: string) => {
- SelectionManager.Views.filter(dv => dv.docView)
- .map(dv => dv.docView!)
- .forEach(docView => {
- const linkButton = IsFollowLinkScript(docView.Document.onClick);
- docView.noOnClick();
- switch (onClick) {
- case 'enterPortal':
- docView.makeIntoPortal();
- break;
- case 'toggleDetail':
- docView.setToggleDetail();
- break;
- case 'linkInPlace':
- docView.toggleFollowLink(false, false);
- docView.Document.followLinkLocation = linkButton ? OpenWhere.lightbox : undefined;
- break;
- case 'linkOnRight':
- docView.toggleFollowLink(false, false);
- docView.Document.followLinkLocation = linkButton ? OpenWhere.addRight : undefined;
- break;
- }
- });
+ SelectionManager.Views.forEach(docView => {
+ const linkButton = IsFollowLinkScript(docView.Document.onClick);
+ docView.noOnClick();
+ switch (onClick) {
+ case 'enterPortal':
+ docView.makeIntoPortal();
+ break;
+ case 'toggleDetail':
+ docView.setToggleDetail();
+ break;
+ case 'linkInPlace':
+ docView.toggleFollowLink(false, false);
+ docView.Document.followLinkLocation = linkButton ? OpenWhere.lightbox : undefined;
+ break;
+ case 'linkOnRight':
+ docView.toggleFollowLink(false, false);
+ docView.Document.followLinkLocation = linkButton ? OpenWhere.addRight : undefined;
+ break;
+ }
+ });
};
@undoBatch
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index a710e7816..54f141a36 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -27,7 +27,7 @@ export class PropertiesDocContextSelector extends ObservableReactComponent<Prope
@computed get _docs() {
if (!this._props.DocView) return [];
const target = this._props.DocView._props.Document;
- const targetContext = this._props.DocView._props.docViewPath().lastElement()?.Document;
+ const targetContext = this._props.DocView.containerViewPath?.().lastElement()?.Document;
const embeddings = DocListCast(target.proto_embeddings);
const containerProtos = embeddings.filter(embedding => embedding.embedContainer && embedding.embedContainer instanceof Doc).reduce((set, embedding) => set.add(Cast(embedding.embedContainer, Doc, null)), new Set<Doc>());
const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.proto_embeddings));
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 2fcb5d12a..208ed56c9 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -37,7 +37,8 @@ import { PropertiesDocContextSelector } from './PropertiesDocContextSelector';
import { PropertiesSection } from './PropertiesSection';
import './PropertiesView.scss';
import { DefaultStyleProvider } from './StyleProvider';
-import { DocumentView, OpenWhere, StyleProviderFunc } from './nodes/DocumentView';
+import { DocumentView, OpenWhere } from './nodes/DocumentView';
+import { StyleProviderFuncType } from './nodes/FieldView';
import { KeyValueBox } from './nodes/KeyValueBox';
import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails';
const _global = (window /* browser */ || global) /* node */ as any;
@@ -45,7 +46,7 @@ const _global = (window /* browser */ || global) /* node */ as any;
interface PropertiesViewProps {
width: number;
height: number;
- styleProvider?: StyleProviderFunc;
+ styleProvider?: StyleProviderFuncType;
addDocTab: (doc: Doc, where: OpenWhere) => boolean;
}
@@ -299,7 +300,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
renderDepth={1}
fitContentsToBox={returnTrue}
styleProvider={DefaultStyleProvider}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
dontCenter={'y'}
isDocumentActive={returnFalse}
isContentActive={emptyFunction}
@@ -318,7 +319,6 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
whenChildContentsActiveChanged={emptyFunction}
addDocTab={returnFalse}
pinToPres={emptyFunction}
- bringToFront={returnFalse}
dontRegisterView={true}
/>
</div>
diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx
index 086f40e96..623201ed1 100644
--- a/src/client/views/ScriptBox.tsx
+++ b/src/client/views/ScriptBox.tsx
@@ -11,6 +11,7 @@ import { EditableView } from './EditableView';
import { DocumentIconContainer } from './nodes/DocumentIcon';
import { OverlayView } from './OverlayView';
import './ScriptBox.scss';
+import { DocData } from '../../fields/DocSymbols';
export interface ScriptBoxProps {
onSave: (text: string, onError: (error: string) => void) => void;
@@ -102,7 +103,7 @@ export class ScriptBox extends React.Component<ScriptBoxProps> {
onCancel={overlayDisposer}
onSave={(text, onError) => {
if (!text) {
- Doc.GetProto(doc)[fieldKey] = undefined;
+ doc[DocData][fieldKey] = undefined;
} else {
const script = CompileScript(text, {
params: { this: Doc.name, ...contextParams },
@@ -125,7 +126,7 @@ export class ScriptBox extends React.Component<ScriptBoxProps> {
div.innerHTML = 'button';
params.length && DragManager.StartButtonDrag([div], text, doc.title + '-instance', {}, params, (button: Doc) => {}, clientX, clientY);
- Doc.GetProto(doc)[fieldKey] = new ScriptField(script);
+ doc[DocData][fieldKey] = new ScriptField(script);
overlayDisposer();
}
}}
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 0f4a4260c..1e9272e93 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -18,6 +18,7 @@ import { StyleProp } from './StyleProvider';
import { CollectionStackingView } from './collections/CollectionStackingView';
import { FieldViewProps } from './nodes/FieldView';
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
+import { DocData } from '../../fields/DocSymbols';
interface ExtraProps {
fieldKey: string;
@@ -90,7 +91,7 @@ export class SidebarAnnos extends ObservableReactComponent<FieldViewProps & Extr
.map(data => {
const key = data.split(':')[0];
const val = Field.Copy(this.allMetadata.get(key));
- Doc.GetProto(target)[key] = val;
+ target[DocData][key] = val;
return {
type: 'dashField',
attrs: { fieldKey: key, docId: '', hideKey: false, editable: true },
@@ -98,7 +99,7 @@ export class SidebarAnnos extends ObservableReactComponent<FieldViewProps & Extr
};
});
- if (!anchor.text) Doc.GetProto(anchor).text = '-selection-';
+ if (!anchor.text) anchor[DocData].text = '-selection-';
const textLines: any = [
{
type: 'paragraph',
@@ -133,7 +134,7 @@ export class SidebarAnnos extends ObservableReactComponent<FieldViewProps & Extr
};
if (taggedContent.length) textLines.push(metadatatext);
if (textLines.length) {
- Doc.GetProto(target).text = new RichTextField(
+ target[DocData].text = new RichTextField(
JSON.stringify({
doc: {
type: 'doc',
@@ -234,7 +235,7 @@ export class SidebarAnnos extends ObservableReactComponent<FieldViewProps & Extr
<div style={{ width: '100%', height: `calc(100% - 38px)`, position: 'relative' }}>
<CollectionStackingView
{...this._props}
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}
ref={this._stackRef}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index d077543f1..5a0167338 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
import { Dropdown, DropdownType, IconButton, IListItemProps, Shadows, Size, Type } from 'browndash-components';
-import { action, runInAction, untracked } from 'mobx';
+import { action, untracked } from 'mobx';
import { extname } from 'path';
import * as React from 'react';
import { BsArrowDown, BsArrowDownUp, BsArrowUp } from 'react-icons/bs';
@@ -20,7 +20,7 @@ import { SnappingManager } from '../util/SnappingManager';
import { undoBatch, UndoManager } from '../util/UndoManager';
import { TreeSort } from './collections/TreeSort';
import { Colors } from './global/globalEnums';
-import { DocumentViewInternalProps, DocumentViewProps } from './nodes/DocumentView';
+import { DocumentViewProps } from './nodes/DocumentView';
import { FieldViewProps } from './nodes/FieldView';
import { KeyValueBox } from './nodes/KeyValueBox';
import { PropertiesView } from './PropertiesView';
@@ -51,21 +51,7 @@ export enum StyleProp {
}
function toggleLockedPosition(doc: Doc) {
- UndoManager.RunInBatch(
- () =>
- runInAction(() => {
- doc._lockedPosition = !doc._lockedPosition;
- doc._pointerEvents = doc._lockedPosition ? 'none' : undefined;
- }),
- 'toggleBackground'
- );
-}
-
-export function testDocProps(toBeDetermined: any): toBeDetermined is DocumentViewProps {
- return toBeDetermined?.isContentActive ? toBeDetermined : undefined;
-}
-export function testFieldProps(toBeDetermined: any): toBeDetermined is FieldViewProps {
- return toBeDetermined?.isContentActive ? toBeDetermined : undefined;
+ UndoManager.RunInBatch(() => Doc.toggleLockedPosition(doc), 'toggleBackground');
}
export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) {
@@ -80,22 +66,21 @@ export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) {
// a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab
//
-export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any {
+export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps & DocumentViewProps>, property: string): any {
const remoteDocHeader = 'author;author_date;noMargin';
- const docProps = testDocProps(props) ? props : undefined;
- const fieldProps = testFieldProps(props) ? props : undefined;
const isCaption = property.includes(':caption');
const isAnchor = property.includes(':anchor');
- const isContent = property.includes(':content');
+ const isNonTransparent = property.includes(':nonTransparent');
+ const isNonTransparentLevel = isNonTransparent ? Number(property.replace(/.*:nonTransparent([0-9]+).*/, '$1')) : 0; // property.includes(':nonTransparent');
const isAnnotated = property.includes(':annotated');
- const isInk = () => doc?._layout_isSvg && !docProps?.LayoutTemplateString;
+ const isInk = () => doc?._layout_isSvg && !props?.LayoutTemplateString;
const isOpen = property.includes(':open');
const isEmpty = property.includes(':empty');
const boxBackground = property.includes(':box');
- const fieldKey = fieldProps?.fieldKey ? fieldProps.fieldKey + '_' : isCaption ? 'caption_' : '';
+ const fieldKey = props?.fieldKey ? props.fieldKey + '_' : isCaption ? 'caption_' : '';
const lockedPosition = () => doc && BoolCast(doc._lockedPosition);
const titleHeight = () => props?.styleProvider?.(doc, props, StyleProp.TitleHeight);
- const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor);
+ const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor + ':nonTransparent' + (isNonTransparentLevel + 1));
const color = () => props?.styleProvider?.(doc, props, StyleProp.Color);
const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity);
const layout_showTitle = () => props?.styleProvider?.(doc, props, StyleProp.ShowTitle);
@@ -135,20 +120,19 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewInter
return undefined;
case StyleProp.DocContents:return undefined;
case StyleProp.WidgetColor:return isAnnotated ? Colors.LIGHT_BLUE : 'dimgrey';
- case StyleProp.Opacity: return docProps?.LayoutTemplateString?.includes(KeyValueBox.name) ? 1 : doc?.text_inlineAnnotations ? 0 : Cast(doc?._opacity, "number", Cast(doc?.opacity, 'number', null));
+ case StyleProp.Opacity: return props?.LayoutTemplateString?.includes(KeyValueBox.name) ? 1 : doc?.text_inlineAnnotations ? 0 : Cast(doc?._opacity, "number", Cast(doc?.opacity, 'number', null));
case StyleProp.FontSize: return StrCast(doc?.[fieldKey + 'fontSize'], StrCast(doc?._text_fontSize, StrCast(Doc.UserDoc().fontSize)));
case StyleProp.FontFamily: return StrCast(doc?.[fieldKey + 'fontFamily'], StrCast(doc?._text_fontFamily, StrCast(Doc.UserDoc().fontFamily)));
case StyleProp.FontWeight: return StrCast(doc?.[fieldKey + 'fontWeight'], StrCast(doc?._text_fontWeight, StrCast(Doc.UserDoc().fontWeight)));
case StyleProp.FillColor: return StrCast(doc?._fillColor, StrCast(doc?.fillColor, 'transparent'));
- case StyleProp.ShowCaption:return doc?._type_collection === CollectionViewType.Carousel || props?.hideCaptions ? undefined : StrCast(doc?._layout_showCaption);
- case StyleProp.TitleHeight:
- return (props?.DocumentView?.().screenToViewTransform().Scale ?? 1) * NumCast(Doc.UserDoc().headerHeight,30)
+ case StyleProp.ShowCaption:return props?.hideCaptions || doc?._type_collection === CollectionViewType.Carousel ? undefined: StrCast(doc?._layout_showCaption);
+ case StyleProp.TitleHeight:return (props?.ScreenToLocalTransform().Scale ?? 1) * NumCast(Doc.UserDoc().headerHeight,30);
case StyleProp.ShowTitle:
return (
(doc &&
- !docProps?.LayoutTemplateString &&
+ !props?.LayoutTemplateString &&
!doc.presentation_targetDoc &&
- !docProps?.LayoutTemplateString?.includes(KeyValueBox.name) &&
+ !props?.LayoutTemplateString?.includes(KeyValueBox.name) &&
props?.layout_showTitle?.() !== '' &&
StrCast(
doc._layout_showTitle,
@@ -167,8 +151,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewInter
if (doc?.type === DocumentType.FONTICON) return SettingsManager.userColor;
const docColor: Opt<string> = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color));
if (docColor) return docColor;
- const docView = props?.DocumentView?.();
- const backColor = backgroundCol() || docView?._props.styleProvider?.(docView._props.treeViewDoc, docView.docView?._props, StyleProp.BackgroundColor);
+ const backColor = backgroundCol();
return backColor ? lightOrDark(backColor) : undefined;
case StyleProp.BorderRounding:
return StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.layout_borderRounding, doc?._type_collection === CollectionViewType.Pile ? '50%' : ''));
@@ -198,18 +181,18 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewInter
: 0;
case StyleProp.BackgroundColor: {
if (SettingsManager.Instance.LastPressedBtn === doc) return SettingsManager.userColor; // hack to indicate active menu panel item
- let docColor: Opt<string> = StrCast(doc?.[fieldKey + '_backgroundColor'], StrCast(doc?._backgroundColor, isCaption ? 'rgba(0,0,0,0.4)' : ''));
+ let docColor: Opt<string> = StrCast(doc?.[fieldKey + 'backgroundColor'], StrCast(doc?._backgroundColor, isCaption ? 'rgba(0,0,0,0.4)' : ''));
// prettier-ignore
switch (doc?.type) {
case DocumentType.PRESELEMENT: docColor = docColor || ""; break;
case DocumentType.PRES: docColor = docColor || 'transparent'; break;
case DocumentType.FONTICON: docColor = boxBackground ? undefined : docColor || Colors.DARK_GRAY; break;
- case DocumentType.RTF: docColor = docColor || Colors.LIGHT_GRAY; break;
+ case DocumentType.RTF: docColor = docColor || Colors.LIGHT_GRAY; break;
case DocumentType.LINK: docColor = (isAnchor ? docColor : undefined); break;
case DocumentType.INK: docColor = doc?.stroke_isInkMask ? 'rgba(0,0,0,0.7)' : undefined; break;
case DocumentType.EQUATION: docColor = docColor || 'transparent'; break;
case DocumentType.LABEL: docColor = docColor || Colors.LIGHT_GRAY; break;
- case DocumentType.BUTTON: docColor = docColor || Colors.LIGHT_GRAY; break;
+ case DocumentType.BUTTON: docColor = docColor || Colors.LIGHT_GRAY; break;
case DocumentType.IMG:
case DocumentType.WEB:
case DocumentType.PDF:
@@ -230,6 +213,9 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewInter
//if (doc._type_collection !== CollectionViewType.Freeform && doc._type_collection !== CollectionViewType.Time) return "rgb(62,62,62)";
default: docColor = docColor || (Colors.WHITE);
}
+ if (isNonTransparent && isNonTransparentLevel < 9 && (!docColor || docColor === 'transparent') && doc?.embedContainer && props?.styleProvider) {
+ return props.styleProvider(DocCast(doc.embedContainer), props, StyleProp.BackgroundColor+":nonTransparent"+(isNonTransparentLevel+1));
+ }
return (docColor && !doc) ? DashColor(docColor).fade(0.5).toString() : docColor;
}
case StyleProp.BoxShadow: {
@@ -242,7 +228,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewInter
doc?.layout_boxShadow,
doc?._type_collection === CollectionViewType.Pile
? '4px 4px 10px 2px'
- : lockedPosition() || doc?.isGroup || docProps?.LayoutTemplateString
+ : lockedPosition() || doc?.isGroup || props?.LayoutTemplateString
? undefined // groups have no drop shadow -- they're supposed to be "invisible". LayoutString's imply collection is being rendered as something else (e.g., title of a Slide)
: `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0.2vw 0.2vw 0.8vw')}`
);
@@ -252,13 +238,13 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewInter
default:
return doc.z
? `#9c9396 ${StrCast(doc?.layout_boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow
- : props?.docViewPath().lastElement()?.Document._freeform_useClusters
- ? `${backgroundCol()} ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
+ : props?.containerViewPath?.().lastElement()?.Document._freeform_useClusters
+ ? `${backgroundCol()} ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (props?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
: NumCast(doc.group, -1) !== -1
- ? `gray ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
+ ? `gray ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (props?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
: lockedPosition()
? undefined // if it's a background & has a cluster color, make the shadow spread really big
- : StrCast(doc.layout_fieldKey).includes('_inline') // if doc is an inline document in a text box
+ : fieldKey.includes('_inline') // if doc is an inline document in a text box
? `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0vw 0vw 0.1vw')}`
: DocCast(doc.embedContainer)?.type=== DocumentType.RTF // if doc is embedded in a text document (but not an inline)
? `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0.2vw 0.2vw 0.8vw')}`
@@ -266,31 +252,27 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewInter
}
}
case StyleProp.PointerEvents:
- if (StrCast(doc?.pointerEvents) && !docProps?.LayoutTemplateString?.includes(KeyValueBox.name)) return StrCast(doc!.pointerEvents); // honor pointerEvents field (set by lock button usually) if it's not a keyValue view of the Doc
- if (docProps?.DocumentView?.()._props.LayoutTemplateString?.includes(KeyValueBox.name)) return 'all';
+ if (StrCast(doc?.pointerEvents) && !props?.LayoutTemplateString?.includes(KeyValueBox.name)) return StrCast(doc!.pointerEvents); // honor pointerEvents field (set by lock button usually) if it's not a keyValue view of the Doc
+ if (props?.LayoutTemplateString?.includes(KeyValueBox.name)) return 'all';
if (SnappingManager.ExploreMode || doc?.layout_unrendered) return isInk() ? 'visiblePainted' : 'all';
if (props?.pointerEvents?.() === 'none') return 'none';
if (opacity() === 0) return 'none';
if (props?.isGroupActive?.() ) return isInk() ? 'visiblePainted': (doc?.
isGroup )? undefined: 'all'
- if (props?.isDocumentActive?.() && !props.treeViewDoc) return isInk() ? 'visiblePainted' : 'all';
+ if (props?.isDocumentActive?.()) return isInk() ? 'visiblePainted' : 'all';
return undefined; // fixes problem with tree view elements getting pointer events when the tree view is not active
case StyleProp.Decorations:
- const lock = () => {
- if (props?.docViewPath().lastElement()?.Document?._type_collection === CollectionViewType.Freeform) {
- return doc?.pointerEvents !== 'none' ? null : (
+ const lock = () => doc?.pointerEvents !== 'none' ? null : (
<div className="styleProvider-lock" onClick={() => toggleLockedPosition(doc)}>
<FontAwesomeIcon icon='lock' size="lg" />
</div>
);
- }
- };
const filter = () => {
const dashView = untracked(() => DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard));
const showFilterIcon =
StrListCast(doc?._childFilters).length || StrListCast(doc?._childFiltersByRanges).length
? 'green' // #18c718bd' //'hasFilter'
- : docProps?.childFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragDocsFilter).length || docProps?.childFiltersByRanges().length
+ : props?.childFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragDocsFilter).length || props?.childFiltersByRanges().length
? 'orange' //'inheritsFilter'
: undefined;
return !showFilterIcon ? null : (
@@ -321,7 +303,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewInter
"this view inherits filters from one of its parents"}
color={SettingsManager.userColor}
background={showFilterIcon}
- items={[ ...(dashView ? [dashView]: []), ...(props?.docViewPath?.()??[]), ...(props?.DocumentView?[props?.DocumentView?.()]:[])]
+ items={[ ...(dashView ? [dashView]: []), ...(props?.docViewPath?.()??[])]
.filter(dv => StrListCast(dv?.Document.childFilters).length || StrListCast(dv?.Document.childRangeFilters).length)
.map(dv => ({
text: StrCast(dv?.Document.title),
@@ -334,12 +316,12 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewInter
};
const audio = () => {
const audioAnnoState = (doc: Doc) => StrCast(doc.audioAnnoState, 'stopped');
- const audioAnnosCount = (doc: Doc) => StrListCast(doc[Doc.LayoutFieldKey(doc) + '_audioAnnotations']).length;
+ const audioAnnosCount = (doc: Doc) => StrListCast(doc[fieldKey + 'audioAnnotations']).length;
if (!doc || props?.renderDepth === -1 || !audioAnnosCount(doc)) return null;
const audioIconColors: { [key: string]: string } = { recording: 'red', playing: 'green', stopped: 'blue' };
return (
- <Tooltip title={<div>{StrListCast(doc[Doc.LayoutFieldKey(doc) + '_audioAnnotations_text']).lastElement()}</div>}>
- <div className="styleProvider-audio" onPointerDown={() => DocumentManager.Instance.getFirstDocumentView(doc)?.docView?.playAnnotation()}>
+ <Tooltip title={<div>{StrListCast(doc[fieldKey + 'audioAnnotations_text']).lastElement()}</div>}>
+ <div className="styleProvider-audio" onPointerDown={() => DocumentManager.Instance.getFirstDocumentView(doc)?.playAnnotation()}>
<FontAwesomeIcon className="documentView-audioFont" style={{ color: audioIconColors[audioAnnoState(doc)] }} icon={'file-audio'} size="sm" />
</div>
</Tooltip>
@@ -374,7 +356,7 @@ export function DashboardToggleButton(doc: Doc, field: string, onIcon: IconProp,
/**
* add hide button decorations for the "Dashboards" flyout TreeView
*/
-export function DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps | DocumentViewInternalProps>, property: string) {
+export function DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) {
if (doc && property.split(':')[0] === StyleProp.Decorations) {
return doc._type_collection === CollectionViewType.Docking || Doc.IsSystem(doc)
? null
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index b42f3c1e9..5fc33207e 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -11,9 +11,10 @@ import { ScriptingGlobals } from '../util/ScriptingGlobals';
import { Transform } from '../util/Transform';
import { undoBatch } from '../util/UndoManager';
import { CollectionTreeView } from './collections/CollectionTreeView';
-import { DocumentView } from './nodes/DocumentView';
+import { DocumentView, returnEmptyDocViewList } from './nodes/DocumentView';
import { DefaultStyleProvider } from './StyleProvider';
import './TemplateMenu.scss';
+import { DocData } from '../../fields/DocSymbols';
@observer
class TemplateToggle extends React.Component<{ template: string; checked: boolean; toggle: (event: React.ChangeEvent<HTMLInputElement>, template: string) => void }> {
@@ -79,7 +80,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
};
componentDidMount() {
!this._addedKeys && (this._addedKeys = new ObservableSet());
- [...Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].Document))), ...Array.from(Object.keys(this.props.docViews[0].Document))]
+ [...Array.from(Object.keys(this.props.docViews[0].Document[DocData])), ...Array.from(Object.keys(this.props.docViews[0].Document))]
.filter(key => key.startsWith('layout_'))
.map(key => runInAction(() => this._addedKeys.add(key.replace('layout_', ''))));
}
@@ -113,9 +114,8 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
{templateMenu}
<CollectionTreeView
Document={Doc.MyTemplates}
+ docViewPath={returnEmptyDocViewList}
styleProvider={DefaultStyleProvider}
- setHeight={returnFalse}
- docViewPath={returnEmptyDoclist}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
@@ -123,7 +123,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
onChildClick={this.scriptField}
isAnyChildContentActive={returnFalse}
isContentActive={returnTrue}
- bringToFront={emptyFunction}
focus={emptyFunction}
whenChildContentsActiveChanged={emptyFunction}
ScreenToLocalTransform={Transform.Identity}
diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx
index 4c0a917f5..cbcc980a9 100644
--- a/src/client/views/collections/CollectionCalendarView.tsx
+++ b/src/client/views/collections/CollectionCalendarView.tsx
@@ -62,7 +62,7 @@ export class CollectionCalendarView extends CollectionSubView() {
screenToLocalTransform = () =>
this._props
.ScreenToLocalTransform()
- .translate(Doc.NativeWidth(this._props.Document), 0)
+ .translate(Doc.NativeWidth(this.Document), 0)
.scale(this._props.NativeDimScaling?.() || 1);
get calendarsKey() {
@@ -74,7 +74,7 @@ export class CollectionCalendarView extends CollectionSubView() {
<div className="collectionCalendarView">
<CollectionStackingView
{...this._props}
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
ref={this._stackRef}
PanelHeight={this.panelHeight}
PanelWidth={this._props.PanelWidth}
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 8e072e235..7e484f3df 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -2,7 +2,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Utils, returnFalse, returnZero } from '../../../Utils';
+import { Utils, emptyFunction, returnFalse, returnZero } from '../../../Utils';
import { Doc, DocListCast } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
@@ -10,7 +10,8 @@ import { DocumentType } from '../../documents/DocumentTypes';
import { DragManager } from '../../util/DragManager';
import { SelectionManager } from '../../util/SelectionManager';
import { StyleProp } from '../StyleProvider';
-import { DocFocusOptions, DocumentView } from '../nodes/DocumentView';
+import { DocumentView } from '../nodes/DocumentView';
+import { FocusViewOptions } from '../nodes/FieldView';
import './CollectionCarousel3DView.scss';
import { CollectionSubView } from './CollectionSubView';
const { default: { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } } = require('../global/globalCssVariables.module.scss'); // prettier-ignore
@@ -49,7 +50,7 @@ export class CollectionCarousel3DView extends CollectionSubView() {
.translate(-this.panelWidth() + ((this.centerScale - 1) * this.panelWidth()) / 2, -((Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) + ((this.centerScale - 1) * this.panelHeight()) / 2)
.scale(1 / this.centerScale);
- focus = (anchor: Doc, options: DocFocusOptions) => {
+ focus = (anchor: Doc, options: FocusViewOptions) => {
const docs = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]);
if (anchor.type !== DocumentType.CONFIG && !docs.includes(anchor)) return;
options.didMove = true;
@@ -70,7 +71,7 @@ export class CollectionCarousel3DView extends CollectionSubView() {
NativeWidth={returnZero}
NativeHeight={returnZero}
layout_fitWidth={undefined}
- onDoubleClick={this.onChildDoubleClick}
+ onDoubleClickScript={this.onChildDoubleClick}
renderDepth={this._props.renderDepth + 1}
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
@@ -80,7 +81,6 @@ export class CollectionCarousel3DView extends CollectionSubView() {
isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
PanelWidth={this.panelWidth}
PanelHeight={this.panelHeight}
- bringToFront={returnFalse}
/>
);
};
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index a125f1356..dae16bafb 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -7,11 +7,11 @@ import { Doc, Opt } from '../../../fields/Doc';
import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { DragManager } from '../../util/DragManager';
import { StyleProp } from '../StyleProvider';
-import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView';
+import { DocumentView } from '../nodes/DocumentView';
+import { FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import './CollectionCarouselView.scss';
import { CollectionSubView } from './CollectionSubView';
-import { FieldViewProps } from '../nodes/FieldView';
@observer
export class CollectionCarouselView extends CollectionSubView() {
@@ -41,7 +41,7 @@ export class CollectionCarouselView extends CollectionSubView() {
e.stopPropagation();
this.layoutDoc._carousel_index = (NumCast(this.layoutDoc._carousel_index) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length;
};
- captionStyleProvider = (doc: Doc | undefined, captionProps: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ captionStyleProvider = (doc: Doc | undefined, captionProps: Opt<FieldViewProps>, property: string): any => {
// first look for properties on the document in the carousel, then fallback to properties on the container
const childValue = doc?.['caption-' + property] ? this._props.styleProvider?.(doc, captionProps, property) : undefined;
return childValue ?? this._props.styleProvider?.(this.layoutDoc, captionProps, property);
@@ -66,9 +66,9 @@ export class CollectionCarouselView extends CollectionSubView() {
NativeWidth={returnZero}
NativeHeight={returnZero}
layout_fitWidth={undefined}
- setContentView={undefined}
- onDoubleClick={this.onContentDoubleClick}
- onClick={this.onContentClick}
+ setContentViewBox={undefined}
+ onDoubleClickScript={this.onContentDoubleClick}
+ onClickScript={this.onContentClick}
isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive}
isContentActive={this._props.childContentsActive ?? this._props.isContentActive() === false ? returnFalse : emptyFunction}
hideCaptions={!!carouselShowsCaptions} // hide captions if the carousel is configured to show the captions
@@ -78,7 +78,6 @@ export class CollectionCarouselView extends CollectionSubView() {
Document={curDoc.layout}
TemplateDataDocument={DocCast(curDoc.layout.resolvedDataDoc)}
PanelHeight={this.panelHeight}
- bringToFront={returnFalse}
/>
</div>
{!carouselShowsCaptions ? null : (
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 874cdffd9..87973fd81 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
import * as GoldenLayout from '../../../client/goldenLayout';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
-import { AclAdmin, AclEdit } from '../../../fields/DocSymbols';
+import { AclAdmin, AclEdit, DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
@@ -277,8 +277,8 @@ export class CollectionDockingView extends CollectionSubView() {
}
setupGoldenLayout = async () => {
if (this._unmounting) return;
- //const config = StrCast(this._props.Document.dockingConfig, JSON.stringify(DashboardView.resetDashboard(this._props.Document)));
- const config = StrCast(this._props.Document.dockingConfig);
+ //const config = StrCast(this.Document.dockingConfig, JSON.stringify(DashboardView.resetDashboard(this.Document)));
+ const config = StrCast(this.Document.dockingConfig);
if (config) {
const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g);
const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) ?? [];
@@ -322,7 +322,7 @@ export class CollectionDockingView extends CollectionSubView() {
);
new _global.ResizeObserver(this.onResize).observe(this._containerRef.current);
this._reactionDisposer = reaction(
- () => StrCast(this._props.Document.dockingConfig),
+ () => StrCast(this.Document.dockingConfig),
config => {
if (!this._goldenLayout || this._ignoreStateChange !== config) {
// bcz: TODO! really need to diff config with ignoreStateChange and modify the current goldenLayout instead of building a new one.
@@ -381,7 +381,7 @@ export class CollectionDockingView extends CollectionSubView() {
.map(id => DocServer.GetCachedRefField(id))
.filter(f => f)
.map(f => f as Doc);
- const changesMade = this._props.Document.dockingConfig !== json;
+ const changesMade = this.Document.dockingConfig !== json;
if (changesMade) {
if (![AclAdmin, AclEdit].includes(GetEffectiveAcl(this.dataDoc))) {
this.layoutDoc.dockingConfig = json;
@@ -431,7 +431,7 @@ export class CollectionDockingView extends CollectionSubView() {
};
public CaptureThumbnail() {
- const content = this._props.DocumentView?.()?.ContentDiv;
+ const content = this.DocumentView?.()?.ContentDiv;
if (content) {
const _width = Number(getComputedStyle(content).width.replace('px', ''));
const _height = Number(getComputedStyle(content).height.replace('px', ''));
@@ -449,7 +449,7 @@ export class CollectionDockingView extends CollectionSubView() {
if (clone) {
const cloned = await Doc.MakeClone(doc);
Array.from(cloned.map.entries()).map(entry => (json = json.replace(entry[0], entry[1][Id])));
- Doc.GetProto(cloned.clone).dockingConfig = json;
+ cloned.clone[DocData].dockingConfig = json;
return DashboardView.openDashboard(cloned.clone);
}
const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g);
@@ -463,7 +463,7 @@ export class CollectionDockingView extends CollectionSubView() {
const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true, undefined, true) : Doc.MakeEmbedding(origtab);
const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeEmbedding(origtabdoc));
if (newtabdocs.length) {
- Doc.GetProto(newtab).data = new List<Doc>(newtabdocs);
+ newtab[DocData].data = new List<Doc>(newtabdocs);
newtabdocs.forEach(ntab => Doc.SetContainer(ntab, newtab));
}
json = json.replace(origtab[Id], newtab[Id]);
@@ -479,7 +479,7 @@ export class CollectionDockingView extends CollectionSubView() {
stateChanged = () => {
this._ignoreStateChange = JSON.stringify(this._goldenLayout.toConfig());
const json = JSON.stringify(this._goldenLayout.toConfig());
- const changesMade = this._props.Document.dockingConfig !== json;
+ const changesMade = this.Document.dockingConfig !== json;
return changesMade;
};
@@ -490,7 +490,7 @@ export class CollectionDockingView extends CollectionSubView() {
// if you close a tab that is not embedded somewhere else (an embedded Doc can be opened simultaneously in a tab), then add the tab to recently closed
if (tab.DashDoc.embedContainer === this.Document) tab.DashDoc.embedContainer = undefined;
if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
- Doc.RemoveDocFromList(Doc.GetProto(tab.DashDoc), 'proto_embeddings', tab.DashDoc);
+ Doc.RemoveDocFromList(tab.DashDoc[DocData], 'proto_embeddings', tab.DashDoc);
}
if (CollectionDockingView.Instance) {
const dview = CollectionDockingView.Instance.Document;
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 8627ba650..41c5d5b42 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -71,7 +71,7 @@ export class CollectionMasonryViewFieldRow extends ObservableReactComponent<CMVF
if (ele) {
this._ele = ele;
this._props.observeHeight(ele);
- this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this));
+ this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this), this._props.Document);
}
};
@action
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 98ae01591..0f90818ef 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -19,14 +19,17 @@ import { undoBatch } from '../../util/UndoManager';
import { AntimodeMenu } from '../AntimodeMenu';
import { EditableView } from '../EditableView';
import { MainView } from '../MainView';
-import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView';
+import { DocumentView, DocumentViewInternal, returnEmptyDocViewList } from '../nodes/DocumentView';
import { DefaultStyleProvider } from '../StyleProvider';
import { CollectionLinearView } from './collectionLinear';
import './CollectionMenu.scss';
+import { DocData } from '../../../fields/DocSymbols';
interface CollectionMenuProps {
panelHeight: () => number;
panelWidth: () => number;
+ toggleTopBar: () => void;
+ topBarHeight: () => number;
}
@observer
@@ -66,15 +69,6 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
};
@action
- toggleTopBar = () => {
- if (SettingsManager.Instance.headerBarHeight > 0) {
- SettingsManager.Instance.headerBarHeight = 0;
- } else {
- SettingsManager.Instance.headerBarHeight = 60;
- }
- };
-
- @action
toggleProperties = () => {
if (MainView.Instance.propertiesWidth() > 0) {
SettingsManager.Instance.propertiesWidth = 0;
@@ -95,16 +89,14 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
<div className="collectionMenu-contMenuButtons" ref={this._docBtnRef} style={{ height: this._props.panelHeight() }}>
<CollectionLinearView
Document={selDoc}
+ docViewPath={returnEmptyDocViewList}
fieldKey="data"
dropAction="embed"
- setHeight={returnFalse}
styleProvider={DefaultStyleProvider}
- bringToFront={emptyFunction}
select={emptyFunction}
isContentActive={returnTrue}
isAnyChildContentActive={returnFalse}
isSelected={returnFalse}
- docViewPath={returnEmptyDoclist}
moveDocument={returnFalse}
addDocument={returnFalse}
addDocTab={DocumentViewInternal.addDocTabFunc}
@@ -125,8 +117,8 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
}
render() {
- const headerIcon = SettingsManager.Instance.headerBarHeight > 0 ? 'angle-double-up' : 'angle-double-down';
- const headerTitle = SettingsManager.Instance.headerBarHeight > 0 ? 'Close Header Bar' : 'Open Header Bar';
+ const headerIcon = this.props.topBarHeight() > 0 ? 'angle-double-up' : 'angle-double-down';
+ const headerTitle = this.props.topBarHeight() > 0 ? 'Close Header Bar' : 'Open Header Bar';
const propIcon = SettingsManager.Instance.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left';
const propTitle = SettingsManager.Instance.propertiesWidth > 0 ? 'Close Properties' : 'Open Properties';
@@ -136,8 +128,8 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
toggleType={ToggleType.BUTTON}
type={Type.PRIM}
color={SettingsManager.userColor}
- onClick={this.toggleTopBar}
- toggleStatus={SettingsManager.Instance.headerBarHeight > 0}
+ onClick={this.props.toggleTopBar}
+ toggleStatus={this.props.topBarHeight() > 0}
icon={<FontAwesomeIcon icon={headerIcon} size="lg" />}
tooltip={headerTitle}
/>
@@ -221,7 +213,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
params: ['target', 'source'],
title: 'set content',
script: 'getProto(this.target).data = copyField(this.source);',
- immediate: undoBatch((source: Doc[]) => (Doc.GetProto(this.target).data = new List<Doc>(source))),
+ immediate: undoBatch((source: Doc[]) => (this.target[DocData].data = new List<Doc>(source))),
initialize: emptyFunction,
};
_onClickCommand = {
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 302ccd2db..f1b4780cf 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -1,6 +1,6 @@
-import * as React from 'react';
import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
+import * as React from 'react';
import { Doc, Field, Opt } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
import { Copy, Id } from '../../../fields/FieldSymbols';
@@ -18,8 +18,8 @@ import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { LightboxView } from '../LightboxView';
-import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView';
-import { FieldViewProps } from '../nodes/FieldView';
+import { DocumentView } from '../nodes/DocumentView';
+import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { StyleProp } from '../StyleProvider';
import './CollectionNoteTakingView.scss';
@@ -51,7 +51,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
}
@computed get chromeHidden() {
- return BoolCast(this.layoutDoc.chromeHidden) || this._props.onBrowseClick?.() ? true : false;
+ return BoolCast(this.layoutDoc.chromeHidden) || this._props.onBrowseClickScript?.() ? true : false;
}
// columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns
@computed get colHeaderData() {
@@ -189,7 +189,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
};
// let's dive in and get the actual document we want to drag/move around
- focusDocument = (doc: Doc, options: DocFocusOptions) => {
+ focusDocument = (doc: Doc, options: FocusViewOptions) => {
Doc.BrushDoc(doc);
const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
if (found) {
@@ -203,7 +203,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
}
};
- styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => {
+ styleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => {
switch (property) {
case StyleProp.BoxShadow:
if (doc && DragManager.docsBeingDragged.includes(doc)) {
@@ -238,7 +238,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
PanelWidth={width}
PanelHeight={height}
styleProvider={this.styleProvider}
- docViewPath={this._props.docViewPath}
+ containerViewPath={this.childContainerViewPath}
layout_fitWidth={this._props.childLayoutFitWidth}
isContentActive={emptyFunction}
onKey={this.onKeyDown}
@@ -254,9 +254,9 @@ export class CollectionNoteTakingView extends CollectionSubView() {
rootSelected={this.rootSelected}
layout_showTitle={this._props.childlayout_showTitle}
dragAction={StrCast(this.layoutDoc.childDragAction) as dropActionType}
- onClick={this.onChildClickHandler}
- onBrowseClick={this._props.onBrowseClick}
- onDoubleClick={this.onChildDoubleClickHandler}
+ onClickScript={this.onChildClickHandler}
+ onBrowseClickScript={this._props.onBrowseClickScript}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
ScreenToLocalTransform={noteTakingDocTransform}
focus={this.focusDocument}
childFilters={this.childDocFilters}
@@ -267,10 +267,9 @@ export class CollectionNoteTakingView extends CollectionSubView() {
addDocument={this._props.addDocument}
moveDocument={this._props.moveDocument}
removeDocument={this._props.removeDocument}
- contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents) as any}
+ contentPointerEvents={StrCast(this.layoutDoc.childContentPointerEvents) as any}
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
addDocTab={this._props.addDocTab}
- bringToFront={returnFalse}
pinToPres={this._props.pinToPres}
/>
);
@@ -407,11 +406,10 @@ export class CollectionNoteTakingView extends CollectionSubView() {
@undoBatch
onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
- const docView = fieldProps.DocumentView?.();
- if (docView && (e.ctrlKey || docView.Document._createDocOnCR) && ['Enter'].includes(e.key)) {
+ if ((e.ctrlKey || fieldProps.Document._createDocOnCR) && ['Enter'].includes(e.key)) {
e.stopPropagation?.();
- const newDoc = Doc.MakeCopy(docView.Document, true);
- Doc.GetProto(newDoc).text = undefined;
+ const newDoc = Doc.MakeCopy(fieldProps.Document, true);
+ newDoc[DocData].text = undefined;
FormattedTextBox.SetSelectOnLoad(newDoc);
return this.addDocument?.(newDoc);
}
@@ -443,7 +441,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
}
return true;
}
- } else if (de.complete.linkDragData?.dragDocument.embedContainer === this._props.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) {
+ } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) {
const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' });
if (!this._props.addDocument?.(source)) e.preventDefault();
de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed
@@ -511,7 +509,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
action((entries: any) => {
if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) {
const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))));
- if (!LightboxView.IsLightboxDocView(this._props.docViewPath())) {
+ if (!LightboxView.Contains(this.DocumentView?.())) {
this._props.setHeight?.(height);
}
}
@@ -643,7 +641,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
onDragOver={e => this.onPointerMove(true, e.clientX, e.clientY)}
onDrop={this.onExternalDrop.bind(this)}
onContextMenu={this.onContextMenu}
- onWheel={e => this._props.isContentActive(true) && e.stopPropagation()}>
+ onWheel={e => this._props.isContentActive() && e.stopPropagation()}>
{this.renderedSections}
</div>
);
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
index 3f6d3c82e..38846c79d 100644
--- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -81,7 +81,7 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV
if (ele) {
this._ele = ele;
this._props.observeHeight(ele);
- this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this));
+ this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document);
}
};
@@ -90,11 +90,11 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV
}
@undoBatch
- columnDrop = action((e: Event, de: DragManager.DropEvent) => {
+ columnDrop = (e: Event, de: DragManager.DropEvent) => {
const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) };
drop.docs?.forEach(d => Doc.SetInPlace(d, this._props.pivotField, drop.val, false));
return true;
- });
+ };
getValue = (value: string): any => {
const parsed = parseInt(value);
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index b1d379631..d0df77cbe 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -48,7 +48,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.dataDoc[this.fieldKey ?? 'data']).length) this._props.DocumentView?.()._props.removeDocument?.(this.Document);
+ if (ret && !DocListCast(this.dataDoc[this.fieldKey ?? 'data']).length) this.DocumentView?.()._props.removeDocument?.(this.Document);
return ret;
};
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 22a67c501..5c47d4b9e 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -3,6 +3,7 @@ import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
import * as React from 'react';
import { Doc, Opt } from '../../../fields/Doc';
+import { DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { listSpec } from '../../../fields/Schema';
@@ -23,17 +24,17 @@ import { undoBatch, UndoManager } from '../../util/UndoManager';
import { CollectionSubView } from '../collections/CollectionSubView';
import { LightboxView } from '../LightboxView';
import { AudioWaveform } from '../nodes/audio/AudioWaveform';
-import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView';
+import { DocumentView, OpenWhere } from '../nodes/DocumentView';
+import { FocusFuncType, FocusViewOptions, StyleProviderFuncType } from '../nodes/FieldView';
import { LabelBox } from '../nodes/LabelBox';
import { VideoBox } from '../nodes/VideoBox';
import { ObservableReactComponent } from '../ObservableReactComponent';
import './CollectionStackedTimeline.scss';
-import { FieldViewProps } from '../nodes/FieldView';
export type CollectionStackedTimelineProps = {
Play: () => void;
Pause: () => void;
- playLink: (linkDoc: Doc, options: DocFocusOptions) => void;
+ playLink: (linkDoc: Doc, options: FocusViewOptions) => void;
playFrom: (seekTimeInSeconds: number, endTime?: number) => void;
playing: () => boolean;
thumbnails?: () => string[];
@@ -162,7 +163,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
makeDocUnfiltered = (doc: Doc) => this.childDocList?.some(item => item === doc);
- getView = async (doc: Doc, options: DocFocusOptions): Promise<Opt<DocumentView>> =>
+ getView = async (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> =>
new Promise<Opt<DocumentView>>(res => {
if (doc.hidden) options.didMove = !(doc.hidden = false);
const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv));
@@ -427,8 +428,8 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
_isTimelineLabel: true,
layout_borderRounding: anchorEndTime === undefined ? '100%' : undefined,
});
- Doc.GetProto(anchor)[startTag] = anchorStartTime;
- Doc.GetProto(anchor)[endTag] = anchorEndTime;
+ anchor[DocData][startTag] = anchorStartTime;
+ anchor[DocData][endTag] = anchorEndTime;
if (addAsAnnotation) {
if (Cast(dataDoc[fieldKey], listSpec(Doc), null)) {
Cast(dataDoc[fieldKey], listSpec(Doc), []).push(anchor);
@@ -579,7 +580,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
const timespan = Math.max(0, Math.min(end - this.clipStart, this.clipEnd)) - Math.max(0, start - this.clipStart);
const width = (timespan / this.clipDuration) * this.timelineContentWidth;
const height = this._props.PanelHeight() / maxLevel;
- return this._props.Document.hideAnchors ? null : (
+ return this.Document.hideAnchors ? null : (
<div
className={'collectionStackedTimeline-marker-timeline'}
key={d.anchor[Id]}
@@ -691,8 +692,8 @@ interface StackedTimelineAnchorProps {
width: number;
height: number;
toTimeline: (screen_delta: number, width: number) => number;
- styleProvider?: StyleProviderFunc;
- playLink: (linkDoc: Doc, options: DocFocusOptions) => void;
+ styleProvider?: StyleProviderFuncType;
+ playLink: (linkDoc: Doc, options: FocusViewOptions) => void;
setTime: (time: number) => void;
startTag: string;
endTag: string;
@@ -701,7 +702,7 @@ interface StackedTimelineAnchorProps {
isDocumentActive?: () => boolean | undefined;
ScreenToLocalTransform: () => Transform;
_timeline: HTMLDivElement | null;
- focus: DocFocusFunc;
+ focus: FocusFuncType;
currentTimecode: () => number;
isSelected: () => boolean;
stackedTimeline: CollectionStackedTimeline;
@@ -810,7 +811,7 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch
// renders anchor LabelBox
renderInner = computedFn(function (this: StackedTimelineAnchor, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), screenXf: () => Transform, width: () => number, height: () => number) {
const anchor = observable({ view: undefined as Opt<DocumentView> | null });
- const focusFunc = (doc: Doc, options: DocFocusOptions): number | undefined => {
+ const focusFunc = (doc: Doc, options: FocusViewOptions): number | undefined => {
this._props.playLink(mark, options);
return undefined;
};
@@ -825,7 +826,7 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch
ref={action((r: DocumentView | null) => (anchor.view = r))}
Document={mark}
TemplateDataDocument={undefined}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
pointerEvents={this.noEvents ? returnNone : undefined}
styleProvider={this._props.styleProvider}
renderDepth={this._props.renderDepth + 1}
@@ -842,11 +843,10 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch
searchFilterDocs={returnEmptyDoclist}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
- onClick={script}
- onDoubleClick={this._props.layoutDoc.autoPlayAnchors ? undefined : doublescript}
+ onClickScript={script}
+ onDoubleClickScript={this._props.layoutDoc.autoPlayAnchors ? undefined : doublescript}
ignoreAutoHeight={false}
hideResizeHandles={true}
- bringToFront={emptyFunction}
contextMenuItems={this.contextMenuItems}
/>
),
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 995f071ca..89e72152a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -24,8 +24,8 @@ import { ContextMenuProps } from '../ContextMenuItem';
import { EditableView } from '../EditableView';
import { LightboxView } from '../LightboxView';
import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
-import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView';
-import { FieldViewProps } from '../nodes/FieldView';
+import { DocumentView } from '../nodes/DocumentView';
+import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { StyleProp } from '../StyleProvider';
import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow';
@@ -203,7 +203,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
componentDidMount() {
super.componentDidMount?.();
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
// reset section headers when a new filter is inputted
this._pivotFieldDisposer = reaction(
@@ -249,7 +249,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
};
// let's dive in and get the actual document we want to drag/move around
- focusDocument = (doc: Doc, options: DocFocusOptions) => {
+ focusDocument = (doc: Doc, options: FocusViewOptions) => {
Doc.BrushDoc(doc);
const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
@@ -265,7 +265,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return undefined;
};
- styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => {
+ styleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => {
if (property === StyleProp.Opacity && doc) {
if (this._props.childOpacity) {
return this._props.childOpacity();
@@ -278,18 +278,17 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
};
@undoBatch
onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
- const docView = fieldProps.DocumentView?.();
- if (docView && ['Enter'].includes(e.key) && e.ctrlKey) {
+ if (['Enter'].includes(e.key) && e.ctrlKey) {
e.stopPropagation?.();
const below = !e.altKey && e.key !== 'Tab';
- const layout_fieldKey = StrCast(docView.LayoutFieldKey);
- const newDoc = Doc.MakeCopy(docView.Document, true);
- const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)];
+ const layout_fieldKey = StrCast(fieldProps.fieldKey);
+ const newDoc = Doc.MakeCopy(fieldProps.Document, true);
+ const dataField = fieldProps.Document[Doc.LayoutFieldKey(newDoc)];
newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
- if (layout_fieldKey !== 'layout' && docView.Document[layout_fieldKey] instanceof Doc) {
- newDoc[layout_fieldKey] = docView.Document[layout_fieldKey];
+ if (layout_fieldKey !== 'layout' && fieldProps.Document[layout_fieldKey] instanceof Doc) {
+ newDoc[layout_fieldKey] = fieldProps.Document[layout_fieldKey];
}
- Doc.GetProto(newDoc).text = undefined;
+ newDoc[DocData].text = undefined;
FormattedTextBox.SetSelectOnLoad(newDoc);
return this.addDocument?.(newDoc);
}
@@ -325,13 +324,13 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
renderDepth={this._props.renderDepth + 1}
PanelWidth={panelWidth}
PanelHeight={panelHeight}
- pointerEvents={this._props.DocumentView?.()._props.onClick?.() ? returnNone : undefined} // if the stack has an onClick, then we don't want the contents to be interactive (see CollectionPileView)
+ pointerEvents={this.DocumentView?.()._props.onClickScript?.() ? returnNone : undefined} // if the stack has an onClick, then we don't want the contents to be interactive (see CollectionPileView)
styleProvider={this.styleProvider}
- docViewPath={this._props.docViewPath}
+ containerViewPath={this.childContainerViewPath}
layout_fitWidth={this.childFitWidth}
isContentActive={doc.onClick ? this.isChildButtonContentActive : this.isChildContentActive}
onKey={this.onKeyDown}
- onBrowseClick={this._props.onBrowseClick}
+ onBrowseClickScript={this._props.onBrowseClickScript}
isDocumentActive={this.isContentActive}
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
@@ -342,8 +341,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
rootSelected={this.rootSelected}
layout_showTitle={this._props.childlayout_showTitle}
dragAction={(this.layoutDoc.childDragAction ?? this._props.childDragAction) as dropActionType}
- onClick={this.onChildClickHandler}
- onDoubleClick={this.onChildDoubleClickHandler}
+ onClickScript={this.onChildClickHandler}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
ScreenToLocalTransform={stackedDocTransform}
focus={this.focusDocument}
childFilters={this.childDocFilters}
@@ -356,10 +355,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
addDocument={this._props.addDocument}
moveDocument={this._props.moveDocument}
removeDocument={this._props.removeDocument}
- contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents) as any}
+ contentPointerEvents={StrCast(this.layoutDoc.childContentPointerEvents) as any}
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
addDocTab={this._props.addDocTab}
- bringToFront={returnFalse}
pinToPres={this._props.pinToPres}
/>
);
@@ -469,7 +467,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}
return true;
}
- } else if (de.complete.linkDragData?.dragDocument.embedContainer === this._props.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) {
+ } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) {
const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' });
if (!this._props.addDocument?.(source)) e.preventDefault();
de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed
@@ -540,7 +538,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
action((entries: any) => {
if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) {
const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))));
- if (!LightboxView.IsLightboxDocView(this._props.docViewPath())) {
+ if (!LightboxView.Contains(this.DocumentView?.())) {
this._props.setHeight?.(height);
}
}
@@ -552,7 +550,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
addDocument={this.addDocument}
chromeHidden={this.chromeHidden}
colHeaderData={this.colHeaderData}
- Document={this._props.Document}
+ Document={this.Document}
TemplateDataDocument={this._props.TemplateDataDocument}
renderChildren={this.children}
columnWidth={this.columnWidth}
@@ -584,7 +582,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return (
<CollectionMasonryViewFieldRow
showHandle={first}
- Document={this._props.Document}
+ Document={this.Document}
chromeHidden={this.chromeHidden}
pivotField={this.pivotField}
unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)}
@@ -671,7 +669,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
addDocument={this._props.addDocument}
moveDocument={this._props.moveDocument}
addDocTab={this._props.addDocTab}
- onBrowseClick={this._props.onBrowseClick}
+ onBrowseClickScript={this._props.onBrowseClickScript}
pinToPres={emptyFunction}
rootSelected={this.rootSelected}
removeDocument={this._props.removeDocument}
@@ -681,9 +679,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
renderDepth={this._props.renderDepth}
focus={emptyFunction}
styleProvider={this._props.styleProvider}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
childFilters={this._props.childFilters}
childFiltersByRanges={this._props.childFiltersByRanges}
searchFilterDocs={this._props.searchFilterDocs}
@@ -739,7 +736,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
onWheel={e => this.isContentActive() && e.stopPropagation()}>
{this.renderedSections}
{!this.showAddAGroup ? null : (
- <div key={`${this._props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton" style={{ width: !this.isStackingView ? '100%' : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}>
+ <div key={`${this.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton" style={{ width: !this.isStackingView ? '100%' : this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}>
<EditableView {...editableViewProps} />
</div>
)}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 69f1c332d..c455f20d8 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -74,7 +74,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
if (ele) {
this._ele = ele;
this._props.observeHeight(ele);
- this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this));
+ this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document);
}
};
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 570330174..fdbd1cc90 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -62,17 +62,16 @@ export function CollectionSubView<X>(moreProps?: X) {
}
get dataDoc() {
- return this._props.TemplateDataDocument instanceof Doc && this._props.Document.isTemplateForField
- ? Doc.GetProto(this._props.TemplateDataDocument)
- : this._props.Document.resolvedDataDoc
- ? this._props.Document
- : Doc.GetProto(this._props.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
+ return this._props.TemplateDataDocument instanceof Doc && this.Document.isTemplateForField ? Doc.GetProto(this._props.TemplateDataDocument) : this.Document.resolvedDataDoc ? this.Document : Doc.GetProto(this.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
}
+ get childContainerViewPath() {
+ return this.DocumentView?.().docViewPath;
+ }
// this returns whether either the collection is selected, or the template that it is part of is selected
rootSelected = () => this._props.isSelected() || BoolCast(this._props.TemplateDataDocument && this._props.rootSelected?.());
- // The data field for rendering this collection will be on the this._props.Document unless we're rendering a template in which case we try to use props.TemplateDataDocument.
+ // The data field for rendering this collection will be on the this.Document unless we're rendering a template in which case we try to use props.TemplateDataDocument.
// When a document has a TemplateDataDoc but it's not a template, then it contains its own rendering data, but needs to pass the TemplateDataDoc through
// to its children which may be templates.
// If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey'
@@ -93,14 +92,14 @@ export function CollectionSubView<X>(moreProps?: X) {
@computed get childDocList() {
return Cast(this.dataField, listSpec(Doc));
}
- collectionFilters = () => this._focusFilters ?? StrListCast(this._props.Document._childFilters);
- collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this._props.Document._childFiltersByRanges, listSpec('string'), []);
+ collectionFilters = () => this._focusFilters ?? StrListCast(this.Document._childFilters);
+ collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.Document._childFiltersByRanges, listSpec('string'), []);
// child filters apply to the descendants of the documents in this collection
childDocFilters = () => [...(this._props.childFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()];
// unrecursive filters apply to the documents in the collection, but no their children. See Utils.noRecursionHack
unrecursiveDocFilters = () => [...(this._props.childFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])];
childDocRangeFilters = () => [...(this._props.childFiltersByRanges?.() || []), ...this.collectionRangeDocFilters()];
- searchFilterDocs = () => this._props.searchFilterDocs?.() ?? DocListCast(this._props.Document._searchFilterDocs);
+ searchFilterDocs = () => this._props.searchFilterDocs?.() ?? DocListCast(this.Document._searchFilterDocs);
@computed.struct get childDocs() {
TraceMobx();
let rawdocs: (Doc | Promise<Doc>)[] = [];
@@ -123,7 +122,7 @@ export function CollectionSubView<X>(moreProps?: X) {
const childDocFilters = this.childDocFilters();
const childFiltersByRanges = this.childDocRangeFilters();
const searchDocs = this.searchFilterDocs();
- if (this._props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) {
+ if (this.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) {
return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one
}
@@ -132,9 +131,9 @@ export function CollectionSubView<X>(moreProps?: X) {
// dragging facets
const dragged = this._props.childFilters?.().some(f => f.includes(Utils.noDragDocsFilter));
if (dragged && SnappingManager.CanEmbed && DragManager.docsBeingDragged.includes(d)) return false;
- let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this._props.Document).length > 0;
+ let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this.Document).length > 0;
if (notFiltered) {
- notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this._props.Document).length > 0;
+ notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this.Document).length > 0;
const fieldKey = Doc.LayoutFieldKey(d);
const annos = !Field.toString(Doc.LayoutField(d) as Field).includes(CollectionView.name);
const data = d[annos ? fieldKey + '_annotations' : fieldKey];
@@ -167,7 +166,7 @@ export function CollectionSubView<X>(moreProps?: X) {
@action
protected async setCursorPosition(position: [number, number]) {
let ind;
- const doc = this._props.Document;
+ const doc = this.Document;
const id = Doc.UserDoc()[Id];
const email = Doc.CurrentUserEmail;
const pos = { x: position[0], y: position[1] };
@@ -197,13 +196,11 @@ export function CollectionSubView<X>(moreProps?: X) {
@undoBatch
protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {}
- protected onInternalPreDrop(e: Event, de: DragManager.DropEvent) {
+ protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, dropAction: dropActionType) {
if (de.complete.docDragData) {
- // override the dropEvent's dropAction
- const dropAction = this.layoutDoc.dropAction as dropActionType;
// if the dropEvent's dragAction is, say 'embed', but we're just dragging within a collection, we may not actually want to make an embedding.
// so we check if our collection has a dropAction set on it and if so, we use that instead.
- if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this._props.Document && this.childDocs.includes(d))) {
+ if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.Document && this.childDocs.includes(d))) {
de.complete.docDragData.dropAction = dropAction;
}
e.stopPropagation();
@@ -467,7 +464,7 @@ export function CollectionSubView<X>(moreProps?: X) {
}
if (generatedDocuments.length) {
// Creating a dash document
- const isFreeformView = this._props.Document._type_collection === CollectionViewType.Freeform;
+ const isFreeformView = this.Document._type_collection === CollectionViewType.Freeform;
const set = !isFreeformView
? generatedDocuments
: generatedDocuments.length > 1
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 7036ec41c..ee5147428 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -16,7 +16,8 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { EditableView } from '../EditableView';
-import { DocFocusOptions, DocumentView } from '../nodes/DocumentView';
+import { DocumentView } from '../nodes/DocumentView';
+import { FocusViewOptions } from '../nodes/FieldView';
import { PresBox } from '../nodes/trails';
import { CollectionSubView } from './CollectionSubView';
import './CollectionTimeView.scss';
@@ -38,7 +39,7 @@ export class CollectionTimeView extends CollectionSubView() {
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
runInAction(() => {
this._childClickedScript = ScriptField.MakeScript('openInLightbox(this)', { this: Doc.name });
this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' });
@@ -68,7 +69,7 @@ export class CollectionTimeView extends CollectionSubView() {
};
@action
- scrollPreview = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: DocFocusOptions) => {
+ scrollPreview = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: FocusViewOptions) => {
// if in preview, then override document's fields with view spec
this._focusFilters = StrListCast(anchor.config_docFilters);
this._focusRangeFilters = StrListCast(anchor.config_docRangeFilters);
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 18e0b98ef..741013148 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -140,20 +140,20 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
if ((this._mainEle = ele)) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.Document, this.onInternalPreDrop.bind(this));
};
- protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent) => {
- const dropAction = this.layoutDoc.dropAction as dropActionType;
+ protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent, dropAction: dropActionType) => {
const dragData = de.complete.docDragData;
if (dragData) {
const sameTree = Doc.AreProtosEqual(dragData.treeViewDoc, this.Document) ? true : false;
const isAlreadyInTree = () => sameTree || dragData.draggedDocuments.some(d => d.embedContainer === this.Document && this.childDocs.includes(d));
- if (isAlreadyInTree() !== sameTree) {
- console.log('WHAAAT');
- }
dragData.dropAction = dropAction && !isAlreadyInTree() ? dropAction : sameTree && dragData.dropAction !== 'inSame' ? 'same' : dragData.dropAction;
e.stopPropagation();
}
};
+ configDrag = (dragData: DragManager.DocumentDragData) => {
+ dragData.treeViewDoc = this.Document;
+ };
+
screenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, -this._headerHeight);
@action
@@ -169,7 +169,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
this._props.removeDocument?.(doc);
if (ind > 0 && prev) {
FormattedTextBox.SetSelectOnLoad(prev);
- DocumentManager.Instance.getDocumentView(prev, this._props.DocumentView?.())?.select(false);
+ DocumentManager.Instance.getDocumentView(prev, this.DocumentView?.())?.select(false);
}
return true;
}
@@ -254,7 +254,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
moveDocument={returnFalse}
removeDocument={returnFalse}
whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
- bringToFront={returnFalse}
/>
);
}
@@ -347,9 +346,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
renderDepth={this._props.renderDepth + 1}
focus={emptyFunction}
styleProvider={this._props.styleProvider}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
childFilters={this._props.childFilters}
childFiltersByRanges={this._props.childFiltersByRanges}
searchFilterDocs={this._props.searchFilterDocs}
@@ -447,20 +445,19 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
{!(this.Document instanceof Doc) || !this.treeChildren ? null : this.Document.treeView_HasOverlay ? (
<CollectionFreeFormView
{...this._props}
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}
pointerEvents={this._props.isContentActive() && SnappingManager.IsDragging ? returnAll : returnNone}
isAnnotationOverlay={true}
isAnnotationOverlayScrollable={true}
- childDocumentsActive={this._props.isDocumentActive}
+ childDocumentsActive={this._props.isContentActive}
fieldKey={this._props.fieldKey + '_annotations'}
dropAction="move"
select={emptyFunction}
addDocument={this.addAnnotationDocument}
removeDocument={this.remAnnotationDocument}
moveDocument={this.moveAnnotationDocument}
- bringToFront={emptyFunction}
renderDepth={this._props.renderDepth + 1}>
{this.content}
</CollectionFreeFormView>
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 4a239e4b1..18eb4dd1f 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -13,7 +13,7 @@ import { dropActionType } from '../../util/DragManager';
import { ImageUtils } from '../../util/Import & Export/ImageUtils';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
import { OpenWhere } from '../nodes/DocumentView';
import { FieldView, FieldViewProps } from '../nodes/FieldView';
import { CollectionCalendarView } from './CollectionCalendarView';
@@ -33,7 +33,7 @@ import { CollectionLinearView } from './collectionLinear';
import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView';
import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
import { CollectionSchemaView } from './collectionSchema/CollectionSchemaView';
-interface CollectionViewProps_ extends FieldViewProps {
+export interface CollectionViewProps extends React.PropsWithChildren<FieldViewProps> {
isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc)
isAnnotationOverlayScrollable?: boolean; // whether the annotation overlay can be vertically scrolled (just for tree views, currently)
layoutEngine?: () => string;
@@ -63,9 +63,8 @@ interface CollectionViewProps_ extends FieldViewProps {
RemFromMap?: (treeViewDoc: Doc, index: number[]) => void;
hierarchyIndex?: number[]; // hierarchical index of a document up to the rendering root (primarily used for tree views)
}
-export interface CollectionViewProps extends React.PropsWithChildren<CollectionViewProps_> {}
@observer
-export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & CollectionViewProps>() {
+export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldStr: string) {
return FieldView.LayoutString(CollectionView, fieldStr);
}
@@ -190,7 +189,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
!options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' });
- if (!Doc.noviceMode && !this.Document.annotationOn) {
+ if (!Doc.noviceMode && !this.Document.annotationOn && !this._props.hideClickBehaviors) {
const existingOnClick = cm.findByDescription('OnClick...');
const onClicks = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
const funcs = [
@@ -232,13 +231,9 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
childLayoutTemplate = () => this._props.childLayoutTemplate?.() || Cast(this.Document.childLayoutTemplate, Doc, null);
isContentActive = (outsideReaction?: boolean) => this._isContentActive;
- pointerEvents = () => {
- const viewPath = this._props.DocumentView?.()?._props.docViewPath();
- return (
- this.layoutDoc._lockedPosition && //
- viewPath?.lastElement()?.Document?._type_collection === CollectionViewType.Freeform
- );
- };
+ pointerEvents = () =>
+ this.layoutDoc._lockedPosition && //
+ this.Document?._type_collection === CollectionViewType.Freeform;
render() {
TraceMobx();
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 80808be92..9bc3ef822 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -29,7 +29,8 @@ import { LightboxView } from '../LightboxView';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { DefaultStyleProvider, StyleProp } from '../StyleProvider';
import { Colors } from '../global/globalEnums';
-import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
+import { DocumentView, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from '../nodes/DocumentView';
+import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView';
import { KeyValueBox } from '../nodes/KeyValueBox';
import { DashFieldView } from '../nodes/formattedText/DashFieldView';
import { PinProps, PresBox, PresMovement } from '../nodes/trails';
@@ -37,7 +38,6 @@ import { CollectionDockingView } from './CollectionDockingView';
import { CollectionView } from './CollectionView';
import './TabDocView.scss';
import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
-import { FieldViewProps } from '../nodes/FieldView';
const _global = (window /* browser */ || global) /* node */ as any;
interface TabDocViewProps {
@@ -118,7 +118,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
titleEle.onchange = (e: any) => {
undoable(() => {
titleEle.size = e.currentTarget.value.length + 3;
- Doc.GetProto(doc).title = e.currentTarget.value;
+ doc[DocData].title = e.currentTarget.value;
}, 'edit tab title')();
};
@@ -416,7 +416,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
return tab !== undefined;
};
@action
- focusFunc = (doc: Doc, options: DocFocusOptions) => {
+ focusFunc = (doc: Doc, options: FocusViewOptions) => {
if (!this.tab.header.parent._activeContentItem || this.tab.header.parent._activeContentItem !== this.tab.contentItem) {
this.tab.header.parent.setActiveContentItem(this.tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost)
}
@@ -452,7 +452,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
hideTitle={this._props.keyValue}
Document={this._document}
TemplateDataDocument={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined}
- onBrowseClick={DocumentView.exploreMode}
+ onBrowseClickScript={DocumentView.exploreMode}
waitForDoubleClickToClick={this.waitForDoubleClick}
isContentActive={this.isContentActive}
isDocumentActive={returnFalse}
@@ -469,8 +469,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
dontCenter={'y'}
whenChildContentsActiveChanged={this.whenChildContentActiveChanges}
focus={this.focusFunc}
- docViewPath={returnEmptyDoclist}
- bringToFront={emptyFunction}
+ containerViewPath={returnEmptyDoclist}
pinToPres={TabDocView.PinDoc}
/>
{this.disableMinimap() ? null : <TabMinimapView key="minimap" addDocTab={this.addDocTab} PanelHeight={this.PanelHeight} PanelWidth={this.PanelWidth} background={this.miniMapColor} document={this._document} tabView={this.tabView} />}
@@ -528,7 +527,7 @@ class TabMiniThumb extends React.Component<TabMiniThumbProps> {
}
@observer
export class TabMinimapView extends ObservableReactComponent<TabMinimapViewProps> {
- static miniStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ static miniStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => {
if (doc) {
switch (property.split(':')[0]) {
default:
@@ -595,17 +594,15 @@ export class TabMinimapView extends ObservableReactComponent<TabMinimapViewProps
<div className="miniMap" style={{ width: miniSize, height: miniSize, background: this._props.background() }}>
<CollectionFreeFormView
Document={this._props.document}
- docViewPath={returnEmptyDoclist}
+ docViewPath={returnEmptyDocViewList}
childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
noOverlay={true} // don't render overlay Docs since they won't scale
- setHeight={returnFalse}
isContentActive={emptyFunction}
isAnyChildContentActive={returnFalse}
select={emptyFunction}
isSelected={returnFalse}
dontRegisterView={true}
fieldKey={Doc.LayoutFieldKey(this._props.document)}
- bringToFront={emptyFunction}
addDocument={returnFalse}
moveDocument={returnFalse}
removeDocument={returnFalse}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 01b80e209..be5737a25 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -4,7 +4,7 @@ import { IconButton, Size } from 'browndash-components';
import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Utils, emptyFunction, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick } from '../../../Utils';
+import { Utils, emptyFunction, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick } from '../../../Utils';
import { Doc, DocListCast, Field, FieldResult, Opt, StrListCast } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
@@ -27,8 +27,8 @@ import { UndoManager, undoBatch, undoable } from '../../util/UndoManager';
import { EditableView } from '../EditableView';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { StyleProp } from '../StyleProvider';
-import { DocumentView, DocumentViewInternal, DocumentViewInternalProps, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView';
-import { FieldViewProps } from '../nodes/FieldView';
+import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView';
+import { FieldViewProps, StyleProviderFuncType } from '../nodes/FieldView';
import { KeyValueBox } from '../nodes/KeyValueBox';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
@@ -62,7 +62,7 @@ export interface TreeViewProps {
ScreenToLocalTransform: () => Transform;
contextMenuItems?: { script: ScriptField; filter: ScriptField; icon: string; label: string }[];
dontRegisterView?: boolean;
- styleProvider?: StyleProviderFunc | undefined;
+ styleProvider?: StyleProviderFuncType | undefined;
treeViewHideHeaderFields: () => boolean;
renderedIds: string[]; // list of document ids rendered used to avoid unending expansion of items in a cycle
onCheckedClick?: () => ScriptField;
@@ -198,7 +198,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
const ind = DocListCast(this.dataDoc[key]).indexOf(doc instanceof Doc ? doc : doc.lastElement());
const res = (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true);
- res && ind > 0 && DocumentManager.Instance.getDocumentView(DocListCast(this.dataDoc[key])[ind - 1], this.treeView._props.DocumentView?.())?.select(false);
+ res && ind > 0 && DocumentManager.Instance.getDocumentView(DocListCast(this.dataDoc[key])[ind - 1], this.treeView.DocumentView?.())?.select(false);
return res;
};
@@ -282,12 +282,13 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
_treeEle: any;
protected createTreeDropTarget = (ele: HTMLDivElement) => {
this._treedropDisposer?.();
- ele && ((this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), undefined, this.preTreeDrop.bind(this))), this.Document);
+ ele && ((this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), this.Document, this.preTreeDrop.bind(this))), this.Document);
if (this._treeEle) this._props.unobserveHeight(this._treeEle);
this._props.observeHeight((this._treeEle = ele));
};
componentWillUnmount() {
+ this._treedropDisposer?.();
this._renderTimer && clearTimeout(this._renderTimer);
Object.values(this._disposers).forEach(disposer => disposer?.());
this._treeEle && this._props.unobserveHeight(this._treeEle);
@@ -339,11 +340,9 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
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.treeView.outlineMode || DragManager.DocDragData?.treeViewDoc === this.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';
- }
+ 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';
e.stopPropagation();
};
@@ -367,8 +366,9 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
_width: 1000,
_height: 10,
});
- Doc.GetProto(bullet).title = ComputedField.MakeFunction('this.text?.Text');
- Doc.GetProto(bullet).data = new List<Doc>([]);
+ const bulletData = bullet[DocData];
+ bulletData.title = ComputedField.MakeFunction('this.text?.Text');
+ bulletData.data = new List<Doc>([]);
DocumentManager.Instance.AddViewRenderedCb(bullet, dv => dv.ComponentView?.setFocus?.());
return bullet;
@@ -386,9 +386,8 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
return this._props.addDocument(folder);
};
- preTreeDrop = (e: Event, de: DragManager.DropEvent) => {
- const dragData = de.complete.docDragData;
- dragData && (dragData.dropAction = this.treeView.Document === dragData.treeViewDoc ? 'same' : dragData.dropAction);
+ preTreeDrop = (e: Event, de: DragManager.DropEvent, docDropAction: dropActionType) => {
+ // fall through and let the CollectionTreeView handle this since treeView items have no special properties of their own
};
@undoBatch
@@ -415,7 +414,8 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
docDragData.dropAction,
docDragData.removeDocument,
docDragData.moveDocument,
- docDragData.treeViewDoc === this.treeView.Document
+ docDragData.treeViewDoc === this.treeView.Document,
+ de.embedKey
);
e.stopPropagation();
!added && e.preventDefault();
@@ -425,7 +425,16 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
};
dropping: boolean = false;
- dropDocuments(droppedDocuments: Doc[], before: boolean, inside: number | boolean, dropAction: dropActionType, removeDocument: DragManager.RemoveFunction | undefined, moveDocument: DragManager.MoveFunction | undefined, forceAdd: boolean) {
+ dropDocuments(
+ droppedDocuments: Doc[],
+ before: boolean,
+ inside: number | boolean,
+ dropAction: dropActionType,
+ removeDocument: DragManager.RemoveFunction | undefined,
+ moveDocument: DragManager.MoveFunction | undefined,
+ forceAdd: boolean,
+ canEmbed?: boolean
+ ) {
const parentAddDoc = (doc: Doc | Doc[]) => this._props.addDocument(doc, undefined, undefined, before);
const localAdd = (doc: Doc | Doc[]) => {
const innerAdd = (doc: Doc) => {
@@ -437,9 +446,9 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean);
};
const addDoc = inside ? localAdd : parentAddDoc;
- const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same' || dropAction === 'inSame') && moveDocument;
- const canAdd = (!this.treeView.outlineMode && !StrCast((inside ? this.Document : this._props.treeViewParent)?.treeView_FreezeChildren).includes('add')) || forceAdd;
+ const canAdd = !StrCast((inside ? this.Document : this._props.treeViewParent)?.treeView_FreezeChildren).includes('add') || forceAdd;
if (canAdd && (dropAction !== 'inSame' || droppedDocuments.every(d => d.embedContainer === this._props.parentTreeView?.Document))) {
+ const move = (!dropAction || canEmbed || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same' || dropAction === 'inSame') && moveDocument;
this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.dropping = true);
const res = droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false);
this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.dropping = false);
@@ -601,7 +610,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
docs.sort((a, b) => (NumCast(a.zIndex) > NumCast(b.zIndex) ? 1 : -1)).forEach((d, i) => (d.zIndex = i));
}
const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[key])) instanceof ComputedField;
- const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
+ const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false);
!dataIsComputed && added && Doc.SetContainer(doc, this.Document);
return added;
@@ -840,7 +849,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
? folderOp
: Doc.IsSystem(this.Document)
? []
- : this.treeView.fileSysMode && this.Document === Doc.GetProto(this.Document)
+ : this.treeView.fileSysMode && this.Document === this.Document[DocData]
? [openEmbedding, makeFolder]
: this.Document._type_collection === CollectionViewType.Docking
? []
@@ -867,7 +876,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
e.preventDefault();
}
};
- titleStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ titleStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => {
if (!doc || doc !== this.Document) return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
const treeView = this.treeView;
@@ -899,7 +908,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
}
return treeView._props.styleProvider?.(doc, props, property);
};
- embeddedStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ embeddedStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => {
if (property.startsWith(StyleProp.Decorations)) return null;
return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
};
@@ -973,17 +982,16 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
Document={this.Document}
layout_fitWidth={returnTrue}
scriptContext={this}
- hideDecorationTitle={this.treeView.outlineMode}
- hideResizeHandles={this.treeView.outlineMode}
+ hideDecorations={true}
+ hideClickBehaviors={true}
styleProvider={this.titleStyleProvider}
onClickScriptDisable="never" // tree docViews have a script to show fields, etc.
- docViewPath={this.treeView._props.docViewPath}
- treeViewDoc={this.treeView.Document}
+ containerViewPath={this.treeView.childContainerViewPath}
addDocument={undefined}
addDocTab={this._props.addDocTab}
pinToPres={this.treeView._props.pinToPres}
- onClick={this.onChildClick}
- onDoubleClick={this.onChildDoubleClick}
+ onClickScript={this.onChildClick}
+ onDoubleClickScript={this.onChildDoubleClick}
dragAction={this._props.dragAction}
moveDocument={this.move}
removeDocument={this._props.removeDoc}
@@ -998,7 +1006,6 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
isDocumentActive={this._props.isContentActive}
focus={this.refocus}
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
- bringToFront={emptyFunction}
disableBrushing={this.treeView._props.disableBrushing}
hideLinkButton={BoolCast(this.treeView.Document.childHideLinkButton)}
dontRegisterView={BoolCast(this.treeView.Document.childDontRegisterViews, this._props.dontRegisterView)}
@@ -1040,7 +1047,19 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
key="titleheader"
ref={this._header}
onClick={this.ignoreEvent}
- onPointerDown={this.ignoreEvent}
+ onPointerDown={e => {
+ this.treeView.isContentActive() &&
+ setupMoveUpEvents(
+ this,
+ e,
+ () => {
+ this._dref?.startDragging(e.clientX, e.clientY, '' as any);
+ return true;
+ },
+ returnFalse,
+ emptyFunction
+ );
+ }}
onPointerEnter={this.onPointerEnter}
onPointerLeave={this.onPointerLeave}>
<div
@@ -1072,22 +1091,21 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
isContentActive={isActive}
isDocumentActive={isActive}
styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
- hideTitle={asText}
fitContentsToBox={returnTrue}
- hideDecorationTitle={this.treeView.outlineMode}
- hideResizeHandles={this.treeView.outlineMode}
- onClick={this.onChildClick}
- focus={this.refocus}
- onKey={this.onKeyDown}
+ hideTitle={asText}
+ hideDecorations={true}
+ hideClickBehaviors={true}
hideLinkButton={BoolCast(this.treeView.Document.childHideLinkButton)}
dontRegisterView={BoolCast(this.treeView.Document.childDontRegisterViews, this._props.dontRegisterView)}
ScreenToLocalTransform={this.docTransform}
renderDepth={this._props.renderDepth + 1}
- treeViewDoc={this.treeView?.Document}
- docViewPath={this.treeView._props.docViewPath}
+ onClickScript={this.onChildClick}
+ onKey={this.onKeyDown}
+ containerViewPath={this.treeView.childContainerViewPath}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
+ focus={this.refocus}
addDocument={this._props.addDocument}
moveDocument={this.move}
removeDocument={this._props.removeDoc}
@@ -1097,7 +1115,6 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
addDocTab={this._props.addDocTab}
pinToPres={this.treeView._props.pinToPres}
disableBrushing={this.treeView._props.disableBrushing}
- bringToFront={returnFalse}
scriptContext={this}
/>
</div>
@@ -1142,7 +1159,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
const before = pt[1] < rect.top + rect.height / 2;
const inside = this.treeView.fileSysMode && !this.Document.isFolder ? false : pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length ? true : false);
- const docs = this.treeView.onTreeDrop(de, (docs: Doc[]) => this.dropDocuments(docs, before, inside, 'copy', undefined, undefined, false));
+ const docs = this.treeView.onTreeDrop(de, (docs: Doc[]) => this.dropDocuments(docs, before, inside, 'copy', undefined, undefined, false, false));
};
render() {
@@ -1209,7 +1226,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
move: DragManager.MoveFunction,
dragAction: dropActionType,
addDocTab: (doc: Doc, where: OpenWhere) => boolean,
- styleProvider: undefined | StyleProviderFunc,
+ styleProvider: undefined | StyleProviderFuncType,
screenToLocalXf: () => Transform,
isContentActive: (outsideReaction?: boolean) => boolean,
panelWidth: () => number,
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 5204633ea..f0a31a8c6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -130,7 +130,7 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent<Collect
LinkManager.currentLink = this._props.LinkDocs[0];
this.toggleProperties();
// OverlayView.Instance.addElement(
- // <LinkEditor sourceDoc={this._props.A._props.Document} linkDoc={this._props.LinkDocs[0]}
+ // <LinkEditor sourceDoc={this._props.A.Document} linkDoc={this._props.LinkDocs[0]}
// showLinks={action(() => { })}
// />, { x: 300, y: 300 });
})
@@ -204,8 +204,8 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent<Collect
const atop = this.visibleY(adiv);
const btop = this.visibleY(bdiv);
if (!a.width || !b.width) return undefined;
- const aDocBounds = (A._props as any).DocumentView?.().getBounds() || { left: 0, right: 0, top: 0, bottom: 0 };
- const bDocBounds = (B._props as any).DocumentView?.().getBounds() || { left: 0, right: 0, top: 0, bottom: 0 };
+ const aDocBounds = (A._props as any).DocumentView?.().getBounds || { left: 0, right: 0, top: 0, bottom: 0 };
+ const bDocBounds = (B._props as any).DocumentView?.().getBounds || { left: 0, right: 0, top: 0, bottom: 0 };
const aleft = this.visibleX(adiv);
const bleft = this.visibleX(bdiv);
const aclipped = aleft !== a.left || atop !== a.top;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 95d521f65..e5b6c366f 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -11,7 +11,7 @@ import './CollectionFreeFormLinksView.scss';
export class CollectionFreeFormLinksView extends React.Component {
@computed get uniqueConnections() {
return Array.from(new Set(DocumentManager.Instance.LinkedDocumentViews))
- .filter(c => !LightboxView.LightboxDoc || (LightboxView.IsLightboxDocView(c.a.docViewPath) && LightboxView.IsLightboxDocView(c.b.docViewPath)))
+ .filter(c => !LightboxView.LightboxDoc || (LightboxView.Contains(c.a) && LightboxView.Contains(c.b)))
.map(c => <CollectionFreeFormLinkView key={c.l[Id]} A={c.a} B={c.b} LinkDocs={[c.l]} />);
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx
index ec8416303..69cbae86f 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx
@@ -1,4 +1,4 @@
-import { computed } from 'mobx';
+import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc } from '../../../../fields/Doc';
@@ -18,6 +18,10 @@ export interface CollectionFreeFormPannableContentsProps {
@observer
export class CollectionFreeFormPannableContents extends React.Component<CollectionFreeFormPannableContentsProps> {
+ constructor(props: CollectionFreeFormPannableContentsProps) {
+ super(props);
+ makeObservable(this);
+ }
@computed get presPaths() {
return CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.pathLines(this.props.Document) : null;
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8268a47d8..53dc389b4 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,6 +1,6 @@
import { Bezier } from 'bezier-js';
import { Colors } from 'browndash-components';
-import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction, toJS } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
import * as React from 'react';
@@ -38,8 +38,8 @@ import { ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } fr
import { LightboxView } from '../../LightboxView';
import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewWrapper } from '../../nodes/CollectionFreeFormDocumentView';
import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp';
-import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from '../../nodes/DocumentView';
-import { FieldViewProps } from '../../nodes/FieldView';
+import { DocumentView, OpenWhere } from '../../nodes/DocumentView';
+import { FocusViewOptions, FieldViewProps } from '../../nodes/FieldView';
import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
import { PinProps, PresBox } from '../../nodes/trails/PresBox';
import { CreateImage } from '../../nodes/WebBoxRenderer';
@@ -54,7 +54,7 @@ import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCurso
import './CollectionFreeFormView.scss';
import { MarqueeView } from './MarqueeView';
-export type collectionFreeformViewProps = {
+export interface collectionFreeformViewProps {
NativeWidth?: () => number;
NativeHeight?: () => number;
originTopLeft?: boolean;
@@ -65,12 +65,12 @@ export type collectionFreeformViewProps = {
noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale)
engineProps?: any;
getScrollHeight?: () => number | undefined;
-};
+}
@observer
export class CollectionFreeFormView extends CollectionSubView<Partial<collectionFreeformViewProps>>() {
public get displayName() {
- return 'CollectionFreeFormView(' + this._props.Document.title?.toString() + ')';
+ return 'CollectionFreeFormView(' + this.Document.title?.toString() + ')';
} // this makes mobx trace() statements more descriptive
constructor(props: any) {
@@ -162,7 +162,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return this._props.isAnnotationOverlay || this._props.originTopLeft ? 0 : this._props.PanelWidth() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
}
@computed get cachedCenteringShiftY(): number {
- const dv = this._props.DocumentView?.();
+ const dv = this.DocumentView?.();
const fitWidth = this._props.layout_fitWidth?.(this.Document) ?? dv?.layoutDoc.layout_fitWidth;
const scaling = !this.nativeDimScaling ? 1 : this.nativeDimScaling;
// if freeform has a native aspect, then the panel height needs to be adjusted to match it
@@ -180,12 +180,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
public static gotoKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], duration: number) {
- if (timer) clearTimeout(timer);
- return DocumentView.SetViewTransition(docs, 'all', duration, undefined, true);
+ return DocumentView.SetViewTransition(docs, 'all', duration, timer, undefined, true);
}
public static updateKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], time: number) {
- if (timer) clearTimeout(timer);
- const newTimer = DocumentView.SetViewTransition(docs, 'all', 1000, undefined, true);
+ const newTimer = DocumentView.SetViewTransition(docs, 'all', 1000, timer, undefined, true);
const timecode = Math.round(time);
docs.forEach(doc => {
CollectionFreeFormDocumentView.animFields.forEach(val => {
@@ -223,7 +221,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@observable _keyframeEditing = false;
@action setKeyFrameEditing = (set: boolean) => (this._keyframeEditing = set);
getKeyFrameEditing = () => this._keyframeEditing;
- onBrowseClickHandler = () => this._props.onBrowseClick?.() || ScriptCast(this.layoutDoc.onBrowseClick);
+ onBrowseClickHandler = () => this._props.onBrowseClickScript?.() || ScriptCast(this.layoutDoc.onBrowseClick);
onChildClickHandler = () => this._props.childClickScript || ScriptCast(this.Document.onChildClick);
onChildDoubleClickHandler = () => this._props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
elementFunc = () => this._layoutElements;
@@ -250,7 +248,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
selectDocuments = (docs: Doc[]) => {
SelectionManager.DeselectAll();
- docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this._props.DocumentView?.())).forEach(dv => dv && SelectionManager.SelectView(dv, true));
+ docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).forEach(dv => dv && SelectionManager.SelectView(dv, true));
};
addDocument = (newBox: Doc | Doc[]) => {
let retVal = false;
@@ -288,14 +286,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return dispTime === -1 || curTime === -1 || (curTime - dispTime >= -1e-4 && curTime <= endTime);
}
- groupFocus = (anchor: Doc, options: DocFocusOptions) => {
+ groupFocus = (anchor: Doc, options: FocusViewOptions) => {
options.docTransform = new Transform(-NumCast(this.layoutDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.layoutDoc[this.panYFieldKey]) + NumCast(anchor.y), 1);
const res = this._props.focus(this.Document, options);
options.docTransform = undefined;
return res;
};
- focus = (anchor: Doc, options: DocFocusOptions) => {
+ focus = (anchor: Doc, options: FocusViewOptions) => {
if (this._lightboxDoc) return;
if (anchor === this.Document) {
if (options.willZoomCentered && options.zoomScale) {
@@ -321,7 +319,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
};
- getView = async (doc: Doc, options: DocFocusOptions): Promise<Opt<DocumentView>> =>
+ getView = async (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> =>
new Promise<Opt<DocumentView>>(res => {
if (doc.hidden && this._lightboxDoc !== doc) options.didMove = !(doc.hidden = false);
const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv));
@@ -409,7 +407,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@undoBatch
internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData) {
- if (linkDragData.linkDragView.props.docViewPath().includes(this._props.docViewPath().lastElement())) {
+ if (this.DocumentView?.() && linkDragData.linkDragView.containerViewPath?.().includes(this.DocumentView())) {
const [x, y] = this.screenToFreeformContentsXf.transformPoint(de.x, de.y);
let added = false;
// do nothing if link is dropped into any freeform view parent of dragged document
@@ -467,7 +465,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return this.childLayoutPairs
.map(pair => pair.layout)
.reduce((cluster, cd) => {
- const grouping = this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster, -1) : NumCast(cd.group, -1);
+ const grouping = this.Document._freeform_useClusters ? NumCast(cd.layout_cluster, -1) : NumCast(cd.group, -1);
if (grouping !== -1) {
const layoutDoc = Doc.Layout(cd);
const cx = NumCast(cd.x) - this._clusterDistance / 2;
@@ -484,9 +482,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (cluster !== -1) {
const ptsParent = e;
if (ptsParent) {
- const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster);
- const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this._props.DocumentView?.())!);
- const { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 };
+ const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster);
+ const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.DocumentView?.())!);
+ const { left, top } = clusterDocs[0].getBounds || { left: 0, top: 0 };
const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'embed' : undefined);
de.moveDocument = this._props.moveDocument;
de.offset = this.screenToFreeformContentsXf.transformDirection(ptsParent.clientX - left, ptsParent.clientY - top);
@@ -506,7 +504,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
updateClusters(_freeform_useClusters: boolean) {
- this._props.Document._freeform_useClusters = _freeform_useClusters;
+ this.Document._freeform_useClusters = _freeform_useClusters;
this._clusterSets.length = 0;
this.childLayoutPairs.map(pair => pair.layout).map(c => this.updateCluster(c));
}
@@ -514,7 +512,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
updateClusterDocs(docs: Doc[]) {
const childLayouts = this.childLayoutPairs.map(pair => pair.layout);
- if (this._props.Document._freeform_useClusters) {
+ if (this.Document._freeform_useClusters) {
const docFirst = docs[0];
docs.map(doc => this._clusterSets.map(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1)));
const preferredInd = NumCast(docFirst.layout_cluster);
@@ -557,7 +555,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
updateCluster = (doc: Doc) => {
const childLayouts = this.childLayoutPairs.map(pair => pair.layout);
- if (this._props.Document._freeform_useClusters) {
+ if (this.Document._freeform_useClusters) {
this._clusterSets.forEach(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1));
const preferredInd = NumCast(doc.layout_cluster);
doc.layout_cluster = -1;
@@ -586,7 +584,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
};
- clusterStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => {
+ clusterStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => {
let styleProp = this._props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1
if (doc && this.childDocList?.includes(doc))
switch (property) {
@@ -616,7 +614,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
trySelectCluster = (addToSel: boolean) => {
if (this._hitCluster !== -1) {
!addToSel && SelectionManager.DeselectAll();
- const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster);
+ const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster);
this.selectDocuments(eles);
return true;
}
@@ -629,7 +627,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this._downY = this._lastY = e.pageY;
this._downTime = Date.now();
const scrollMode = e.altKey ? (Doc.UserDoc().freeformScrollMode === freeformScrollMode.Pan ? freeformScrollMode.Zoom : freeformScrollMode.Pan) : Doc.UserDoc().freeformScrollMode;
- if (e.button === 0 && (!(e.ctrlKey && !e.metaKey) || scrollMode !== freeformScrollMode.Pan) && this._props.isContentActive(true)) {
+ if (e.button === 0 && (!(e.ctrlKey && !e.metaKey) || scrollMode !== freeformScrollMode.Pan) && this._props.isContentActive()) {
if (!this.Document.isGroup) {
// group freeforms don't pan when dragged -- instead let the event go through to allow the group itself to drag
// prettier-ignore
@@ -704,7 +702,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
@action
onEraserUp = (e: PointerEvent): void => {
- this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.Document));
+ this._deleteList.forEach(ink => ink._props.removeDocument?.(ink.Document));
this._deleteList = [];
this._batch?.end();
};
@@ -714,7 +712,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (this._lightboxDoc) this._lightboxDoc = undefined;
if (Utils.isClick(e.pageX, e.pageY, this._downX, this._downY, this._downTime)) {
if (this.onBrowseClickHandler()) {
- this.onBrowseClickHandler().script.run({ documentView: this._props.DocumentView?.(), clientX: e.clientX, clientY: e.clientY });
+ this.onBrowseClickHandler().script.run({ documentView: this.DocumentView?.(), clientX: e.clientX, clientY: e.clientY });
e.stopPropagation();
e.preventDefault();
} else if (this.isContentActive() && e.shiftKey) {
@@ -737,7 +735,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const ctrlKey = e.ctrlKey && !e.shiftKey;
const shiftKey = e.shiftKey && !e.ctrlKey;
PresBox.Instance?.pauseAutoPres();
- this._props.DocumentView?.().clearViewTransition();
+ this.DocumentView?.().clearViewTransition();
const [dxi, dyi] = this.screenToFreeformContentsXf.transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
const { x: dx, y: dy } = Utils.rotPt(dxi, dyi, this.ScreenToLocalBoxXf().Rotate);
this.setPan(NumCast(this.Document[this.panXFieldKey]) - (ctrlKey ? 0 : dx), NumCast(this.Document[this.panYFieldKey]) - (shiftKey ? 0 : dy), 0, true);
@@ -808,9 +806,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const eraserMax = { X: Math.max(lastPoint.X, currPoint.X), Y: Math.max(lastPoint.Y, currPoint.Y) };
return this.childDocs
- .map(doc => DocumentManager.Instance.getDocumentView(doc, this._props.DocumentView?.()))
+ .map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.()))
.filter(inkView => inkView?.ComponentView instanceof InkingStroke)
- .map(inkView => ({ inkViewBounds: inkView!.getBounds(), inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! }))
+ .map(inkView => ({ inkViewBounds: inkView!.getBounds, inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! }))
.filter(
({ inkViewBounds }) =>
inkViewBounds && // bounding box of eraser segment and ink stroke overlap
@@ -905,7 +903,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this.childDocs
.filter(doc => doc.type === DocumentType.INK && !doc.dontIntersect)
.forEach(doc => {
- const otherInk = DocumentManager.Instance.getDocumentView(doc, this._props.DocumentView?.())?.ComponentView as InkingStroke;
+ const otherInk = DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())?.ComponentView as InkingStroke;
const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] };
const otherScreenPts = otherInkData.map(point => otherInk.ptToScreen(point));
const otherCtrlPts = otherScreenPts.map(spt => (ink.ComponentView as InkingStroke).ptFromScreen(spt));
@@ -959,8 +957,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const localTransform = invTransform.scaleAbout(deltaScale, x, y);
if (localTransform.Scale >= 0.05 || localTransform.Scale > this.zoomScaling()) {
const safeScale = Math.min(Math.max(0.05, localTransform.Scale), 20);
- this._props.Document[this.scaleFieldKey] = Math.abs(safeScale);
- this.setPan(-localTransform.TranslateX / safeScale, (this._props.originTopLeft ? undefined : NumCast(this._props.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale);
+ this.Document[this.scaleFieldKey] = Math.abs(safeScale);
+ this.setPan(-localTransform.TranslateX / safeScale, (this._props.originTopLeft ? undefined : NumCast(this.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale);
}
};
@@ -968,7 +966,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
onPointerWheel = (e: React.WheelEvent): void => {
if (this.Document.isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom
PresBox.Instance?.pauseAutoPres();
- if (this.layoutDoc._Transform || this._props.Document.treeView_OutlineMode === TreeViewType.outline) return;
+ if (this.layoutDoc._Transform || this.Document.treeView_OutlineMode === TreeViewType.outline) return;
e.stopPropagation();
const docHeight = NumCast(this.Document[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight);
const scrollable = this.isAnnotationOverlay && NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this._props.PanelHeight() / this.nativeDimScaling + 1e-4;
@@ -979,7 +977,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
freeformScrollMode.Zoom : freeformScrollMode.Pan // prettier-ignore
) {
case freeformScrollMode.Pan:
- if (((!e.metaKey && !e.altKey) || Doc.UserDoc().freeformScrollMode === freeformScrollMode.Zoom) && this._props.isContentActive(true)) {
+ if (((!e.metaKey && !e.altKey) || Doc.UserDoc().freeformScrollMode === freeformScrollMode.Zoom) && this._props.isContentActive()) {
const deltaX = e.shiftKey ? e.deltaX : e.ctrlKey ? 0 : e.deltaX;
const deltaY = e.shiftKey ? 0 : e.ctrlKey ? e.deltaY : e.deltaY;
this.scrollPan({ deltaX: -deltaX * this.screenToFreeformContentsXf.Scale, deltaY: e.shiftKey ? 0 : -deltaY * this.screenToFreeformContentsXf.Scale });
@@ -987,9 +985,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
default:
case freeformScrollMode.Zoom:
- if ((e.ctrlKey || !scrollable) && this._props.isContentActive(true)) {
+ if ((e.ctrlKey || !scrollable) && this._props.isContentActive()) {
this.zoom(e.clientX, e.clientY, Math.max(-1, Math.min(1, e.deltaY))); // if (!this._props.isAnnotationOverlay) // bcz: do we want to zoom in on images/videos/etc?
- e.preventDefault();
+ // e.preventDefault();
}
break;
}
@@ -1065,7 +1063,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
nudge = (x: number, y: number, nudgeTime: number = 500) => {
- const collectionDoc = this._props.docViewPath().lastElement().Document;
+ const collectionDoc = this.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
@@ -1170,35 +1168,33 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@undoBatch
onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
- const docView = fieldProps.DocumentView?.();
- if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) {
+ if ((e.metaKey || e.ctrlKey || e.altKey || fieldProps.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.Document, true);
- const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)];
+ const layout_fieldKey = StrCast(fieldProps.fieldKey);
+ const newDoc = Doc.MakeCopy(fieldProps.Document, true);
+ const dataField = fieldProps.Document[Doc.LayoutFieldKey(newDoc)];
newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
- 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];
+ if (below) newDoc.y = NumCast(fieldProps.Document.y) + NumCast(fieldProps.Document._height) + 10;
+ else newDoc.x = NumCast(fieldProps.Document.x) + NumCast(fieldProps.Document._width) + 10;
+ if (layout_fieldKey !== 'layout' && fieldProps.Document[layout_fieldKey] instanceof Doc) {
+ newDoc[layout_fieldKey] = fieldProps.Document[layout_fieldKey];
}
- Doc.GetProto(newDoc).text = undefined;
+ newDoc[DocData].text = undefined;
FormattedTextBox.SetSelectOnLoad(newDoc);
return this.addDocument?.(newDoc);
}
};
@computed get childPointerEvents() {
- const engine = this._props.layoutEngine?.() || StrCast(this._props.Document._layoutEngine);
- const pointerevents = SnappingManager.IsResizing
+ const engine = this._props.layoutEngine?.() || StrCast(this.Document._layoutEngine);
+ return SnappingManager.IsResizing
? 'none'
: this._props.childPointerEvents?.() ??
- (this._props.viewDefDivClick || //
- (engine === computePassLayout.name && !this._props.isSelected()) ||
- this.isContentActive() === false
- ? 'none'
- : this._props.pointerEvents?.());
- return pointerevents;
+ (this._props.viewDefDivClick || //
+ (engine === computePassLayout.name && !this._props.isSelected()) ||
+ this.isContentActive() === false
+ ? 'none'
+ : this._props.pointerEvents?.());
}
@observable _childPointerEvents: 'none' | 'all' | 'visiblepainted' | undefined = undefined;
@@ -1212,6 +1208,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
{...OmitKeys(entry, ['replica', 'pair']).omit}
key={childLayout[Id] + (entry.replica || '')}
Document={childLayout}
+ containerViewPath={this.DocumentView?.().docViewPath}
+ styleProvider={this.clusterStyleProvider}
TemplateDataDocument={childData}
dragStarting={this.dragStarting}
dragEnding={this.dragEnding}
@@ -1225,10 +1223,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
LayoutTemplateString={childLayout.z ? undefined : this._props.childLayoutString}
rootSelected={childData ? this.rootSelected : returnFalse}
waitForDoubleClickToClick={this._props.waitForDoubleClickToClick}
- onClick={this.onChildClickHandler}
+ onClickScript={this.onChildClickHandler}
onKey={this.onKeyDown}
- onDoubleClick={this.onChildDoubleClickHandler}
- onBrowseClick={this.onBrowseClickHandler}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
+ onBrowseClickScript={this.onBrowseClickHandler}
ScreenToLocalTransform={childLayout.z ? this.ScreenToLocalBoxXf : this.ScreenToContentsXf}
PanelWidth={childLayout[Width]}
PanelHeight={childLayout[Height]}
@@ -1244,10 +1242,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
moveDocument={this._props.moveDocument}
pinToPres={this._props.pinToPres}
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
- docViewPath={this._props.docViewPath}
- styleProvider={this.clusterStyleProvider}
dragAction={(this.Document.childDragAction ?? this._props.childDragAction) as dropActionType}
- bringToFront={this.bringToFront}
layout_showTitle={this._props.childlayout_showTitle}
dontRegisterView={this._props.dontRegisterView}
pointerEvents={this.childPointerEventsFunc}
@@ -1324,7 +1319,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
onViewDefDivClick = (e: React.MouseEvent, payload: any) => {
- (this._props.viewDefDivClick || ScriptCast(this._props.Document.onViewDefDivClick))?.script.run({ this: this._props.Document, payload });
+ (this._props.viewDefDivClick || ScriptCast(this.Document.onViewDefDivClick))?.script.run({ this: this.Document, payload });
e.stopPropagation();
};
@@ -1379,7 +1374,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
poolData: Map<string, PoolData>,
engine: (poolData: Map<string, PoolData>, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) => ViewDefResult[]
) {
- return engine(poolData, this._props.Document, this.childLayoutPairs, [this._props.PanelWidth(), this._props.PanelHeight()], this.viewDefsToJSX, this._props.engineProps);
+ return engine(poolData, this.Document, this.childLayoutPairs, [this._props.PanelWidth(), this._props.PanelHeight()], this.viewDefsToJSX, this._props.engineProps);
}
doFreeformLayout(poolData: Map<string, PoolData>) {
@@ -1439,7 +1434,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
infoUI = () => (this.Document._hideInfo || this.Document.annotationOn || this._props.renderDepth ? null : <CollectionFreeFormInfoUI Document={this.Document} Freeform={this} close={this.closeInfo} />);
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
super.componentDidMount?.();
setTimeout(
action(() => {
@@ -1476,17 +1471,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
);
this._disposers.pointerevents = reaction(
- () => {
- const engine = this._props.layoutEngine?.() || StrCast(this._props.Document._layoutEngine);
- return SnappingManager.IsResizing
- ? 'none'
- : this._props.childPointerEvents?.() ??
- (this._props.viewDefDivClick || //
- (engine === computePassLayout.name && !this._props.isSelected()) ||
- this.isContentActive() === false
- ? 'none'
- : this._props.pointerEvents?.());
- },
+ () => this.childPointerEvents,
pointerevents => (this._childPointerEvents = pointerevents as any),
{ fireImmediately: true }
);
@@ -1540,7 +1525,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
updateIcon = () =>
CollectionFreeFormView.UpdateIcon(
this.layoutDoc[Id] + '-icon' + new Date().getTime(),
- this._props.docViewPath().lastElement().ContentDiv!,
+ this.DocumentView?.().ContentDiv!,
NumCast(this.layoutDoc._width),
NumCast(this.layoutDoc._height),
this._props.PanelWidth(),
@@ -1651,15 +1636,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const appearance = ContextMenu.Instance.findByDescription('Appearance...');
const appearanceItems = appearance && 'subitems' in appearance ? appearance.subitems : [];
- !this._props.Document.isGroup && appearanceItems.push({ description: 'Reset View', event: this.resetView, icon: 'compress-arrows-alt' });
- !this._props.Document.isGroup && appearanceItems.push({ description: 'Toggle Auto Reset View', event: this.toggleResetView, icon: 'compress-arrows-alt' });
+ !this.Document.isGroup && appearanceItems.push({ description: 'Reset View', event: this.resetView, icon: 'compress-arrows-alt' });
+ !this.Document.isGroup && appearanceItems.push({ description: 'Toggle Auto Reset View', event: this.toggleResetView, icon: 'compress-arrows-alt' });
!Doc.noviceMode &&
appearanceItems.push({
description: 'Toggle auto arrange',
event: () => (this.layoutDoc._autoArrange = !this.layoutDoc._autoArrange),
icon: 'compress-arrows-alt',
});
- if (this._props.setContentView === emptyFunction) {
+ if (this._props.setContentViewBox === emptyFunction) {
!appearance && ContextMenu.Instance.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'eye' });
return;
}
@@ -1668,7 +1653,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
!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.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;
@@ -1692,8 +1677,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@undoBatch
transcribeStrokes = () => {
- if (this._props.Document.isGroup && this._props.Document.transcription) {
- const text = StrCast(this._props.Document.transcription);
+ if (this.Document.isGroup && this.Document.transcription) {
+ const text = StrCast(this.Document.transcription);
const lines = text.split('\n');
const height = 30 + 15 * lines.length;
@@ -1741,7 +1726,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
incrementalRendering = () => this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])).length !== 0;
incrementalRender = action(() => {
- if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath())) {
+ if (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.())) {
const layout_unrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id]));
const loadIncrement = 5;
for (var i = 0; i < Math.min(layout_unrendered.length, loadIncrement); i++) {
@@ -1751,17 +1736,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this.childDocs.some(doc => !this._renderCutoffData.get(doc[Id])) && setTimeout(this.incrementalRender, 1);
});
- // if a freeform view has any children, then the children will likely consist of a single child
- // which will be a DocumentView. In this sitation, this freeform views acts as an annotation overlay for
- // the underlying DocumentView and will pan and scoll with the underlying Documen tView.
- @computed get underlayViews() {
- return this._props.children ? [toJS(this._props.children)] : [];
- }
-
@computed get placeholder() {
return (
<div className="collectionfreeformview-placeholder" style={{ background: this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) }}>
- <span className="collectionfreeformview-placeholderSpan">{this._props.Document.annotationOn ? '' : this._props.Document.title?.toString()}</span>
+ <span className="collectionfreeformview-placeholderSpan">{this.Document.annotationOn ? '' : this.Document.title?.toString()}</span>
</div>
);
}
@@ -1790,7 +1768,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
</div>
);
}
- @computed get pannableContents() {
+ get pannableContents() {
this.incrementalRender();
return (
<CollectionFreeFormPannableContents
@@ -1798,16 +1776,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
brushedView={this.brushedView}
isAnnotationOverlay={this.isAnnotationOverlay}
transform={this.PanZoomCenterXf}
- transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', Cast(this._props.DocumentView?.()?.Document._viewTransition, 'string', null))}
+ transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', Cast(this.Document._viewTransition, 'string', null))}
viewDefDivClick={this._props.viewDefDivClick}>
- {this.underlayViews}
+ {this.props.children ?? null} {/* most likely case of children is document content that's being annoated: eg., an image */}
{this.contentViews}
<CollectionFreeFormRemoteCursors {...this._props} key="remoteCursors" />
</CollectionFreeFormPannableContents>
);
}
- @computed get marqueeView() {
- TraceMobx();
+ get marqueeView() {
return (
<MarqueeView
{...this._props}
@@ -1896,15 +1873,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
<DocumentView
{...this._props}
Document={this._lightboxDoc}
+ containerViewPath={this.DocumentView?.().docViewPath}
TemplateDataDocument={undefined}
PanelWidth={this.lightboxPanelWidth}
PanelHeight={this.lightboxPanelHeight}
NativeWidth={returnZero}
NativeHeight={returnZero}
- onClick={this.onChildClickHandler}
+ onClickScript={this.onChildClickHandler}
onKey={this.onKeyDown}
- onDoubleClick={this.onChildDoubleClickHandler}
- onBrowseClick={this.onBrowseClickHandler}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
+ onBrowseClickScript={this.onBrowseClickHandler}
childFilters={this.childDocFilters}
childFiltersByRanges={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
@@ -1942,15 +1920,15 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY
DocumentManager.Instance.showDocument(dv.Document, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => {
if (!focused) {
const selfFfview = !dv.Document.isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined;
- let containers = dv.props.docViewPath();
+ let containers = dv.containerViewPath?.() ?? [];
let parFfview = dv.CollectionFreeFormView;
for (var cont of containers) {
parFfview = parFfview ?? cont.CollectionFreeFormView;
}
- while (parFfview?.Document.isGroup) parFfview = parFfview.props.DocumentView?.().CollectionFreeFormView;
+ while (parFfview?.Document.isGroup) parFfview = parFfview.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.screenToFreeformContentsXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime);
- Doc.linkFollowHighlight(dv?.props.Document, false);
+ Doc.linkFollowHighlight(dv?.Document, false);
}
});
}
@@ -1968,13 +1946,13 @@ ScriptingGlobals.add(function curKeyFrame(readOnly: boolean) {
});
ScriptingGlobals.add(function pinWithView(pinContent: boolean) {
SelectionManager.Views.forEach(view =>
- view.props.pinToPres(view.Document, {
+ view._props.pinToPres(view.Document, {
currentFrame: Cast(view.Document.currentFrame, 'number', null),
pinData: {
poslayoutview: pinContent,
dataview: pinContent,
},
- pinViewport: MarqueeView.CurViewBounds(view.Document, view.props.PanelWidth(), view.props.PanelHeight()),
+ pinViewport: MarqueeView.CurViewBounds(view.Document, view._props.PanelWidth(), view._props.PanelHeight()),
})
);
});
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 39d828302..c2f8232c6 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -352,9 +352,10 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
const newCollection = creator
? creator(selected, { title: 'nested stack' })
: ((doc: Doc) => {
- Doc.GetProto(doc).data = new List<Doc>(selected);
- Doc.GetProto(doc).isGroup = makeGroup;
- Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform';
+ const docData = doc[DocData];
+ docData.data = new List<Doc>(selected);
+ docData.isGroup = makeGroup;
+ docData.title = makeGroup ? 'grouping' : 'nested freeform';
doc._freeform_panX = doc._freeform_panY = 0;
return doc;
})(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 113ffedb3..f25872c2b 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -192,7 +192,7 @@ export class CollectionGridView extends CollectionSubView() {
{...this._props}
NativeWidth={returnZero}
NativeHeight={returnZero}
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
Document={layout}
TemplateDataDocument={layout.resolvedDataDoc as Doc}
isContentActive={this.isChildContentActive}
@@ -200,7 +200,7 @@ export class CollectionGridView extends CollectionSubView() {
PanelHeight={height}
ScreenToLocalTransform={dxf}
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
- onClick={this.onChildClickHandler}
+ onClickScript={this.onChildClickHandler}
renderDepth={this._props.renderDepth + 1}
dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy'
/>
@@ -340,7 +340,7 @@ export class CollectionGridView extends CollectionSubView() {
* Handles text document creation on double click.
*/
onPointerDown = (e: React.PointerEvent) => {
- if (this._props.isContentActive(true)) {
+ if (this._props.isContentActive()) {
setupMoveUpEvents(
this,
e,
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index d105b04f7..228af78aa 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -79,16 +79,16 @@ export class CollectionLinearView extends CollectionSubView() {
@action
changeDescriptionSetting = () => {
- if (LinkDescriptionPopup.showDescriptions) {
- if (LinkDescriptionPopup.showDescriptions === 'ON') {
- LinkDescriptionPopup.showDescriptions = 'OFF';
- LinkDescriptionPopup.descriptionPopup = false;
+ if (LinkDescriptionPopup.Instance.showDescriptions) {
+ if (LinkDescriptionPopup.Instance.showDescriptions === 'ON') {
+ LinkDescriptionPopup.Instance.showDescriptions = 'OFF';
+ LinkDescriptionPopup.Instance.display = false;
} else {
- LinkDescriptionPopup.showDescriptions = 'ON';
+ LinkDescriptionPopup.Instance.showDescriptions = 'ON';
}
} else {
- LinkDescriptionPopup.showDescriptions = 'OFF';
- LinkDescriptionPopup.descriptionPopup = false;
+ LinkDescriptionPopup.Instance.showDescriptions = 'OFF';
+ LinkDescriptionPopup.Instance.display = false;
}
};
@@ -110,7 +110,7 @@ export class CollectionLinearView extends CollectionSubView() {
<Tooltip title={<div className="dash-tooltip">{'Toggle description pop-up'} </div>} placement="top">
<span className="bottomPopup-descriptions" onClick={this.changeDescriptionSetting}>
- Labels: {LinkDescriptionPopup.showDescriptions ? LinkDescriptionPopup.showDescriptions : 'ON'}
+ Labels: {LinkDescriptionPopup.Instance.showDescriptions ? LinkDescriptionPopup.Instance.showDescriptions : 'ON'}
</span>
</Tooltip>
@@ -147,8 +147,8 @@ export class CollectionLinearView extends CollectionSubView() {
switch (doc.layout) {
case '<LinkingUI>': return this.getLinkUI();
case '<CurrentlyPlayingUI>': return this.getCurrentlyPlayingUI();
- case '<UndoStack>': return <UndoStack />;
- case '<Branching>': return Doc.UserDoc().isBranchingMode ? <BranchingTrailManager /> : null;
+ case '<UndoStack>': return <UndoStack key={doc[Id]}/>;
+ case '<Branching>': return Doc.UserDoc().isBranchingMode ? <BranchingTrailManager key={doc[Id]} /> : null;
}
const nested = doc._type_collection === CollectionViewType.Linear;
@@ -189,9 +189,8 @@ export class CollectionLinearView extends CollectionSubView() {
dontRegisterView={BoolCast(this.Document.childDontRegisterViews)}
focus={emptyFunction}
styleProvider={this._props.styleProvider}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={this.childContainerViewPath}
whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
childFilters={this._props.childFilters}
childFiltersByRanges={this._props.childFiltersByRanges}
searchFilterDocs={this._props.searchFilterDocs}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 563084af8..b181b59ce 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -4,7 +4,7 @@ import { Button } from 'browndash-components';
import { action, computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { returnFalse } from '../../../../Utils';
+import { emptyFunction, returnFalse } from '../../../../Utils';
import { Doc, DocListCast } from '../../../../fields/Doc';
import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { DragManager, dropActionType } from '../../../util/DragManager';
@@ -127,7 +127,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
private get totalRatioAllocation(): number | undefined {
const layoutInfoLen = this.resolvedLayoutInformation.widthSpecifiers.length;
if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) {
- return this._props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)) - 2 * NumCast(this._props.Document._xMargin);
+ return this._props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)) - 2 * NumCast(this.Document._xMargin);
}
}
@@ -259,16 +259,16 @@ export class CollectionMulticolumnView extends CollectionSubView() {
Document={childLayout}
TemplateDataDocument={childLayout.resolvedDataDoc as Doc}
styleProvider={this._props.styleProvider}
- docViewPath={this._props.docViewPath}
+ containerViewPath={this.childContainerViewPath}
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
renderDepth={this._props.renderDepth + 1}
PanelWidth={width}
PanelHeight={height}
rootSelected={this.rootSelected}
- dragAction={(this._props.Document.childDragAction ?? this._props.childDragAction) as dropActionType}
- onClick={this.onChildClickHandler}
- onDoubleClick={this.onChildDoubleClickHandler}
+ dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType}
+ onClickScript={this.onChildClickHandler}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
suppressSetHeight={true}
ScreenToLocalTransform={dxf}
isContentActive={this.isChildContentActive}
@@ -287,7 +287,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
addDocTab={this._props.addDocTab}
pinToPres={this._props.pinToPres}
- bringToFront={returnFalse}
dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy'
/>
);
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index bf0d39197..659f7ccdc 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -1,7 +1,7 @@
import { action, computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { returnFalse } from '../../../../Utils';
+import { emptyFunction, returnFalse } from '../../../../Utils';
import { Doc, DocListCast } from '../../../../fields/Doc';
import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { DragManager, dropActionType } from '../../../util/DragManager';
@@ -122,7 +122,7 @@ export class CollectionMultirowView extends CollectionSubView() {
private get totalRatioAllocation(): number | undefined {
const layoutInfoLen = this.resolvedLayoutInformation.heightSpecifiers.length;
if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) {
- return this._props.PanelHeight() - (this.totalFixedAllocation + resizerHeight * (layoutInfoLen - 1)) - 2 * NumCast(this._props.Document._yMargin);
+ return this._props.PanelHeight() - (this.totalFixedAllocation + resizerHeight * (layoutInfoLen - 1)) - 2 * NumCast(this.Document._yMargin);
}
}
@@ -254,23 +254,22 @@ export class CollectionMultirowView extends CollectionSubView() {
Document={layout}
TemplateDataDocument={layout.resolvedDataDoc as Doc}
styleProvider={this._props.styleProvider}
- docViewPath={this._props.docViewPath}
+ containerViewPath={this.childContainerViewPath}
LayoutTemplate={this._props.childLayoutTemplate}
LayoutTemplateString={this._props.childLayoutString}
renderDepth={this._props.renderDepth + 1}
PanelWidth={width}
PanelHeight={height}
rootSelected={this.rootSelected}
- dropAction={StrCast(this.Document.childDragAction) as dropActionType}
- onClick={this.onChildClickHandler}
- onDoubleClick={this.onChildDoubleClickHandler}
+ dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType}
+ onClickScript={this.onChildClickHandler}
+ onDoubleClickScript={this.onChildDoubleClickHandler}
ScreenToLocalTransform={dxf}
isContentActive={this.isChildContentActive}
isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
hideResizeHandles={layout.layout_fitWidth || this._props.childHideResizeHandles ? true : false}
hideDecorationTitle={this._props.childHideDecorationTitle}
fitContentsToBox={this._props.fitContentsToBox}
- dragAction={this._props.childDragAction}
focus={this._props.focus}
childFilters={this.childDocFilters}
childFiltersByRanges={this.childDocRangeFilters}
@@ -282,7 +281,6 @@ export class CollectionMultirowView extends CollectionSubView() {
whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
addDocTab={this._props.addDocTab}
pinToPres={this._props.pinToPres}
- bringToFront={returnFalse}
dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy'
/>
);
diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
index c38c6dc4e..d580d9c52 100644
--- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
+++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
@@ -1,16 +1,16 @@
-import { action, observable } from 'mobx';
+import { action } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc } from '../../../../fields/Doc';
import { NumCast, StrCast } from '../../../../fields/Types';
import { UndoManager } from '../../../util/UndoManager';
import { StyleProp } from '../../StyleProvider';
-import { StyleProviderFunc } from '../../nodes/DocumentView';
+import { StyleProviderFuncType } from '../../nodes/FieldView';
import { DimUnit } from './CollectionMulticolumnView';
interface ResizerProps {
width: number;
- styleProvider?: StyleProviderFunc;
+ styleProvider?: StyleProviderFuncType;
isContentActive?: () => boolean | undefined;
columnUnitLength(): number | undefined;
toLeft?: Doc;
diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx
index 6f1b3b425..73d08d5ef 100644
--- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx
+++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx
@@ -1,16 +1,16 @@
-import { action, observable } from 'mobx';
+import { action } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc } from '../../../../fields/Doc';
import { NumCast, StrCast } from '../../../../fields/Types';
import { UndoManager } from '../../../util/UndoManager';
import { StyleProp } from '../../StyleProvider';
-import { StyleProviderFunc } from '../../nodes/DocumentView';
+import { StyleProviderFuncType } from '../../nodes/FieldView';
import { DimUnit } from './CollectionMultirowView';
interface ResizerProps {
height: number;
- styleProvider?: StyleProviderFunc;
+ styleProvider?: StyleProviderFuncType;
isContentActive?: () => boolean | undefined;
columnUnitLength(): number | undefined;
toTop?: Doc;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
index 02131ae22..29d121974 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss
@@ -210,8 +210,9 @@
border: 1px solid $medium-gray;
overflow-x: hidden;
overflow-y: auto;
- padding: 5px;
display: inline-flex;
+ padding: 0;
+ align-items: center;
}
.schema-row {
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 492aed0ea..581425d77 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -16,7 +16,8 @@ import { undoable, undoBatch } from '../../../util/UndoManager';
import { ContextMenu } from '../../ContextMenu';
import { EditableView } from '../../EditableView';
import { Colors } from '../../global/globalEnums';
-import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../../nodes/DocumentView';
+import { DocumentView } from '../../nodes/DocumentView';
+import { FocusViewOptions, FieldViewProps } from '../../nodes/FieldView';
import { KeyValueBox } from '../../nodes/KeyValueBox';
import { ObservableReactComponent } from '../../ObservableReactComponent';
import { DefaultStyleProvider, StyleProp } from '../../StyleProvider';
@@ -24,7 +25,6 @@ import { CollectionSubView } from '../CollectionSubView';
import './CollectionSchemaView.scss';
import { SchemaColumnHeader } from './SchemaColumnHeader';
import { SchemaRowBox } from './SchemaRowBox';
-import { FieldViewProps } from '../../nodes/FieldView';
export enum ColumnType {
Number,
@@ -147,7 +147,7 @@ export class CollectionSchemaView extends CollectionSubView() {
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
document.addEventListener('keydown', this.onKeyDown);
Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1]));
@@ -498,13 +498,13 @@ export class CollectionSchemaView extends CollectionSubView() {
ContextMenu.Instance.displayMenu(x, y, undefined, true);
};
- focusDocument = (doc: Doc, options: DocFocusOptions) => {
+ focusDocument = (doc: Doc, options: FocusViewOptions) => {
Doc.BrushDoc(doc);
this.scrollToDoc(doc, options);
return undefined;
};
- scrollToDoc = (doc: Doc, options: DocFocusOptions) => {
+ scrollToDoc = (doc: Doc, options: FocusViewOptions) => {
const found = this._tableContentRef && Array.from(this._tableContentRef.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]);
if (found) {
const rect = found.getBoundingClientRect();
@@ -907,14 +907,13 @@ export class CollectionSchemaView extends CollectionSubView() {
childFiltersByRanges={this.childDocRangeFilters}
searchFilterDocs={this.searchFilterDocs}
styleProvider={DefaultStyleProvider}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
moveDocument={this._props.moveDocument}
addDocument={this.addRow}
removeDocument={this._props.removeDocument}
whenChildContentsActiveChanged={returnFalse}
addDocTab={this._props.addDocTab}
pinToPres={this._props.pinToPres}
- bringToFront={returnFalse}
/>
)}
</div>
@@ -962,7 +961,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV
tableWidthFunc = () => this._props.schema.tableWidth;
screenToLocalXf = () => this._props.schema.ScreenToLocalBoxXf().translate(0, -this._props.rowHeight() - this._props.index * this._props.rowHeight());
- noOpacityStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => {
+ noOpacityStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => {
if (property === StyleProp.Opacity) return 1;
return DefaultStyleProvider(doc, props, property);
};
@@ -971,6 +970,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV
<DocumentView
key={this._props.doc[Id]}
{...this._props.schema._props}
+ containerViewPath={this._props.schema.childContainerViewPath}
LayoutTemplate={this._props.schema._props.childLayoutTemplate}
LayoutTemplateString={SchemaRowBox.LayoutString(this._props.schema._props.fieldKey, this._props.index)}
Document={this._props.doc}
@@ -988,7 +988,6 @@ class CollectionSchemaViewDoc extends ObservableReactComponent<CollectionSchemaV
searchFilterDocs={this._props.schema.searchFilterDocs}
rootSelected={this._props.schema.rootSelected}
ScreenToLocalTransform={this.screenToLocalXf}
- bringToFront={emptyFunction}
dragWhenActive={true}
isDocumentActive={this._props.schema._props.childDocumentsActive?.() ? this._props.schema._props.isDocumentActive : this._props.schema.isContentActive}
isContentActive={emptyFunction}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 5a3be826b..f2fe0dde7 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -3,7 +3,7 @@ import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
import * as React from 'react';
-import { CgClose } from 'react-icons/cg';
+import { CgClose, CgLock, CgLockUnlock } from 'react-icons/cg';
import { FaExternalLinkAlt } from 'react-icons/fa';
import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../../Utils';
import { Doc } from '../../../../fields/Doc';
@@ -20,17 +20,17 @@ import { CollectionSchemaView } from './CollectionSchemaView';
import './CollectionSchemaView.scss';
import { SchemaTableCell } from './SchemaTableCell';
-interface SchemaRowBoxProps {
+interface SchemaRowBoxProps extends FieldViewProps {
rowIndex: number;
}
@observer
-export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps & SchemaRowBoxProps>() {
+export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
public static LayoutString(fieldKey: string, rowIndex: number) {
return FieldView.LayoutString(SchemaRowBox, fieldKey).replace('fieldKey', `rowIndex={${rowIndex}} fieldKey`);
}
private _ref: HTMLDivElement | null = null;
- constructor(props: any) {
+ constructor(props: SchemaRowBoxProps) {
super(props);
makeObservable(this);
}
@@ -38,11 +38,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps & SchemaRo
bounds = () => this._ref?.getBoundingClientRect();
@computed get schemaView() {
- return this._props.DocumentView?.()._props.docViewPath().lastElement()?.ComponentView as CollectionSchemaView;
+ return this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionSchemaView;
}
@computed get schemaDoc() {
- return this._props.DocumentView?.()._props.docViewPath().lastElement()?.Document;
+ return this.DocumentView?.().containerViewPath?.().lastElement()?.Document;
}
@computed get rowIndex() {
@@ -50,7 +50,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps & SchemaRo
}
componentDidMount(): void {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
select = (ctrlKey: boolean, shiftKey: boolean) => {
@@ -121,6 +121,22 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps & SchemaRo
pointerEvents: !this._props.isContentActive() ? 'none' : undefined,
}}>
<IconButton
+ tooltip="whether document interations are enabled"
+ icon={this.Document._lockedPosition ? <CgLockUnlock size="12px" /> : <CgLock size="12px" />}
+ size={Size.XSMALL}
+ onPointerDown={e =>
+ setupMoveUpEvents(
+ this,
+ e,
+ returnFalse,
+ emptyFunction,
+ undoable(e => {
+ e.stopPropagation();
+ Doc.toggleLockedPosition(this.Document);
+ }, 'Delete Row')
+ )
+ }></IconButton>
+ <IconButton
tooltip="close"
icon={<CgClose size={'16px'} />}
size={Size.XSMALL}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 85269028b..dbaa6e110 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -18,7 +18,7 @@ import { EditableView } from '../../EditableView';
import { ObservableReactComponent } from '../../ObservableReactComponent';
import { DefaultStyleProvider } from '../../StyleProvider';
import { Colors } from '../../global/globalEnums';
-import { OpenWhere } from '../../nodes/DocumentView';
+import { OpenWhere, returnEmptyDocViewList } from '../../nodes/DocumentView';
import { FieldViewProps } from '../../nodes/FieldView';
import { KeyValueBox } from '../../nodes/KeyValueBox';
import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
@@ -49,7 +49,7 @@ export interface SchemaTableCellProps {
@observer
export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellProps> {
- constructor(props: any) {
+ constructor(props: SchemaTableCellProps) {
super(props);
makeObservable(this);
}
@@ -75,14 +75,13 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
const fieldProps: FieldViewProps = {
childFilters: returnEmptyFilter,
childFiltersByRanges: returnEmptyFilter,
+ docViewPath: returnEmptyDocViewList,
searchFilterDocs: returnEmptyDoclist,
styleProvider: DefaultStyleProvider,
- docViewPath: returnEmptyDoclist,
isSelected: returnFalse,
setHeight: returnFalse,
select: emptyFunction,
dragAction: 'move',
- bringToFront: emptyFunction,
renderDepth: 1,
isContentActive: returnFalse,
whenChildContentsActiveChanged: emptyFunction,
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index e57ef4871..3084a7972 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -43,14 +43,14 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
if (checkResult) {
const selView = selectedViews.lastElement();
const fieldKey = selView.Document.type === DocumentType.INK ? 'fillColor' : 'backgroundColor';
- const layoutFrameNumber = Cast(selView._props.docViewPath().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
+ const layoutFrameNumber = Cast(selView.containerViewPath?.().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
const contentFrameNumber = Cast(selView.Document?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
return CollectionFreeFormDocumentView.getStringValues(selView?.Document, contentFrameNumber)[fieldKey] ?? 'transparent';
}
selectedViews.some(dv => dv.ComponentView instanceof InkingStroke) && SetActiveFillColor(color ?? 'transparent');
selectedViews.forEach(dv => {
const fieldKey = dv.Document.type === DocumentType.INK ? 'fillColor' : 'backgroundColor';
- const layoutFrameNumber = Cast(dv._props.docViewPath().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
+ const layoutFrameNumber = Cast(dv.containerViewPath?.().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
const contentFrameNumber = Cast(dv.Document?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
if (contentFrameNumber !== undefined) {
const obj: { [key: string]: Opt<string> } = {};
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index b7376e901..12b83414c 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -61,7 +61,7 @@ export class LinkMenu extends ObservableReactComponent<Props> {
render() {
const sourceDoc = this.props.docView.Document;
const sourceAnchor = this.props.docView.anchorViewDoc ?? sourceDoc;
- const style = this.props.style ?? (dv => ({ left: dv?.left || 0, top: this.props.docView.topMost ? undefined : (dv?.bottom || 0) + 15, bottom: this.props.docView.topMost ? 20 : undefined, maxWidth: 200 }))(this.props.docView.getBounds());
+ const style = this.props.style ?? (dv => ({ left: dv?.left || 0, top: this.props.docView.topMost ? undefined : (dv?.bottom || 0) + 15, bottom: this.props.docView.topMost ? 20 : undefined, maxWidth: 200 }))(this.props.docView.getBounds);
return (
<div className="linkMenu" ref={this._linkMenuRef} style={{ ...style, background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index 91142b90b..028d3da53 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -47,18 +47,18 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
const sourceDoc =
this.props.docView.anchorViewDoc ??
(this.props.docView.Document.type === DocumentType.LINK //
- ? this.props.docView.props.LayoutTemplateString?.includes('link_anchor_1')
+ ? this.props.docView._props.LayoutTemplateString?.includes('link_anchor_1')
? DocCast(linkDoc.link_anchor_1)
: DocCast(linkDoc.link_anchor_2)
: this.props.sourceDoc);
const destDoc = !sourceDoc
? undefined
: this.props.docView.Document.type === DocumentType.LINK
- ? this.props.docView.props.LayoutTemplateString?.includes('link_anchor_1')
- ? DocCast(linkDoc.link_anchor_2)
- : DocCast(linkDoc.link_anchor_1)
- : LinkManager.getOppositeAnchor(linkDoc, sourceDoc) ||
- LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.link_anchor_2, Doc, null).annotationOn === sourceDoc ? Cast(linkDoc.link_anchor_2, Doc, null) : Cast(linkDoc.link_anchor_1, Doc, null));
+ ? this.props.docView._props.LayoutTemplateString?.includes('link_anchor_1')
+ ? DocCast(linkDoc.link_anchor_2)
+ : DocCast(linkDoc.link_anchor_1)
+ : LinkManager.getOppositeAnchor(linkDoc, sourceDoc) ||
+ LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.link_anchor_2, Doc, null).annotationOn === sourceDoc ? Cast(linkDoc.link_anchor_2, Doc, null) : Cast(linkDoc.link_anchor_1, Doc, null));
return !destDoc || !sourceDoc ? null : (
<LinkMenuItem
key={linkDoc[Id]}
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 85e97f95f..dc4aee1ca 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -136,6 +136,7 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
deleteLink = (e: React.PointerEvent): void => setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => LinkManager.Instance.deleteLink(this._props.linkDoc))));
@observable _hover = false;
+ docView = () => this.props.docView;
render() {
const destinationIcon = Doc.toIcon(this._props.destinationDoc) as any as IconProp;
@@ -179,7 +180,8 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
this._props.linkDoc &&
this._props.clearLinkEditor &&
LinkInfo.SetLinkInfo({
- docProps: this._props.docView._props,
+ DocumentView: this.docView,
+ styleProvider: this._props.docView._props.styleProvider,
linkSrc: this._props.sourceDoc,
linkDoc: this._props.linkDoc,
showHeader: false,
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 7e344dd7a..c9e3c203d 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -7,7 +7,7 @@ import { Doc } from '../../../fields/Doc';
import { Transform } from '../../util/Transform';
import { undoBatch } from '../../util/UndoManager';
import { DefaultStyleProvider } from '../StyleProvider';
-import { OpenWhere } from '../nodes/DocumentView';
+import { OpenWhere, returnEmptyDocViewList } from '../nodes/DocumentView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { SearchBox } from '../search/SearchBox';
import './LinkPopup.scss';
@@ -61,6 +61,7 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
<SearchBox
Document={Doc.MySearcher}
+ docViewPath={returnEmptyDocViewList}
linkFrom={linkDoc}
linkCreateAnchor={this.props.linkCreateAnchor}
linkSearch={true}
@@ -69,7 +70,6 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
isSelected={returnTrue}
isContentActive={returnTrue}
select={returnTrue}
- setHeight={returnFalse}
addDocument={undefined}
addDocTab={returnTrue}
pinToPres={emptyFunction}
@@ -81,9 +81,7 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
PanelHeight={this.getPHeight}
renderDepth={0}
focus={emptyFunction}
- docViewPath={returnEmptyDoclist}
whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
diff --git a/src/client/views/newlightbox/NewLightboxView.tsx b/src/client/views/newlightbox/NewLightboxView.tsx
index 3d159c3e3..12b9870ca 100644
--- a/src/client/views/newlightbox/NewLightboxView.tsx
+++ b/src/client/views/newlightbox/NewLightboxView.tsx
@@ -302,7 +302,7 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
styleProvider={DefaultStyleProvider}
ScreenToLocalTransform={this.newLightboxScreenToLocal}
renderDepth={0}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
childFilters={this.docFilters}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
@@ -311,8 +311,7 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
whenChildContentsActiveChanged={emptyFunction}
addDocTab={this.addDocTab}
pinToPres={TabDocView.PinDoc}
- bringToFront={emptyFunction}
- onBrowseClick={DocumentView.exploreMode}
+ onBrowseClickScript={DocumentView.exploreMode}
focus={emptyFunction}
/>
</GestureOverlay>
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 908cd5dc0..8a38ef663 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -5,6 +5,7 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import { DateField } from '../../../fields/DateField';
import { Doc } from '../../../fields/Doc';
+import { DocData } from '../../../fields/DocSymbols';
import { ComputedField } from '../../../fields/ScriptField';
import { Cast, DateCast, NumCast } from '../../../fields/Types';
import { AudioField, nullAudio } from '../../../fields/URLField';
@@ -19,8 +20,7 @@ import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { ViewBoxAnnotatableComponent } from '../DocComponent';
import './AudioBox.scss';
-import { DocFocusOptions } from './DocumentView';
-import { FieldView, FieldViewProps } from './FieldView';
+import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView';
import { PinProps, PresBox } from './trails';
/**
@@ -121,7 +121,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@action
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
if (this.path) {
this.mediaState = media_state.Paused;
this.setPlayheadTime(NumCast(this.layoutDoc.clipStart));
@@ -211,7 +211,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// removes from currently playing display
@action
removeCurrentlyPlaying = () => {
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
if (CollectionStackedTimeline.CurrentlyPlaying && docView) {
const index = CollectionStackedTimeline.CurrentlyPlaying.indexOf(docView);
index !== -1 && CollectionStackedTimeline.CurrentlyPlaying.splice(index, 1);
@@ -221,7 +221,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// adds doc to currently playing display
@action
addCurrentlyPlaying = () => {
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
if (!CollectionStackedTimeline.CurrentlyPlaying) {
CollectionStackedTimeline.CurrentlyPlaying = [];
}
@@ -374,9 +374,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
action(() => {
const newDoc = DocUtils.GetNewTextDoc('', NumCast(this.Document.x), NumCast(this.Document.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height));
const textField = Doc.LayoutFieldKey(newDoc);
- Doc.GetProto(newDoc)[`${textField}_recordingSource`] = this.dataDoc;
- Doc.GetProto(newDoc)[`${textField}_recordingStart`] = ComputedField.MakeFunction(`this.${textField}_recordingSource.${this.fieldKey}_recordingStart`);
- Doc.GetProto(newDoc).mediaState = ComputedField.MakeFunction(`this.${textField}_recordingSource.mediaState`);
+ const newDocData = newDoc[DocData];
+ newDocData[`${textField}_recordingSource`] = this.dataDoc;
+ newDocData[`${textField}_recordingStart`] = ComputedField.MakeFunction(`this.${textField}_recordingSource.${this.fieldKey}_recordingStart`);
+ newDocData.mediaState = ComputedField.MakeFunction(`this.${textField}_recordingSource.mediaState`);
if (Doc.IsInMyOverlay(this.Document)) {
newDoc.overlayX = this.Document.x;
newDoc.overlayY = NumCast(this.Document.y) + NumCast(this.layoutDoc._height);
@@ -432,7 +433,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
};
// plays link
- playLink = (link: Doc, options: DocFocusOptions) => {
+ playLink = (link: Doc, options: FocusViewOptions) => {
if (link.annotationOn === this.Document) {
if (!this.layoutDoc.dontAutoPlayFollowedLinks) {
this.playFrom(this.timeline?.anchorStart(link) || 0, this.timeline?.anchorEnd(link));
@@ -567,8 +568,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
const [xp, yp] = this.ScreenToLocalBoxXf().transformPoint(de.x, de.y);
de.complete.docDragData && this.timeline?.internalDocDrop(e, de, de.complete.docDragData, xp);
},
- this.layoutDoc,
- undefined
+ this.layoutDoc
);
}
};
@@ -717,7 +717,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
renderDepth={this._props.renderDepth + 1}
startTag={'_timecodeToShow' /* audioStart */}
endTag={'_timecodeToHide' /* audioEnd */}
- bringToFront={emptyFunction}
playFrom={this.playFrom}
setTime={this.setPlayheadTime}
playing={this.playing}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index ad5aabc21..0ae4ed62c 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -12,10 +12,11 @@ import { DocumentManager } from '../../util/DocumentManager';
import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { SelectionManager } from '../../util/SelectionManager';
import { DocComponent } from '../DocComponent';
+import { ObservableReactComponent } from '../ObservableReactComponent';
import { StyleProp } from '../StyleProvider';
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import './CollectionFreeFormDocumentView.scss';
-import { DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from './DocumentView';
+import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView';
import { FieldViewProps } from './FieldView';
export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentViewProps {
@@ -37,8 +38,8 @@ export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentView
CollectionFreeFormView: CollectionFreeFormView;
}
@observer
-export class CollectionFreeFormDocumentViewWrapper extends DocComponent<CollectionFreeFormDocumentViewWrapperProps & { fieldKey: string }>() implements CollectionFreeFormDocumentViewProps {
- constructor(props: any) {
+export class CollectionFreeFormDocumentViewWrapper extends ObservableReactComponent<CollectionFreeFormDocumentViewWrapperProps> {
+ constructor(props: CollectionFreeFormDocumentViewWrapperProps) {
super(props);
makeObservable(this);
}
@@ -59,6 +60,9 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent<Collecti
CollectionFreeFormView = this.props.CollectionFreeFormView; // needed for type checking
RenderCutoffProvider = this.props.RenderCutoffProvider; // needed for type checking
+ get Document() {
+ return this._props.Document;
+ }
@computed get WrapperKeys() {
return Object.keys(this).filter(key => key.startsWith('w_')).map(key => key.replace('w_', ''))
.map(key => ({upper:key, lower:key[0].toLowerCase() + key.substring(1)})); // prettier-ignore
@@ -100,7 +104,7 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent<Collecti
);
}
}
-export interface CollectionFreeFormDocumentViewProps {
+export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
w_X: () => number;
w_Y: () => number;
w_Z: () => number;
@@ -121,8 +125,8 @@ export interface CollectionFreeFormDocumentViewProps {
}
@observer
-export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeFormDocumentViewProps & DocumentViewProps>() {
- constructor(props: any) {
+export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeFormDocumentViewProps>() {
+ constructor(props: CollectionFreeFormDocumentViewProps) {
super(props);
makeObservable(this);
}
@@ -149,7 +153,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
return this._props.CollectionFreeFormView;
}
- styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => {
+ styleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => {
if (doc === this.layoutDoc) {
switch (property) {
case StyleProp.Opacity: return this._props.w_Opacity(); // only change the opacity for this specific document, not its children
@@ -227,9 +231,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
});
}
- @action public float = () => {
+ float = () => {
const topDoc = this.Document;
- const containerDocView = this._props.docViewPath().lastElement();
+ const containerDocView = this._props.containerViewPath?.().lastElement();
const screenXf = containerDocView?.screenToContentsTransform();
if (screenXf) {
SelectionManager.DeselectAll();
@@ -252,9 +256,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
};
nudge = (x: number, y: number) => {
- const [locX, locY] = this.ScreenToLocalBoxXf().transformDirection(x, y);
- this._props.Document.x = this._props.w_X() + locX;
- this._props.Document.y = this._props.w_Y() + locY;
+ const [locX, locY] = this._props.ScreenToLocalTransform().transformDirection(x, y);
+ this.Document.x = this._props.w_X() + locX;
+ this.Document.y = this._props.w_Y() + locY;
};
screenToLocalTransform = () =>
this._props
@@ -288,7 +292,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
zIndex: this._props.w_ZIndex?.(),
display: this._props.w_Width?.() ? undefined : 'none',
}}>
- {this._props.RenderCutoffProvider(this._props.Document) ? (
+ {this._props.RenderCutoffProvider(this.Document) ? (
<div style={{ position: 'absolute', width: this._props.PanelWidth(), height: this._props.PanelHeight(), background: 'lightGreen' }} />
) : (
<DocumentView {...passOnProps} CollectionFreeFormDocumentView={this.returnThis} styleProvider={this.styleProvider} ScreenToLocalTransform={this.screenToLocalTransform} isGroupActive={this.isGroupActive} />
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 5e7e568b0..116dc48a6 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -8,20 +8,20 @@ import { DocCast, NumCast, StrCast } from '../../../fields/Types';
import { DocUtils, Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
import { undoBatch } from '../../util/UndoManager';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
import { StyleProp } from '../StyleProvider';
import './ComparisonBox.scss';
-import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from './DocumentView';
+import { DocumentView } from './DocumentView';
import { FieldView, FieldViewProps } from './FieldView';
import { PinProps, PresBox } from './trails';
@observer
-export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(ComparisonBox, fieldKey);
}
private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined];
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
@@ -35,7 +35,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
return '_' + this._props.fieldKey + '_clipWidth';
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string, disposerId: number) => {
this._disposers[disposerId]?.();
@@ -148,7 +148,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
e => this.clearDoc(which)
);
};
- docStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ docStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => {
if (property === StyleProp.PointerEvents) return 'none';
return this._props.styleProvider?.(doc, props, property);
};
@@ -178,6 +178,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
{...this._props}
Document={targetDoc}
TemplateDataDocument={undefined}
+ containerViewPath={this.DocumentView?.().docViewPath}
moveDocument={which.endsWith('1') ? this.moveDoc1 : this.moveDoc2}
removeDocument={which.endsWith('1') ? this.remDoc1 : this.remDoc2}
NativeWidth={returnZero}
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 5a55ca764..8365f4770 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Colors, Toggle, ToggleType, Type } from 'browndash-components';
-import { ObservableMap, action, computed, observable, runInAction } from 'mobx';
+import { ObservableMap, action, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { emptyFunction, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents } from '../../../../Utils';
@@ -14,14 +14,13 @@ import { TraceMobx } from '../../../../fields/util';
import { Docs } from '../../../documents/Documents';
import { DocumentManager } from '../../../util/DocumentManager';
import { UndoManager, undoable } from '../../../util/UndoManager';
-import { ViewBoxAnnotatableComponent } from '../../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent';
import { MarqueeAnnotator } from '../../MarqueeAnnotator';
import { SidebarAnnos } from '../../SidebarAnnos';
-import { CollectionFreeFormView } from '../../collections/collectionFreeForm';
import { AnchorMenu } from '../../pdf/AnchorMenu';
import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup';
-import { DocFocusOptions, DocumentView } from '../DocumentView';
-import { FieldView, FieldViewProps } from '../FieldView';
+import { DocumentView } from '../DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
import { PinProps } from '../trails';
import './DataVizBox.scss';
import { Histogram } from './components/Histogram';
@@ -37,22 +36,28 @@ export enum DataVizView {
}
@observer
-export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
+export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
- private _ffref = React.createRef<CollectionFreeFormView>();
private _marqueeref = React.createRef<MarqueeAnnotator>();
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
anchorMenuClick?: () => undefined | ((anchor: Doc) => void);
crop: ((region: Doc | undefined, addCrop?: boolean) => Doc | undefined) | undefined;
- @observable schemaDataVizChildren: any = undefined;
+ @observable _schemaDataVizChildren: any = undefined;
@observable _marqueeing: number[] | undefined = undefined;
@observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
+
+ constructor(props: FieldViewProps) {
+ super(props);
+ makeObservable(this);
+ this._props.setContentViewBox?.(this);
+ }
+
@computed get annotationLayer() {
TraceMobx();
return <div className="dataVizBox-annotationLayer" style={{ height: this._props.PanelHeight(), width: this._props.PanelWidth() }} ref={this._annotationLayer} />;
}
marqueeDown = (e: React.PointerEvent) => {
- if (!e.altKey && e.button === 0 && NumCast(this.Document._freeform_scale, 1) <= NumCast(this.Document.freeform_scaleMin, 1) && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && NumCast(this.Document._freeform_scale, 1) <= NumCast(this.Document.freeform_scaleMin, 1) && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
setupMoveUpEvents(
this,
e,
@@ -211,12 +216,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
.ScreenToLocalTransform()
.scale(this._props.NativeDimScaling?.() || 1)
.transformDirection(delta[0], delta[1]);
- const fullWidth = this._props.width;
- const mapWidth = fullWidth! - this.sidebarWidth();
+ const fullWidth = NumCast(this.layoutDoc._width);
+ const mapWidth = fullWidth - this.sidebarWidth();
if (this.sidebarWidth() + localDelta[0] > 0) {
this.layoutDoc._layout_showSidebar = true;
- this.layoutDoc._width = fullWidth! + localDelta[0];
- this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth! + localDelta[0])).toString() + '%';
+ this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%';
+ this.layoutDoc._width = fullWidth + localDelta[0];
} else {
this.layoutDoc._layout_showSidebar = false;
this.layoutDoc._width = mapWidth;
@@ -228,7 +233,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
() => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar')
);
};
- getView = async (doc: Doc, options: DocFocusOptions) => {
+ getView = async (doc: Doc, options: FocusViewOptions) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
options.didMove = true;
this.toggleSidebar();
@@ -249,7 +254,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => this.removeDocument(doc, sidebarKey);
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData();
}
@@ -269,12 +274,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
axes: this.axes,
//width: this.SidebarShown? this._props.PanelWidth()*.9/1.2: this._props.PanelWidth() * 0.9,
height: (this._props.PanelHeight() / scale - 32) /* height of 'change view' button */ * 0.9,
- width: (this._props.PanelWidth() / scale) * 0.9,
+ width: ((this._props.PanelWidth() - this.sidebarWidth()) / scale) * 0.9,
margin: { top: 10, right: 25, bottom: 75, left: 45 },
};
if (!this.records.length) return 'no data/visualization';
switch (this.dataVizView) {
- case DataVizView.TABLE: return <TableBox {...sharedProps} docView={this._props.DocumentView} selectAxes={this.selectAxes} />;
+ case DataVizView.TABLE: return <TableBox {...sharedProps} docView={this.DocumentView} selectAxes={this.selectAxes} />;
case DataVizView.LINECHART: return <LineChart {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} vizBox={this} />;
case DataVizView.HISTOGRAM: return <Histogram {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />;
case DataVizView.PIECHART: return <PieChart {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)}
@@ -285,7 +290,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@action
onPointerDown = (e: React.PointerEvent): void => {
if ((this.Document._freeform_scale || 1) !== 1) return;
- if (!e.altKey && e.button === 0 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
this._props.select(false);
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
this._marqueeing = [e.clientX, e.clientY];
@@ -345,7 +350,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
render() {
if (this.layoutDoc && this.layoutDoc.dataViz_asSchema) {
- this.schemaDataVizChildren = DocListCast(DocCast(this.layoutDoc.dataViz_asSchema)[Doc.LayoutFieldKey(DocCast(this.layoutDoc.dataViz_asSchema))]).length;
+ this._schemaDataVizChildren = DocListCast(DocCast(this.layoutDoc.dataViz_asSchema)[Doc.LayoutFieldKey(DocCast(this.layoutDoc.dataViz_asSchema))]).length;
this.updateSchemaViz();
}
@@ -366,7 +371,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}}
onWheel={e => e.stopPropagation()}
ref={this._mainCont}>
- <div className={'datatype-button'}>
+ <div className="datatype-button">
<Toggle text={' TABLE '} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.TABLE)} toggleStatus={this.layoutDoc._dataViz === DataVizView.TABLE} />
<Toggle text={'LINECHART'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.LINECHART)} toggleStatus={this.layoutDoc._dataViz === DataVizView.LINECHART} />
<Toggle text={'HISTOGRAM'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.HISTOGRAM)} toggleStatus={this.layoutDoc._dataViz === DataVizView.HISTOGRAM} />
@@ -414,7 +419,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
</div>
{this.sidebarHandle}
{this.annotationLayer}
- {!this._mainCont.current || !this._annotationLayer.current ? null : (
+ {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : (
<MarqueeAnnotator
ref={this._marqueeref}
Document={this.Document}
@@ -422,7 +427,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
scrollTop={0}
annotationLayerScrollTop={NumCast(this.Document._layout_scrollTop)}
scaling={returnOne}
- docView={this._props.DocumentView!}
+ docView={this.DocumentView}
addDocument={this.sidebarAddDocument}
finishMarquee={this.finishMarquee}
savedAnnotations={this.savedAnnotations}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 4cc7fe4c8..07e179246 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -24,7 +24,6 @@ import { YoutubeBox } from './../../apis/youtube/YoutubeBox';
import { AudioBox } from './AudioBox';
import { ComparisonBox } from './ComparisonBox';
import { DataVizBox } from './DataVizBox/DataVizBox';
-import { DocumentViewProps } from './DocumentView';
import './DocumentView.scss';
import { EquationBox } from './EquationBox';
import { FieldView, FieldViewProps } from './FieldView';
@@ -114,14 +113,11 @@ export class HTMLtag extends React.Component<HTMLtagProps> {
}
}
+export interface DocumentContentsViewProps extends FieldViewProps {
+ layoutFieldKey: string;
+}
@observer
-export class DocumentContentsView extends ObservableReactComponent<
- DocumentViewProps &
- FieldViewProps & {
- setHeight?: (height: number) => void;
- layout_fieldKey: string;
- }
-> {
+export class DocumentContentsView extends ObservableReactComponent<DocumentContentsViewProps> {
constructor(props: any) {
super(props);
makeObservable(this);
@@ -131,8 +127,8 @@ export class DocumentContentsView extends ObservableReactComponent<
TraceMobx();
if (this._props.LayoutTemplateString) return this._props.LayoutTemplateString;
if (!this.layoutDoc) return '<p>awaiting layout</p>';
- if (this._props.layout_fieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString());
- const layout = Cast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.layout_fieldKey ? this._props.layout_fieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string');
+ if (this._props.layoutFieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString());
+ const layout = Cast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.layoutFieldKey ? this._props.layoutFieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string');
if (layout === undefined) return this._props.Document.data ? "<FieldView {...props} fieldKey='data' />" : KeyValueBox.LayoutString();
if (typeof layout === 'string') return layout;
return '<p>Loading layout</p>';
@@ -140,30 +136,31 @@ export class DocumentContentsView extends ObservableReactComponent<
get layoutDoc() {
// bcz: replaced this with below : is it correct? change was made to accommodate passing fieldKey's from a layout script
- // const template: Doc = this._props.LayoutTemplate?.() || Doc.Layout(this._props.Document, this._props.layout_fieldKey ? Cast(this._props.Document[this._props.layout_fieldKey], Doc, null) : undefined);
+ // const template: Doc = this._props.LayoutTemplate?.() || Doc.Layout(this._props.Document, this._props.fieldKey ? Cast(this._props.Document[this._props.fieldKey], Doc, null) : undefined);
const template: Doc =
this._props.LayoutTemplate?.() ||
(this._props.LayoutTemplateString && this._props.Document) ||
- (this._props.layout_fieldKey && StrCast(this._props.Document[this._props.layout_fieldKey]) && this._props.Document) ||
- Doc.Layout(this._props.Document, this._props.layout_fieldKey ? Cast(this._props.Document[this._props.layout_fieldKey], Doc, null) : undefined);
+ (this._props.layoutFieldKey && StrCast(this._props.Document[this._props.layoutFieldKey]) && this._props.Document) ||
+ Doc.Layout(this._props.Document, this._props.layoutFieldKey ? Cast(this._props.Document[this._props.layoutFieldKey], Doc, null) : undefined);
return Doc.expandTemplateLayout(template, this._props.Document);
}
CreateBindings(onClick: Opt<ScriptField>, onInput: Opt<ScriptField>): JsxBindings {
const docOnlyProps = [
- // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews
+ // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews
'hideResizeHandles',
'hideTitle',
- 'contentPointerEvents',
- 'radialMenu',
+ 'bringToFront',
+ 'childContentPointerEvents',
'LayoutTemplateString',
'LayoutTemplate',
+ 'layoutFieldKey',
'dontCenter',
'contextMenuItems',
//'onClick', // don't need to omit this since it will be set
- 'onDoubleClick',
- 'onPointerDown',
- 'onPointerUp',
+ 'onDoubleClickScript',
+ 'onPointerDownScript',
+ 'onPointerUpScript',
];
const templateDataDoc = this._props.TemplateDataDocument ?? (this.layoutDoc !== this._props.Document ? this._props.Document[DocData] : undefined);
const list: BindingProps & React.DetailedHTMLProps<React.HtmlHTMLAttributes<HTMLDivElement>, HTMLDivElement> = {
diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx
index dfd610581..4a22766cc 100644
--- a/src/client/views/nodes/DocumentIcon.tsx
+++ b/src/client/views/nodes/DocumentIcon.tsx
@@ -25,11 +25,11 @@ export class DocumentIcon extends ObservableReactComponent<DocumentIconProps> {
}
static get DocViews() {
- return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.IsLightboxDocView(v._props.docViewPath())) : DocumentManager.Instance.DocumentViews;
+ return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.Contains(v)) : DocumentManager.Instance.DocumentViews;
}
render() {
const view = this._props.view;
- const { left, top, right, bottom } = view.getBounds() || { left: 0, top: 0, right: 0, bottom: 0 };
+ const { left, top, right, bottom } = view.getBounds || { left: 0, top: 0, right: 0, bottom: 0 };
return (
<div
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index c549a146a..d1805308d 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -17,6 +17,7 @@ import { DocumentView } from './DocumentView';
import { LinkDescriptionPopup } from './LinkDescriptionPopup';
import { TaskCompletionBox } from './TaskCompletedBox';
import { PinProps } from './trails';
+import { DocData } from '../../../fields/DocSymbols';
interface DocumentLinksButtonProps {
View: DocumentView;
@@ -152,47 +153,46 @@ export class DocumentLinksButton extends ObservableReactComponent<DocumentLinksB
DocumentLinksButton.AnnotationUri = undefined;
//!this._props.StartLink
} else if (startLink !== endLink) {
- endLink = endLinkView?.docView?._componentView?.getAnchor?.(true, pinProps) || endLink;
- startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.(true) || startLink;
+ endLink = endLinkView?.ComponentView?.getAnchor?.(true, pinProps) || endLink;
+ startLink = DocumentLinksButton.StartLinkView?.ComponentView?.getAnchor?.(true) || startLink;
const linkDoc = DocUtils.MakeLink(startLink, endLink, { link_relationship: DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined });
LinkManager.currentLink = linkDoc;
- if (DocumentLinksButton.AnnotationId && DocumentLinksButton.AnnotationUri) {
- // if linking from a Hypothes.is annotation
- Doc.GetProto(linkDoc as Doc).linksToAnnotation = true;
- Doc.GetProto(linkDoc as Doc).annotationId = DocumentLinksButton.AnnotationId;
- Doc.GetProto(linkDoc as Doc).annotationUri = DocumentLinksButton.AnnotationUri;
- const dashHyperlink = Doc.globalServerPath(startIsAnnotation ? endLink : startLink);
- Hypothesis.makeLink(StrCast(startIsAnnotation ? endLink.title : startLink.title), dashHyperlink, DocumentLinksButton.AnnotationId, startIsAnnotation ? startLink : endLink); // edit annotation to add a Dash hyperlink to the linked doc
- }
-
if (linkDoc) {
+ if (DocumentLinksButton.AnnotationId && DocumentLinksButton.AnnotationUri) {
+ // if linking from a Hypothes.is annotation
+ const linkDocData = linkDoc[DocData];
+ linkDocData.linksToAnnotation = true;
+ linkDocData.annotationId = DocumentLinksButton.AnnotationId;
+ linkDocData.annotationUri = DocumentLinksButton.AnnotationUri;
+ const dashHyperlink = Doc.globalServerPath(startIsAnnotation ? endLink : startLink);
+ Hypothesis.makeLink(StrCast(startIsAnnotation ? endLink.title : startLink.title), dashHyperlink, DocumentLinksButton.AnnotationId, startIsAnnotation ? startLink : endLink); // edit annotation to add a Dash hyperlink to the linked doc
+ }
+
TaskCompletionBox.textDisplayed = 'Link Created';
TaskCompletionBox.popupX = screenX;
TaskCompletionBox.popupY = screenY - 133;
TaskCompletionBox.taskCompleted = true;
- if (LinkDescriptionPopup.showDescriptions === 'ON' || !LinkDescriptionPopup.showDescriptions) {
- LinkDescriptionPopup.popupX = screenX;
- LinkDescriptionPopup.popupY = screenY - 100;
- LinkDescriptionPopup.descriptionPopup = true;
+ if (LinkDescriptionPopup.Instance.showDescriptions === 'ON' || !LinkDescriptionPopup.Instance.showDescriptions) {
+ LinkDescriptionPopup.Instance.popupX = screenX;
+ LinkDescriptionPopup.Instance.popupY = screenY - 100;
+ LinkDescriptionPopup.Instance.display = true;
}
const rect = document.body.getBoundingClientRect();
- if (LinkDescriptionPopup.popupX + 200 > rect.width) {
- LinkDescriptionPopup.popupX -= 190;
+ if (LinkDescriptionPopup.Instance.popupX + 200 > rect.width) {
+ LinkDescriptionPopup.Instance.popupX -= 190;
TaskCompletionBox.popupX -= 40;
}
- if (LinkDescriptionPopup.popupY + 100 > rect.height) {
- LinkDescriptionPopup.popupY -= 40;
+ if (LinkDescriptionPopup.Instance.popupY + 100 > rect.height) {
+ LinkDescriptionPopup.Instance.popupY -= 40;
TaskCompletionBox.popupY -= 40;
}
setTimeout(
- action(() => {
- TaskCompletionBox.taskCompleted = false;
- }),
+ action(() => (TaskCompletionBox.taskCompleted = false)),
2500
);
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 6cc61ec62..8eb354e1e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -3,19 +3,17 @@ import { Dropdown, DropdownType, Type } from 'browndash-components';
import { Howl } from 'howler';
import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
-import { computedFn } from 'mobx-utils';
import * as React from 'react';
import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal';
import { Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils';
import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc';
-import { AclPrivate, Animation, AudioPlay, DocViews } from '../../../fields/DocSymbols';
+import { AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
-import { RefField } from '../../../fields/RefField';
import { listSpec } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
+import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { AudioField } from '../../../fields/URLField';
import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
import { DocServer } from '../../DocServer';
@@ -33,34 +31,27 @@ import { SelectionManager } from '../../util/SelectionManager';
import { SettingsManager } from '../../util/SettingsManager';
import { SharingManager } from '../../util/SharingManager';
import { SnappingManager } from '../../util/SnappingManager';
-import { Transform } from '../../util/Transform';
-import { UndoManager, undoBatch } from '../../util/UndoManager';
+import { UndoManager, undoBatch, undoable } from '../../util/UndoManager';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { DocComponent } from '../DocComponent';
+import { DocComponent, ViewBoxInterface } from '../DocComponent';
import { EditableView } from '../EditableView';
import { GestureOverlay } from '../GestureOverlay';
import { LightboxView } from '../LightboxView';
-import { ObservableReactComponent } from '../ObservableReactComponent';
import { StyleProp } from '../StyleProvider';
-import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView';
import { DocumentContentsView, ObserverJsxParser } from './DocumentContentsView';
import { DocumentLinksButton } from './DocumentLinksButton';
import './DocumentView.scss';
-import { FieldViewProps } from './FieldView';
+import { FieldViewProps, FieldViewSharedProps } from './FieldView';
import { KeyValueBox } from './KeyValueBox';
import { LinkAnchorBox } from './LinkAnchorBox';
import { FormattedTextBox } from './formattedText/FormattedTextBox';
import { PresEffect, PresEffectDirection } from './trails';
-import { PinProps, PresBox } from './trails/PresBox';
-
interface Window {
MediaRecorder: MediaRecorder;
}
-
declare class MediaRecorder {
- // whatever MediaRecorder has
- constructor(e: any);
+ constructor(e: any); // whatever MediaRecorder has
}
export enum OpenWhereMod {
@@ -89,118 +80,10 @@ export enum OpenWhere {
addRightKeyvalue = 'add:right:keyValue',
}
-export interface DocFocusOptions {
- willPan?: boolean; // determines whether to pan to target document
- willZoomCentered?: boolean; // determines whether to zoom in on target document. if zoomScale is 0, this just centers the document
- zoomScale?: number; // percent of containing frame to zoom into document
- zoomTime?: number;
- didMove?: boolean; // whether a document was changed during the showDocument process
- docTransform?: Transform; // when a document can't be panned and zoomed within its own container (say a group), then we need to continue to move up the render hierarchy to find something that can pan and zoom. when this happens the docTransform must accumulate all the transforms of each level of the hierarchy
- instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom)
- preview?: boolean; // whether changes should be previewed by the componentView or written to the document
- effect?: Doc; // animation effect for focus
- noSelect?: boolean; // whether target should be selected after focusing
- playAudio?: boolean; // whether to play audio annotation on focus
- playMedia?: boolean; // whether to play start target videos
- openLocation?: OpenWhere; // where to open a missing document
- zoomTextSelections?: boolean; // whether to display a zoomed overlay of anchor text selections
- toggleTarget?: boolean; // whether to toggle target on and off
- anchorDoc?: Doc; // doc containing anchor info to apply at end of focus to target doc
- easeFunc?: 'linear' | 'ease'; // transition method for scrolling
-}
-export type DocFocusFunc = (doc: Doc, options: DocFocusOptions) => Opt<number>;
-export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => any;
-export interface DocComponentView {
- fieldKey?: string;
- annotationKey?: string;
- updateIcon?: () => void; // updates the icon representation of the document
- getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box)
- restoreView?: (viewSpec: Doc) => boolean;
- scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: DocFocusOptions) => Opt<number>; // returns the duration of the focus
- brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number, holdTime: number) => void; // highlight a region of a view (used by freeforms)
- getView?: (doc: Doc, options: DocFocusOptions) => Promise<Opt<DocumentView>>; // returns a nested DocumentView for the specified doc or undefined
- addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox
- addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections)
- select?: (ctrlKey: boolean, shiftKey: boolean) => void;
- focus?: (textAnchor: Doc, options: DocFocusOptions) => Opt<number>;
- isAnyChildContentActive?: () => boolean; // is any child content of the document active
- onClickScriptDisable?: () => 'never' | 'always'; // disable click scripts : never, always, or undefined = only when selected
- getKeyFrameEditing?: () => boolean; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
- setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
- playFrom?: (time: number, endTime?: number) => void;
- Pause?: () => void; // pause a media document (eg, audio/video)
- IsPlaying?: () => boolean; // is a media document playing
- TogglePause?: (keep?: boolean) => void; // toggle media document playing state
- setFocus?: () => void; // sets input focus to the componentView
- setData?: (data: Field | Promise<RefField | undefined>) => boolean;
- componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element | null;
- dragStarting?: (snapToDraggedDoc: boolean, showGroupDragTarget: boolean, visited: Set<Doc>) => void;
- incrementalRendering?: () => void;
- infoUI?: () => JSX.Element | null;
- screenBounds?: () => Opt<{ left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } }>;
- ptToScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number };
- ptFromScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number };
- snapPt?: (pt: { X: number; Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number; Y: number }; distance: number };
- search?: (str: string, bwd?: boolean, clear?: boolean) => boolean;
-}
-// These props are passed to both FieldViews and DocumentViews
-export interface DocumentViewSharedProps {
- renderDepth: number;
- Document: Doc;
- TemplateDataDocument?: Doc;
- scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document
- DocumentView?: () => DocumentView;
- CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView;
- fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document
- isGroupActive?: () => string | undefined; // is this document part of a group that is active
- setContentView?: (view: DocComponentView) => any;
- PanelWidth: () => number;
- PanelHeight: () => number;
- docViewPath: () => DocumentView[];
- childFilters: () => string[];
- childFiltersByRanges: () => string[];
- styleProvider: Opt<StyleProviderFunc>;
- setTitleFocus?: () => void;
- focus: DocFocusFunc;
- layout_fitWidth?: (doc: Doc) => boolean | undefined;
- searchFilterDocs: () => Doc[];
- layout_showTitle?: () => string;
- whenChildContentsActiveChanged: (isActive: boolean) => void;
- rootSelected?: () => boolean; // whether the root of a template has been selected
- addDocTab: (doc: Doc, where: OpenWhere) => boolean;
- filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
- addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean;
- removeDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean;
- moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => boolean;
- pinToPres: (document: Doc, pinProps: PinProps) => void;
- ScreenToLocalTransform: () => Transform;
- bringToFront: (doc: Doc, sendToBack?: boolean) => void;
- waitForDoubleClickToClick?: () => 'never' | 'always' | undefined;
- defaultDoubleClick?: () => 'default' | 'ignore' | undefined;
- pointerEvents?: () => Opt<string>;
- treeViewDoc?: Doc;
- xPadding?: number;
- yPadding?: number;
- dontRegisterView?: boolean;
- childHideDecorationTitle?: boolean;
- childHideResizeHandles?: boolean;
- childDragAction?: dropActionType; // allows child documents to be dragged out of collection without holding the embedKey or dragging the doc decorations title bar.
- dropAction?: dropActionType;
- dragAction?: dropActionType;
- dragWhenActive?: boolean;
- dontHideOnDrag?: boolean;
- hideLinkButton?: boolean;
- hideCaptions?: boolean;
- ignoreAutoHeight?: boolean;
- forceAutoHeight?: boolean;
- suppressSetHeight?: boolean;
- disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
- onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected
+export function returnEmptyDocViewList() {
+ return [] as DocumentView[];
}
-
-// these props are specific to DocuentViews
-export interface DocumentViewProps extends DocumentViewSharedProps {
- // properties specific to DocumentViews but not to FieldView
+export interface DocumentViewProps extends FieldViewSharedProps {
hideDecorations?: boolean; // whether to suppress all DocumentDecorations when doc is selected
hideResizeHandles?: boolean; // whether to suppress resized handles on doc decorations when this document is selected
hideTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings
@@ -209,37 +92,35 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
hideOpenButton?: boolean;
hideDeleteButton?: boolean;
hideLinkAnchors?: boolean;
+ hideLinkButton?: boolean;
+ hideCaptions?: boolean;
contentPointerEvents?: 'none' | 'all' | undefined; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
- LayoutTemplateString?: string;
dontCenter?: 'x' | 'y' | 'xy';
- isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events
- isContentActive: () => boolean | undefined; // whether document contents should handle pointer events
+ childHideDecorationTitle?: boolean;
+ childHideResizeHandles?: boolean;
+ childDragAction?: dropActionType; // allows child documents to be dragged out of collection without holding the embedKey or dragging the doc decorations title bar.
+ dragWhenActive?: boolean;
+ dontHideOnDrag?: boolean;
+ suppressSetHeight?: boolean;
+ onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected
NativeWidth?: () => number;
NativeHeight?: () => number;
- NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to FieldViewProps
- LayoutTemplate?: () => Opt<Doc>;
contextMenuItems?: () => { script: ScriptField; filter?: ScriptField; label: string; icon: string }[];
- onClick?: () => ScriptField;
- onDoubleClick?: () => ScriptField;
- onPointerDown?: () => ScriptField;
- onPointerUp?: () => ScriptField;
- onBrowseClick?: () => ScriptField | undefined;
- onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined;
dragStarting?: () => void;
dragEnding?: () => void;
}
-
-// these props are only available in DocumentViewIntenral
-export interface DocumentViewInternalProps extends DocumentViewProps {
- isSelected: () => boolean;
- select: (ctrlPressed: boolean, shiftPress?: boolean) => void;
- DocumentView: () => DocumentView;
- viewPath: () => DocumentView[];
-}
-
@observer
-export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps>() {
+export class DocumentViewInternal extends DocComponent<FieldViewProps & DocumentViewProps>() {
+ // this makes mobx trace() statements more descriptive
+ public get displayName() { return 'DocumentViewInternal(' + this.Document.title + ')'; } // prettier-ignore
public static SelectAfterContextMenu = true; // whether a document should be selected after it's contextmenu is triggered.
+
+ /**
+ * This function is filled in by MainView to allow non-viewBox views to add Docs as tabs without
+ * needing to know about/reference MainView
+ */
+ public static addDocTabFunc: (doc: Doc, location: OpenWhere) => boolean = returnFalse;
+
private _disposers: { [name: string]: IReactionDisposer } = {};
private _doubleClickTimeout: NodeJS.Timeout | undefined;
private _singleClickFunc: undefined | (() => any);
@@ -252,72 +133,51 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
private _mainCont = React.createRef<HTMLDivElement>();
private _titleRef = React.createRef<EditableView>();
private _dropDisposer?: DragManager.DragDropDisposer;
- constructor(props: any) {
+ constructor(props: FieldViewProps & DocumentViewProps) {
super(props);
makeObservable(this);
}
- @observable _componentView: Opt<DocComponentView> = undefined; // needs to be accessed from DocumentView wrapper class
+ @observable _changingTitleField = false;
+ @observable _titleDropDownInnerWidth = 0; // width of menu dropdown when setting doc title
+ @observable _mounted = false; // turn off all pointer events if component isn't yet mounted (enables nested Docs in alternate UI textboxes that appear on hover which otherwise would grab focus from the text box, reverting to the original UI )
+ @observable _isContentActive: boolean | undefined = undefined;
+ @observable _pointerEvents: 'none' | 'all' | 'visiblePainted' | undefined = undefined;
+ @observable _componentView: Opt<ViewBoxInterface> = undefined; // needs to be accessed from DocumentView wrapper class
@observable _animateScaleTime: Opt<number> = undefined; // milliseconds for animating between views. defaults to 300 if not uset
@observable _animateScalingTo = 0;
- public get animateScaleTime() {
- return this._animateScaleTime ?? 100;
- }
- public get displayName() {
- return 'DocumentViewInternal(' + this._props.Document.title + ')';
- } // this makes mobx trace() statements more descriptive
+ get _contentDiv() { return this._mainCont.current; } // prettier-ignore
+ get _docView() { return this._props.DocumentView?.(); } // prettier-ignore
+
+ animateScaleTime = () => this._animateScaleTime ?? 100;
+ style = (doc: Doc, sprop: StyleProp | string) => this._props.styleProvider?.(doc, this._props, sprop);
+ @computed get layout_showTitle() { return this.style(this.layoutDoc, StyleProp.ShowTitle) as Opt<string>; } // prettier-ignore
+ @computed get opacity() { return this.style(this.layoutDoc, StyleProp.Opacity); } // prettier-ignore
+ @computed get boxShadow() { return this.style(this.layoutDoc, StyleProp.BoxShadow); } // prettier-ignore
+ @computed get borderRounding() { return this.style(this.layoutDoc, StyleProp.BorderRounding); } // prettier-ignore
+ @computed get widgetDecorations() { return this.style(this.layoutDoc, StyleProp.Decorations); } // prettier-ignore
+ @computed get backgroundBoxColor() { return this.style(this.layoutDoc, StyleProp.BackgroundColor + ':box'); } // prettier-ignore
+ @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) ?? 0; } // prettier-ignore
+ @computed get layout_showCaption() { return this.style(this.layoutDoc, StyleProp.ShowCaption) ?? 0; } // prettier-ignore
+ @computed get titleHeight() { return this.style(this.layoutDoc, StyleProp.TitleHeight) ?? 0; } // prettier-ignore
+ @computed get docContents() { return this.style(this.Document, StyleProp.DocContents); } // prettier-ignore
+ @computed get highlighting() { return this.style(this.Document, StyleProp.Highlighting); } // prettier-ignore
+ @computed get borderPath() { return this.style(this.Document, StyleProp.BorderPath); } // prettier-ignore
- public get ContentDiv() {
- return this._mainCont.current;
- }
- public get LayoutFieldKey() {
- return Doc.LayoutFieldKey(this.layoutDoc);
- }
- @computed get layout_showTitle() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.ShowTitle) as Opt<string>;
- }
- @computed get NativeDimScaling() {
- return this._props.NativeDimScaling?.() || 1;
- }
- @computed get thumb() {
- return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url?.href.replace('.png', '_m.png');
- }
- @computed get opacity() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Opacity);
- }
- @computed get boxShadow() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BoxShadow);
- }
- @computed get borderRounding() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding);
- }
- @computed get widgetDecorations() {
- TraceMobx();
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Decorations);
- }
- @computed get backgroundBoxColor() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor + ':box');
- }
- @computed get docContents() {
- return this._props.styleProvider?.(this.Document, this._props, StyleProp.DocContents);
- }
- @computed get headerMargin() {
- return this._props?.styleProvider?.(this.layoutDoc, this._props, StyleProp.HeaderMargin) || 0;
- }
- @computed get layout_showCaption() {
- return this._props?.styleProvider?.(this.layoutDoc, this._props, StyleProp.ShowCaption) || 0;
+ @computed get onClickHandler() {
+ return this._props.onClickScript?.() ?? this._props.onBrowseClickScript?.() ?? ScriptCast(this.Document.onClick, ScriptCast(this.layoutDoc.onClick));
}
- @computed get titleHeight() {
- return this._props?.styleProvider?.(this.layoutDoc, this._props, StyleProp.TitleHeight) || 0;
+ @computed get onDoubleClickHandler() {
+ return this._props.onDoubleClickScript?.() ?? ScriptCast(this.layoutDoc.onDoubleClick, ScriptCast(this.Document.onDoubleClick));
}
- @observable _pointerEvents: 'none' | 'all' | 'visiblePainted' | undefined = undefined;
- @computed get pointerEvents(): 'none' | 'all' | 'visiblePainted' | undefined {
- return this._pointerEvents;
+ @computed get onPointerDownHandler() {
+ return this._props.onPointerDownScript?.() ?? ScriptCast(this.layoutDoc.onPointerDown, ScriptCast(this.Document.onPointerDown));
}
- @computed get finalLayoutKey() {
- return StrCast(this.Document.layout_fieldKey, 'layout');
+ @computed get onPointerUpHandler() {
+ return this._props.onPointerUpScript?.() ?? ScriptCast(this.layoutDoc.onPointerUp, ScriptCast(this.Document.onPointerUp));
}
+
@computed get disableClickScriptFunc() {
const onScriptDisable = this._props.onClickScriptDisable ?? this._componentView?.onClickScriptDisable?.() ?? this.layoutDoc.onClickScriptDisable;
// prettier-ignore
@@ -327,23 +187,50 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
(onScriptDisable !== 'never' && (this.rootSelected() || this._componentView?.isAnyChildContentActive?.()))
);
}
- @computed get onClickHandler() {
- return this._props.onClick?.() ?? this._props.onBrowseClick?.() ?? Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null));
+ @computed get _rootSelected() {
+ return this._props.isSelected() || BoolCast(this._props.TemplateDataDocument && this._props.rootSelected?.());
}
- @computed get onDoubleClickHandler() {
- return this._props.onDoubleClick?.() ?? Cast(this.layoutDoc.onDoubleClick, ScriptField, null) ?? this.Document.onDoubleClick;
+ /// disable pointer events on content when there's an enabled onClick script (but not the browse script) and the contents aren't forced active, or if contents are marked inactive
+ @computed get _contentPointerEvents() {
+ TraceMobx();
+ return this._props.contentPointerEvents ??
+ ((!this.disableClickScriptFunc && //
+ this.onClickHandler &&
+ !this._props.onBrowseClickScript?.() &&
+ this.isContentActive() !== true) ||
+ this.isContentActive() === false)
+ ? 'none'
+ : this._pointerEvents;
}
- @computed get onPointerDownHandler() {
- return this._props.onPointerDown?.() ?? ScriptCast(this.Document.onPointerDown);
+
+ // We need to use allrelatedLinks to get not just links to the document as a whole, but links to
+ // anchors that are not rendered as DocumentViews (marked as 'layout_unrendered' with their 'annotationOn' set to this document). e.g.,
+ // - PDF text regions are rendered as an Annotations without generating a DocumentView, '
+ // - RTF selections are rendered via Prosemirror and have a mark which contains the Document ID for the annotation link
+ // - and links to PDF/Web docs at a certain scroll location never create an explicit view.
+ // For each of these, we create LinkAnchorBox's on the border of the DocumentView.
+ @computed get directLinks() {
+ TraceMobx();
+ return LinkManager.Instance.getAllRelatedLinks(this.Document).filter(
+ link =>
+ (link.link_matchEmbeddings ? link.link_anchor_1 === this.Document : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.Document)) ||
+ (link.link_matchEmbeddings ? link.link_anchor_2 === this.Document : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.Document)) ||
+ ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.Document)) ||
+ ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.Document))
+ );
}
- @computed get onPointerUpHandler() {
- return this._props.onPointerUp?.() ?? ScriptCast(this.Document.onPointerUp);
+ @computed get _allLinks() {
+ TraceMobx();
+ return LinkManager.Instance.getAllRelatedLinks(this.Document).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document);
+ }
+
+ @computed get filteredLinks() {
+ return DocUtils.FilterDocs(this.directLinks, this._props.childFilters?.() ?? [], []).filter(d => d.link_displayLine || Doc.UserDoc().showLinkLines);
}
componentWillUnmount() {
this.cleanupHandlers(true);
}
- @observable _mounted = false; // turn off all pointer events if component isn't yet mounted (enables nested Docs in alternate UI textboxes that appear on hover which otherwise would grab focus from the text box, reverting to the original UI )
componentDidMount() {
runInAction(() => (this._mounted = true));
@@ -363,47 +250,48 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
{ fireImmediately: true }
);
this._disposers.pointerevents = reaction(
- () => this._props.styleProvider?.(this.Document, this._props, StyleProp.PointerEvents),
+ () => this.style(this.Document, StyleProp.PointerEvents),
pointerevents => (this._pointerEvents = pointerevents),
{ fireImmediately: true }
);
}
- preDropFunc = (e: Event, de: DragManager.DropEvent) => {
- const dropAction = this.layoutDoc.dropAction as dropActionType;
- if (de.complete.docDragData && this.isContentActive() && !this._props.treeViewDoc) {
- dropAction && (de.complete.docDragData.dropAction = dropAction);
+ preDrop = (e: Event, de: DragManager.DropEvent, dropAction: dropActionType) => {
+ const dragData = de.complete.docDragData;
+ if (dragData && this.isContentActive() && !this.props.dontRegisterView) {
+ dragData.dropAction = dropAction ? dropAction : dragData.dropAction;
e.stopPropagation();
}
};
setupHandlers() {
this.cleanupHandlers(false);
if (this._mainCont.current) {
- this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this._props.Document, this.preDropFunc);
+ this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.Document, this.preDrop);
}
}
cleanupHandlers(unbrush: boolean) {
this._dropDisposer?.();
- unbrush && Doc.UnBrushDoc(this._props.Document);
+ unbrush && Doc.UnBrushDoc(this.Document);
Object.values(this._disposers).forEach(disposer => disposer?.());
}
startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) {
- if (this._mainCont.current) {
- const views = SelectionManager.Views.filter(dv => dv.docView?._mainCont.current);
- const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [this._props.DocumentView()];
+ const docView = this._docView;
+ if (this._mainCont.current && docView) {
+ const views = SelectionManager.Views.filter(dv => dv.ContentDiv);
+ const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [docView];
const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.Document));
- const screenXf = this.props.DocumentView().screenToViewTransform();
+ const screenXf = docView.screenToViewTransform();
const [left, top] = screenXf.inverse().transformPoint(0, 0);
dragData.offset = screenXf.transformDirection(x - left, y - top);
dragData.dropAction = dropAction;
- dragData.treeViewDoc = this._props.treeViewDoc;
dragData.removeDocument = this._props.removeDocument;
dragData.moveDocument = this._props.moveDocument;
- dragData.draggedViews = [this._props.DocumentView()];
+ dragData.draggedViews = [docView];
dragData.canEmbed = this.Document.dragAction ?? this._props.dragAction ? true : false;
+ this._componentView?.dragConfig?.(dragData);
DragManager.StartDocumentDrag(
- selected.map(dv => dv.docView!._mainCont.current!),
+ selected.map(dv => dv.ContentDiv!),
dragData,
x,
y,
@@ -412,29 +300,18 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
}
- defaultRestoreTargetView = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: DocFocusOptions) => {
- const targetMatch =
- 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;
- };
-
// switches text input focus to the title bar of the document (and displays the title bar if it hadn't been)
setTitleFocus = () => {
if (!StrCast(this.layoutDoc._layout_showTitle)) this.layoutDoc._layout_showTitle = 'title';
setTimeout(() => this._titleRef.current?.setIsFocused(true)); // use timeout in case title wasn't shown to allow re-render so that titleref will be defined
};
-
- public static addDocTabFunc: (doc: Doc, location: OpenWhere) => boolean = returnFalse;
-
onClick = action((e: React.MouseEvent | React.PointerEvent) => {
if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return;
- if (!this.Document.ignoreClick && this._props.renderDepth >= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
+ const documentView = this._docView;
+ if (documentView && !this.Document.ignoreClick && this._props.renderDepth >= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
let stopPropagate = true;
let preventDefault = true;
- !this.layoutDoc._keepZWhenDragged && this._props.bringToFront(this.Document);
+ !this.layoutDoc._keepZWhenDragged && this._props.bringToFront?.(this.Document);
if (this._doubleTap) {
const defaultDblclick = this._props.defaultDoubleClick?.() || this.Document.defaultDoubleClick;
if (this.onDoubleClickHandler?.script) {
@@ -443,7 +320,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const func = () => this.onDoubleClickHandler.script.run( {
this: this.Document,
scriptContext: this._props.scriptContext,
- documentView: this._props.DocumentView(),
+ documentView,
clientX, clientY, altKey, shiftKey, ctrlKey,
value: undefined,
}, console.log );
@@ -451,7 +328,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
} 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);
+ Doc.UnBrushDoc(this.Document);
} else {
this._singleClickFunc?.();
}
@@ -474,7 +351,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
this: this.Document,
_readOnly_: false,
scriptContext: this._props.scriptContext,
- documentView: this._props.DocumentView(),
+ documentView,
clientX,
clientY,
shiftKey,
@@ -498,7 +375,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const sendToBack = e.altKey;
this._singleClickFunc =
// prettier-ignore
- clickFunc ?? (() => (sendToBack ? this._props.DocumentView()._props.bringToFront(this.Document, true) :
+ clickFunc ?? (() => (sendToBack ? documentView._props.bringToFront?.(this.Document, true) :
this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ??
this._props.select(e.ctrlKey||e.shiftKey, e.metaKey)));
const waitFordblclick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick;
@@ -517,12 +394,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
onPointerDown = (e: React.PointerEvent): void => {
if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return;
- this._longPressSelector = setTimeout(() => {
- if (DocumentView.LongPress) {
- this._props.select(false);
- }
- }, 1000);
- if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this._props.DocumentView();
+ this._longPressSelector = setTimeout(() => DocumentView.LongPress && this._props.select(false), 1000);
+ if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this._docView;
this._downX = e.clientX;
this._downY = e.clientY;
@@ -533,7 +406,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (
// prettier-ignore
(this._props.isDocumentActive?.() || this._props.isContentActive?.()) &&
- !this._props.onBrowseClick?.() &&
+ !this._props.onBrowseClickScript?.() &&
!this.Document.ignoreClick &&
e.button === 0 &&
!Doc.IsInMyOverlay(this.layoutDoc)
@@ -579,40 +452,41 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (DocumentView.LongPress) e.preventDefault();
};
- @undoBatch
- toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => {
+ toggleFollowLink = undoable((zoom?: boolean, setTargetToggle?: boolean): void => {
const hadOnClick = this.Document.onClick;
this.noOnClick();
this.Document.onClick = hadOnClick ? undefined : FollowLinkScript();
this.Document.waitForDoubleClickToClick = hadOnClick ? undefined : 'never';
- };
- @undoBatch
- followLinkOnClick = () => {
+ }, 'toggle follow link');
+
+ followLinkOnClick = undoable(() => {
this.Document.ignoreClick = false;
this.Document.onClick = FollowLinkScript();
this.Document.followLinkToggle = false;
this.Document.followLinkZoom = false;
this.Document.followLinkLocation = undefined;
- };
- @undoBatch
- noOnClick = () => {
- this.Document.ignoreClick = false;
- this.Document.onClick = Doc.GetProto(this.Document).onClick = undefined;
- };
-
- @undoBatch deleteClicked = () => this._props.removeDocument?.(this._props.Document);
- @undoBatch setToggleDetail = () =>
- (this.Document.onClick = ScriptField.MakeScript(
- `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey)
- .replace('layout_', '')
- .replace(/^layout$/, 'detail')}")`,
- { documentView: 'any' }
- ));
+ }, 'follow link on click');
- @undoBatch
- drop = (e: Event, de: DragManager.DropEvent) => {
+ noOnClick = undoable(() => {
+ this.Document.ignoreClick = false;
+ this.Document.onClick = this.Document[DocData].onClick = undefined;
+ }, 'default on click');
+
+ deleteClicked = undoable(() => this._props.removeDocument?.(this.Document), 'delete doc');
+ setToggleDetail = undoable(
+ () =>
+ (this.Document.onClick = ScriptField.MakeScript(
+ `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey)
+ .replace('layout_', '')
+ .replace(/^layout$/, 'detail')}")`,
+ { documentView: 'any' }
+ )),
+ 'set toggle detail'
+ );
+
+ drop = undoable((e: Event, de: DragManager.DropEvent) => {
if (this._props.dontRegisterView || this._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return false;
- if (this._props.Document === Doc.ActiveDashboard) {
+ if (this.Document === Doc.ActiveDashboard) {
e.stopPropagation();
e.preventDefault();
alert(
@@ -634,7 +508,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]);
if (de.complete.linkDocument) {
de.complete.linkDocument.layout_isSvg = true;
- this._props.DocumentView().CollectionFreeFormView?.addDocument(de.complete.linkDocument);
+ this._docView?.CollectionFreeFormView?.addDocument(de.complete.linkDocument);
}
}
e.stopPropagation();
@@ -642,27 +516,26 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
}
return false;
- };
+ }, 'drop doc');
- @undoBatch
- makeIntoPortal = () => {
- const portalLink = this.allLinks.find(d => d.link_anchor_1 === this._props.Document && d.link_relationship === 'portal to:portal from');
+ makeIntoPortal = undoable(() => {
+ const portalLink = this._allLinks.find(d => d.link_anchor_1 === this.Document && d.link_relationship === 'portal to:portal from');
if (!portalLink) {
DocUtils.MakeLink(
- this._props.Document,
+ this.Document,
Docs.Create.FreeformDocument([], {
_width: NumCast(this.layoutDoc._width) + 10,
_height: Math.max(NumCast(this.layoutDoc._height), NumCast(this.layoutDoc._width) + 10),
_isLightbox: true,
_layout_fitWidth: true,
- title: StrCast(this._props.Document.title) + ' [Portal]',
+ title: StrCast(this.Document.title) + ' [Portal]',
}),
{ link_relationship: 'portal to:portal from' }
);
}
this.Document.followLinkLocation = OpenWhere.lightbox;
this.Document.onClick = FollowLinkScript();
- };
+ }, 'make into portal');
importDocument = () => {
const input = document.createElement('input');
@@ -686,7 +559,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (e && this.layoutDoc._layout_hideContextMenu && Doc.noviceMode) {
e.preventDefault();
e.stopPropagation();
- //!this._props.isSelected(true) && SelectionManager.SelectView(this._props.DocumentView(), false);
+ //!this._props.isSelected(true) && SelectionManager.SelectView(this.DocumentView(), false);
}
// the touch onContextMenu is button 0, the pointer onContextMenu is button 2
if (e) {
@@ -708,7 +581,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (e && !(e.nativeEvent as any).dash) {
const onDisplay = () => {
- 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.
+ if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && this._props.select(false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear.
setTimeout(() => simulateMouseClick(document.elementFromPoint(e.clientX, e.clientY), e.clientX, e.clientY, e.screenX, e.screenY));
};
if (navigator.userAgent.includes('Macintosh')) {
@@ -719,14 +592,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
return;
}
- const customScripts = Cast(this._props.Document.contextMenuScripts, listSpec(ScriptField), []);
+ const customScripts = Cast(this.Document.contextMenuScripts, listSpec(ScriptField), []);
StrListCast(this.Document.contextMenuLabels).forEach((label, i) =>
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.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);
+ if (!this.Document.isFolder) {
+ const templateDoc = Cast(this.Document[StrCast(this.Document.layout_fieldKey)], Doc, null);
const appearance = cm.findByDescription('Appearance...');
const appearanceItems: ContextMenuProps[] = appearance && 'subitems' in appearance ? appearance.subitems : [];
@@ -737,40 +610,38 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
!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.Document) && this.Document.type !== DocumentType.PRES && ![CollectionViewType.Docking, CollectionViewType.Tree].includes(this.Document._type_collection as any)) {
+ if (this._props.bringToFront) {
+ 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.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.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' });
+ }
+
+ if (!Doc.IsSystem(this.Document) && !this.Document.hideClickBehaviors && !this._props.hideClickBehaviors) {
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.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.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' });
- }
-
onClicks.push({ description: 'Enter Portal', event: this.makeIntoPortal, icon: 'window-restore' });
!Doc.noviceMode && onClicks.push({ description: 'Toggle Detail', event: this.setToggleDetail, icon: 'concierge-bell' });
- if (!this._props.treeViewDoc) {
- if (!this.Document.annotationOn) {
- const options = cm.findByDescription('Options...');
- const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : [];
- !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'compass' });
-
- onClicks.push({ description: this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(false, false), icon: 'link' });
- !Doc.noviceMode && onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this._props.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' });
- !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
- } else if (LinkManager.Links(this.Document).length) {
- onClicks.push({ description: 'Restore On Click default', event: () => this.noOnClick(), icon: 'link' });
- onClicks.push({ description: 'Follow Link on Click', event: () => this.followLinkOnClick(), icon: 'link' });
- !existingOnClick && cm.addItem({ description: 'OnClick...', subitems: onClicks, icon: 'mouse-pointer' });
- }
+ if (!this.Document.annotationOn) {
+ const options = cm.findByDescription('Options...');
+ const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : [];
+ !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'compass' });
+
+ onClicks.push({ description: this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(false, false), icon: 'link' });
+ !Doc.noviceMode && onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' });
+ !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
+ } else if (LinkManager.Links(this.Document).length) {
+ onClicks.push({ description: 'Restore On Click default', event: () => this.noOnClick(), icon: 'link' });
+ onClicks.push({ description: 'Follow Link on Click', event: () => this.followLinkOnClick(), icon: 'link' });
+ !existingOnClick && cm.addItem({ description: 'OnClick...', subitems: onClicks, icon: 'mouse-pointer' });
}
}
@@ -786,15 +657,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const moreItems = more && 'subitems' in more ? more.subitems : [];
if (!Doc.IsSystem(this.Document)) {
if (!Doc.noviceMode) {
- moreItems.push({ description: 'Make View of Metadata Field', event: () => Doc.MakeMetadataFieldTemplate(this._props.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' });
+ moreItems.push({ description: 'Make View of Metadata Field', event: () => Doc.MakeMetadataFieldTemplate(this.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' });
moreItems.push({ description: `${this.Document._chromeHidden ? 'Show' : 'Hide'} Chrome`, event: () => (this.Document._chromeHidden = !this.Document._chromeHidden), icon: 'project-diagram' });
- if (Cast(Doc.GetProto(this._props.Document).data, listSpec(Doc))) {
- moreItems.push({ description: 'Export to Google Photos Album', event: () => GooglePhotos.Export.CollectionToAlbum({ collection: this._props.Document }).then(console.log), icon: 'caret-square-right' });
- moreItems.push({ description: 'Tag Child Images via Google Photos', event: () => GooglePhotos.Query.TagChildImages(this._props.Document), icon: 'caret-square-right' });
- moreItems.push({ description: 'Write Back Link to Album', event: () => GooglePhotos.Transactions.AddTextEnrichment(this._props.Document), icon: 'caret-square-right' });
+ if (Cast(Doc.GetProto(this.Document).data, listSpec(Doc))) {
+ moreItems.push({ description: 'Export to Google Photos Album', event: () => GooglePhotos.Export.CollectionToAlbum({ collection: this.Document }).then(console.log), icon: 'caret-square-right' });
+ moreItems.push({ description: 'Tag Child Images via Google Photos', event: () => GooglePhotos.Query.TagChildImages(this.Document), icon: 'caret-square-right' });
+ moreItems.push({ description: 'Write Back Link to Album', event: () => GooglePhotos.Transactions.AddTextEnrichment(this.Document), icon: 'caret-square-right' });
}
- moreItems.push({ description: 'Copy ID', event: () => Utils.CopyText(Doc.globalServerPath(this._props.Document)), icon: 'fingerprint' });
+ moreItems.push({ description: 'Copy ID', event: () => Utils.CopyText(Doc.globalServerPath(this.Document)), icon: 'fingerprint' });
}
}
@@ -802,14 +673,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
const constantItems: ContextMenuProps[] = [];
if (!Doc.IsSystem(this.Document) && this.Document._type_collection !== CollectionViewType.Docking) {
- constantItems.push({ description: 'Zip Export', icon: 'download', event: async () => Doc.Zip(this._props.Document) });
- (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) {
+ constantItems.push({ description: 'Zip Export', icon: 'download', event: async () => Doc.Zip(this.Document) });
+ (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this._docView), icon: 'users' });
+ if (this._props.removeDocument && Doc.ActiveDashboard !== this.Document) {
// need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions)
constantItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' });
}
}
- constantItems.push({ description: 'Show Metadata', event: () => this._props.addDocTab(this._props.Document, OpenWhere.addRightKeyvalue), icon: 'table-columns' });
+ constantItems.push({ description: 'Show Metadata', event: () => this._props.addDocTab(this.Document, OpenWhere.addRightKeyvalue), icon: 'table-columns' });
cm.addItem({ description: 'General...', noexpand: false, subitems: constantItems, icon: 'question' });
const help = cm.findByDescription('Help...');
@@ -820,7 +691,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
let documentationDescription: string | undefined = undefined;
let documentationLink: string | undefined = undefined;
- switch (this._props.Document.type) {
+ switch (this.Document.type) {
case DocumentType.COL:
documentationDescription = 'See collection documentation';
documentationLink = 'https://brown-dash.github.io/Dash-Documentation/views/';
@@ -854,8 +725,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
documentationLink = 'https://brown-dash.github.io/Dash-Documentation/documents/dataViz/';
break;
}
- // Add link to help documentation
- if (!this._props.treeViewDoc && documentationDescription && documentationLink) {
+ // Add link to help documentation (unless the doc contents have been overriden in which case the documentation isn't relevant)
+ if (!this.docContents && documentationDescription && documentationLink) {
helpItems.push({
description: documentationDescription,
event: () => window.open(documentationLink, '_blank'),
@@ -869,69 +740,20 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
cm.displayMenu((e?.pageX || pageX || 0) - 15, (e?.pageY || pageY || 0) - 15, undefined, undefined, undefined);
};
- @computed get _rootSelected() {
- return this._props.isSelected() || BoolCast(this._props.TemplateDataDocument && this._props.rootSelected?.());
- }
rootSelected = () => this._rootSelected;
panelHeight = () => this._props.PanelHeight() - this.headerMargin;
- screenToLocalContent = () => this.ScreenToLocalBoxXf().translate(0, -this.headerMargin);
- onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler);
+ screenToLocalContent = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin);
+ onClickFunc = this.disableClickScriptFunc ? undefined : () => this.onClickHandler;
setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = height);
- setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view));
- @observable _isContentActive: boolean | undefined = undefined;
-
+ setContentView = action((view: ViewBoxInterface) => (this._componentView = view));
isContentActive = (): boolean | undefined => this._isContentActive;
childFilters = () => [...this._props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)];
- /// disable pointer events on content when there's an enabled onClick script (but not the browse script) and the contents aren't forced active, or if contents are marked inactive
- @computed get _contentPointerEvents() {
- TraceMobx();
- return this._props.contentPointerEvents ??
- ((!this.disableClickScriptFunc && //
- this.onClickHandler &&
- !this._props.onBrowseClick?.() &&
- this.isContentActive() !== true) ||
- this.isContentActive() === false)
- ? 'none'
- : this.pointerEvents;
- }
contentPointerEvents = () => this._contentPointerEvents;
- @computed get contents() {
- TraceMobx();
- const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString;
- const noBackground = this.Document.isGroup && !this._props.LayoutTemplateString?.includes(KeyValueBox.name) && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent');
- return (
- <div
- className="documentView-contentsView"
- style={{
- pointerEvents: (isInk || noBackground ? 'none' : this.contentPointerEvents()) ?? (this._mounted ? 'all' : 'none'),
- height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
- }}>
- <DocumentContentsView
- key={1}
- {...this._props}
- fieldKey=""
- pointerEvents={this.contentPointerEvents}
- docViewPath={this._props.viewPath}
- setContentView={this.setContentView}
- childFilters={this.childFilters}
- PanelHeight={this.panelHeight}
- setHeight={this.setHeight}
- isContentActive={this.isContentActive}
- ScreenToLocalTransform={this.screenToLocalContent}
- rootSelected={this.rootSelected}
- onClick={this.onClickFunc}
- setTitleFocus={this.setTitleFocus}
- layout_fieldKey={this.finalLayoutKey}
- />
- {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints}
- </div>
- );
- }
anchorPanelWidth = () => this._props.PanelWidth() || 1;
anchorPanelHeight = () => this._props.PanelHeight() || 1;
- anchorStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ anchorStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => {
// prettier-ignore
switch (property.split(':')[0]) {
case StyleProp.ShowTitle: return '';
@@ -944,39 +766,18 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
return this._props.styleProvider?.(doc, props, property);
};
- // We need to use allrelatedLinks to get not just links to the document as a whole, but links to
- // anchors that are not rendered as DocumentViews (marked as 'layout_unrendered' with their 'annotationOn' set to this document). e.g.,
- // - PDF text regions are rendered as an Annotations without generating a DocumentView, '
- // - RTF selections are rendered via Prosemirror and have a mark which contains the Document ID for the annotation link
- // - and links to PDF/Web docs at a certain scroll location never create an explicit view.
- // For each of these, we create LinkAnchorBox's on the border of the DocumentView.
- @computed get directLinks() {
- TraceMobx();
- return LinkManager.Instance.getAllRelatedLinks(this.Document).filter(
- link =>
- (link.link_matchEmbeddings ? link.link_anchor_1 === this.Document : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.Document)) ||
- (link.link_matchEmbeddings ? link.link_anchor_2 === this.Document : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.Document)) ||
- ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.Document)) ||
- ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.Document))
- );
- }
- @computed get allLinks() {
- TraceMobx();
- return LinkManager.Instance.getAllRelatedLinks(this.Document);
- }
- hideLink = computedFn((link: Doc) => () => (link.link_displayLine = false));
- @computed get allLinkEndpoints() {
+
+ removeLinkByHiding = (link: Doc) => () => (link.link_displayLine = false);
+ allLinkEndpoints = () => {
// the small blue dots that mark the endpoints of links
- TraceMobx();
if (this._componentView instanceof KeyValueBox || this._props.hideLinkAnchors || this.layoutDoc.layout_hideLinkAnchors || this._props.dontRegisterView || this.layoutDoc.layout_unrendered) return null;
- const filtered = DocUtils.FilterDocs(this.directLinks, this._props.childFilters?.() ?? [], []).filter(d => d.link_displayLine || Doc.UserDoc().showLinkLines);
- return filtered.map(link => (
+ return this.filteredLinks.map(link => (
<div className="documentView-anchorCont" key={link[Id]}>
<DocumentView
{...this._props}
isContentActive={returnFalse}
Document={link}
- docViewPath={this._props.viewPath}
+ containerViewPath={this._props.docViewPath}
PanelWidth={this.anchorPanelWidth}
PanelHeight={this.anchorPanelHeight}
dontRegisterView={false}
@@ -984,107 +785,55 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
hideCaptions={true}
hideLinkAnchors={true}
layout_fitWidth={returnTrue}
- removeDocument={this.hideLink(link)}
+ removeDocument={this.removeLinkByHiding(link)}
styleProvider={this.anchorStyleProvider}
LayoutTemplate={undefined}
LayoutTemplateString={LinkAnchorBox.LayoutString(`link_anchor_${LinkManager.anchorIndex(link, this.Document)}`)}
/>
</div>
));
- }
-
- static recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) {
- let gumStream: any;
- let recorder: any;
- navigator.mediaDevices
- .getUserMedia({
- audio: true,
- })
- .then(function (stream) {
- let audioTextAnnos = Cast(dataDoc[field + '_audioAnnotations_text'], listSpec('string'), null);
- if (audioTextAnnos) audioTextAnnos.push('');
- else audioTextAnnos = dataDoc[field + '_audioAnnotations_text'] = new List<string>(['']);
- DictationManager.Controls.listen({
- interimHandler: value => (audioTextAnnos[audioTextAnnos.length - 1] = value),
- continuous: { indefinite: false },
- }).then(results => {
- if (results && [DictationManager.Controls.Infringed].includes(results)) {
- DictationManager.Controls.stop();
- }
- onEnd?.();
- });
+ };
- gumStream = stream;
- recorder = new MediaRecorder(stream);
- recorder.ondataavailable = async (e: any) => {
- const [{ result }] = await Networking.UploadFilesToServer({ file: e.data });
- if (!(result instanceof Error)) {
- const audioField = new AudioField(result.accessPaths.agnostic.client);
- const audioAnnos = Cast(dataDoc[field + '_audioAnnotations'], listSpec(AudioField), null);
- if (audioAnnos === undefined) {
- dataDoc[field + '_audioAnnotations'] = new List([audioField]);
- } else {
- audioAnnos.push(audioField);
- }
- }
- };
- //runInAction(() => (dataDoc.audioAnnoState = 'recording'));
- recorder.start();
- const stopFunc = () => {
- recorder.stop();
- DictationManager.Controls.stop(false);
- runInAction(() => (dataDoc.audioAnnoState = 'stopped'));
- gumStream.getAudioTracks()[0].stop();
- };
- if (onRecording) onRecording(stopFunc);
- else setTimeout(stopFunc, 5000);
- });
- }
- playAnnotation = () => {
- const self = this;
- const audioAnnoState = this.dataDoc.audioAnnoState ?? 'stopped';
- const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '_audioAnnotations'], listSpec(AudioField), null);
- const anno = audioAnnos?.lastElement();
- if (anno instanceof AudioField) {
- switch (audioAnnoState) {
- case 'stopped':
- this.dataDoc[AudioPlay] = new Howl({
- src: [anno.url.href],
- format: ['mp3'],
- autoplay: true,
- loop: false,
- volume: 0.5,
- onend: action(() => (self.dataDoc.audioAnnoState = 'stopped')),
- });
- this.dataDoc.audioAnnoState = 'playing';
- break;
- case 'playing':
- this.dataDoc[AudioPlay]?.stop();
- this.dataDoc.audioAnnoState = 'stopped';
- break;
- }
- }
+ viewBoxContents = () => {
+ TraceMobx();
+ const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString;
+ const noBackground = this.Document.isGroup && !this._props.LayoutTemplateString?.includes(KeyValueBox.name) && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent');
+ return (
+ <div
+ className="documentView-contentsView"
+ style={{
+ pointerEvents: (isInk || noBackground ? 'none' : this.contentPointerEvents()) ?? (this._mounted ? 'all' : 'none'),
+ height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
+ }}>
+ <DocumentContentsView
+ {...this._props}
+ layoutFieldKey={StrCast(this.Document.layout_fieldKey, 'layout')}
+ pointerEvents={this.contentPointerEvents}
+ setContentViewBox={this.setContentView}
+ childFilters={this.childFilters}
+ PanelHeight={this.panelHeight}
+ setHeight={this.setHeight}
+ isContentActive={this.isContentActive}
+ ScreenToLocalTransform={this.screenToLocalContent}
+ rootSelected={this.rootSelected}
+ onClickScript={this.onClickFunc}
+ setTitleFocus={this.setTitleFocus}
+ hideClickBehaviors={BoolCast(this.layoutDoc.hideClickBehaviors)}
+ />
+ {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints()}
+ </div>
+ );
};
- captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption');
- @observable _changingTitleField = false;
- @observable _dropDownInnerWidth = 0;
- fieldsDropdown = (inputOptions: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => {
- const filteredOptions = new Set(inputOptions);
- const scaling = this.titleHeight / 30; /* height of Dropdown */
- Object.entries(DocOptions)
- .filter(opts => opts[1].filterable)
- .forEach((pair: [string, FInfo]) => filteredOptions.add(pair[0]));
- filteredOptions.add(StrCast(this.layoutDoc.layout_showTitle));
- const options = Array.from(filteredOptions)
- .filter(f => f)
- .map(facet => ({ val: facet, text: facet }));
+ captionStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption');
+ fieldsDropdown = (reqdFields: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => {
+ const filteredFields = Object.entries(DocOptions).reduce((set, [field, opts]) => (opts.filterable ? set.add(field) : set), new Set(reqdFields));
return (
<div style={{ width: dropdownWidth }}>
<div
- ref={action((r: any) => r && (this._dropDownInnerWidth = Number(getComputedStyle(r).width.replace('px', ''))))}
+ ref={action((r: any) => r && (this._titleDropDownInnerWidth = Number(getComputedStyle(r).width.replace('px', ''))))}
onPointerDown={action(e => (this._changingTitleField = true))}
- style={{ width: 'max-content', transformOrigin: 'left', transform: `scale(${scaling})` }}>
+ style={{ width: 'max-content', transformOrigin: 'left', transform: `scale(${this.titleHeight / 30 /* height of Dropdown */})` }}>
<Dropdown
activeChanged={action(isOpen => !isOpen && (this._changingTitleField = false))}
selectedVal={placeholder}
@@ -1094,7 +843,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
type={Type.TERT}
closeOnSelect={true}
dropdownType={DropdownType.SELECT}
- items={options}
+ items={Array.from(filteredFields).map(facet => ({ val: facet, text: facet }))}
width={100}
fillWidth
/>
@@ -1102,43 +851,24 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
</div>
);
};
- @computed get innards() {
- TraceMobx();
+ /**
+ * displays a 'title' at the top of a document. The title contents default to the 'title' field, but can be changed to one or more fields by
+ * setting layout_showTitle using the format: field1[;field2[...][:hover]]
+ * from the UI, this is done by clicking the title field and prefixin the format with '#'. eg., #field1[;field2;...][:hover]
+ **/
+ titleView = () => {
const showTitle = this.layout_showTitle?.split(':')[0];
const showTitleHover = this.layout_showTitle?.includes(':hover');
- const captionView = !this.layout_showCaption ? null : (
- <div
- className="documentView-captionWrapper"
- style={{
- pointerEvents: this.Document.ignoreClick ? 'none' : this.isContentActive() || this._props.isDocumentActive?.() ? 'all' : undefined,
- background: StrCast(this.layoutDoc._backgroundColor, 'rgba(0,0,0,0.2)'),
- color: lightOrDark(StrCast(this.layoutDoc._backgroundColor, 'black')),
- }}>
- <FormattedTextBox
- {...this._props}
- yPadding={10}
- xPadding={10}
- fieldKey={this.layout_showCaption}
- styleProvider={this.captionStyleProvider}
- dontRegisterView={true}
- noSidebar={true}
- dontScale={true}
- renderDepth={this._props.renderDepth}
- isContentActive={this.isContentActive}
- />
- </div>
- );
+
const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.Document;
const background = StrCast(
this.layoutDoc.layout_headingColor,
StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.userBackgroundColor))
);
- const dropdownWidth = this._titleRef.current?._editing || this._changingTitleField ? Math.max(10, (this._dropDownInnerWidth * this.titleHeight) / 30) : 0;
+ const dropdownWidth = this._titleRef.current?._editing || this._changingTitleField ? Math.max(10, (this._titleDropDownInnerWidth * this.titleHeight) / 30) : 0;
const sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', '');
- // displays a 'title' at the top of a document. The title contents default to the 'title' field, but can be changed to one or more fields by
- // setting layout_showTitle using the format: field1[;field2[...][:hover]]
- // from the UI, this is done by clicking the title field and prefixin the format with '#'. eg., #field1[;field2;...][:hover]
- const titleView = !showTitle ? null : (
+
+ return !showTitle ? null : (
<div
className={`documentView-titleWrapper${showTitleHover ? '-hover' : ''}`}
key="title"
@@ -1154,7 +884,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
{!dropdownWidth
? null
: this.fieldsDropdown(
- [],
+ [StrCast(this.layoutDoc.layout_showTitle)],
dropdownWidth,
StrCast(this.layoutDoc.layout_showTitle).split(':')[0],
action((field: string | number) => {
@@ -1200,19 +930,36 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
</div>
</div>
);
- return this._props.hideTitle || (!showTitle && !this.layout_showCaption) ? (
- this.contents
- ) : (
- <div className="documentView-styleWrapper">
- {titleView}
- {this.contents}
- {captionView}
+ };
+
+ captionView = () => {
+ return !this.layout_showCaption ? null : (
+ <div
+ className="documentView-captionWrapper"
+ style={{
+ pointerEvents: this.Document.ignoreClick ? 'none' : this.isContentActive() || this._props.isDocumentActive?.() ? 'all' : undefined,
+ background: StrCast(this.layoutDoc._backgroundColor, 'rgba(0,0,0,0.2)'),
+ color: lightOrDark(StrCast(this.layoutDoc._backgroundColor, 'black')),
+ }}>
+ <FormattedTextBox
+ {...this._props}
+ yPadding={10}
+ xPadding={10}
+ fieldKey={this.layout_showCaption}
+ styleProvider={this.captionStyleProvider}
+ dontRegisterView={true}
+ noSidebar={true}
+ dontScale={true}
+ renderDepth={this._props.renderDepth}
+ isContentActive={this.isContentActive}
+ />
</div>
);
- }
+ };
renderDoc = (style: object) => {
TraceMobx();
+ const showTitle = this.layout_showTitle?.split(':')[0];
return !DocCast(this.Document) || GetEffectiveAcl(this.dataDoc) === AclPrivate
? null
: this.docContents ?? (
@@ -1228,59 +975,31 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
fontFamily: StrCast(this.Document._text_fontFamily, 'inherit'),
fontSize: Cast(this.Document._text_fontSize, 'string', null),
transform: this._animateScalingTo ? `scale(${this._animateScalingTo})` : undefined,
- transition: !this._animateScalingTo ? StrCast(this.Document.dataTransition) : `transform ${this.animateScaleTime / 1000}s ease-${this._animateScalingTo < 1 ? 'in' : 'out'}`,
+ transition: !this._animateScalingTo ? StrCast(this.Document.dataTransition) : `transform ${this.animateScaleTime() / 1000}s ease-${this._animateScalingTo < 1 ? 'in' : 'out'}`,
}}>
- {this.innards}
+ {this._props.hideTitle || (!showTitle && !this.layout_showCaption) ? (
+ this.viewBoxContents()
+ ) : (
+ <div className="documentView-styleWrapper">
+ {this.titleView()}
+ {this.viewBoxContents()}
+ {this.captionView()}
+ </div>
+ )}
{this.widgetDecorations ?? null}
</div>
);
};
- /**
- * returns an entrance animation effect function to wrap a JSX element
- * @param presEffectDoc presentation effects document that specifies the animation effect parameters
- * @returns a function that will wrap a JSX animation element wrapping any JSX element
- */
- public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Opt<Doc>, root: Doc) {
- const dir = presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection;
- const effectProps = {
- left: dir === PresEffectDirection.Left,
- right: dir === PresEffectDirection.Right,
- top: dir === PresEffectDirection.Top,
- bottom: dir === PresEffectDirection.Bottom,
- opposite: true,
- delay: 0,
- duration: Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)),
- };
- //prettier-ignore
- switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) {
- default:
- case PresEffect.None: return renderDoc;
- case PresEffect.Zoom: return <Zoom {...effectProps}>{renderDoc}</Zoom>;
- case PresEffect.Fade: return <Fade {...effectProps}>{renderDoc}</Fade>;
- case PresEffect.Flip: return <Flip {...effectProps}>{renderDoc}</Flip>;
- case PresEffect.Rotate: return <Rotate {...effectProps}>{renderDoc}</Rotate>;
- case PresEffect.Bounce: return <Bounce {...effectProps}>{renderDoc}</Bounce>;
- case PresEffect.Roll: return <Roll {...effectProps}>{renderDoc}</Roll>;
- case PresEffect.Lightspeed: return <JackInTheBox {...effectProps}>{renderDoc}</JackInTheBox>;
- }
- }
- @computed get highlighting() {
- return this._props.styleProvider?.(this.Document, this._props, StyleProp.Highlighting);
- }
- @computed get borderPath() {
- return this._props.styleProvider?.(this.Document, this._props, StyleProp.BorderPath);
- }
render() {
TraceMobx();
const highlighting = this.highlighting;
const borderPath = this.borderPath;
- const boxShadow =
- this._props.treeViewDoc || !highlighting
- ? this.boxShadow
- : highlighting && this.borderRounding && highlighting.highlightStyle !== 'dashed'
- ? `0 0 0 ${highlighting.highlightIndex}px ${highlighting.highlightColor}`
- : this.boxShadow || (this.Document.isTemplateForField ? 'black 0.2vw 0.2vw 0.8vw' : undefined);
+ const boxShadow = !highlighting
+ ? this.boxShadow
+ : highlighting && this.borderRounding && highlighting.highlightStyle !== 'dashed'
+ ? `0 0 0 ${highlighting.highlightIndex}px ${highlighting.highlightColor}`
+ : this.boxShadow || (this.Document.isTemplateForField ? 'black 0.2vw 0.2vw 0.8vw' : undefined);
const renderDoc = this.renderDoc({
borderRadius: this.borderRounding,
outline: highlighting && !this.borderRounding && !highlighting.highlightStroke ? `${highlighting.highlightColor} ${highlighting.highlightStyle} ${highlighting.highlightIndex}px` : 'solid 0px',
@@ -1298,10 +1017,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
onClick={this.onClick}
onPointerEnter={e => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)}
onPointerOver={e => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)}
- onPointerLeave={e => !isParentOf(this.ContentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)}
+ onPointerLeave={e => !isParentOf(this._contentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)}
style={{
borderRadius: this.borderRounding,
- pointerEvents: this.pointerEvents === 'visiblePainted' ? 'none' : this.pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here)
+ pointerEvents: this._pointerEvents === 'visiblePainted' ? 'none' : this._pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here)
}}>
<>
{this._componentView instanceof KeyValueBox ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)}
@@ -1310,157 +1029,124 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
</div>
);
}
-}
-@observer
-export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
- public static ROOT_DIV = 'documentView-effectsWrapper';
-
- constructor(props: any) {
- super(props);
- makeObservable(this);
+ /**
+ * returns an entrance animation effect function to wrap a JSX element
+ * @param presEffectDoc presentation effects document that specifies the animation effect parameters
+ * @returns a function that will wrap a JSX animation element wrapping any JSX element
+ */
+ public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Opt<Doc>, root: Doc) {
+ const dir = presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection;
+ const effectProps = {
+ left: dir === PresEffectDirection.Left,
+ right: dir === PresEffectDirection.Right,
+ top: dir === PresEffectDirection.Top,
+ bottom: dir === PresEffectDirection.Bottom,
+ opposite: true,
+ delay: 0,
+ duration: Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)),
+ };
+ //prettier-ignore
+ switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) {
+ default:
+ case PresEffect.None: return renderDoc;
+ case PresEffect.Zoom: return <Zoom {...effectProps}>{renderDoc}</Zoom>;
+ case PresEffect.Fade: return <Fade {...effectProps}>{renderDoc}</Fade>;
+ case PresEffect.Flip: return <Flip {...effectProps}>{renderDoc}</Flip>;
+ case PresEffect.Rotate: return <Rotate {...effectProps}>{renderDoc}</Rotate>;
+ case PresEffect.Bounce: return <Bounce {...effectProps}>{renderDoc}</Bounce>;
+ case PresEffect.Roll: return <Roll {...effectProps}>{renderDoc}</Roll>;
+ case PresEffect.Lightspeed: return <JackInTheBox {...effectProps}>{renderDoc}</JackInTheBox>;
+ }
}
+ public static recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) {
+ let gumStream: any;
+ let recorder: any;
+ navigator.mediaDevices
+ .getUserMedia({
+ audio: true,
+ })
+ .then(function (stream) {
+ let audioTextAnnos = Cast(dataDoc[field + '_audioAnnotations_text'], listSpec('string'), null);
+ if (audioTextAnnos) audioTextAnnos.push('');
+ else audioTextAnnos = dataDoc[field + '_audioAnnotations_text'] = new List<string>(['']);
+ DictationManager.Controls.listen({
+ interimHandler: value => (audioTextAnnos[audioTextAnnos.length - 1] = value),
+ continuous: { indefinite: false },
+ }).then(results => {
+ if (results && [DictationManager.Controls.Infringed].includes(results)) {
+ DictationManager.Controls.stop();
+ }
+ onEnd?.();
+ });
- @observable _selected = false;
- public get IsSelected() {
- return this._selected;
- }
- public set IsSelected(val) {
- runInAction(() => (this._selected = val));
- }
- @observable public static LongPress = false;
- @computed public static get exploreMode() {
- return () => (SnappingManager.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined);
+ gumStream = stream;
+ recorder = new MediaRecorder(stream);
+ recorder.ondataavailable = async (e: any) => {
+ const [{ result }] = await Networking.UploadFilesToServer({ file: e.data });
+ if (!(result instanceof Error)) {
+ const audioField = new AudioField(result.accessPaths.agnostic.client);
+ const audioAnnos = Cast(dataDoc[field + '_audioAnnotations'], listSpec(AudioField), null);
+ if (audioAnnos === undefined) {
+ dataDoc[field + '_audioAnnotations'] = new List([audioField]);
+ } else {
+ audioAnnos.push(audioField);
+ }
+ }
+ };
+ //runInAction(() => (dataDoc.audioAnnoState = 'recording'));
+ recorder.start();
+ const stopFunc = () => {
+ recorder.stop();
+ DictationManager.Controls.stop(false);
+ runInAction(() => (dataDoc.audioAnnoState = 'stopped'));
+ gumStream.getAudioTracks()[0].stop();
+ };
+ if (onRecording) onRecording(stopFunc);
+ else setTimeout(stopFunc, 5000);
+ });
}
- @observable public docView: DocumentViewInternal | undefined | null = undefined;
- @observable public textHtmlOverlay: Opt<string> = undefined;
- @observable public textHtmlOverlayTime: Opt<number> = undefined;
- @observable private _isHovering = false;
+}
- public htmlOverlayEffect: Opt<Doc>;
- public get displayName() {
- return 'DocumentView(' + this._props.Document?.title + ')';
- } // this makes mobx trace() statements more descriptive
+@observer
+export class DocumentView extends DocComponent<DocumentViewProps>() {
+ public static ROOT_DIV = 'documentView-effectsWrapper';
+ public get displayName() { return 'DocumentView(' + this.Document?.title + ')'; } // prettier-ignore
public ContentRef = React.createRef<HTMLDivElement>();
- public ViewTimer: NodeJS.Timeout | undefined; // timer for res
- public AnimEffectTimer: NodeJS.Timeout | undefined; // timer for res
+ private _htmlOverlayEffect: Opt<Doc>;
private _disposers: { [name: string]: IReactionDisposer } = {};
- public clearViewTransition = () => {
- this.ViewTimer && clearTimeout(this.ViewTimer);
- this.layoutDoc._viewTransition = undefined;
- };
- public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this.docView?.startDragging(x, y, dropAction, hideSource);
-
- public showContextMenu = (pageX: number, pageY: number) => this.docView?.onContextMenu(undefined, pageX, pageY);
+ private _viewTimer: NodeJS.Timeout | undefined;
+ private _animEffectTimer: NodeJS.Timeout | undefined;
- public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => {
- this.AnimEffectTimer && clearTimeout(this.AnimEffectTimer);
- this.Document[Animation] = presEffect;
- this.AnimEffectTimer = setTimeout(() => (this.Document[Animation] = undefined), timeInMs);
- };
- public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => {
- this.layoutDoc._viewTransition = `${transProp} ${timeInMs}ms`;
- if (dataTrans) this.Document._dataTransition = `${transProp} ${timeInMs}ms`;
- this.ViewTimer && clearTimeout(this.ViewTimer);
- return (this.ViewTimer = setTimeout(() => {
- this.layoutDoc._viewTransition = undefined;
- this.Document._dataTransition = 'inherit';
- afterTrans?.();
- }, timeInMs + 10));
- };
- public static SetViewTransition(docs: Doc[], transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) {
- docs.forEach(doc => {
- doc._viewTransition = `${transProp} ${timeInMs}ms`;
- dataTrans && (doc.dataTransition = `${transProp} ${timeInMs}ms`);
- });
- return setTimeout(
- () =>
- docs.forEach(doc => {
- doc._viewTransition = undefined;
- dataTrans && (doc.dataTransition = 'inherit');
- afterTrans?.();
- }),
- timeInMs + 10
- );
+ @computed public static get exploreMode() {
+ return () => (SnappingManager.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined);
}
- // shows a stacking view collection (by default, but the user can change) of all documents linked to the source
- public static showBackLinks(linkAnchor: Doc) {
- const docId = Doc.CurrentUserEmail + Doc.GetProto(linkAnchor)[Id] + '-pivotish';
- // prettier-ignore
- DocServer.GetRefField(docId).then(docx =>
- LightboxView.Instance.SetLightboxDoc(
- (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection
- Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId)
- )
- );
+ constructor(props: DocumentViewProps) {
+ super(props);
+ makeObservable(this);
}
- get Document() {
- return this._props.Document;
- }
- get topMost() {
- return this._props.renderDepth === 0;
- }
- get dataDoc() {
- return this.docView?.dataDoc ?? this.Document;
- }
- get ContentDiv() {
- return this.docView?.ContentDiv;
- }
- get ComponentView() {
- return this.docView?._componentView;
- }
- get allLinks() {
- return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document);
- }
- get LayoutFieldKey() {
- return this.docView?.LayoutFieldKey || 'layout';
- }
- @computed get layout_fitWidth() {
- return this._props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.layout_fitWidth;
- }
- @computed get anchorViewDoc() {
- return this._props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined;
- }
- @computed get hideLinkButton() {
- return (
- this._props.hideLinkButton ||
- this._props.renderDepth === -1 || //
- (this.IsSelected && this._props.renderDepth) ||
- !this._isHovering ||
- (!this.IsSelected && this.layoutDoc.layout_hideLinkButton) ||
- SnappingManager.IsDragging ||
- SnappingManager.IsResizing
- );
- }
- hideLinkCount = () => (this.hideLinkButton ? true : false);
+ // want the htmloverlay to be able to fade in but we also want it to be display 'none' until it is needed.
+ // unfortunately, CSS can't transition animate any properties for something that is display 'none'.
+ // so we need to first activate the div, then, after a render timeout, start the opacity transition.
+ @observable private _enableHtmlOverlayTransitions: boolean = false;
+ @observable private _docViewInternal: DocumentViewInternal | undefined | null = undefined;
+ @observable private _htmlOverlayText: Opt<string> = undefined;
+ @observable private _isHovering = false;
+ @observable private _selected = false;
+ @observable public static LongPress = false;
- @computed get linkCountView() {
- return <DocumentLinksButton hideCount={this.hideLinkCount} View={this} scaling={this.screenToLocalScale} OnHover={true} Bottom={this.topMost} ShowCount={true} />;
- }
- @computed get docViewPath(): DocumentView[] {
- return this._props.docViewPath ? [...this._props.docViewPath(), this] : [this];
- }
- @computed get layoutDoc() {
- return Doc.Layout(this.Document, this._props.LayoutTemplate?.());
- }
- @computed get nativeWidth() {
- return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth));
- }
- @computed get nativeHeight() {
- return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth));
- }
- @computed get shouldNotScale() {
+ @computed private get shouldNotScale() {
return (this.layout_fitWidth && !this.nativeWidth) || this._props.LayoutTemplateString?.includes(KeyValueBox.name) || [CollectionViewType.Docking].includes(this.Document._type_collection as any);
}
- @computed get effectiveNativeWidth() {
+ @computed private get effectiveNativeWidth() {
return this.shouldNotScale ? 0 : this.nativeWidth || NumCast(this.layoutDoc.width);
}
- @computed get effectiveNativeHeight() {
+ @computed private get effectiveNativeHeight() {
return this.shouldNotScale ? 0 : this.nativeHeight || NumCast(this.layoutDoc.height);
}
- @computed get nativeScaling() {
+ @computed private get nativeScaling() {
if (this.shouldNotScale) return 1;
const minTextScale = this.Document.type === DocumentType.RTF ? 0.1 : 0;
if (this.layout_fitWidth || this._props.PanelHeight() / (this.effectiveNativeHeight || 1) > this._props.PanelWidth() / (this.effectiveNativeWidth || 1)) {
@@ -1468,19 +1154,19 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
}
return Math.max(minTextScale, this._props.PanelHeight() / (this.effectiveNativeHeight || 1)); // height-limited or unscaled
}
- @computed get panelWidth() {
+ @computed private get panelWidth() {
return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this._props.PanelWidth();
}
- @computed get panelHeight() {
+ @computed private get panelHeight() {
if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.layout_reflowVertical)) {
return Math.min(this._props.PanelHeight(), this.effectiveNativeHeight * this.nativeScaling);
}
return this._props.PanelHeight();
}
- @computed get Xshift() {
+ @computed private get Xshift() {
return this.effectiveNativeWidth ? Math.max(0, (this._props.PanelWidth() - this.effectiveNativeWidth * this.nativeScaling) / 2) : 0;
}
- @computed get Yshift() {
+ @computed private get Yshift() {
return this.effectiveNativeWidth &&
this.effectiveNativeHeight &&
Math.abs(this.Xshift) < 0.001 &&
@@ -1488,45 +1174,103 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
? Math.max(0, (this._props.PanelHeight() - this.effectiveNativeHeight * this.nativeScaling) / 2)
: 0;
}
- @computed get centeringX() {
- return this._props.dontCenter?.includes('x') ? 0 : this.Xshift;
+ @computed private get hideLinkButton() {
+ return (
+ this._props.hideLinkButton ||
+ this._props.renderDepth === -1 || //
+ (this.IsSelected && this._props.renderDepth) ||
+ !this._isHovering ||
+ (!this.IsSelected && this.layoutDoc.layout_hideLinkButton) ||
+ SnappingManager.IsDragging ||
+ SnappingManager.IsResizing
+ );
}
- @computed get centeringY() {
- return this._props.dontCenter?.includes('y') ? 0 : this.Yshift;
+
+ componentDidMount() {
+ runInAction(() => this.Document[DocViews].add(this));
+ this._disposers.onViewMounted = reaction(() => ScriptCast(this.Document.onViewMounted)?.script?.run({ this: this.Document }).result, emptyFunction);
+ !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.AddView(this);
}
- @computed get CollectionFreeFormView() {
- return this.CollectionFreeFormDocumentView?.CollectionFreeFormView;
+ componentWillUnmount() {
+ runInAction(() => this.Document[DocViews].delete(this));
+ Object.values(this._disposers).forEach(disposer => disposer?.());
+ !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.RemoveView(this);
}
- @computed get CollectionFreeFormDocumentView() {
- return this._props.CollectionFreeFormDocumentView?.();
+
+ public set IsSelected(val) { runInAction(() => (this._selected = val)); } // prettier-ignore
+ public get IsSelected() { return this._selected; } // prettier-ignore
+ public get topMost() { return this._props.renderDepth === 0; } // prettier-ignore
+ public get ContentDiv() { return this._docViewInternal?._contentDiv; } // prettier-ignore
+ public get ComponentView() { return this._docViewInternal?._componentView; } // prettier-ignore
+ public get allLinks() { return this._docViewInternal?._allLinks ?? []; } // prettier-ignore
+
+ get LayoutFieldKey() {
+ return Doc.LayoutFieldKey(this.Document, this._props.LayoutTemplateString);
}
- 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())) {
+ @computed get layout_fitWidth() {
+ return this._props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.layout_fitWidth;
+ }
+ @computed get anchorViewDoc() {
+ return this._props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined;
+ }
+
+ @computed get getBounds() {
+ if (!this._docViewInternal?._contentDiv || Doc.AreProtosEqual(this.Document, Doc.UserDoc())) {
return undefined;
}
- if (this.docView._componentView?.screenBounds?.()) {
- return this.docView._componentView.screenBounds();
+ if (this._docViewInternal._componentView?.screenBounds?.()) {
+ return this._docViewInternal._componentView.screenBounds();
}
- const xf = this.docView.ScreenToLocalBoxXf().scale(this.nativeScaling).inverse();
+ const xf = this.screenToContentsTransform().scale(this.nativeScaling).inverse();
const [[left, top], [right, bottom]] = [xf.transformPoint(0, 0), xf.transformPoint(this.panelWidth, this.panelHeight)];
- if (this.docView._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) {
- const docuBox = this.docView.ContentDiv.getElementsByClassName('linkAnchorBox-cont');
+ if (this._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) {
+ const docuBox = this._docViewInternal._contentDiv.getElementsByClassName('linkAnchorBox-cont');
if (docuBox.length) return { ...docuBox[0].getBoundingClientRect(), center: undefined };
}
return { left, top, right, bottom };
+ }
+
+ @computed get nativeWidth() {
+ return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth));
+ }
+ @computed get nativeHeight() {
+ return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth));
+ }
+ @computed public get centeringX() { return this._props.dontCenter?.includes('x') ? 0 : this.Xshift; } // prettier-ignore
+ @computed public get centeringY() { return this._props.dontCenter?.includes('y') ? 0 : this.Yshift; } // prettier-ignore
+
+ /**
+ * path of DocumentViews hat contains this DocumentView (does not includes this DocumentView thouhg)
+ */
+ public get containerViewPath() { return this._props.containerViewPath; } // prettier-ignore
+ public get CollectionFreeFormView() { return this.CollectionFreeFormDocumentView?.CollectionFreeFormView; } // prettier-ignore
+ public get CollectionFreeFormDocumentView() { return this._props.CollectionFreeFormDocumentView?.(); } // prettier-ignore
+
+ public clearViewTransition = () => {
+ this._viewTimer && clearTimeout(this._viewTimer);
+ this.layoutDoc._viewTransition = undefined;
};
+ public noOnClick = () => this._docViewInternal?.noOnClick();
+ public makeIntoPortal = () => this._docViewInternal?.makeIntoPortal();
+ public toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => this._docViewInternal?.toggleFollowLink(zoom, setTargetToggle);
+ public setToggleDetail = () => this._docViewInternal?.setToggleDetail();
+ public onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY);
+ public cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents();
+ public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource);
+ public showContextMenu = (pageX: number, pageY: number) => this._docViewInternal?.onContextMenu(undefined, pageX, pageY);
+
+ public toggleNativeDimensions = () => this._docViewInternal && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.NativeDimScaling() ?? 1, this._props.PanelWidth(), this._props.PanelHeight());
public iconify(finished?: () => void, animateTime?: number) {
this.ComponentView?.updateIcon?.();
- const animTime = this.docView?._animateScaleTime;
- runInAction(() => this.docView && animateTime !== undefined && (this.docView._animateScaleTime = animateTime));
+ const animTime = this._docViewInternal?.animateScaleTime();
+ runInAction(() => this._docViewInternal && animateTime !== undefined && (this._docViewInternal._animateScaleTime = animateTime));
const finalFinished = action(() => {
finished?.();
- this.docView && (this.docView._animateScaleTime = animTime);
+ this._docViewInternal && (this._docViewInternal._animateScaleTime = animTime);
});
const layout_fieldKey = Cast(this.Document.layout_fieldKey, 'string', null);
if (layout_fieldKey !== 'layout_icon') {
@@ -1536,17 +1280,62 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
const deiconifyLayout = Cast(this.Document.deiconifyLayout, 'string', null);
this.switchViews(deiconifyLayout ? true : false, deiconifyLayout, finalFinished);
this.Document.deiconifyLayout = undefined;
- this._props.bringToFront(this.Document);
+ this._props.bringToFront?.(this.Document);
}
}
- @undoBatch
- setCustomView = (custom: boolean, layout: string): void => {
- Doc.setNativeView(this._props.Document);
- custom && DocUtils.makeCustomViewClicked(this._props.Document, Docs.Create.StackingDocument, layout, undefined);
+
+ public playAnnotation = () => {
+ const self = this;
+ const audioAnnoState = this.dataDoc.audioAnnoState ?? 'stopped';
+ const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '_audioAnnotations'], listSpec(AudioField), null);
+ const anno = audioAnnos?.lastElement();
+ if (anno instanceof AudioField) {
+ switch (audioAnnoState) {
+ case 'stopped':
+ this.dataDoc[AudioPlay] = new Howl({
+ src: [anno.url.href],
+ format: ['mp3'],
+ autoplay: true,
+ loop: false,
+ volume: 0.5,
+ onend: action(() => (self.dataDoc.audioAnnoState = 'stopped')),
+ });
+ this.dataDoc.audioAnnoState = 'playing';
+ break;
+ case 'playing':
+ this.dataDoc[AudioPlay]?.stop();
+ this.dataDoc.audioAnnoState = 'stopped';
+ break;
+ }
+ }
};
- switchViews = (custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => {
- runInAction(() => this.docView && (this.docView._animateScalingTo = 0.1)); // shrink doc
+ public setTextHtmlOverlay = action((text: string | undefined, effect?: Doc) => {
+ this._htmlOverlayText = text;
+ this._htmlOverlayEffect = effect;
+ });
+ public setAnimateScaling = action((scale: number, time?: number) => {
+ if (this._docViewInternal) {
+ this._docViewInternal._animateScalingTo = scale;
+ this._docViewInternal._animateScaleTime = time;
+ }
+ });
+ public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => {
+ this._animEffectTimer && clearTimeout(this._animEffectTimer);
+ this.Document[Animation] = presEffect;
+ this._animEffectTimer = setTimeout(() => (this.Document[Animation] = undefined), timeInMs);
+ };
+ public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => {
+ this._viewTimer = DocumentView.SetViewTransition([this.layoutDoc], transProp, timeInMs, this._viewTimer, afterTrans, dataTrans);
+ };
+
+ public setCustomView = undoable((custom: boolean, layout: string): void => {
+ Doc.setNativeView(this.Document);
+ custom && DocUtils.makeCustomViewClicked(this.Document, Docs.Create.StackingDocument, layout, undefined);
+ }, 'set custom view');
+
+ public switchViews = (custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => {
+ runInAction(() => this._docViewInternal && (this._docViewInternal._animateScalingTo = 0.1)); // shrink doc
setTimeout(
action(() => {
if (useExistingLayout && custom && this.Document['layout_' + view]) {
@@ -1554,22 +1343,25 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
} else {
this.setCustomView(custom, view);
}
- this.docView && (this.docView._animateScalingTo = 1); // expand it
+ this._docViewInternal && (this._docViewInternal._animateScalingTo = 1); // expand it
setTimeout(
action(() => {
- this.docView && (this.docView._animateScalingTo = 0);
+ this._docViewInternal && (this._docViewInternal._animateScalingTo = 0);
finished?.();
}),
- this.docView ? Math.max(0, this.docView.animateScaleTime - 10) : 0
+ Math.max(0, (this._docViewInternal?.animateScaleTime() ?? 0) - 10)
);
}),
- this.docView ? Math.max(0, this.docView?.animateScaleTime - 10) : 0
+ Math.max(0, (this._docViewInternal?.animateScaleTime() ?? 0) - 10)
);
};
+ /**
+ * @returns a hierarchy path through the nested DocumentViews that display this view. The last element of the path is this view.
+ */
+ public docViewPath = () => (this.containerViewPath ? [...this.containerViewPath(), this] : [this]);
layout_fitWidthFunc = (doc: Doc) => BoolCast(this.layout_fitWidth);
screenToLocalScale = () => this._props.ScreenToLocalTransform().Scale;
- docViewPathFunc = () => this.docViewPath;
isSelected = () => this.IsSelected;
select = (extendSelection: boolean, focusSelection?: boolean) => {
if (this.IsSelected && SelectionManager.Views.length > 1) SelectionManager.DeselectView(this);
@@ -1590,6 +1382,7 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
PanelWidth = () => this.panelWidth;
PanelHeight = () => this.panelHeight;
NativeDimScaling = () => this.nativeScaling;
+ hideLinkCount = () => (this.hideLinkButton ? true : false);
selfView = () => this;
/**
* @returns Transform to the document view (in the coordinate system of whatever contains the DocumentView)
@@ -1604,57 +1397,30 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
.translate(-this.centeringX, -this.centeringY)
.scale(1 / this.nativeScaling);
- componentDidMount() {
- runInAction(() => 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),
- action(height => {
- const docMax = NumCast(this.layoutDoc.layout_maxAutoHeight);
- if (docMax && docMax < height) this.layoutDoc.layout_maxAutoHeight = height;
- })
- );
- !BoolCast(this._props.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.AddView(this);
- }
-
- componentWillUnmount() {
- this.Document[DocViews].delete(this);
- Object.values(this._disposers).forEach(disposer => disposer?.());
- !BoolCast(this._props.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.RemoveView(this);
- }
- // want the htmloverlay to be able to fade in but we also want it to be display 'none' until it is needed.
- // unfortunately, CSS can't transition animate any properties for something that is display 'none'.
- // so we need to first activate the div, then, after a render timeout, start the opacity transition.
- @observable enableHtmlOverlayTransitions: boolean = false;
- @computed get htmlOverlay() {
- const effect = StrCast(this.htmlOverlayEffect?.presentation_effect, StrCast(this.htmlOverlayEffect?.followLinkAnimEffect));
+ htmlOverlay = () => {
+ const effect = StrCast(this._htmlOverlayEffect?.presentation_effect, StrCast(this._htmlOverlayEffect?.followLinkAnimEffect));
return (
<div
className="documentView-htmlOverlay"
ref={r => {
const val = r?.style.display !== 'none'; // if the outer overlay has been displayed, trigger the innner div to start it's opacity fade in transition
- if (r && val !== this.enableHtmlOverlayTransitions) {
- setTimeout(action(() => (this.enableHtmlOverlayTransitions = val)));
+ if (r && val !== this._enableHtmlOverlayTransitions) {
+ setTimeout(action(() => (this._enableHtmlOverlayTransitions = val)));
}
}}
- style={{ display: !this.textHtmlOverlay ? 'none' : undefined }}>
- <div className="documentView-htmlOverlayInner" style={{ transition: `all 500ms`, opacity: this.enableHtmlOverlayTransitions ? 0.9 : 0 }}>
+ style={{ display: !this._htmlOverlayText ? 'none' : undefined }}>
+ <div className="documentView-htmlOverlayInner" style={{ transition: `all 500ms`, opacity: this._enableHtmlOverlayTransitions ? 0.9 : 0 }}>
{DocumentViewInternal.AnimationEffect(
<div className="webBox-textHighlight">
- <ObserverJsxParser autoCloseVoidElements={true} key={42} onError={(e: any) => console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this.textHtmlOverlay)} />
+ <ObserverJsxParser autoCloseVoidElements={true} key={42} onError={(e: any) => console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this._htmlOverlayText)} />
</div>,
- { ...(this.htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Zoom } as any as Doc,
+ { ...(this._htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Zoom } as any as Doc,
this.Document
)}
</div>
</div>
);
- }
-
- @computed get infoUI() {
- return this.ComponentView?.infoUI?.();
- }
+ };
render() {
TraceMobx();
@@ -1663,20 +1429,20 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
return (
<div className="contentFittingDocumentView" onPointerEnter={action(() => (this._isHovering = true))} onPointerLeave={action(() => (this._isHovering = false))}>
- {!this._props.Document || !this._props.PanelWidth() ? null : (
+ {!this.Document || !this._props.PanelWidth() ? null : (
<div
className="contentFittingDocumentView-previewDoc"
ref={this.ContentRef}
style={{
- transition: 'inherit', // this._props.dataTransition,
transform: `translate(${this.centeringX}px, ${this.centeringY}px)`,
width: xshift ?? `${this._props.PanelWidth() - this.Xshift * 2}px`,
height: this._props.forceAutoHeight ? undefined : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this._props.PanelWidth()}px`),
}}>
<DocumentViewInternal
{...this._props}
+ fieldKey={this.LayoutFieldKey}
DocumentView={this.selfView}
- viewPath={this.docViewPathFunc}
+ docViewPath={this.docViewPath}
PanelWidth={this.PanelWidth}
PanelHeight={this.PanelHeight}
NativeWidth={this.NativeWidth}
@@ -1687,17 +1453,46 @@ export class DocumentView extends ObservableReactComponent<DocumentViewProps> {
layout_fitWidth={this.layout_fitWidthFunc}
ScreenToLocalTransform={this.screenToContentsTransform}
focus={this._props.focus || emptyFunction}
- ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))}
+ ref={action((r: DocumentViewInternal | null) => r && (this._docViewInternal = r))}
/>
- {this.htmlOverlay}
- {this.infoUI}
+ {this.htmlOverlay()}
+ {this.ComponentView?.infoUI?.()}
</div>
)}
-
- {this.linkCountView}
+ {/* display link count button */}
+ <DocumentLinksButton hideCount={this.hideLinkCount} View={this} scaling={this.screenToLocalScale} OnHover={true} Bottom={this.topMost} ShowCount={true} />
</div>
);
}
+
+ public static SetViewTransition(docs: Doc[], transProp: string, timeInMs: number, timer?: NodeJS.Timeout | undefined, afterTrans?: () => void, dataTrans = false) {
+ docs.forEach(doc => {
+ doc._viewTransition = `${transProp} ${timeInMs}ms`;
+ dataTrans && (doc.dataTransition = `${transProp} ${timeInMs}ms`);
+ });
+ timer && clearTimeout(timer);
+ return setTimeout(
+ () =>
+ docs.forEach(doc => {
+ doc._viewTransition = undefined;
+ dataTrans && (doc.dataTransition = 'inherit');
+ afterTrans?.();
+ }),
+ timeInMs + 10
+ );
+ }
+
+ // shows a stacking view collection (by default, but the user can change) of all documents linked to the source
+ public static showBackLinks(linkAnchor: Doc) {
+ const docId = Doc.CurrentUserEmail + Doc.GetProto(linkAnchor)[Id] + '-pivotish';
+ // prettier-ignore
+ DocServer.GetRefField(docId).then(docx =>
+ LightboxView.Instance.SetLightboxDoc(
+ (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection
+ Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, onViewMounted: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId)
+ )
+ );
+ }
}
ScriptingGlobals.add(function deiconifyView(documentView: DocumentView) {
diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx
index ff92c701f..2e03a766a 100644
--- a/src/client/views/nodes/EquationBox.tsx
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -20,14 +20,14 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static SelectOnLoad: string = '';
_ref: React.RefObject<EquationEditor> = React.createRef();
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
componentDidMount() {
- this._props.setContentView?.(this);
- if (EquationBox.SelectOnLoad === this.Document[Id] && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath()))) {
+ this._props.setContentViewBox?.(this);
+ if (EquationBox.SelectOnLoad === this.Document[Id] && (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.()))) {
this._props.select(false);
this._ref.current!.mathField.focus();
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 008f10f26..8a49b4757 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -1,43 +1,119 @@
-import { computed } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { DateField } from '../../../fields/DateField';
-import { Doc, Field, FieldResult, Opt } from '../../../fields/Doc';
+import { Doc, Field, Opt } from '../../../fields/Doc';
import { List } from '../../../fields/List';
import { ScriptField } from '../../../fields/ScriptField';
import { WebField } from '../../../fields/URLField';
-import { DocumentViewSharedProps } from './DocumentView';
+import { dropActionType } from '../../util/DragManager';
+import { Transform } from '../../util/Transform';
+import { ViewBoxInterface } from '../DocComponent';
+import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView';
+import { DocumentView, OpenWhere } from './DocumentView';
+import { PinProps } from './trails';
+export interface FocusViewOptions {
+ willPan?: boolean; // determines whether to pan to target document
+ willZoomCentered?: boolean; // determines whether to zoom in on target document. if zoomScale is 0, this just centers the document
+ zoomScale?: number; // percent of containing frame to zoom into document
+ zoomTime?: number;
+ didMove?: boolean; // whether a document was changed during the showDocument process
+ docTransform?: Transform; // when a document can't be panned and zoomed within its own container (say a group), then we need to continue to move up the render hierarchy to find something that can pan and zoom. when this happens the docTransform must accumulate all the transforms of each level of the hierarchy
+ instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom)
+ preview?: boolean; // whether changes should be previewed by the componentView or written to the document
+ effect?: Doc; // animation effect for focus
+ noSelect?: boolean; // whether target should be selected after focusing
+ playAudio?: boolean; // whether to play audio annotation on focus
+ playMedia?: boolean; // whether to play start target videos
+ openLocation?: OpenWhere; // where to open a missing document
+ zoomTextSelections?: boolean; // whether to display a zoomed overlay of anchor text selections
+ toggleTarget?: boolean; // whether to toggle target on and off
+ anchorDoc?: Doc; // doc containing anchor info to apply at end of focus to target doc
+ easeFunc?: 'linear' | 'ease'; // transition method for scrolling
+}
+export type FocusFuncType = (doc: Doc, options: FocusViewOptions) => Opt<number>;
+export type StyleProviderFuncType = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => any;
//
// these properties get assigned through the render() method of the DocumentView when it creates this node.
// However, that only happens because the properties are "defined" in the markup for the field view.
// See the LayoutString method on each field view : ImageBox, FormattedTextBox, etc.
//
-export interface FieldViewProps extends DocumentViewSharedProps {
- // FieldView specific props that are not part of DocumentView props
- fieldKey: string;
+export interface FieldViewSharedProps {
+ Document: Doc;
+ TemplateDataDocument?: Doc;
+ LayoutTemplateString?: string;
+ LayoutTemplate?: () => Opt<Doc>;
+ renderDepth: number;
+ scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document
+ xPadding?: number;
+ yPadding?: number;
+ dontRegisterView?: boolean;
+ dropAction?: dropActionType;
+ dragAction?: dropActionType;
+ forceAutoHeight?: boolean;
+ ignoreAutoHeight?: boolean;
+ disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
+ hideClickBehaviors?: boolean; // whether to suppress menu item options for changing click behaviors
+ CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView;
+ containerViewPath?: () => DocumentView[];
+ fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document
+ isGroupActive?: () => string | undefined; // is this document part of a group that is active
+ setContentViewBox?: (view: ViewBoxInterface) => any; // called by rendered field's viewBox so that DocumentView can make direct calls to the viewBox
+ PanelWidth: () => number;
+ PanelHeight: () => number;
+ isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events
+ isContentActive: () => boolean | undefined; // whether document contents should handle pointer events
+ childFilters: () => string[];
+ childFiltersByRanges: () => string[];
+ styleProvider: Opt<StyleProviderFuncType>;
+ setTitleFocus?: () => void;
+ focus: FocusFuncType;
+ onClickScript?: () => ScriptField;
+ onDoubleClickScript?: () => ScriptField;
+ onPointerDownScript?: () => ScriptField;
+ onPointerUpScript?: () => ScriptField;
+ onBrowseClickScript?: () => ScriptField | undefined;
+ onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined;
+ layout_fitWidth?: (doc: Doc) => boolean | undefined;
+ searchFilterDocs: () => Doc[];
+ layout_showTitle?: () => string;
+ whenChildContentsActiveChanged: (isActive: boolean) => void;
+ rootSelected?: () => boolean; // whether the root of a template has been selected
+ addDocTab: (doc: Doc, where: OpenWhere) => boolean;
+ filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
+ addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean;
+ removeDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean;
+ moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => boolean;
+ pinToPres: (document: Doc, pinProps: PinProps) => void;
+ ScreenToLocalTransform: () => Transform;
+ bringToFront?: (doc: Doc, sendToBack?: boolean) => void;
+ waitForDoubleClickToClick?: () => 'never' | 'always' | undefined;
+ defaultDoubleClick?: () => 'default' | 'ignore' | undefined;
+ pointerEvents?: () => Opt<string>;
+}
- select: (isCtrlPressed: boolean) => void;
- isContentActive: (outsideReaction?: boolean) => boolean | undefined;
- isDocumentActive?: () => boolean | undefined;
+/**
+ * FieldView specific props that are not shared with DocumentView props
+ * */
+export interface FieldViewProps extends FieldViewSharedProps {
+ DocumentView?: () => DocumentView;
+ fieldKey: string;
isSelected: () => boolean;
+ select: (ctrlPressed: boolean, shiftPress?: boolean) => void;
+ docViewPath: () => DocumentView[];
setHeight?: (height: number) => void;
- NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to DocumentViewInternalsProps
- onBrowseClick?: () => ScriptField | undefined;
- onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined;
- pointerEvents?: () => Opt<string>;
+ NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal
// properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React)
// See currentUserUtils headerTemplate for examples of creating text boxes from html which set some of these fields
// Also, see InkingStroke for examples of creating text boxes from render() methods which set some of these fields
backgroundColor?: string;
- treeViewDoc?: Doc;
color?: string;
height?: number;
width?: number;
+ dontSelectOnLoad?: boolean; // suppress selecting (e.g.,. text box) when loaded (and mark as not being associated with scrollTop document field)
noSidebar?: boolean;
dontScale?: boolean;
- dontSelectOnLoad?: boolean; // suppress selecting (e.g.,. text box) when loaded (and mark as not being associated with scrollTop document field)
}
@observer
@@ -46,13 +122,8 @@ export class FieldView extends React.Component<FieldViewProps> {
return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "<ImageBox {...props} fieldKey={'data'} />"
}
- @computed
- get field(): FieldResult {
- const { Document, fieldKey: fieldKey } = this.props;
- return Document[fieldKey];
- }
render() {
- const field = this.field;
+ const field = this.props.Document[this.props.fieldKey];
// prettier-ignore
if (field instanceof Doc) return <p> <b>{field.title?.toString()}</b></p>;
if (field === undefined) return <p>{'<null>'}</p>;
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index 5a8665aaf..cf07d98be 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -46,7 +46,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
return FieldView.LayoutString(FontIconBox, fieldKey);
}
- constructor(props: any) {
+ constructor(props: ButtonProps) {
super(props);
makeObservable(this);
}
diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx
index c26579e66..2e7a2120e 100644
--- a/src/client/views/nodes/FunctionPlotBox.tsx
+++ b/src/client/views/nodes/FunctionPlotBox.tsx
@@ -31,7 +31,7 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps>
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
reaction(
() => [DocListCast(this.dataDoc[this.fieldKey]).map(doc => doc?.text), this.layoutDoc.width, this.layoutDoc.height, this.layoutDoc.xRange, this.layoutDoc.yRange],
() => this.createGraph()
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index a5853499f..923aead64 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -21,17 +21,17 @@ import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from '../../views/ContextMenu';
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
import { MarqueeAnnotator } from '../MarqueeAnnotator';
import { AnchorMenu } from '../pdf/AnchorMenu';
import { StyleProp } from '../StyleProvider';
-import { DocFocusOptions, OpenWhere } from './DocumentView';
-import { FieldView, FieldViewProps } from './FieldView';
+import { OpenWhere } from './DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView';
import './ImageBox.scss';
import { PinProps, PresBox } from './trails';
@observer
-export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(ImageBox, fieldKey);
}
@@ -55,10 +55,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
private _marqueeref = React.createRef<MarqueeAnnotator>();
@observable _curSuffix = '';
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
protected createDropTarget = (ele: HTMLDivElement) => {
@@ -158,7 +158,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
@undoBatch
setNativeSize = action(() => {
- const scaling = (this._props.DocumentView?.().screenToViewTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1);
+ const scaling = (this.DocumentView?.().screenToViewTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1);
const nscale = NumCast(this._props.PanelWidth()) / scaling;
const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw;
@@ -186,9 +186,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
crop = (region: Doc | undefined, addCrop?: boolean) => {
if (!region) return;
const cropping = Doc.MakeCopy(region, true);
- Doc.GetProto(region).lockedPosition = true;
- Doc.GetProto(region).title = 'region:' + this.Document.title;
- Doc.GetProto(region).followLinkToggle = true;
+ const regionData = region[DocData];
+ regionData.lockedPosition = true;
+ regionData.title = 'region:' + this.Document.title;
+ regionData.followLinkToggle = true;
this.addDocument(region);
const anchx = NumCast(cropping.x);
const anchy = NumCast(cropping.y);
@@ -201,7 +202,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
cropping._width = anchw * (this._props.NativeDimScaling?.() || 1);
cropping._height = anchh * (this._props.NativeDimScaling?.() || 1);
cropping.onClick = undefined;
- const croppingProto = Doc.GetProto(cropping);
+ const croppingProto = cropping[DocData];
croppingProto.annotationOn = undefined;
croppingProto.isDataDoc = true;
croppingProto.backgroundColor = undefined;
@@ -226,7 +227,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
this._props.addDocTab(cropping, OpenWhere.inParent);
}
DocumentManager.Instance.AddViewRenderedCb(cropping, dv => setTimeout(() => (dv.ComponentView as ImageBox).setNativeSize(), 200));
- this._props.bringToFront(cropping);
+ this._props.bringToFront?.(cropping);
return cropping;
};
@@ -368,7 +369,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
screenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop) * this.ScreenToLocalBoxXf().Scale);
marqueeDown = (e: React.PointerEvent) => {
- if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
setupMoveUpEvents(
this,
e,
@@ -389,7 +390,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
this._marqueeref.current?.onTerminateSelection();
this._props.select(false);
};
- focus = (anchor: Doc, options: DocFocusOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options));
+ focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options));
_ffref = React.createRef<CollectionFreeFormView>();
savedAnnotations = () => this._savedAnnotations;
@@ -421,7 +422,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
<CollectionFreeFormView
ref={this._ffref}
{...this._props}
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}
renderDepth={this._props.renderDepth + 1}
@@ -444,7 +445,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
{this.content}
</CollectionFreeFormView>
{this.annotationLayer}
- {!this._mainCont.current || !this._annotationLayer.current ? null : (
+ {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : (
<MarqueeAnnotator
Document={this.Document}
ref={this._marqueeref}
@@ -452,7 +453,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
annotationLayerScrollTop={0}
scaling={returnOne}
annotationLayerScaling={this._props.NativeDimScaling}
- docView={this._props.DocumentView!}
+ docView={this.DocumentView}
addDocument={this.addDocument}
finishMarquee={this.finishMarquee}
savedAnnotations={this.savedAnnotations}
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 73fdc3a23..39a45693e 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -44,7 +44,7 @@ export class KeyValueBox extends ObservableReactComponent<FieldViewProps> {
private _valInput = React.createRef<HTMLInputElement>();
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
isKeyValueBox = returnTrue;
able = returnAlways;
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 7bc9d3f85..f9e8ce4f3 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -12,8 +12,7 @@ import { ContextMenu } from '../ContextMenu';
import { EditableView } from '../EditableView';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { DefaultStyleProvider } from '../StyleProvider';
-import { OpenWhere } from './DocumentView';
-import { FieldViewProps } from './FieldView';
+import { OpenWhere, returnEmptyDocViewList } from './DocumentView';
import { KeyValueBox } from './KeyValueBox';
import './KeyValueBox.scss';
import './KeyValuePair.scss';
@@ -61,33 +60,11 @@ export class KeyValuePair extends ObservableReactComponent<KeyValuePairProps> {
};
render() {
- const props: FieldViewProps = {
- Document: this._props.doc,
- childFilters: returnEmptyFilter,
- childFiltersByRanges: returnEmptyFilter,
- searchFilterDocs: returnEmptyDoclist,
- styleProvider: DefaultStyleProvider,
- docViewPath: returnEmptyDoclist,
- fieldKey: this._props.keyName,
- isSelected: returnFalse,
- setHeight: returnFalse,
- select: emptyFunction,
- bringToFront: emptyFunction,
- renderDepth: 1,
- isContentActive: returnFalse,
- whenChildContentsActiveChanged: emptyFunction,
- ScreenToLocalTransform: Transform.Identity,
- focus: emptyFunction,
- PanelWidth: this._props.PanelWidth,
- PanelHeight: this._props.PanelHeight,
- addDocTab: returnFalse,
- pinToPres: returnZero,
- };
// let fieldKey = Object.keys(props.Document).indexOf(props.fieldKey) !== -1 ? props.fieldKey : "(" + props.fieldKey + ")";
let protoCount = 0;
- let doc: Doc | undefined = props.Document;
+ let doc = this._props.doc;
while (doc) {
- if (Object.keys(doc).includes(props.fieldKey)) {
+ if (Object.keys(doc).includes(this._props.keyName)) {
break;
}
protoCount++;
@@ -106,17 +83,17 @@ export class KeyValuePair extends ObservableReactComponent<KeyValuePairProps> {
style={hover}
className="keyValuePair-td-key-delete"
onClick={undoBatch(() => {
- if (Object.keys(props.Document).indexOf(props.fieldKey) !== -1) {
- delete props.Document[props.fieldKey];
- } else delete DocCast(props.Document.proto)?.[props.fieldKey];
+ if (Object.keys(this._props.doc).indexOf(this._props.keyName) !== -1) {
+ delete this._props.doc[this._props.keyName];
+ } else delete DocCast(this._props.doc.proto)?.[this._props.keyName];
})}>
X
</button>
<input className="keyValuePair-td-key-check" type="checkbox" style={hover} onChange={this.handleCheck} ref={this.checkbox} />
- <Tooltip title={Object.entries(new DocumentOptions()).find((pair: [string, FInfo]) => pair[0].replace(/^_/, '') === props.fieldKey)?.[1].description ?? ''}>
- <div className="keyValuePair-keyField" style={{ marginLeft: 20 * (props.fieldKey.match(/_/g)?.length || 0), color: keyStyle }}>
+ <Tooltip title={Object.entries(new DocumentOptions()).find((pair: [string, FInfo]) => pair[0].replace(/^_/, '') === this._props.keyName)?.[1].description ?? ''}>
+ <div className="keyValuePair-keyField" style={{ marginLeft: 20 * (this._props.keyName.match(/_/g)?.length || 0), color: keyStyle }}>
{'('.repeat(parenCount)}
- {props.fieldKey}
+ {this._props.keyName}
{')'.repeat(parenCount)}
</div>
</Tooltip>
@@ -124,7 +101,32 @@ export class KeyValuePair extends ObservableReactComponent<KeyValuePairProps> {
</td>
<td className="keyValuePair-td-value" style={{ width: `${100 - this._props.keyWidth}%` }} onContextMenu={this.onContextMenu}>
<div className="keyValuePair-td-value-container">
- <EditableView contents={undefined} fieldContents={props} GetValue={() => Field.toKeyValueString(props.Document, props.fieldKey)} SetValue={(value: string) => KeyValueBox.SetField(props.Document, props.fieldKey, value)} />
+ <EditableView
+ contents={undefined}
+ fieldContents={{
+ Document: this._props.doc,
+ childFilters: returnEmptyFilter,
+ childFiltersByRanges: returnEmptyFilter,
+ searchFilterDocs: returnEmptyDoclist,
+ styleProvider: DefaultStyleProvider,
+ docViewPath: returnEmptyDocViewList,
+ fieldKey: this._props.keyName,
+ isSelected: returnFalse,
+ setHeight: returnFalse,
+ select: emptyFunction,
+ renderDepth: 1,
+ isContentActive: returnFalse,
+ whenChildContentsActiveChanged: emptyFunction,
+ ScreenToLocalTransform: Transform.Identity,
+ focus: emptyFunction,
+ PanelWidth: this._props.PanelWidth,
+ PanelHeight: this._props.PanelHeight,
+ addDocTab: returnFalse,
+ pinToPres: returnZero,
+ }}
+ GetValue={() => Field.toKeyValueString(this._props.doc, this._props.keyName)}
+ SetValue={(value: string) => KeyValueBox.SetField(this._props.doc, this._props.keyName, value)}
+ />
</div>
</td>
</tr>
diff --git a/src/client/views/nodes/LabelBox.scss b/src/client/views/nodes/LabelBox.scss
index 42e158584..0b195713d 100644
--- a/src/client/views/nodes/LabelBox.scss
+++ b/src/client/views/nodes/LabelBox.scss
@@ -18,6 +18,9 @@
display: inline-block;
margin: auto;
text-overflow: ellipsis;
+ > span {
+ max-height: 100%; // make sure top of text is in view, otherwise it would center on middle of large text span
+ }
}
.labelBox-params {
@@ -29,4 +32,4 @@
width: 100%;
background: lightgray;
border: dimgray solid 1px;
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 934bce448..10eeff08d 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -1,7 +1,7 @@
import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Doc, DocListCast } from '../../../fields/Doc';
+import { Doc, DocListCast, Field } from '../../../fields/Doc';
import { List } from '../../../fields/List';
import { listSpec } from '../../../fields/Schema';
import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
@@ -14,13 +14,15 @@ import { StyleProp } from '../StyleProvider';
import { FieldView, FieldViewProps } from './FieldView';
import BigText from './LabelBigText';
import './LabelBox.scss';
+import { PinProps, PresBox } from './trails';
+import { Docs } from '../../documents/Documents';
-export interface LabelBoxProps {
+export interface LabelBoxProps extends FieldViewProps {
label?: string;
}
@observer
-export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProps>() {
+export class LabelBox extends ViewBoxBaseComponent<LabelBoxProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(LabelBox, fieldKey);
}
@@ -30,20 +32,20 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
private dropDisposer?: DragManager.DragDropDisposer;
private _timeout: any;
- constructor(props: any) {
+ constructor(props: LabelBoxProps) {
super(props);
makeObservable(this);
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
componentWillUnMount() {
this._timeout && clearTimeout(this._timeout);
}
@computed get Title() {
- return this.dataDoc.title_custom ? StrCast(this.Document.title) : this._props.label ? this._props.label : typeof this.dataDoc[this.fieldKey] === 'string' ? StrCast(this.dataDoc[this.fieldKey]) : StrCast(this.Document.title);
+ return this.dataDoc.title_custom ? StrCast(this.Document.title) : this._props.label ? this._props.label : Field.toString(this.dataDoc[this.fieldKey] as Field);
}
protected createDropTarget = (ele: HTMLDivElement) => {
@@ -89,6 +91,19 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
return this._mouseOver ? StrCast(this.layoutDoc._hoverBackgroundColor) : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor);
}
+ getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
+ if (!pinProps) return this.Document;
+ const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.Document.title), annotationOn: this.Document });
+
+ if (anchor) {
+ if (!addAsAnnotation) anchor.backgroundColor = 'transparent';
+ // addAsAnnotation && this.addDocument(anchor);
+ PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}) } }, this.Document);
+ return anchor;
+ }
+ return anchor;
+ };
+
fitTextToBox = (
r: any
):
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index b86ba72a0..00e1f04c5 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -1,4 +1,5 @@
import { action, computed, makeObservable } from 'mobx';
+import { observer } from 'mobx-react';
import * as React from 'react';
import { Utils, emptyFunction, setupMoveUpEvents } from '../../../Utils';
import { Doc } from '../../../fields/Doc';
@@ -13,6 +14,7 @@ import { FieldView, FieldViewProps } from './FieldView';
import './LinkAnchorBox.scss';
import { LinkInfo } from './LinkDocPreview';
const { default: { MEDIUM_GRAY }, } = require('../global/globalCssVariables.module.scss'); // prettier-ignore
+@observer
export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(LinkAnchorBox, fieldKey);
@@ -23,24 +25,26 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
_isOpen = false;
_timeout: NodeJS.Timeout | undefined;
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
@computed get linkSource() {
- return this._props.docViewPath()[this._props.docViewPath().length - 2].Document; // this._props.styleProvider?.(this.dataDoc, this._props, StyleProp.LinkSource);
+ return this.DocumentView?.().containerViewPath?.().lastElement().Document; // this._props.styleProvider?.(this.dataDoc, this._props, StyleProp.LinkSource);
}
onPointerDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => {
- if (doubleTap) LinkFollower.FollowLink(this.Document, this.linkSource, false);
- else this._props.select(false);
- });
+ const linkSource = this.linkSource;
+ linkSource &&
+ setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => {
+ if (doubleTap) LinkFollower.FollowLink(this.Document, linkSource, false);
+ else this._props.select(false);
+ });
};
onPointerMove = action((e: PointerEvent, down: number[], delta: number[]) => {
const cdiv = this._ref?.current?.parentElement;
@@ -86,7 +90,8 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
className={`linkAnchorBox-cont${small ? '-small' : ''}`}
onPointerEnter={e =>
LinkInfo.SetLinkInfo({
- docProps: this._props,
+ DocumentView: this.DocumentView,
+ styleProvider: this._props.styleProvider,
linkSrc: this.linkSource,
linkDoc: this.Document,
showHeader: true,
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 7f1d41547..8b6293806 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -20,7 +20,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
return FieldView.LayoutString(LinkBox, fieldKey);
}
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
@@ -29,12 +29,12 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get anchor1() {
const anchor1 = DocCast(this.dataDoc.link_anchor_1);
const anchor_1 = anchor1?.layout_unrendered ? DocCast(anchor1.annotationOn) : anchor1;
- return DocumentManager.Instance.getDocumentView(anchor_1, this._props.docViewPath()[this._props.docViewPath().length - 2]); // this._props.docViewPath().lastElement());
+ return DocumentManager.Instance.getDocumentView(anchor_1, this.DocumentView?.().containerViewPath?.().lastElement());
}
@computed get anchor2() {
const anchor2 = DocCast(this.dataDoc.link_anchor_2);
const anchor_2 = anchor2?.layout_unrendered ? DocCast(anchor2.annotationOn) : anchor2;
- return DocumentManager.Instance.getDocumentView(anchor_2, this._props.docViewPath()[this._props.docViewPath().length - 2]); // this._props.docViewPath().lastElement());
+ return DocumentManager.Instance.getDocumentView(anchor_2, this.DocumentView?.().containerViewPath?.().lastElement());
}
screenBounds = () => {
if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.CollectionFreeFormView) {
@@ -59,14 +59,14 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
disposer: IReactionDisposer | undefined;
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
this.disposer = reaction(
() => {
if (this.layoutDoc._layout_isSvg && (this.anchor1 || this.anchor2)?.CollectionFreeFormView) {
const a = (this.anchor1 ?? this.anchor2)!;
const b = (this.anchor2 ?? this.anchor1)!;
- const parxf = this._props.docViewPath()[this._props.docViewPath().length - 2].ComponentView as CollectionFreeFormView;
+ const parxf = this.DocumentView?.().containerViewPath?.().lastElement().ComponentView as CollectionFreeFormView;
const this_xf = parxf?.screenToFreeformContentsXf ?? Transform.Identity; //this.ScreenToLocalTransform();
const a_invXf = a.screenToViewTransform().inverse();
const b_invXf = b.screenToViewTransform().inverse();
@@ -100,6 +100,9 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.layoutDoc._width = params.rx - params?.lx;
this.layoutDoc._height = params?.by - params?.ty;
}
+ } else {
+ this.layoutDoc._width = Math.max(50, NumCast(this.layoutDoc._width));
+ this.layoutDoc._height = Math.max(50, NumCast(this.layoutDoc._height));
}
},
{ fireImmediately: true }
@@ -161,12 +164,11 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
return (
<div className={`linkBox-container${this._props.isContentActive() ? '-interactive' : ''}`} style={{ background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) }}>
<ComparisonBox
- {...this._props}
+ {...this._props} //
fieldKey="link_anchor"
setHeight={emptyFunction}
dontRegisterView={true}
renderDepth={this._props.renderDepth + 1}
- isContentActive={this._props.isContentActive}
addDocument={returnFalse}
removeDocument={returnFalse}
moveDocument={returnFalse}
diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx
index 8ad0b7dde..13f0ac4fc 100644
--- a/src/client/views/nodes/LinkDescriptionPopup.tsx
+++ b/src/client/views/nodes/LinkDescriptionPopup.tsx
@@ -1,20 +1,27 @@
-import { action, observable } from 'mobx';
+import { action, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Doc } from '../../../fields/Doc';
+import { DocData } from '../../../fields/DocSymbols';
import { LinkManager } from '../../util/LinkManager';
import './LinkDescriptionPopup.scss';
import { TaskCompletionBox } from './TaskCompletedBox';
@observer
export class LinkDescriptionPopup extends React.Component<{}> {
- @observable public static descriptionPopup: boolean = false;
- @observable public static showDescriptions: string = 'ON';
- @observable public static popupX: number = 700;
- @observable public static popupY: number = 350;
+ public static Instance: LinkDescriptionPopup;
+ @observable public display: boolean = false;
+ @observable public showDescriptions: string = 'ON';
+ @observable public popupX: number = 700;
+ @observable public popupY: number = 350;
@observable description: string = '';
@observable popupRef = React.createRef<HTMLDivElement>();
+ constructor(props: any) {
+ super(props);
+ makeObservable(this);
+ LinkDescriptionPopup.Instance = this;
+ }
+
@action
descriptionChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
this.description = e.currentTarget.value;
@@ -22,16 +29,16 @@ export class LinkDescriptionPopup extends React.Component<{}> {
@action
onDismiss = (add: boolean) => {
- LinkDescriptionPopup.descriptionPopup = false;
+ this.display = false;
if (add) {
- LinkManager.currentLink && (Doc.GetProto(LinkManager.currentLink).link_description = this.description);
+ LinkManager.currentLink && (LinkManager.currentLink[DocData].link_description = this.description);
}
};
@action
onClick = (e: PointerEvent) => {
if (this.popupRef && !!!this.popupRef.current?.contains(e.target as any)) {
- LinkDescriptionPopup.descriptionPopup = false;
+ this.display = false;
TaskCompletionBox.taskCompleted = false;
}
};
@@ -46,13 +53,13 @@ export class LinkDescriptionPopup extends React.Component<{}> {
}
render() {
- return (
+ return !this.display ? null : (
<div
className="linkDescriptionPopup"
ref={this.popupRef}
style={{
- left: LinkDescriptionPopup.popupX ? LinkDescriptionPopup.popupX : 700,
- top: LinkDescriptionPopup.popupY ? LinkDescriptionPopup.popupY : 350,
+ left: this.popupX ? this.popupX : 700,
+ top: this.popupY ? this.popupY : 350,
}}>
<input
className="linkDescriptionPopup-input"
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index ea23ecbea..4b242649a 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -18,7 +18,8 @@ import { SearchUtil } from '../../util/SearchUtil';
import { SettingsManager } from '../../util/SettingsManager';
import { Transform } from '../../util/Transform';
import { ObservableReactComponent } from '../ObservableReactComponent';
-import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView';
+import { DocumentView, OpenWhere } from './DocumentView';
+import { StyleProviderFuncType } from './FieldView';
import './LinkDocPreview.scss';
export class LinkInfo {
@@ -43,7 +44,8 @@ export class LinkInfo {
interface LinkDocPreviewProps {
linkDoc?: Doc;
linkSrc?: Doc;
- docProps: DocumentViewSharedProps;
+ DocumentView?: () => DocumentView;
+ styleProvider?: StyleProviderFuncType;
location: number[];
hrefs?: string[];
showHeader?: boolean;
@@ -152,7 +154,7 @@ export class LinkDocPreview extends ObservableReactComponent<LinkDocPreviewProps
action(() => {
LinkManager.currentLink = this._linkDoc;
LinkManager.currentLinkAnchor = this._linkSrc;
- this._props.docProps.DocumentView?.().select(false);
+ this._props.DocumentView?.().select(false);
if ((SettingsManager.Instance.propertiesWidth ?? 0) < 100) {
SettingsManager.Instance.propertiesWidth = 250;
}
@@ -269,8 +271,8 @@ export class LinkDocPreview extends ObservableReactComponent<LinkDocPreviewProps
}}
Document={this._targetDoc!}
moveDocument={returnFalse}
- styleProvider={this._props.docProps?.styleProvider}
- docViewPath={returnEmptyDoclist}
+ styleProvider={this._props.styleProvider}
+ containerViewPath={returnEmptyDoclist}
ScreenToLocalTransform={Transform.Identity}
isDocumentActive={returnFalse}
isContentActive={returnFalse}
@@ -291,7 +293,6 @@ export class LinkDocPreview extends ObservableReactComponent<LinkDocPreviewProps
focus={emptyFunction}
whenChildContentsActiveChanged={returnFalse}
ignoreAutoHeight={true} // need to ignore layout_autoHeight otherwise layout_autoHeight text boxes will expand beyond the preview panel size.
- bringToFront={returnFalse}
NativeWidth={Doc.NativeWidth(this._targetDoc) ? () => Doc.NativeWidth(this._targetDoc) : undefined}
NativeHeight={Doc.NativeHeight(this._targetDoc) ? () => Doc.NativeHeight(this._targetDoc) : undefined}
/>
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 3575b21e4..c185c66fc 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -23,12 +23,12 @@ import { DragManager } from '../../../util/DragManager';
import { LinkManager } from '../../../util/LinkManager';
import { SnappingManager } from '../../../util/SnappingManager';
import { UndoManager, undoable } from '../../../util/UndoManager';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent';
import { SidebarAnnos } from '../../SidebarAnnos';
import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
import { Colors } from '../../global/globalEnums';
-import { DocFocusOptions, DocumentView } from '../DocumentView';
-import { FieldView, FieldViewProps } from '../FieldView';
+import { DocumentView } from '../DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
import { FormattedTextBox } from '../formattedText/FormattedTextBox';
import { PinProps, PresBox } from '../trails';
import { fastSpeedIcon, mediumSpeedIcon, slowSpeedIcon } from './AnimationSpeedIcons';
@@ -96,7 +96,7 @@ type MapMarker = {
// });
@observer
-export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(MapBox, fieldKey);
}
@@ -107,7 +107,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
private _disposers: { [key: string]: IReactionDisposer } = {};
private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void);
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
@@ -248,7 +248,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
componentDidMount() {
this._unmounting = false;
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
_unmounting = false;
@@ -379,16 +379,16 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
});
const targetCreator = (annotationOn: Doc | undefined) => {
- const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow');
+ const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, 'yellow');
FormattedTextBox.SetSelectOnLoad(target);
return target;
};
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
docView &&
DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(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.Document;
+ e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.Document;
e.annoDragData.linkSourceDoc.followLinkZoom = false;
}
},
@@ -504,7 +504,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
};
- getView = async (doc: Doc, options: DocFocusOptions) => {
+ getView = async (doc: Doc, options: FocusViewOptions) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
this.toggleSidebar();
options.didMove = true;
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
index 9734d9db1..9825824bd 100644
--- a/src/client/views/nodes/MapBox/MapBox2.tsx
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -12,7 +12,7 @@
// import { SnappingManager } from '../../../util/SnappingManager';
// import { UndoManager } from '../../../util/UndoManager';
// import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
-// import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent';
+// import { ViewBoxAnnotatableComponent } from '../../DocComponent';
// import { Colors } from '../../global/globalEnums';
// import { AnchorMenu } from '../../pdf/AnchorMenu';
// import { Annotation } from '../../pdf/Annotation';
@@ -83,7 +83,7 @@
// } as google.maps.places.AutocompleteOptions;
// @observer
-// export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps & Partial<GoogleMapProps>>() {
+// export class MapBox2 extends ViewBoxAnnotatableComponent<FieldViewProps & Partial<GoogleMapProps>>() {
// private _dropDisposer?: DragManager.DragDropDisposer;
// private _disposers: { [name: string]: IReactionDisposer } = {};
// private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
@@ -137,7 +137,7 @@
// // iterate allMarkers to size, center, and zoom map to contain all markers
// private fitBounds = (map: google.maps.Map) => {
-// const curBounds = map.getBounds() ?? new window.google.maps.LatLngBounds();
+// const curBounds = map.getBounds ?? new window.google.maps.LatLngBounds();
// const isFitting = this.allMapMarkers.reduce((fits, place) => fits && curBounds?.contains({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), true as boolean);
// !isFitting && map.fitBounds(this.allMapMarkers.reduce((bounds, place) => bounds.extend({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), new window.google.maps.LatLngBounds()));
// };
@@ -257,7 +257,7 @@
// map.setZoom(NumCast(this.dataDoc.map_zoom, 2.5));
// map.setCenter(new google.maps.LatLng(NumCast(this.dataDoc.mapLat), NumCast(this.dataDoc.mapLng)));
// setTimeout(() => {
-// if (this._loadPending && this._map.getBounds()) {
+// if (this._loadPending && this._map.getBounds) {
// this._loadPending = false;
// this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
// }
@@ -272,7 +272,7 @@
// @action
// centered = () => {
-// if (this._loadPending && this._map.getBounds()) {
+// if (this._loadPending && this._map.getBounds) {
// this._loadPending = false;
// this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
// }
@@ -282,7 +282,7 @@
// @action
// zoomChanged = () => {
-// if (this._loadPending && this._map.getBounds()) {
+// if (this._loadPending && this._map.getBounds) {
// this._loadPending = false;
// this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
// }
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index a9c6ba22c..6ccbbbe1c 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -9,19 +9,18 @@
// import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
// import { CollectionNoteTakingView } from '../../collections/CollectionNoteTakingView';
// import { CollectionStackingView } from '../../collections/CollectionStackingView';
-// import { ViewBoxAnnotatableProps } from '../../DocComponent';
// import { FieldViewProps } from '../FieldView';
// import { FormattedTextBox } from '../formattedText/FormattedTextBox';
// import './MapBox.scss';
-// interface MapBoxInfoWindowProps {
+// interface MapBoxInfoWindowProps extends FieldViewProps {
// place: Doc;
// renderDepth: number;
// markerMap: { [id: string]: google.maps.Marker };
// isAnyChildContentActive: () => boolean;
// }
// @observer
-// export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & ViewBoxAnnotatableProps & FieldViewProps> {
+// export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps> {
// @action
// private handleInfoWindowClose = () => {
// if (this.props.place.infoWindowOpen) {
diff --git a/src/client/views/nodes/MapBox/MapPushpinBox.tsx b/src/client/views/nodes/MapBox/MapPushpinBox.tsx
index 34e237007..fc5b4dd18 100644
--- a/src/client/views/nodes/MapBox/MapPushpinBox.tsx
+++ b/src/client/views/nodes/MapBox/MapPushpinBox.tsx
@@ -18,10 +18,10 @@ export class MapPushpinBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
get mapBoxView() {
- return this._props.DocumentView?.()?._props.docViewPath().lastElement()?.ComponentView as MapBox;
+ return this.DocumentView?.()?.containerViewPath?.().lastElement()?.ComponentView as MapBox;
}
get mapBox() {
- return this._props.DocumentView?.()._props.docViewPath().lastElement()?.Document;
+ return this.DocumentView?.().containerViewPath?.().lastElement()?.Document;
}
render() {
diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
index ea8496c99..8a5bd7ce6 100644
--- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
+++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button, EditableText, IconButton, Type } from 'browndash-components';
-import { IReactionDisposer, ObservableMap, action, computed, observable, reaction, runInAction } from 'mobx';
+import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { MapProvider, Map as MapboxMap } from 'react-map-gl';
@@ -16,18 +16,17 @@ import { LinkManager } from '../../../util/LinkManager';
import { SnappingManager } from '../../../util/SnappingManager';
import { Transform } from '../../../util/Transform';
import { UndoManager, undoable } from '../../../util/UndoManager';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent';
+import { ViewBoxAnnotatableComponent } from '../../DocComponent';
import { SidebarAnnos } from '../../SidebarAnnos';
import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
import { Colors } from '../../global/globalEnums';
-import { DocFocusOptions, DocumentView } from '../DocumentView';
-import { FieldView, FieldViewProps } from '../FieldView';
+import { DocumentView } from '../DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
import { MapAnchorMenu } from '../MapBox/MapAnchorMenu';
import { FormattedTextBox } from '../formattedText/FormattedTextBox';
import { PinProps, PresBox } from '../trails';
import './MapBox.scss';
-// amongus
/**
* MapBox architecture:
* Main component: MapBox.tsx
@@ -61,7 +60,7 @@ const bingApiKey = process.env.BING_MAPS; // if you're running local, get a Bing
// });
@observer
-export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class MapBoxContainer extends ViewBoxAnnotatableComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(MapBoxContainer, fieldKey);
}
@@ -71,6 +70,11 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
private _disposers: { [key: string]: IReactionDisposer } = {};
private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void);
+ constructor(props: FieldViewProps) {
+ super(props);
+ makeObservable(this);
+ }
+
@observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
@computed get allSidebarDocs() {
return DocListCast(this.dataDoc[this.SidebarKey]);
@@ -97,7 +101,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
componentDidMount() {
this._unmounting = false;
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
_unmounting = false;
@@ -228,16 +232,16 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
});
const targetCreator = (annotationOn: Doc | undefined) => {
- const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow');
+ const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, 'yellow');
FormattedTextBox.SetSelectOnLoad(target);
return target;
};
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
docView &&
DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(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.Document;
+ e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.Document;
e.annoDragData.linkSourceDoc.followLinkZoom = false;
}
},
@@ -374,7 +378,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
}
};
- getView = async (doc: Doc, options: DocFocusOptions) => {
+ getView = async (doc: Doc, options: FocusViewOptions) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
this.toggleSidebar();
options.didMove = true;
@@ -787,8 +791,8 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<ViewBoxAnnotata
NativeWidth={returnOne}
NativeHeight={returnOne}
onKey={undefined}
- onDoubleClick={undefined}
- onBrowseClick={undefined}
+ onDoubleClickScript={undefined}
+ onBrowseClickScript={undefined}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 959d5d88d..1274220b6 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -5,6 +5,7 @@ import * as Pdfjs from 'pdfjs-dist';
import 'pdfjs-dist/web/pdf_viewer.css';
import * as React from 'react';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { ComputedField } from '../../../fields/ScriptField';
@@ -22,19 +23,19 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm';
import { CollectionStackingView } from '../collections/CollectionStackingView';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
import { Colors } from '../global/globalEnums';
import { CreateImage } from '../nodes/WebBoxRenderer';
import { PDFViewer } from '../pdf/PDFViewer';
import { SidebarAnnos } from '../SidebarAnnos';
-import { DocFocusOptions, DocumentView, OpenWhere } from './DocumentView';
-import { FieldView, FieldViewProps } from './FieldView';
+import { DocumentView, OpenWhere } from './DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView';
import { ImageBox } from './ImageBox';
import './PDFBox.scss';
import { PinProps, PresBox } from './trails';
@observer
-export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(PDFBox, fieldKey);
}
@@ -58,7 +59,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url;
}
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
const nw = Doc.NativeWidth(this.Document, this.dataDoc) || 927;
@@ -97,12 +98,13 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
crop = (region: Doc | undefined, addCrop?: boolean) => {
if (!region) return;
const cropping = Doc.MakeCopy(region, true);
- Doc.GetProto(region).lockedPosition = true;
- Doc.GetProto(region).title = 'region:' + this.Document.title;
- Doc.GetProto(region).followLinkToggle = true;
+ const regionData = region[DocData];
+ regionData.lockedPosition = true;
+ regionData.title = 'region:' + this.Document.title;
+ regionData.followLinkToggle = true;
this.addDocument(region);
- const docViewContent = this._props.docViewPath().lastElement().ContentDiv!;
+ const docViewContent = this.DocumentView?.().ContentDiv!;
const newDiv = docViewContent.cloneNode(true) as HTMLDivElement;
newDiv.style.width = NumCast(this.layoutDoc._width).toString();
newDiv.style.height = NumCast(this.layoutDoc._height).toString();
@@ -120,7 +122,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
cropping._width = anchw;
cropping._height = anchh;
cropping.onClick = undefined;
- const croppingProto = Doc.GetProto(cropping);
+ const croppingProto = cropping[DocData];
croppingProto.annotationOn = undefined;
croppingProto.isDataDoc = true;
croppingProto.proto = Cast(this.Document.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
@@ -132,7 +134,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
if (addCrop) {
DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' });
}
- this._props.bringToFront(cropping);
+ this._props.bringToFront?.(cropping);
CreateImage(
'',
@@ -163,7 +165,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
updateIcon = () => {
// currently we render pdf icons as text labels
- const docViewContent = this._props.docViewPath().lastElement().ContentDiv!;
+ const docViewContent = this.DocumentView?.().ContentDiv!;
const filename = this.layoutDoc[Id] + '-icon' + new Date().getTime();
this._pdfViewer?._mainCont.current &&
CollectionFreeFormView.UpdateIcon(
@@ -191,7 +193,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
Object.values(this._disposers).forEach(disposer => disposer?.());
}
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
this._disposers.select = reaction(
() => this._props.isSelected(),
() => {
@@ -219,12 +221,12 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
return this._props.addDocTab(doc, where);
};
- focus = (anchor: Doc, options: DocFocusOptions) => {
+ focus = (anchor: Doc, options: FocusViewOptions) => {
this._initialScrollTarget = anchor;
return this._pdfViewer?.scrollFocus(anchor, NumCast(anchor.y, NumCast(anchor.config_scrollTop)), options);
};
- getView = async (doc: Doc, options: DocFocusOptions) => {
+ getView = async (doc: Doc, options: FocusViewOptions) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
options.didMove = true;
this.toggleSidebar(false);
@@ -304,7 +306,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
setPdfViewer = (pdfViewer: PDFViewer) => {
this._pdfViewer = pdfViewer;
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
if (this._initialScrollTarget && docView) {
this.focus(this._initialScrollTarget, { instant: true });
this._initialScrollTarget = undefined;
@@ -525,10 +527,10 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
removeDocument={this.removeDocument}
/>
) : (
- <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this._props.DocumentView?.()!, false), true)}>
+ <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.DocumentView?.()!, false), true)}>
<ComponentTag
{...this._props}
- setContentView={emptyFunction} // override setContentView to do nothing
+ setContentViewBox={emptyFunction} // override setContentView to do nothing
NativeWidth={this.sidebarNativeWidthFunc}
NativeHeight={this.sidebarNativeHeightFunc}
PanelHeight={this._props.PanelHeight}
@@ -581,6 +583,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}}>
<PDFViewer
{...this._props}
+ pdfBox={this}
sidebarAddDoc={this.sidebarAddDocument}
addDocTab={this.sidebarAddDocTab}
layoutDoc={this.layoutDoc}
diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
index c04a81f7d..f6d94ce05 100644
--- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
@@ -1,4 +1,4 @@
-import { action, observable } from 'mobx';
+import { action, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { DateField } from '../../../../fields/DateField';
@@ -21,6 +21,7 @@ import { media_state } from '../AudioBox';
import { FieldView, FieldViewProps } from '../FieldView';
import { VideoBox } from '../VideoBox';
import { RecordingView } from './RecordingView';
+import { DocData } from '../../../../fields/DocSymbols';
@observer
export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -30,8 +31,13 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
private _ref: React.RefObject<HTMLDivElement> = React.createRef();
+ constructor(props: FieldViewProps) {
+ super(props);
+ makeObservable(this);
+ }
+
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
Doc.SetNativeWidth(this.dataDoc, 1280);
Doc.SetNativeHeight(this.dataDoc, 720);
}
@@ -100,7 +106,7 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
});
screengrabber.overlayX = 70; //was -400
screengrabber.overlayY = 590; //was 0
- Doc.GetProto(screengrabber)[Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true;
+ screengrabber[DocData][Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true;
Doc.AddToMyOverlay(screengrabber); //just adds doc to overlay
DocumentManager.Instance.AddViewRenderedCb(screengrabber, docView => {
RecordingBox.screengrabber = docView.ComponentView as RecordingBox;
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index f74e6fb2b..1e3933ac3 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -21,12 +21,13 @@ import { TrackMovements } from '../../util/TrackMovements';
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { CollectionStackedTimeline } from '../collections/CollectionStackedTimeline';
import { ContextMenu } from '../ContextMenu';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { media_state } from './AudioBox';
import { FieldView, FieldViewProps } from './FieldView';
import { FormattedTextBox } from './formattedText/FormattedTextBox';
import './ScreenshotBox.scss';
import { VideoBox } from './VideoBox';
+import { DocData } from '../../../fields/DocSymbols';
declare class MediaRecorder {
constructor(e: any, options?: any); // whatever MediaRecorder has
@@ -109,7 +110,7 @@ declare class MediaRecorder {
// }
@observer
-export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class ScreenshotBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(ScreenshotBox, fieldKey);
}
@@ -121,7 +122,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
return Cast(this.dataDoc[this._props.fieldKey + '_recordingStart'], DateField)?.date.getTime();
}
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
this.setupDictation();
@@ -144,7 +145,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
componentDidMount() {
this.dataDoc.nativeWidth = this.dataDoc.nativeHeight = 0;
- this._props.setContentView?.(this); // this tells the DocumentView that this ScreenshotBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
+ this._props.setContentViewBox?.(this); // this tells the DocumentView that this ScreenshotBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
// this.layoutDoc.videoWall && reaction(() => ({ width: this._props.PanelWidth(), height: this._props.PanelHeight() }),
// ({ width, height }) => {
// if (this._camera) {
@@ -281,7 +282,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
const dictationText = DocUtils.GetNewTextDoc('dictation', NumCast(this.Document.x), NumCast(this.Document.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height));
const textField = Doc.LayoutFieldKey(dictationText);
dictationText._layout_autoHeight = false;
- const dictationTextProto = Doc.GetProto(dictationText);
+ const dictationTextProto = dictationText[DocData];
dictationTextProto[`${textField}_recordingSource`] = this.dataDoc;
dictationTextProto[`${textField}_recordingStart`] = ComputedField.MakeFunction(`this.${textField}_recordingSource.${this.fieldKey}_recordingStart`);
dictationTextProto.mediaState = ComputedField.MakeFunction(`this.${textField}_recordingSource.mediaState`);
@@ -297,7 +298,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
<div style={{ position: 'relative', height: this.videoPanelHeight() }}>
<CollectionFreeFormView
{...this._props}
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}
PanelHeight={this.videoPanelHeight}
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index 73ad3a004..89650889d 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -14,7 +14,7 @@ import { ScriptManager } from '../../util/ScriptManager';
import { CompileScript, ScriptParam } from '../../util/Scripting';
import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { ContextMenu } from '../ContextMenu';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { EditableView } from '../EditableView';
import { OverlayView } from '../OverlayView';
import { FieldView, FieldViewProps } from '../nodes/FieldView';
@@ -23,7 +23,7 @@ import './ScriptingBox.scss';
const _global = (window /* browser */ || global) /* node */ as any;
@observer
-export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class ScriptingBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
private dropDisposer?: DragManager.DragDropDisposer;
public static LayoutString(fieldStr: string) {
return FieldView.LayoutString(ScriptingBox, fieldStr);
@@ -56,7 +56,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
@observable private _scriptSuggestedParams: any = '';
@observable private _scriptParamsText: any = '';
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
if (!this.compileParams.length) {
@@ -116,7 +116,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
@action
componentDidMount() {
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
this.rawText = this.rawScript;
const observer = new _global.ResizeObserver(
action((entries: any) => {
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index fb42286af..40647feff 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -4,10 +4,11 @@ import { observer } from 'mobx-react';
import { basename } from 'path';
import * as React from 'react';
import { Doc, Opt, StrListCast } from '../../../fields/Doc';
+import { DocData } from '../../../fields/DocSymbols';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
-import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
import { AudioField, ImageField, VideoField } from '../../../fields/URLField';
import { emptyFunction, formatTime, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
@@ -21,12 +22,12 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm/Collec
import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionStackedTimeline';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxAnnotatableComponent } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
import { MarqueeAnnotator } from '../MarqueeAnnotator';
import { AnchorMenu } from '../pdf/AnchorMenu';
import { StyleProp } from '../StyleProvider';
-import { DocFocusOptions, DocumentView } from './DocumentView';
-import { FieldView, FieldViewProps } from './FieldView';
+import { DocumentView } from './DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView';
import { RecordingBox } from './RecordingBox';
import { PinProps, PresBox } from './trails';
import './VideoBox.scss';
@@ -44,7 +45,7 @@ import './VideoBox.scss';
*/
@observer
-export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
+export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(VideoBox, fieldKey);
}
@@ -61,10 +62,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
private _playRegionTimer: any = null; // timeout for playback
private _controlsFadeTimer: any = null; // timeout for controls fade
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
}
@observable _stackedTimeline: CollectionStackedTimeline | undefined = undefined; // CollectionStackedTimeline ref
@@ -115,7 +116,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
componentDidMount() {
this.unmounting = false;
- this._props.setContentView?.(this); // this tells the DocumentView that this VideoBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the VideoBox when making a link.
+ this._props.setContentViewBox?.(this); // this tells the DocumentView that this VideoBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the VideoBox when making a link.
this.player && this.setPlayheadTime(this.timeline?.clipStart || 0);
document.addEventListener('keydown', this.keyEvents, true);
@@ -329,11 +330,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
_height: (height / width) * 150,
title: '--snapshot' + NumCast(this.layoutDoc._layout_currentTimecode) + ' image-',
});
- Doc.SetNativeWidth(Doc.GetProto(imageSnapshot), Doc.NativeWidth(this.layoutDoc));
- Doc.SetNativeHeight(Doc.GetProto(imageSnapshot), Doc.NativeHeight(this.layoutDoc));
+ Doc.SetNativeWidth(imageSnapshot[DocData], Doc.NativeWidth(this.layoutDoc));
+ Doc.SetNativeHeight(imageSnapshot[DocData], Doc.NativeHeight(this.layoutDoc));
this._props.addDocument?.(imageSnapshot);
const link = DocUtils.MakeLink(imageSnapshot, this.getAnchor(true), { link_relationship: 'video snapshot' });
- link && (Doc.GetProto(link.link_anchor_2 as Doc).timecodeToHide = NumCast((link.link_anchor_2 as Doc).timecodeToShow) + 3);
+ link && (DocCast(link.link_anchor_2)[DocData].timecodeToHide = NumCast(DocCast(link.link_anchor_2).timecodeToShow) + 3);
setTimeout(() => downX !== undefined && downY !== undefined && DocumentManager.Instance.getFirstDocumentView(imageSnapshot)?.startDragging(downX, downY, 'move', true));
};
@@ -368,7 +369,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
!this.unmounting && this.player && (this.layoutDoc._layout_currentTimecode = this.player.currentTime);
};
- getView = (doc: Doc, options: DocFocusOptions) => {
+ getView = (doc: Doc, options: FocusViewOptions) => {
if (this._stackedTimeline?.makeDocUnfiltered(doc)) {
if (this.heightPercent === 100) {
this.layoutDoc._layout_timelineHeightPercent = VideoBox.heightPercent;
@@ -608,7 +609,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// removes from currently playing display
@action
removeCurrentlyPlaying = () => {
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
if (CollectionStackedTimeline.CurrentlyPlaying && docView) {
const index = CollectionStackedTimeline.CurrentlyPlaying.indexOf(docView);
index !== -1 && CollectionStackedTimeline.CurrentlyPlaying.splice(index, 1);
@@ -617,7 +618,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// adds doc to currently playing display
@action
addCurrentlyPlaying = () => {
- const docView = this._props.DocumentView?.();
+ const docView = this.DocumentView?.();
if (!CollectionStackedTimeline.CurrentlyPlaying) {
CollectionStackedTimeline.CurrentlyPlaying = [];
}
@@ -738,7 +739,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
zoom = (zoom: number) => this.timeline?.setZoom(zoom);
// plays link
- playLink = (doc: Doc, options: DocFocusOptions) => {
+ playLink = (doc: Doc, options: FocusViewOptions) => {
const startTime = Math.max(0, NumCast(doc.config_clipStart, this._stackedTimeline?.anchorStart(doc) || 0));
const endTime = this.timeline?.anchorEnd(doc);
if (startTime !== undefined) {
@@ -749,7 +750,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// starts marquee selection
marqueeDown = (e: React.PointerEvent) => {
- if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) {
setupMoveUpEvents(
this,
e,
@@ -854,7 +855,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
renderDepth={this._props.renderDepth + 1}
startTag={'_timecodeToShow' /* videoStart */}
endTag={'_timecodeToHide' /* videoEnd */}
- bringToFront={emptyFunction}
playFrom={this.playFrom}
setTime={this.setPlayheadTime}
playing={this.playing}
@@ -885,10 +885,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
crop = (region: Doc | undefined, addCrop?: boolean) => {
if (!region) return;
const cropping = Doc.MakeCopy(region, true);
- Doc.GetProto(region).backgroundColor = 'transparent';
- Doc.GetProto(region).lockedPosition = true;
- Doc.GetProto(region).title = 'region:' + this.Document.title;
- Doc.GetProto(region).followLinkToggle = true;
+ const regionData = region[DocData];
+ regionData.backgroundColor = 'transparent';
+ regionData.lockedPosition = true;
+ regionData.title = 'region:' + this.Document.title;
+ regionData.followLinkToggle = true;
region._timecodeToHide = NumCast(region._timecodeToShow) + 0.0001;
this.addDocument(region);
const anchx = NumCast(cropping.x);
@@ -904,7 +905,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
cropping.timecodeToHide = undefined;
cropping.timecodeToShow = undefined;
cropping.onClick = undefined;
- const croppingProto = Doc.GetProto(cropping);
+ const croppingProto = cropping[DocData];
croppingProto.annotationOn = undefined;
croppingProto.isDataDoc = true;
croppingProto.proto = Cast(this.Document.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
@@ -926,7 +927,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
if (addCrop) {
DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' });
}
- this._props.bringToFront(cropping);
+ this._props.bringToFront?.(cropping);
return cropping;
};
savedAnnotations = () => this._savedAnnotations;
@@ -941,7 +942,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
style={{
pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined,
borderRadius,
- overflow: this._props.docViewPath?.().slice(-1)[0].layout_fitWidth ? 'auto' : undefined,
+ overflow: this.DocumentView?.().layout_fitWidth ? 'auto' : undefined,
}}>
<div className="videoBox-viewer" onPointerDown={this.marqueeDown}>
<div
@@ -955,7 +956,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}}>
<CollectionFreeFormView
{...this._props}
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}
renderDepth={this._props.renderDepth + 1}
@@ -978,7 +979,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
</CollectionFreeFormView>
</div>
{this.annotationLayer}
- {!this._mainCont.current || !this._annotationLayer.current ? null : (
+ {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : (
<MarqueeAnnotator
ref={this._marqueeref}
Document={this.Document}
@@ -986,7 +987,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
annotationLayerScrollTop={0}
scaling={returnOne}
annotationLayerScaling={this._props.NativeDimScaling}
- docView={this._props.DocumentView!}
+ docView={this.DocumentView}
containerOffset={this.marqueeOffset}
addDocument={this.addDocWithTimecode}
finishMarquee={this.finishMarquee}
@@ -1004,7 +1005,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
@computed get UIButtons() {
- const bounds = this._props.docViewPath().lastElement().getBounds();
+ const bounds = this.DocumentView?.().getBounds;
const width = (bounds?.right || 0) - (bounds?.left || 0);
const curTime = NumCast(this.layoutDoc._layout_currentTimecode);
return (
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index c3be2b390..5a07540da 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -24,7 +24,7 @@ import { MarqueeOptionsMenu } from '../collections/collectionFreeForm';
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent';
import { Colors } from '../global/globalEnums';
import { LightboxView } from '../LightboxView';
import { MarqueeAnnotator } from '../MarqueeAnnotator';
@@ -33,15 +33,15 @@ import { Annotation } from '../pdf/Annotation';
import { GPTPopup } from '../pdf/GPTPopup/GPTPopup';
import { SidebarAnnos } from '../SidebarAnnos';
import { StyleProp } from '../StyleProvider';
-import { DocComponentView, DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from './DocumentView';
-import { FieldView, FieldViewProps } from './FieldView';
+import { DocumentView, OpenWhere } from './DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView';
import { LinkInfo } from './LinkDocPreview';
import { PinProps, PresBox } from './trails';
import './WebBox.scss';
const { CreateImage } = require('./WebBoxRenderer');
const _global = (window /* browser */ || global) /* node */ as any;
@observer
-export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
+export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(WebBox, fieldKey);
}
@@ -98,7 +98,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
return Cast(this.Document[this._props.fieldKey], WebField)?.url;
}
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
this._webUrl = this._url; // setting the weburl will change the src parameter of the embedded iframe and force a navigation to it.
@@ -172,7 +172,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
};
componentDidMount() {
- this._props.setContentView?.(this); // this tells the DocumentView that this WebBox is the "content" of the document. this allows the DocumentView to call WebBox relevant methods to configure the UI (eg, show back/forward buttons)
+ this._props.setContentViewBox?.(this); // this tells the DocumentView that this WebBox is the "content" of the document. this allows the DocumentView to call WebBox relevant methods to configure the UI (eg, show back/forward buttons)
runInAction(() => {
this._annotationKeySuffix = () => (this._urlHash ? this._urlHash + '_' : '') + 'annotations';
@@ -250,7 +250,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@action
createTextAnnotation = (sel: Selection, selRange: Range | undefined) => {
if (this._mainCont.current && selRange) {
- if (this.dataDoc[this._props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`;
+ if (this.dataDoc[this._props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`;
const clientRects = selRange.getClientRects();
for (let i = 0; i < clientRects.length; i++) {
const rect = clientRects.item(i);
@@ -274,12 +274,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
// clear selection
this._textAnnotationCreator = undefined;
- if (sel.empty) sel.empty(); // Chrome
+ if (sel.empty)
+ sel.empty(); // Chrome
else if (sel.removeAllRanges) sel.removeAllRanges(); // Firefox
return this._savedAnnotations;
};
- focus = (anchor: Doc, options: DocFocusOptions) => {
+ focus = (anchor: Doc, options: FocusViewOptions) => {
if (anchor !== this.Document && this._outerRef.current) {
const windowHeight = this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1);
const scrollTo = Utils.scrollIntoView(NumCast(anchor.y), NumCast(anchor._height), NumCast(this.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(anchor.y) + NumCast(anchor._height), this._scrollHeight));
@@ -296,9 +297,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
};
@action
- getView = (doc: Doc, options: DocFocusOptions) => {
- if (Doc.AreProtosEqual(doc, this.Document)) return new Promise<Opt<DocumentView>>(res => res(this._props.DocumentView?.()));
- if (this.Document.layout_fieldKey === 'layout_icon') this._props.DocumentView?.().iconify();
+ getView = (doc: Doc, options: FocusViewOptions) => {
+ if (Doc.AreProtosEqual(doc, this.Document)) return new Promise<Opt<DocumentView>>(res => res(this.DocumentView?.()));
+ if (this.Document.layout_fieldKey === 'layout_icon') this.DocumentView?.().iconify();
const webUrl = WebCast(doc.config_data)?.url;
if (this._url && webUrl && webUrl.href !== this._url) this.setData(webUrl.href);
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(false);
@@ -343,7 +344,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
iframeUp = (e: PointerEvent) => {
this._getAnchor = AnchorMenu.Instance?.GetAnchor; // need to save AnchorMenu's getAnchor since a subsequent selection on another doc will overwrite this value
this._textAnnotationCreator = undefined;
- this._props.docViewPath().lastElement()?.docView?.cleanupPointerEvents(); // pointerup events aren't generated on containing document view, so we have to invoke it here.
+ this.DocumentView?.()?.cleanupPointerEvents(); // pointerup events aren't generated on containing document view, so we have to invoke it here.
if (this._iframe?.contentWindow && this._iframe.contentDocument && !this._iframe.contentWindow.getSelection()?.isCollapsed) {
const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!);
const scale = (this._props.NativeDimScaling?.() || 1) * mainContBounds.scale;
@@ -364,7 +365,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
e.stopPropagation();
const sel = window.getSelection();
this._textAnnotationCreator = undefined;
- if (sel?.empty) sel.empty(); // Chrome
+ if (sel?.empty)
+ sel.empty(); // Chrome
else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox
// bcz: NEED TO unrotate e.clientX and e.clientY
const word = getWordAtPoint(e.target, e.clientX, e.clientY);
@@ -556,7 +558,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
clearStyleSheetRules(WebBox.webStyleSheet);
this._scrollTimer = undefined;
const newScrollTop = scrollTop > iframeHeight ? iframeHeight : scrollTop;
- if (!LinkInfo.Instance?.LinkInfo && this._outerRef.current && newScrollTop !== this.layoutDoc.thumbScrollTop && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath()))) {
+ if (!LinkInfo.Instance?.LinkInfo && this._outerRef.current && newScrollTop !== this.layoutDoc.thumbScrollTop && (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.()))) {
this.layoutDoc.thumb = undefined;
this.layoutDoc.thumbScrollTop = undefined;
this.layoutDoc.thumbNativeWidth = undefined;
@@ -723,10 +725,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
onMarqueeDown = (e: React.PointerEvent) => {
const sel = this._url ? this._iframe?.contentDocument?.getSelection() : window.document.getSelection();
this._textAnnotationCreator = undefined;
- if (sel?.empty) sel.empty(); // Chrome
+ if (sel?.empty)
+ sel.empty(); // Chrome
else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox
this.marqueeing = [e.clientX, e.clientY];
- if (!e.altKey && e.button === 0 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
setupMoveUpEvents(
this,
e,
@@ -750,7 +753,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this.marqueeing = undefined;
this._textAnnotationCreator = undefined;
const sel = this._url ? this._iframe?.contentDocument?.getSelection() : window.document.getSelection();
- if (sel?.empty) sel.empty(); // Chrome
+ if (sel?.empty)
+ sel.empty(); // Chrome
else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox
this._setPreviewCursor?.(x ?? 0, y ?? 0, false, !this._marqueeref.current?.isEmpty, this.Document);
if (x !== undefined && y !== undefined) {
@@ -762,7 +766,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
setTimeout(() => {
// if menu comes up right away, the down event can still be active causing a menu item to be selected
this.specificContextMenu(undefined as any);
- this._props.docViewPath().lastElement().docView?.onContextMenu(undefined, x, y);
+ this.DocumentView?.().onContextMenu(undefined, x, y);
});
}
}
@@ -908,7 +912,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
});
@action
onZoomWheel = (e: React.WheelEvent) => {
- if (this._props.isContentActive(true)) {
+ if (this._props.isContentActive()) {
e.stopPropagation();
}
};
@@ -920,7 +924,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
};
_innerCollectionView: CollectionFreeFormView | undefined;
zoomScaling = () => this._innerCollectionView?.zoomScaling() ?? 1;
- setInnerContent = (component: DocComponentView) => (this._innerCollectionView = component as CollectionFreeFormView);
+ setInnerContent = (component: ViewBoxInterface) => (this._innerCollectionView = component as CollectionFreeFormView);
@computed get content() {
const interactive = this._props.isContentActive() && this._props.pointerEvents?.() !== 'none' && Doc.ActiveTool === InkTool.None;
@@ -962,7 +966,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
renderAnnotations = (childFilters: () => string[]) => (
<CollectionFreeFormView
{...this._props}
- setContentView={this.setInnerContent}
+ setContentViewBox={this.setInnerContent}
NativeWidth={returnZero}
NativeHeight={returnZero}
originTopLeft={false}
@@ -979,7 +983,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
childFilters={childFilters}
select={emptyFunction}
isAnyChildContentActive={returnFalse}
- bringToFront={emptyFunction}
styleProvider={this.childStyleProvider}
whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
removeDocument={this.removeDocument}
@@ -1065,7 +1068,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter];
opaqueFilter = () => [...this._props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.CanEmbed ? [] : [Utils.OpaqueBackgroundFilter])];
- childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ childStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => {
if (doc instanceof Doc && property === StyleProp.PointerEvents) {
if (this.inlineTextAnnotations.includes(doc)) return 'none';
}
@@ -1099,7 +1102,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
onContextMenu={this.specificContextMenu}>
{this.webpage}
</div>
- {!this._mainCont.current || !this._annotationLayer.current ? null : (
+ {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : (
<div style={{ position: 'absolute', height: '100%', width: '100%', pointerEvents: this.marqueeing ? 'all' : 'none' }}>
<MarqueeAnnotator
ref={this._marqueeref}
@@ -1109,7 +1112,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
annotationLayerScrollTop={0}
scaling={this._props.NativeDimScaling}
addDocument={this.addDocumentWrapper}
- docView={this._props.DocumentView!}
+ docView={this.DocumentView}
finishMarquee={this.finishMarquee}
savedAnnotations={this.savedAnnotationsCreator}
selectionText={this.selectionText}
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index 4fb1a7f17..748c3322e 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -18,6 +18,11 @@ export class CalendarBox extends ViewBoxBaseComponent<FieldViewProps>() {
return FieldView.LayoutString(CalendarBox, fieldKey);
}
+ constructor(props: FieldViewProps) {
+ super(props);
+ makeObservable(this);
+ }
+
componentDidMount(): void {}
componentWillUnmount(): void {}
@@ -105,11 +110,6 @@ export class CalendarBox extends ViewBoxBaseComponent<FieldViewProps>() {
});
}
- constructor(props: any) {
- super(props);
- makeObservable(this);
- }
-
render() {
return (
<div className="calendar-box-conatiner">
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 6a2cd359c..7335c9286 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -11,7 +11,8 @@ import { DocServer } from '../../../DocServer';
import { Docs, DocUtils } from '../../../documents/Documents';
import { Transform } from '../../../util/Transform';
import { ObservableReactComponent } from '../../ObservableReactComponent';
-import { DocFocusOptions, DocumentView } from '../DocumentView';
+import { DocumentView } from '../DocumentView';
+import { FocusViewOptions } from '../FieldView';
import { FormattedTextBox } from './FormattedTextBox';
var horizPadding = 3; // horizontal padding to container to allow cursor to show up on either side.
@@ -159,7 +160,7 @@ export class DashDocViewInternal extends ObservableReactComponent<IDashDocViewIn
const { scale, translateX, translateY } = Utils.GetScreenTransform(this._spanRef.current);
return new Transform(-translateX, -translateY, 1).scale(1 / scale);
};
- outerFocus = (target: Doc, options: DocFocusOptions) => this._textBox.focus(target, options); // ideally, this would scroll to show the focus target
+ outerFocus = (target: Doc, options: FocusViewOptions) => this._textBox.focus(target, options); // ideally, this would scroll to show the focus target
onKeyDown = (e: any) => {
e.stopPropagation();
@@ -207,7 +208,7 @@ export class DashDocViewInternal extends ObservableReactComponent<IDashDocViewIn
isDocumentActive={returnFalse}
isContentActive={this.isContentActive}
styleProvider={this._textBox._props.styleProvider}
- docViewPath={this._textBox._props.docViewPath}
+ containerViewPath={this._textBox.DocumentView?.().docViewPath}
ScreenToLocalTransform={this.getDocTransform}
addDocTab={this._textBox._props.addDocTab}
pinToPres={returnFalse}
@@ -216,7 +217,6 @@ export class DashDocViewInternal extends ObservableReactComponent<IDashDocViewIn
PanelHeight={this._dashDoc[Height]}
focus={this.outerFocus}
whenChildContentsActiveChanged={this._props.tbox.whenChildContentsActiveChanged}
- bringToFront={emptyFunction}
dontRegisterView={false}
childFilters={this._props.tbox?._props.childFilters}
childFiltersByRanges={this._props.tbox?._props.childFiltersByRanges}
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 555b752f0..dc9914637 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -148,7 +148,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
}
createPivotForField = (e: React.MouseEvent) => {
- let container = this._props.tbox._props.DocumentView?.()._props.docViewPath().lastElement();
+ let container = this._props.tbox.DocumentView?.().containerViewPath?.().lastElement();
if (container) {
const embedding = Doc.MakeEmbedding(container.Document);
embedding._type_collection = CollectionViewType.Time;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index ae26f170b..731ab1d53 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -14,7 +14,7 @@ import * as React from 'react';
import { BsMarkdownFill } from 'react-icons/bs';
import { DateField } from '../../../../fields/DateField';
import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
-import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols';
+import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, DocData, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols';
import { Id } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
@@ -42,7 +42,7 @@ import { CollectionStackingView } from '../../collections/CollectionStackingView
import { CollectionTreeView } from '../../collections/CollectionTreeView';
import { ContextMenu } from '../../ContextMenu';
import { ContextMenuProps } from '../../ContextMenuItem';
-import { ViewBoxAnnotatableComponent } from '../../DocComponent';
+import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent';
import { Colors } from '../../global/globalEnums';
import { LightboxView } from '../../LightboxView';
import { AnchorMenu } from '../../pdf/AnchorMenu';
@@ -50,8 +50,8 @@ import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup';
import { SidebarAnnos } from '../../SidebarAnnos';
import { StyleProp } from '../../StyleProvider';
import { media_state } from '../AudioBox';
-import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere } from '../DocumentView';
-import { FieldView, FieldViewProps } from '../FieldView';
+import { DocumentView, DocumentViewInternal, OpenWhere } from '../DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
import { LinkInfo } from '../LinkDocPreview';
import { PinProps, PresBox } from '../trails';
import { DashDocCommentView } from './DashDocCommentView';
@@ -68,10 +68,8 @@ import { RichTextRules } from './RichTextRules';
import { schema } from './schema_rts';
import { SummaryView } from './SummaryView';
// import * as applyDevTools from 'prosemirror-dev-tools';
-
-export interface FormattedTextBoxProps {}
@observer
-export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps & FormattedTextBoxProps>() {
+export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
public static LayoutString(fieldStr: string) {
return FieldView.LayoutString(FormattedTextBox, fieldStr);
}
@@ -91,6 +89,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
private _scrollRef: React.RefObject<HTMLDivElement> = React.createRef();
private _editorView: Opt<EditorView>;
public _applyingChange: string = '';
+ private _inDrop = false;
private _finishingLink = false;
private _searchIndex = 0;
private _lastTimedMark: Mark | undefined = undefined;
@@ -123,7 +122,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
@computed get noSidebar() {
- return this._props.docViewPath().lastElement()?._props.hideDecorationTitle || this._props.noSidebar || this.Document._layout_noSidebar;
+ return this.DocumentView?.()._props.hideDecorationTitle || this._props.noSidebar || this.Document._layout_noSidebar;
}
@computed get layout_sidebarWidthPercent() {
return this._showSidebar ? '20%' : StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
@@ -202,7 +201,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return url.startsWith(document.location.origin) ? new URL(url).pathname.split('doc/').lastElement() : ''; // docId
}
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
FormattedTextBox.Instance = this;
@@ -271,14 +270,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
if (target) {
anchor.followLinkAudio = true;
let stopFunc: any;
- Doc.GetProto(target).mediaState = media_state.Recording;
- Doc.GetProto(target).audioAnnoState = 'recording';
- DocumentViewInternal.recordAudioAnnotation(Doc.GetProto(target), Doc.LayoutFieldKey(target), stop => (stopFunc = stop));
+ const targetData = target[DocData];
+ targetData.mediaState = media_state.Recording;
+ targetData.audioAnnoState = 'recording';
+ DocumentViewInternal.recordAudioAnnotation(targetData, Doc.LayoutFieldKey(target), stop => (stopFunc = stop));
let reactionDisposer = reaction(
() => target.mediaState,
action(dictation => {
if (!dictation) {
- Doc.GetProto(target).audioAnnoState = 'stopped';
+ targetData.audioAnnoState = 'stopped';
stopFunc();
reactionDisposer();
}
@@ -310,7 +310,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return target;
};
- DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this._props.docViewPath().lastElement(), () => this.getAnchor(true), targetCreator), e.pageX, e.pageY);
+ DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.DocumentView?.()!, () => this.getAnchor(true), targetCreator), e.pageX, e.pageY);
});
const coordsB = this._editorView!.coordsAtPos(this._editorView!.state.selection.to);
this._props.rootSelected?.() && AnchorMenu.Instance.jumpTo(coordsB.left, coordsB.bottom);
@@ -356,7 +356,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
textChange && (dataDoc[this.fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())));
if ((!prevData && !protoData) || newText || (!newText && !templateData)) {
// if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
- if ((this._finishingLink || this._props.isContentActive()) && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
+ if ((this._finishingLink || this._props.isContentActive() || this._inDrop) && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
const numstring = NumCast(dataDoc[this.fieldKey], null);
dataDoc[this.fieldKey] = numstring !== undefined ? Number(newText) : new RichTextField(newJson, newText);
dataDoc[this.fieldKey + '_noTemplate'] = true; // mark the data field as being split from the template if it has been edited
@@ -433,7 +433,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
autoLink = () => {
const newAutoLinks = new Set<Doc>();
- const oldAutoLinks = LinkManager.Links(this._props.Document).filter(link => link.link_relationship === LinkManager.AutoKeywords);
+ const oldAutoLinks = LinkManager.Links(this.Document).filter(link => link.link_relationship === LinkManager.AutoKeywords);
if (this._editorView?.state.doc.textContent) {
const isNodeSel = this._editorView.state.selection instanceof NodeSelection;
const f = this._editorView.state.selection.from;
@@ -451,7 +451,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
updateTitle = () => {
const title = StrCast(this.dataDoc.title, Cast(this.dataDoc.title, RichTextField, null)?.Text);
if (
- !this._props.dontRegisterView && // (this._props.Document.isTemplateForField === "text" || !this._props.Document.isTemplateForField) && // only update the title if the data document's data field is changing
+ !this._props.dontRegisterView && // (this.Document.isTemplateForField === "text" || !this.Document.isTemplateForField) && // only update the title if the data document's data field is changing
(title.startsWith('-') || title.startsWith('@')) &&
this._editorView &&
!this.dataDoc.title_custom &&
@@ -494,7 +494,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
DocUtils.MakeLink(this.Document, target, { link_relationship: LinkManager.AutoKeywords })!);
newAutoLinks.add(alink);
// DocCast(alink.link_anchor_1).followLinkLocation = 'add:right';
- const allAnchors = [{ href: Doc.localServerPath(target), title: 'a link', anchorId: this._props.Document[Id] }];
+ const allAnchors = [{ href: Doc.localServerPath(target), title: 'a link', anchorId: this.Document[Id] }];
allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.autoLinkAnchor.name)?.attrs.allAnchors ?? []));
const link = editorView.state.schema.marks.autoLinkAnchor.create({ allAnchors, title: 'auto term' });
tr = tr.addMark(pos, pos + node.nodeSize, link);
@@ -572,18 +572,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
if (dragData) {
const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc.proto), this.fieldKey) ? DocCast(this.layoutDoc.proto) : this.dataDoc;
const effectiveAcl = GetEffectiveAcl(dataDoc);
- const draggedDoc = dragData.draggedDocuments.lastElement();
+ const draggedDoc = dragData.droppedDocuments.lastElement();
let added: Opt<boolean>;
+ const dropAction = dragData.dropAction || dragData.userDropAction;
if ([AclEdit, AclAdmin, AclSelfEdit].includes(effectiveAcl)) {
// replace text contents when dragging with Alt
if (de.altKey) {
const fieldKey = Doc.LayoutFieldKey(draggedDoc);
- if (draggedDoc[fieldKey] instanceof RichTextField && !Doc.AreProtosEqual(draggedDoc, this._props.Document)) {
+ if (draggedDoc[fieldKey] instanceof RichTextField && !Doc.AreProtosEqual(draggedDoc, this.Document)) {
Doc.GetProto(this.dataDoc)[this.fieldKey] = Field.Copy(draggedDoc[fieldKey]);
}
// embed document when drag marked as embed
- } else if (de.embedKey) {
+ } else if (de.embedKey || dropAction) {
const node = schema.nodes.dashDoc.create({
width: NumCast(draggedDoc._width),
height: NumCast(draggedDoc._height),
@@ -591,20 +592,25 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
docId: draggedDoc[Id],
float: 'unset',
});
- if (!['embed', 'copy'].includes((dragData.dropAction ?? '') as any)) {
+ if (!['embed', 'copy'].includes((dropAction ?? '') as any)) {
added = dragData.removeDocument?.(draggedDoc) ? true : false;
+ } else {
+ added = true;
}
if (added) {
draggedDoc._freeform_fitContentsToBox = true;
Doc.SetContainer(draggedDoc, this.Document);
const view = this._editorView!;
try {
+ this._inDrop = true;
const pos = view.posAtCoords({ left: de.x, top: de.y })?.pos;
pos && view.dispatch(view.state.tr.insert(pos, node));
added = pos ? true : false; // pos will be null if you don't drop onto an actual text location
} catch (e) {
console.log('Drop failed', e);
added = false;
+ } finally {
+ this._inDrop = false;
}
}
}
@@ -991,7 +997,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
};
const link = DocUtils.MakeLinkToActiveAudio(textanchorFunc, false).lastElement();
if (link) {
- Doc.GetProto(link).isDictation = true;
+ link[DocData].isDictation = true;
const audioanchor = Cast(link.link_anchor_2, Doc, null);
const textanchor = Cast(link.link_anchor_1, Doc, null);
if (audioanchor) {
@@ -1001,7 +1007,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
audioId: audioanchor[Id],
textId: textanchor[Id],
});
- Doc.GetProto(textanchor).title = 'dictation:' + audiotag.attrs.timeCode;
+ textanchor[DocData].title = 'dictation:' + audiotag.attrs.timeCode;
const tr = this._editorView.state.tr.insert(this._editorView.state.doc.content.size, audiotag);
const tr2 = tr.setSelection(TextSelection.create(tr.doc, tr.doc.content.size));
this._editorView.dispatch(tr.setSelection(TextSelection.create(tr2.doc, tr2.doc.content.size)));
@@ -1056,7 +1062,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return anchorDoc ?? this.Document;
}
- getView = async (doc: Doc, options: DocFocusOptions) => {
+ getView = async (doc: Doc, options: FocusViewOptions) => {
if (DocListCast(this.dataDoc[this.SidebarKey]).find(anno => Doc.AreProtosEqual(doc.layout_unrendered ? DocCast(doc.annotationOn) : doc, anno))) {
if (!this.SidebarShown) {
this.toggleSidebar(false);
@@ -1066,7 +1072,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
};
- focus = (textAnchor: Doc, options: DocFocusOptions) => {
+ focus = (textAnchor: Doc, options: FocusViewOptions) => {
const focusSpeed = options.zoomTime ?? 500;
const textAnchorId = textAnchor[Id];
const findAnchorFrag = (frag: Fragment, editor: EditorView) => {
@@ -1141,7 +1147,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return Doc.NativeAspect(this.Document, this.dataDoc, false) ? this._props.NativeDimScaling?.() || 1 : 1;
}
componentDidMount() {
- !this._props.dontSelectOnLoad && this._props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
+ !this._props.dontSelectOnLoad && this._props.setContentViewBox?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
this._cachedLinks = LinkManager.Links(this.Document);
this._disposers.breakupDictation = reaction(() => Doc.RecordingEvent, this.breakupDictation);
this._disposers.layout_autoHeight = reaction(
@@ -1410,7 +1416,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
(this._editorView as any).TextView = this;
}
- const selectOnLoad = Doc.AreProtosEqual(this._props.TemplateDataDocument ?? this.Document, FormattedTextBox.SelectOnLoad) && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath()));
+ const selectOnLoad = Doc.AreProtosEqual(this._props.TemplateDataDocument ?? this.Document, FormattedTextBox.SelectOnLoad) && (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.()));
if (this._editorView && selectOnLoad && !this._props.dontRegisterView && !this._props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) {
const selLoadChar = FormattedTextBox.SelectOnLoadChar;
FormattedTextBox.SelectOnLoad = undefined;
@@ -1531,7 +1537,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
if (!state || !editor || !this.ProseRef?.children[0].className.includes('-focused')) return;
if (!state.selection.empty && !(state.selection instanceof NodeSelection)) this.setupAnchorMenu();
- else if (this._props.isContentActive(true)) {
+ else if (this._props.isContentActive()) {
const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY });
let xpos = pcords?.pos || 0;
while (xpos > 0 && !state.doc.resolve(xpos).node()?.isTextblock) {
@@ -1764,7 +1770,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return toNum(height) + Math.max(0, toNum(marginTop)) + Math.max(0, toNum(marginBottom));
};
const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + toHgt(child), margins);
- const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.layout_maxAutoHeight, proseHeight), proseHeight);
+ const scrollHeight = this.ProseRef && proseHeight;
if (this._props.setHeight && scrollHeight && !this._props.dontRegisterView) {
// if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
const setScrollHeight = () => (this.dataDoc[this.fieldKey + '_scrollHeight'] = scrollHeight);
@@ -1777,7 +1783,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
}
};
- fitContentsToBox = () => BoolCast(this._props.Document._freeform_fitContentsToBox);
+ fitContentsToBox = () => BoolCast(this.Document._freeform_fitContentsToBox);
sidebarContentScaling = () => (this._props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => {
if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar();
@@ -1852,7 +1858,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
setHeight={this.setSidebarHeight}
/>
) : (
- <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this._props.DocumentView?.()!, false), true)}>
+ <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.DocumentView?.()!, false), true)}>
<ComponentTag
{...this._props}
ref={this._sidebarTagRef as any}
@@ -2011,7 +2017,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
cursor: this._props.isContentActive() ? 'text' : undefined,
height: this._props.height ? 'max-content' : undefined,
overflow: this.layout_autoHeight ? 'hidden' : undefined,
- pointerEvents: Doc.ActiveTool === InkTool.None && !this._props.onBrowseClick?.() ? undefined : 'none',
+ pointerEvents: Doc.ActiveTool === InkTool.None && !this._props.onBrowseClickScript?.() ? undefined : 'none',
}}
onContextMenu={this.specificContextMenu}
onKeyDown={this.onKeyDown}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index be8736525..ce17af6ca 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -134,7 +134,8 @@ export class FormattedTextBoxComment {
//nbef &&
naft &&
LinkInfo.SetLinkInfo({
- docProps: textBox.props,
+ DocumentView: textBox.DocumentView,
+ styleProvider: textBox._props.styleProvider,
linkSrc: textBox.Document,
linkDoc: linkDoc ? (DocServer.GetCachedRefField(linkDoc) as Doc) : undefined,
location: (pos => [pos.left, pos.top + 25])(view.coordsAtPos(state.selection.from - Math.max(0, nbef - 1))),
diff --git a/src/client/views/nodes/importBox/ImportElementBox.tsx b/src/client/views/nodes/importBox/ImportElementBox.tsx
index 7d0086c0c..6e7c3e612 100644
--- a/src/client/views/nodes/importBox/ImportElementBox.tsx
+++ b/src/client/views/nodes/importBox/ImportElementBox.tsx
@@ -1,4 +1,4 @@
-import { computed } from 'mobx';
+import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { returnFalse } from '../../../../Utils';
@@ -12,6 +12,10 @@ export class ImportElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(ImportElementBox, fieldKey);
}
+ constructor(props: FieldViewProps) {
+ super(props);
+ makeObservable(this);
+ }
screenToLocalXf = () => this.ScreenToLocalBoxXf().scale(1 * (this._props.NativeDimScaling?.() || 1));
@computed get mainItem() {
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 6fa64a765..9e5ea9524 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -4,7 +4,7 @@ import { action, computed, IReactionDisposer, makeObservable, observable, Observ
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast, FieldResult, NumListCast, Opt, StrListCast } from '../../../../fields/Doc';
-import { Animation } from '../../../../fields/DocSymbols';
+import { Animation, DocData } from '../../../../fields/DocSymbols';
import { Copy, Id } from '../../../../fields/FieldSymbols';
import { InkField } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
@@ -31,8 +31,8 @@ import { TreeView } from '../../collections/TreeView';
import { ViewBoxBaseComponent } from '../../DocComponent';
import { Colors } from '../../global/globalEnums';
import { LightboxView } from '../../LightboxView';
-import { DocFocusOptions, DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView';
-import { FieldView, FieldViewProps } from '../FieldView';
+import { DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView';
+import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
import { ScriptingBox } from '../ScriptingBox';
import './PresBox.scss';
import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums';
@@ -70,7 +70,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
static navigateToDocScript: ScriptField;
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
if (!PresBox.navigateToDocScript) {
@@ -184,7 +184,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
},
{ fireImmediately: true }
);
- this._props.setContentView?.(this);
+ this._props.setContentViewBox?.(this);
this._unmounting = false;
this.turnOffEdit(true);
this._disposers.selection = reaction(
@@ -294,13 +294,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
listItemDoc.presentation_effect = this.activeItem.presBulletEffect;
listItemDoc.presentation_transition = 500;
targetView?.setAnimEffect(listItemDoc, 500);
- if (targetView?.docView && this.activeItem.presBulletExpand) {
- targetView.docView._animateScalingTo = 1.2;
- targetView.docView._animateScaleTime = 400;
- Doc.AddUnHighlightWatcher(() => {
- targetView.docView!._animateScaleTime = undefined;
- targetView!.docView!._animateScalingTo = 0;
- });
+ if (targetView && this.activeItem.presBulletExpand) {
+ targetView.setAnimateScaling(1.2, 400);
+ Doc.AddUnHighlightWatcher(() => targetView?.setAnimateScaling(0, undefined));
}
listItemDoc.opacity = undefined;
this.activeItem.presentation_indexed = presIndexed + 1;
@@ -442,9 +438,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const setData = bestTargetView?.ComponentView?.setData;
if (setData) setData(activeItem.config_data);
else {
- const current = Doc.GetProto(bestTarget)[fkey];
- Doc.GetProto(bestTarget)[fkey + '_' + Date.now()] = current instanceof ObjectField ? current[Copy]() : current;
- Doc.GetProto(bestTarget)[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data;
+ const bestTargetData = bestTarget[DocData];
+ const current = bestTargetData[fkey];
+ bestTargetData[fkey + '_' + Date.now()] = current instanceof ObjectField ? current[Copy]() : current;
+ bestTargetData[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data;
}
bestTarget[fkey + '_usePath'] = activeItem.config_usePath;
setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10);
@@ -502,11 +499,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
if (pinDataTypes?.inkable || (!pinDataTypes && (activeItem.config_fillColor !== undefined || activeItem.color !== undefined))) {
if (bestTarget.fillColor !== activeItem.config_fillColor) {
- Doc.GetProto(bestTarget).fillColor = StrCast(activeItem.config_fillColor, StrCast(bestTarget.fillColor));
+ bestTarget[DocData].fillColor = StrCast(activeItem.config_fillColor, StrCast(bestTarget.fillColor));
changed = true;
}
if (bestTarget.color !== activeItem.config_color) {
- Doc.GetProto(bestTarget).color = StrCast(activeItem.config_color, StrCast(bestTarget.color));
+ bestTarget[DocData].color = StrCast(activeItem.config_color, StrCast(bestTarget.color));
changed = true;
}
if (bestTarget.width !== activeItem.width) {
@@ -563,7 +560,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
return doc;
});
const newList = new List<Doc>([...oldItems, ...hiddenItems, ...newItems]);
- Doc.GetProto(bestTarget)[fkey + '_annotations'] = newList;
+ bestTarget[DocData][fkey + '_annotations'] = newList;
}
if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.config_pinLayoutData !== undefined)) {
changed = true;
@@ -584,9 +581,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
data.fill && (doc._fillColor = data.fill);
doc._width = data.w;
doc._height = data.h;
- data.data && (Doc.GetProto(doc).data = field);
- data.text && (Doc.GetProto(doc).text = tfield);
- Doc.AddDocToList(Doc.GetProto(bestTarget), layoutField, doc);
+ data.data && (doc[DocData].data = field);
+ data.text && (doc[DocData].text = tfield);
+ Doc.AddDocToList(bestTarget[DocData], layoutField, doc);
}
});
setTimeout(() => Array.from(transitioned).forEach(action(doc => (doc._dataTransition = undefined))), transTime + 10);
@@ -652,7 +649,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
if (pinProps.pinData.dataannos) {
const fkey = Doc.LayoutFieldKey(targetDoc);
- pinDoc.config_annotations = new List<Doc>(DocListCast(Doc.GetProto(targetDoc)[fkey + '_annotations']).filter(doc => !doc.layout_unrendered));
+ pinDoc.config_annotations = new List<Doc>(DocListCast(targetDoc[DocData][fkey + '_annotations']).filter(doc => !doc.layout_unrendered));
}
if (pinProps.pinData.inkable) {
pinDoc.config_fillColor = targetDoc.fillColor;
@@ -767,7 +764,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
const effect = activeItem.presentation_effect && activeItem.presentation_effect !== PresEffect.None ? activeItem.presentation_effect : undefined;
const presTime = NumCast(activeItem.presentation_transition, effect ? 750 : 500);
- const options: DocFocusOptions = {
+ const options: FocusViewOptions = {
willPan: activeItem.presentation_movement !== PresMovement.None,
willZoomCentered: activeItem.presentation_movement === PresMovement.Zoom || activeItem.presentation_movement === PresMovement.Jump || activeItem.presentation_movement === PresMovement.Center,
zoomScale: activeItem.presentation_movement === PresMovement.Center ? 0 : NumCast(activeItem.config_zoom, 1),
@@ -1119,7 +1116,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
presDocView && SelectionManager.SelectView(presDocView, false);
};
- focusElement = (doc: Doc, options: DocFocusOptions) => {
+ focusElement = (doc: Doc, options: FocusViewOptions) => {
this.selectElement(doc);
return undefined;
};
@@ -2609,7 +2606,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
moveDocument={returnFalse}
ignoreUnrendered={true}
childDragAction="move"
- setContentView={emptyFunction}
+ setContentViewBox={emptyFunction}
//childLayoutFitWidth={returnTrue}
childOpacity={returnOne}
childClickScript={PresBox.navigateToDocScript}
@@ -2622,7 +2619,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
ScreenToLocalTransform={this.getTransform}
AddToMap={this.AddToMap}
RemFromMap={this.RemFromMap}
- hierarchyIndex={emptyPath}
+ hierarchyIndex={emptyPath as any as number[]}
/>
) : null}
</div>
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 4945d66c8..5b2aa1cde 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -19,7 +19,7 @@ import { TreeView } from '../../collections/TreeView';
import { ViewBoxBaseComponent } from '../../DocComponent';
import { EditableView } from '../../EditableView';
import { Colors } from '../../global/globalEnums';
-import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../../nodes/DocumentView';
+import { DocumentView } from '../../nodes/DocumentView';
import { FieldView, FieldViewProps } from '../../nodes/FieldView';
import { StyleProp } from '../../StyleProvider';
import { PresBox } from './PresBox';
@@ -41,7 +41,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
readonly expandViewHeight = 100;
readonly collapsedHeight = 35;
- constructor(props: any) {
+ constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
@@ -50,7 +50,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
// the presentation view that renders this slide
@computed get presBoxView() {
- return this._props.DocumentView?.()?._props.docViewPath().lastElement()?.ComponentView as PresBox;
+ return this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as PresBox;
}
// the presentation view document that renders this slide
@@ -97,7 +97,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
presExpandDocumentClick = () => (this.slideDoc.presentation_expandInlineButton = !this.slideDoc.presentation_expandInlineButton);
embedHeight = () => this.collapsedHeight + this.expandViewHeight;
embedWidth = () => this._props.PanelWidth() / 2;
- styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ styleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => {
return property === StyleProp.Opacity ? 1 : this._props.styleProvider?.(doc, props, property);
};
/**
@@ -116,7 +116,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
hideLinkButton={true}
ScreenToLocalTransform={Transform.Identity}
renderDepth={this._props.renderDepth + 1}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
childFilters={this._props.childFilters}
childFiltersByRanges={this._props.childFiltersByRanges}
searchFilterDocs={this._props.searchFilterDocs}
@@ -128,7 +128,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
whenChildContentsActiveChanged={returnFalse}
addDocTab={returnFalse}
pinToPres={returnFalse}
- bringToFront={returnFalse}
/>
</div>
);
@@ -196,7 +195,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
const dragArray = this.presBoxView?._dragArray ?? [];
const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []);
if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.slideDoc);
- dragData.treeViewDoc = this.presBox?._type_collection === CollectionViewType.Tree ? this.presBox : undefined; // this._props.DocumentView?.()?._props.treeViewDoc;
+ dragData.treeViewDoc = this.presBox?._type_collection === CollectionViewType.Tree ? this.presBox : undefined; // this.DocumentView?.()?._props.treeViewDoc;
dragData.moveDocument = this._props.moveDocument;
const dragItem: HTMLElement[] = [];
const classesToRestore = new Map<HTMLElement, string>();
diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss
index cfe07f6cb..d3dd9f727 100644
--- a/src/client/views/pdf/PDFViewer.scss
+++ b/src/client/views/pdf/PDFViewer.scss
@@ -52,6 +52,7 @@
.textLayer {
pointer-events: all;
user-select: text;
+ z-index: 0;
}
}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 1eee28ef3..0d4cfda88 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -17,11 +17,11 @@ import { SnappingManager } from '../../util/SnappingManager';
import { MarqueeOptionsMenu } from '../collections/collectionFreeForm';
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { MarqueeAnnotator } from '../MarqueeAnnotator';
-import { DocFocusOptions, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView';
-import { FieldViewProps } from '../nodes/FieldView';
+import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView';
import { LinkInfo } from '../nodes/LinkDocPreview';
+import { PDFBox } from '../nodes/PDFBox';
import { ObservableReactComponent } from '../ObservableReactComponent';
-import { StyleProp, testDocProps } from '../StyleProvider';
+import { StyleProp } from '../StyleProvider';
import { AnchorMenu } from './AnchorMenu';
import { Annotation } from './Annotation';
import { GPTPopup } from './GPTPopup/GPTPopup';
@@ -33,6 +33,7 @@ const _global = (window /* browser */ || global) /* node */ as any;
Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.0.379/build/pdf.worker.mjs';
interface IViewerProps extends FieldViewProps {
+ pdfBox: PDFBox;
Document: Doc;
dataDoc: Doc;
layoutDoc: Doc;
@@ -170,7 +171,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
// scrolls to focus on a nested annotation document. if this is part a link preview then it will jump to the scroll location,
// otherwise it will scroll smoothly.
- scrollFocus = (doc: Doc, scrollTop: number, options: DocFocusOptions) => {
+ scrollFocus = (doc: Doc, scrollTop: number, options: FocusViewOptions) => {
const mainCont = this._mainCont.current;
let focusSpeed: Opt<number>;
if (doc !== this._props.Document && mainCont) {
@@ -313,7 +314,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
this._ignoreScroll = false;
if (this._scrollTimer) clearTimeout(this._scrollTimer); // wait until a scrolling pause, then create an anchor to audio
this._scrollTimer = setTimeout(() => {
- DocUtils.MakeLinkToActiveAudio(() => this._props.DocumentView?.().ComponentView?.getAnchor!(true)!, false);
+ DocUtils.MakeLinkToActiveAudio(() => this._props.pdfBox.getAnchor(true)!, false);
this._scrollTimer = undefined;
}, 200);
}
@@ -364,10 +365,10 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
this._downX = e.clientX;
this._downY = e.clientY;
if ((this._props.Document._freeform_scale || 1) !== 1) return;
- if ((e.button !== 0 || e.altKey) && this._props.isContentActive(true)) {
+ if ((e.button !== 0 || e.altKey) && this._props.isContentActive()) {
this._setPreviewCursor?.(e.clientX, e.clientY, true, false, this._props.Document);
}
- if (!e.altKey && e.button === 0 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
this._props.select(false);
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
this._marqueeref.current?.onInitiateSelection([e.clientX, e.clientY]);
@@ -419,7 +420,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
@action
createTextAnnotation = (sel: Selection, selRange: Range) => {
if (this._mainCont.current) {
- this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`;
+ this._mainCont.current.style.transform = `rotate(${NumCast(this._props.pdfBox.ScreenToLocalBoxXf().RotateDeg)}deg)`;
const boundingRect = this._mainCont.current.getBoundingClientRect();
const clientRects = selRange.getClientRects();
for (let i = 0; i < clientRects.length; i++) {
@@ -465,7 +466,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
@action
onZoomWheel = (e: React.WheelEvent) => {
- if (this._props.isContentActive(true)) {
+ if (this._props.isContentActive()) {
e.stopPropagation();
if (e.ctrlKey) {
const curScale = Number(this._pdfViewer.currentScaleValue);
@@ -497,11 +498,10 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1);
transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter];
opaqueFilter = () => [...this._props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.CanEmbed && this._props.isContentActive() ? [] : [Utils.OpaqueBackgroundFilter])];
- childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewInternalProps | FieldViewProps>, property: string): any => {
+ childStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => {
if (doc instanceof Doc && property === StyleProp.PointerEvents) {
- const docProps = testDocProps(props) ? props : undefined;
if (this.inlineTextAnnotations.includes(doc) || this._props.isContentActive() === false) return 'none';
- const isInk = doc.layout_isSvg && !docProps?.LayoutTemplateString;
+ const isInk = doc.layout_isSvg && !props?.LayoutTemplateString;
return isInk ? 'visiblePainted' : 'all';
}
return this._props.styleProvider?.(doc, props, property);
@@ -520,7 +520,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
{...this._props}
NativeWidth={returnZero}
NativeHeight={returnZero}
- setContentView={emptyFunction} // override setContentView to do nothing
+ setContentViewBox={emptyFunction} // override setContentView to do nothing
pointerEvents={this._props.isContentActive() && (SnappingManager.IsDragging || Doc.ActiveTool !== InkTool.None) ? returnAll : returnNone} // freeform view doesn't get events unless something is being dragged onto it.
childPointerEvents={this.childPointerEvents} // but freeform children need to get events to allow text editing, etc
renderDepth={this._props.renderDepth + 1}
@@ -535,7 +535,6 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
isAnnotationOverlayScrollable={true}
childFilters={childFilters}
select={emptyFunction}
- bringToFront={emptyFunction}
styleProvider={this.childStyleProvider}
/>
</div>
@@ -589,7 +588,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
isNativeScaled={true}
annotationLayerScrollTop={NumCast(this._props.Document._layout_scrollTop)}
addDocument={this.addDocumentWrapper}
- docView={this._props.DocumentView!}
+ docView={this._props.pdfBox.DocumentView!}
finishMarquee={this.finishMarquee}
savedAnnotations={this.savedAnnotations}
selectionText={this.selectionText}
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 4d29573d4..5dc4f5550 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -3,7 +3,7 @@ import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCastAsync, Field } from '../../../fields/Doc';
-import { DirectLinks } from '../../../fields/DocSymbols';
+import { DirectLinks, DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { DocCast, StrCast } from '../../../fields/Types';
import { DocumentType } from '../../documents/DocumentTypes';
@@ -58,7 +58,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
/**
* This is the constructor for the SearchBox class.
*/
- constructor(props: any) {
+ constructor(props: SearchBoxProps) {
super(props);
makeObservable(this);
SearchBox.Instance = this;
@@ -207,7 +207,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
this._results.forEach((_, doc) => {
this._pageRanks.set(doc, 1.0 / this._results.size);
- if (Doc.GetProto(doc)[DirectLinks].size === 0) {
+ if (doc[DocData][DirectLinks].size === 0) {
this._linkedDocsOut.set(doc, new Set(this._results.keys()));
this._results.forEach((_, linkedDoc) => {
@@ -216,7 +216,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
} else {
const linkedDocSet = new Set<Doc>();
- Doc.GetProto(doc)[DirectLinks].forEach(link => {
+ doc[DocData][DirectLinks].forEach(link => {
const d1 = link?.link_anchor_1 as Doc;
const d2 = link?.link_anchor_2 as Doc;
if (doc === d1 && this._results.has(d2)) {
diff --git a/src/client/views/selectedDoc/SelectedDocView.tsx b/src/client/views/selectedDoc/SelectedDocView.tsx
index 39e778b76..c9c01189e 100644
--- a/src/client/views/selectedDoc/SelectedDocView.tsx
+++ b/src/client/views/selectedDoc/SelectedDocView.tsx
@@ -1,14 +1,14 @@
-import * as React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { ListBox } from 'browndash-components';
import { computed } from 'mobx';
import { observer } from 'mobx-react';
+import * as React from 'react';
+import { emptyFunction } from '../../../Utils';
import { Doc } from '../../../fields/Doc';
import { StrCast } from '../../../fields/Types';
import { DocumentManager } from '../../util/DocumentManager';
-import { DocFocusOptions } from '../nodes/DocumentView';
-import { emptyFunction } from '../../../Utils';
import { SettingsManager } from '../../util/SettingsManager';
+import { FocusViewOptions } from '../nodes/FieldView';
export interface SelectedDocViewProps {
selectedDocs: Doc[];
@@ -25,7 +25,7 @@ export class SelectedDocView extends React.Component<SelectedDocViewProps> {
<div className="selectedDocView-container">
<ListBox
items={this.selectedDocs.map(doc => {
- const options: DocFocusOptions = {
+ const options: FocusViewOptions = {
playAudio: false,
playMedia: false,
willPan: true,
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index 575d5849e..4155800b8 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -22,7 +22,7 @@ import { CollectionDockingView } from '../collections/CollectionDockingView';
import { CollectionLinearView } from '../collections/collectionLinear';
import { DashboardView } from '../DashboardView';
import { Colors } from '../global/globalEnums';
-import { DocumentViewInternal } from '../nodes/DocumentView';
+import { DocumentViewInternal, returnEmptyDocViewList } from '../nodes/DocumentView';
import { DefaultStyleProvider } from '../StyleProvider';
import './TopBar.scss';
@@ -100,16 +100,14 @@ export class TopBar extends React.Component {
<div className="collectionMenu-contMenuButtons" style={{ height: '100%' }}>
<CollectionLinearView
Document={selDoc}
+ docViewPath={returnEmptyDocViewList}
fieldKey="data"
dropAction="embed"
- setHeight={returnFalse}
styleProvider={DefaultStyleProvider}
- bringToFront={emptyFunction}
select={emptyFunction}
isContentActive={returnTrue}
isAnyChildContentActive={returnFalse}
isSelected={returnFalse}
- docViewPath={returnEmptyDoclist}
moveDocument={returnFalse}
addDocument={returnFalse}
addDocTab={DocumentViewInternal.addDocTabFunc}
diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx
index 94458563e..4e984f3d6 100644
--- a/src/client/views/webcam/DashWebRTCVideo.tsx
+++ b/src/client/views/webcam/DashWebRTCVideo.tsx
@@ -8,7 +8,6 @@ import { Doc } from '../../../fields/Doc';
import { InkTool } from '../../../fields/InkField';
import { SnappingManager } from '../../util/SnappingManager';
import '../../views/nodes/WebBox.scss';
-import { CollectionFreeFormDocumentViewProps } from '../nodes/CollectionFreeFormDocumentView';
import { FieldView, FieldViewProps } from '../nodes/FieldView';
import './DashWebRTCVideo.scss';
import { hangup, initialize, refreshVideos } from './WebCamLogic';
@@ -17,14 +16,12 @@ import { hangup, initialize, refreshVideos } from './WebCamLogic';
* This models the component that will be rendered, that can be used as a doc that will reflect the video cams.
*/
@observer
-export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentViewProps & FieldViewProps> {
+export class DashWebRTCVideo extends React.Component<FieldViewProps> {
private roomText: HTMLInputElement | undefined;
@observable remoteVideoAdded: boolean = false;
@action
- changeUILook = () => {
- this.remoteVideoAdded = true;
- };
+ changeUILook = () => (this.remoteVideoAdded = true);
/**
* Function that submits the title entered by user on enter press.
@@ -42,14 +39,9 @@ export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentV
return FieldView.LayoutString(DashWebRTCVideo, fieldKey);
}
- @action
- onClickRefresh = () => {
- refreshVideos();
- };
+ onClickRefresh = () => refreshVideos();
- onClickHangUp = () => {
- hangup();
- };
+ onClickHangUp = () => hangup();
render() {
const content = (
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index d726f7064..ff416bbe7 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -31,6 +31,7 @@ import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor }
import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField';
import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, setter, SharingPermissions } from './util';
import * as JSZip from 'jszip';
+import { FieldViewProps } from '../client/views/nodes/FieldView';
export const LinkedTo = '-linkedTo';
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -423,7 +424,7 @@ export namespace Doc {
//
export async function SetInPlace(doc: Doc, key: string, value: Field | undefined, defaultProto: boolean) {
if (key.startsWith('_')) key = key.substring(1);
- const hasProto = Doc.GetProto(doc) !== doc ? Doc.GetProto(doc) : undefined;
+ const hasProto = doc[DocData] !== doc ? doc[DocData] : undefined;
const onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1;
const onProto = hasProto && Object.getOwnPropertyNames(hasProto).indexOf(key) !== -1;
if (onDeleg || !hasProto || (!onProto && !defaultProto)) {
@@ -510,7 +511,7 @@ export namespace Doc {
export function RemoveDocFromList(listDoc: Doc, fieldKey: string | undefined, doc: Doc) {
const key = fieldKey ? fieldKey : Doc.LayoutFieldKey(listDoc);
if (listDoc[key] === undefined) {
- Doc.GetProto(listDoc)[key] = new List<Doc>();
+ listDoc[DocData][key] = new List<Doc>();
}
const list = Cast(listDoc[key], listSpec(Doc));
if (list) {
@@ -530,7 +531,7 @@ export namespace Doc {
export function AddDocToList(listDoc: Doc, fieldKey: string | undefined, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean, allowDuplicates?: boolean, reversed?: boolean) {
const key = fieldKey ? fieldKey : Doc.LayoutFieldKey(listDoc);
if (listDoc[key] === undefined) {
- Doc.GetProto(listDoc)[key] = new List<Doc>();
+ listDoc[DocData][key] = new List<Doc>();
}
const list = Cast(listDoc[key], listSpec(Doc));
if (list) {
@@ -564,7 +565,7 @@ export namespace Doc {
Doc.SetLayout(embedding, Doc.MakeEmbedding(layout));
}
embedding.createdFrom = doc;
- embedding.proto_embeddingId = Doc.GetProto(doc).proto_embeddingId = DocListCast(Doc.GetProto(doc).proto_embeddings).length - 1;
+ embedding.proto_embeddingId = doc[DocData].proto_embeddingId = DocListCast(doc[DocData].proto_embeddings).length - 1;
!Doc.GetT(embedding, 'title', 'string', true) && (embedding.title = ComputedField.MakeFunction(`renameEmbedding(this)`));
embedding.author = Doc.CurrentUserEmail;
@@ -1084,8 +1085,8 @@ export namespace Doc {
export function LayoutField(doc: Doc) {
return doc[StrCast(doc.layout_fieldKey, 'layout')];
}
- export function LayoutFieldKey(doc: Doc): string {
- return StrCast(Doc.Layout(doc).layout).split("'")[1]; // bcz: TODO check on this . used to always reference 'layout', now it uses the layout speicfied by the current layout_fieldKey
+ export function LayoutFieldKey(doc: Doc, templateLayoutString?: string): string {
+ return StrCast(templateLayoutString || Doc.Layout(doc).layout).split("'")[1]; // bcz: TODO check on this . used to always reference 'layout', now it uses the layout speicfied by the current layout_fieldKey
}
export function NativeAspect(doc: Doc, dataDoc?: Doc, useDim?: boolean) {
return Doc.NativeWidth(doc, dataDoc, useDim) / (Doc.NativeHeight(doc, dataDoc, useDim) || 1);
@@ -1100,10 +1101,10 @@ export namespace Doc {
return NumCast(doc._nativeHeight, nheight || dheight);
}
export function SetNativeWidth(doc: Doc, width: number | undefined, fieldKey?: string) {
- doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '_nativeWidth'] = width;
+ doc[(fieldKey || Doc.LayoutFieldKey(doc)) + '_nativeWidth'] = width;
}
export function SetNativeHeight(doc: Doc, height: number | undefined, fieldKey?: string) {
- doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '_nativeHeight'] = height;
+ doc[(fieldKey || Doc.LayoutFieldKey(doc)) + '_nativeHeight'] = height;
}
const manager = new UserDocData();
@@ -1127,22 +1128,22 @@ export namespace Doc {
}
const isSearchMatchCache = computedFn(function IsSearchMatch(doc: Doc) {
- return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) : brushManager.SearchMatchDoc.has(Doc.GetProto(doc)) ? brushManager.SearchMatchDoc.get(Doc.GetProto(doc)) : undefined;
+ return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) : brushManager.SearchMatchDoc.has(doc[DocData]) ? brushManager.SearchMatchDoc.get(doc[DocData]) : undefined;
});
export function IsSearchMatch(doc: Doc) {
return isSearchMatchCache(doc);
}
export function IsSearchMatchUnmemoized(doc: Doc) {
- return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) : brushManager.SearchMatchDoc.has(Doc.GetProto(doc)) ? brushManager.SearchMatchDoc.get(Doc.GetProto(doc)) : undefined;
+ return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) : brushManager.SearchMatchDoc.has(doc[DocData]) ? brushManager.SearchMatchDoc.get(doc[DocData]) : undefined;
}
export function SetSearchMatch(doc: Doc, results: { searchMatch: number }) {
- if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(Doc.GetProto(doc)) !== AclPrivate) {
+ if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(doc[DocData]) !== AclPrivate) {
brushManager.SearchMatchDoc.set(doc, results);
}
return doc;
}
export function SearchMatchNext(doc: Doc, backward: boolean) {
- if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc;
+ if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(doc[DocData]) === AclPrivate) return doc;
const result = brushManager.SearchMatchDoc.get(doc);
const num = Math.abs(result?.searchMatch || 0) + 1;
runInAction(() => result && brushManager.SearchMatchDoc.set(doc, { searchMatch: backward ? -num : num }));
@@ -1160,13 +1161,13 @@ export namespace Doc {
}
// returns 'how' a Doc has been brushed over - whether the document itself was brushed, it's prototype, or neither
export function GetBrushStatus(doc: Doc) {
- if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return DocBrushStatus.unbrushed;
- return doc[Brushed] ? DocBrushStatus.selfBrushed : Doc.GetProto(doc)[Brushed] ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed;
+ if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(doc[DocData]) === AclPrivate || doc.opacity === 0) return DocBrushStatus.unbrushed;
+ return doc[Brushed] ? DocBrushStatus.selfBrushed : doc[DocData][Brushed] ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed;
}
export function BrushDoc(doc: Doc, unbrush = false) {
- if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(Doc.GetProto(doc)) !== AclPrivate) {
+ if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(doc[DocData]) !== AclPrivate) {
brushManager.brushDoc(doc, unbrush);
- brushManager.brushDoc(Doc.GetProto(doc), unbrush);
+ brushManager.brushDoc(doc[DocData], unbrush);
}
return doc;
}
@@ -1186,6 +1187,7 @@ export namespace Doc {
}
export function linkFollowUnhighlight() {
clearTimeout(UnhighlightTimer);
+ UnhighlightTimer = 0;
UnhighlightWatchers.forEach(watcher => watcher());
UnhighlightWatchers.length = 0;
highlightedDocs.forEach(doc => Doc.UnHighlightDoc(doc));
@@ -1205,8 +1207,8 @@ export namespace Doc {
export var highlightedDocs = new ObservableSet<Doc>();
export function IsHighlighted(doc: Doc) {
- if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return false;
- return doc[Highlight] || Doc.GetProto(doc)[Highlight];
+ if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(doc[DocData]) === AclPrivate || doc.opacity === 0) return false;
+ return doc[Highlight] || doc[DocData][Highlight];
}
export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true, presentation_effect?: Doc) {
runInAction(() => {
@@ -1214,8 +1216,8 @@ export namespace Doc {
doc[Highlight] = true;
doc[Animation] = presentation_effect;
if (dataAndDisplayDocs) {
- highlightedDocs.add(Doc.GetProto(doc));
- Doc.GetProto(doc)[Highlight] = true;
+ highlightedDocs.add(doc[DocData]);
+ doc[DocData][Highlight] = true;
}
});
}
@@ -1224,8 +1226,8 @@ export namespace Doc {
runInAction(() => {
(doc ? [doc] : Array.from(highlightedDocs)).forEach(doc => {
highlightedDocs.delete(doc);
- highlightedDocs.delete(Doc.GetProto(doc));
- doc[Highlight] = Doc.GetProto(doc)[Highlight] = false;
+ highlightedDocs.delete(doc[DocData]);
+ doc[Highlight] = doc[DocData][Highlight] = false;
doc[Animation] = undefined;
});
});
@@ -1245,6 +1247,11 @@ export namespace Doc {
: undefined;
}
+ export function toggleLockedPosition(doc: Doc) {
+ doc._lockedPosition = !doc._lockedPosition;
+ doc._pointerEvents = doc._lockedPosition ? 'none' : undefined;
+ }
+
export function deiconifyView(doc: Doc) {
StrCast(doc.layout_fieldKey).split('_')[1] === 'icon' && setNativeView(doc);
}
@@ -1341,7 +1348,7 @@ export namespace Doc {
});
}
- export function styleFromLayoutString(doc: Doc, props: any, scale: number) {
+ export function styleFromLayoutString(doc: Doc, props: FieldViewProps, scale: number) {
const style: { [key: string]: any } = {};
const divKeys = ['width', 'height', 'fontSize', 'transform', 'left', 'backgroundColor', 'left', 'right', 'top', 'bottom', 'pointerEvents', 'position'];
const replacer = (match: any, expr: string, offset: any, string: any) => {
@@ -1349,7 +1356,7 @@ export namespace Doc {
return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: 'number' })?.script.run({ this: doc, self: doc, scale }).result?.toString() ?? '';
};
divKeys.map((prop: string) => {
- const p = props[prop];
+ const p = (props as any)[prop];
typeof p === 'string' && (style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer));
});
return style;
@@ -1588,7 +1595,7 @@ ScriptingGlobals.add(function idToDoc(id: string): any {
return IdToDoc(id);
});
ScriptingGlobals.add(function renameEmbedding(doc: any) {
- return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, '') + `(${doc.proto_embeddingId})`;
+ return StrCast(doc[DocData].title).replace(/\([0-9]*\)/, '') + `(${doc.proto_embeddingId})`;
});
ScriptingGlobals.add(function getProto(doc: any) {
return Doc.GetProto(doc);
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index a1ce55314..c31e73b42 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -396,9 +396,8 @@ export class MobileInterface extends React.Component {
isContentActive={emptyFunction}
focus={emptyFunction}
styleProvider={this.whitebackground}
- docViewPath={returnEmptyDoclist}
+ containerViewPath={returnEmptyDoclist}
whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
childFilters={returnEmptyFilter}
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
diff --git a/src/server/DashStats.ts b/src/server/DashStats.ts
index b6164832f..a9e6af67c 100644
--- a/src/server/DashStats.ts
+++ b/src/server/DashStats.ts
@@ -15,7 +15,8 @@ export namespace DashStats {
export const SAMPLING_INTERVAL = 1000; // in milliseconds (ms) - Time interval to update the frontend.
export const RATE_INTERVAL = 10; // in seconds (s) - Used to calculate rate
- const statsCSVFilename = './src/server/stats/userLoginStats.csv';
+ const statsCSVDirectory = './src/server/stats/';
+ const statsCSVFilename = statsCSVDirectory + 'userLoginStats.csv';
const columns = ['USERNAME', 'ACTION', 'TIME'];
/**
@@ -153,6 +154,7 @@ export namespace DashStats {
TIME: currentDate.toISOString(),
};
+ if (!fs.existsSync(statsCSVDirectory)) fs.mkdirSync(statsCSVDirectory);
let statsFile = fs.createWriteStream(statsCSVFilename, { flags: 'a' });
statsFile.write(convertToCSV(toWrite));
statsFile.end();