From a6cc25e5d03ffed16bfaa32e48e9cc2eaff7deaf Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 7 Nov 2023 13:48:26 -0500 Subject: Changed how selection works to avoid invalidations. Fixed Cast problem with ProxyFields that caused renameEmbedding to infinite loop.. Changed brushing for the same reason. Cleaned up a few things with filter code. --- src/client/util/CurrentUserUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/util/CurrentUserUtils.ts') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 87ee1b252..ba3c26b42 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -339,7 +339,7 @@ export class CurrentUserUtils { /// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}, hidden?: boolean}[] { - const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())"; + const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target?.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())"; const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails"; return [ { title: "Dashboards", toolTip: "Dashboards", target: this.setupDashboards(doc, "myDashboards"), ignoreClick: true, icon: "desktop", funcs: {hidden: "IsNoviceMode()"} }, -- cgit v1.2.3-70-g09d2 From 216385c7e84febce8988ef1390845b0c661fb04f Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 8 Nov 2023 12:55:59 -0500 Subject: fixed bug where tableBox's didn't render all of the rows they receive. lots of code cleanup -- moving things from Doc.ts to better locations. Changed overlays and published docs to be local to their dashboard. changed treeview icons. --- src/client/documents/Documents.ts | 46 +- src/client/util/CurrentUserUtils.ts | 8 +- src/client/util/DocumentManager.ts | 5 +- src/client/util/LinkManager.ts | 32 +- src/client/util/SettingsManager.tsx | 10 +- src/client/views/DashboardView.tsx | 5 +- src/client/views/DocumentDecorations.tsx | 10 +- src/client/views/GestureOverlay.tsx | 11 +- src/client/views/InkTranscription.tsx | 9 +- src/client/views/InkingStroke.tsx | 9 +- src/client/views/MainView.tsx | 5 +- src/client/views/OverlayView.tsx | 128 +++--- src/client/views/PropertiesView.tsx | 12 +- src/client/views/StyleProvider.tsx | 4 +- .../views/collections/CollectionNoteTakingView.tsx | 10 +- .../views/collections/CollectionPileView.tsx | 17 +- .../views/collections/CollectionStackingView.tsx | 12 +- src/client/views/collections/CollectionSubView.tsx | 5 +- .../views/collections/CollectionTreeView.tsx | 6 +- src/client/views/collections/TabDocView.tsx | 4 +- src/client/views/collections/TreeView.tsx | 18 +- .../CollectionFreeFormLayoutEngines.tsx | 9 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 31 +- .../collectionLinear/CollectionLinearView.tsx | 2 +- src/client/views/global/globalScripts.ts | 25 +- src/client/views/nodes/ColorBox.tsx | 19 +- .../views/nodes/DataVizBox/components/TableBox.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 14 +- src/client/views/nodes/EquationBox.tsx | 3 +- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 11 +- src/client/views/nodes/ImageBox.tsx | 6 +- src/client/views/nodes/LinkBox.tsx | 11 +- src/client/views/nodes/LinkDocPreview.tsx | 30 +- src/client/views/nodes/LoadingBox.tsx | 21 +- src/client/views/nodes/MapBox/MapBox.tsx | 4 +- src/client/views/nodes/MapBox/MapBox2.tsx | 3 +- src/client/views/nodes/PDFBox.tsx | 25 +- src/client/views/nodes/ScreenshotBox.tsx | 9 +- src/client/views/nodes/VideoBox.tsx | 5 +- src/client/views/nodes/WebBox.tsx | 21 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 21 +- src/client/views/nodes/formattedText/marks_rts.ts | 2 +- src/client/views/nodes/trails/PresElementBox.tsx | 17 +- src/client/views/pdf/Annotation.tsx | 6 +- src/fields/Doc.ts | 464 +++++---------------- src/fields/RichTextUtils.ts | 2 +- src/fields/util.ts | 2 +- src/mobile/MobileInterface.tsx | 11 +- 48 files changed, 482 insertions(+), 660 deletions(-) (limited to 'src/client/util/CurrentUserUtils.ts') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c5a42aadc..edf72e45b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { action, reaction, runInAction } from 'mobx'; import { basename } from 'path'; import { DateField } from '../../fields/DateField'; -import { Doc, DocListCast, Field, LinkedTo, Opt, updateCachedAcls } from '../../fields/Doc'; +import { Doc, DocListCast, Field, LinkedTo, Opt, StrListCast, updateCachedAcls } from '../../fields/Doc'; import { Initializing } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { HtmlField } from '../../fields/HtmlField'; @@ -1253,6 +1253,40 @@ export namespace Docs { } export namespace DocUtils { + function matchFieldValue(doc: Doc, key: string, value: any): boolean { + const hasFunctionFilter = Utils.HasFunctionFilter(value); + if (hasFunctionFilter) { + return hasFunctionFilter(StrCast(doc[key])); + } + if (key === LinkedTo) { + // links are not a field value, so handled here. value is an expression of form ([field=]idToDoc("...")) + const allLinks = LinkManager.Instance.getAllRelatedLinks(doc); + const matchLink = (value: string, anchor: Doc) => { + const linkedToExp = value?.split('='); + if (linkedToExp.length === 1) return Field.toScriptString(anchor) === value; + return Field.toScriptString(DocCast(anchor[linkedToExp[0]])) === linkedToExp[1]; + }; + // prettier-ignore + return (value === Doc.FilterNone && !allLinks.length) || + (value === Doc.FilterAny && !!allLinks.length) || + (allLinks.some(link => matchLink(value,DocCast(link.link_anchor_1)) || + matchLink(value,DocCast(link.link_anchor_2)) )); + } + if (typeof value === 'string') { + value = value.replace(`,${Utils.noRecursionHack}`, ''); + } + const fieldVal = doc[key]; + // prettier-ignore + if ((value === Doc.FilterAny && fieldVal !== undefined) || + (value === Doc.FilterNone && fieldVal === undefined)) { + return true; + } + const vals = StrListCast(fieldVal); // list typing is very imperfect. casting to a string list doesn't mean that the entries will actually be strings + if (vals.length) { + return vals.some(v => typeof v === 'string' && v.includes(value)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring + } + return Field.toString(fieldVal as Field).includes(value); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring + } /** * @param docs * @param childFilters @@ -1303,8 +1337,8 @@ export namespace DocUtils { const xs = Object.keys(facet).filter(value => facet[value] === 'x'); if (!unsets.length && !exists.length && !xs.length && !checks.length && !matches.length) return true; - const failsNotEqualFacets = !xs.length ? false : xs.some(value => Doc.matchFieldValue(d, facetKey, value)); - const satisfiesCheckFacets = !checks.length ? true : checks.some(value => Doc.matchFieldValue(d, facetKey, value)); + const failsNotEqualFacets = !xs.length ? false : xs.some(value => matchFieldValue(d, facetKey, value)); + const satisfiesCheckFacets = !checks.length ? true : checks.some(value => matchFieldValue(d, facetKey, value)); const satisfiesExistsFacets = !exists.length ? true : exists.some(value => (facetKey !== LinkedTo ? d[facetKey] !== undefined : LinkManager.Instance.getAllRelatedLinks(d).length)); const satisfiesUnsetsFacets = !unsets.length ? true : unsets.some(value => d[facetKey] === undefined); const satisfiesMatchFacets = !matches.length @@ -1802,7 +1836,7 @@ export namespace DocUtils { proto.data_duration = result.duration; } if (overwriteDoc) { - Doc.removeCurrentlyLoading(overwriteDoc); + LoadingBox.removeCurrentlyLoading(overwriteDoc); } generatedDocuments.push(doc); } @@ -1844,7 +1878,7 @@ export namespace DocUtils { if (overwriteDoc) { overwriteDoc.isLoading = false; overwriteDoc.loadingError = (result as any).message; - Doc.removeCurrentlyLoading(overwriteDoc); + LoadingBox.removeCurrentlyLoading(overwriteDoc); } } else name && processFileupload(generatedDocuments, name, type, result, options, overwriteDoc); }); @@ -1885,7 +1919,7 @@ export namespace DocUtils { if ((result as any).message) { if (overwriteDoc) { overwriteDoc.loadingError = (result as any).message; - Doc.removeCurrentlyLoading(overwriteDoc); + LoadingBox.removeCurrentlyLoading(overwriteDoc); } } else name && type && processFileupload(generatedDocuments, name, type, result, options, overwriteDoc); }); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index ba3c26b42..cd19daee5 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -110,7 +110,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: "docCast(documentView?.props.docViewPath().lastElement()?.rootDoc.target).then((target) => target && (target.proto.data = new List([self])))"}, + { opts: { title: "Open In Target", targetScriptKey: "onChildClick"}, script: "docCastAsync(documentView?.props.docViewPath().lastElement()?.rootDoc.target).then((target) => target && (target.proto.data = new List([self])))"}, { opts: { title: "Open Detail On Right", targetScriptKey: "onChildDoubleClick"}, script: `openDoc(self.doubleClickView.${OpenWhere.addRight})`}]; const reqdClickList = reqdTempOpts.map(opts => { const allOpts = {...reqdClickOpts, ...opts.opts}; @@ -793,11 +793,6 @@ export class CurrentUserUtils { return DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), dockBtnsReqdOpts, btns); } - /// collection of documents rendered in the overlay layer above all tabs and other UI - static setupOverlays(doc: Doc, field = "myOverlayDocs") { - return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.FreeformDocument([], opts), { title: "overlay documents", backgroundColor: "#aca3a6", isSystem: true }); - } - static setupPublished(doc:Doc, field = "myPublishedDocs") { return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), { title: "published docs", backgroundColor: "#aca3a6", isSystem: true }); } @@ -901,7 +896,6 @@ export class CurrentUserUtils { this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon this.setupActiveMobileMenu(doc); // sets up the current mobile menu for Dash Mobile - this.setupOverlays(doc); // sets up the overlay panel where documents and other widgets can be added to float over the rest of the dashboard this.setupPublished(doc); // sets up the list doc of all docs that have been published (meaning that they can be auto-linked by typing their title into another text box) this.setupContextMenuButtons(doc); // set up the row of buttons at the top of the dashboard that change depending on what is selected this.setupTopbarButtons(doc); diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 7cc8afaa6..f05c41fa7 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -13,6 +13,7 @@ import { LightboxView } from '../views/LightboxView'; import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView'; import { KeyValueBox } from '../views/nodes/KeyValueBox'; import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox'; +import { LoadingBox } from '../views/nodes/LoadingBox'; import { PresBox } from '../views/nodes/trails'; import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; @@ -40,8 +41,8 @@ export class DocumentManager { //private constructor so no other class can create a nodemanager private constructor() { - if (!Doc.CurrentlyLoading) Doc.CurrentlyLoading = []; - observe(Doc.CurrentlyLoading, change => { + if (!LoadingBox.CurrentlyLoading) LoadingBox.CurrentlyLoading = []; + observe(LoadingBox.CurrentlyLoading, change => { // watch CurrentlyLoading-- when something is loaded, it's removed from the list and we have to update its icon if it were iconified since LoadingBox icons are different than the media they become switch (change.type as any) { case 'update': diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index ba53a760f..608184596 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -197,14 +197,32 @@ export class LinkManager { } // finds the opposite anchor of a given anchor in a link - //TODO This should probably return undefined if there isn't an opposite anchor - //TODO This should also await the return value of the anchor so we don't filter out promises public static getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc | undefined { - const a1 = Cast(linkDoc.link_anchor_1, Doc, null); - const a2 = Cast(linkDoc.link_anchor_2, Doc, null); - if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a1?.annotationOn, a1))) return a2; - if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a2?.annotationOn, a2))) return a1; - if (Doc.AreProtosEqual(anchor, linkDoc)) return linkDoc; + const id = LinkManager.anchorIndex(linkDoc, anchor); + const a1 = DocCast(linkDoc.link_anchor_1); + const a2 = DocCast(linkDoc.link_anchor_2); + return id === '1' ? a2 : id === '2' ? a1 : id === '0' ? linkDoc : undefined; + // if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a1?.annotationOn, a1))) return a2; + // if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a2?.annotationOn, a2))) return a1; + // if (Doc.AreProtosEqual(anchor, linkDoc)) return linkDoc; + } + public static anchorIndex(linkDoc: Doc, anchor: Doc) { + const a1 = DocCast(linkDoc.link_anchor_1); + const a2 = DocCast(linkDoc.link_anchor_2); + if (linkDoc.link_matchEmbeddings) { + return [a2, a2.annotationOn].includes(anchor) ? '2' : '1'; + } + if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a1?.annotationOn, a1))) return '1'; + if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a2?.annotationOn, a2))) return '2'; + if (Doc.AreProtosEqual(anchor, linkDoc)) return '0'; + + // const a1 = DocCast(linkDoc.link_anchor_1); + // const a2 = DocCast(linkDoc.link_anchor_2); + // if (linkDoc.link_matchEmbeddings) { + // return [a2, a2.annotationOn].includes(anchor) ? '2' : '1'; + // } + // if (Doc.AreProtosEqual(a2, anchor) || Doc.AreProtosEqual(a2.annotationOn as Doc, anchor)) return '2'; + // return Doc.AreProtosEqual(a1, anchor) || Doc.AreProtosEqual(a1.annotationOn as Doc, anchor) ? '1' : '2'; } } diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index f75322905..e58c2687c 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -12,7 +12,9 @@ import { addStyleSheet, addStyleSheetRule, Utils } from '../../Utils'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; import { Networking } from '../Network'; +import { GestureOverlay } from '../views/GestureOverlay'; import { MainViewModal } from '../views/MainViewModal'; +import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox'; import { GroupManager } from './GroupManager'; import './SettingsManager.scss'; import { undoBatch } from './UndoManager'; @@ -228,8 +230,8 @@ export class SettingsManager extends React.Component<{}> { formLabel={'Show Button Labels'} formLabelPlacement={'right'} toggleType={ToggleType.SWITCH} - onClick={e => Doc.SetShowIconLabels(!Doc.GetShowIconLabels())} - toggleStatus={Doc.GetShowIconLabels()} + onClick={e => (FontIconBox.ShowIconLabels = !FontIconBox.ShowIconLabels)} + toggleStatus={FontIconBox.ShowIconLabels} size={Size.XSMALL} color={SettingsManager.userColor} /> @@ -237,8 +239,8 @@ export class SettingsManager extends React.Component<{}> { formLabel={'Recognize Ink Gestures'} formLabelPlacement={'right'} toggleType={ToggleType.SWITCH} - onClick={e => Doc.SetRecognizeGestures(!Doc.GetRecognizeGestures())} - toggleStatus={Doc.GetRecognizeGestures()} + onClick={e => (GestureOverlay.RecognizeGestures = !GestureOverlay.RecognizeGestures)} + toggleStatus={GestureOverlay.RecognizeGestures} size={Size.XSMALL} color={SettingsManager.userColor} /> diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 014a6358f..9e2ed7822 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -12,6 +12,7 @@ import { PrefetchProxy } from '../../fields/Proxy'; import { listSpec } from '../../fields/Schema'; import { ScriptField } from '../../fields/ScriptField'; import { Cast, ImageCast, StrCast } from '../../fields/Types'; +import { normalizeEmail } from '../../fields/util'; import { DocServer } from '../DocServer'; import { Docs, DocumentOptions, DocUtils } from '../documents/Documents'; import { HistoryUtil } from '../util/History'; @@ -149,7 +150,7 @@ export class DashboardView extends React.Component { : this.getDashboards(this.selectedDashboardGroup).map(dashboard => { const href = ImageCast(dashboard.thumb)?.url?.href; const shared = Object.keys(dashboard[DocAcl]) - .filter(key => key !== `acl-${Doc.CurrentUserEmailNormalized}` && !['acl-Me', 'acl-Guest'].includes(key)) + .filter(key => key !== `acl-${normalizeEmail(Doc.CurrentUserEmail)}` && !['acl-Me', 'acl-Guest'].includes(key)) .some(key => dashboard[DocAcl][key] !== AclPrivate); return (
(); + dashboardDoc.myPublishedDocs = new List(); Doc.AddDocToList(Doc.MyDashboards, 'data', dashboardDoc); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 5a145e94a..6c55895ef 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -7,7 +7,7 @@ import { observer } from 'mobx-react'; import { FaUndo } from 'react-icons/fa'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc'; -import { AclAdmin, AclAugment, AclEdit, DocData, Height, Width } 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'; @@ -126,10 +126,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if (titleFieldKey === 'title') { d.dataDoc.title_custom = !this._accumulatedTitle.startsWith('-'); if (StrCast(d.rootDoc.title).startsWith('@') && !this._accumulatedTitle.startsWith('@')) { - Doc.RemoveDocFromList(Doc.MyPublishedDocs, undefined, d.rootDoc); + Doc.RemFromMyPublished(d.rootDoc); } if (!StrCast(d.rootDoc.title).startsWith('@') && this._accumulatedTitle.startsWith('@')) { - Doc.AddDocToList(Doc.MyPublishedDocs, undefined, d.rootDoc); + Doc.AddToMyPublished(d.rootDoc); } } //@ts-ignore @@ -295,8 +295,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P // open centered in a new workspace with Shift Key const embedding = Doc.MakeEmbedding(selectedDocs[0].rootDoc); embedding.embedContainer = undefined; - embedding.x = -embedding[Width]() / 2; - embedding.y = -embedding[Height]() / 2; + embedding.x = -NumCast(embedding._width) / 2; + embedding.y = -NumCast(embedding._height) / 2; CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([embedding], { title: 'Tab for ' + embedding.title }), OpenWhereMod.right); } else if (e.altKey) { // open same document in new tab diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 35d6d73e4..caabdb09b 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -5,7 +5,7 @@ import { observer } from 'mobx-react'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../Utils'; import { Doc, Opt } from '../../fields/Doc'; import { InkData, InkTool } from '../../fields/InkField'; -import { NumCast } from '../../fields/Types'; +import { BoolCast, NumCast } from '../../fields/Types'; import MobileInkOverlay from '../../mobile/MobileInkOverlay'; import { GestureUtils } from '../../pen-gestures/GestureUtils'; import { MobileInkOverlayContent } from '../../server/Message'; @@ -44,6 +44,13 @@ export class GestureOverlay extends Touchable { static Instance: GestureOverlay; static Instances: GestureOverlay[] = []; + public static set RecognizeGestures(active) { + Doc.UserDoc().recognizeGestures = active; + } + public static get RecognizeGestures() { + return BoolCast(Doc.UserDoc().recognizeGestures); + } + @observable public InkShape: Opt; @observable public SavedColor?: string; @observable public SavedWidth?: number; @@ -590,7 +597,7 @@ export class GestureOverlay extends Touchable { // need to decide when to turn gestures back on const result = points.length > 2 && GestureUtils.GestureRecognizer.Recognize(new Array(points)); let actionPerformed = false; - if (Doc.UserDoc().recognizeGestures && result && result.Score > 0.7) { + if (GestureOverlay.RecognizeGestures && result && result.Score > 0.7) { switch (result.Name) { case GestureUtils.Gestures.Line: case GestureUtils.Gestures.Triangle: diff --git a/src/client/views/InkTranscription.tsx b/src/client/views/InkTranscription.tsx index 258bfad66..17136a737 100644 --- a/src/client/views/InkTranscription.tsx +++ b/src/client/views/InkTranscription.tsx @@ -2,7 +2,6 @@ import * as iink from 'iink-js'; import { action, observable } from 'mobx'; import * as React from 'react'; import { Doc, DocListCast } from '../../fields/Doc'; -import { Height, Width } from '../../fields/DocSymbols'; import { InkData, InkField, InkTool } from '../../fields/InkField'; import { Cast, DateCast, NumCast } from '../../fields/Types'; import { aggregateBounds } from '../../Utils'; @@ -287,8 +286,8 @@ export class InkTranscription extends React.Component { action(d => { const x = NumCast(d.x); const y = NumCast(d.y); - const width = d[Width](); - const height = d[Height](); + const width = NumCast(d._width); + const height = NumCast(d._height); bounds.push({ x, y, width, height }); }) ); @@ -327,8 +326,8 @@ export class InkTranscription extends React.Component { // Gets a collection based on the selected nodes using a marquee view ref const newCollection = marqViewRef?.getCollection(selected, undefined, true); if (newCollection) { - newCollection.height = newCollection[Height](); - newCollection.width = newCollection[Width](); + newCollection.width = NumCast(newCollection._width); + newCollection.height = NumCast(newCollection._height); // if the grouping we are creating is an individual word if (word) { newCollection.title = word; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index d26c7761e..513061e79 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -24,7 +24,6 @@ import React = require('react'); import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../fields/Doc'; -import { Height, Width } from '../../fields/DocSymbols'; import { InkData, InkField } from '../../fields/InkField'; import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; @@ -382,10 +381,10 @@ export class InkingStroke extends ViewBoxBaseComponent() { const fillColor = this.fillColor; // bcz: Hack!! Not really sure why, but having fractional values for width/height of mask ink strokes causes the dragging clone (see DragManager) to be offset from where it should be. - if (isInkMask && (this.layoutDoc[Width]() !== Math.round(this.layoutDoc[Width]()) || this.layoutDoc[Height]() !== Math.round(this.layoutDoc[Height]()))) { + if (isInkMask && (this.layoutDoc._width !== Math.round(NumCast(this.layoutDoc._width)) || this.layoutDoc._height !== Math.round(NumCast(this.layoutDoc._height)))) { setTimeout(() => { - this.layoutDoc._width = Math.round(NumCast(this.layoutDoc[Width]())); - this.layoutDoc._height = Math.round(NumCast(this.layoutDoc[Height]())); + this.layoutDoc._width = Math.round(NumCast(this.layoutDoc._width)); + this.layoutDoc._height = Math.round(NumCast(this.layoutDoc._height)); }); } const highlight = !this.controlUndo && this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Highlighting); @@ -481,7 +480,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { style={{ color: StrCast(this.layoutDoc.textColor, 'black'), pointerEvents: this.props.isDocumentActive?.() ? 'all' : undefined, - width: this.layoutDoc[Width](), + width: NumCast(this.layoutDoc._width), transform: `scale(${this.props.NativeDimScaling?.() || 1})`, transformOrigin: 'top left', //top: (this.props.PanelHeight() - (lineHeightGuess * fsize + 20) * (this.props.NativeDimScaling?.() || 1)) / 2, diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index da5e4f966..ccb46d7ec 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -261,6 +261,8 @@ export class MainView extends React.Component { fa.faWindowRestore, fa.faFolder, fa.faFolderOpen, + fa.faFolderPlus, + fa.faFolderClosed, fa.faMapPin, fa.faMapMarker, fa.faFingerprint, @@ -450,6 +452,7 @@ export class MainView extends React.Component { fa.faSortUp, fa.faSortDown, fa.faTable, + fa.faTableCells, fa.faTableColumns, fa.faTh, fa.faThList, @@ -475,11 +478,11 @@ export class MainView extends React.Component { fa.faBookmark, fa.faList, fa.faListOl, - fa.faFolderPlus, fa.faLightbulb, fa.faBookOpen, fa.faMapMarkerAlt, fa.faSearchPlus, + fa.faSolarPanel, fa.faVolumeUp, fa.faVolumeDown, fa.faSquareRootAlt, diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index c174befc0..c7b59a8e2 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -3,7 +3,7 @@ import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; import ReactLoading from 'react-loading'; -import { Doc, DocListCast } from '../../fields/Doc'; +import { Doc } from '../../fields/Doc'; import { Height, Width } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { NumCast } from '../../fields/Types'; @@ -119,7 +119,7 @@ export class OverlayView extends React.Component { new _global.ResizeObserver( action((entries: any) => { for (const entry of entries) { - DocListCast(Doc.MyOverlayDocs?.data).forEach(doc => { + Doc.MyOverlayDocs.forEach(doc => { if (NumCast(doc.overlayX) > entry.contentRect.width - 10) { doc.overlayX = entry.contentRect.width - 10; } @@ -184,70 +184,68 @@ export class OverlayView extends React.Component { ); @computed get overlayDocs() { - return DocListCast(Doc.MyOverlayDocs?.data) - .filter(d => !LightboxView.LightboxDoc || d.type === DocumentType.PRES) - .map(d => { - let offsetx = 0, - offsety = 0; - const dref = React.createRef(); - const onPointerMove = action((e: PointerEvent, down: number[]) => { - if (e.cancelBubble) return false; // if the overlay doc processed the move event (e.g., to pan its contents), then the event should be marked as canceled since propagation can't be stopped - if (e.buttons === 1) { - d.overlayX = e.clientX + offsetx; - d.overlayY = e.clientY + offsety; - } - if (e.metaKey) { - const dragData = new DragManager.DocumentDragData([d]); - dragData.offset = [-offsetx, -offsety]; - dragData.dropAction = 'move'; - dragData.removeDocument = this.removeOverlayDoc; - dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { - return dragData.removeDocument!(doc) ? addDocument(doc) : false; - }; - DragManager.StartDocumentDrag([dref.current!], dragData, down[0], down[1]); - return true; - } - return false; - }); - - const onPointerDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, onPointerMove, emptyFunction, emptyFunction, false); - offsetx = NumCast(d.overlayX) - e.clientX; - offsety = NumCast(d.overlayY) - e.clientY; - }; - return ( -
- -
- ); + return Doc.MyOverlayDocs.filter(d => !LightboxView.LightboxDoc || d.type === DocumentType.PRES).map(d => { + let offsetx = 0, + offsety = 0; + const dref = React.createRef(); + const onPointerMove = action((e: PointerEvent, down: number[]) => { + if (e.cancelBubble) return false; // if the overlay doc processed the move event (e.g., to pan its contents), then the event should be marked as canceled since propagation can't be stopped + if (e.buttons === 1) { + d.overlayX = e.clientX + offsetx; + d.overlayY = e.clientY + offsety; + } + if (e.metaKey) { + const dragData = new DragManager.DocumentDragData([d]); + dragData.offset = [-offsetx, -offsety]; + dragData.dropAction = 'move'; + dragData.removeDocument = this.removeOverlayDoc; + dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { + return dragData.removeDocument!(doc) ? addDocument(doc) : false; + }; + DragManager.StartDocumentDrag([dref.current!], dragData, down[0], down[1]); + return true; + } + return false; }); + + const onPointerDown = (e: React.PointerEvent) => { + setupMoveUpEvents(this, e, onPointerMove, emptyFunction, emptyFunction, false); + offsetx = NumCast(d.overlayX) - e.clientX; + offsety = NumCast(d.overlayY) - e.clientY; + }; + return ( +
+ +
+ ); + }); } public static ShowSpinner() { diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index d37971517..49bf982ec 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -5,12 +5,12 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Checkbox, Tooltip } from '@material-ui/core'; import { Colors, EditableText, IconButton, NumberInput, Size, Slider, Type } from 'browndash-components'; import { concat } from 'lodash'; -import { action, computed, IReactionDisposer, observable, reaction, trace } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { ColorState, SketchPicker } from 'react-color'; import * as Icons from 'react-icons/bs'; //{BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs" import { Doc, DocListCast, Field, FieldResult, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast } from '../../fields/Doc'; -import { AclAdmin, DocAcl, DocData, Height, Width } from '../../fields/DocSymbols'; +import { AclAdmin, DocAcl, DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { InkField } from '../../fields/InkField'; import { List } from '../../fields/List'; @@ -123,16 +123,16 @@ export class PropertiesView extends React.Component { return [CollectionViewType.Stacking, CollectionViewType.NoteTaking].includes(this.selectedDoc?.type_collection as any); } - rtfWidth = () => (!this.selectedDoc ? 0 : Math.min(this.selectedDoc?.[Width](), this.props.width - 20)); - rtfHeight = () => (!this.selectedDoc ? 0 : this.rtfWidth() <= this.selectedDoc?.[Width]() ? Math.min(this.selectedDoc?.[Height](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT); + rtfWidth = () => (!this.selectedDoc ? 0 : Math.min(NumCast(this.selectedDoc?._width), this.props.width - 20)); + rtfHeight = () => (!this.selectedDoc ? 0 : this.rtfWidth() <= NumCast(this.selectedDoc?._width) ? Math.min(NumCast(this.selectedDoc?._height), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT); @action docWidth = () => { if (this.selectedDoc) { const layoutDoc = this.selectedDoc; const aspect = Doc.NativeAspect(layoutDoc, undefined, !layoutDoc._layout_fitWidth); - if (aspect) return Math.min(layoutDoc[Width](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.width - 20)); - return Doc.NativeWidth(layoutDoc) ? Math.min(layoutDoc[Width](), this.props.width - 20) : this.props.width - 20; + if (aspect) return Math.min(NumCast(layoutDoc._width), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.width - 20)); + return Doc.NativeWidth(layoutDoc) ? Math.min(NumCast(layoutDoc._width), this.props.width - 20) : this.props.width - 20; } return 0; }; diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 72d7cd1c5..2162d8878 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -105,7 +105,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt; } - return Doc.toIcon(doc, isEmpty ? undefined : isOpen); + return Doc.toIcon(doc, isOpen); case StyleProp.TreeViewSortings: const allSorts: { [key: string]: { color: string; icon: JSX.Element | string } | undefined } = {}; allSorts[TreeSort.AlphaDown] = { color: Colors.MEDIUM_BLUE, icon: }; @@ -117,7 +117,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt dv.SELECTED).length; - const highlightIndex = Doc.isBrushedHighlightedDegree(doc) || (selected ? Doc.DocBrushStatus.selfBrushed : 0); + const highlightIndex = Doc.GetBrushHighlightStatus(doc) || (selected ? Doc.DocBrushStatus.selfBrushed : 0); const highlightColor = ['transparent', 'rgb(68, 118, 247)', selected ? "black" : 'rgb(68, 118, 247)', 'orange', 'lightBlue'][highlightIndex]; const highlightStyle = ['solid', 'dashed', 'solid', 'solid', 'solid'][highlightIndex]; if (highlightIndex) { diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index afeef5a8f..bb6d94590 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -1,9 +1,9 @@ import React = require('react'); import { CursorProperty } from 'csstype'; -import { action, computed, IReactionDisposer, observable, reaction, trace } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Field, Opt } from '../../../fields/Doc'; -import { DocData, Height, Width } from '../../../fields/DocSymbols'; +import { DocData } from '../../../fields/DocSymbols'; import { Copy, Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; @@ -289,7 +289,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { const existingHeader = this.colHeaderData.find(sh => sh.heading === heading); const existingWidth = existingHeader?.width ? existingHeader.width : 0; const maxWidth = existingWidth > 0 ? existingWidth * this.availableWidth : this.maxColWidth; - const width = d.layout_fitWidth ? maxWidth : d[Width](); + const width = d.layout_fitWidth ? maxWidth : NumCast(d._width); return Math.min(maxWidth - CollectionNoteTakingViewColumn.ColumnMargin, width < maxWidth ? width : maxWidth); } @@ -299,8 +299,8 @@ export class CollectionNoteTakingView extends CollectionSubView() { const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.()); const childDataDoc = !d.isTemplateDoc && !d.isTemplateForField ? undefined : this.props.DataDoc; const maxHeight = (lim => (lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1)); - const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[Width]() : 0); - const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[Height]() : 0); + const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? NumCast(d._width) : 0); + const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? NumCast(d._height) : 0); if (nw && nh) { const docWid = this.getDocWidth(d); return Math.min(maxHeight, (docWid * nh) / nw); diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 91701b213..abb12a8ab 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -1,7 +1,6 @@ import { action, computed, IReactionDisposer } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast } from '../../../fields/Doc'; -import { Height, Width } from '../../../fields/DocSymbols'; import { ScriptField } from '../../../fields/ScriptField'; import { NumCast, StrCast } from '../../../fields/Types'; import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils'; @@ -79,12 +78,12 @@ export class CollectionPileView extends CollectionSubView() { toggleStarburst = action(() => { this.layoutDoc._freeform_scale = undefined; if (this.layoutEngine() === computeStarburstLayout.name) { - if (this.rootDoc[Width]() !== NumCast(this.rootDoc._starburstDiameter, 500)) { - this.rootDoc._starburstDiameter = this.rootDoc[Width](); + if (NumCast(this.rootDoc._width) !== NumCast(this.rootDoc._starburstDiameter, 500)) { + this.rootDoc._starburstDiameter = NumCast(this.rootDoc._width); } const defaultSize = 110; - this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[Width]() / 2 - NumCast(this.layoutDoc._freeform_pileWidth, defaultSize) / 2; - this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[Height]() / 2 - NumCast(this.layoutDoc._freeform_pileHeight, defaultSize) / 2; + this.rootDoc.x = NumCast(this.rootDoc.x) + NumCast(this.layoutDoc._width) / 2 - NumCast(this.layoutDoc._freeform_pileWidth, defaultSize) / 2; + this.rootDoc.y = NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) / 2 - NumCast(this.layoutDoc._freeform_pileHeight, defaultSize) / 2; this.layoutDoc._width = NumCast(this.layoutDoc._freeform_pileWidth, defaultSize); this.layoutDoc._height = NumCast(this.layoutDoc._freeform_pileHeight, defaultSize); DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false); @@ -93,10 +92,10 @@ export class CollectionPileView extends CollectionSubView() { this.props.Document._freeform_pileEngine = computePassLayout.name; } else { const defaultSize = NumCast(this.rootDoc._starburstDiameter, 400); - this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[Width]() / 2 - defaultSize / 2; - this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[Height]() / 2 - defaultSize / 2; - this.layoutDoc._freeform_pileWidth = this.layoutDoc[Width](); - this.layoutDoc._freeform_pileHeight = this.layoutDoc[Height](); + this.rootDoc.x = NumCast(this.rootDoc.x) + NumCast(this.layoutDoc._width) / 2 - defaultSize / 2; + this.rootDoc.y = NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) / 2 - defaultSize / 2; + this.layoutDoc._freeform_pileWidth = NumCast(this.layoutDoc._width); + this.layoutDoc._freeform_pileHeight = NumCast(this.layoutDoc._height); this.layoutDoc._freeform_panX = this.layoutDoc._freeform_panY = 0; this.layoutDoc._width = this.layoutDoc._height = defaultSize; this.layoutDoc.background; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0b29e7286..e5695f63b 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -4,17 +4,18 @@ import { CursorProperty } from 'csstype'; import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Opt } from '../../../fields/Doc'; -import { DocData, Height, Width } from '../../../fields/DocSymbols'; +import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnNone, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils'; +import { emptyFunction, returnEmptyDoclist, returnFalse, returnNone, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { CollectionViewType } from '../../documents/DocumentTypes'; import { DragManager, dropActionType } from '../../util/DragManager'; +import { SettingsManager } from '../../util/SettingsManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from '../../util/UndoManager'; @@ -31,7 +32,6 @@ import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow'; import './CollectionStackingView.scss'; import { CollectionStackingViewFieldColumn } from './CollectionStackingViewFieldColumn'; import { CollectionSubView } from './CollectionSubView'; -import { SettingsManager } from '../../util/SettingsManager'; const _global = (window /* browser */ || global) /* node */ as any; export type collectionStackingViewProps = { @@ -378,7 +378,7 @@ export class CollectionStackingView extends CollectionSubView (lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1)); - const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[Width]() : 0); - const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[Height]() : 0); + const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? NumCast(d._width) : 0); + const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? NumCast(d._height) : 0); if (nw && nh) { const colWid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index e9192ebbe..7c8b2f195 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -25,6 +25,7 @@ import { DocComponent } from '../DocComponent'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { CollectionView, CollectionViewProps } from './CollectionView'; import React = require('react'); +import { LoadingBox } from '../nodes/LoadingBox'; export interface SubCollectionViewProps extends CollectionViewProps { isAnyChildContentActive: () => boolean; @@ -450,13 +451,13 @@ export function CollectionSubView(moreProps?: X) { if (typeof files === 'string') { const loading = Docs.Create.LoadingDocument(files, options); generatedDocuments.push(loading); - Doc.addCurrentlyLoading(loading); + LoadingBox.addCurrentlyLoading(loading); DocUtils.uploadYoutubeVideoLoading(files, {}, loading); } else { generatedDocuments.push( ...files.map(file => { const loading = Docs.Create.LoadingDocument(file, options); - Doc.addCurrentlyLoading(loading); + LoadingBox.addCurrentlyLoading(loading); DocUtils.uploadFileToDoc(file, {}, loading); return loading; }) diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index e408c193a..761192a22 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,7 +1,7 @@ import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc'; -import { DocData, Height, Width } from '../../../fields/DocSymbols'; +import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; @@ -371,8 +371,8 @@ export class CollectionTreeView extends CollectionSubView NumCast(this.doc._xMargin); marginTop = () => NumCast(this.doc._yMargin); marginBot = () => NumCast(this.doc._yMargin); - documentTitleWidth = () => Math.min(this.layoutDoc?.[Width](), this.panelWidth()); - documentTitleHeight = () => (this.layoutDoc?.[Height]() || 0) - NumCast(this.layoutDoc.layout_autoHeightMargins); + documentTitleWidth = () => Math.min(NumCast(this.layoutDoc?._width), this.panelWidth()); + documentTitleHeight = () => NumCast(this.layoutDoc?._height) - NumCast(this.layoutDoc.layout_autoHeightMargins); truncateTitleWidth = () => this.treeViewtruncateTitleWidth; onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick); panelWidth = () => Math.max(0, this.props.PanelWidth() - 2 * this.marginX() * (this.props.NativeDimScaling?.() || 1)); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 41f3b2603..180578a36 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -6,7 +6,7 @@ import { action, computed, IReactionDisposer, observable, ObservableSet, reactio import { observer } from 'mobx-react'; import * as ReactDOM from 'react-dom/client'; import { Doc, Opt } from '../../../fields/Doc'; -import { DocData, Height, Width } from '../../../fields/DocSymbols'; +import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { FieldId } from '../../../fields/RefField'; @@ -539,7 +539,7 @@ export class TabMinimapView extends React.Component { default: return 'gray'; } })(doc.type as DocumentType); - return !background ? undefined :
; + return !background ? undefined :
; } } }; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 193c70add..dbce45fda 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -1,9 +1,10 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { IconButton, Size } from 'browndash-components'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast, Field, FieldResult, Opt, StrListCast } from '../../../fields/Doc'; -import { DocData, Height, Width } from '../../../fields/DocSymbols'; +import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { RichTextField } from '../../../fields/RichTextField'; @@ -19,6 +20,7 @@ import { DragManager, dropActionType } from '../../util/DragManager'; import { LinkManager } from '../../util/LinkManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SelectionManager } from '../../util/SelectionManager'; +import { SettingsManager } from '../../util/SettingsManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { undoable, undoBatch, UndoManager } from '../../util/UndoManager'; @@ -32,11 +34,9 @@ import { KeyValueBox } from '../nodes/KeyValueBox'; import { StyleProp } from '../StyleProvider'; import { CollectionTreeView, TreeViewType } from './CollectionTreeView'; import { CollectionView } from './CollectionView'; +import { TreeSort } from './TreeSort'; import './TreeView.scss'; import React = require('react'); -import { IconButton, Size } from 'browndash-components'; -import { TreeSort } from './TreeSort'; -import { SettingsManager } from '../../util/SettingsManager'; export interface TreeViewProps { treeView: CollectionTreeView; @@ -455,7 +455,7 @@ export class TreeView extends React.Component { embeddedPanelHeight = () => { const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc; return Math.min( - layoutDoc[Height](), + NumCast(layoutDoc._height), this.MAX_EMBED_HEIGHT, (() => { const aspect = Doc.NativeAspect(layoutDoc); @@ -464,7 +464,7 @@ export class TreeView extends React.Component { ? !Doc.NativeHeight(layoutDoc) ? NumCast(layoutDoc._height) : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.treeViewParent._height))) - : (this.embeddedPanelWidth() * layoutDoc[Height]()) / layoutDoc[Width](); + : (this.embeddedPanelWidth() * NumCast(layoutDoc._height)) / NumCast(layoutDoc._width); })() ); }; @@ -741,7 +741,7 @@ export class TreeView extends React.Component {
{ case StyleProp.Highlighting: if (this.props.treeView.outlineMode) return undefined; case StyleProp.BoxShadow: return undefined; case StyleProp.DocContents: - const highlightIndex = this.props.treeView.outlineMode ? Doc.DocBrushStatus.unbrushed : Doc.isBrushedHighlightedDegree(doc); + const highlightIndex = this.props.treeView.outlineMode ? Doc.DocBrushStatus.unbrushed : Doc.GetBrushHighlightStatus(doc); const highlightColor = ['transparent', 'rgb(68, 118, 247)', 'rgb(68, 118, 247)', 'orange', 'lightBlue'][highlightIndex]; return treeView.outlineMode ? null : (
{ const childLayout = Doc.Layout(pair.layout); const rowHeight = () => { const aspect = Doc.NativeAspect(childLayout); - return aspect ? Math.min(childLayout[Width](), rowWidth()) / aspect : childLayout[Height](); + return aspect ? Math.min(NumCast(childLayout._width), rowWidth()) / aspect : NumCast(childLayout._height); }; return ( , pivotDoc: Doc docMap.set(layout[Id], { x: NumCast(layout.x), y: NumCast(layout.y), - width: layout[Width](), - height: layout[Height](), + width: NumCast(layout._width), + height: NumCast(layout._height), pair: { layout, data }, transition: 'all .3s', replica: '', @@ -106,8 +105,8 @@ export function computeStarburstLayout(poolData: Map, pivotDoc const burstDiam = [NumCast(pivotDoc._width), NumCast(pivotDoc._height)]; const burstScale = NumCast(pivotDoc._starburstDocScale, 1); childPairs.forEach(({ layout, data }, i) => { - const aspect = layout[Height]() / layout[Width](); - const docSize = Math.min(Math.min(400, layout[Width]()), Math.min(400, layout[Width]()) / aspect) * burstScale; + const aspect = NumCast(layout._height) / NumCast(layout._width); + const docSize = Math.min(Math.min(400, NumCast(layout._width)), Math.min(400, NumCast(layout._width)) / aspect) * burstScale; const deg = (i / childPairs.length) * Math.PI * 2; docMap.set(layout[Id], { x: Math.min(burstDiam[0] / 2 - docSize, Math.max(-burstDiam[0] / 2, (Math.cos(deg) * burstDiam[0]) / 2 - docSize / 2)), diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index da0f7c893..ee3dcca11 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -460,6 +460,19 @@ export class CollectionFreeFormView extends CollectionSubView (([x, y]) => super.onExternalDrop(e, { x, y }))(this.getTransform().transformPoint(e.pageX, e.pageY)); + static overlapping(doc1: Doc, doc2: Doc, clusterDistance: number) { + const doc2Layout = Doc.Layout(doc2); + const doc1Layout = Doc.Layout(doc1); + const x2 = NumCast(doc2.x) - clusterDistance; + const y2 = NumCast(doc2.y) - clusterDistance; + const w2 = NumCast(doc2Layout._width) + clusterDistance; + const h2 = NumCast(doc2Layout._height) + clusterDistance; + const x = NumCast(doc1.x) - clusterDistance; + const y = NumCast(doc1.y) - clusterDistance; + const w = NumCast(doc1Layout._width) + clusterDistance; + const h = NumCast(doc1Layout._height) + clusterDistance; + return doc1.z === doc2.z && intersectRect({ left: x, top: y, width: w, height: h }, { left: x2, top: y2, width: w2, height: h2 }); + } pickCluster(probe: number[]) { return this.childLayoutPairs .map(pair => pair.layout) @@ -519,7 +532,7 @@ export class CollectionFreeFormView extends CollectionSubView this._clusterSets.map((set, i) => set.map(member => { - if (docFirst.layout_cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(doc, member, this._clusterDistance)) { + if (docFirst.layout_cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && CollectionFreeFormView.overlapping(doc, member, this._clusterDistance)) { docFirst.layout_cluster = i; } }) @@ -560,7 +573,7 @@ export class CollectionFreeFormView extends CollectionSubView set.forEach(member => { - if (doc.layout_cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(doc, member, this._clusterDistance)) { + if (doc.layout_cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && CollectionFreeFormView.overlapping(doc, member, this._clusterDistance)) { doc.layout_cluster = i; } }) @@ -737,9 +750,9 @@ export class CollectionFreeFormView extends CollectionSubView { if (doc.type === 'ink') { const l = NumCast(doc.x); - const r = l + doc[Width](); + const r = l + NumCast(doc._width); const t = NumCast(doc.y); - const b = t + doc[Height](); + const b = t + NumCast(doc._height); const pass = !(this._inkToTextStartX! > r || end[0] < l || this._inkToTextStartY! > b || end[1] < t); return pass; } @@ -1217,7 +1230,7 @@ export class CollectionFreeFormView extends CollectionSubView { const layoutdoc = Doc.Layout(doc); const pt = xf.transformPoint(NumCast(doc.x), NumCast(doc.y)); - const pt2 = xf.transformPoint(NumCast(doc.x) + layoutdoc[Width](), NumCast(doc.y) + layoutdoc[Height]()); + const pt2 = xf.transformPoint(NumCast(doc.x) + NumCast(layoutdoc._width), NumCast(doc.y) + NumCast(layoutdoc._height)); const bounds = { left: pt[0], right: pt2[0], top: pt[1], bot: pt2[1], width: pt2[0] - pt[0], height: pt2[1] - pt[1] }; if (scale !== undefined) { @@ -1586,14 +1599,14 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.Document._isGroup && this.childDocs.length === this.childDocList?.length) { - const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[Width](), height: cd[Height]() })); + const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: NumCast(cd._width), height: NumCast(cd._height) })); return aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding)); } return undefined; }, cbounds => { if (cbounds) { - const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[Width]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[Height]() / 2]; + const c = [NumCast(this.layoutDoc.x) + NumCast(this.layoutDoc._width) / 2, NumCast(this.layoutDoc.y) + NumCast(this.layoutDoc._height) / 2]; const p = [NumCast(this.layoutDoc[this.panXFieldKey]), NumCast(this.layoutDoc[this.panYFieldKey])]; const pbounds = { x: cbounds.x - p[0] + c[0], @@ -1680,8 +1693,8 @@ export class CollectionFreeFormView extends CollectionSubView 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearView_IsOpen ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (doc[Width]() || this.dimension()) + tot + 4, 0) : 0), + () => 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearView_IsOpen ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (NumCast(doc._width) || this.dimension()) + tot + 4, 0) : 0), width => this.childDocs.length && (this.layoutDoc._width = width), { fireImmediately: true } ); diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 894afebfd..b529991cb 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -1,25 +1,24 @@ import { Colors } from 'browndash-components'; -import { runInAction, action } from 'mobx'; -import { aggregateBounds } from '../../../Utils'; +import { action, runInAction } from 'mobx'; import { Doc } from '../../../fields/Doc'; -import { Width, Height } from '../../../fields/DocSymbols'; import { InkTool } from '../../../fields/InkField'; -import { Cast, StrCast, NumCast, BoolCast } from '../../../fields/Types'; +import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; +import { aggregateBounds } from '../../../Utils'; +import { DocumentType } from '../../documents/DocumentTypes'; import { LinkManager } from '../../util/LinkManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SelectionManager } from '../../util/SelectionManager'; import { undoable, UndoManager } from '../../util/UndoManager'; +import { CollectionFreeFormView } from '../collections/collectionFreeForm'; import { GestureOverlay } from '../GestureOverlay'; +import { ActiveFillColor, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth, SetActiveIsInkMask } from '../InkingStroke'; import { InkTranscription } from '../InkTranscription'; -import { ActiveFillColor, SetActiveFillColor, ActiveIsInkMask, SetActiveIsInkMask, ActiveInkWidth, SetActiveInkWidth, ActiveInkColor, SetActiveInkColor, InkingStroke } from '../InkingStroke'; -import { CollectionFreeFormView } from '../collections/collectionFreeForm'; import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; -import { WebBox } from '../nodes/WebBox'; -import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; -import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentView } from '../nodes/DocumentView'; +import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; +import { WebBox } from '../nodes/WebBox'; ScriptingGlobals.add(function IsNoneSelected() { return SelectionManager.Views().length <= 0; @@ -239,8 +238,8 @@ export function createInkGroup(inksToGroup?: Doc[], isSubGroup?: boolean) { action(d => { const x = NumCast(d.x); const y = NumCast(d.y); - const width = d[Width](); - const height = d[Height](); + const width = NumCast(d._width); + const height = NumCast(d._height); bounds.push({ x, y, width, height }); }) ); @@ -277,8 +276,8 @@ export function createInkGroup(inksToGroup?: Doc[], isSubGroup?: boolean) { // TODO: nda - this is the code to actually get a new grouped collection const newCollection = marqViewRef?.getCollection(selected, undefined, true); if (newCollection) { - newCollection.height = newCollection[Height](); - newCollection.width = newCollection[Width](); + newCollection.height = NumCast(newCollection._height); + newCollection.width = NumCast(newCollection._width); } // nda - bug: when deleting a stroke before leaving writing mode, delete the stroke from unprocessed ink docs diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index 1b6fe5748..23ffd1080 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -3,10 +3,12 @@ import { action } from 'mobx'; import { observer } from 'mobx-react'; import { ColorState, SketchPicker } from 'react-color'; import { Doc } from '../../../fields/Doc'; -import { Height, Width } from '../../../fields/DocSymbols'; +import { Height } from '../../../fields/DocSymbols'; import { InkTool } from '../../../fields/InkField'; -import { StrCast } from '../../../fields/Types'; +import { NumCast, StrCast } from '../../../fields/Types'; +import { DashColor } from '../../../Utils'; import { DocumentType } from '../../documents/DocumentTypes'; +import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SelectionManager } from '../../util/SelectionManager'; import { undoBatch } from '../../util/UndoManager'; import { ViewBoxBaseComponent } from '../DocComponent'; @@ -14,8 +16,6 @@ import { ActiveInkColor, ActiveInkWidth, SetActiveInkColor, SetActiveInkWidth } import './ColorBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; import { RichTextMenu } from './formattedText/RichTextMenu'; -import { ScriptingGlobals } from '../../util/ScriptingGlobals'; -import { DashColor } from '../../../Utils'; @observer export class ColorBox extends ViewBoxBaseComponent() { @@ -51,7 +51,7 @@ export class ColorBox extends ViewBoxBaseComponent() { } render() { - const scaling = Math.min(this.layoutDoc.layout_fitWidth ? 10000 : this.props.PanelHeight() / this.rootDoc[Height](), this.props.PanelWidth() / this.rootDoc[Width]()); + const scaling = Math.min(this.layoutDoc.layout_fitWidth ? 10000 : this.props.PanelHeight() / NumCast(this.rootDoc._height), this.props.PanelWidth() / NumCast(this.rootDoc._width)); return (
() { } } - -ScriptingGlobals.add( - function interpColors(c1:string, c2:string, weight=0.5) { - return DashColor(c1).mix(DashColor(c2),weight) - } -) \ No newline at end of file +ScriptingGlobals.add(function interpColors(c1: string, c2: string, weight = 0.5) { + return DashColor(c1).mix(DashColor(c2), weight); +}); diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index b88389de6..147dfb182 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -219,7 +219,7 @@ export class TableBox extends React.Component { {this._tableDataIds - .filter(rowId => this.startID <= rowId && rowId <= this.endID) + .filter((rowId, i) => this.startID <= i && i <= this.endID) ?.map(rowId => ( string; getCenter?: (xf: Transform) => { X: number; Y: number }; - screenBounds?: () => { left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } }; + screenBounds?: () => Opt<{ left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } }>; ptToScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; ptFromScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; snapPt?: (pt: { X: number; Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number; Y: number }; distance: number }; @@ -1016,7 +1016,7 @@ export class DocumentViewInternal extends DocComponent
)); @@ -1520,7 +1520,7 @@ export class DocumentView extends React.Component { if (!this.docView?.ContentDiv || this.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { return undefined; } - if (this.docView._componentView?.screenBounds) { + if (this.docView._componentView?.screenBounds?.()) { return this.docView._componentView.screenBounds(); } const xf = this.docView.props @@ -1712,7 +1712,7 @@ ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuff ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc, linkSource: Doc) { const collectedLinks = DocListCast(Doc.GetProto(linkCollection).data); - let wid = linkSource[Width](); + let wid = NumCast(linkSource._width); let embedding: Doc | undefined; const links = LinkManager.Links(linkSource); links.forEach(link => { @@ -1723,7 +1723,7 @@ ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc, linkSour embedding.x = wid; embedding.y = 0; embedding._lockedPosition = false; - wid += otherdoc[Width](); + wid += NumCast(otherdoc._width); Doc.AddDocToList(Doc.GetProto(linkCollection), 'data', embedding); } }); diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index a77e4bdd1..d8b8bcb27 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -2,7 +2,6 @@ import EquationEditor from 'equation-editor-react'; import { action, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Width } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { NumCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; @@ -68,7 +67,7 @@ export class EquationBox extends ViewBoxBaseComponent() { } if (e.key === 'Tab') { const graph = Docs.Create.FunctionPlotDocument([this.rootDoc], { - x: NumCast(this.layoutDoc.x) + this.layoutDoc[Width](), + x: NumCast(this.layoutDoc.x) + NumCast(this.layoutDoc._width), y: NumCast(this.layoutDoc.y), _width: 400, _height: 300, diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index d2e1293da..de5ad1631 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -46,6 +46,15 @@ export class FontIconBox extends DocComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(FontIconBox, fieldKey); } + // + // This controls whether fontIconButtons will display labels under their icons or not + // + public static get ShowIconLabels() { + return BoolCast(Doc.UserDoc()._showLabel); + } + public static set ShowIconLabels(show: boolean) { + Doc.UserDoc()._showLabel = show; + } @observable noTooltip = false; showTemplate = (): void => { const dragFactory = Cast(this.layoutDoc.dragFactory, Doc, null); @@ -161,7 +170,7 @@ export class FontIconBox extends DocComponent() { Doc.UnBrushAllDocs(); })}> {this.Icon(color)} - {!this.label || !Doc.GetShowIconLabels() ? null : ( + {!this.label || !FontIconBox.ShowIconLabels ? null : (
{' '} {this.label}{' '} diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 2f4f788d4..f7dee1cc1 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -4,7 +4,7 @@ import { action, computed, IReactionDisposer, observable, ObservableMap, reactio import { observer } from 'mobx-react'; import { extname } from 'path'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; -import { DocData, Width } from '../../../fields/DocSymbols'; +import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; @@ -116,7 +116,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent ({ nativeSize: this.nativeSize, width: this.layoutDoc[Width]() }), + () => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width) }), ({ nativeSize, width }) => { if (layoutDoc === this.layoutDoc || !this.layoutDoc._height) { this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth; @@ -240,7 +240,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView) { const a_invXf = this.anchor1.props.ScreenToLocalTransform().inverse(); const b_invXf = this.anchor2.props.ScreenToLocalTransform().inverse(); - const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(this.anchor1.rootDoc[Width](), this.anchor1.rootDoc[Height]()) }; - const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(this.anchor2.rootDoc[Width](), this.anchor2.rootDoc[Height]()) }; + const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(NumCast(this.anchor1.rootDoc._width), NumCast(this.anchor1.rootDoc._height)) }; + const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(NumCast(this.anchor2.rootDoc._width), NumCast(this.anchor2.rootDoc._height)) }; const pts = [] as number[][]; pts.push([(a_scrBds.tl[0] + a_scrBds.br[0]) / 2, (a_scrBds.tl[1] + a_scrBds.br[1]) / 2]); @@ -51,7 +50,7 @@ export class LinkBox extends ViewBoxBaseComponent() { ); return { left: agg.x, top: agg.y, right: agg.r, bottom: agg.b, center: undefined }; } - return { left: 0, top: 0, right: 0, bottom: 0, center: undefined }; + return undefined; }; disposer: IReactionDisposer | undefined; componentDidMount() { @@ -66,8 +65,8 @@ export class LinkBox extends ViewBoxBaseComponent() { const this_xf = parxf?.getTransform() ?? Transform.Identity; //this.props.ScreenToLocalTransform(); const a_invXf = a.props.ScreenToLocalTransform().inverse(); const b_invXf = b.props.ScreenToLocalTransform().inverse(); - const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(a.rootDoc[Width](), a.rootDoc[Height]()) }; - const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(b.rootDoc[Width](), b.rootDoc[Height]()) }; + const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(NumCast(a.rootDoc._width), NumCast(a.rootDoc._height)) }; + const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(NumCast(b.rootDoc._width), NumCast(b.rootDoc._height)) }; const a_bds = { tl: this_xf.transformPoint(a_scrBds.tl[0], a_scrBds.tl[1]), br: this_xf.transformPoint(a_scrBds.br[0], a_scrBds.br[1]) }; const b_bds = { tl: this_xf.transformPoint(b_scrBds.tl[0], b_scrBds.tl[1]), br: this_xf.transformPoint(b_scrBds.br[0], b_scrBds.br[1]) }; diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 198cbe851..7e4f1da8e 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -3,13 +3,13 @@ import { Tooltip } from '@material-ui/core'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import wiki from 'wikijs'; -import { Doc, DocCastAsync, Opt } from '../../../fields/Doc'; -import { Height, Width } from '../../../fields/DocSymbols'; +import { Doc, Opt } from '../../../fields/Doc'; import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils'; import { DocServer } from '../../DocServer'; import { Docs } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; +import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; @@ -19,7 +19,6 @@ import { Transform } from '../../util/Transform'; import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; import './LinkDocPreview.scss'; import React = require('react'); -import { DocumentManager } from '../../util/DocumentManager'; interface LinkDocPreviewProps { linkDoc?: Doc; @@ -56,21 +55,20 @@ export class LinkDocPreview extends React.Component { LinkDocPreview._instance = this; } - @action init() { + @action + init() { var linkTarget = this.props.linkDoc; this._linkSrc = this.props.linkSrc; this._linkDoc = this.props.linkDoc; - const link_anchor_1 = this._linkDoc?.link_anchor_1 as Doc; - const link_anchor_2 = this._linkDoc?.link_anchor_2 as Doc; + const link_anchor_1 = DocCast(this._linkDoc?.link_anchor_1); + const link_anchor_2 = DocCast(this._linkDoc?.link_anchor_2); if (link_anchor_1 && link_anchor_2) { linkTarget = Doc.AreProtosEqual(link_anchor_1, this._linkSrc) || Doc.AreProtosEqual(link_anchor_1?.annotationOn as Doc, this._linkSrc) ? link_anchor_2 : link_anchor_1; } if (linkTarget?.annotationOn && linkTarget?.type !== DocumentType.RTF) { - // want to show annotation embedContainer document if annotation is not text - linkTarget && DocCastAsync(linkTarget.annotationOn).then(action(anno => (this._markerTargetDoc = this._targetDoc = anno))); - } else { - this._markerTargetDoc = this._targetDoc = linkTarget; + linkTarget = DocCast(linkTarget.annotationOn); // want to show annotation embedContainer document if annotation is not text } + this._markerTargetDoc = this._targetDoc = linkTarget; this._toolTipText = ''; this.updateHref(); } @@ -190,17 +188,17 @@ export class LinkDocPreview extends React.Component { width = () => { if (!this._targetDoc) return 225; - if (this._targetDoc[Width]() < this._targetDoc?.[Height]()) { - return (Math.min(225, this._targetDoc[Height]()) * this._targetDoc[Width]()) / this._targetDoc[Height](); + if (NumCast(this._targetDoc._width) < NumCast(this._targetDoc._height)) { + return (Math.min(225, NumCast(this._targetDoc._height)) * NumCast(this._targetDoc._width)) / NumCast(this._targetDoc._height); } - return Math.min(225, NumCast(this._targetDoc?.[Width](), 225)); + return Math.min(225, NumCast(this._targetDoc._width, 225)); }; height = () => { if (!this._targetDoc) return 225; - if (this._targetDoc[Width]() > this._targetDoc?.[Height]()) { - return (Math.min(225, this._targetDoc[Width]()) * this._targetDoc[Height]()) / this._targetDoc[Width](); + if (NumCast(this._targetDoc._width) > NumCast(this._targetDoc._height)) { + return (Math.min(225, NumCast(this._targetDoc._width)) * NumCast(this._targetDoc._height)) / NumCast(this._targetDoc._width); } - return Math.min(225, NumCast(this._targetDoc?.[Height](), 225)); + return Math.min(225, NumCast(this._targetDoc._height, 225)); }; @computed get previewHeader() { return !this._linkDoc || !this._markerTargetDoc || !this._targetDoc || !this._linkSrc ? null : ( diff --git a/src/client/views/nodes/LoadingBox.tsx b/src/client/views/nodes/LoadingBox.tsx index bdc074e0c..4bb0f14d2 100644 --- a/src/client/views/nodes/LoadingBox.tsx +++ b/src/client/views/nodes/LoadingBox.tsx @@ -1,4 +1,4 @@ -import { observable, runInAction } from 'mobx'; +import { action, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import ReactLoading from 'react-loading'; @@ -36,11 +36,28 @@ export class LoadingBox extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LoadingBox, fieldKey); } + @observable public static CurrentlyLoading: Doc[] = []; // this assignment doesn't work. the actual assignment happens in DocumentManager's constructor + // removes from currently loading display + @action + public static removeCurrentlyLoading(doc: Doc) { + if (LoadingBox.CurrentlyLoading) { + const index = LoadingBox.CurrentlyLoading.indexOf(doc); + index !== -1 && LoadingBox.CurrentlyLoading.splice(index, 1); + } + } + + // adds doc to currently loading display + @action + public static addCurrentlyLoading(doc: Doc) { + if (LoadingBox.CurrentlyLoading.indexOf(doc) === -1) { + LoadingBox.CurrentlyLoading.push(doc); + } + } _timer: any; @observable progress = ''; componentDidMount() { - if (!Doc.CurrentlyLoading?.includes(this.rootDoc)) { + if (!LoadingBox.CurrentlyLoading?.includes(this.rootDoc)) { this.rootDoc.loadingError = 'Upload interrupted, please try again'; } else { const updateFunc = async () => { diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 08dda2e1f..37935c513 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -5,7 +5,7 @@ import { action, computed, IReactionDisposer, observable, ObservableMap, reactio import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc'; -import { DocCss, Highlight, Width } from '../../../../fields/DocSymbols'; +import { DocCss, Highlight } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; import { DocCast, NumCast, StrCast } from '../../../../fields/Types'; @@ -170,7 +170,7 @@ export class MapBox extends ViewBoxAnnotatableComponent 0) { this.layoutDoc._layout_showSidebar = true; diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx index d38857d90..c42664abe 100644 --- a/src/client/views/nodes/MapBox/MapBox2.tsx +++ b/src/client/views/nodes/MapBox/MapBox2.tsx @@ -4,7 +4,6 @@ import { action, computed, IReactionDisposer, observable, ObservableMap, runInAc import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../../../fields/Doc'; -import { Width } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; import { NumCast, StrCast } from '../../../../fields/Types'; @@ -368,7 +367,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent 0) { this._showSidebar = true; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index c068d9dd7..bde1d5fa4 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -4,7 +4,6 @@ import { observer } from 'mobx-react'; import * as Pdfjs from 'pdfjs-dist'; import 'pdfjs-dist/web/pdf_viewer.css'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; -import { Height, Width } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { ComputedField } from '../../../fields/ScriptField'; @@ -63,7 +62,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent (this._pdf = PDFBox.pdfcache.get(this.pdfUrl!.url.href))); else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href)) PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then(action((pdf: any) => (this._pdf = pdf))); @@ -104,15 +103,15 @@ export class PDFBox extends ViewBoxAnnotatableComponent { @@ -331,7 +330,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent= 1) { this.layoutDoc.nativeWidth = nativeWidth * ratio; - onButton && (this.layoutDoc._width = this.layoutDoc[Width]() + localDelta[0]); + onButton && (this.layoutDoc._width = NumCast(this.layoutDoc._width) + localDelta[0]); this.layoutDoc._show_sidebar = nativeWidth !== this.layoutDoc._nativeWidth; } return false; @@ -352,11 +351,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent (NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], this.layoutDoc[Height]()) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], this.layoutDoc[Width]())) * this.props.PanelWidth(); + videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], NumCast(this.layoutDoc._height)) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], NumCast(this.layoutDoc._width))) * this.props.PanelWidth(); formattedPanelHeight = () => Math.max(0, this.props.PanelHeight() - this.videoPanelHeight()); render() { TraceMobx(); diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index d7f7c9b73..81749c98b 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -4,7 +4,6 @@ import { action, computed, IReactionDisposer, observable, ObservableMap, reactio import { observer } from 'mobx-react'; import { basename } from 'path'; import { Doc, StrListCast } from '../../../fields/Doc'; -import { Height, Width } from '../../../fields/DocSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; @@ -355,8 +354,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent { const makeIcon = (returnedfilename: string) => { this.dataDoc.icon = new ImageField(returnedfilename); - this.dataDoc.icon_nativeWidth = this.layoutDoc[Width](); - this.dataDoc.icon_nativeHeight = this.layoutDoc[Height](); + this.dataDoc.icon_nativeWidth = NumCast(this.layoutDoc._width); + this.dataDoc.icon_nativeHeight = NumCast(this.layoutDoc._height); }; this.Snapshot(undefined, undefined, makeIcon); }; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 5c526fe38..a452b1cdd 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -3,7 +3,6 @@ import { action, computed, IReactionDisposer, observable, ObservableMap, reactio import { observer } from 'mobx-react'; import * as WebRequest from 'web-request'; import { Doc, DocListCast, Field, Opt } from '../../../fields/Doc'; -import { Height, Width } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { HtmlField } from '../../../fields/HtmlField'; import { InkTool } from '../../../fields/InkField'; @@ -81,7 +80,7 @@ export class WebBox extends ViewBoxAnnotatableComponent 0.05) { if (!nativeWidth) Doc.SetNativeWidth(this.layoutDoc, 600); Doc.SetNativeHeight(this.layoutDoc, (nativeWidth || 600) / youtubeaspect); - this.layoutDoc._height = this.layoutDoc[Width]() / youtubeaspect; + this.layoutDoc._height = NumCast(this.layoutDoc._width) / youtubeaspect; } } // else it's an HTMLfield } else if (this.webField && !this.dataDoc.text) { @@ -276,7 +275,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { if (anchor !== this.rootDoc && this._outerRef.current) { const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); - const scrollTo = Utils.scrollIntoView(NumCast(anchor.y), anchor[Height](), NumCast(this.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(anchor.y) + anchor[Height](), this._scrollHeight)); + 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)); if (scrollTo !== undefined) { if (this._initialScroll === undefined) { const focusTime = options.zoomTime ?? 500; @@ -490,7 +489,7 @@ export class WebBox extends ViewBoxAnnotatableComponent= 1) { this.layoutDoc.nativeWidth = nativeWidth * ratio; this.layoutDoc.nativeHeight = nativeHeight * (1 + ratio); - onButton && (this.layoutDoc._width = this.layoutDoc[Width]() + localDelta[0]); + onButton && (this.layoutDoc._width = NumCast(this.layoutDoc._width) + localDelta[0]); this.layoutDoc._layout_showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; } return false; @@ -873,9 +872,9 @@ export class WebBox extends ViewBoxAnnotatableComponent { var nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']); if (!nativeWidth) { - const defaultNativeWidth = this.rootDoc[this.fieldKey] instanceof WebField ? 850 : this.Document[Width](); + const defaultNativeWidth = this.rootDoc[this.fieldKey] instanceof WebField ? 850 : NumCast(this.Document._width); Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(this.dataDoc) || defaultNativeWidth); - Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || (this.Document[Height]() / this.Document[Width]()) * defaultNativeWidth); + Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || (NumCast(this.Document._height) / NumCast(this.Document._width)) * defaultNativeWidth); nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']); } const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth; @@ -883,11 +882,11 @@ export class WebBox extends ViewBoxAnnotatableComponent (tr = this.hyperlinkTerm(tr, term, newAutoLinks))); + Doc.MyPublishedDocs.forEach(term => (tr = this.hyperlinkTerm(tr, term, newAutoLinks))); tr = tr.setSelection(isNodeSel && false ? new NodeSelection(tr.doc.resolve(f)) : new TextSelection(tr.doc.resolve(f), tr.doc.resolve(t))); this._editorView?.dispatch(tr); - // this.prepareForTyping(); } oldAutoLinks.filter(oldLink => !newAutoLinks.has(oldLink) && oldLink.link_anchor_2 !== this.rootDoc).forEach(LinkManager.Instance.deleteLink); }; @@ -460,7 +459,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent 40 ? '...' : '')).trim(); if (str.startsWith('@') && str.length > 1) { - Doc.AddDocToList(Doc.MyPublishedDocs, undefined, this.rootDoc); + Doc.AddToMyPublished(this.rootDoc); } } } @@ -487,9 +486,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent m.type.name === schema.marks.autoLinkAnchor.name)?.attrs.allAnchors ?? [])); - const link = editorView.state.schema.marks.autoLinkAnchor.create({ allAnchors, title: 'auto term', location: 'add:right' }); + const link = editorView.state.schema.marks.autoLinkAnchor.create({ allAnchors, title: 'auto term' }); tr = tr.addMark(pos, pos + node.nodeSize, link); } }); @@ -579,8 +579,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (p ? p + ' ' + item.href : item.href), ''); const anchorids = node.attrs.allAnchors.reduce((p: string, item: { href: string; title: string; anchorId: string }) => (p ? p + ' ' + item.anchorId : item.anchorId), ''); - return ['a', { class: anchorids, 'data-targethrefs': targethrefs, 'data-noPreview': 'true', 'data-linkdoc': node.attrs.linkDoc, title: node.attrs.title, location: node.attrs.location, style: `background: lightBlue` }, 0]; + return ['a', { class: anchorids, 'data-targethrefs': targethrefs, /*'data-noPreview': 'true', */ 'data-linkdoc': node.attrs.linkDoc, title: node.attrs.title, location: node.attrs.location, style: `background: lightBlue` }, 0]; }, }, noAutoLinkAnchor: { diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 82ed9e8d5..0402516a2 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -3,7 +3,6 @@ import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast, Opt } from '../../../../fields/Doc'; -import { Height, Width } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; @@ -15,6 +14,7 @@ import { DragManager } from '../../../util/DragManager'; import { SettingsManager } from '../../../util/SettingsManager'; import { Transform } from '../../../util/Transform'; import { undoable, undoBatch } from '../../../util/UndoManager'; +import { TreeView } from '../../collections/TreeView'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; @@ -25,9 +25,6 @@ import { PresBox } from './PresBox'; import './PresElementBox.scss'; import { PresMovement } from './PresEnums'; import React = require('react'); -import { TreeView } from '../../collections/TreeView'; -import { BranchingTrailManager } from '../../../util/BranchingTrailManager'; -import { MultiToggle, Type } from 'browndash-components'; /** * This class models the view a document added to presentation will have in the presentation. * It involves some functionality for its buttons and options. @@ -331,7 +328,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { }; @computed get recordingIsInOverlay() { - return DocListCast(Doc.MyOverlayDocs.data).some(doc => doc.slides === this.rootDoc); + return Doc.MyOverlayDocs.some(doc => doc.slides === this.rootDoc); } // a previously recorded video will have timecode defined @@ -341,14 +338,12 @@ export class PresElementBox extends ViewBoxBaseComponent() { }; removeAllRecordingInOverlay = () => { - DocListCast(Doc.MyOverlayDocs.data) - .filter(doc => doc.slides === this.rootDoc) - .forEach(Doc.RemFromMyOverlay); + Doc.MyOverlayDocs.filter(doc => doc.slides === this.rootDoc).forEach(Doc.RemFromMyOverlay); }; static removeEveryExistingRecordingInOverlay = () => { // Remove every recording that already exists in overlay view - DocListCast(Doc.MyOverlayDocs.data).forEach(doc => { + Doc.MyOverlayDocs.forEach(doc => { if (doc.slides !== null) { // if it's a recording video, don't remove from overlay (user can lose data) if (PresElementBox.videoIsRecorded(DocCast(doc.slides))) { @@ -407,8 +402,8 @@ export class PresElementBox extends ViewBoxBaseComponent() { activeItem.recording = recording; // make recording box appear in the bottom right corner of the screen - recording.overlayX = window.innerWidth - recording[Width]() - 20; - recording.overlayY = window.innerHeight - recording[Height]() - 20; + recording.overlayX = window.innerWidth - NumCast(recording._width) - 20; + recording.overlayY = window.innerHeight - NumCast(recording._height) - 20; Doc.AddToMyOverlay(recording); } }; diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 17a8048e9..38e4f65b6 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -24,7 +24,7 @@ interface IAnnotationProps extends FieldViewProps { export class Annotation extends React.Component { render() { return ( -
+
{DocListCast(this.props.anno.text_inlineAnnotations).map(a => ( ))} @@ -90,12 +90,12 @@ class RegionAnnotation extends React.Component { @computed get linkHighlighted() { for (const link of LinkManager.Instance.getAllDirectLinks(this.props.document)) { const a1 = LinkManager.getOppositeAnchor(link, this.props.document); - if (a1 && Doc.IsBrushedDegree(DocCast(a1.annotationOn, this.props.document))) return true; + if (a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, this.props.document))) return true; } } render() { - const brushed = this.annoTextRegion && Doc.isBrushedHighlightedDegree(this.annoTextRegion); + const brushed = this.annoTextRegion && Doc.GetBrushHighlightStatus(this.annoTextRegion); return (
list) : Promise.resolve(defaultValue); } - -export async function DocCastAsync(field: FieldResult): Promise> { - return Cast(field, Doc); -} - export function NumListCast(field: FieldResult, defaultVal: number[] = []) { return Cast(field, listSpec('number'), defaultVal); } @@ -162,140 +131,51 @@ export function updateCachedAcls(doc: Doc) { @Deserializable('Doc', updateCachedAcls, ['id']) export class Doc extends RefField { @observable public static RecordingEvent = 0; - - // this isn't really used at the moment, but is intended to indicate whether ink stroke are passed through a gesture recognizer - static GetRecognizeGestures() { - return BoolCast(Doc.UserDoc()._recognizeGestures); - } - static SetRecognizeGestures(show: boolean) { - Doc.UserDoc()._recognizeGestures = show; - } - - // - // This controls whether fontIconButtons will display labels under their icons or not - // - static GetShowIconLabels() { - return BoolCast(Doc.UserDoc()._showLabel); - } - static SetShowIconLabels(show: boolean) { - Doc.UserDoc()._showLabel = show; - } - @observable public static CurrentlyLoading: Doc[] = []; // this assignment doesn't work. the actual assignment happens in DocumentManager's constructor - // removes from currently loading display - @action - public static removeCurrentlyLoading(doc: Doc) { - if (Doc.CurrentlyLoading) { - const index = Doc.CurrentlyLoading.indexOf(doc); - index !== -1 && Doc.CurrentlyLoading.splice(index, 1); - } - } - - // adds doc to currently loading display - @action - public static addCurrentlyLoading(doc: Doc) { - if (Doc.CurrentlyLoading.indexOf(doc) === -1) { - Doc.CurrentlyLoading.push(doc); - } - } - @observable public static GuestDashboard: Doc | undefined; @observable public static GuestTarget: Doc | undefined; @observable public static GuestMobile: Doc | undefined; - public static get MySharedDocs() { - return DocCast(Doc.UserDoc().mySharedDocs); - } - public static get MyUserDocView() { - return DocCast(Doc.UserDoc().myUserDocView); - } - public static get MyDockedBtns() { - return DocCast(Doc.UserDoc().myDockedBtns); - } - public static get MySearcher() { - return DocCast(Doc.UserDoc().mySearcher); - } - public static get MyHeaderBar() { - return DocCast(Doc.UserDoc().myHeaderBar); - } - public static get MyLeftSidebarMenu() { - return DocCast(Doc.UserDoc().myLeftSidebarMenu); - } - public static get MyLeftSidebarPanel() { - return DocCast(Doc.UserDoc().myLeftSidebarPanel); - } - public static get MyContextMenuBtns() { - return DocCast(Doc.UserDoc().myContextMenuBtns); - } - public static get MyTopBarBtns() { - return DocCast(Doc.UserDoc().myTopBarBtns); - } - public static get MyRecentlyClosed() { - return DocCast(Doc.UserDoc().myRecentlyClosed); - } - public static get MyTrails() { - return DocCast(Doc.ActiveDashboard?.myTrails); - } - public static IsInMyOverlay(doc: Doc) { - return DocListCast(Doc.MyOverlayDocs?.data).includes(doc); - } - public static AddToMyOverlay(doc: Doc) { - Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc); - } - public static RemFromMyOverlay(doc: Doc) { - Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, doc); - } - public static get MyOverlayDocs() { - return DocCast(Doc.UserDoc().myOverlayDocs); - } - public static get MyPublishedDocs() { - return DocCast(Doc.UserDoc().myPublishedDocs); - } - public static get MyDashboards() { - return DocCast(Doc.UserDoc().myDashboards); - } - public static get MyTemplates() { - return DocCast(Doc.UserDoc().myTemplates); - } - public static get MyImports() { - return DocCast(Doc.UserDoc().myImports); - } - public static get MyFilesystem() { - return DocCast(Doc.UserDoc().myFilesystem); - } - public static get MyTools() { - return DocCast(Doc.UserDoc().myTools); - } - public static get ActivePage() { - return StrCast(Doc.UserDoc().activePage); - } - public static set ActivePage(val) { - Doc.UserDoc().activePage = val; - DocServer.UPDATE_SERVER_CACHE(); - } - public static IsComicStyle(doc?: Doc) { - return doc && Doc.ActiveDashboard && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === 'comic'; - } - public static get ActiveDashboard() { - return DocCast(Doc.UserDoc().activeDashboard); - } - public static set ActiveDashboard(val: Doc | undefined) { - const overlays = Cast(Doc.MyOverlayDocs.data, listSpec(Doc), null); - overlays && (overlays.length = 0); - Doc.UserDoc().activeDashboard = val; - } - public static set ActiveTool(tool: InkTool) { - Doc.UserDoc().activeTool = tool; - } - public static get ActiveTool(): InkTool { - return StrCast(Doc.UserDoc().activeTool, InkTool.None) as InkTool; - } - public static get ActivePresentation(): Opt { - return DocCast(Doc.ActiveDashboard?.activePresentation); - } - public static set ActivePresentation(val) { - if (Doc.ActiveDashboard) { - Doc.ActiveDashboard.activePresentation = val; - } - } + public static CurrentUserEmail: string = ''; + + public static get MySharedDocs() { return DocCast(Doc.UserDoc().mySharedDocs); } // prettier-ignore + public static get MyUserDocView() { return DocCast(Doc.UserDoc().myUserDocView); } // prettier-ignore + public static get MyDockedBtns() { return DocCast(Doc.UserDoc().myDockedBtns); } // prettier-ignore + public static get MySearcher() { return DocCast(Doc.UserDoc().mySearcher); } // prettier-ignore + public static get MyHeaderBar() { return DocCast(Doc.UserDoc().myHeaderBar); } // prettier-ignore + public static get MyLeftSidebarMenu() { return DocCast(Doc.UserDoc().myLeftSidebarMenu); } // prettier-ignore + public static get MyLeftSidebarPanel() { return DocCast(Doc.UserDoc().myLeftSidebarPanel); } // prettier-ignore + public static get MyContextMenuBtns() { return DocCast(Doc.UserDoc().myContextMenuBtns); } // prettier-ignore + public static get MyTopBarBtns() { return DocCast(Doc.UserDoc().myTopBarBtns); } // prettier-ignore + public static get MyRecentlyClosed() { return DocCast(Doc.UserDoc().myRecentlyClosed); } // prettier-ignore + public static get MyTrails() { return DocCast(Doc.ActiveDashboard?.myTrails); } // prettier-ignore + public static get MyOverlayDocs() { return DocListCast(Doc.ActiveDashboard?.myOverlayDocs ?? DocCast(Doc.UserDoc().myOverlayDocs).data); } // prettier-ignore + public static get MyPublishedDocs() { return DocListCast(Doc.ActiveDashboard?.myPublishedDocs ?? DocCast(Doc.UserDoc().myPublishedDocs).data); } // prettier-ignore + public static get MyDashboards() { return DocCast(Doc.UserDoc().myDashboards); } // prettier-ignore + public static get MyTemplates() { return DocCast(Doc.UserDoc().myTemplates); } // prettier-ignore + public static get MyImports() { return DocCast(Doc.UserDoc().myImports); } // prettier-ignore + public static get MyFilesystem() { return DocCast(Doc.UserDoc().myFilesystem); } // prettier-ignore + public static get MyTools() { return DocCast(Doc.UserDoc().myTools); } // prettier-ignore + public static get noviceMode() { return BoolCast(Doc.UserDoc().noviceMode); } // prettier-ignore + public static set noviceMode(val) { Doc.UserDoc().noviceMode = val; } // prettier-ignore + public static get IsSharingEnabled() { return BoolCast(Doc.UserDoc().isSharingEnabled); } // prettier-ignore + public static set IsSharingEnabled(val) { Doc.UserDoc().isSharingEnabled = val; } // prettier-ignore + public static get defaultAclPrivate() { return Doc.UserDoc().defaultAclPrivate; } // prettier-ignore + public static set defaultAclPrivate(val) { Doc.UserDoc().defaultAclPrivate = val; } // prettier-ignore + public static get ActivePage() { return StrCast(Doc.UserDoc().activePage); } // prettier-ignore + public static set ActivePage(val) { Doc.UserDoc().activePage = val; } // prettier-ignore + public static get ActiveTool(): InkTool { return StrCast(Doc.UserDoc().activeTool, InkTool.None) as InkTool; } // prettier-ignore + public static set ActiveTool(tool:InkTool){ Doc.UserDoc().activeTool = tool; } // prettier-ignore + public static get ActivePresentation() { return DocCast(Doc.ActiveDashboard?.activePresentation) as Opt; } // prettier-ignore + public static set ActivePresentation(val) { Doc.ActiveDashboard && (Doc.ActiveDashboard.activePresentation = val) } // prettier-ignore + public static get ActiveDashboard() { return DocCast(Doc.UserDoc().activeDashboard); } // prettier-ignore + public static set ActiveDashboard(val: Opt) { Doc.UserDoc().activeDashboard = val; } // prettier-ignore + + public static IsInMyOverlay(doc: Doc) { return Doc.MyOverlayDocs.includes(doc); } // prettier-ignore + public static AddToMyOverlay(doc: Doc) { Doc.ActiveDashboard?.myOverlayDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myOverlayDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore + public static RemFromMyOverlay(doc: Doc) { Doc.ActiveDashboard?.myOverlayDocs ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myOverlayDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore + public static AddToMyPublished(doc: Doc) { Doc.ActiveDashboard?.myPublishedDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myPublishedDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore + public static RemFromMyPublished(doc: Doc){ Doc.ActiveDashboard?.myPublishedDocs ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myPublishedDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore + public static IsComicStyle(doc?: Doc) { return doc && Doc.ActiveDashboard && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === 'comic' ; } // prettier-ignore + constructor(id?: FieldId, forceSave?: boolean) { super(id); const docProxy = new Proxy(this, { @@ -359,17 +239,14 @@ export class Doc extends RefField { @observable public [Highlight]: boolean = false; @observable public [Brushed]: boolean = false; @observable public [DocViews] = new ObservableSet(); - static __Anim(Doc: Doc) { - // for debugging to print AnimationSym field easily. - return Doc[Animation]; - } + private [Self] = this; + private [SelfProxy]: any; private [UpdatingFromServer]: boolean = false; private [ForceServerWrite]: boolean = false; - public [Initializing]: boolean = false; + private [CachedUpdates]: { [key: string]: () => void | Promise } = {}; - private [Self] = this; - private [SelfProxy]: any; + public [Initializing]: boolean = false; public [FieldChanged] = (diff: undefined | { op: '$addToSet' | '$remFromSet' | '$set'; items: Field[] | undefined; length: number | undefined; hint?: any }, serverOp: any) => { if (!this[UpdatingFromServer] || this[ForceServerWrite]) { DocServer.UpdateField(this[Id], serverOp); @@ -380,9 +257,7 @@ export class Doc extends RefField { public [Height] = () => NumCast(this[SelfProxy]._height); public [ToScriptString] = () => `idToDoc("${this[Self][Id]}")`; public [ToString] = () => `Doc(${GetEffectiveAcl(this[SelfProxy]) === AclPrivate ? '-inaccessible-' : this[SelfProxy].title})`; - public get [DocLayout]() { - return this[SelfProxy].__LAYOUT__; - } + public get [DocLayout]() { return this[SelfProxy].__LAYOUT__; } // prettier-ignore public get [DocData](): Doc { const self = this[SelfProxy]; return self.resolvedDataDoc && !self.isTemplateForField ? self : Doc.GetProto(Cast(Doc.Layout(self).resolvedDataDoc, Doc, null) || self); @@ -403,29 +278,6 @@ export class Doc extends RefField { return undefined; } - private [CachedUpdates]: { [key: string]: () => void | Promise } = {}; - public static get noviceMode() { - return Doc.UserDoc().noviceMode as boolean; - } - public static set noviceMode(val) { - Doc.UserDoc().noviceMode = val; - } - public static get IsSharingEnabled() { - return Doc.UserDoc().isSharingEnabled as boolean; - } - public static set IsSharingEnabled(val) { - Doc.UserDoc().isSharingEnabled = val; - } - public static get defaultAclPrivate() { - return Doc.UserDoc().defaultAclPrivate; - } - public static set defaultAclPrivate(val) { - Doc.UserDoc().defaultAclPrivate = val; - } - public static CurrentUserEmail: string = ''; - public static get CurrentUserEmailNormalized() { - return normalizeEmail(Doc.CurrentUserEmail); - } public async [HandleUpdate](diff: any) { const set = diff.$set; const sameAuthor = this.author === Doc.CurrentUserEmail; @@ -482,17 +334,6 @@ export class Doc extends RefField { } export namespace Doc { - // export function GetAsync(doc: Doc, key: string, ignoreProto: boolean = false): Promise { - // const self = doc[Self]; - // return new Promise(res => getField(self, key, ignoreProto, res)); - // } - // export function GetTAsync(doc: Doc, key: string, ctor: ToConstructor, ignoreProto: boolean = false): Promise { - // return new Promise(async res => { - // const field = await GetAsync(doc, key, ignoreProto); - // return Cast(field, ctor); - // }); - // } - export function SetContainer(doc: Doc, container: Doc) { doc.embedContainer = container; } @@ -626,10 +467,9 @@ export namespace Doc { /** * @returns the index of doc toFind in list of docs, -1 otherwise */ - export function IndexOf(toFind: Doc, list: Doc[], allowProtos: boolean = true) { - let index = list.reduce((p, v, i) => (v instanceof Doc && v === toFind ? i : p), -1); - index = allowProtos && index !== -1 ? index : list.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, toFind) ? i : p), -1); - return index; // list.findIndex(doc => doc === toFind || Doc.AreProtosEqual(doc, toFind)); + export function IndexOf(toFind: Doc, list: Doc[]) { + const index = list.indexOf(toFind); + return index !== -1 ? index : list.findIndex(doc => Doc.AreProtosEqual(doc, toFind)); } /** @@ -663,11 +503,10 @@ export namespace Doc { } const list = Cast(listDoc[key], listSpec(Doc)); if (list) { - if (allowDuplicates !== true) { - const pind = list.reduce((l, d, i) => (d instanceof Doc && d[Id] === doc[Id] ? i : l), -1); + if (!allowDuplicates) { + const pind = list.findIndex(d => d instanceof Doc && d[Id] === doc[Id]); if (pind !== -1) { return true; - //list.splice(pind, 1); // bcz: this causes schemaView docs in the Catalog to move to the bottom of the schema view when they are dragged even though they haven't left the collection } } if (first) { @@ -687,22 +526,6 @@ export namespace Doc { return false; } - /** - * Computes the bounds of the contents of a set of documents. - */ - export function ComputeContentBounds(docList: Doc[]) { - const bounds = docList.reduce( - (bounds, doc) => ({ - x: Math.min(NumCast(doc.x), bounds.x), - y: Math.min(NumCast(doc.y), bounds.y), - r: Math.max(NumCast(doc.x) + doc[Width](), bounds.r), - b: Math.max(NumCast(doc.y) + doc[Height](), bounds.b), - }), - { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: -Number.MAX_VALUE, b: -Number.MAX_VALUE } - ); - return bounds; - } - export function MakeEmbedding(doc: Doc, id?: string) { const embedding = !GetT(doc, 'isDataDoc', 'boolean', true) && doc.proto ? Doc.MakeCopy(doc, undefined, id) : Doc.MakeDelegate(doc, id); const layout = Doc.LayoutField(embedding); @@ -779,7 +602,7 @@ export namespace Doc { } else if (field instanceof RefField) { assignKey(field); } else if (cfield instanceof ComputedField) { - assignKey(cfield[Copy]()); // ComputedField.MakeFunction(cfield.script.originalScript)); + assignKey(cfield[Copy]()); } else if (field instanceof ObjectField) { await copyObjectField(field); } else if (field instanceof Promise) { @@ -990,29 +813,6 @@ export namespace Doc { return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc }; } - export function Overwrite(doc: Doc, overwrite: Doc, copyProto: boolean = false): Doc { - Object.keys(doc).forEach(key => { - const field = ProxyField.WithoutProxy(() => doc[key]); - if (key === 'proto' && copyProto) { - if (doc.proto instanceof Doc && overwrite.proto instanceof Doc) { - overwrite[key] = Doc.Overwrite(doc.proto, overwrite.proto); - } - } else { - if (field instanceof RefField) { - overwrite[key] = field; - } else if (field instanceof ObjectField) { - overwrite[key] = ObjectField.MakeCopy(field); - } else if (field instanceof Promise) { - debugger; //This shouldn't happend... - } else { - overwrite[key] = field; - } - } - }); - - return overwrite; - } - export function FindReferences(infield: Doc | List, references: Set, system: boolean | undefined) { if (infield instanceof List) { infield.forEach(val => (val instanceof Doc || val instanceof List) && FindReferences(val, references, system)); @@ -1217,22 +1017,8 @@ export namespace Doc { return '/doc/' + (doc ? doc[Id] : ''); } - export function overlapping(doc1: Doc, doc2: Doc, clusterDistance: number) { - const doc2Layout = Doc.Layout(doc2); - const doc1Layout = Doc.Layout(doc1); - const x2 = NumCast(doc2.x) - clusterDistance; - const y2 = NumCast(doc2.y) - clusterDistance; - const w2 = NumCast(doc2Layout._width) + clusterDistance; - const h2 = NumCast(doc2Layout._height) + clusterDistance; - const x = NumCast(doc1.x) - clusterDistance; - const y = NumCast(doc1.y) - clusterDistance; - const w = NumCast(doc1Layout._width) + clusterDistance; - const h = NumCast(doc1Layout._height) + clusterDistance; - return doc1.z === doc2.z && intersectRect({ left: x, top: y, width: w, height: h }, { left: x2, top: y2, width: w2, height: h2 }); - } - - export function isBrushedHighlightedDegree(doc: Doc) { - return Doc.IsHighlighted(doc) ? DocBrushStatus.highlighted : Doc.IsBrushedDegree(doc); + export function GetBrushHighlightStatus(doc: Doc) { + return Doc.IsHighlighted(doc) ? DocBrushStatus.highlighted : Doc.GetBrushStatus(doc); } export class DocBrush { BrushedDoc = new Set(); @@ -1269,12 +1055,12 @@ export namespace Doc { return Doc.NativeWidth(doc, dataDoc, useDim) / (Doc.NativeHeight(doc, dataDoc, useDim) || 1); } export function NativeWidth(doc?: Doc, dataDoc?: Doc, useWidth?: boolean) { - return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeWidth'], useWidth ? doc[Width]() : 0)); + return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeWidth'], useWidth ? NumCast(doc._width) : 0)); } export function NativeHeight(doc?: Doc, dataDoc?: Doc, useHeight?: boolean) { if (!doc) return 0; - const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) * doc[Height]()) / doc[Width](); - const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeHeight'], useHeight ? doc[Height]() : 0); + const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) * NumCast(doc._height)) / NumCast(doc._width); + const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeHeight'], useHeight ? NumCast(doc._height) : 0); return NumCast(doc._nativeHeight, nheight || dheight); } export function SetNativeWidth(doc: Doc, width: number | undefined, fieldKey?: string) { @@ -1337,36 +1123,22 @@ export namespace Doc { highlighted = 3, } // returns 'how' a Doc has been brushed over - whether the document itself was brushed, it's prototype, or neither - export function IsBrushedDegree(doc: Doc) { + 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; } export function BrushDoc(doc: Doc, unbrush = false) { - if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc; - brushManager.brushDoc(doc, unbrush); - brushManager.brushDoc(Doc.GetProto(doc), unbrush); + if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(Doc.GetProto(doc)) !== AclPrivate) { + brushManager.brushDoc(doc, unbrush); + brushManager.brushDoc(Doc.GetProto(doc), unbrush); + } return doc; } export function UnBrushDoc(doc: Doc) { return BrushDoc(doc, true); } - - export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) { - const linkAnchor2 = DocCast(linkDoc.link_anchor_2); - const linkAnchor1 = DocCast(linkDoc.link_anchor_1); - if (linkDoc.link_matchEmbeddings) { - return [linkAnchor2, linkAnchor2.annotationOn].includes(anchorDoc) ? '2' : '1'; - } - if (Doc.AreProtosEqual(linkAnchor2, anchorDoc) || Doc.AreProtosEqual(linkAnchor2.annotationOn as Doc, anchorDoc)) return '2'; - return Doc.AreProtosEqual(linkAnchor1, anchorDoc) || Doc.AreProtosEqual(linkAnchor1.annotationOn as Doc, anchorDoc) ? '1' : '2'; - } - - export function linkFollowUnhighlight() { - clearTimeout(UnhighlightTimer); - UnhighlightWatchers.forEach(watcher => watcher()); - UnhighlightWatchers.length = 0; - highlightedDocs.forEach(doc => Doc.UnHighlightDoc(doc)); - document.removeEventListener('pointerdown', linkFollowUnhighlight); + export function UnBrushAllDocs() { + Array.from(brushManager.BrushedDoc).forEach(action(doc => (doc[Brushed] = false))); } let UnhighlightWatchers: (() => void)[] = []; @@ -1376,6 +1148,13 @@ export namespace Doc { UnhighlightWatchers.push(watcher); } else watcher(); } + export function linkFollowUnhighlight() { + clearTimeout(UnhighlightTimer); + UnhighlightWatchers.forEach(watcher => watcher()); + UnhighlightWatchers.length = 0; + highlightedDocs.forEach(doc => Doc.UnHighlightDoc(doc)); + document.removeEventListener('pointerdown', linkFollowUnhighlight); + } export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true, presentation_effect?: Doc) { linkFollowUnhighlight(); (destDoc instanceof Doc ? [destDoc] : destDoc).forEach(doc => Doc.HighlightDoc(doc, dataAndDisplayDocs, presentation_effect)); @@ -1415,9 +1194,6 @@ export namespace Doc { }); }); } - export function UnBrushAllDocs() { - Array.from(brushManager.BrushedDoc).forEach(action(doc => (doc[Brushed] = false))); - } export function getDocTemplate(doc?: Doc) { return !doc @@ -1433,41 +1209,6 @@ export namespace Doc { : undefined; } - export function matchFieldValue(doc: Doc, key: string, value: any): boolean { - const hasFunctionFilter = Utils.HasFunctionFilter(value); - if (hasFunctionFilter) { - return hasFunctionFilter(StrCast(doc[key])); - } - if (key === LinkedTo) { - // links are not a field value, so handled here. value is an expression of form ([field=]idToDoc("...")) - const allLinks = LinkManager.Instance.getAllRelatedLinks(doc); - const matchLink = (value: string, anchor: Doc) => { - const linkedToExp = value?.split('='); - if (linkedToExp.length === 1) return Field.toScriptString(anchor) === value; - return Field.toScriptString(DocCast(anchor[linkedToExp[0]])) === linkedToExp[1]; - }; - // prettier-ignore - return (value === Doc.FilterNone && !allLinks.length) || - (value === Doc.FilterAny && !!allLinks.length) || - (allLinks.some(link => matchLink(value,DocCast(link.link_anchor_1)) || - matchLink(value,DocCast(link.link_anchor_2)) )); - } - if (typeof value === 'string') { - value = value.replace(`,${Utils.noRecursionHack}`, ''); - } - const fieldVal = doc[key]; - // prettier-ignore - if ((value === Doc.FilterAny && fieldVal !== undefined) || - (value === Doc.FilterNone && fieldVal === undefined)) { - return true; - } - const vals = StrListCast(fieldVal); // list typing is very imperfect. casting to a string list doesn't mean that the entries will actually be strings - if (vals.length) { - return vals.some(v => typeof v === 'string' && v.includes(value)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring - } - return Field.toString(fieldVal as Field).includes(value); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring - } - export function deiconifyView(doc: Doc) { StrCast(doc.layout_fieldKey).split('_')[1] === 'icon' && setNativeView(doc); } @@ -1603,15 +1344,25 @@ export namespace Doc { } // prettier-ignore - export function toIcon(doc?: Doc, isOpen?: boolean) { - switch (isOpen !== undefined ? DocumentType.COL: StrCast(doc?.type)) { + export function toIcon(doc?: Doc, isOpen?: Opt) { + if (isOpen) return doc?.isFolder ? 'chevron-down' : 'folder-open'; + switch (StrCast(doc?.type)) { case DocumentType.IMG: return 'image'; case DocumentType.COMPARISON: return 'columns'; case DocumentType.RTF: return 'sticky-note'; case DocumentType.COL: - const folder: IconProp = isOpen === true ? 'folder-open' : isOpen === false ? 'folder' : doc?.title==='Untitled Collection'? 'object-group': 'chalkboard'; - const chevron: IconProp = isOpen === true ? 'chevron-down' : isOpen === false ? 'chevron-right' : 'question'; - return !doc?.isFolder ? folder : chevron; + if (doc?.isFolder) { + switch (doc.type_collection) { + default: return isOpen === false ? 'chevron-right' : 'question'; + } // prettier-ignore + } + switch (doc?.type_collection) { + case CollectionViewType.Freeform : return 'object-group'; + case CollectionViewType.NoteTaking : return 'chalkboard'; + case CollectionViewType.Schema : return 'table-cells'; + case CollectionViewType.Docking: return 'solar-panel'; + default: return 'folder'; + } // prettier-ignore case DocumentType.WEB: return 'globe-asia'; case DocumentType.SCREENSHOT: return 'photo-video'; case DocumentType.WEBCAM: return 'video'; @@ -1628,9 +1379,9 @@ export namespace Doc { case DocumentType.DATAVIZ: return 'chart-bar'; case DocumentType.EQUATION: return 'calculator'; case DocumentType.SIMULATION: return 'rocket'; - case DocumentType.CONFIG: return 'question-circle'; - default: return 'question'; + case DocumentType.CONFIG: return 'folder-closed'; } + return 'question'; } /// @@ -1839,14 +1590,13 @@ ScriptingGlobals.add(function sameDocs(doc1: any, doc2: any) { ScriptingGlobals.add(function assignDoc(doc: Doc, field: string, id: string) { return Doc.assignDocToField(doc, field, id); }); -ScriptingGlobals.add(function docCast(doc: FieldResult): any { - return DocCastAsync(doc); +ScriptingGlobals.add(function docCastAsync(doc: FieldResult): any { + return Cast(doc, Doc); }); ScriptingGlobals.add(function activePresentationItem() { const curPres = Doc.ActivePresentation; return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)]; }); - ScriptingGlobals.add(function setDocFilter(container: Doc, key: string, value: any, modifiers: 'match' | 'check' | 'x' | 'remove') { Doc.setDocFilter(container, key, value, modifiers); }); diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts index 5ecf25e08..dfd02dbc0 100644 --- a/src/fields/RichTextUtils.ts +++ b/src/fields/RichTextUtils.ts @@ -275,7 +275,7 @@ export namespace RichTextUtils { } else { docId = backingDocId; } - return schema.node('image', { src, agnostic, width, docId, float: null, location: 'add:right' }); + return schema.node('image', { src, agnostic, width, docId, float: null }); }; const textNode = (schema: any, run: docs_v1.Schema$TextRun) => { diff --git a/src/fields/util.ts b/src/fields/util.ts index 28db77c65..ca02284da 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -234,7 +234,7 @@ function getEffectiveAcl(target: any, user?: string): symbol { * @param layoutOnly just sets the layout doc's ACL (unless the data doc has no entry for the ACL, in which case it will be set as well) */ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, visited?: Doc[], allowUpgrade?: boolean, layoutOnly = false) { - const selfKey = `acl-${Doc.CurrentUserEmailNormalized}`; + const selfKey = `acl-${normalizeEmail(Doc.CurrentUserEmail)}`; if (!visited) visited = [] as Doc[]; if (!target || visited.includes(target) || key === selfKey) return; visited.push(target); diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 498bec6ed..e24bcd733 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -658,7 +658,7 @@ export class MobileInterface extends React.Component { // DocButton for switching into ink mode @computed get drawInk() { return !this.mainContainer || this._activeDoc._type_collection !== CollectionViewType.Docking ? null : ( -
+
); @@ -668,7 +668,7 @@ export class MobileInterface extends React.Component { @computed get uploadImageButton() { if (this._activeDoc.type === DocumentType.COL && this._activeDoc !== this._homeDoc && this._activeDoc._type_collection !== CollectionViewType.Docking && this._activeDoc.title !== 'WORKSPACES') { return ( -
+
); @@ -692,13 +692,8 @@ export class MobileInterface extends React.Component { @computed get pinToPresentation() { // Only making button available if it is an image if (!(this._activeDoc.type === 'collection' || this._activeDoc.type === 'presentation')) { - const isPinned = this._activeDoc && Doc.isDocPinned(this._activeDoc); return ( -
TabDocView.PinDoc(this._activeDoc, {})}> +
TabDocView.PinDoc(this._activeDoc, {})}>
); -- cgit v1.2.3-70-g09d2 From 0dc39baf9630ae5aeaa41b89523ec6bf96d0b198 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Nov 2023 21:53:36 -0500 Subject: major overhaul of resizing code. updated doc fields for enabling native with modification to be cleaner. added Vcenter option for text in menu bar. fixed doc rotation. enabled scaling of DataViz views. fixed text sidebar opening size and sidebar issues with native dims for PDF/Web --- src/client/documents/Documents.ts | 43 +-- src/client/util/CurrentUserUtils.ts | 4 +- src/client/views/DocumentDecorations.tsx | 312 +++++++++------------ src/client/views/InkControlPtHandles.tsx | 7 +- src/client/views/MainView.tsx | 1 + .../CollectionMulticolumnView.tsx | 2 +- .../CollectionMultirowView.tsx | 2 +- src/client/views/global/globalScripts.ts | 14 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 10 +- src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 13 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 6 +- src/fields/Doc.ts | 6 - 15 files changed, 191 insertions(+), 237 deletions(-) (limited to 'src/client/util/CurrentUserUtils.ts') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 1ea9b1dcc..bd5fa5d78 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -186,8 +186,6 @@ export class DocumentOptions { linearBtnWidth?: NUMt = new NumInfo('unexpanded width of a linear menu button (button "width" changes when it expands)', false); _nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)', false); _nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)', false); - _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false); - _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers'); 'acl-Guest'?: STRt = new StrInfo("permissions granted to users logged in as 'guest' (either view, or private)"); // public permissions '_acl-Guest'?: string; // public permissions @@ -229,12 +227,16 @@ export class DocumentOptions { 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_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'); _layout_fieldKey?: STRt = new StrInfo('the field key containing the current layout definition', false); @@ -472,9 +474,9 @@ export namespace Docs { _height: 35, _xMargin: 10, _yMargin: 10, - nativeDimModifiable: true, - nativeHeightUnfrozen: true, - layout_forceReflow: true, + layout_nativeDimEditable: true, + layout_reflowVertical: true, + layout_reflowHorizontal: true, defaultDoubleClick: 'ignore', systemIcon: 'BsFileEarmarkTextFill', }, @@ -505,7 +507,7 @@ export namespace Docs { DocumentType.WEB, { layout: { view: WebBox, dataField: defaultDataKey }, - options: { _height: 300, _layout_fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true, waitForDoubleClickToClick: 'always', systemIcon: 'BsGlobe' }, + options: { _height: 300, _layout_fitWidth: true, layout_nativeDimEditable: true, layout_reflowVertical: true, waitForDoubleClickToClick: 'always', systemIcon: 'BsGlobe' }, }, ], [ @@ -533,7 +535,7 @@ export namespace Docs { DocumentType.AUDIO, { layout: { view: AudioBox, dataField: defaultDataKey }, - options: { _height: 100, layout_fitWidth: true, layout_forceReflow: true, nativeDimModifiable: true, systemIcon: 'BsFillVolumeUpFill' }, + options: { _height: 100, layout_fitWidth: true, layout_reflowHorizontal: true, layout_nativeDimEditable: true, systemIcon: 'BsFillVolumeUpFill' }, }, ], [ @@ -547,14 +549,14 @@ export namespace Docs { DocumentType.PDF, { layout: { view: PDFBox, dataField: defaultDataKey }, - options: { _layout_curPage: 1, _layout_fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true, systemIcon: 'BsFileEarmarkPdfFill' }, + options: { _layout_curPage: 1, _layout_fitWidth: true, layout_nativeDimEditable: true, layout_reflowVertical: true, systemIcon: 'BsFileEarmarkPdfFill' }, }, ], [ DocumentType.MAP, { layout: { view: MapBox, dataField: defaultDataKey }, - options: { map: '', _height: 600, _width: 800, nativeDimModifiable: true, systemIcon: 'BsFillPinMapFill' }, + options: { map: '', _height: 600, _width: 800, layout_reflowHorizontal: true, layout_reflowVertical: true, layout_nativeDimEditable: true, systemIcon: 'BsFillPinMapFill' }, }, ], [ @@ -613,14 +615,14 @@ export namespace Docs { DocumentType.EQUATION, { layout: { view: EquationBox, dataField: 'text' }, - options: { nativeDimModifiable: true, fontSize: '14px', layout_hideResizeHandles: true, layout_hideDecorationTitle: true, systemIcon: 'BsCalculatorFill' }, ///systemIcon: 'BsSuperscript' + BsSubscript + options: { layout_nativeDimEditable: true, fontSize: '14px', layout_hideResizeHandles: true, layout_hideDecorationTitle: true, systemIcon: 'BsCalculatorFill' }, ///systemIcon: 'BsSuperscript' + BsSubscript }, ], [ DocumentType.FUNCPLOT, { layout: { view: FunctionPlotBox, dataField: defaultDataKey }, - options: { nativeDimModifiable: true }, + options: { layout_nativeDimEditable: true }, }, ], [ @@ -672,12 +674,12 @@ export namespace Docs { layout: { view: InkingStroke, dataField: 'stroke' }, options: { systemIcon: 'BsFillPencilFill', // - nativeDimModifiable: true, - nativeHeightUnfrozen: true, + layout_nativeDimEditable: true, + layout_reflowVertical: true, + layout_reflowHorizontal: true, layout_hideDecorationTitle: true, // don't show title when selected fitWidth: false, layout_isSvg: true, - layout_forceReflow: true, }, }, ], @@ -685,7 +687,7 @@ export namespace Docs { DocumentType.SCREENSHOT, { layout: { view: ScreenshotBox, dataField: defaultDataKey }, - options: { nativeDimModifiable: true, nativeHeightUnfrozen: true, systemIcon: 'BsCameraFill' }, + options: { layout_nativeDimEditable: true, systemIcon: 'BsCameraFill' }, }, ], [ @@ -714,14 +716,14 @@ export namespace Docs { DocumentType.DATAVIZ, { layout: { view: DataVizBox, dataField: defaultDataKey }, - options: { dataViz_title: '', dataViz_line: '', dataViz_pie: '', dataViz_histogram: '', dataViz: 'table', _layout_fitWidth: true, nativeDimModifiable: true }, + options: { dataViz_title: '', dataViz_line: '', dataViz_pie: '', dataViz_histogram: '', dataViz: 'table', _layout_fitWidth: true, layout_reflowHorizontal: true, layout_reflowVertical: true, layout_nativeDimEditable: true }, }, ], [ DocumentType.LOADING, { layout: { view: LoadingBox, dataField: '' }, - options: { _layout_fitWidth: true, _fitHeight: true, nativeDimModifiable: true }, + options: { _layout_fitWidth: true, _fitHeight: true, layout_nativeDimEditable: true }, }, ], [ @@ -731,11 +733,9 @@ export namespace Docs { layout: { view: PhysicsSimulationBox, dataField: defaultDataKey, _width: 1000, _height: 800 }, options: { _height: 100, - layout_forceReflow: true, - nativeHeightUnfrozen: true, mass1: '', mass2: '', - nativeDimModifiable: true, + layout_nativeDimEditable: true, position: '', acceleration: '', pendulum: '', @@ -948,7 +948,7 @@ export namespace Docs { export function ImageDocument(url: string | ImageField, options: DocumentOptions = {}, overwriteDoc?: Doc) { const imgField = url instanceof ImageField ? url : new ImageField(url); - return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { _nativeDimModifiable: false, _nativeHeightUnfrozen: false, title: basename(imgField.url.href), ...options }, undefined, undefined, undefined, overwriteDoc); + return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: basename(imgField.url.href), ...options }, undefined, undefined, undefined, overwriteDoc); } export function PresDocument(options: DocumentOptions = {}) { @@ -1864,6 +1864,7 @@ export namespace DocUtils { _height: 35, x: x, y: y, + _layout_centered: BoolCast(Doc.UserDoc().layout_centered), _layout_fitWidth: true, _layout_autoHeight: true, _layout_enableAltContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards), diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index cd19daee5..ac506e2d6 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -655,13 +655,13 @@ export class CurrentUserUtils { { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", toolType:"underline",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", toolType:"bullet", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", toolType:"decimal", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, + { title: "Vcenter", toolTip: "Vertical center", btnType: ButtonType.ToggleButton, icon: "pallet", toolType:"vcent", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, { title: "Align", toolTip: "Alignment", btnType: ButtonType.MultiToggleButton, toolType:"alignment", ignoreClick: true, subMenu: [ { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }}, { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - ] - }, + ]}, { title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}}, { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", toolType:"noAutoLink", expertMode:true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}}, // { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", scripts: {onClick:: 'toggleStrikethrough()'}}, diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 33886e791..8df5740fa 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -2,18 +2,17 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { IconButton } from 'browndash-components'; -import { action, computed, observable, reaction } from 'mobx'; +import { action, computed, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { FaUndo } from 'react-icons/fa'; -import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols'; import { InkField } from '../../fields/InkField'; import { RichTextField } from '../../fields/RichTextField'; import { ScriptField } from '../../fields/ScriptField'; -import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; +import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { GetEffectiveAcl } from '../../fields/util'; -import { aggregateBounds, emptyFunction, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils'; +import { emptyFunction, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils'; import { Docs } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { DocumentManager } from '../util/DocumentManager'; @@ -36,6 +35,7 @@ import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { ImageBox } from './nodes/ImageBox'; import React = require('react'); import _ = require('lodash'); +import { DateField } from '../../fields/DateField'; @observer export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> { @@ -46,11 +46,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P private _linkBoxHeight = 20 + 3; // link button height + margin private _titleHeight = 20; private _resizeUndo?: UndoManager.Batch; - private _offX = 0; - private _offY = 0; // offset from click pt to inner edge of resize border - private _snapX = 0; - private _snapY = 0; // last snapped location of resize border - private _dragHeights = new Map(); + private _offset = { x: 0, y: 0 }; // offset from click pt to inner edge of resize border + private _snapPt = { x: 0, y: 0 }; // last snapped location of resize border private _inkDragDocs: { doc: Doc; x: number; y: number; width: number; height: number }[] = []; @observable private _accumulatedTitle = ''; @@ -479,29 +476,24 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P DocumentView.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them this._resizeHdlId = e.currentTarget.className; const bounds = e.currentTarget.getBoundingClientRect(); - this._offX = this._resizeHdlId.toLowerCase().includes('left') ? bounds.right - e.clientX : bounds.left - e.clientX; - this._offY = this._resizeHdlId.toLowerCase().includes('top') ? bounds.bottom - e.clientY : bounds.top - e.clientY; + this._offset = { x: this._resizeHdlId.toLowerCase().includes('left') ? bounds.right - e.clientX : bounds.left - e.clientX, y: this._resizeHdlId.toLowerCase().includes('top') ? bounds.bottom - e.clientY : bounds.top - e.clientY }; this._resizeUndo = UndoManager.StartBatch('drag resizing'); - this._snapX = e.pageX; - this._snapY = e.pageY; - const ffviewSet = new Set(); - SelectionManager.Views().forEach(docView => { - docView.CollectionFreeFormView && ffviewSet.add(docView.CollectionFreeFormView); - this._dragHeights.set(docView.layoutDoc, { start: NumCast(docView.rootDoc._height), lowest: NumCast(docView.rootDoc._height) }); - }); - Array.from(ffviewSet).map(ffview => ffview.dragStarting(false, false)); + this._snapPt = { x: e.pageX, y: e.pageY }; + SelectionManager.Views().forEach(docView => docView.CollectionFreeFormView?.dragStarting(false, false)); }; + _lock: any; onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => { const first = SelectionManager.Views()[0]; const effectiveAcl = GetEffectiveAcl(first.rootDoc); if (!(effectiveAcl == AclAdmin || effectiveAcl == AclEdit || effectiveAcl == AclAugment)) return false; if (!first) return false; - let thisPt = { x: e.clientX - this._offX, y: e.clientY - this._offY }; + let thisPt = { x: e.clientX - this._offset.x, y: e.clientY - this._offset.y }; var fixedAspect = Doc.NativeAspect(first.layoutDoc); + const dragHdl = this._resizeHdlId.split(' ')[0].replace('documentDecorations-', '').replace('Resizer', ''); - const resizeHdl = this._resizeHdlId.split(' ')[0]; - if (fixedAspect && (resizeHdl === 'documentDecorations-bottomRightResizer' || resizeHdl === 'documentDecorations-topLeftResizer')) { + // do snapping of drag point + if (fixedAspect && (dragHdl === 'bottomRight' || dragHdl === 'topLeft')) { // need to generalize for bl and tr drag handles const project = (p: number[], a: number[], b: number[]) => { const atob = [b[0] - a[0], b[1] - a[1]]; @@ -513,173 +505,124 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P return [a[0] + atob[0] * t, a[1] + atob[1] * t]; }; const tl = first.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - const drag = project([e.clientX + this._offX, e.clientY + this._offY], tl, [tl[0] + fixedAspect, tl[1] + 1]); + const drag = project([e.clientX + this._offset.x, e.clientY + this._offset.y], tl, [tl[0] + fixedAspect, tl[1] + 1]); thisPt = DragManager.snapDragAspect(drag, fixedAspect); } else { - thisPt = DragManager.snapDrag(e, -this._offX, -this._offY, this._offX, this._offY); + thisPt = DragManager.snapDrag(e, -this._offset.x, -this._offset.y, this._offset.x, this._offset.y); } - move[0] = thisPt.x - this._snapX; - move[1] = thisPt.y - this._snapY; - this._snapX = thisPt.x; - this._snapY = thisPt.y; - let dragBottom = false, - dragRight = false, - dragBotRight = false, - dragTop = false; - let dXin = 0, - dYin = 0, - dWin = 0, - dHin = 0; - switch (this._resizeHdlId.split(' ')[0]) { - case '': - break; - case 'documentDecorations-topLeftResizer': - dXin = -1; - dYin = -1; - dWin = -move[0]; - dHin = -move[1]; - break; - case 'documentDecorations-topRightResizer': - dWin = move[0]; - dYin = -1; - dHin = -move[1]; - break; - case 'documentDecorations-topResizer': - dYin = -1; - dHin = -move[1]; - dragTop = true; - break; - case 'documentDecorations-bottomLeftResizer': - dXin = -1; - dWin = -move[0]; - dHin = move[1]; - break; - case 'documentDecorations-bottomRightResizer': - dWin = move[0]; - dHin = move[1]; - dragBotRight = true; - break; - case 'documentDecorations-bottomResizer': - dHin = move[1]; - dragBottom = true; - break; - case 'documentDecorations-leftResizer': - dXin = -1; - dWin = -move[0]; - break; - case 'documentDecorations-rightResizer': - dWin = move[0]; - dragRight = true; - break; - } + const { scale, refPt } = this.getResizeVals(thisPt, dragHdl); + // resize selected docs + !this._lock && runInAction(async () => { + this._lock = true; + this._snapPt = thisPt; + e.ctrlKey && (SelectionManager.Views().forEach(docView => !Doc.NativeHeight(docView.props.Document) && docView.toggleNativeDimensions())); + const fixedAspect = SelectionManager.Docs().some(this.hasFixedAspect); + SelectionManager.Views().forEach(docView => + this.resizeView(docView, refPt, scale.x === 1 && fixedAspect ? scale.y : scale.x, + scale.x !== 1 && fixedAspect ? scale.x : scale.y, { dragHdl, ctrlKey:e.ctrlKey })); // prettier-ignore + await new Promise(res => setTimeout(() => res(this._lock = undefined))); + }); // prettier-ignore - const isGroup = first.rootDoc._isGroup ? first.rootDoc : undefined; - const scaleViews = isGroup ? DocListCast(isGroup.data).map(doc => DocumentManager.Instance.getFirstDocumentView(doc)!) : SelectionManager.Views(); - const aggBounds = aggregateBounds(scaleViews.map(view => view.rootDoc) as any, 0, 0); - const refWidth = aggBounds.r - aggBounds.x; - const refHeight = aggBounds.b - aggBounds.y; - const scaleRefPt = first.props - .ScreenToLocalTransform() - .inverse() - .transformPoint( - NumCast(isGroup?._xPadding) + (dXin ? refWidth : 0), // - NumCast(isGroup?._yPadding) + (dYin ? refHeight : 0) - ); - scaleViews.forEach( - action((docView: DocumentView) => { - if (e.ctrlKey && !Doc.NativeHeight(docView.props.Document)) docView.toggleNativeDimensions(); - if (dXin !== 0 || dYin !== 0 || dWin !== 0 || dHin !== 0) { - const doc = docView.rootDoc; - const refCent = docView.props.ScreenToLocalTransform().transformPoint(scaleRefPt[0], scaleRefPt[1]); - - if (doc.nativeHeightUnfrozen && !NumCast(doc.nativeHeight) && doc._nativeWidth !== undefined) { - doc._nativeHeight = (NumCast(doc._height) / NumCast(doc._width, 1)) * docView.nativeWidth; - } - const nwidth = docView.nativeWidth; - const nheight = docView.nativeHeight; - const docwidth = NumCast(doc._width); - let docheight = (hgt => (!hgt || isNaN(hgt) ? 20 : hgt))(NumCast(doc._height) || (nheight / nwidth) * docwidth); - let dW = docwidth * (dWin / refWidth); - let dH = docheight * (dHin / refHeight); - const scale = docView.props.ScreenToLocalTransform().Scale; - const modifyNativeDim = (e.ctrlKey && doc.nativeDimModifiable) || (doc.layout_forceReflow && !dragBottom && !dragTop) || (doc.nativeHeightUnfrozen && (dragBottom || dragTop || e.ctrlKey)); - if (nwidth && nheight) { - if (nwidth / nheight !== docwidth / docheight && !dragBottom && !dragTop) { - docheight = (nheight / nwidth) * docwidth; - } - if (modifyNativeDim && !dragBottom && !dragTop) { - // ctrl key enables modification of the nativeWidth or nativeHeight durin the interaction - if (Math.abs(dW) > Math.abs(dH)) dH = (dW * nheight) / nwidth; - else dW = (dH * nwidth) / nheight; - } - } - let actualdW = Math.max(docwidth + dW * scale, 20); - let actualdH = Math.max(docheight + dH * scale, 20); - let dX = !dWin ? 0 : (scale * refCent[0] * -dWin) / refWidth; - let dY = !dHin ? 0 : (scale * refCent[1] * -dHin) / refHeight; - const preserveNativeDim = !doc._nativeHeightUnfrozen && !doc._nativeDimModifiable; - const fixedAspect = nwidth && nheight && (!doc._layout_fitWidth || preserveNativeDim || e.ctrlKey || doc.nativeHeightUnfrozen || doc.nativeDimModifiable); - if (fixedAspect) { - if ((Math.abs(dW) > Math.abs(dH) && ((!dragBottom && !dragTop) || !modifyNativeDim)) || dragRight) { - if (dragRight && modifyNativeDim) { - if (Doc.NativeWidth(doc)) { - doc._nativeWidth = (actualdW / (docwidth || 1)) * Doc.NativeWidth(doc); - } - } else { - if (!doc._layout_fitWidth || preserveNativeDim) { - actualdH = (nheight / nwidth) * actualdW; - dYin && (dY = -dW * scale * (nheight / nwidth)); - doc._height = actualdH; - } else if (!modifyNativeDim || dragBotRight) { - doc._height = actualdH; - } - } - doc._width = actualdW; - } else { - if ((dragBottom || dragTop) && (modifyNativeDim || (docView.layoutDoc.nativeHeightUnfrozen && docView.layoutDoc._layout_fitWidth))) { - // frozen web pages, PDFs, and some RTFS have frozen nativewidth/height. But they are marked to allow their nativeHeight - // to be explicitly modified with fitWidth and vertical resizing. (ie, with fitWidth they can't grow horizontally to match - // a vertical resize so it makes more sense to change their nativeheight even if the ctrl key isn't used) - doc._nativeHeight = (actualdH / (docheight || 1)) * Doc.NativeHeight(doc); - doc._layout_autoHeight = false; - } else { - if (!doc._layout_fitWidth || preserveNativeDim) { - actualdW = (nwidth / nheight) * actualdH; - dXin && (dX = -dH * scale * (nwidth / nheight)); - doc._width = actualdW; - } else if (!modifyNativeDim || dragBotRight) { - doc._width = actualdW; - } - } - if (!modifyNativeDim) { - actualdH = (nheight / nwidth) * NumCast(doc._width); //, actualdH); - } - doc._height = actualdH; - } - } else { - const rotCtr = [docwidth / 2, docheight / 2]; - const tlRotated = Utils.rotPt(-rotCtr[0], -rotCtr[1], (NumCast(doc._rotation) / 180) * Math.PI); - - const maxHeight = doc.nativeHeightUnfrozen || !nheight ? 0 : Math.max(nheight, NumCast(doc.scrollHeight, NumCast(doc[docView.LayoutFieldKey + '_scrollHeight']))) * docView.NativeDimScaling(); - dH && (doc._height = actualdH > maxHeight && maxHeight ? maxHeight : actualdH); - dW && (doc._width = actualdW); - dH && (doc._layout_autoHeight = false); - - const rotCtr2 = [NumCast(doc._width) / 2, NumCast(doc._height) / 2]; - const tlRotated2 = Utils.rotPt(-rotCtr2[0], -rotCtr2[1], (NumCast(doc._rotation) / 180) * Math.PI); - doc.x = NumCast(doc.x) + tlRotated.x + rotCtr[0] - (tlRotated2.x + rotCtr2[0]); // doc shifts by amount topleft moves because rotation is about center of doc - doc.y = NumCast(doc.y) + tlRotated.y + rotCtr[1] - (tlRotated2.y + rotCtr2[1]); - } - doc.x = NumCast(doc.x) + dX; - doc.y = NumCast(doc.y) + dY; - doc._layout_modificationDate = new DateField(); + return false; + }; + + // + // determines how much to resize, and determines the resize reference point + // + getResizeVals = (thisPt: { x: number; y: number }, dragHdl: string) => { + const [w, h] = [this.Bounds.r - this.Bounds.x, this.Bounds.b - this.Bounds.y]; + const [moveX, moveY] = [thisPt.x - this._snapPt.x, thisPt.y - this._snapPt.y]; + switch (dragHdl) { + case 'topLeft': return { scale: { x: 1 - moveX / w, y: 1 -moveY / h }, refPt: [this.Bounds.r, this.Bounds.b] }; + case 'topRight': return { scale: { x: 1 + moveX / w, y: 1 -moveY / h }, refPt: [this.Bounds.x, this.Bounds.b] }; + case 'top': return { scale: { x: 1, y: 1 -moveY / h }, refPt: [this.Bounds.x, this.Bounds.b] }; + case 'left': return { scale: { x: 1 - moveX / w, y: 1 }, refPt: [this.Bounds.r, this.Bounds.y] }; + case 'bottomLeft': return { scale: { x: 1 - moveX / w, y: 1 + moveY / h }, refPt: [this.Bounds.r, this.Bounds.y] }; + case 'right': return { scale: { x: 1 + moveX / w, y: 1 }, refPt: [this.Bounds.x, this.Bounds.y] }; + case 'bottomRight':return { scale: { x: 1 + moveX / w, y: 1 + moveY / h }, refPt: [this.Bounds.x, this.Bounds.y] }; + case 'bottom': return { scale: { x: 1, y: 1 + moveY / h }, refPt: [this.Bounds.x, this.Bounds.y] }; + default: return { scale: { x: 1, y: 1 }, refPt: [this.Bounds.x, this.Bounds.y] }; + } // prettier-ignore + }; + + // + // determines if anything being dragged directly or via a group has a fixed aspect ratio (in which case we resize uniformly) + // + hasFixedAspect = (doc: Doc): boolean => (doc.isGroup ? DocListCast(doc.data).some(this.hasFixedAspect) : !BoolCast(doc.layout_nativeDimEditable)); + + // + // resize a single DocumentView about the specified reference point, possibly setting/updating the native dimensions of the Doc + // + resizeView = (docView: DocumentView, refPt: number[], scaleX: number, scaleY: number, opts: { dragHdl: string; ctrlKey: boolean }) => { + const doc = docView.rootDoc; + if (doc.isGroup) { + DocListCast(doc.data) + .map(member => DocumentManager.Instance.getDocumentView(member, docView)!) + .forEach(member => this.resizeView(member, refPt, scaleX, scaleY, opts)); + doc.xPadding = NumCast(doc.xPadding) * scaleX; + doc.yPadding = NumCast(doc.yPadding) * scaleY; + } else { + const doc = docView.rootDoc; + const refCent = docView.props.ScreenToLocalTransform().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)]; + + const modifyNativeDim = + (opts.ctrlKey && doc.layout_nativeDimEditable) || // e.g., PDF or web page + (doc.layout_reflowHorizontal && opts.dragHdl !== 'bottom' && opts.dragHdl !== 'top') || // eg rtf or some web pages + (doc.layout_reflowVertical && (opts.dragHdl === 'bottom' || opts.dragHdl === 'top' || opts.ctrlKey)); // eg rtf, web, pdf + if (nwidth && nheight && !modifyNativeDim) { + // eg., dragging right resizer on PDF -- enforce native dimensions because not expliclty overridden with ctrl or bottom resize drag + scaleX === 1 ? (scaleX = scaleY) : (scaleY = scaleX); + } + + if (['right', 'left'].includes(opts.dragHdl) && modifyNativeDim && Doc.NativeWidth(doc)) { + const setData = Doc.NativeWidth(Doc.GetProto(doc)) === doc.nativeWidth; + doc.nativeWidth = scaleX * Doc.NativeWidth(doc); + if (setData) Doc.SetNativeWidth(Doc.GetProto(doc), NumCast(doc.nativeWidth)); + if (doc.layout_reflowVertical && !NumCast(doc.nativeHeight)) { + doc._nativeHeight = (initHeight / initWidth) * nwidth; // initializes the nativeHeight for a PDF } - const val = this._dragHeights.get(docView.layoutDoc); - if (val) this._dragHeights.set(docView.layoutDoc, { start: val.start, lowest: Math.min(val.lowest, NumCast(docView.layoutDoc._height)) }); - }) + } + if (['bottom', 'top'].includes(opts.dragHdl) && modifyNativeDim && Doc.NativeHeight(doc)) { + const setData = Doc.NativeHeight(Doc.GetProto(doc)) === doc.nativeHeight; + doc._nativeHeight = scaleY * Doc.NativeHeight(doc); + if (setData) Doc.SetNativeHeight(Doc.GetProto(doc), NumCast(doc._nativeHeight)); + } + + doc._width = NumCast(doc._width) * scaleX; + doc._height = NumCast(doc._height) * scaleY; + const { deltaX, deltaY } = this.realignRefPt(doc, refCent, initWidth, initHeight); + doc.x = NumCast(doc.x) + deltaX; + doc.y = NumCast(doc.y) + deltaY; + + doc._layout_modificationDate = new DateField(); + scaleY !== 1 && (doc._layout_autoHeight = undefined); + } + }; + + // This realigns the doc's resize reference point with where it was before resizing it. + // This is needed, because the transformation for doc's with a rotation is screwy: + // the top left of the doc is the 'origin', but the rotation happens about the center of the Doc. + // So resizing a rotated doc will cause it to shift -- this counteracts that shift by determine how + // the reference points shifted, and returning a translation to restore the reference point. + realignRefPt = (doc: Doc, refCent: number[], initWidth: number, initHeight: number) => { + const refCentPct = [refCent[0] / initWidth, refCent[1] / initHeight]; + const rotRefStart = Utils.rotPt( + refCent[0] - initWidth / 2, // rotate reference pointe before scaling + refCent[1] - initHeight / 2, + (NumCast(doc._rotation) / 180) * Math.PI ); - return false; + const rotRefEnd = Utils.rotPt( + refCentPct[0] * NumCast(doc._width) - NumCast(doc._width) / 2, // rotate reference point after scaling + refCentPct[1] * NumCast(doc._height) - NumCast(doc._height) / 2, + (NumCast(doc._rotation) / 180) * Math.PI + ); + return { + deltaX: rotRefStart.x + initWidth / 2 - (rotRefEnd.x + NumCast(doc._width) / 2), // + deltaY: rotRefStart.y + initHeight / 2 - (rotRefEnd.y + NumCast(doc._height) / 2), + }; }; @action @@ -691,10 +634,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P SnappingManager.clearSnapLines(); // detect layout_autoHeight gesture and apply - SelectionManager.Views() - .map(docView => ({ doc: docView.layoutDoc, hgts: this._dragHeights.get(docView.layoutDoc) })) - .filter(pair => pair.hgts && pair.hgts.lowest < pair.hgts.start && pair.hgts.lowest <= 20) - .forEach(pair => (pair.doc._layout_autoHeight = true)); + SelectionManager.Docs().forEach(doc => NumCast(doc._height) < 20 && (doc._layout_autoHeight = true)); //need to change points for resize, or else rotation/control points will fail. this._inkDragDocs .map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] })) diff --git a/src/client/views/InkControlPtHandles.tsx b/src/client/views/InkControlPtHandles.tsx index 0d7f7ebd8..e5141b7f4 100644 --- a/src/client/views/InkControlPtHandles.tsx +++ b/src/client/views/InkControlPtHandles.tsx @@ -12,6 +12,7 @@ import { UndoManager } from '../util/UndoManager'; import { Colors } from './global/globalEnums'; import { InkingStroke } from './InkingStroke'; import { InkStrokeProperties } from './InkStrokeProperties'; +import { SnappingManager } from '../util/SnappingManager'; export interface InkControlProps { inkDoc: Doc; @@ -190,6 +191,7 @@ export class InkEndPtHandles extends React.Component { @action dragRotate = (e: React.PointerEvent, pt1: () => { X: number; Y: number }, pt2: () => { X: number; Y: number }) => { + SnappingManager.SetIsDragging(true); setupMoveUpEvents( this, e, @@ -211,6 +213,7 @@ export class InkEndPtHandles extends React.Component { return false; }), action(() => { + SnappingManager.SetIsDragging(false); this.props.inkView.controlUndo?.end(); this.props.inkView.controlUndo = undefined; UndoManager.FilterBatches(['stroke', 'x', 'y', 'width', 'height']); @@ -237,8 +240,8 @@ export class InkEndPtHandles extends React.Component { ); return ( - {hdl('start', this.props.startPt(), (e: React.PointerEvent) => this.dragRotate(e, this.props.startPt, this.props.endPt))} - {hdl('end', this.props.endPt(), (e: React.PointerEvent) => this.dragRotate(e, this.props.endPt, this.props.startPt))} + {hdl('start', this.props.startPt(), e => this.dragRotate(e, this.props.startPt, this.props.endPt))} + {hdl('end', this.props.endPt(), e => this.dragRotate(e, this.props.endPt, this.props.startPt))} ); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index a6f0b9e84..5bed0f923 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -252,6 +252,7 @@ export class MainView extends React.Component { fa.faShare, fa.faTaxi, fa.faDownload, + fa.faPallet, fa.faExpandArrowsAlt, fa.faAmbulance, fa.faLayerGroup, diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 81453c0b8..c2586fb4b 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -295,7 +295,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { const aspect = Doc.NativeAspect(layout, undefined, true); const width = () => this.lookupPixels(layout); const height = () => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); - const docwidth = () => (layout._layout_forceReflow ? width() : Math.min(height() * aspect, width())); + const docwidth = () => (layout._layout_reflowHorizontal ? width() : Math.min(height() * aspect, width())); const docheight = () => Math.min(docwidth() / aspect, height()); const dxf = () => this.lookupIndividualTransform(layout) diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 04cfc5456..249c3551b 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -292,7 +292,7 @@ export class CollectionMultirowView extends CollectionSubView() { const height = () => this.lookupPixels(layout); const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); const docheight = () => Math.min(width() / aspect, height()); - const docwidth = () => (layout._layout_forceReflow ? width() : Math.min(width(), docheight() * aspect)); + const docwidth = () => (layout._layout_reflowHorizontal ? width() : Math.min(width(), docheight() * aspect)); const dxf = () => this.lookupIndividualTransform(layout) .translate(-NumCast(Document._xMargin) - (width() - docwidth()) / 2, -NumCast(Document._yMargin) - (height() - docheight()) / 2) diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index c690b8623..3af523d73 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -181,16 +181,22 @@ ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highligh map.get(attr)?.setDoc?.(); }); -type attrname = 'noAutoLink' | 'dictation' | 'bold' | 'italics' | 'underline' | 'left' | 'center' | 'right' | 'bullet' | 'decimal'; +type attrname = 'noAutoLink' | 'dictation' | 'bold' | 'italics' | 'underline' | 'left' | 'center' | 'right' | 'vcent' | 'bullet' | 'decimal'; type attrfuncs = [attrname, { checkResult: () => boolean; toggle: () => any }]; ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?: boolean) { const textView = RichTextMenu.Instance?.TextView; const editorView = textView?.EditorView; // prettier-ignore - const alignments:attrfuncs[] = (['left','right','center'] as ("left"|"center"|"right")[]).map((where) => - [ where, { checkResult: () =>(editorView ? (RichTextMenu.Instance.textAlign ===where): (Doc.UserDoc().textAlign ===where) ? true:false), - toggle: () => (editorView?.state ? RichTextMenu.Instance.align(editorView, editorView.dispatch, where):(Doc.UserDoc().textAlign = where))}]); + const alignments:attrfuncs[] = (['left','right','center','vcent'] as ("left"|"center"|"right"|"vcent")[]).map((where) => + [ where, { checkResult: () =>(editorView ? (where === 'vcent' ? SelectionManager.Docs().some(doc => doc.layout_centered): + (RichTextMenu.Instance.textAlign === where)): + where === 'vcent' ? BoolCast(Doc.UserDoc().layout_centered): + (Doc.UserDoc().textAlign ===where) ? true:false), + toggle: () => (editorView?.state ? (where === 'vcent' ? SelectionManager.Docs().forEach(doc => doc.layout_centered = !doc.layout_centered): + RichTextMenu.Instance.align(editorView, editorView.dispatch, where)): + where === 'vcent' ? Doc.UserDoc().layout_centered = !Doc.UserDoc().layout_centered: + (Doc.UserDoc().textAlign = where))}]); // prettier-ignore // prettier-ignore const listings:attrfuncs[] = (['bullet','decimal'] as attrname[]).map(list => [ list, { checkResult: () => (editorView ? RichTextMenu.Instance.getActiveListStyle() === list:false), diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index a05d6c904..582a5518a 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -62,7 +62,7 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent this.Y; // prettier-ignore w_Z = () => this.Z; // prettier-ignore w_ZIndex = () => this.ZIndex ?? NumCast(this.props.Document.zIndex); // prettier-ignore - w_Rot = () => this.Rotation ?? NumCast(this.props.Document._rotation); // prettier-ignore + w_Rotation = () => this.Rotation ?? NumCast(this.props.Document._rotation); // prettier-ignore w_Opacity = () => this.Opacity; // prettier-ignore w_BackgroundColor = () => this.BackgroundColor ?? Cast(this.props.Document._backgroundColor, 'string', null); // prettier-ignore w_Color = () => this.Color ?? Cast(this.props.Document._color, 'string', null); // prettier-ignore diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 299494c83..b3f813eda 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -115,8 +115,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { layoutDoc: this.layoutDoc, records: this.records, axes: this.axes, - height: (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9, - width: this.props.PanelWidth() * 0.9, + height: (this.props.PanelHeight() * (this.props.NativeDimScaling?.() || 1) - 32) /* height of 'change view' button */ * 0.9, + width: this.props.PanelWidth() * (this.props.NativeDimScaling?.() || 1) * 0.9, margin: { top: 10, right: 25, bottom: 75, left: 45 }, }; if (!this.records.length) return 'no data/visualization'; @@ -133,6 +133,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { }; render() { + const scale = this.props.NativeDimScaling?.() || 1; + return !this.records.length ? ( // displays how to get data into the DataVizBox if its empty
To create a DataViz box, either import / drag a CSV file into your canvas or copy a data table and use the command 'ctrl + p' to bring the data table to your canvas.
@@ -141,6 +143,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { className="dataViz" style={{ pointerEvents: this.props.isContentActive() === true ? 'all' : 'none', + width: `${100 / scale}%`, + height: `${100 / scale}%`, + transform: `scale(${scale})`, + position: 'absolute', }} onWheel={e => e.stopPropagation()} ref={r => diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d1caf0acf..e3d6c3fdf 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1495,7 +1495,7 @@ export class DocumentView extends React.Component { return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this.props.PanelWidth(); } @computed get panelHeight() { - if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.nativeHeightUnfrozen)) { + if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.layout_reflowVertical)) { return Math.min(this.props.PanelHeight(), this.effectiveNativeHeight * this.nativeScaling); } return this.props.PanelHeight(); @@ -1507,7 +1507,7 @@ export class DocumentView extends React.Component { return this.effectiveNativeWidth && this.effectiveNativeHeight && Math.abs(this.Xshift) < 0.001 && - (!this.layoutDoc.nativeHeightUnfrozen || (!this.layout_fitWidth && this.effectiveNativeHeight * this.nativeScaling <= this.props.PanelHeight())) + (!this.layoutDoc.layout_reflowVertical || (!this.layout_fitWidth && this.effectiveNativeHeight * this.nativeScaling <= this.props.PanelHeight())) ? Math.max(0, (this.props.PanelHeight() - this.effectiveNativeHeight * this.nativeScaling) / 2) : 0; } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index bde1d5fa4..185c6553a 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -347,7 +347,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']); const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth; - const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth + PDFBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth; + const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth + PDFBox.sidebarResizerWidth : 0) + NumCast(this.layoutDoc._width)) / NumCast(this.layoutDoc._width); const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); if (preview) { this._previewNativeWidth = nativeWidth * sideratio; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index a452b1cdd..d9ea48c3b 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -707,10 +707,10 @@ export class WebBox extends ViewBoxAnnotatableComponent { - const nw = !this.layoutDoc.layout_forceReflow ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.NativeDimScaling?.() || 1); - this.layoutDoc.layout_forceReflow = !nw; + const nw = !this.layoutDoc.layout_reflowHorizontal ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.NativeDimScaling?.() || 1); + this.layoutDoc.layout_reflowHorizontal = !nw; if (nw) { Doc.SetInPlace(this.layoutDoc, this.fieldKey + '_nativeWidth', nw, true); } @@ -872,13 +872,13 @@ export class WebBox extends ViewBoxAnnotatableComponent { var nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']); if (!nativeWidth) { - const defaultNativeWidth = this.rootDoc[this.fieldKey] instanceof WebField ? 850 : NumCast(this.Document._width); + const defaultNativeWidth = NumCast(this.rootDoc.nativeWidth, this.rootDoc[this.fieldKey] instanceof WebField ? 850 : NumCast(this.Document._width)); Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(this.dataDoc) || defaultNativeWidth); Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || (NumCast(this.Document._height) / NumCast(this.Document._width)) * defaultNativeWidth); nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']); } const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth; - const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth + WebBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth; + const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth + WebBox.sidebarResizerWidth : 0) + NumCast(this.layoutDoc.width)) / NumCast(this.layoutDoc.width); const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); if (preview) { this._previewNativeWidth = nativeWidth * sideratio; @@ -890,6 +890,7 @@ export class WebBox extends ViewBoxAnnotatableComponent e.stopPropagation()} style={{ - width: !this.layoutDoc.layout_forceReflow ? NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']) || `100%` : '100%', + width: !this.layoutDoc.layout_reflowHorizontal ? NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']) || `100%` : '100%', transform: `scale(${this.zoomScaling()}) translate(${-NumCast(this.layoutDoc.freeform_panX)}px, ${-NumCast(this.layoutDoc.freeform_panY)}px)`, }}> {this._hackHide ? null : this.urlContent} diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 9ab3189a6..a80c1e030 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -704,14 +704,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + const defaultSidebar = 250; const prevWidth = 1 - this.sidebarWidth() / Number(getComputedStyle(this._ref.current!).width.replace('px', '')); if (preview) this._showSidebar = true; else { this.layoutDoc[this.SidebarKey + '_freeform_scale_max'] = 1; - this.layoutDoc._layout_showSidebar = (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? '50%' : '0%') !== '0%'; + this.layoutDoc._layout_showSidebar = + (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? `${(defaultSidebar / (NumCast(this.layoutDoc._width) + defaultSidebar)) * 100}%` : '0%') !== '0%'; } - this.layoutDoc._width = !preview && this.SidebarShown ? NumCast(this.layoutDoc._width) * 2 : Math.max(20, NumCast(this.layoutDoc._width) * prevWidth); + this.layoutDoc._width = !preview && this.SidebarShown ? NumCast(this.layoutDoc._width) + defaultSidebar : Math.max(20, NumCast(this.layoutDoc._width) * prevWidth); }; sidebarDown = (e: React.PointerEvent) => { const batch = UndoManager.StartBatch('toggle sidebar'); diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 6dece87b5..e91fcd858 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1295,17 +1295,11 @@ export namespace Doc { layoutDoc._freeform_scale = NumCast(layoutDoc._freeform_scale, 1) * contentScale; layoutDoc._nativeWidth = undefined; layoutDoc._nativeHeight = undefined; - layoutDoc._layout_forceReflow = undefined; - layoutDoc._nativeHeightUnfrozen = undefined; - layoutDoc._nativeDimModifiable = undefined; } else { layoutDoc._layout_autoHeight = false; if (!Doc.NativeWidth(layoutDoc)) { layoutDoc._nativeWidth = NumCast(layoutDoc._width, panelWidth); layoutDoc._nativeHeight = NumCast(layoutDoc._height, panelHeight); - layoutDoc._layout_forceReflow = true; - layoutDoc._nativeHeightUnfrozen = true; - layoutDoc._nativeDimModifiable = true; } } }); -- cgit v1.2.3-70-g09d2 From a1bd5f7bce9aa1e9cb0d1194789fc482472465bc Mon Sep 17 00:00:00 2001 From: bobzel Date: Sat, 25 Nov 2023 23:02:21 -0500 Subject: changed Slide template to write to 'hero' not 'data' to avoid conflict with 'data' being used already for the template parts. fixed freeform view to read _width/_height to get template values when present for panning beyond edge. Made CollectionSubView read datafield from dataDoc which is where template writes go. fixed docview dragging to use its own view unless multi-dragging. turnded off user-select in overlay view which made repl viewer title selectable. fixed crash on rebuilding db cause by myOverlay and myPublished not yet existing. --- src/client/util/CurrentUserUtils.ts | 6 +++--- src/client/views/OverlayView.scss | 1 + src/client/views/collections/CollectionSubView.tsx | 2 +- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/fields/Doc.ts | 4 ++-- 6 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src/client/util/CurrentUserUtils.ts') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index ac506e2d6..18c7a1fb6 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -67,7 +67,7 @@ export class CurrentUserUtils { templateOpts: { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, isSystem: true }, template: (opts:DocumentOptions) => Docs.Create.MultirowDocument( [ - Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, isSystem: true }), + Docs.Create.MulticolumnDocument([], { title: "hero", _height: 200, isSystem: true }), Docs.Create.TextDocument("", { title: "text", _layout_fitWidth:true, _height: 100, isSystem: true, _text_fontFamily: StrCast(Doc.UserDoc().fontFamily), _text_fontSize: StrCast(Doc.UserDoc().fontSize) }) ], opts) }, @@ -97,7 +97,7 @@ export class CurrentUserUtils { const reqdOpts:DocumentOptions = { title: "Experimental Tools", _xMargin: 0, _layout_showTitle: "title", _chromeHidden: true, - _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _forceActive: true, isSystem: true, + _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, isSystem: true, _forceActive: true, _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true, }; const reqdScripts = { dropConverter : "convertToButtons(dragData)" }; @@ -589,7 +589,7 @@ export class CurrentUserUtils { }) static createToolButton = (opts: DocumentOptions) => Docs.Create.FontIconDocument({ - btnType: ButtonType.ToolButton, _forceActive: true, _layout_hideContextMenu: true, + btnType: ButtonType.ToolButton, _layout_hideContextMenu: true, _dropPropertiesToRemove: new List([ "_layout_hideContextMenu"]), /*_nativeWidth: 40, _nativeHeight: 40, */ _width: 40, _height: 40, isSystem: true, ...opts, }) diff --git a/src/client/views/OverlayView.scss b/src/client/views/OverlayView.scss index 9b10d1cf7..33a297fd4 100644 --- a/src/client/views/OverlayView.scss +++ b/src/client/views/OverlayView.scss @@ -6,6 +6,7 @@ height: 100vh; z-index: 1001; // shouold be greater than LightboxView's z-index so that link lines and the presentation mini player appear /* background-color: pink; */ + user-select: none; } .overlayWindow-outerDiv { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 328b060c4..9626f06ca 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -67,7 +67,7 @@ export function CollectionSubView(moreProps?: X) { // 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' @computed get dataField() { - return this.layoutDoc[this.props.fieldKey]; + return this.dataDoc[this.props.fieldKey]; // this used to be 'layoutDoc', but then template fields will get ignored since the template is not a proto of the layout. hopefully nothing depending on the previous code. } @computed get childLayoutPairs(): { layout: Doc; data: Doc }[] { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a6b2da5f7..2e66c9012 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -994,7 +994,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).filter(doc => doc instanceof Doc); const measuredDocs = docs - .map(doc => ({ pos: { x: NumCast(doc.x), y: NumCast(doc.y) }, size: { width: NumCast(doc.width), height: NumCast(doc.height) } })) + .map(doc => ({ pos: { x: NumCast(doc.x), y: NumCast(doc.y) }, size: { width: NumCast(doc._width), height: NumCast(doc._height) } })) .filter(({ pos, size }) => pos && size) .map(({ pos, size }) => ({ pos: pos!, size: size! })); if (measuredDocs.length) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 0d6b88392..ef2736b6d 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -405,7 +405,7 @@ export class DocumentViewInternal extends DocComponent dv.docView?._mainCont.current); - const selected = views.some(dv => dv.rootDoc === this.Document) ? views : [this.props.DocumentView()]; + const selected = views.length > 1 && views.some(dv => dv.rootDoc === this.Document) ? views : [this.props.DocumentView()]; const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.rootDoc)); const [left, top] = this.props.ScreenToLocalTransform().scale(this.NativeDimScaling).inverse().transformPoint(0, 0); dragData.offset = this.props diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index e91fcd858..368aaa5db 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -147,8 +147,8 @@ export class Doc extends RefField { public static get MyTopBarBtns() { return DocCast(Doc.UserDoc().myTopBarBtns); } // prettier-ignore public static get MyRecentlyClosed() { return DocCast(Doc.UserDoc().myRecentlyClosed); } // prettier-ignore public static get MyTrails() { return DocCast(Doc.ActiveDashboard?.myTrails); } // prettier-ignore - public static get MyOverlayDocs() { return DocListCast(Doc.ActiveDashboard?.myOverlayDocs ?? DocCast(Doc.UserDoc().myOverlayDocs).data); } // prettier-ignore - public static get MyPublishedDocs() { return DocListCast(Doc.ActiveDashboard?.myPublishedDocs ?? DocCast(Doc.UserDoc().myPublishedDocs).data); } // prettier-ignore + public static get MyOverlayDocs() { return DocListCast(Doc.ActiveDashboard?.myOverlayDocs ?? DocCast(Doc.UserDoc().myOverlayDocs)?.data); } // prettier-ignore + public static get MyPublishedDocs() { return DocListCast(Doc.ActiveDashboard?.myPublishedDocs ?? DocCast(Doc.UserDoc().myPublishedDocs)?.data); } // prettier-ignore public static get MyDashboards() { return DocCast(Doc.UserDoc().myDashboards); } // prettier-ignore public static get MyTemplates() { return DocCast(Doc.UserDoc().myTemplates); } // prettier-ignore public static get MyImports() { return DocCast(Doc.UserDoc().myImports); } // prettier-ignore -- cgit v1.2.3-70-g09d2 From ba3b3f6f261074bd3f35012bde8730f5d4a36905 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 29 Nov 2023 10:02:34 -0500 Subject: numerous changes to fix bugs and to fix/remove old or hacky code. fixed doc dec resizing. moving this.rootDoc => this.Document . fixing template artifacts. --- src/client/documents/Documents.ts | 19 +- src/client/util/CurrentUserUtils.ts | 96 +-- src/client/util/Scripting.ts | 4 +- src/client/views/DashboardView.tsx | 2 +- src/client/views/DocComponent.tsx | 16 +- src/client/views/DocumentButtonBar.tsx | 14 +- src/client/views/DocumentDecorations.tsx | 18 +- src/client/views/GlobalKeyHandler.ts | 4 +- src/client/views/MainView.tsx | 6 +- src/client/views/MarqueeAnnotator.tsx | 26 +- src/client/views/PropertiesButtons.tsx | 5 +- src/client/views/PropertiesView.tsx | 47 +- src/client/views/StyleProvider.tsx | 9 +- .../views/collections/CollectionDockingView.tsx | 53 +- src/client/views/collections/CollectionMenu.tsx | 824 +-------------------- .../views/collections/CollectionNoteTakingView.tsx | 4 +- .../views/collections/CollectionPileView.tsx | 16 +- .../collections/CollectionStackedTimeline.tsx | 16 +- .../views/collections/CollectionStackingView.scss | 2 +- .../views/collections/CollectionStackingView.tsx | 96 ++- src/client/views/collections/CollectionSubView.tsx | 20 +- .../views/collections/CollectionTimeView.tsx | 4 +- .../views/collections/CollectionTreeView.tsx | 16 +- src/client/views/collections/TabDocView.tsx | 4 +- src/client/views/collections/TreeView.tsx | 13 +- .../CollectionFreeFormLayoutEngines.tsx | 1 + .../CollectionFreeFormPannableContents.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 199 ++--- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../collectionGrid/CollectionGridView.tsx | 5 +- .../collectionLinear/CollectionLinearView.tsx | 8 +- .../CollectionMulticolumnView.scss | 2 +- .../CollectionMulticolumnView.tsx | 39 +- .../CollectionMultirowView.scss | 5 - .../CollectionMultirowView.tsx | 37 +- .../collectionSchema/CollectionSchemaView.tsx | 10 +- .../collectionSchema/SchemaTableCell.tsx | 3 +- src/client/views/global/globalScripts.ts | 8 +- src/client/views/nodes/AudioBox.tsx | 4 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 51 +- src/client/views/nodes/DocumentContentsView.tsx | 23 +- src/client/views/nodes/DocumentView.tsx | 171 +++-- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 121 ++- src/client/views/nodes/FunctionPlotBox.tsx | 6 +- src/client/views/nodes/ImageBox.tsx | 3 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/LinkBox.tsx | 18 +- src/client/views/nodes/MapBox/MapPushpinBox.tsx | 6 +- src/client/views/nodes/PDFBox.tsx | 1 - .../views/nodes/RecordingBox/RecordingBox.tsx | 12 +- src/client/views/nodes/ScreenshotBox.tsx | 4 +- src/client/views/nodes/ScriptingBox.tsx | 6 +- src/client/views/nodes/VideoBox.tsx | 6 +- src/client/views/nodes/WebBox.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 53 +- .../views/nodes/formattedText/RichTextMenu.tsx | 46 +- .../views/nodes/formattedText/RichTextRules.ts | 2 +- src/client/views/nodes/trails/PresBox.tsx | 97 ++- src/client/views/nodes/trails/PresElementBox.tsx | 64 +- src/client/views/pdf/PDFViewer.tsx | 5 +- src/client/views/search/SearchBox.tsx | 2 +- src/fields/Doc.ts | 15 +- src/fields/ScriptField.ts | 26 +- 63 files changed, 798 insertions(+), 1605 deletions(-) (limited to 'src/client/util/CurrentUserUtils.ts') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 029653204..4def19384 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -292,6 +292,7 @@ export class DocumentOptions { childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox layout in tree view) childLayoutString?: string; // template string for collection to use to render its children childDocumentsActive?: BOOLt = new BoolInfo('whether child documents are active when parent is document active'); + childLayoutFitWidth?: BOOLt = new BoolInfo("whether a child doc's fitWith should be overriden by collection"); childDontRegisterViews?: BOOLt = new BoolInfo('whether child document views should be registered so that they can be found when following links, etc'); childHideLinkButton?: BOOLt = new BoolInfo('hide link buttons on all children'); childContextMenuFilters?: List; @@ -1134,7 +1135,7 @@ export namespace Docs { // } export function FreeformDocument(documents: Array, options: DocumentOptions, id?: string) { - const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xPadding: 20, _yPadding: 20, ...options, _type_collection: CollectionViewType.Freeform }, id); + const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _type_collection: CollectionViewType.Freeform }, id); documents.forEach(d => Doc.SetContainer(d, inst)); return inst; } @@ -1217,7 +1218,7 @@ export namespace Docs { } export function FunctionPlotDocument(documents: Array, options?: DocumentOptions) { - return InstanceFromProto(Prototypes.get(DocumentType.FUNCPLOT), new List(documents), { ...(options || {}) }); + return InstanceFromProto(Prototypes.get(DocumentType.FUNCPLOT), new List(documents), { title: 'func plot', ...(options || {}) }); } export function ButtonDocument(options?: DocumentOptions) { @@ -1487,7 +1488,7 @@ export namespace DocUtils { Object.keys(scripts).map(key => { const script = scripts[key]; if (ScriptCast(doc[key])?.script.originalScript !== scripts[key] && script) { - doc[key] = ScriptField.MakeScript(script, { + (key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = ScriptField.MakeScript(script, { self: Doc.name, this: Doc.name, dragData: DragManager.DocumentDragData.name, @@ -1511,7 +1512,7 @@ export namespace DocUtils { const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); if (ScriptCast(cfield)?.script.originalScript !== funcs[key]) { const setFunc = Cast(funcs[key + '-setter'], 'string', null); - doc[key] = funcs[key] ? ComputedField.MakeFunction(funcs[key], { dragData: DragManager.DocumentDragData.name }, { _readOnly_: true }, setFunc) : undefined; + (key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = funcs[key] ? ComputedField.MakeFunction(funcs[key], { dragData: DragManager.DocumentDragData.name }, { _readOnly_: true }, setFunc) : undefined; } }); return doc; @@ -1717,7 +1718,7 @@ export namespace DocUtils { } export function createCustomView(doc: Doc, creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = 'custom', docLayoutTemplate?: Doc) { const templateName = templateSignature.replace(/\(.*\)/, ''); - docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc._isGroup && doc.transcription ? 'transcription' : doc.type), templateSignature); + docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc.isGroup && doc.transcription ? 'transcription' : doc.type), templateSignature); const customName = 'layout_' + templateSignature; const _width = NumCast(doc._width); @@ -1987,9 +1988,9 @@ ScriptingGlobals.add(function makeDelegate(proto: any) { const d = Docs.Create.DelegateDocument(proto, { title: 'child of ' + proto.title }); return d; }); -ScriptingGlobals.add(function generateLinkTitle(self: Doc) { - const link_anchor_1title = self.link_anchor_1 && self.link_anchor_1 !== self ? Cast(self.link_anchor_1, Doc, null)?.title : ''; - const link_anchor_2title = self.link_anchor_2 && self.link_anchor_2 !== self ? Cast(self.link_anchor_2, Doc, null)?.title : ''; - const relation = self.link_relationship || 'to'; +ScriptingGlobals.add(function generateLinkTitle(link: Doc) { + const link_anchor_1title = link.link_anchor_1 && link.link_anchor_1 !== link ? Cast(link.link_anchor_1, Doc, null)?.title : ''; + const link_anchor_2title = link.link_anchor_2 && link.link_anchor_2 !== link ? Cast(link.link_anchor_2, Doc, null)?.title : ''; + const relation = link.link_relationship || 'to'; return `${link_anchor_1title} (${relation}) ${link_anchor_2title}`; }); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 18c7a1fb6..2f2ac2a71 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -284,7 +284,7 @@ export class CurrentUserUtils { treeView_HasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, dropAction:'move', treeView_Type: TreeViewType.outline, backgroundColor: "white", _xMargin: 0, _yMargin: 0, _createDocOnCR: true - }, funcs: {title: 'self.text?.Text'}}, + }, funcs: {title: 'this.text?.Text'}}, ]; emptyThings.forEach(thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs)); @@ -339,7 +339,7 @@ export class CurrentUserUtils { /// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}, hidden?: boolean}[] { - const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target?.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())"; + const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(this.target?.data).filter(doc => !docList(this.target.viewed).includes(doc)).length.toString())"; const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails"; return [ { title: "Dashboards", toolTip: "Dashboards", target: this.setupDashboards(doc, "myDashboards"), ignoreClick: true, icon: "desktop", funcs: {hidden: "IsNoviceMode()"} }, @@ -467,6 +467,7 @@ export class CurrentUserUtils { const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc,DocListCast(myTools?.data)?.length > 1 ? DocListCast(myTools.data)[1]:undefined); const reqdToolOps:DocumentOptions = { title: "My Tools", isSystem: true, ignoreClick: true, layout_boxShadow: "0 0", + layout_explainer: "This is a palette of documents that can be created.", _layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _chromeHidden: true, }; return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdToolOps, [creatorBtns, templateBtns]); @@ -558,7 +559,7 @@ export class CurrentUserUtils { const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton, color: Colors.BLACK, buttonText: "Empty", icon: "trash", isSystem: true, toolTip: "Empty recently closed",}; - DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")}); + DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("this.target")}); if (!Cast(recentlyClosed.contextMenuScripts, listSpec(ScriptField),null)?.find((script) => script.script.originalScript === clearAll("self"))) { recentlyClosed.contextMenuScripts = new List([ScriptField.MakeScript(clearAll("self"))!]) @@ -628,42 +629,42 @@ export class CurrentUserUtils { } static stackTools(): Button[] { return [ - { title: "Center", icon: "align-center", toolTip: "Center Align Stack", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"center", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Center", icon: "align-center", toolTip: "Center Align Stack", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"center", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform ] } static viewTools(): Button[] { return [ - { title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"snaplines", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"grid", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "View All", icon: "object-group", toolTip: "Keep all Docs in View",btnType: ButtonType.ToggleButton, ignoreClick:true, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"snaplines", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"grid", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "View All", icon: "object-group", toolTip: "Keep all Docs in View",btnType: ButtonType.ToggleButton, ignoreClick:true, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform // want the same style as toggle button, but don't want it to act as an actual toggle, so set disableToggle to true, - { title: "Fit All", icon: "arrows-left-right", toolTip: "Fit Docs to View (once)",btnType: ButtonType.ClickButton,ignoreClick:false,expertMode: false, toolType:"fitOnce", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"clusters", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Cards", icon: "brain", toolTip: "Flashcards", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Arrange", icon:"arrow-down-short-wide",toolTip:"Toggle Auto Arrange", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"arrange", funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Fit All", icon: "arrows-left-right", toolTip: "Fit Docs to View (once)",btnType: ButtonType.ClickButton,ignoreClick:false,expertMode: false, toolType:"fitOnce", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"clusters", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Cards", icon: "brain", toolTip: "Flashcards", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Arrange", icon:"arrow-down-short-wide",toolTip:"Toggle Auto Arrange", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"arrange", funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform ] } static textTools():Button[] { return [ - { title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, toolType:"font", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, + { title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, toolType:"font", ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'}, btnList: new List(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]) }, - { title: "Font Size",toolTip: "Font size (%size)", btnType: ButtonType.NumberDropdownButton, toolType:"fontSize", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 6 }, - { title: "Color", toolTip: "Font color (%color)", btnType: ButtonType.ColorButton, icon: "font", toolType:"fontColor",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}}, - { title: "Highlight",toolTip: "Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", toolType:"highlight",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} }, - { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", toolType:"bold", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", toolType:"italics", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", toolType:"underline",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", toolType:"bullet", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", toolType:"decimal", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Vcenter", toolTip: "Vertical center", btnType: ButtonType.ToggleButton, icon: "pallet", toolType:"vcent", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, + { title: "Font Size",toolTip: "Font size (%size)", btnType: ButtonType.NumberDropdownButton, toolType:"fontSize", ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 6 }, + { title: "Color", toolTip: "Font color (%color)", btnType: ButtonType.ColorButton, icon: "font", toolType:"fontColor",ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'}}, + { title: "Highlight",toolTip: "Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", toolType:"highlight",ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} }, + { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", toolType:"bold", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", toolType:"italics", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", toolType:"underline",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", toolType:"bullet", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", toolType:"decimal", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Vcenter", toolTip: "Vertical center", btnType: ButtonType.ToggleButton, icon: "pallet", toolType:"vcent", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, { title: "Align", toolTip: "Alignment", btnType: ButtonType.MultiToggleButton, toolType:"alignment", ignoreClick: true, subMenu: [ - { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }}, - { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, + { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}' }}, + { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, ]}, - { title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}}, - { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", toolType:"noAutoLink", expertMode:true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}}, + { title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'}}, + { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", toolType:"noAutoLink", expertMode:true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}}, // { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", scripts: {onClick:: 'toggleStrikethrough()'}}, // { title: "Superscript", tooltip: "Superscript", btnType: ButtonType.ToggleButton, icon: "superscript", scripts: {onClick:: 'toggleSuperscript()'}}, // { title: "Subscript", tooltip: "Subscript", btnType: ButtonType.ToggleButton, icon: "subscript", scripts: {onClick:: 'toggleSubscript()'}}, @@ -672,15 +673,15 @@ export class CurrentUserUtils { static inkTools():Button[] { return [ - { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", toolType: "pen", scripts: {onClick:'{ return setActiveTool(self.toolType, false, _readOnly_);}' }}, - { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", toolType: "write", scripts: {onClick:'{ return setActiveTool(self.toolType, false, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }}, - { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", toolType: "eraser", scripts: {onClick:'{ return setActiveTool(self.toolType, false, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }}, - { title: "Circle", toolTip: "Circle (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "circle", toolType:GestureUtils.Gestures.Circle, scripts: {onClick:`{ return setActiveTool(self.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(self.toolType, true, _readOnly_);}`} }, - { title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square", toolType:GestureUtils.Gestures.Rectangle, scripts: {onClick:`{ return setActiveTool(self.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(self.toolType, true, _readOnly_);}`} }, - { title: "Line", toolTip: "Line (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "minus", toolType:GestureUtils.Gestures.Line, scripts: {onClick:`{ return setActiveTool(self.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(self.toolType, true, _readOnly_);}`} }, - { title: "Mask", toolTip: "Mask", btnType: ButtonType.ToggleButton, icon: "user-circle",toolType: "inkMask", scripts: {onClick:'{ return setInkProperty(self.toolType, value, _readOnly_);}'}, funcs: {hidden:"IsNoviceMode()" } }, - { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberSliderButton, toolType: "strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(self.toolType, value, _readOnly_);}'}, numBtnMin: 1}, - { title: "Ink", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", toolType: "strokeColor", ignoreClick: true, scripts: {script: '{ return setInkProperty(self.toolType, value, _readOnly_);}'} }, + { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", toolType: "pen", scripts: {onClick:'{ return setActiveTool(this.toolType, false, _readOnly_);}' }}, + { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", toolType: "write", scripts: {onClick:'{ return setActiveTool(this.toolType, false, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }}, + { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", toolType: "eraser", scripts: {onClick:'{ return setActiveTool(this.toolType, false, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }}, + { title: "Circle", toolTip: "Circle (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "circle", toolType:GestureUtils.Gestures.Circle, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} }, + { title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square", toolType:GestureUtils.Gestures.Rectangle, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} }, + { title: "Line", toolTip: "Line (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "minus", toolType:GestureUtils.Gestures.Line, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} }, + { title: "Mask", toolTip: "Mask", btnType: ButtonType.ToggleButton, icon: "user-circle",toolType: "inkMask", scripts: {onClick:'{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"IsNoviceMode()" } }, + { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberSliderButton, toolType: "strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, numBtnMin: 1}, + { title: "Ink", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", toolType: "strokeColor", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'} }, ]; } @@ -709,17 +710,17 @@ export class CurrentUserUtils { { title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, expertMode: false, width: 30, scripts: { onClick: 'pinWithView(altKey)'}, funcs: {hidden: "IsNoneSelected()"}}, { title: "Header", icon: "heading", toolTip: "Doc Titlebar Color", btnType: ButtonType.ColorButton, expertMode: true, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'} }, { title: "Fill", icon: "fill-drip", toolTip: "Fill/Background Color",btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, width: 30, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'}, funcs: {hidden: "IsNoneSelected()"}}, // Only when a document is selected - { title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)'}, scripts: { onClick: '{ return toggleOverlay(_readOnly_); }'}}, // Only when floating document is selected in freeform - { title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 30, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}}, - { title: "Num", icon:"", toolTip: "Frame Number (click to toggle edit mode)", btnType: ButtonType.TextButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}}, - { title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 30, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}}, - { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available - { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: {hidden: `IsExploreMode()`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available - { title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available - { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available - { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available - { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected - { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Schema is selected + { title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(this.toolType, this.expertMode, true)'}, scripts: { onClick: '{ return toggleOverlay(_readOnly_); }'}}, // Only when floating document is selected in freeform + { title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}}, + { title: "Num", icon:"", toolTip: "Frame # (click to toggle edit mode)",btnType: ButtonType.TextButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(this.toolType, this.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}}, + { title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}}, + { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: {hidden: `IsExploreMode()`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available + { title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode, true)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected + { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Schema is selected ]; } @@ -904,7 +905,7 @@ export class CurrentUserUtils { this.setupDocTemplates(doc); // sets up the template menu of templates //this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption DocUtils.AssignDocField(doc, "globalScriptDatabase", (opts) => Docs.Prototypes.MainScriptDocument(), {}); - DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents + DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, _chromeHidden:true, childLayoutFitWidth:false, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards) Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs) @@ -976,6 +977,7 @@ export class CurrentUserUtils { DashboardView.createNewDashboard(undefined, "guest dashboard"); } else { userDoc.activePage = "home"; + userDoc.noviceMode = true; } } return userDoc; diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 70c2e3842..400b63a1c 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -264,6 +264,6 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp } ScriptingGlobals.add(CompileScript); -ScriptingGlobals.add(function runScript(self: Doc, script: ScriptField) { - return script?.script.run({ this: self, self: self }).result; +ScriptingGlobals.add(function runScript(doc: Doc, script: ScriptField) { + return script?.script.run({ this: doc }).result; }); diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 9e2ed7822..2765e95e6 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -370,7 +370,7 @@ export class DashboardView extends React.Component { const freeformDoc = Doc.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: title }, id, 'row'); - Doc.AddDocToList(Doc.MyHeaderBar, 'data', freeformDoc); + Doc.AddDocToList(Doc.MyHeaderBar, 'data', freeformDoc, undefined, undefined, true); dashboardDoc['pane-count'] = 1; freeformDoc.embedContainer = dashboardDoc; dashboardDoc.myOverlayDocs = new List(); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index fdaca8056..61b7a3bff 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -10,6 +10,8 @@ import { DocUtils } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { DocumentView } from './nodes/DocumentView'; import * as React from 'react'; +import { DocumentManager } from '../util/DocumentManager'; +import { CollectionFreeFormView } from './collections/collectionFreeForm'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) export interface DocComponentProps { @@ -26,7 +28,7 @@ export function DocComponent

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

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

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

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

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

{suggestion}

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

Loading layout

'; } + componentDidUpdate(prevProps: Readonly void) | undefined; layout_fieldKey: string }>, prevState: Readonly<{}>, snapshot?: any): void { + Object.keys(prevProps).forEach(pkey => (prevProps as any)[pkey] !== (this.props as any)[pkey] && console.log(pkey + ' ' + (prevProps as any)[pkey] + ' ' + (this.props as any)[pkey])); + } + get dataDoc() { const proto = this.props.DataDoc || Doc.GetProto(this.props.Document); return proto instanceof Promise ? undefined : proto; @@ -170,7 +170,6 @@ export class DocumentContentsView extends React.Component< ]; const list = { ...OmitKeys(this.props, [...docOnlyProps], '').omit, - RootDoc: Cast(this.layoutDoc?.rootDocument, Doc, null) || this.layoutDoc, Document: this.layoutDoc, DataDoc: this.dataDoc, onClick: onClick, @@ -195,7 +194,7 @@ export class DocumentContentsView extends React.Component< // replace HTML with corresponding HTML tag as in: becomes const replacer2 = (match: any, p1: string, offset: any, string: any) => { - return `; + return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.ShowTitle) as Opt; } @computed get NativeDimScaling() { return this.props.NativeDimScaling?.() || 1; @@ -302,13 +302,13 @@ export class DocumentViewInternal extends DocComponent dv.docView?._mainCont.current); - const selected = views.length > 1 && views.some(dv => dv.rootDoc === this.Document) ? views : [this.props.DocumentView()]; - const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.rootDoc)); + const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [this.props.DocumentView()]; + const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.Document)); const [left, top] = this.props.ScreenToLocalTransform().scale(this.NativeDimScaling).inverse().transformPoint(0, 0); dragData.offset = this.props .ScreenToLocalTransform() @@ -417,7 +417,7 @@ export class DocumentViewInternal extends DocComponent dv.docView!._mainCont.current!), dragData, @@ -430,8 +430,8 @@ export class DocumentViewInternal extends DocComponent { const targetMatch = - Doc.AreProtosEqual(anchor, this.rootDoc) || // anchor is this document, so anchor's properties apply to this document - (DocCast(anchor)?.layout_unrendered && Doc.AreProtosEqual(DocCast(anchor.annotationOn), this.rootDoc)) // the anchor is an layout_unrendered annotation on this document, so anchor properties apply to this document + Doc.AreProtosEqual(anchor, this.Document) || // anchor is this document, so anchor's properties apply to this document + (DocCast(anchor)?.layout_unrendered && Doc.AreProtosEqual(DocCast(anchor.annotationOn), this.Document)) // the anchor is an layout_unrendered annotation on this document, so anchor properties apply to this document ? true : false; return targetMatch && PresBox.restoreTargetDocView(docView, anchor, focusSpeed) ? focusSpeed : undefined; @@ -450,23 +450,22 @@ export class DocumentViewInternal extends DocComponent= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) { let stopPropagate = true; let preventDefault = true; - !this.rootDoc._keepZWhenDragged && this.props.bringToFront(this.rootDoc); + !this.layoutDoc._keepZWhenDragged && this.props.bringToFront(this.Document); if (this._doubleTap) { const defaultDblclick = this.props.defaultDoubleClick?.() || this.Document.defaultDoubleClick; if (this.onDoubleClickHandler?.script) { const { clientX, clientY, shiftKey, altKey, ctrlKey } = e; // or we could call e.persist() to capture variables // prettier-ignore const func = () => this.onDoubleClickHandler.script.run( { - this: this.layoutDoc, - self: this.rootDoc, + this: this.Document, scriptContext: this.props.scriptContext, documentView: this.props.DocumentView(), clientX, clientY, altKey, shiftKey, ctrlKey, value: undefined, }, console.log ); UndoManager.RunInBatch(() => (func().result?.select === true ? this.props.select(false) : ''), 'on double click'); - } else if (!Doc.IsSystem(this.rootDoc) && (defaultDblclick === undefined || defaultDblclick === 'default')) { - UndoManager.RunInBatch(() => LightboxView.Instance.AddDocTab(this.rootDoc, OpenWhere.lightbox), 'double tap'); + } else if (!Doc.IsSystem(this.Document) && (defaultDblclick === undefined || defaultDblclick === 'default')) { + UndoManager.RunInBatch(() => LightboxView.Instance.AddDocTab(this.Document, OpenWhere.lightbox), 'double tap'); SelectionManager.DeselectAll(); Doc.UnBrushDoc(this.props.Document); } else { @@ -488,8 +487,7 @@ export class DocumentViewInternal extends DocComponent UndoManager.RunInBatch(func, 'click ' + this.rootDoc.title); + clickFunc = () => UndoManager.RunInBatch(func, 'click ' + this.Document.title); } else { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) { @@ -516,7 +514,7 @@ export class DocumentViewInternal extends DocComponent (sendToBack ? this.props.DocumentView().props.bringToFront(this.rootDoc, true) : + clickFunc ?? (() => (sendToBack ? this.props.DocumentView().props.bringToFront(this.Document, true) : this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this.props.select(e.ctrlKey||e.shiftKey, e.metaKey))); const waitFordblclick = this.props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick; @@ -538,7 +536,7 @@ export class DocumentViewInternal extends DocComponent { if (DocumentView.LongPress) { - if (this.rootDoc.undoIgnoreFields) { + if (this.Document.undoIgnoreFields) { runInAction(() => (UndoStack.HideInline = !UndoStack.HideInline)); } else { this.props.select(false); @@ -563,10 +561,10 @@ export class DocumentViewInternal extends DocComponent { - const hadOnClick = this.rootDoc.onClick; + const hadOnClick = this.Document.onClick; this.noOnClick(); this.Document.onClick = hadOnClick ? undefined : FollowLinkScript(); this.Document.waitForDoubleClickToClick = hadOnClick ? undefined : 'never'; @@ -653,11 +651,11 @@ export class DocumentViewInternal extends DocComponent { - if (e && this.rootDoc._layout_hideContextMenu && Doc.noviceMode) { + if (e && this.layoutDoc._layout_hideContextMenu && Doc.noviceMode) { e.preventDefault(); e.stopPropagation(); //!this.props.isSelected(true) && SelectionManager.SelectView(this.props.DocumentView(), false); @@ -738,7 +736,7 @@ export class DocumentViewInternal extends DocComponent { - if (this.rootDoc.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && !this.props.isSelected() && SelectionManager.SelectView(this.props.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. + if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && !this.props.isSelected() && SelectionManager.SelectView(this.props.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. setTimeout(() => simulateMouseClick(document.elementFromPoint(e.clientX, e.clientY), e.clientX, e.clientY, e.screenX, e.screenY)); }; if (navigator.userAgent.includes('Macintosh')) { @@ -751,11 +749,9 @@ export class DocumentViewInternal extends DocComponent - cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ documentView: this, this: this.layoutDoc, scriptContext: this.props.scriptContext, self: this.rootDoc }), icon: 'sticky-note' }) + cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ documentView: this, this: this.Document, scriptContext: this.props.scriptContext }), icon: 'sticky-note' }) ); - this.props - .contextMenuItems?.() - .forEach(item => item.label && cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.layoutDoc, scriptContext: this.props.scriptContext, self: this.rootDoc }), icon: item.icon as IconProp })); + this.props.contextMenuItems?.().forEach(item => item.label && cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.Document, scriptContext: this.props.scriptContext }), icon: item.icon as IconProp })); if (!this.props.Document.isFolder) { const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layout_fieldKey)], Doc, null); @@ -765,22 +761,22 @@ export class DocumentViewInternal extends DocComponent LightboxView.Instance.SetLightboxDoc(this.rootDoc), icon: 'external-link-alt' }); } - this.rootDoc.type === DocumentType.PRES && appearanceItems.push({ description: 'Pin', event: () => this.props.pinToPres(this.rootDoc, {}), icon: 'eye' }); + this.Document.type === DocumentType.PRES && appearanceItems.push({ description: 'Pin', event: () => this.props.pinToPres(this.rootDoc, {}), icon: 'eye' }); !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); !appearance && appearanceItems.length && cm.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'compass' }); - if (!Doc.IsSystem(this.rootDoc) && this.rootDoc.type !== DocumentType.PRES && ![CollectionViewType.Docking, CollectionViewType.Tree].includes(this.rootDoc._type_collection as any)) { + if (!Doc.IsSystem(this.Document) && this.Document.type !== DocumentType.PRES && ![CollectionViewType.Docking, CollectionViewType.Tree].includes(this.Document._type_collection as any)) { const existingOnClick = cm.findByDescription('OnClick...'); const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; if (this.props.bringToFront !== emptyFunction) { const zorders = cm.findByDescription('ZOrder...'); const zorderItems: ContextMenuProps[] = zorders && 'subitems' in zorders ? zorders.subitems : []; - zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, false)), icon: 'arrow-up' }); - zorderItems.push({ description: 'Send to Back', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, true)), icon: 'arrow-down' }); + zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.Document, false)), icon: 'arrow-up' }); + zorderItems.push({ description: 'Send to Back', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.Document, true)), icon: 'arrow-down' }); zorderItems.push({ - description: !this.rootDoc._keepZDragged ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged', - event: undoBatch(action(() => (this.rootDoc._keepZWhenDragged = !this.rootDoc._keepZWhenDragged))), + description: !this.layoutDoc._keepZDragged ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged', + event: undoBatch(action(() => (this.layoutDoc._keepZWhenDragged = !this.layoutDoc._keepZWhenDragged))), icon: 'hand-point-up', }); !zorders && cm.addItem({ description: 'Z Order...', addDivider: true, noexpand: true, subitems: zorderItems, icon: 'layer-group' }); @@ -816,7 +812,7 @@ export class DocumentViewInternal extends DocComponent Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: 'concierge-bell' }); moreItems.push({ description: `${this.Document._chromeHidden ? 'Show' : 'Hide'} Chrome`, event: () => (this.Document._chromeHidden = !this.Document._chromeHidden), icon: 'project-diagram' }); @@ -833,9 +829,9 @@ export class DocumentViewInternal extends DocComponent Doc.Zip(this.props.Document) }); - (this.rootDoc._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' }); + (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' }); if (this.props.removeDocument && Doc.ActiveDashboard !== this.props.Document) { // need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions) constantItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' }); @@ -847,8 +843,8 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'keyboard' }); - !Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.props.Document), icon: 'hand-point-right' }); - !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.props.Document[DocData]), icon: 'hand-point-right' }); + !Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.Document), icon: 'hand-point-right' }); + !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.dataDoc), icon: 'hand-point-right' }); let documentationDescription: string | undefined = undefined; let documentationLink: string | undefined = undefined; @@ -902,7 +898,7 @@ export class DocumentViewInternal extends DocComponent this._rootSelected; panelHeight = () => this.props.PanelHeight() - this.headerMargin; @@ -931,7 +927,7 @@ export class DocumentViewInternal extends DocComponent - (link.link_matchEmbeddings ? link.link_anchor_1 === this.rootDoc : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.rootDoc)) || - (link.link_matchEmbeddings ? link.link_anchor_2 === this.rootDoc : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.rootDoc)) || - ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.rootDoc)) || - ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.rootDoc)) + (link.link_matchEmbeddings ? link.link_anchor_1 === this.Document : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.Document)) || + (link.link_matchEmbeddings ? link.link_anchor_2 === this.Document : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.Document)) || + ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.Document)) || + ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.Document)) ); } @computed get allLinks() { TraceMobx(); - return LinkManager.Instance.getAllRelatedLinks(this.rootDoc); + return LinkManager.Instance.getAllRelatedLinks(this.Document); } hideLink = computedFn((link: Doc) => () => (link.link_displayLine = false)); @computed get allLinkEndpoints() { @@ -1020,7 +1015,7 @@ export class DocumentViewInternal extends DocComponent
)); @@ -1143,7 +1138,7 @@ export class DocumentViewInternal extends DocComponent @@ -1191,8 +1186,8 @@ export class DocumentViewInternal extends DocComponent { - if (this.rootDoc.layout_showTitle) { - this.rootDoc._layout_showTitle = field; + if (this.layoutDoc.layout_showTitle) { + this.layoutDoc._layout_showTitle = field; } else if (!this.props.layout_showTitle) { Doc.UserDoc().layout_showTitle = field; } @@ -1216,11 +1211,11 @@ export class DocumentViewInternal extends DocComponent (showTitle.split(';').length !== 1 ? '#' + showTitle : Field.toKeyValueString(this.rootDoc, showTitle.split(';')[0]))} + GetValue={() => (showTitle.split(';').length !== 1 ? '#' + showTitle : Field.toKeyValueString(this.Document, showTitle.split(';')[0]))} SetValue={undoBatch((input: string) => { if (input?.startsWith('#')) { - if (this.rootDoc.layout_showTitle) { - this.rootDoc._layout_showTitle = input?.substring(1); + if (this.layoutDoc.layout_showTitle) { + this.layoutDoc._layout_showTitle = input?.substring(1); } else if (!this.props.layout_showTitle) { Doc.UserDoc().layout_showTitle = input?.substring(1) ?? 'author_date'; } @@ -1246,7 +1241,7 @@ export class DocumentViewInternal extends DocComponent { TraceMobx(); - return !DocCast(this.Document) || GetEffectiveAcl(this.Document[DocData]) === AclPrivate + return !DocCast(this.Document) || GetEffectiveAcl(this.dataDoc) === AclPrivate ? null : this.docContents ?? (
<> - {this._componentView instanceof KeyValueBox ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.rootDoc[Animation], this.rootDoc)} + {this._componentView instanceof KeyValueBox ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} {borderPath?.jsx}
@@ -1377,7 +1372,7 @@ export class DocumentView extends React.Component { private _disposers: { [name: string]: IReactionDisposer } = {}; public clearViewTransition = () => { this.ViewTimer && clearTimeout(this.ViewTimer); - this.rootDoc._viewTransition = undefined; + this.layoutDoc._viewTransition = undefined; }; public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this.docView?.startDragging(x, y, dropAction, hideSource); @@ -1385,15 +1380,15 @@ export class DocumentView extends React.Component { public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => { this.AnimEffectTimer && clearTimeout(this.AnimEffectTimer); - this.rootDoc[Animation] = presEffect; - this.AnimEffectTimer = setTimeout(() => (this.rootDoc[Animation] = undefined), timeInMs); + this.Document[Animation] = presEffect; + this.AnimEffectTimer = setTimeout(() => (this.Document[Animation] = undefined), timeInMs); }; public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => { - this.rootDoc._viewTransition = `${transProp} ${timeInMs}ms`; + this.layoutDoc._viewTransition = `${transProp} ${timeInMs}ms`; if (dataTrans) this.rootDoc._dataTransition = `${transProp} ${timeInMs}ms`; this.ViewTimer && clearTimeout(this.ViewTimer); return (this.ViewTimer = setTimeout(() => { - this.rootDoc._viewTransition = undefined; + this.layoutDoc._viewTransition = undefined; this.rootDoc._dataTransition = 'inherit'; afterTrans?.(); }, timeInMs + 10)); @@ -1421,7 +1416,7 @@ export class DocumentView extends React.Component { DocServer.GetRefField(docId).then(docx => LightboxView.Instance.SetLightboxDoc( (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection - Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(self, self.target)') }, docId) + Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId) ) ); } @@ -1445,16 +1440,16 @@ export class DocumentView extends React.Component { return this.docView?._componentView; } get allLinks() { - return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.rootDoc || link.link_anchor_2 === this.rootDoc); + return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.rootDoc); } get LayoutFieldKey() { return this.docView?.LayoutFieldKey || 'layout'; } @computed get layout_fitWidth() { - return this.docView?._componentView?.layout_fitWidth?.() ?? this.props.layout_fitWidth?.(this.rootDoc) ?? this.layoutDoc?.layout_fitWidth; + return this.docView?._componentView?.layout_fitWidth?.() ?? this.props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.layout_fitWidth; } @computed get anchorViewDoc() { - return this.props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.rootDoc['link_anchor_2']) : this.props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.rootDoc['link_anchor_1']) : undefined; + return this.props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this.props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined; } @computed get hideLinkButton() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkBtn + (this.isSelected() ? ':selected' : '')); @@ -1526,7 +1521,7 @@ export class DocumentView extends React.Component { return this.props.CollectionFreeFormDocumentView?.(); } - public toggleNativeDimensions = () => this.docView && this.rootDoc.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight()); + public toggleNativeDimensions = () => this.docView && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight()); public getBounds = () => { if (!this.docView?.ContentDiv || this.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { return undefined; @@ -1560,7 +1555,7 @@ export class DocumentView extends React.Component { const deiconifyLayout = Cast(this.Document.deiconifyLayout, 'string', null); this.switchViews(deiconifyLayout ? true : false, deiconifyLayout, finalFinished); this.Document.deiconifyLayout = undefined; - this.props.bringToFront(this.rootDoc); + this.props.bringToFront(this.Document); } } @undoBatch @@ -1574,8 +1569,8 @@ export class DocumentView extends React.Component { this.docView && (this.docView._animateScalingTo = 0.1); // shrink doc setTimeout( action(() => { - if (useExistingLayout && custom && this.rootDoc['layout_' + view]) { - this.rootDoc.layout_fieldKey = 'layout_' + view; + if (useExistingLayout && custom && this.Document['layout_' + view]) { + this.Document.layout_fieldKey = 'layout_' + view; } else { this.setCustomView(custom, view); } @@ -1592,6 +1587,7 @@ export class DocumentView extends React.Component { ); }; + layout_fitWidthFunc = (doc: Doc) => BoolCast(this.layout_fitWidth); scaleToScreenSpace = () => (1 / (this.props.NativeDimScaling?.() || 1)) * this.screenToLocalTransform().Scale; docViewPathFunc = () => this.docViewPath; isSelected = () => this.SELECTED; @@ -1600,7 +1596,7 @@ export class DocumentView extends React.Component { else { SelectionManager.SelectView(this, extendSelection); if (focusSelection) { - DocumentManager.Instance.showDocument(this.rootDoc, { + DocumentManager.Instance.showDocument(this.Document, { willZoomCentered: true, zoomScale: 0.9, zoomTime: 500, @@ -1608,6 +1604,7 @@ export class DocumentView extends React.Component { } } }; + ShouldNotScale = () => this.shouldNotScale; NativeWidth = () => this.effectiveNativeWidth; NativeHeight = () => this.effectiveNativeHeight; PanelWidth = () => this.panelWidth; @@ -1622,8 +1619,8 @@ export class DocumentView extends React.Component { @action componentDidMount() { - this.rootDoc[DocViews].add(this); - this._disposers.updateContentsScript = reaction(() => ScriptCast(this.rootDoc.updateContentsScript)?.script?.run({ this: this.rootDoc, self: this.rootDoc }).result, emptyFunction); + this.Document[DocViews].add(this); + this._disposers.updateContentsScript = reaction(() => ScriptCast(this.Document.updateContentsScript)?.script?.run({ this: this.Document }).result, emptyFunction); this._disposers.height = reaction( // increase max auto height if document has been resized to be greater than current max () => NumCast(this.layoutDoc._height), @@ -1636,7 +1633,7 @@ export class DocumentView extends React.Component { } @action componentWillUnmount() { - this.rootDoc[DocViews].delete(this); + this.Document[DocViews].delete(this); Object.values(this._disposers).forEach(disposer => disposer?.()); !BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); } @@ -1662,7 +1659,7 @@ export class DocumentView extends React.Component { console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this.textHtmlOverlay)} />
, { ...(this.htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Zoom } as any as Doc, - this.rootDoc + this.Document )}
@@ -1683,15 +1680,14 @@ export class DocumentView extends React.Component { style={{ transition: 'inherit', // this.props.dataTransition, transform: `translate(${this.centeringX}px, ${this.centeringY}px)`, - width: xshift ?? `${(100 * (this.props.PanelWidth() - this.Xshift * 2)) / this.props.PanelWidth()}%`, - height: this.props.forceAutoHeight - ? undefined - : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(((100 * this.effectiveNativeHeight) / this.effectiveNativeWidth) * this.props.PanelWidth()) / this.props.PanelHeight()}%`), + width: xshift ?? `${this.props.PanelWidth() - this.Xshift * 2}px`, + height: this.props.forceAutoHeight ? undefined : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this.props.PanelWidth()}px`), }}> { NativeDimScaling={this.NativeDimScaling} isSelected={this.isSelected} select={this.select} + layout_fitWidth={this.layout_fitWidthFunc} ScreenToLocalTransform={this.screenToLocalTransform} focus={this.props.focus || emptyFunction} ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))} @@ -1719,7 +1716,7 @@ ScriptingGlobals.add(function deiconifyView(documentView: DocumentView) { }); ScriptingGlobals.add(function deiconifyViewToLightbox(documentView: DocumentView) { - LightboxView.Instance.AddDocTab(documentView.rootDoc, OpenWhere.lightbox, 'layout'); //, 0); + LightboxView.Instance.AddDocTab(documentView.Document, OpenWhere.lightbox, 'layout'); //, 0); }); ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuffix: string) { diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index de5ad1631..ba5370360 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -26,7 +26,6 @@ export enum ButtonType { TextButton = 'textBtn', MenuButton = 'menuBtn', DropdownList = 'dropdownList', - DropdownButton = 'dropdownBtn', ClickButton = 'clickBtn', ToggleButton = 'toggleBtn', ColorButton = 'colorBtn', @@ -78,7 +77,7 @@ export class FontIconBox extends DocComponent() { // Determining UI Specs @computed get label() { - return StrCast(this.rootDoc.icon_label, StrCast(this.rootDoc.title)); + return StrCast(this.dataDoc.icon_label, StrCast(this.Document.title)); } Icon = (color: string, iconFalse?: boolean) => { let icon; @@ -91,13 +90,13 @@ export class FontIconBox extends DocComponent() { return !icon ? null : icon === 'pres-trail' ? TrailsIcon(color) : ; }; @computed get dropdown() { - return BoolCast(this.rootDoc.dropDownOpen); + return BoolCast(this.Document.dropDownOpen); } @computed get buttonList() { - return StrListCast(this.rootDoc.btnList); + return StrListCast(this.Document.btnList); } @computed get type() { - return StrCast(this.rootDoc.btnType); + return StrCast(this.Document.btnType); } /** @@ -131,8 +130,8 @@ export class FontIconBox extends DocComponent() { type = 'slider'; break; } - const numScript = (value?: number) => ScriptCast(this.rootDoc.script).script.run({ this: this.layoutDoc, self: this.rootDoc, value, _readOnly_: value === undefined }); - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); + const numScript = (value?: number) => ScriptCast(this.Document.script).script.run({ this: this.Document, value, _readOnly_: value === undefined }); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); // Script for checking the outcome of the toggle const checkResult = Number(Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3))); @@ -144,52 +143,21 @@ export class FontIconBox extends DocComponent() { showPlusMinus={false} tooltip={this.label} type={Type.PRIM} - min={NumCast(this.rootDoc.numBtnMin, 0)} - max={NumCast(this.rootDoc.numBtnMax, 100)} + min={NumCast(this.dataDoc.numBtnMin, 0)} + max={NumCast(this.dataDoc.numBtnMax, 100)} number={checkResult} - setNumber={undoable(value => numScript(value), `${this.rootDoc.title} button set from list`)} + setNumber={undoable(value => numScript(value), `${this.Document.title} button set from list`)} fillWidth /> ); } - /** - * Dropdown button - */ - @computed get dropdownButton() { - const active: string = StrCast(this.rootDoc.dropDownOpen); - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); - return ( -
{ - this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen; - this.noTooltip = this.rootDoc.dropDownOpen; - Doc.UnBrushAllDocs(); - })}> - {this.Icon(color)} - {!this.label || !FontIconBox.ShowIconLabels ? null : ( -
- {' '} - {this.label}{' '} -
- )} -
- -
- {this.rootDoc.dropDownOpen ?
{/* DROPDOWN BOX CONTENTS */}
: null} -
- ); - } - dropdownItemDown = (e: React.PointerEvent, value: string | number) => { setupMoveUpEvents( this, e, (e: PointerEvent) => { - return ScriptCast(this.rootDoc.onDragScript)?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: { doc: value, e } }).result; + return ScriptCast(this.Document.onDragScript)?.script.run({ this: this.Document, value: { doc: value, e } }).result; }, emptyFunction, emptyFunction @@ -201,7 +169,7 @@ export class FontIconBox extends DocComponent() { * Dropdown list */ @computed get dropdownListButton() { - const script = ScriptCast(this.rootDoc.script); + const script = ScriptCast(this.Document.script); let noviceList: string[] = []; let text: string | undefined; @@ -237,7 +205,7 @@ export class FontIconBox extends DocComponent() { } noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Carousel3D, CollectionViewType.Stacking, CollectionViewType.NoteTaking]; } else { - text = script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result; + text = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result; // text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily); getStyle = (val: string) => ({ fontFamily: val }); } @@ -255,7 +223,7 @@ export class FontIconBox extends DocComponent() { return ( script.script.run({ this: this.layoutDoc, self: this.rootDoc, value }), `dropdown select ${this.label}`)} + setSelectedVal={undoable(value => script.script.run({ this: this.Document, value }), `dropdown select ${this.label}`)} color={SettingsManager.userColor} background={SettingsManager.userVariantColor} type={Type.TERT} @@ -270,7 +238,7 @@ export class FontIconBox extends DocComponent() { } @computed get colorScript() { - return ScriptCast(this.rootDoc.script); + return ScriptCast(this.Document.script); } colorBatch: UndoManager.Batch | undefined; @@ -278,18 +246,18 @@ export class FontIconBox extends DocComponent() { * Color button */ @computed get colorButton() { - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const curColor = this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result ?? 'transparent'; - const tooltip: string = StrCast(this.rootDoc.toolTip); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const curColor = this.colorScript?.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result ?? 'transparent'; + const tooltip: string = StrCast(this.Document.toolTip); return ( { if (!this.colorBatch) this.colorBatch = UndoManager.StartBatch(`Set ${tooltip} color`); - this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: value, _readOnly_: false }); + this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false }); }} setFinalColor={value => { - this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: value, _readOnly_: false }); + this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false }); this.colorBatch?.end(); this.colorBatch = undefined; }} @@ -306,13 +274,13 @@ export class FontIconBox extends DocComponent() { } @computed get multiToggleButton() { // Determine the type of toggle button - const tooltip: string = StrCast(this.rootDoc.toolTip); + const tooltip: string = StrCast(this.Document.toolTip); - const script = ScriptCast(this.rootDoc.onClick); - const toggleStatus = script ? script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result : false; + const script = ScriptCast(this.Document.onClick); + const toggleStatus = script ? script.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result : false; // Colors - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const items = DocListCast(this.rootDoc.data); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const items = DocListCast(this.dataDoc.data); return ( () { color={color} background={SettingsManager.userBackgroundColor} label={this.label} - items={DocListCast(this.rootDoc.data).map(item => ({ + items={DocListCast(this.dataDoc.data).map(item => ({ icon: , tooltip: StrCast(item.toolTip), val: StrCast(item.toolType), @@ -336,14 +304,14 @@ export class FontIconBox extends DocComponent() { @computed get toggleButton() { // Determine the type of toggle button - const buttonText: string = StrCast(this.rootDoc.buttonText); - const tooltip: string = StrCast(this.rootDoc.toolTip); + const buttonText = StrCast(this.dataDoc.buttonText); + const tooltip = StrCast(this.Document.toolTip); - const script = ScriptCast(this.rootDoc.onClick); - const toggleStatus = script ? script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result : false; + const script = ScriptCast(this.Document.onClick); + const toggleStatus = script ? script.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result : false; // Colors - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const backgroundColor = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor); return ( () { //background={SettingsManager.userBackgroundColor} icon={this.Icon(color)!} label={this.label} - onPointerDown={() => script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: !toggleStatus, _readOnly_: false })} + onPointerDown={() => script.script.run({ this: this.Document, value: !toggleStatus, _readOnly_: false })} /> ); } @@ -365,20 +333,20 @@ export class FontIconBox extends DocComponent() { * Default */ @computed get defaultButton() { - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); - const tooltip: string = StrCast(this.rootDoc.toolTip); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const backgroundColor = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor); + const tooltip: string = StrCast(this.Document.toolTip); return ; } @computed get editableText() { // Script for running the toggle - const script = ScriptCast(this.rootDoc.script); + const script = ScriptCast(this.Document.script); // Function to run the script - const checkResult = script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result; + const checkResult = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result; - const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value, _readOnly_: false }).result; + const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ this: this.Document, value, _readOnly_: false }).result; return {}} />; @@ -386,16 +354,16 @@ export class FontIconBox extends DocComponent() {
- script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} /> + script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} />
); } render() { - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const tooltip = StrCast(this.rootDoc.toolTip); - const scriptFunc = () => ScriptCast(this.rootDoc.onClick)?.script.run({ this: this.layoutDoc, self: this.rootDoc, _readOnly_: false }); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const tooltip = StrCast(this.Document.toolTip); + const scriptFunc = () => ScriptCast(this.Document.onClick)?.script.run({ this: this.Document, self: this.Document, _readOnly_: false }); const btnProps = { tooltip, icon: this.Icon(color)!, label: this.label }; // prettier-ignore switch (this.type) { @@ -405,15 +373,14 @@ export class FontIconBox extends DocComponent() { case ButtonType.EditableText: return this.editableText; case ButtonType.DropdownList: return this.dropdownListButton; case ButtonType.ColorButton: return this.colorButton; - case ButtonType.DropdownButton: return this.dropdownButton; case ButtonType.MultiToggleButton: return this.multiToggleButton; case ButtonType.ToggleButton: return this.toggleButton; case ButtonType.ClickButton: case ButtonType.ToolButton: return ; case ButtonType.TextButton: return - */} +
)}
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index c440a7e3f..6033b897d 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -37,8 +37,8 @@ export class CollectionTimeView extends CollectionSubView() { makeObservable(this); } - async componentDidMount() { - this.props.setContentView?.(this); + componentDidMount() { + this._props.setContentView?.(this); runInAction(() => { this._childClickedScript = ScriptField.MakeScript('openInLightbox(this)', { this: Doc.name }); this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' }); @@ -58,10 +58,10 @@ export class CollectionTimeView extends CollectionSubView() { if (addAsAnnotation) { // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered - if (Cast(this.dataDoc[this.props.fieldKey + '_annotations'], listSpec(Doc), null) !== undefined) { - Cast(this.dataDoc[this.props.fieldKey + '_annotations'], listSpec(Doc), []).push(anchor); + if (Cast(this.dataDoc[this._props.fieldKey + '_annotations'], listSpec(Doc), null) !== undefined) { + Cast(this.dataDoc[this._props.fieldKey + '_annotations'], listSpec(Doc), []).push(anchor); } else { - this.dataDoc[this.props.fieldKey + '_annotations'] = new List([anchor]); + this.dataDoc[this._props.fieldKey + '_annotations'] = new List([anchor]); } } return anchor; @@ -84,10 +84,10 @@ export class CollectionTimeView extends CollectionSubView() { this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - const minReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMinReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMin'], 0)); - const maxReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMaxReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMax'], 10)); - this.props.Document[this.props.fieldKey + '-timelineMinReq'] = minReq + ((maxReq - minReq) * delta[0]) / this.props.PanelWidth(); - this.props.Document[this.props.fieldKey + '-timelineSpan'] = undefined; + const minReq = NumCast(this.Document[this._props.fieldKey + '-timelineMinReq'], NumCast(this.Document[this._props.fieldKey + '-timelineMin'], 0)); + const maxReq = NumCast(this.Document[this._props.fieldKey + '-timelineMaxReq'], NumCast(this.Document[this._props.fieldKey + '-timelineMax'], 10)); + this.Document[this._props.fieldKey + '-timelineMinReq'] = minReq + ((maxReq - minReq) * delta[0]) / this._props.PanelWidth(); + this.Document[this._props.fieldKey + '-timelineSpan'] = undefined; return false; }), returnFalse, @@ -100,9 +100,9 @@ export class CollectionTimeView extends CollectionSubView() { this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - const minReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMinReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMin'], 0)); - const maxReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMaxReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMax'], 10)); - this.props.Document[this.props.fieldKey + '-timelineMaxReq'] = maxReq + ((maxReq - minReq) * delta[0]) / this.props.PanelWidth(); + const minReq = NumCast(this.Document[this._props.fieldKey + '-timelineMinReq'], NumCast(this.Document[this._props.fieldKey + '-timelineMin'], 0)); + const maxReq = NumCast(this.Document[this._props.fieldKey + '-timelineMaxReq'], NumCast(this.Document[this._props.fieldKey + '-timelineMax'], 10)); + this.Document[this._props.fieldKey + '-timelineMaxReq'] = maxReq + ((maxReq - minReq) * delta[0]) / this._props.PanelWidth(); return false; }), returnFalse, @@ -115,10 +115,10 @@ export class CollectionTimeView extends CollectionSubView() { this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - const minReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMinReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMin'], 0)); - const maxReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMaxReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMax'], 10)); - this.props.Document[this.props.fieldKey + '-timelineMinReq'] = minReq - ((maxReq - minReq) * delta[0]) / this.props.PanelWidth(); - this.props.Document[this.props.fieldKey + '-timelineMaxReq'] = maxReq - ((maxReq - minReq) * delta[0]) / this.props.PanelWidth(); + const minReq = NumCast(this.Document[this._props.fieldKey + '-timelineMinReq'], NumCast(this.Document[this._props.fieldKey + '-timelineMin'], 0)); + const maxReq = NumCast(this.Document[this._props.fieldKey + '-timelineMaxReq'], NumCast(this.Document[this._props.fieldKey + '-timelineMax'], 10)); + this.Document[this._props.fieldKey + '-timelineMinReq'] = minReq - ((maxReq - minReq) * delta[0]) / this._props.PanelWidth(); + this.Document[this._props.fieldKey + '-timelineMaxReq'] = maxReq - ((maxReq - minReq) * delta[0]) / this._props.PanelWidth(); return false; }), returnFalse, @@ -145,9 +145,9 @@ export class CollectionTimeView extends CollectionSubView() { @computed get contents() { return ( -
+
(); this.childDocs.forEach(child => Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key))); - Doc.AreProtosEqual(this.dataDoc, this.props.Document) && this.childDocs.forEach(child => Object.keys(child).forEach(key => facets.add(key))); + Doc.AreProtosEqual(this.dataDoc, this.Document) && this.childDocs.forEach(child => Object.keys(child).forEach(key => facets.add(key))); return Array.from(facets); } menuCallback = (x: number, y: number) => { @@ -211,7 +211,7 @@ export class CollectionTimeView extends CollectionSubView() { Array.from(keySet).map(fieldKey => docItems.push({ description: ':' + fieldKey, event: () => (this.layoutDoc._pivotField = fieldKey), icon: 'compress-arrows-alt' })); docItems.push({ description: ':default', event: () => (this.layoutDoc._pivotField = undefined), icon: 'compress-arrows-alt' }); ContextMenu.Instance.addItem({ description: 'Pivot Fields ...', subitems: docItems, icon: 'eye' }); - const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y); + const pt = this._props.ScreenToLocalTransform().inverse().transformPoint(x, y); ContextMenu.Instance.displayMenu(x, y, ':'); }; @@ -227,7 +227,7 @@ export class CollectionTimeView extends CollectionSubView() { } return false; }} - background={'#f1efeb'} // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; + background={'#f1efeb'} // this._props.headingObject ? this._props.headingObject.color : "#f1efeb"; contents={':' + StrCast(this.layoutDoc._pivotField)} showMenuOnLoad={true} display={'inline'} @@ -246,7 +246,7 @@ export class CollectionTimeView extends CollectionSubView() { } }); const forceLayout = StrCast(this.layoutDoc._forceRenderEngine); - const doTimeline = forceLayout ? forceLayout === computeTimelineLayout.name : nonNumbers / this.childDocs.length < 0.1 && this.props.PanelWidth() / this.props.PanelHeight() > 6; + const doTimeline = forceLayout ? forceLayout === computeTimelineLayout.name : nonNumbers / this.childDocs.length < 0.1 && this._props.PanelWidth() / this._props.PanelHeight() > 6; if (doTimeline !== (this._layoutEngine === computeTimelineLayout.name)) { if (!this._changing) { this._changing = true; @@ -261,10 +261,10 @@ export class CollectionTimeView extends CollectionSubView() { } return ( -
+
{this.pivotKeyUI} {this.contents} - {!this.props.isSelected() || !doTimeline ? null : ( + {!this._props.isSelected() || !doTimeline ? null : ( <>
diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts index 710b0211e..12fb42077 100644 --- a/src/typings/index.d.ts +++ b/src/typings/index.d.ts @@ -13,7 +13,6 @@ declare module 'pdfjs-dist/web/pdf_viewer'; declare module 'reveal'; declare module 'react-reveal'; declare module 'react-reveal/makeCarousel'; -declare module '@hig/flyout'; declare module 'express-flash'; declare module 'connect-flash' { interface flash {} -- cgit v1.2.3-70-g09d2 From e39665be22ecee11b093db07ebe72896a6d43a8c Mon Sep 17 00:00:00 2001 From: zaultavangar Date: Sun, 17 Dec 2023 15:59:39 -0500 Subject: starting calendar collection view --- package-lock.json | 2 + package.json | 4 +- src/client/documents/DocumentTypes.ts | 2 +- src/client/documents/Documents.ts | 12 +++- src/client/util/CalendarManager.scss | 18 ++--- src/client/util/CalendarManager.tsx | 82 +++++++++++++++++----- src/client/util/CurrentUserUtils.ts | 2 +- .../views/collections/CollectionCalendarView.tsx | 32 +++++++++ src/client/views/collections/CollectionView.tsx | 3 + src/client/views/nodes/DocumentContentsView.tsx | 2 + src/client/views/nodes/MapBox/MapBox.tsx | 18 +++-- src/client/views/nodes/calendarBox/CalendarBox.tsx | 26 +++++++ 12 files changed, 162 insertions(+), 41 deletions(-) create mode 100644 src/client/views/collections/CollectionCalendarView.tsx create mode 100644 src/client/views/nodes/calendarBox/CalendarBox.tsx (limited to 'src/client/util/CurrentUserUtils.ts') diff --git a/package-lock.json b/package-lock.json index 180ff097a..2d2740381 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@fortawesome/free-regular-svg-icons": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/react-fontawesome": "^0.2.0", + "@internationalized/date": "^3.5.0", "@mapbox/mapbox-gl-geocoder": "^5.0.2", "@mui/icons-material": "^5.14.19", "@mui/material": "^5.14.19", @@ -37,6 +38,7 @@ "@types/dom-speech-recognition": "0.0.4", "@types/formidable": "3.4.5", "@types/google-maps": "^3.2.6", + "@types/mapbox-gl": "^2.7.19", "@types/reveal": "^4.2.0", "@types/supercluster": "^7.1.3", "@types/web": "^0.0.127", diff --git a/package.json b/package.json index 661f8c5ec..098e30ffb 100644 --- a/package.json +++ b/package.json @@ -92,12 +92,12 @@ "webpack-hot-middleware": "^2.25.4" }, "dependencies": { + "@adobe/react-spectrum": "^3.32.2", "@azure/storage-blob": "^12.17.0", "@babel/preset-env": "^7.23.5", "@babel/preset-react": "^7.23.3", "@bundled-es-modules/pdfjs-dist": "^3.6.172-alpha.1", "@emotion/react": "^11.11.1", - "@adobe/react-spectrum": "^3.32.2", "@emotion/styled": "^11.11.0", "@ffmpeg/core": "0.12.4", "@ffmpeg/ffmpeg": "0.12.7", @@ -106,6 +106,7 @@ "@fortawesome/free-regular-svg-icons": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/react-fontawesome": "^0.2.0", + "@internationalized/date": "^3.5.0", "@mapbox/mapbox-gl-geocoder": "^5.0.2", "@mui/icons-material": "^5.14.19", "@mui/material": "^5.14.19", @@ -121,6 +122,7 @@ "@types/dom-speech-recognition": "0.0.4", "@types/formidable": "3.4.5", "@types/google-maps": "^3.2.6", + "@types/mapbox-gl": "^2.7.19", "@types/reveal": "^4.2.0", "@types/supercluster": "^7.1.3", "@types/web": "^0.0.127", diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index 5c2792a53..1123bcac9 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -62,5 +62,5 @@ export enum CollectionViewType { Pile = 'pileup', StackedTimeline = 'stacked timeline', NoteTaking = 'notetaking', - Calendar = 'calendar_view' + Calendar = 'calendar' } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index d6fd8aea3..ff14eb101 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -58,6 +58,7 @@ import { VideoBox } from '../views/nodes/VideoBox'; import { WebBox } from '../views/nodes/WebBox'; import { SearchBox } from '../views/search/SearchBox'; import { CollectionViewType, DocumentType } from './DocumentTypes'; +import { CalendarBox } from '../views/nodes/calendarBox/CalendarBox'; const { default: { DFLT_IMAGE_NATIVE_DIM }, } = require('../views/global/globalCssVariables.module.scss'); @@ -784,6 +785,13 @@ export namespace Docs { options: {}, }, ], + [ + DocumentType.CALENDAR, + { + layout: { view: CalendarBox, dataField: defaultDataKey }, + options: {}, + } + ] ]); const suffix = 'Proto'; @@ -1146,8 +1154,8 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.MAPROUTE), new List(documents), { infoWindowOpen, ...options }, id); } - export function CalendarDocument(options: DocumentOptions={}, documents: Array){ - return InstanceFromProto(Prototypes.get(DocumentType.CALENDAR), new List(documents), options) + export function CalendarDocument(options: DocumentOptions, documents: Array){ + return InstanceFromProto(Prototypes.get(DocumentType.CALENDAR), new List(documents), {...options}) } // shouldn't ever need to create a KVP document-- instead set the LayoutTemplateString to be a KeyValueBox for the DocumentView (see addDocTab in TabDocView) diff --git a/src/client/util/CalendarManager.scss b/src/client/util/CalendarManager.scss index 60610f298..114e19a0e 100644 --- a/src/client/util/CalendarManager.scss +++ b/src/client/util/CalendarManager.scss @@ -31,19 +31,20 @@ margin-top: 10px; align-self: center; width: 60%; + } - .MuiFilledInput-input{ - padding: 10px; - } + .description-container{ + margin-top: 10px; + align-self: center; + width: 60%; } .date-range-picker-container{ margin-top: 5px; - align-self:center; - - .react-date-range{ - - } + align-self: center; + display: flex; + flex-direction: column; + gap: 2px; } .create-button-container{ @@ -57,6 +58,5 @@ border-radius: 5px; background-color: #EFF2F7; } - } } diff --git a/src/client/util/CalendarManager.tsx b/src/client/util/CalendarManager.tsx index 3872294db..d5d4203b1 100644 --- a/src/client/util/CalendarManager.tsx +++ b/src/client/util/CalendarManager.tsx @@ -10,16 +10,16 @@ import { MainViewModal } from '../views/MainViewModal'; import { TextField } from '@mui/material'; import Select from 'react-select'; import { SettingsManager } from './SettingsManager'; -import { DocCast, StrCast } from '../../fields/Types'; +import { DateCast, DocCast, StrCast } from '../../fields/Types'; import { SelectionManager } from './SelectionManager'; import { DocumentManager } from './DocumentManager'; import { DocData } from '../../fields/DocSymbols'; // import { DateRange, Range, RangeKeyDict } from 'react-date-range'; import { Button } from 'browndash-components'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Provider, useProvider, defaultTheme } from '@adobe/react-spectrum'; - -import { DateRangePicker } from '@adobe/react-spectrum'; +import { Provider, defaultTheme } from '@adobe/react-spectrum'; +import { DateValue } from '@internationalized/date'; +import { DateRangePicker, SpectrumDateRangePickerProps } from '@adobe/react-spectrum'; import { IconLookup, faPlus } from '@fortawesome/free-solid-svg-icons'; import { Docs } from '../documents/Documents'; import { ObservableReactComponent } from '../views/ObservableReactComponent'; @@ -33,7 +33,10 @@ interface CalendarSelectOptions { value: string; } -const formatDateToString = (date: Date) => { +const formatCalendarDateToString = (calendarDate: any) => { + console.log("Formatting the following date: ", calendarDate); + const date = new Date(calendarDate.year, calendarDate.month-1, calendarDate.day) + console.log(typeof date); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); @@ -121,19 +124,26 @@ export class CalendarManager extends ObservableReactComponent<{}> { }; @action - handleTextFieldChange = (event: React.ChangeEvent) => { + handleCalendarTitleChange = (event: React.ChangeEvent) => { this.calendarName = event.target.value; }; + @action + handleCalendarDescriptionChange = (event: React.ChangeEvent) => { + this.calendarDescription = event.target.value; + } + // TODO: Make undoable private addToCalendar = () => { let docs = SelectionManager.Views.length < 2 ? [this.targetDoc] : SelectionManager.Views.map(docView => docView.Document); const targetDoc = this.layoutDocAcls ? docs[0] : docs[0]?.[DocData]; // doc to add to calendar + console.log(targetDoc); if (targetDoc) { let calendar: Doc; if (this.creationType === 'new-calendar') { if (!this.existingCalendars.find(doc => StrCast(doc.title) === this.calendarName)) { + console.log('creating...') calendar = Docs.Create.CalendarDocument( { title: this.calendarName, @@ -141,6 +151,7 @@ export class CalendarManager extends ObservableReactComponent<{}> { }, [] ); + console.log('successful calendar creation') } else { this.errorMessage = 'Calendar with this name already exists'; return; @@ -155,15 +166,20 @@ export class CalendarManager extends ObservableReactComponent<{}> { } } // Get start and end date strings - const startDateStr = formatDateToString(this.selectedDateRange.start); - const endDateStr = formatDateToString(this.selectedDateRange.end); + const startDateStr = formatCalendarDateToString(this.selectedDateRange.start); + const endDateStr = formatCalendarDateToString(this.selectedDateRange.end); + + console.log("start date: ", startDateStr); + console.log("end date: ", endDateStr) const subDocEmbedding = Doc.MakeEmbedding(targetDoc); // embedding + console.log("subdoc embedding", subDocEmbedding); subDocEmbedding.embedContainer = calendar; // set embed container subDocEmbedding.date_range = `${startDateStr}-${endDateStr}`; // set subDoc date range Doc.AddDocToList(calendar, 'data', subDocEmbedding); // add embedded subDoc to calendar + console.log("my calendars: ", Doc.MyCalendars); if (this.creationType === 'new-calendar') { Doc.AddDocToList(Doc.MyCalendars, 'data', calendar); // add to new calendar to dashboard calendars } @@ -211,6 +227,7 @@ export class CalendarManager extends ObservableReactComponent<{}> { @action setSelectedDateRange = (range: any) => { + console.log("Range: ", range); this.selectedDateRange = range; }; @@ -220,9 +237,12 @@ export class CalendarManager extends ObservableReactComponent<{}> { let startDate: Date | undefined; let endDate: Date | undefined; try { - startDate = this.selectedDateRange[0].startDate; - endDate = this.selectedDateRange[0].endDate; + startDate = this.selectedDateRange.start; + endDate = this.selectedDateRange.end; + console.log(startDate); + console.log(endDate) } catch (e: any) { + console.log(e); return false; // disabled } if (!startDate || !endDate) return false; // disabled if any is undefined @@ -258,8 +278,9 @@ export class CalendarManager extends ObservableReactComponent<{}> { {this.creationType === 'new-calendar' ? ( { }}> )}
+
+ +
+
Select a date range:
- this.setSelectedDateRange(v)} label="Date range" /> + this.setSelectedDateRange(v)}/>
-
-
+ {this.createButtonActive && +
+
+ + } +
); } @@ -313,4 +361,4 @@ export class CalendarManager extends ObservableReactComponent<{}> { render() { return ; } -} +} \ No newline at end of file diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 61a9fa7c2..f7070a862 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1022,4 +1022,4 @@ ScriptingGlobals.add(function IsExploreMode() { return DocumentView.ExploreMode; 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; }); +ScriptingGlobals.add(function setInkToolDefaults() { Doc.ActiveTool = InkTool.None; }); \ No newline at end of file diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx new file mode 100644 index 000000000..99dc09732 --- /dev/null +++ b/src/client/views/collections/CollectionCalendarView.tsx @@ -0,0 +1,32 @@ +import * as React from 'react'; +import { CollectionSubView } from "./CollectionSubView"; +import { observer } from 'mobx-react'; +import { makeObservable, observable } from 'mobx'; +import { Doc, DocListCast } from '../../../fields/Doc'; + +@observer +export class CollectionCalendarView extends CollectionSubView(){ + + constructor(props: any){ + super(props); + makeObservable(this); + } + + componentDidMount(): void { + + } + + componentWillUnmount(): void { + + } + + @observable private existingCalendars: Doc[] = DocListCast(Doc.MyCalendars?.data); + + render(){ + return ( +
+ Hello +
+ ) + } +} \ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 0673b264b..0237ec95e 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -28,6 +28,7 @@ import { CollectionTreeView } from './CollectionTreeView'; import './CollectionView.scss'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionGridView } from './collectionGrid/CollectionGridView'; +import { CollectionCalendarView} from './CollectionCalendarView'; import { CollectionLinearView } from './collectionLinear'; import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView'; import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView'; @@ -122,6 +123,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent; case CollectionViewType.Schema: return ; + case CollectionViewType.Calendar: return ; case CollectionViewType.Docking: return ; case CollectionViewType.Tree: return ; case CollectionViewType.Multicolumn: return ; @@ -146,6 +148,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent func(CollectionViewType.Schema), icon: 'th-list' }, { description: 'Tree', event: () => func(CollectionViewType.Tree), icon: 'tree' }, { description: 'Stacking', event: () => (func(CollectionViewType.Stacking)._layout_autoHeight = true), icon: 'ellipsis-v' }, + { description: 'Calendar', event: () => func(CollectionViewType.Calendar), icon: 'columns'}, { description: 'Notetaking', event: () => (func(CollectionViewType.NoteTaking)._layout_autoHeight = true), icon: 'ellipsis-v' }, { description: 'Multicolumn', event: () => func(CollectionViewType.Multicolumn), icon: 'columns' }, { description: 'Multirow', event: () => func(CollectionViewType.Multirow), icon: 'columns' }, diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index e161b4c4c..5b2bf4774 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -14,6 +14,7 @@ import { CollectionDockingView } from '../collections/CollectionDockingView'; import { CollectionView } from '../collections/CollectionView'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { CollectionSchemaView } from '../collections/collectionSchema/CollectionSchemaView'; +import { CollectionCalendarView } from '../collections/CollectionCalendarView'; import { SchemaRowBox } from '../collections/collectionSchema/SchemaRowBox'; import { PresElementBox } from '../nodes/trails/PresElementBox'; import { SearchBox } from '../search/SearchBox'; @@ -243,6 +244,7 @@ export class DocumentContentsView extends ObservableReactComponent< CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, + CollectionCalendarView, CollectionView, WebBox, KeyValueBox, diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index b627ba459..44afb8e7b 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -23,9 +23,7 @@ import { FieldView, FieldViewProps } from '../FieldView'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; import { MapAnchorMenu } from './MapAnchorMenu'; - import { ControlPosition, Layer, MapProvider, MapRef, Map as MapboxMap, Marker, MarkerProps, Source, ViewState, ViewStateChangeEvent } from 'react-map-gl'; -import MapboxGeocoder, { GeocoderOptions } from '@mapbox/mapbox-gl-geocoder!'; import './MapBox.scss'; // import { GeocoderControl } from './GeocoderControl'; import { IconLookup, faCircleXmark, faGear, faPause, faPlay, faRotate } from '@fortawesome/free-solid-svg-icons'; @@ -33,7 +31,7 @@ import { Checkbox, FormControlLabel, TextField } from '@mui/material'; import * as turf from '@turf/turf'; import * as d3 from 'd3'; import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, Position } from 'geojson'; -import mapboxgl, { LngLat, LngLatBoundsLike, MapLayerMouseEvent } from 'mapbox-gl!'; +import mapboxgl, { LngLat, LngLatBoundsLike, MapLayerMouseEvent } from '!mapbox-gl'; import { CirclePicker, ColorResult } from 'react-color'; import { MarkerEvent } from 'react-map-gl/dist/esm/types'; import { fastSpeedIcon, mediumSpeedIcon, slowSpeedIcon } from './AnimationSpeedIcons'; @@ -68,13 +66,13 @@ type PopupInfo = { description: string; }; -export type GeocoderControlProps = Omit & { - mapboxAccessToken: string; - marker?: Omit; - position: ControlPosition; +// export type GeocoderControlProps = Omit & { +// mapboxAccessToken: string; +// marker?: Omit; +// position: ControlPosition; - onResult: (...args: any[]) => void; -}; +// onResult: (...args: any[]) => void; +// }; type MapMarker = { longitude: number; @@ -1866,4 +1864,4 @@ export class MapBox extends ViewBoxAnnotatableComponent
*/ -} +} \ No newline at end of file diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx new file mode 100644 index 000000000..0aa3b4ccc --- /dev/null +++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx @@ -0,0 +1,26 @@ +import * as React from 'react'; +import { observer } from "mobx-react"; +import { Doc } from "../../../../fields/Doc"; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps, ViewBoxBaseComponent } from '../../DocComponent'; +import { FieldView, FieldViewProps } from '../FieldView'; +import { StrCast } from '../../../../fields/Types'; +import { makeObservable } from 'mobx'; + +@observer +export class CalendarBox extends ViewBoxBaseComponent(){ + public static LayoutString(fieldKey: string = 'calendar') { + return FieldView.LayoutString(CalendarBox, fieldKey); + } + + constructor(props: any){ + super(props); + makeObservable(this); + } + + render(){ + return ( +
+ ); + + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 6693adb16545cc932fe9d244a15c658288adadc7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 21 Dec 2023 14:56:03 -0500 Subject: fixes post-merge for dataViz-annotations --- src/client/util/CurrentUserUtils.ts | 4 +-- src/client/views/MainView.tsx | 2 ++ .../collectionFreeForm/CollectionFreeFormView.tsx | 38 ++++++++++++++++++++++ .../views/nodes/DataVizBox/SchemaCSVPopUp.tsx | 5 +-- 4 files changed, 45 insertions(+), 4 deletions(-) (limited to 'src/client/util/CurrentUserUtils.ts') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index f7070a862..dd72051fa 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -688,8 +688,8 @@ export class CurrentUserUtils { static schemaTools():Button[] { return [ {title: "Preview", toolTip: "Show selection preview", btnType: ButtonType.ToggleButton, icon: "portrait", scripts:{ onClick: '{ return toggleSchemaPreview(_readOnly_); }'} }, - {title: "1 Line",toolTip: "Single Line Rows", btnType: ButtonType.ToggleButton, icon: "eye", scripts:{ onClick: '{ return toggleSingleLineSchema(_readOnly_); }'} }, - ]; + {title: "1 Line", toolTip: "Single Line Rows", btnType: ButtonType.ToggleButton, icon: "eye", scripts:{ onClick: '{ return toggleSingleLineSchema(_readOnly_); }'} }, + {title: "DataViz", toolTip: "Turn Schema Table into Data Visualization Doc", btnType: ButtonType.ClickButton, icon: "chart-bar", scripts:{ onClick: '{ datavizFromSchema()'} }, ]; } static webTools() { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index c71c72257..f2a1ca57e 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -31,6 +31,7 @@ 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'; @@ -1071,6 +1072,7 @@ export class MainView extends ObservableReactComponent<{}> { {/* {this.mapBoxHack} */} + {/* */}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 1f4688729..88cdd51ff 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -52,6 +52,7 @@ import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannable import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors'; import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; +import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; export type collectionFreeformViewProps = { NativeWidth?: () => number; @@ -1982,3 +1983,40 @@ ScriptingGlobals.add(function bringToFront() { ScriptingGlobals.add(function sendToBack(doc: Doc) { SelectionManager.Views.forEach(view => view.CollectionFreeFormView?.bringToFront(view.Document, true)); }); +ScriptingGlobals.add(function datavizFromSchema(doc: Doc) { + SelectionManager.Views.forEach(view => { + if (!view.layoutDoc.schema_columnKeys){ + view.layoutDoc.schema_columnKeys = new List(['title', 'type', 'author', 'author_date']) + } + const keys = Cast(view.layoutDoc.schema_columnKeys, listSpec('string'))?.filter(key => key!="text"); + if (!keys) return; + + const children = DocListCast(view.Document[Doc.LayoutFieldKey(view.Document)]); + let csvRows = []; + csvRows.push(keys.join(',')); + for (let i=0; i < children.length; i++) { + let eachRow = []; + for (let j=0; j { constructor(props: SchemaCSVPopUpProps) { super(props); + makeObservable(this); SchemaCSVPopUp.Instance = this; } -- cgit v1.2.3-70-g09d2 From 1a3aa8a4e79deb501fce0c89ace8ea960003d8cd Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 29 Dec 2023 10:50:42 -0500 Subject: fixed sidebar button highoighting. fixed explore mode. --- src/client/util/CurrentUserUtils.ts | 3 ++- src/client/util/DragManager.ts | 2 +- src/client/util/SettingsManager.tsx | 6 +++++- src/client/util/SnappingManager.ts | 3 +++ src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/LightboxView.tsx | 7 ++++--- src/client/views/MainView.tsx | 6 +++--- src/client/views/StyleProvider.tsx | 11 ++++++----- src/client/views/collections/TabDocView.tsx | 2 +- .../views/collections/collectionFreeForm/MarqueeView.tsx | 3 ++- src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx | 5 +++-- src/client/views/newlightbox/NewLightboxView.tsx | 3 ++- src/client/views/nodes/DocumentView.tsx | 6 ++---- src/client/views/topbar/TopBar.tsx | 7 ++++--- 14 files changed, 39 insertions(+), 27 deletions(-) (limited to 'src/client/util/CurrentUserUtils.ts') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index dd72051fa..c1d74c398 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -30,6 +30,7 @@ import { LinkManager } from "./LinkManager"; import { ScriptingGlobals } from "./ScriptingGlobals"; import { ColorScheme } from "./SettingsManager"; import { UndoManager } from "./UndoManager"; +import { SnappingManager } from "./SnappingManager"; interface Button { // DocumentOptions fields a button can set @@ -1018,7 +1019,7 @@ export class CurrentUserUtils { } ScriptingGlobals.add(function MySharedDocs() { return Doc.MySharedDocs; }, "document containing all shared Docs"); -ScriptingGlobals.add(function IsExploreMode() { return DocumentView.ExploreMode; }, "is Dash in exploration mode"); +ScriptingGlobals.add(function IsExploreMode() { return SnappingManager.ExploreMode; }, "is Dash in exploration mode"); 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"); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index c711db31a..fe3a52be7 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -333,7 +333,7 @@ export namespace DragManager { export let CanEmbed = false; export let DocDragData: DocumentDragData | undefined; export function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void, dragUndoName?: string) { - if (dragData.dropAction === 'none' || DocumentView.ExploreMode) return; + if (dragData.dropAction === 'none' || SnappingManager.ExploreMode) return; DocDragData = dragData as DocumentDragData; const batch = UndoManager.StartBatch(dragUndoName ?? 'document drag'); eles = eles.filter(e => e); diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index ccf6fb820..0233c4051 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -5,7 +5,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { BsGoogle } from 'react-icons/bs'; import { FaFillDrip, FaPalette } from 'react-icons/fa'; -import { Doc } from '../../fields/Doc'; +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'; @@ -43,6 +43,7 @@ export class SettingsManager extends React.Component<{}> { @observable private curr_password = ''; @observable private new_password = ''; @observable private new_confirm = ''; + @observable private _lastPressedSidebarBtn: Opt = undefined; // bcz: this is a hack to handle highlighting buttons in the leftpanel menu .. need to find a cleaner approach @observable activeTab = 'Accounts'; @observable public propertiesWidth: number = 0; @@ -94,6 +95,9 @@ export class SettingsManager extends React.Component<{}> { return StrCast(Doc.UserDoc().userBackgroundColor); } + public get LastPressedBtn() { return this._lastPressedSidebarBtn; } // prettier-ignore + public SetLastPressedBtn = (state?:Doc) => runInAction(() => (this._lastPressedSidebarBtn = state)); // prettier-ignore + @undoBatch selectUserMode = action((mode: string) => (Doc.noviceMode = mode === 'Novice')); @undoBatch changelayout_showTitle = action((e: React.ChangeEvent) => (Doc.UserDoc().layout_showTitle = (e.currentTarget as any).value ? 'title' : undefined)); @undoBatch changeFontFamily = action((font: string) => (Doc.UserDoc().fontFamily = font)); diff --git a/src/client/util/SnappingManager.ts b/src/client/util/SnappingManager.ts index b8bd90983..c4d299fa1 100644 --- a/src/client/util/SnappingManager.ts +++ b/src/client/util/SnappingManager.ts @@ -14,6 +14,7 @@ export class SnappingManager { @observable _canEmbed: boolean = false; @observable _horizSnapLines: number[] = []; @observable _vertSnapLines: number[] = []; + @observable _exploreMode = false; private constructor() { SnappingManager._manager = this; @@ -33,9 +34,11 @@ export class SnappingManager { public static get IsDragging() { return this.Instance._isDragging; } // prettier-ignore public static get IsResizing() { return this.Instance._isResizing; } // prettier-ignore public static get CanEmbed() { return this.Instance._canEmbed; } // prettier-ignore + public static get ExploreMode() { return this.Instance._exploreMode; } // prettier-ignore public static SetShiftKey = (down: boolean) => runInAction(() => (this.Instance._shiftKey = down)); // prettier-ignore public static SetCtrlKey = (down: boolean) => runInAction(() => (this.Instance._ctrlKey = down)); // prettier-ignore public static SetIsDragging = (drag: boolean) => runInAction(() => (this.Instance._isDragging = drag)); // prettier-ignore public static SetIsResizing = (doc: Opt) => runInAction(() => (this.Instance._isResizing = doc)); // prettier-ignore public static SetCanEmbed = (embed:boolean) => runInAction(() => (this.Instance._canEmbed = embed)); // prettier-ignore + public static SetExploreMode= (state:boolean) => runInAction(() => (this.Instance._exploreMode = state)); // prettier-ignore } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index f3da133c3..d2f23c2f3 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -97,7 +97,7 @@ export class DocumentDecorations extends ObservableReactComponent dv._props.renderDepth > 0) diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 7577f2935..ab3be3d7a 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -22,6 +22,7 @@ import './LightboxView.scss'; import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; import { DefaultStyleProvider, wavyBorderPath } from './StyleProvider'; import { ObservableReactComponent } from './ObservableReactComponent'; +import { SnappingManager } from '../util/SnappingManager'; interface LightboxViewProps { PanelWidth: number; @@ -77,7 +78,7 @@ export class LightboxView extends ObservableReactComponent { this._future = []; this._history = []; Doc.ActiveTool = InkTool.None; - DocumentView.ExploreMode = false; + SnappingManager.SetExploreMode(false); } SelectionManager.DeselectAll(); if (future) { @@ -172,7 +173,7 @@ export class LightboxView extends ObservableReactComponent { }; toggleFitWidth = () => this._doc && (this._doc._layout_fitWidth = !this._doc._layout_fitWidth); togglePen = () => (Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen); - toggleExplore = () => (DocumentView.ExploreMode = !DocumentView.ExploreMode); + toggleExplore = () => SnappingManager.SetExploreMode(!SnappingManager.ExploreMode); lightboxDoc = () => this._doc; lightboxWidth = () => this._props.PanelWidth - this.leftBorder * 2; @@ -286,7 +287,7 @@ export class LightboxView extends ObservableReactComponent { {toggleBtn('lightboxView-navBtn', 'toggle reading view', this._doc?._layout_fitWidth, 'book-open', 'book', this.toggleFitWidth)} {toggleBtn('lightboxView-tabBtn', 'open document in a tab', false, 'file-download', '', this.downloadDoc)} {toggleBtn('lightboxView-penBtn', 'toggle pen annotation', Doc.ActiveTool === InkTool.Pen, 'pen', '', this.togglePen)} - {toggleBtn('lightboxView-exploreBtn', 'toggle navigate only mode', DocumentView.ExploreMode, 'globe-americas', '', this.toggleExplore)} + {toggleBtn('lightboxView-exploreBtn', 'toggle navigate only mode', SnappingManager.ExploreMode, 'globe-americas', '', this.toggleExplore)}
); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index f2a1ca57e..094bd2adb 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -593,7 +593,7 @@ export class MainView extends ObservableReactComponent<{}> { Doc.AddDocToList(Doc.MyFilesystem, 'data', folder); }; - waitForDoubleClick = () => (DocumentView.ExploreMode ? 'never' : undefined); + waitForDoubleClick = () => (SnappingManager.ExploreMode ? 'never' : undefined); headerBarScreenXf = () => new Transform(-this.leftScreenOffsetOfMainDocView - this.leftMenuFlyoutWidth(), -this.headerBarDocHeight(), 1); mainScreenToLocalXf = () => new Transform(-this.leftScreenOffsetOfMainDocView - this.leftMenuFlyoutWidth(), -this.topOfMainDocContent, 1); addHeaderDoc = (doc: Doc | Doc[], annotationKey?: string) => (doc instanceof Doc ? [doc] : doc).reduce((done, doc) => Doc.AddDocToList(this.headerBarDoc, 'data', doc), true); @@ -873,11 +873,11 @@ export class MainView extends ObservableReactComponent<{}> { //setTimeout(action(() => (this._leftMenuFlyoutWidth += 0.5))); this._sidebarContent.proto = DocCast(button.target); - DocumentView.LastPressedSidebarBtn = button; + SettingsManager.Instance.SetLastPressedBtn(button); }); closeFlyout = action(() => { - DocumentView.LastPressedSidebarBtn = undefined; + SettingsManager.Instance.SetLastPressedBtn(undefined); this._panelContent = 'none'; this._sidebarContent.proto = undefined; this._leftMenuFlyoutWidth = 0; diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 3e7e4be90..c8f6d6013 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -4,6 +4,7 @@ import { Tooltip } from '@mui/material'; import { Dropdown, DropdownType, IconButton, IListItemProps, Shadows, Size, Type } from 'browndash-components'; import { action, runInAction, untracked } from 'mobx'; import { extname } from 'path'; +import * as React from 'react'; import { BsArrowDown, BsArrowDownUp, BsArrowUp } from 'react-icons/bs'; import { FaFilter } from 'react-icons/fa'; import { Doc, Opt, StrListCast } from '../../fields/Doc'; @@ -15,15 +16,15 @@ import { DocFocusOrOpen, DocumentManager } from '../util/DocumentManager'; import { IsFollowLinkScript } from '../util/LinkFollower'; import { LinkManager } from '../util/LinkManager'; import { SettingsManager } from '../util/SettingsManager'; +import { SnappingManager } from '../util/SnappingManager'; import { undoBatch, UndoManager } from '../util/UndoManager'; import { TreeSort } from './collections/TreeSort'; import { Colors } from './global/globalEnums'; -import { DocumentView, DocumentViewProps } from './nodes/DocumentView'; +import { DocumentViewProps } from './nodes/DocumentView'; import { FieldViewProps } from './nodes/FieldView'; import { KeyValueBox } from './nodes/KeyValueBox'; import { PropertiesView } from './PropertiesView'; import './StyleProvider.scss'; -import * as React from 'react'; export enum StyleProp { TreeViewIcon = 'treeView_Icon', @@ -164,7 +165,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color)); @@ -199,7 +200,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt = StrCast(doc?.[fieldKey + '_backgroundColor'], StrCast(doc?._backgroundColor, isCaption ? 'rgba(0,0,0,0.4)' : '')); // prettier-ignore switch (doc?.type) { @@ -266,7 +267,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt { disableMinimap = () => !this._document; whenChildContentActiveChanges = (isActive: boolean) => (this._isAnyChildContentActive = isActive); isContentActive = () => this._isContentActive; - waitForDoubleClick = () => (DocumentView.ExploreMode ? 'never' : undefined); + waitForDoubleClick = () => (SnappingManager.ExploreMode ? 'never' : undefined); @computed get docView() { return !this._activated || !this._document ? null : ( <> diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 2c65726b2..b22fdfa19 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -27,6 +27,7 @@ import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { SubCollectionViewProps } from '../CollectionSubView'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; +import { SnappingManager } from '../../../util/SnappingManager'; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -321,7 +322,7 @@ export class MarqueeView extends ObservableReactComponent { return ( @@ -39,10 +40,10 @@ export const ButtonMenu = (props: IButtonMenu) => {
{ e.stopPropagation(); - DocumentView.ExploreMode = !DocumentView.ExploreMode; + SnappingManager.SetExploreMode(!SnappingManager.ExploreMode); })}>
); diff --git a/src/client/views/newlightbox/NewLightboxView.tsx b/src/client/views/newlightbox/NewLightboxView.tsx index f3cde3f5a..6980e31c1 100644 --- a/src/client/views/newlightbox/NewLightboxView.tsx +++ b/src/client/views/newlightbox/NewLightboxView.tsx @@ -23,6 +23,7 @@ import { emptyBounds, IBounds } from './ExploreView/utils'; import { NewLightboxHeader } from './Header'; import './NewLightboxView.scss'; import { RecommendationList } from './RecommendationList'; +import { SnappingManager } from '../../util/SnappingManager'; enum LightboxStatus { RECOMMENDATIONS = 'recommendations', @@ -126,7 +127,7 @@ export class NewLightboxView extends React.Component { this._docFilters && (this._docFilters.length = 0); this._future = this._history = []; Doc.ActiveTool = InkTool.None; - DocumentView.ExploreMode = false; + SnappingManager.SetExploreMode(false); } else { const l = DocUtils.MakeLinkToActiveAudio(() => doc).lastElement(); l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen'); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 336f65b85..cc7fca8d2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -712,7 +712,7 @@ export class DocumentViewInternal extends DocComponent { @@ -1337,10 +1337,8 @@ export class DocumentView extends ObservableReactComponent { runInAction(() => (this._selected = val)); } @observable public static LongPress = false; - @observable public static ExploreMode = false; - @observable public static LastPressedSidebarBtn: Opt = undefined; // bcz: this is a hack to handle highlighting buttons in the leftpanel menu .. need to find a cleaner approach @computed public static get exploreMode() { - return () => (DocumentView.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined); + return () => (SnappingManager.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined); } @observable public docView: DocumentViewInternal | undefined | null = undefined; @observable public textHtmlOverlay: Opt = undefined; diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index d1c039d95..0f3487cd1 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -24,6 +24,7 @@ import { Colors } from '../global/globalEnums'; import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; import './TopBar.scss'; +import { SnappingManager } from '../../util/SnappingManager'; /** * ABOUT: This is the topbar in Dash, which included the current Dashboard as well as access to information on the user @@ -84,9 +85,9 @@ export class TopBar extends React.Component { type={Type.TERT} tooltip="Browsing mode for directly navigating to documents" size={Size.SMALL} - color={DocumentView.ExploreMode ? this.variantColor : this.color} - background={DocumentView.ExploreMode ? this.color : 'transparent'} - onClick={action(() => (DocumentView.ExploreMode = !DocumentView.ExploreMode))} + color={SnappingManager.ExploreMode ? this.variantColor : this.color} + background={SnappingManager.ExploreMode ? this.color : 'transparent'} + onClick={() => SnappingManager.SetExploreMode(!SnappingManager.ExploreMode)} /> )}
-- cgit v1.2.3-70-g09d2 From 9b9f54a43793ca6ffb26c56f962d11ba8325abd2 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 29 Dec 2023 17:01:40 -0500 Subject: cleaned up imports, mobx observable initialization and some compile errors. --- src/Utils.ts | 27 ++--- src/client/util/CalendarManager.tsx | 34 +++--- src/client/util/CaptureManager.tsx | 2 +- src/client/util/CurrentUserUtils.ts | 14 +-- src/client/util/GroupManager.tsx | 2 +- src/client/util/HypothesisUtils.ts | 13 ++- src/client/views/DocumentButtonBar.tsx | 5 - src/client/views/DocumentDecorations.tsx | 11 +- src/client/views/FilterPanel.tsx | 11 +- src/client/views/GestureOverlay.tsx | 25 +++-- src/client/views/InkTranscription.tsx | 8 +- src/client/views/InkingStroke.tsx | 76 +++++--------- src/client/views/MainView.tsx | 2 +- src/client/views/MetadataEntryMenu.tsx | 12 +-- src/client/views/PreviewCursor.tsx | 2 +- src/client/views/PropertiesButtons.tsx | 17 +-- .../views/PropertiesDocBacklinksSelector.tsx | 4 +- src/client/views/PropertiesSection.tsx | 6 +- src/client/views/TemplateMenu.tsx | 2 +- src/client/views/UndoStack.tsx | 22 ++-- src/client/views/animationtimeline/Region.tsx | 2 +- src/client/views/animationtimeline/Timeline.tsx | 4 +- .../views/animationtimeline/TimelineOverview.tsx | 2 +- src/client/views/animationtimeline/Track.tsx | 8 +- .../views/collections/CollectionCalendarView.tsx | 19 ++-- .../views/collections/CollectionDockingView.tsx | 4 +- src/client/views/collections/CollectionMenu.tsx | 3 - .../CollectionNoteTakingViewDivider.tsx | 2 +- .../views/collections/CollectionPileView.tsx | 2 +- .../collections/CollectionStackedTimeline.tsx | 4 +- .../CollectionStackingViewFieldColumn.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 8 +- .../views/collections/CollectionTimeView.tsx | 14 +-- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/KeyRestrictionRow.tsx | 37 +++---- src/client/views/collections/TreeView.tsx | 2 +- .../CollectionFreeFormBackgroundGrid.tsx | 2 +- .../CollectionFreeFormInfoState.tsx | 2 +- .../CollectionFreeFormInfoUI.tsx | 8 +- .../CollectionFreeFormLinksView.tsx | 4 +- .../CollectionFreeFormPannableContents.tsx | 5 +- .../CollectionFreeFormRemoteCursors.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 5 +- .../collectionGrid/CollectionGridView.tsx | 4 +- .../views/collections/collectionGrid/Grid.tsx | 2 +- .../CollectionMulticolumnView.tsx | 4 +- .../CollectionMultirowView.tsx | 3 +- .../collectionMulticolumn/MulticolumnResizer.tsx | 8 +- .../MulticolumnWidthLabel.tsx | 27 +++-- .../collectionMulticolumn/MultirowHeightLabel.tsx | 22 ++-- .../collectionMulticolumn/MultirowResizer.tsx | 6 +- .../collectionSchema/SchemaColumnHeader.tsx | 4 +- src/client/views/linking/LinkMenuItem.tsx | 6 +- src/client/views/linking/LinkPopup.tsx | 8 +- .../views/linking/LinkRelationshipSearch.tsx | 2 +- .../views/newlightbox/ButtonMenu/ButtonMenu.tsx | 4 +- src/client/views/newlightbox/NewLightboxView.tsx | 26 ++--- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 4 +- .../views/nodes/DataVizBox/SchemaCSVPopUp.tsx | 30 +++--- .../nodes/DataVizBox/components/Histogram.tsx | 6 +- .../nodes/DataVizBox/components/LineChart.tsx | 28 ++--- .../views/nodes/DataVizBox/components/PieChart.tsx | 6 +- .../views/nodes/DataVizBox/components/TableBox.tsx | 12 +-- src/client/views/nodes/DocumentContentsView.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 7 +- src/client/views/nodes/FaceRectangle.tsx | 4 +- src/client/views/nodes/FaceRectangles.tsx | 4 +- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/KeyValuePair.tsx | 6 +- src/client/views/nodes/LinkDescriptionPopup.tsx | 2 +- src/client/views/nodes/LinkDocPreview.tsx | 8 +- src/client/views/nodes/LoadingBox.tsx | 2 +- src/client/views/nodes/MapBox/AnimationUtility.ts | 13 +-- .../views/nodes/MapBox/DirectionsAnchorMenu.tsx | 14 +-- src/client/views/nodes/MapBox/MapAnchorMenu.tsx | 106 +++++++------------ src/client/views/nodes/MapBox/MapBox.tsx | 60 +++++------ src/client/views/nodes/MapBox/MapBox2.tsx | 2 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 20 ++-- src/client/views/nodes/PDFBox.tsx | 2 +- .../nodes/PhysicsBox/PhysicsSimulationBox.tsx | 4 +- .../nodes/PhysicsBox/PhysicsSimulationWeight.tsx | 2 +- src/client/views/nodes/RadialMenu.tsx | 2 +- src/client/views/nodes/RadialMenuItem.tsx | 2 +- .../views/nodes/RecordingBox/RecordingBox.tsx | 4 +- src/client/views/nodes/ScreenshotBox.tsx | 2 +- src/client/views/nodes/ScriptingBox.tsx | 8 +- src/client/views/nodes/TaskCompletedBox.tsx | 8 +- src/client/views/nodes/VideoBox.tsx | 6 +- src/client/views/nodes/audio/AudioWaveform.tsx | 2 +- src/client/views/nodes/calendarBox/CalendarBox.tsx | 114 +++++++++------------ .../views/nodes/formattedText/DashDocView.tsx | 6 +- .../views/nodes/formattedText/EquationView.tsx | 7 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- .../views/nodes/formattedText/RichTextMenu.tsx | 2 +- .../views/nodes/importBox/ImportElementBox.tsx | 8 +- src/client/views/nodes/trails/PresBox.tsx | 6 +- src/client/views/pdf/Annotation.tsx | 5 +- src/client/views/pdf/GPTPopup/GPTPopup.tsx | 16 +-- src/client/views/pdf/PDFViewer.tsx | 2 +- src/client/views/search/SearchBox.tsx | 15 ++- src/client/views/selectedDoc/SelectedDocView.tsx | 6 +- src/client/views/topbar/TopBar.tsx | 4 +- src/client/views/webcam/DashWebRTCVideo.tsx | 5 +- src/debug/Repl.tsx | 10 +- src/debug/Viewer.tsx | 18 ++-- src/fields/CursorField.ts | 7 +- src/fields/Doc.ts | 4 +- src/fields/List.ts | 8 +- src/fields/Proxy.ts | 12 +-- src/fields/util.ts | 4 +- src/mobile/ImageUpload.tsx | 6 +- src/mobile/MobileInkOverlay.tsx | 2 +- src/mobile/MobileInterface.tsx | 110 ++++++++++---------- src/typings/index.d.ts | 4 +- test/test.ts | 106 ++++++++++--------- 116 files changed, 650 insertions(+), 793 deletions(-) (limited to 'src/client/util/CurrentUserUtils.ts') diff --git a/src/Utils.ts b/src/Utils.ts index a060e4a2c..b5c218e01 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,13 +1,12 @@ -import * as uuid from 'uuid'; import { ColorResult } from 'react-color'; +import * as uuid from 'uuid'; //import { Socket } from '../node_modules/socket.io-client'; -import { Socket } from '../node_modules/socket.io/dist/index'; +import * as Color from 'color'; import * as rp from 'request-promise'; +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 * as Color from 'color'; -import { action } from 'mobx'; export namespace Utils { export let CLICK_TIME = 300; @@ -896,23 +895,19 @@ export function setupMoveUpEvents( document.addEventListener('click', _clickEvent, true); } -export function dateRangeStrToDates (dateStr: string) { +export function dateRangeStrToDates(dateStr: string) { // dateStr in yyyy-mm-dd format - const dateRangeParts = dateStr.split("|"); // splits into from and to date - const fromParts = dateRangeParts[0].split("-"); - const toParts = dateRangeParts[1].split("-"); + const dateRangeParts = dateStr.split('|'); // splits into from and to date + const fromParts = dateRangeParts[0].split('-'); + const toParts = dateRangeParts[1].split('-'); const fromYear = parseInt(fromParts[0]); - const fromMonth = parseInt(fromParts[1])-1; + const fromMonth = parseInt(fromParts[1]) - 1; const fromDay = parseInt(fromParts[2]); const toYear = parseInt(toParts[0]); - const toMonth = parseInt(toParts[1])-1; + const toMonth = parseInt(toParts[1]) - 1; const toDay = parseInt(toParts[2]); - - return [ - new Date(fromYear, fromMonth, fromDay), - new Date(toYear, toMonth, toDay) - ]; -} \ No newline at end of file + return [new Date(fromYear, fromMonth, fromDay), new Date(toYear, toMonth, toDay)]; +} diff --git a/src/client/util/CalendarManager.tsx b/src/client/util/CalendarManager.tsx index 6ef2d3429..6e9094b3a 100644 --- a/src/client/util/CalendarManager.tsx +++ b/src/client/util/CalendarManager.tsx @@ -1,26 +1,24 @@ -import * as React from 'react'; -import './CalendarManager.scss'; +import { TextField } from '@mui/material'; +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { action, computed, observable, runInAction, makeObservable } from 'mobx'; +import * as React from 'react'; +import Select from 'react-select'; import { Doc, DocListCast } from '../../fields/Doc'; -import { DocumentView } from '../views/nodes/DocumentView'; +import { DocData } from '../../fields/DocSymbols'; +import { StrCast } from '../../fields/Types'; import { DictationOverlay } from '../views/DictationOverlay'; -import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox'; import { MainViewModal } from '../views/MainViewModal'; -import { TextField } from '@mui/material'; -import Select from 'react-select'; -import { SettingsManager } from './SettingsManager'; -import { DateCast, DocCast, StrCast } from '../../fields/Types'; -import { SelectionManager } from './SelectionManager'; +import { DocumentView } from '../views/nodes/DocumentView'; +import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox'; +import './CalendarManager.scss'; import { DocumentManager } from './DocumentManager'; -import { DocData } from '../../fields/DocSymbols'; +import { SelectionManager } from './SelectionManager'; +import { SettingsManager } from './SettingsManager'; // import { DateRange, Range, RangeKeyDict } from 'react-date-range'; -import { Button } from 'browndash-components'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Provider, defaultTheme } from '@adobe/react-spectrum'; -import { DateValue } from '@internationalized/date'; -import { DateRangePicker, SpectrumDateRangePickerProps } from '@adobe/react-spectrum'; +import { DateRangePicker, Provider, defaultTheme } from '@adobe/react-spectrum'; import { IconLookup, faPlus } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Button } from 'browndash-components'; import { Docs } from '../documents/Documents'; import { ObservableReactComponent } from '../views/ObservableReactComponent'; // import 'react-date-range/dist/styles.css'; @@ -51,8 +49,8 @@ const formatCalendarDateToString = (calendarDate: any) => { export class CalendarManager extends ObservableReactComponent<{}> { public static Instance: CalendarManager; @observable private isOpen = false; - @observable private targetDoc: Doc | undefined; // the target document - @observable private targetDocView: DocumentView | undefined; // the DocumentView of the target doc + @observable private targetDoc: Doc | undefined = undefined; // the target document + @observable private targetDocView: DocumentView | undefined = undefined; // the DocumentView of the target doc @observable private dialogueBoxOpacity = 1; // for the modal @observable private overlayOpacity = 0.4; // for the modal diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx index 071fc1ee9..c1e0a5b2e 100644 --- a/src/client/util/CaptureManager.tsx +++ b/src/client/util/CaptureManager.tsx @@ -15,7 +15,7 @@ import { SelectionManager } from './SelectionManager'; export class CaptureManager extends React.Component<{}> { public static Instance: CaptureManager; static _settingsStyle = addStyleSheet(); - @observable _document: any; + @observable _document: any = undefined; @observable isOpen: boolean = false; // whether the CaptureManager is to be displayed or not. constructor(props: {}) { diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index c1d74c398..3f28f44fc 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1,5 +1,6 @@ import { observable, reaction, runInAction } from "mobx"; import * as rp from 'request-promise'; +import { OmitKeys, Utils } from "../../Utils"; import { Doc, DocListCast, DocListCastAsync, Opt } from "../../fields/Doc"; import { InkTool } from "../../fields/InkField"; import { List } from "../../fields/List"; @@ -8,29 +9,28 @@ import { RichTextField } from "../../fields/RichTextField"; import { listSpec } from "../../fields/Schema"; import { ScriptField } from "../../fields/ScriptField"; import { Cast, DateCast, DocCast, StrCast } from "../../fields/Types"; -import { nullAudio, WebField } from "../../fields/URLField"; +import { WebField, nullAudio } from "../../fields/URLField"; import { SetCachedGroups, SharingPermissions } from "../../fields/util"; import { GestureUtils } from "../../pen-gestures/GestureUtils"; -import { OmitKeys, Utils } from "../../Utils"; import { DocServer } from "../DocServer"; -import { Docs, DocumentOptions, DocUtils, FInfo } from "../documents/Documents"; import { CollectionViewType, DocumentType } from "../documents/DocumentTypes"; -import { TreeViewType } from "../views/collections/CollectionTreeView"; +import { DocUtils, Docs, DocumentOptions, FInfo } from "../documents/Documents"; import { DashboardView } from "../views/DashboardView"; +import { OverlayView } from "../views/OverlayView"; +import { TreeViewType } from "../views/collections/CollectionTreeView"; import { Colors } from "../views/global/globalEnums"; import { media_state } from "../views/nodes/AudioBox"; -import { DocumentView, OpenWhere } from "../views/nodes/DocumentView"; +import { OpenWhere } from "../views/nodes/DocumentView"; import { ButtonType } from "../views/nodes/FontIconBox/FontIconBox"; import { ImportElementBox } from "../views/nodes/importBox/ImportElementBox"; -import { OverlayView } from "../views/OverlayView"; import { DragManager, dropActionType } from "./DragManager"; import { MakeTemplate } from "./DropConverter"; import { FollowLinkScript } from "./LinkFollower"; import { LinkManager } from "./LinkManager"; import { ScriptingGlobals } from "./ScriptingGlobals"; import { ColorScheme } from "./SettingsManager"; -import { UndoManager } from "./UndoManager"; import { SnappingManager } from "./SnappingManager"; +import { UndoManager } from "./UndoManager"; interface Button { // DocumentOptions fields a button can set diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 90f65b648..f4f879208 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -33,7 +33,7 @@ export class GroupManager extends ObservableReactComponent<{}> { @observable isOpen: boolean = false; // whether the GroupManager is to be displayed or not. @observable private users: string[] = []; // list of users populated from the database. @observable private selectedUsers: UserOptions[] | null = null; // list of users selected in the "Select users" dropdown. - @observable currentGroup: Opt; // the currently selected group. + @observable currentGroup: Opt = undefined; // the currently selected group. @observable private createGroupModalOpen: boolean = false; private inputRef: React.RefObject = React.createRef(); // the ref for the input box. private createGroupButtonRef: React.RefObject = React.createRef(); // the ref for the group creation button diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts index 990798ed3..0ae23d793 100644 --- a/src/client/util/HypothesisUtils.ts +++ b/src/client/util/HypothesisUtils.ts @@ -1,16 +1,15 @@ -import { StrCast, Cast } from '../../fields/Types'; -import { SearchUtil } from './SearchUtil'; import { action, runInAction } from 'mobx'; +import { simulateMouseClick } from '../../Utils'; import { Doc, Opt } from '../../fields/Doc'; +import { Cast, StrCast } from '../../fields/Types'; +import { WebField } from '../../fields/URLField'; import { DocumentType } from '../documents/DocumentTypes'; import { Docs } from '../documents/Documents'; -import { SelectionManager } from './SelectionManager'; -import { WebField } from '../../fields/URLField'; -import { DocumentManager } from './DocumentManager'; import { DocumentLinksButton } from '../views/nodes/DocumentLinksButton'; -import { simulateMouseClick, Utils } from '../../Utils'; import { DocumentView } from '../views/nodes/DocumentView'; -import { Id } from '../../fields/FieldSymbols'; +import { DocumentManager } from './DocumentManager'; +import { SearchUtil } from './SearchUtil'; +import { SelectionManager } from './SelectionManager'; export namespace Hypothesis { /** diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index f0887676f..3938b81cd 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -40,14 +40,9 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => ( private _pullAnimating = false; private _pushAnimating = false; private _pullColorAnimating = false; - @observable private pushIcon: IconProp = 'arrow-alt-circle-up'; - @observable private pullIcon: IconProp = 'arrow-alt-circle-down'; - @observable private pullColor: string = 'white'; @observable public isAnimatingFetch = false; @observable public isAnimatingPulse = false; - @observable private openHover: UtilityButtonState = UtilityButtonState.Default; - @observable public static Instance: DocumentButtonBar; public static hasPushedHack = false; public static hasPulledHack = false; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index d2f23c2f3..dab6e6193 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -12,7 +12,7 @@ import { RichTextField } from '../../fields/RichTextField'; import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { GetEffectiveAcl } from '../../fields/util'; -import { emptyFunction, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils'; +import { emptyFunction, lightOrDark, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils'; import { Docs } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { DocumentManager } from '../util/DocumentManager'; @@ -85,7 +85,7 @@ export class DocumentDecorations extends ObservableReactComponent; - @observable public SavedColor?: string; - @observable public SavedWidth?: number; + @observable public InkShape: Opt = undefined; + @observable public SavedColor?: string = undefined; + @observable public SavedWidth?: number = undefined; @observable public Tool: ToolglassTools = ToolglassTools.None; @observable public KeepPrimitiveMode = false; // for whether primitive selection enters a one-shot or persistent mode - @observable private _thumbX?: number; - @observable private _thumbY?: number; + @observable private _thumbX?: number = undefined; + @observable private _thumbY?: number = undefined; @observable private _selectedIndex: number = -1; @observable private _menuX: number = -300; @observable private _menuY: number = -300; - @observable private _pointerY?: number; + @observable private _pointerY?: number = undefined; @observable private _points: { X: number; Y: number }[] = []; @observable private _strokes: InkData[] = []; - @observable private _palette?: JSX.Element; - @observable private _clipboardDoc?: JSX.Element; + @observable private _palette?: JSX.Element = undefined; + @observable private _clipboardDoc?: JSX.Element = undefined; @observable private _possibilities: JSX.Element[] = []; public static DownDocView: DocumentView | undefined; diff --git a/src/client/views/InkTranscription.tsx b/src/client/views/InkTranscription.tsx index b2ac208ca..7e2b334af 100644 --- a/src/client/views/InkTranscription.tsx +++ b/src/client/views/InkTranscription.tsx @@ -17,10 +17,10 @@ // export class InkTranscription extends React.Component { // static Instance: InkTranscription; -// @observable _mathRegister: any; -// @observable _mathRef: any; -// @observable _textRegister: any; -// @observable _textRef: any; +// @observable _mathRegister: any= undefined; +// @observable _mathRef: any= undefined; +// @observable _textRegister: any= undefined; +// @observable _textRef: any= undefined; // private lastJiix: any; // private currGroup?: Doc; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 9c96b4563..95c677845 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -20,9 +20,9 @@ Most of the operations that can be performed on an InkStroke (eg delete a point, rotate, stretch) are implemented in the InkStrokeProperties helper class */ -import * as React from 'react'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../fields/Doc'; import { InkData, InkField } from '../../fields/InkField'; import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types'; @@ -32,7 +32,6 @@ import { CognitiveServices } from '../cognitive_services/CognitiveServices'; import { Docs } from '../documents/Documents'; import { InteractionUtils } from '../util/InteractionUtils'; import { SnappingManager } from '../util/SnappingManager'; -import { Transform } from '../util/Transform'; import { UndoManager } from '../util/UndoManager'; import { ContextMenu } from './ContextMenu'; import { ViewBoxBaseComponent } from './DocComponent'; @@ -59,14 +58,14 @@ export class InkingStroke extends ViewBoxBaseComponent() { private _handledClick = false; // flag denoting whether ink stroke has handled a psuedo-click onPointerUp so that the real onClick event can be stopPropagated private _disposers: { [key: string]: IReactionDisposer } = {}; - @observable _nearestSeg?: number; // nearest Bezier segment along the ink stroke to the cursor (used for displaying the Add Point highlight) - @observable _nearestT?: number; // nearest t value within the nearest Bezier segment " + @observable _nearestSeg?: number = undefined; // nearest Bezier segment along the ink stroke to the cursor (used for displaying the Add Point highlight) + @observable _nearestT?: number = undefined; // nearest t value within the nearest Bezier segment " @observable _nearestScrPt?: { X: number; Y: number }; // nearst screen point on the ink stroke "" componentDidMount() { - this.props.setContentView?.(this); + this._props.setContentView?.(this); this._disposers.selfDisper = reaction( - () => this.props.isSelected(), // react to stroke being deselected by turning off ink handles + () => this._props.isSelected(), // react to stroke being deselected by turning off ink handles selected => !selected && (InkStrokeProperties.Instance._controlButton = false) ); } @@ -76,7 +75,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { // transform is the inherited screentolocal xf plus any scaling that was done to make the stroke // fit within its panel (e.g., for content fitting views like Lightbox or multicolumn, etc) - screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.NativeDimScaling?.() || 1); + screenToLocal = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1); getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { const subAnchor = this._subContentView?.getAnchor?.(addAsAnnotation); @@ -100,27 +99,6 @@ export class InkingStroke extends ViewBoxBaseComponent() { return this.Document; }; - /** - * @returns the center of the ink stroke in the ink document's coordinate space (not screen space, and not the ink data coordinate space); - * DocumentDecorations calls getBounds() on DocumentViews which call getCenter() if defined - in the case of ink it needs to be defined since - * the center of the ink stroke changes as the stroke is rotated. - */ - getCenter = (xf: Transform) => { - const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); - const angle = -NumCast(this.layoutDoc.rotation); - const newPoints = inkData.map(pt => { - const newX = Math.cos(angle) * pt.X - (Math.sin(angle) * pt.Y * inkScaleY) / inkScaleX; - const newY = (Math.sin(angle) * pt.X * inkScaleX) / inkScaleY + Math.cos(angle) * pt.Y; - return { X: newX, Y: newY }; - }); - const crx = (Math.max(...newPoints.map(np => np.X)) + Math.min(...newPoints.map(np => np.X))) / 2; - const cry = (Math.max(...newPoints.map(np => np.Y)) + Math.min(...newPoints.map(np => np.Y))) / 2; - const cx = Math.cos(-angle) * crx - (Math.sin(-angle) * cry * inkScaleY) / inkScaleX; - const cy = (Math.sin(-angle) * crx * inkScaleX) / inkScaleY + Math.cos(-angle) * cry; - const tc = xf.transformPoint((cx - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (cy - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2); - return { X: tc[0], Y: tc[1] }; - }; - /** * analyzes the ink stroke and saves the analysis of the stroke to the 'inkAnalysis' field, * and the recognized words to the 'handwriting' @@ -147,7 +125,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { @action onPointerDown = (e: React.PointerEvent) => { this._handledClick = false; - const inkView = this.props.docViewPath().lastElement(); + const inkView = this._props.docViewPath().lastElement(); const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); const screenPts = inkData .map(point => @@ -159,7 +137,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const { nearestSeg } = InkStrokeProperties.nearestPtToStroke(screenPts, { X: e.clientX, Y: e.clientY }); const controlIndex = nearestSeg; const wasSelected = InkStrokeProperties.Instance._currentPoint === controlIndex; - const isEditing = InkStrokeProperties.Instance._controlButton && this.props.isSelected(); + const isEditing = InkStrokeProperties.Instance._controlButton && this._props.isSelected(); this.controlUndo = undefined; setupMoveUpEvents( this, @@ -187,7 +165,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { 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(this._props.docViewPath().lastElement(), this._nearestT, this._nearestSeg, this.inkScaledData().inkData.slice()); } } }), @@ -258,8 +236,8 @@ export class InkingStroke extends ViewBoxBaseComponent() { inkLeft, inkWidth, inkHeight, - inkScaleX: (this.props.PanelWidth() - inkStrokeWidth) / (inkWidth - inkStrokeWidth || 1) || 1, - inkScaleY: (this.props.PanelHeight() - inkStrokeWidth) / (inkHeight - inkStrokeWidth || 1) || 1, + inkScaleX: (this._props.PanelWidth() - inkStrokeWidth) / (inkWidth - inkStrokeWidth || 1) || 1, + inkScaleY: (this._props.PanelHeight() - inkStrokeWidth) / (inkHeight - inkStrokeWidth || 1) || 1, }; }; @@ -311,7 +289,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { * @returns the JSX controls for displaying an editing UI for the stroke (control point & tangent handles) */ componentUI = (boundsLeft: number, boundsTop: number) => { - const inkDoc = this.props.Document; + const inkDoc = this.Document; const { inkData, inkStrokeWidth } = this.inkScaledData(); const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.screenToLocal().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke @@ -321,7 +299,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const endMarker = StrCast(this.layoutDoc.stroke_endMarker); const markerScale = NumCast(this.layoutDoc.stroke_markerScale); return SnappingManager.IsDragging ? null : !InkStrokeProperties.Instance._controlButton ? ( - !this.props.isSelected() || InkingStroke.IsClosed(inkData) ? null : ( + !this._props.isSelected() || InkingStroke.IsClosed(inkData) ? null : (
@@ -360,12 +338,12 @@ export class InkingStroke extends ViewBoxBaseComponent() { setSubContentView = (doc: DocComponentView) => (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'; + return isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FillColor) ?? 'transparent'; } @computed get strokeColor() { const { inkData } = this.inkScaledData(); const fillColor = this.fillColor; - return !InkingStroke.IsClosed(inkData) && fillColor && fillColor !== 'transparent' ? fillColor : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color) ?? StrCast(this.layoutDoc.color); + return !InkingStroke.IsClosed(inkData) && fillColor && fillColor !== 'transparent' ? fillColor : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) ?? StrCast(this.layoutDoc.color); } render() { TraceMobx(); @@ -385,9 +363,9 @@ export class InkingStroke extends ViewBoxBaseComponent() { this.layoutDoc._height = Math.round(NumCast(this.layoutDoc._height)); }); } - const highlight = !this.controlUndo && this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Highlighting); + const highlight = !this.controlUndo && this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Highlighting); const highlightIndex = highlight?.highlightIndex; - const highlightColor = !this.props.isSelected() && !isInkMask && highlight?.highlightIndex ? highlight?.highlightColor : undefined; + const highlightColor = !this._props.isSelected() && !isInkMask && highlight?.highlightIndex ? highlight?.highlightColor : undefined; const color = StrCast(this.layoutDoc.stroke_outlineColor, !closed && fillColor && fillColor !== 'transparent' ? StrCast(this.layoutDoc.color, 'transparent') : 'transparent'); // Visually renders the polygonal line made by the user. @@ -437,7 +415,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { inkScaleX, inkScaleY, '', - this.props.pointerEvents?.() ?? 'visiblepainted', + this._props.pointerEvents?.() ?? 'visiblepainted', 0.0, false, downHdlr, @@ -450,7 +428,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const lineHeightGuess = +getComputedStyle(document.body).lineHeight.replace('px', '') / +getComputedStyle(document.body).fontSize.replace('px', ''); const interactions = { onPointerLeave: action(() => (this._nearestScrPt = undefined)), - onPointerMove: this.props.isSelected() ? this.onPointerMove : undefined, + onPointerMove: this._props.isSelected() ? this.onPointerMove : undefined, onClick: (e: React.MouseEvent) => this._handledClick && e.stopPropagation(), onContextMenu: () => { const cm = ContextMenu.Instance; @@ -464,27 +442,27 @@ export class InkingStroke extends ViewBoxBaseComponent() { {clickableLine(this.onPointerDown, isInkMask)} {isInkMask ? null : inkLine} - {!closed || (!RTFCast(this.dataDoc.text)?.Text && (!this.props.isSelected() || Doc.UserDoc().activeInkHideTextLabels)) ? null : ( + {!closed || (!RTFCast(this.dataDoc.text)?.Text && (!this._props.isSelected() || Doc.UserDoc().activeInkHideTextLabels)) ? null : (
() { dontRegisterView={true} noSidebar={true} dontScale={true} - isContentActive={this.props.isContentActive} + isContentActive={this._props.isContentActive} />
)} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 094bd2adb..35ffab337 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -118,7 +118,7 @@ export class MainView extends ObservableReactComponent<{}> { @computed private get userDoc() { return Doc.UserDoc(); } - @observable mainDoc: Opt; + @observable mainDoc: Opt = undefined; @computed private get mainContainer() { if (window.location.pathname.startsWith('/doc/') && Doc.CurrentUserEmail === 'guest') { DocServer.GetRefField(window.location.pathname.substring('/doc/'.length)).then(main => runInAction(() => (this.mainDoc = main as Doc))); diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx index 5c6912121..89c3c41f8 100644 --- a/src/client/views/MetadataEntryMenu.tsx +++ b/src/client/views/MetadataEntryMenu.tsx @@ -1,12 +1,12 @@ -import * as React from 'react'; -import './MetadataEntryMenu.scss'; +import { IReactionDisposer, action, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { observable, action, runInAction, trace, computed, IReactionDisposer, reaction } from 'mobx'; -import { KeyValueBox } from './nodes/KeyValueBox'; -import { Doc, Field, DocListCastAsync, DocListCast } from '../../fields/Doc'; +import * as React from 'react'; import * as Autosuggest from 'react-autosuggest'; -import { undoBatch, UndoManager } from '../util/UndoManager'; import { emptyFunction, emptyPath } from '../../Utils'; +import { Doc, DocListCast, Field } from '../../fields/Doc'; +import { undoBatch } from '../util/UndoManager'; +import './MetadataEntryMenu.scss'; +import { KeyValueBox } from './nodes/KeyValueBox'; export type DocLike = Doc | Doc[] | Promise | Promise; export interface MetadataEntryProps { diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 166afc0c2..a69a5f5e8 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -24,7 +24,7 @@ export class PreviewCursor extends ObservableReactComponent<{}> { _addLiveTextDoc?: (doc: Doc) => void; _nudge?: undefined | ((x: number, y: number) => boolean); _slowLoadDocuments?: (files: File[] | string, options: DocumentOptions, generatedDocuments: Doc[], text: string, completed: ((doc: Doc[]) => void) | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => Promise; - @observable _clickPoint: number[]; + @observable _clickPoint: number[] = []; @observable public Visible = false; public Doc: Opt; constructor(props: any) { diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 8540e81e1..f1dadcd5e 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -2,6 +2,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Dropdown, DropdownType, IListItemProps, Toggle, ToggleType, Type } from 'browndash-components'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { AiOutlineColumnWidth } from 'react-icons/ai'; import { BiHide, BiShow } from 'react-icons/bi'; import { BsGrid3X3GapFill } from 'react-icons/bs'; @@ -12,28 +13,20 @@ import { RxWidth } from 'react-icons/rx'; import { TbEditCircle, TbEditCircleOff, TbHandOff, TbHandStop, TbHighlight, TbHighlightOff } from 'react-icons/tb'; import { TfiBarChart } from 'react-icons/tfi'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; -import { InkField } from '../../fields/InkField'; import { RichTextField } from '../../fields/RichTextField'; import { BoolCast, ScriptCast } from '../../fields/Types'; import { ImageField } from '../../fields/URLField'; -import { DocUtils } from '../documents/Documents'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; +import { DocUtils } from '../documents/Documents'; import { IsFollowLinkScript } from '../util/LinkFollower'; import { LinkManager } from '../util/LinkManager'; import { SelectionManager } from '../util/SelectionManager'; import { SettingsManager } from '../util/SettingsManager'; -import { undoable, undoBatch } from '../util/UndoManager'; -import { Colors } from './global/globalEnums'; +import { undoBatch, undoable } from '../util/UndoManager'; import { InkingStroke } from './InkingStroke'; -import { DocumentView, OpenWhere } from './nodes/DocumentView'; import './PropertiesButtons.scss'; -import * as React from 'react'; - -enum UtilityButtonState { - Default, - OpenRight, - OpenExternally, -} +import { Colors } from './global/globalEnums'; +import { DocumentView, OpenWhere } from './nodes/DocumentView'; @observer export class PropertiesButtons extends React.Component<{}, {}> { diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx index 58d3b72e8..244cd4aa0 100644 --- a/src/client/views/PropertiesDocBacklinksSelector.tsx +++ b/src/client/views/PropertiesDocBacklinksSelector.tsx @@ -7,10 +7,10 @@ import { DocumentType } from '../documents/DocumentTypes'; import { LinkManager } from '../util/LinkManager'; import { SelectionManager } from '../util/SelectionManager'; import { SettingsManager } from '../util/SettingsManager'; +import './PropertiesDocBacklinksSelector.scss'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { LinkMenu } from './linking/LinkMenu'; -import { OpenWhere, OpenWhereMod } from './nodes/DocumentView'; -import './PropertiesDocBacklinksSelector.scss'; +import { OpenWhere } from './nodes/DocumentView'; type PropertiesDocBacklinksSelectorProps = { Document: Doc; diff --git a/src/client/views/PropertiesSection.tsx b/src/client/views/PropertiesSection.tsx index 2b9bfb505..3c9fa1123 100644 --- a/src/client/views/PropertiesSection.tsx +++ b/src/client/views/PropertiesSection.tsx @@ -1,11 +1,9 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; -import './PropertiesSection.scss'; -import { Doc } from '../../fields/Doc'; -import { StrCast } from '../../fields/Types'; +import * as React from 'react'; import { SettingsManager } from '../util/SettingsManager'; +import './PropertiesSection.scss'; export interface PropertiesSectionProps { title: string; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 48653f30a..791928b4a 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -1,5 +1,6 @@ import { action, computed, observable, ObservableSet, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast } from '../../fields/Doc'; import { ScriptField } from '../../fields/ScriptField'; import { Cast, StrCast } from '../../fields/Types'; @@ -13,7 +14,6 @@ import { CollectionTreeView } from './collections/CollectionTreeView'; import { DocumentView } from './nodes/DocumentView'; import { DefaultStyleProvider } from './StyleProvider'; import './TemplateMenu.scss'; -import * as React from 'react'; @observer class TemplateToggle extends React.Component<{ template: string; checked: boolean; toggle: (event: React.ChangeEvent, template: string) => void }> { diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx index f07e38af1..ea038250e 100644 --- a/src/client/views/UndoStack.tsx +++ b/src/client/views/UndoStack.tsx @@ -15,8 +15,8 @@ interface UndoStackProps { } @observer export class UndoStack extends React.Component { - @observable static HideInline: boolean; - @observable static Expand: boolean; + @observable static HideInline: boolean = false; + @observable static Expand: boolean = false; render() { const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.userVariantColor; const color = UndoManager.batchCounter.get() ? 'black' : SettingsManager.userColor; @@ -39,19 +39,25 @@ export class UndoStack extends React.Component { color, }}> {Array.from(UndoManager.undoStackNames).map((name, i) => ( -
{ +
{ const size = UndoManager.undoStackNames.length; - for (let n = 0; n < size-i; n++ ) UndoManager.Undo(); } } - > + for (let n = 0; n < size - i; n++) UndoManager.Undo(); + }}>
{StrCast(name).replace(/[^\.]*\./, '')}
))} {Array.from(UndoManager.redoStackNames) .reverse() .map((name, i) => ( -
- { for (let n = 0; n <= i; n++ ) UndoManager.Redo() }}> +
{ + for (let n = 0; n <= i; n++) UndoManager.Redo(); + }}>
{StrCast(name).replace(/[^\.]*\./, '')}
diff --git a/src/client/views/animationtimeline/Region.tsx b/src/client/views/animationtimeline/Region.tsx index 15cbbc16f..99163f6c6 100644 --- a/src/client/views/animationtimeline/Region.tsx +++ b/src/client/views/animationtimeline/Region.tsx @@ -6,11 +6,11 @@ import { List } from '../../../fields/List'; import { createSchema, defaultSpec, listSpec, makeInterface } from '../../../fields/Schema'; import { Cast, NumCast } from '../../../fields/Types'; import { Transform } from '../../util/Transform'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import '../global/globalCssVariables.module.scss'; import './Region.scss'; import './Timeline.scss'; import { TimelineMenu } from './TimelineMenu'; -import { ObservableReactComponent } from '../ObservableReactComponent'; /** * Useful static functions that you can use. Mostly for logic, but you can also add UI logic here also diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index f27a2d2fd..cc4da1694 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -4,17 +4,17 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { Utils, emptyFunction, setupMoveUpEvents } from '../../../Utils'; import { Doc, DocListCast } from '../../../fields/Doc'; import { BoolCast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, setupMoveUpEvents, Utils } from '../../../Utils'; import { DocumentType } from '../../documents/DocumentTypes'; import clamp from '../../util/clamp'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { FieldViewProps } from '../nodes/FieldView'; import { RegionHelpers } from './Region'; import './Timeline.scss'; import { TimelineOverview } from './TimelineOverview'; import { Track } from './Track'; -import { ObservableReactComponent } from '../ObservableReactComponent'; /** * Timeline class controls most of timeline functions besides individual region and track mechanism. Main functions are diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 82ac69a3b..928739b53 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -28,7 +28,7 @@ export class TimelineOverview extends React.Component { @observable private overviewBarWidth: number = 0; @observable private playbarWidth: number = 0; @observable private activeOverviewWidth: number = 0; - @observable private _authoringReaction?: IReactionDisposer; + @observable private _authoringReaction?: IReactionDisposer = undefined; @observable private visibleTime: number = 0; @observable private currentX: number = 0; @observable private visibleStart: number = 0; diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 00aa51cac..490a14be5 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -8,10 +8,10 @@ import { ObjectField } from '../../../fields/ObjectField'; import { listSpec } from '../../../fields/Schema'; import { Cast, NumCast } from '../../../fields/Types'; import { Transform } from '../../util/Transform'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { Region, RegionData, RegionHelpers } from './Region'; import { Timeline } from './Timeline'; import './Track.scss'; -import { ObservableReactComponent } from '../ObservableReactComponent'; interface IProps { timeline: Timeline; @@ -29,9 +29,9 @@ interface IProps { @observer export class Track extends ObservableReactComponent { @observable private _inner = React.createRef(); - @observable private _currentBarXReaction: any; - @observable private _timelineVisibleReaction: any; - @observable private _autoKfReaction: any; + @observable private _currentBarXReaction: any = undefined; + @observable private _timelineVisibleReaction: any = undefined; + @observable private _autoKfReaction: any = undefined; @observable private _newKeyframe: boolean = false; private readonly MAX_TITLE_HEIGHT = 75; @observable private _trackHeight = 0; diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx index 2cec29669..4c0a917f5 100644 --- a/src/client/views/collections/CollectionCalendarView.tsx +++ b/src/client/views/collections/CollectionCalendarView.tsx @@ -1,18 +1,11 @@ -import * as React from 'react'; -import { CollectionSubView } from './CollectionSubView'; +import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; -import { computed, makeObservable, observable } from 'mobx'; -import { Doc, DocListCast, Opt } from '../../../fields/Doc'; +import * as React from 'react'; +import { dateRangeStrToDates, emptyFunction, returnTrue } from '../../../Utils'; +import { Doc, DocListCast } from '../../../fields/Doc'; +import { StrCast } from '../../../fields/Types'; import { CollectionStackingView } from './CollectionStackingView'; -import { CollectionViewType } from '../../documents/DocumentTypes'; -import { dateRangeStrToDates, emptyFunction, returnAll, returnEmptyDoclist, returnNone, returnOne, returnTrue } from '../../../Utils'; -import { DocumentView, DocumentViewProps } from '../nodes/DocumentView'; -import { TbRuler } from 'react-icons/tb'; -import { Transform } from '../../util/Transform'; -import { DocData } from '../../../fields/DocSymbols'; -import { Cast, NumCast, StrCast } from '../../../fields/Types'; -import { StyleProp } from '../StyleProvider'; -import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; +import { CollectionSubView } from './CollectionSubView'; @observer export class CollectionCalendarView extends CollectionSubView() { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 75c178136..868df7a3b 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -1,4 +1,4 @@ -import { action, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; +import { action, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; @@ -30,7 +30,7 @@ import { ScriptingRepl } from '../ScriptingRepl'; import { UndoStack } from '../UndoStack'; import './CollectionDockingView.scss'; import { CollectionFreeFormView } from './collectionFreeForm'; -import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; +import { CollectionSubView } from './CollectionSubView'; import { TabDocView } from './TabDocView'; const _global = (window /* browser */ || global) /* node */ as any; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 443aa3f17..2a6cb081f 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -32,16 +32,13 @@ interface CollectionMenuProps { @observer export class CollectionMenu extends AntimodeMenu { @observable static Instance: CollectionMenu; - @observable SelectedCollection: DocumentView | undefined = undefined; - @observable FieldKey: string; private _docBtnRef = React.createRef(); constructor(props: any) { super(props); makeObservable(this); - this.FieldKey = ''; CollectionMenu.Instance = this; this._canFade = false; // don't let the inking menu fade away this.Pinned = Cast(Doc.UserDoc()['menuCollections-pinned'], 'boolean', true); diff --git a/src/client/views/collections/CollectionNoteTakingViewDivider.tsx b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx index af822d917..2aad48d4a 100644 --- a/src/client/views/collections/CollectionNoteTakingViewDivider.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx @@ -1,4 +1,4 @@ -import { action, observable, trace } from 'mobx'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { emptyFunction, setupMoveUpEvents } from '../../../Utils'; diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 170b1f1ec..e5068645f 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -1,5 +1,6 @@ import { action, computed, IReactionDisposer, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast } from '../../../fields/Doc'; import { ScriptField } from '../../../fields/ScriptField'; import { NumCast, StrCast } from '../../../fields/Types'; @@ -12,7 +13,6 @@ import { computePassLayout, computeStarburstLayout } from './collectionFreeForm' import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import './CollectionPileView.scss'; import { CollectionSubView } from './CollectionSubView'; -import * as React from 'react'; @observer export class CollectionPileView extends CollectionSubView() { diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index fb8bc4da2..fa3844aa4 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -20,7 +20,7 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from '../../util/UndoManager'; -import { CollectionSubView, SubCollectionViewProps } from '../collections/CollectionSubView'; +import { CollectionSubView } from '../collections/CollectionSubView'; import { LightboxView } from '../LightboxView'; import { AudioWaveform } from '../nodes/audio/AudioWaveform'; import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../nodes/DocumentView'; @@ -56,7 +56,7 @@ export enum TrimScope { @observer export class CollectionStackedTimeline extends CollectionSubView() { @observable static SelectingRegion: CollectionStackedTimeline | undefined = undefined; - @observable public static CurrentlyPlaying: DocumentView[]; + @observable public static CurrentlyPlaying: DocumentView[] = []; constructor(props: any) { super(props); makeObservable(this); diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index f9d575da2..69f1c332d 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -20,8 +20,8 @@ import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; -import './CollectionStackingView.scss'; import { ObservableReactComponent } from '../ObservableReactComponent'; +import './CollectionStackingView.scss'; // So this is how we are storing a column interface CSVFieldColumnProps { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 2ff435ce2..570330174 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -4,11 +4,11 @@ import * as rp from 'request-promise'; import { Utils, returnFalse } from '../../../Utils'; import CursorField from '../../../fields/CursorField'; import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; -import { AclPrivate, DocData } from '../../../fields/DocSymbols'; +import { AclPrivate } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; -import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; @@ -41,8 +41,8 @@ export function CollectionSubView(moreProps?: X) { makeObservable(this); } - @observable _focusFilters: Opt; // childFilters that are overridden when previewing a link to an anchor which has childFilters set on it - @observable _focusRangeFilters: Opt; // childFiltersByRanges that are overridden when previewing a link to an anchor which has childFiltersByRanges set on it + @observable _focusFilters: Opt = undefined; // childFilters that are overridden when previewing a link to an anchor which has childFilters set on it + @observable _focusRangeFilters: Opt = undefined; // childFiltersByRanges that are overridden when previewing a link to an anchor which has childFiltersByRanges set on it protected createDashEventsTarget = (ele: HTMLDivElement | null) => { this.dropDisposer?.(); this.gestureDisposer?.(); diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 6033b897d..7bbdb7073 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -1,6 +1,8 @@ import { toUpper } from 'lodash'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { emptyFunction, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils'; import { Doc, Opt, StrListCast } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; @@ -8,7 +10,6 @@ import { RichTextField } from '../../../fields/RichTextField'; import { listSpec } from '../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../fields/ScriptField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; @@ -17,20 +18,19 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; import { DocFocusOptions, DocumentView } from '../nodes/DocumentView'; import { PresBox } from '../nodes/trails'; -import { computePivotLayout, computeTimelineLayout, ViewDefBounds } from './collectionFreeForm/CollectionFreeFormLayoutEngines'; -import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionSubView } from './CollectionSubView'; import './CollectionTimeView.scss'; -import * as React from 'react'; +import { ViewDefBounds, computePivotLayout, computeTimelineLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines'; +import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; @observer export class CollectionTimeView extends CollectionSubView() { _changing = false; @observable _layoutEngine = computePivotLayout.name; @observable _collapsed: boolean = false; - @observable _childClickedScript: Opt; - @observable _viewDefDivClick: Opt; - @observable _focusPivotField: Opt; + @observable _childClickedScript: Opt = undefined; + @observable _viewDefDivClick: Opt = undefined; + @observable _focusPivotField: Opt = undefined; constructor(props: any) { super(props); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 0656843cb..c2f5ab2c0 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -16,6 +16,7 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { OpenWhere } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; +import { CollectionCalendarView } from './CollectionCalendarView'; import { CollectionCarousel3DView } from './CollectionCarousel3DView'; import { CollectionCarouselView } from './CollectionCarouselView'; import { CollectionDockingView } from './CollectionDockingView'; @@ -28,7 +29,6 @@ import { CollectionTreeView } from './CollectionTreeView'; import './CollectionView.scss'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionGridView } from './collectionGrid/CollectionGridView'; -import { CollectionCalendarView } from './CollectionCalendarView'; import { CollectionLinearView } from './collectionLinear'; import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView'; import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView'; diff --git a/src/client/views/collections/KeyRestrictionRow.tsx b/src/client/views/collections/KeyRestrictionRow.tsx index f3071b316..4523a4f1e 100644 --- a/src/client/views/collections/KeyRestrictionRow.tsx +++ b/src/client/views/collections/KeyRestrictionRow.tsx @@ -1,6 +1,6 @@ -import * as React from "react"; -import { observable, runInAction } from "mobx"; -import { observer } from "mobx-react"; +import { observable, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; interface IKeyRestrictionProps { contains: boolean; @@ -19,37 +19,28 @@ export default class KeyRestrictionRow extends React.Component - runInAction(() => this._key = e.target.value)} - placeholder="KEY" /> - - runInAction(() => this._value = e.target.value)} - placeholder="VALUE" /> + runInAction(() => (this._value = e.target.value))} placeholder="VALUE" />
); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index a7705ea7e..72882ac17 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -93,7 +93,7 @@ export class TreeView extends ObservableReactComponent { static _openLevelScript: Opt; private _header: React.RefObject = React.createRef(); private _tref = React.createRef(); - @observable _docRef: Opt; + @observable _docRef: Opt = undefined; private _disposers: { [name: string]: IReactionDisposer } = {}; private _editTitleScript: (() => ScriptField) | undefined; private _openScript: (() => ScriptField) | undefined; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx index 99ee5ef4e..08dfb32ad 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx @@ -1,8 +1,8 @@ import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast } from '../../../../fields/Types'; import './CollectionFreeFormView.scss'; -import * as React from 'react'; export interface CollectionFreeFormViewBackgroundGridProps { panX: () => number; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx index 2606304d0..58f6b1593 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx @@ -1,5 +1,5 @@ import { IconButton, Size, Type } from 'browndash-components'; -import { action, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { SettingsManager } from '../../../util/SettingsManager'; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx index 15e4d8360..8628ca3c3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx @@ -1,16 +1,16 @@ -import { IReactionDisposer, makeObservable, observable, runInAction } from 'mobx'; +import { makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, Field, FieldResult } from '../../../../fields/Doc'; import { InkTool } from '../../../../fields/InkField'; +import { StrCast } from '../../../../fields/Types'; import { DocumentManager } from '../../../util/DocumentManager'; import { LinkManager } from '../../../util/LinkManager'; -import { DocButtonState, DocumentLinksButton } from '../../nodes/DocumentLinksButton'; import { ObservableReactComponent } from '../../ObservableReactComponent'; -import { CollectionFreeFormInfoState, InfoState, infoState, StateEntryFunc } from './CollectionFreeFormInfoState'; +import { DocButtonState, DocumentLinksButton } from '../../nodes/DocumentLinksButton'; +import { CollectionFreeFormInfoState, InfoState, StateEntryFunc, infoState } from './CollectionFreeFormInfoState'; import { CollectionFreeFormView } from './CollectionFreeFormView'; import './CollectionFreeFormView.scss'; -import { StrCast } from '../../../../fields/Types'; export interface CollectionFreeFormInfoUIProps { Document: Doc; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 779a0bf96..95d521f65 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -1,11 +1,11 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Id } from '../../../../fields/FieldSymbols'; import { DocumentManager } from '../../../util/DocumentManager'; import { LightboxView } from '../../LightboxView'; -import './CollectionFreeFormLinksView.scss'; import { CollectionFreeFormLinkView } from './CollectionFreeFormLinkView'; -import * as React from 'react'; +import './CollectionFreeFormLinksView.scss'; @observer export class CollectionFreeFormLinksView extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx index f54726a00..ec8416303 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx @@ -1,12 +1,11 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { ScriptField } from '../../../../fields/ScriptField'; import { PresBox } from '../../nodes/trails/PresBox'; -import './CollectionFreeFormView.scss'; -import * as React from 'react'; import { CollectionFreeFormView } from './CollectionFreeFormView'; - +import './CollectionFreeFormView.scss'; export interface CollectionFreeFormPannableContentsProps { Document: Doc; viewDefDivClick?: ScriptField; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 45e24bbb2..fa8218bdd 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,6 +1,8 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; import * as mobxUtils from 'mobx-utils'; +import * as React from 'react'; +import * as uuid from 'uuid'; import CursorField from '../../../../fields/CursorField'; import { Doc, FieldResult } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; @@ -9,8 +11,6 @@ import { listSpec } from '../../../../fields/Schema'; import { Cast } from '../../../../fields/Types'; import { CollectionViewProps } from '../CollectionView'; import './CollectionFreeFormView.scss'; -import * as React from 'react'; -import * as uuid from 'uuid'; @observer export class CollectionFreeFormRemoteCursors extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 645e9cff7..cc0833698 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -37,6 +37,7 @@ import { CtrlKey } from '../../GlobalKeyHandler'; import { ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke'; import { LightboxView } from '../../LightboxView'; import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewWrapper } from '../../nodes/CollectionFreeFormDocumentView'; +import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; @@ -52,7 +53,6 @@ import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannable import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors'; import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; -import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; export type collectionFreeformViewProps = { NativeWidth?: () => number; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b22fdfa19..39d828302 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -16,19 +16,18 @@ import { DocumentType } from '../../../documents/DocumentTypes'; import { DocUtils, Docs, DocumentOptions } from '../../../documents/Documents'; import { SelectionManager } from '../../../util/SelectionManager'; import { freeformScrollMode } from '../../../util/SettingsManager'; +import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { UndoManager, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { PreviewCursor } from '../../PreviewCursor'; -import { DocumentView, OpenWhere } from '../../nodes/DocumentView'; +import { OpenWhere } from '../../nodes/DocumentView'; import { pasteImageBitmap } from '../../nodes/WebBoxRenderer'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { SubCollectionViewProps } from '../CollectionSubView'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; -import { SnappingManager } from '../../../util/SnappingManager'; - interface MarqueeViewProps { getContainerTransform: () => Transform; getTransform: () => Transform; diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 1e19964d7..3e75257e5 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -7,7 +7,6 @@ import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; -import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; @@ -17,13 +16,12 @@ import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionGridView.scss'; import Grid, { Layout } from './Grid'; - @observer export class CollectionGridView extends CollectionSubView() { private _containerRef: React.RefObject = React.createRef(); private _changeListenerDisposer: Opt; // listens for changes in this.childLayoutPairs private _resetListenerDisposer: Opt; // listens for when the reset button is clicked - @observable private _rowHeight: Opt; // temporary store of row height to make change undoable + @observable private _rowHeight: Opt = undefined; // temporary store of row height to make change undoable @observable private _scroll: number = 0; // required to make sure the decorations box container updates on scroll private dropLocation: object = {}; // sets the drop location for external drops diff --git a/src/client/views/collections/collectionGrid/Grid.tsx b/src/client/views/collections/collectionGrid/Grid.tsx index 3d1d87aa0..9145d7ef1 100644 --- a/src/client/views/collections/collectionGrid/Grid.tsx +++ b/src/client/views/collections/collectionGrid/Grid.tsx @@ -1,5 +1,5 @@ -import * as React from 'react'; import { observer } from 'mobx-react'; +import * as React from 'react'; import '../../../../../node_modules/react-grid-layout/css/styles.css'; import '../../../../../node_modules/react-resizable/css/styles.css'; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index e12bcd8b0..5bea59e7b 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -4,13 +4,13 @@ import { Button } from 'browndash-components'; import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { returnFalse } from '../../../../Utils'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; -import { returnFalse } from '../../../../Utils'; import { DragManager, dropActionType } from '../../../util/DragManager'; import { SettingsManager } from '../../../util/SettingsManager'; import { Transform } from '../../../util/Transform'; -import { undoable, undoBatch } from '../../../util/UndoManager'; +import { undoBatch, undoable } from '../../../util/UndoManager'; import { DocumentView } from '../../nodes/DocumentView'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionMulticolumnView.scss'; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 7dbc18e60..3043eb0f8 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -1,9 +1,9 @@ import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { returnFalse } from '../../../../Utils'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; -import { returnFalse } from '../../../../Utils'; import { DragManager, dropActionType } from '../../../util/DragManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; @@ -12,7 +12,6 @@ import { CollectionSubView } from '../CollectionSubView'; import './CollectionMultirowView.scss'; import HeightLabel from './MultirowHeightLabel'; import ResizeBar from './MultirowResizer'; - interface HeightSpecifier { magnitude: number; unit: string; diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx index 868b1140d..ea99bff2e 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx @@ -1,12 +1,12 @@ -import * as React from 'react'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { observable, action } from 'mobx'; +import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { DimUnit } from './CollectionMulticolumnView'; import { UndoManager } from '../../../util/UndoManager'; -import { StyleProviderFunc } from '../../nodes/DocumentView'; import { StyleProp } from '../../StyleProvider'; +import { StyleProviderFunc } from '../../nodes/DocumentView'; +import { DimUnit } from './CollectionMulticolumnView'; interface ResizerProps { width: number; diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx index 9985a9fba..a9579d931 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx @@ -1,27 +1,25 @@ -import * as React from "react"; -import { observer } from "mobx-react"; -import { computed } from "mobx"; -import { Doc } from "../../../../fields/Doc"; -import { NumCast, StrCast, BoolCast } from "../../../../fields/Types"; -import { EditableView } from "../../EditableView"; -import { DimUnit } from "./CollectionMulticolumnView"; +import { computed } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc } from '../../../../fields/Doc'; +import { BoolCast, NumCast, StrCast } from '../../../../fields/Types'; +import { EditableView } from '../../EditableView'; +import { DimUnit } from './CollectionMulticolumnView'; interface WidthLabelProps { layout: Doc; collectionDoc: Doc; - decimals?: number; } @observer export default class WidthLabel extends React.Component { - @computed private get contents() { - const { layout, decimals } = this.props; + const { layout } = this.props; const getUnit = () => StrCast(layout.dimUnit); - const getMagnitude = () => String(+NumCast(layout.dimMagnitude).toFixed(decimals ?? 3)); + const getMagnitude = () => String(+NumCast(layout.dimMagnitude).toFixed(3)); return ( -
+
{ @@ -50,7 +48,6 @@ export default class WidthLabel extends React.Component { } render() { - return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : (null); + return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : null; } - -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx b/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx index aa5439fa4..878c7ff3c 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx @@ -1,10 +1,10 @@ -import * as React from "react"; -import { observer } from "mobx-react"; -import { computed } from "mobx"; -import { Doc } from "../../../../fields/Doc"; -import { NumCast, StrCast, BoolCast } from "../../../../fields/Types"; -import { EditableView } from "../../EditableView"; -import { DimUnit } from "./CollectionMultirowView"; +import { computed } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc } from '../../../../fields/Doc'; +import { BoolCast, NumCast, StrCast } from '../../../../fields/Types'; +import { EditableView } from '../../EditableView'; +import { DimUnit } from './CollectionMultirowView'; interface HeightLabelProps { layout: Doc; @@ -14,14 +14,13 @@ interface HeightLabelProps { @observer export default class HeightLabel extends React.Component { - @computed private get contents() { const { layout, decimals } = this.props; const getUnit = () => StrCast(layout.dimUnit); const getMagnitude = () => String(+NumCast(layout.dimMagnitude).toFixed(decimals ?? 3)); return ( -
+
{ @@ -50,7 +49,6 @@ export default class HeightLabel extends React.Component { } render() { - return BoolCast(this.props.collectionDoc.showHeightLabels) ? this.contents : (null); + return BoolCast(this.props.collectionDoc.showHeightLabels) ? this.contents : null; } - -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx index 5a9d6a82c..7dee65e58 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx @@ -1,12 +1,12 @@ -import * as React from 'react'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { observable, action } from 'mobx'; +import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { DimUnit } from './CollectionMultirowView'; import { UndoManager } from '../../../util/UndoManager'; import { StyleProp } from '../../StyleProvider'; import { StyleProviderFunc } from '../../nodes/DocumentView'; +import { DimUnit } from './CollectionMultirowView'; interface ResizerProps { height: number; diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index 04443b4a7..5f8b412be 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -1,7 +1,7 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable } from 'mobx'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { Colors } from '../../global/globalEnums'; import './CollectionSchemaView.scss'; diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 06073b52c..85e97f95f 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -1,3 +1,4 @@ +import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, makeObservable, observable } from 'mobx'; @@ -7,18 +8,17 @@ import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { Cast, DocCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; +import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; +import { undoBatch } from '../../util/UndoManager'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView'; import { LinkInfo } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; -import { undoBatch } from '../../util/UndoManager'; -import { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { DocumentType } from '../../documents/DocumentTypes'; interface LinkMenuItemProps { groupType: string; diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index 5460a6daf..7e344dd7a 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -1,16 +1,16 @@ import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import { EditorView } from 'prosemirror-view'; -import { Doc } from '../../../fields/Doc'; +import * as React from 'react'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils'; +import { Doc } from '../../../fields/Doc'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; +import { DefaultStyleProvider } from '../StyleProvider'; import { OpenWhere } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { SearchBox } from '../search/SearchBox'; -import { DefaultStyleProvider } from '../StyleProvider'; import './LinkPopup.scss'; -import * as React from 'react'; interface LinkPopupProps { linkFrom?: () => Doc | undefined; @@ -29,7 +29,7 @@ interface LinkPopupProps { @observer export class LinkPopup extends React.Component { @observable private linkURL: string = ''; - @observable public view?: EditorView; + @observable public view?: EditorView = undefined; // TODO: should check for valid URL @undoBatch diff --git a/src/client/views/linking/LinkRelationshipSearch.tsx b/src/client/views/linking/LinkRelationshipSearch.tsx index 3e7f5be74..0902d53b2 100644 --- a/src/client/views/linking/LinkRelationshipSearch.tsx +++ b/src/client/views/linking/LinkRelationshipSearch.tsx @@ -1,6 +1,6 @@ import { observer } from 'mobx-react'; -import './LinkEditor.scss'; import * as React from 'react'; +import './LinkEditor.scss'; interface link_relationshipSearchProps { results: string[] | undefined; diff --git a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx index 72b63cf8f..bce2b296f 100644 --- a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx +++ b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx @@ -3,12 +3,12 @@ import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { InkTool } from '../../../../fields/InkField'; import { SelectionManager } from '../../../util/SelectionManager'; +import { SnappingManager } from '../../../util/SnappingManager'; import { CollectionDockingView } from '../../collections/CollectionDockingView'; -import { DocumentView, OpenWhereMod } from '../../nodes/DocumentView'; +import { OpenWhereMod } from '../../nodes/DocumentView'; import { NewLightboxView } from '../NewLightboxView'; import './ButtonMenu.scss'; import { IButtonMenu } from './utils'; -import { SnappingManager } from '../../../util/SnappingManager'; export const ButtonMenu = (props: IButtonMenu) => { return ( diff --git a/src/client/views/newlightbox/NewLightboxView.tsx b/src/client/views/newlightbox/NewLightboxView.tsx index 6980e31c1..3d159c3e3 100644 --- a/src/client/views/newlightbox/NewLightboxView.tsx +++ b/src/client/views/newlightbox/NewLightboxView.tsx @@ -2,28 +2,28 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../../Utils'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { LinkManager } from '../../util/LinkManager'; import { SelectionManager } from '../../util/SelectionManager'; +import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; -import { CollectionStackedTimeline } from '../collections/CollectionStackedTimeline'; -import { TabDocView } from '../collections/TabDocView'; import { GestureOverlay } from '../GestureOverlay'; import { LightboxView } from '../LightboxView'; -import { DocumentView, OpenWhere } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; -import { IRecommendation } from './components'; +import { CollectionStackedTimeline } from '../collections/CollectionStackedTimeline'; +import { TabDocView } from '../collections/TabDocView'; +import { DocumentView, OpenWhere } from '../nodes/DocumentView'; import { ExploreView } from './ExploreView'; -import { emptyBounds, IBounds } from './ExploreView/utils'; +import { IBounds, emptyBounds } from './ExploreView/utils'; import { NewLightboxHeader } from './Header'; import './NewLightboxView.scss'; import { RecommendationList } from './RecommendationList'; -import { SnappingManager } from '../../util/SnappingManager'; +import { IRecommendation } from './components'; enum LightboxStatus { RECOMMENDATIONS = 'recommendations', @@ -50,15 +50,15 @@ export class NewLightboxView extends React.Component { return this._doc; } private static LightboxDocTemplate = () => NewLightboxView._layoutTemplate; - @observable private static _layoutTemplate: Opt; - @observable private static _layoutTemplateString: Opt; - @observable private static _doc: Opt; - @observable private static _docTarget: Opt; + @observable private static _layoutTemplate: Opt = undefined; + @observable private static _layoutTemplateString: Opt = undefined; + @observable private static _doc: Opt = undefined; + @observable private static _docTarget: Opt = undefined; @observable private static _docFilters: string[] = []; // filters - private static _savedState: Opt; + private static _savedState: Opt = undefined; private static _history: Opt<{ doc: Doc; target?: Doc }[]> = []; @observable private static _future: Opt = []; - @observable private static _docView: Opt; + @observable private static _docView: Opt = undefined; // keywords @observable private static _keywords: string[] = []; diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 4c36d2fcb..12e8e1a69 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -44,8 +44,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { private _annotationLayer: React.RefObject = React.createRef(); anchorMenuClick?: () => undefined | ((anchor: Doc) => void); crop: ((region: Doc | undefined, addCrop?: boolean) => Doc | undefined) | undefined; - @observable schemaDataVizChildren: any; - @observable _marqueeing: number[] | undefined; + @observable schemaDataVizChildren: any = undefined; + @observable _marqueeing: number[] | undefined = undefined; @observable _savedAnnotations = new ObservableMap(); @computed get annotationLayer() { TraceMobx(); diff --git a/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx b/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx index 3cb5125da..24023077f 100644 --- a/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx +++ b/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx @@ -1,15 +1,14 @@ -import * as React from 'react'; -import './SchemaCSVPopUp.scss'; +import { IconButton } from 'browndash-components'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { CgClose } from 'react-icons/cg'; +import { Utils, emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { Doc } from '../../../../fields/Doc'; -import { Button, IconButton, Type } from 'browndash-components'; import { StrCast } from '../../../../fields/Types'; -import { MarqueeView } from '../../collections/collectionFreeForm/MarqueeView'; -import { Utils, emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { DragManager } from '../../../util/DragManager'; import { DocumentView } from '../DocumentView'; -import { CgClose } from 'react-icons/cg'; +import './SchemaCSVPopUp.scss'; interface SchemaCSVPopUpProps {} @@ -56,13 +55,11 @@ export class SchemaCSVPopUp extends React.Component {
{this.heading('Schema Table as Data Visualization Doc')}
-
-
this.drag(e)}> - -
+
+
this.drag(e)}> +
+
); @@ -88,9 +85,10 @@ export class SchemaCSVPopUp extends React.Component { return embedding; }; if (this.view && sourceAnchorCreator && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { - DragManager.StartAnchorAnnoDrag(e.target instanceof HTMLElement ? [e.target] : [], - new DragManager.AnchorAnnoDragData(this.view, sourceAnchorCreator, targetCreator), downX, downY, { - dragComplete: e => {this.setVisible(false);}, + DragManager.StartAnchorAnnoDrag(e.target instanceof HTMLElement ? [e.target] : [], new DragManager.AnchorAnnoDragData(this.view, sourceAnchorCreator, targetCreator), downX, downY, { + dragComplete: e => { + this.setVisible(false); + }, }); return true; } @@ -108,4 +106,4 @@ export class SchemaCSVPopUp extends React.Component {
); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 227c993c7..9e9a43b34 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -1,7 +1,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ColorPicker, EditableText, IconButton, Size, Type } from 'browndash-components'; import * as d3 from 'd3'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { FaFillDrip } from 'react-icons/fa'; @@ -11,10 +11,10 @@ import { listSpec } from '../../../../../fields/Schema'; import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; import { Docs } from '../../../../documents/Documents'; import { undoable } from '../../../../util/UndoManager'; +import { ObservableReactComponent } from '../../../ObservableReactComponent'; import { PinProps, PresBox } from '../../trails'; import { scaleCreatorNumerical, yAxisCreator } from '../utils/D3Utils'; import './Chart.scss'; -import { ObservableReactComponent } from '../../../ObservableReactComponent'; export interface HistogramProps { Document: Doc; @@ -461,7 +461,7 @@ export class Histogram extends ObservableReactComponent { if (this._histogramData.length > 0 || !this.parentViz) { return this._props.axes.length >= 1 ? ( -
+
{ private _lineChartSvg: d3.Selection | undefined; @observable _currSelected: SelectedDataPoint | undefined = undefined; // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates - constructor(props:any) { + constructor(props: any) { super(props); makeObservable(this); } - @computed get _tableDataIds() { return !this.parentViz ? this._props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows); } @@ -359,7 +358,7 @@ export class LineChart extends ObservableReactComponent { const selectedPt = this._currSelected ? `{ ${this._props.axes[0]}: ${this._currSelected.x} ${this._props.axes[1]}: ${this._currSelected.y} }` : 'none'; if (this._lineChartData.length > 0 || !this.parentViz || this.parentViz.length == 0) { return this._props.axes.length >= 2 && /\d/.test(this._props.records[0][this._props.axes[0]]) && /\d/.test(this._props.records[0][this._props.axes[1]]) ? ( -
+
{ />
- {selectedPt != 'none' ? -
+ {selectedPt != 'none' ? ( +
{`Selected: ${selectedPt}`} - -
- : null} + +
+ ) : null}
) : ( {'first use table view to select two numerical axes to plot'} diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index e644870da..e67556cd0 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -1,7 +1,7 @@ import { Checkbox } from '@mui/material'; import { ColorPicker, EditableText, Size, Type } from 'browndash-components'; import * as d3 from 'd3'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { FaFillDrip } from 'react-icons/fa'; @@ -11,9 +11,9 @@ import { listSpec } from '../../../../../fields/Schema'; import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; import { Docs } from '../../../../documents/Documents'; import { undoable } from '../../../../util/UndoManager'; +import { ObservableReactComponent } from '../../../ObservableReactComponent'; import { PinProps, PresBox } from '../../trails'; import './Chart.scss'; -import { ObservableReactComponent } from '../../../ObservableReactComponent'; export interface PieChartProps { Document: Doc; @@ -356,7 +356,7 @@ export class PieChart extends ObservableReactComponent { if (this._pieChartData.length > 0 || !this.parentViz) { return this._props.axes.length >= 1 ? ( -
+
{ return (this.viewScale * this._tableHeight) / this._tableDataIds.length; } @computed get startID() { - return this.rowHeight ? Math.max(Math.floor(this._scrollTop / this.rowHeight)-1, 0) : 0; + return this.rowHeight ? Math.max(Math.floor(this._scrollTop / this.rowHeight) - 1, 0) : 0; } @computed get endID() { console.log('start = ' + this.startID + ' container = ' + this._tableContainerHeight + ' scale = ' + this.viewScale + ' row = ' + this.rowHeight); @@ -169,7 +169,7 @@ export class TableBox extends ObservableReactComponent { return (
{ if (this._props.layoutDoc && e.key === 'a' && (e.ctrlKey || e.metaKey)) { @@ -226,7 +226,7 @@ export class TableBox extends ObservableReactComponent { {this._tableDataIds - .filter((rowId, i) => this.startID-2 <= i && i <= this.endID+2) + .filter((rowId, i) => this.startID - 2 <= i && i <= this.endID + 2) ?.map(rowId => ( ; export interface JsxBindings { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cc7fca8d2..f8f4b94a2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,10 +1,11 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { Dropdown, DropdownType, Type } from 'browndash-components'; +import { Howl } from 'howler'; import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; -import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal'; import * as React from 'react'; +import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal'; import { Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils'; import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; import { AclPrivate, Animation, AudioPlay, DocViews } from '../../../fields/DocSymbols'; @@ -53,7 +54,6 @@ import { LinkAnchorBox } from './LinkAnchorBox'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { PresEffect, PresEffectDirection } from './trails'; import { PinProps, PresBox } from './trails/PresBox'; -import { Howl } from 'howler'; interface Window { MediaRecorder: MediaRecorder; @@ -138,7 +138,6 @@ export interface DocComponentView { dragStarting?: (snapToDraggedDoc: boolean, showGroupDragTarget: boolean, visited: Set) => void; incrementalRendering?: () => void; infoUI?: () => JSX.Element | null; - getCenter?: (xf: Transform) => { X: number; Y: number }; screenBounds?: () => Opt<{ left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } }>; ptToScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; ptFromScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; @@ -1516,7 +1515,7 @@ export class DocumentView extends ObservableReactComponent { const docuBox = this.docView.ContentDiv.getElementsByClassName('linkAnchorBox-cont'); if (docuBox.length) return { ...docuBox[0].getBoundingClientRect(), center: undefined }; } - return { left, top, right, bottom, center: this.ComponentView?.getCenter?.(xf) }; + return { left, top, right, bottom }; }; public iconify(finished?: () => void, animateTime?: number) { diff --git a/src/client/views/nodes/FaceRectangle.tsx b/src/client/views/nodes/FaceRectangle.tsx index 8d03bf57a..46bc6eb03 100644 --- a/src/client/views/nodes/FaceRectangle.tsx +++ b/src/client/views/nodes/FaceRectangle.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; -import { observer } from 'mobx-react'; import { observable, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; import { RectangleTemplate } from './FaceRectangles'; @observer diff --git a/src/client/views/nodes/FaceRectangles.tsx b/src/client/views/nodes/FaceRectangles.tsx index 26e720c0d..ade4225d9 100644 --- a/src/client/views/nodes/FaceRectangles.tsx +++ b/src/client/views/nodes/FaceRectangles.tsx @@ -1,8 +1,8 @@ +import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../../fields/Doc'; -import { Cast, NumCast } from '../../../fields/Types'; -import { observer } from 'mobx-react'; import { Id } from '../../../fields/FieldSymbols'; +import { Cast, NumCast } from '../../../fields/Types'; import FaceRectangle from './FaceRectangle'; interface FaceRectanglesProps { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index f4c5167a5..008f10f26 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { DateField } from '../../../fields/DateField'; import { Doc, Field, FieldResult, Opt } from '../../../fields/Doc'; import { List } from '../../../fields/List'; diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index fd8d8ef56..7bc9d3f85 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -1,7 +1,6 @@ import { Tooltip } from '@mui/material'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { ObservableGroupMap } from 'mobx-utils'; import * as React from 'react'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../Utils'; import { Doc, Field } from '../../../fields/Doc'; @@ -11,13 +10,13 @@ import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { EditableView } from '../EditableView'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider } from '../StyleProvider'; import { OpenWhere } from './DocumentView'; import { FieldViewProps } from './FieldView'; import { KeyValueBox } from './KeyValueBox'; import './KeyValueBox.scss'; import './KeyValuePair.scss'; -import { ObservableReactComponent } from '../ObservableReactComponent'; // Represents one row in a key value plane @@ -35,12 +34,11 @@ export class KeyValuePair extends ObservableReactComponent { @observable private isPointerOver = false; @observable public isChecked = false; private checkbox = React.createRef(); - constructor(props:any) { + constructor(props: any) { super(props); makeObservable(this); } - @action handleCheck = (e: React.ChangeEvent) => { this.isChecked = e.currentTarget.checked; diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index 32300d60a..8ad0b7dde 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../fields/Doc'; import { LinkManager } from '../../util/LinkManager'; import './LinkDescriptionPopup.scss'; diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index d0a9f10b4..ea23ecbea 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -2,13 +2,14 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import wiki from 'wikijs'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils'; import { DocServer } from '../../DocServer'; -import { Docs } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; +import { Docs } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; @@ -16,10 +17,9 @@ import { LinkManager } from '../../util/LinkManager'; import { SearchUtil } from '../../util/SearchUtil'; import { SettingsManager } from '../../util/SettingsManager'; import { Transform } from '../../util/Transform'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; import './LinkDocPreview.scss'; -import * as React from 'react'; -import { ObservableReactComponent } from '../ObservableReactComponent'; export class LinkInfo { private static _instance: Opt; diff --git a/src/client/views/nodes/LoadingBox.tsx b/src/client/views/nodes/LoadingBox.tsx index 27d73a585..adccc9db6 100644 --- a/src/client/views/nodes/LoadingBox.tsx +++ b/src/client/views/nodes/LoadingBox.tsx @@ -1,4 +1,4 @@ -import { action, observable, runInAction } from 'mobx'; +import { observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import ReactLoading from 'react-loading'; diff --git a/src/client/views/nodes/MapBox/AnimationUtility.ts b/src/client/views/nodes/MapBox/AnimationUtility.ts index 42dfa59b7..35153f439 100644 --- a/src/client/views/nodes/MapBox/AnimationUtility.ts +++ b/src/client/views/nodes/MapBox/AnimationUtility.ts @@ -1,13 +1,10 @@ -import mapboxgl from 'mapbox-gl'; -import { MercatorCoordinate } from 'mapbox-gl'; -import { MapRef } from 'react-map-gl'; -import * as React from 'react'; -import * as d3 from 'd3'; import * as turf from '@turf/turf'; import { Position } from '@turf/turf'; -import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from 'geojson'; -import { observer } from 'mobx-react'; -import { action, computed, observable, runInAction, makeObservable } from 'mobx'; +import * as d3 from 'd3'; +import { Feature, GeoJsonProperties, Geometry } from 'geojson'; +import mapboxgl, { MercatorCoordinate } from 'mapbox-gl'; +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; +import { MapRef } from 'react-map-gl'; export enum AnimationStatus { START = 'start', diff --git a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx index f9607becf..7e99795b5 100644 --- a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx +++ b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx @@ -1,15 +1,15 @@ -import * as React from 'react'; -import { observer } from 'mobx-react'; -import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; +import { IconLookup, faAdd, faCalendarDays, faRoute } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { IconButton } from 'browndash-components'; import { IReactionDisposer, ObservableMap, reaction } from 'mobx'; -import { Doc, Opt } from '../../../../fields/Doc'; +import { observer } from 'mobx-react'; +import * as React from 'react'; import { returnFalse, unimplementedFunction } from '../../../../Utils'; +import { Doc, Opt } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; import { SelectionManager } from '../../../util/SelectionManager'; -import { IconButton } from 'browndash-components'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { SettingsManager } from '../../../util/SettingsManager'; -import { IconLookup, faAdd, faCalendarDays, faRoute } from '@fortawesome/free-solid-svg-icons'; +import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; @observer export class DirectionsAnchorMenu extends AntimodeMenu { diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx index 1b1b74e7c..08bea5d9d 100644 --- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx +++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx @@ -1,26 +1,23 @@ +import { IconLookup, faAdd, faArrowDown, faArrowLeft, faArrowsRotate, faBicycle, faCalendarDays, faCar, faDiamondTurnRight, faEdit, faPersonWalking, faRoute } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import * as React from 'react'; +import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/material'; +import { IconButton } from 'browndash-components'; +import { Position } from 'geojson'; import { IReactionDisposer, ObservableMap, action, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { Doc, NumListCast, Opt } from '../../../../fields/Doc'; +import * as React from 'react'; +import { CirclePicker, ColorResult } from 'react-color'; import { returnFalse, setupMoveUpEvents, unimplementedFunction } from '../../../../Utils'; +import { Doc, Opt } from '../../../../fields/Doc'; +import { NumCast, StrCast } from '../../../../fields/Types'; +import { CalendarManager } from '../../../util/CalendarManager'; import { SelectionManager } from '../../../util/SelectionManager'; -import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; -// import { GPTPopup, GPTPopupMode } from './../../GPTPopup/GPTPopup'; -import { Button, IconButton } from 'browndash-components'; import { SettingsManager } from '../../../util/SettingsManager'; +import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; import './MapAnchorMenu.scss'; -import { NumCast, StrCast } from '../../../../fields/Types'; -import { IconLookup, faDiamondTurnRight, faCalendarDays, faEdit, faAdd, faRoute, faArrowLeft, faLocationDot, faArrowDown, faCar, faBicycle, faPersonWalking, faUpload, faArrowsRotate } from '@fortawesome/free-solid-svg-icons'; -import { DirectionsAnchorMenu } from './DirectionsAnchorMenu'; -import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/material'; import { MapboxApiUtility, TransportationType } from './MapboxApiUtility'; -import { MapBox } from './MapBox'; -import { List } from '../../../../fields/List'; import { MarkerIcons } from './MarkerIcons'; -import { CirclePicker, ColorResult } from 'react-color'; -import { Position } from 'geojson'; -import { CalendarManager } from '../../../util/CalendarManager'; +// import { GPTPopup, GPTPopupMode } from './../../GPTPopup/GPTPopup'; type MapAnchorMenuType = 'standard' | 'routeCreation' | 'calendar' | 'customize' | 'route'; @@ -52,7 +49,6 @@ export class MapAnchorMenu extends AntimodeMenu { public UpdateMarkerColor: (color: string) => void = unimplementedFunction; public UpdateMarkerIcon: (iconKey: string) => void = unimplementedFunction; - public Hide: () => void = unimplementedFunction; public OpenAnimationPanel: (routeDoc: Doc | undefined) => void = unimplementedFunction; @@ -74,22 +70,21 @@ export class MapAnchorMenu extends AntimodeMenu { private title: string | undefined = undefined; public setPinDoc(pinDoc: Doc | undefined) { - if (pinDoc){ + if (pinDoc) { this.pinDoc = pinDoc; this.title = StrCast(pinDoc.title ? pinDoc.title : `${NumCast(pinDoc.longitude)}, ${NumCast(pinDoc.latitude)}`); } - } public setRouteDoc(routeDoc: Doc | undefined) { - if (routeDoc){ + if (routeDoc) { this.routeDoc = routeDoc; this.title = StrCast(routeDoc.title ?? 'Map route'); } } @action - public Reset(){ + public Reset() { this.destinationSelected = false; this.currentRouteInfoMap = undefined; this.destinationFeatures = []; @@ -296,34 +291,23 @@ export class MapAnchorMenu extends AntimodeMenu { return undefined; }; - getDirectionsButton: JSX.Element = ( - } - color={SettingsManager.userColor} /> - ) + getDirectionsButton: JSX.Element = (} color={SettingsManager.userColor} />); getAddToCalendarButton = (docType: string): JSX.Element => { return ( - { - CalendarManager.Instance.open(undefined, docType === 'pin' ? this.pinDoc : this.routeDoc) - }} - icon={} - color={SettingsManager.userColor} + { + CalendarManager.Instance.open(undefined, docType === 'pin' ? this.pinDoc : this.routeDoc); + }} + icon={} + color={SettingsManager.userColor} /> - ) - - } + ); + }; addToCalendarButton: JSX.Element = ( - CalendarManager.Instance.open(undefined, this.pinDoc)} - icon={} - color={SettingsManager.userColor} /> - ) + CalendarManager.Instance.open(undefined, this.pinDoc)} icon={} color={SettingsManager.userColor} /> + ); getLinkNoteToDocButton = (docType: string): JSX.Element => { return ( @@ -335,8 +319,8 @@ export class MapAnchorMenu extends AntimodeMenu { color={SettingsManager.userColor} />
- ) - } + ); + }; linkNoteToPinOrRoutenButton: JSX.Element = (
@@ -347,16 +331,9 @@ export class MapAnchorMenu extends AntimodeMenu { color={SettingsManager.userColor} />
- ) - - customizePinButton: JSX.Element = ( - } - color={SettingsManager.userColor} - /> - ) + ); + + customizePinButton: JSX.Element = (} color={SettingsManager.userColor} />); centerOnPinButton: JSX.Element = ( { icon={} color={SettingsManager.userColor} /> - ) + ); backButton: JSX.Element = ( { icon={} color={SettingsManager.userColor} /> - ) + ); addRouteButton: JSX.Element = ( { icon={} color={SettingsManager.userColor} /> - ) + ); getDeleteButton = (type: string) => { return ( @@ -393,17 +370,10 @@ export class MapAnchorMenu extends AntimodeMenu { icon={} color={SettingsManager.userColor} /> - ) - } + ); + }; - animateRouteButton: JSX.Element = ( - this.OpenAnimationPanel(this.routeDoc)} - icon={} - color={SettingsManager.userColor} - /> - ) + animateRouteButton: JSX.Element = ( this.OpenAnimationPanel(this.routeDoc)} icon={} color={SettingsManager.userColor} />); revertToOriginalMarkerButton = ( { icon={} color={SettingsManager.userColor} /> - ) + ); render() { const buttons = ( diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 7db139d74..ffd52fb0e 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -1,8 +1,17 @@ +import { IconLookup, faCircleXmark, faGear, faPause, faPlay, faRotate } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Checkbox, FormControlLabel, TextField } from '@mui/material'; +import * as turf from '@turf/turf'; import { IconButton, Size, Type } from 'browndash-components'; +import * as d3 from 'd3'; +import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, Position } from 'geojson'; +import mapboxgl, { LngLat, LngLatBoundsLike, MapLayerMouseEvent } from 'mapbox-gl'; import { IReactionDisposer, ObservableMap, action, autorun, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { CirclePicker, ColorResult } from 'react-color'; +import { Layer, MapProvider, MapRef, Map as MapboxMap, Marker, Source, ViewState, ViewStateChangeEvent } from 'react-map-gl'; +import { MarkerEvent } from 'react-map-gl/dist/esm/types'; import { Utils, emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc'; import { DocCss, Highlight } from '../../../../fields/DocSymbols'; @@ -22,22 +31,13 @@ import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; -import { MapAnchorMenu } from './MapAnchorMenu'; -import { ControlPosition, Layer, MapProvider, MapRef, Map as MapboxMap, Marker, MarkerProps, Source, ViewState, ViewStateChangeEvent } from 'react-map-gl'; -import './MapBox.scss'; -// import { GeocoderControl } from './GeocoderControl'; -import { IconLookup, faCircleXmark, faGear, faPause, faPlay, faRotate } from '@fortawesome/free-solid-svg-icons'; -import { Checkbox, FormControlLabel, TextField } from '@mui/material'; -import * as turf from '@turf/turf'; -import * as d3 from 'd3'; -import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, Position } from 'geojson'; -import mapboxgl, { LngLat, LngLatBoundsLike, MapLayerMouseEvent } from 'mapbox-gl'; -import { CirclePicker, ColorResult } from 'react-color'; -import { MarkerEvent } from 'react-map-gl/dist/esm/types'; import { fastSpeedIcon, mediumSpeedIcon, slowSpeedIcon } from './AnimationSpeedIcons'; import { AnimationSpeed, AnimationStatus, AnimationUtility } from './AnimationUtility'; +import { MapAnchorMenu } from './MapAnchorMenu'; +import './MapBox.scss'; import { MapboxApiUtility, TransportationType } from './MapboxApiUtility'; import { MarkerIcons } from './MarkerIcons'; +// import { GeocoderControl } from './GeocoderControl'; // amongus /** @@ -480,7 +480,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { @@ -650,7 +650,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { - console.log('deleting') + console.log('deleting'); if (this.selectedPinOrRoute) { // Removes filter Doc.setDocFilter(this.Document, 'latitude', this.selectedPinOrRoute.latitude, 'remove'); @@ -677,15 +677,12 @@ export class MapBox extends ViewBoxAnnotatableComponent { if (this.selectedPinOrRoute) { @@ -882,8 +879,8 @@ export class MapBox extends ViewBoxAnnotatableComponent { return ( <> @@ -1423,20 +1417,14 @@ export class MapBox extends ViewBoxAnnotatableComponent
|
- } - /> + } />
|
|
-
+
Select Line Color:
- this.setAnimationLineColor(color)} /> + this.setAnimationLineColor(color)} />
-
@@ -1478,7 +1466,7 @@ export class MapBox extends ViewBoxAnnotatableComponent) => { const bearing = parseInt(e.target.value); if (!isNaN(bearing) && this._mapRef.current) { - console.log('bearing change') + console.log('bearing change'); const fixedBearing = Math.max(0, Math.min(360, bearing)); this._mapRef.current.setBearing(fixedBearing); this.dataDoc.map_bearing = fixedBearing; @@ -1489,7 +1477,7 @@ export class MapBox extends ViewBoxAnnotatableComponent) => { const pitch = parseInt(e.target.value); if (!isNaN(pitch) && this._mapRef.current) { - console.log('pitch change') + console.log('pitch change'); const fixedPitch = Math.max(0, Math.min(85, pitch)); this._mapRef.current.setPitch(fixedPitch); this.dataDoc.map_pitch = fixedPitch; @@ -1648,7 +1636,7 @@ export class MapBox extends ViewBoxAnnotatableComponent = React.createRef(); -// @observable private _overlayAnnoInfo: Opt; +// @observable private _overlayAnnoInfo: Opt = undefined; // showInfo = action((anno: Opt) => (this._overlayAnnoInfo = anno)); // public static LayoutString(fieldKey: string) { // return FieldView.LayoutString(MapBox2, fieldKey); diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index 6a14427c0..70037f29c 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -1,33 +1,31 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import BingMapsReact from 'bingmaps-react'; import { Button, EditableText, IconButton, Type } from 'browndash-components'; -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx'; +import { IReactionDisposer, ObservableMap, action, computed, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { MapProvider, Map as MapboxMap } from 'react-map-gl'; +import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, setupMoveUpEvents } from '../../../../Utils'; import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc'; import { DocCss, Highlight } from '../../../../fields/DocSymbols'; -import { Id } from '../../../../fields/FieldSymbols'; import { DocCast, NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; -import { Docs, DocUtils } from '../../../documents/Documents'; import { DocumentType } from '../../../documents/DocumentTypes'; +import { DocUtils, Docs } from '../../../documents/Documents'; import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { LinkManager } from '../../../util/LinkManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; -import { undoable, UndoManager } from '../../../util/UndoManager'; -import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; +import { UndoManager, undoable } from '../../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; -import { Colors } from '../../global/globalEnums'; import { SidebarAnnos } from '../../SidebarAnnos'; +import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; +import { Colors } from '../../global/globalEnums'; import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; +import { MapAnchorMenu } from '../MapBox/MapAnchorMenu'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; import './MapBox.scss'; -import { MapAnchorMenu } from '../MapBox/MapAnchorMenu'; -import { MapProvider, Map as MapboxMap } from 'react-map-gl'; // amongus /** @@ -351,7 +349,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 733febd2d..7f1d6b049 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -48,7 +48,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent(); @observable private _searching: boolean = false; - @observable private _pdf: Opt; + @observable private _pdf: Opt = undefined; @observable private _pageControls = false; @computed get pdfUrl() { diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx index e75b1ab6f..135db64e0 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx @@ -6,8 +6,9 @@ import QuestionMarkIcon from '@mui/icons-material/QuestionMark'; import ReplayIcon from '@mui/icons-material/Replay'; import { Box, Button, Checkbox, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, FormControl, FormControlLabel, FormGroup, IconButton, LinearProgress, Stack } from '@mui/material'; import Typography from '@mui/material/Typography'; -import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { NumListCast } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; import { BoolCast, NumCast, StrCast } from '../../../../fields/Types'; @@ -19,7 +20,6 @@ import questions from './PhysicsSimulationQuestions.json'; import tutorials from './PhysicsSimulationTutorial.json'; import Wall from './PhysicsSimulationWall'; import Weight from './PhysicsSimulationWeight'; -import * as React from 'react'; interface IWallProps { length: number; diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx index f5077a07e..3b232ddd0 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx @@ -1,7 +1,7 @@ import { computed, IReactionDisposer, makeObservable, reaction } from 'mobx'; import { observer } from 'mobx-react'; -import './PhysicsSimulationBox.scss'; import * as React from 'react'; +import './PhysicsSimulationBox.scss'; interface IWallProps { length: number; diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx index 061a46f03..3b2fc033d 100644 --- a/src/client/views/nodes/RadialMenu.tsx +++ b/src/client/views/nodes/RadialMenu.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import './RadialMenu.scss'; import { RadialMenuItem, RadialMenuProps } from './RadialMenuItem'; diff --git a/src/client/views/nodes/RadialMenuItem.tsx b/src/client/views/nodes/RadialMenuItem.tsx index c931202f1..10a90befd 100644 --- a/src/client/views/nodes/RadialMenuItem.tsx +++ b/src/client/views/nodes/RadialMenuItem.tsx @@ -1,7 +1,7 @@ -import * as React from 'react'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { UndoManager } from '../../util/UndoManager'; export interface RadialMenuProps { diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx index f01642236..658cfb1ca 100644 --- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx +++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx @@ -8,15 +8,15 @@ import { List } from '../../../../fields/List'; import { BoolCast, DocCast } from '../../../../fields/Types'; import { VideoField } from '../../../../fields/URLField'; import { Upload } from '../../../../server/SharedMediaTypes'; -import { Docs } from '../../../documents/Documents'; import { DocumentType } from '../../../documents/DocumentTypes'; +import { Docs } from '../../../documents/Documents'; import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; import { Presentation } from '../../../util/TrackMovements'; import { undoBatch } from '../../../util/UndoManager'; -import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView'; import { ViewBoxBaseComponent } from '../../DocComponent'; +import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView'; import { media_state } from '../AudioBox'; import { FieldView, FieldViewProps } from '../FieldView'; import { VideoBox } from '../VideoBox'; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index d5d31b407..79ed69cdd 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -1,5 +1,5 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import * as React from 'react'; // import { Canvas } from '@react-three/fiber'; import { computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index 7e7eaee45..8e506ec64 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -2,25 +2,23 @@ let ReactTextareaAutocomplete = require('@webscopeio/react-textarea-autocomplete import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { returnAlways, returnEmptyString } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { returnAlways, returnEmptyString, returnTrue } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; -import { InteractionUtils } from '../../util/InteractionUtils'; +import { ScriptManager } from '../../util/ScriptManager'; import { CompileScript, ScriptParam } from '../../util/Scripting'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; -import { ScriptManager } from '../../util/ScriptManager'; import { ContextMenu } from '../ContextMenu'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { EditableView } from '../EditableView'; -import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { OverlayView } from '../OverlayView'; +import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { DocumentIconContainer } from './DocumentIcon'; -import { DocFocusOptions, DocumentView } from './DocumentView'; import './ScriptingBox.scss'; const _global = (window /* browser */ || global) /* node */ as any; diff --git a/src/client/views/nodes/TaskCompletedBox.tsx b/src/client/views/nodes/TaskCompletedBox.tsx index 9aab8c5a9..c9e15d314 100644 --- a/src/client/views/nodes/TaskCompletedBox.tsx +++ b/src/client/views/nodes/TaskCompletedBox.tsx @@ -1,15 +1,15 @@ -import * as React from 'react'; +import { Fade } from '@mui/material'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import './TaskCompletedBox.scss'; -import { observable, action } from 'mobx'; -import { Fade } from '@mui/material'; @observer export class TaskCompletionBox extends React.Component<{}> { @observable public static taskCompleted: boolean = false; @observable public static popupX: number = 500; @observable public static popupY: number = 150; - @observable public static textDisplayed: string; + @observable public static textDisplayed: string = ''; @action public static toggleTaskCompleted = () => { diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index f205dbd56..8e9cfe3d7 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -74,8 +74,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent(); @observable _screenCapture = false; @observable _clicking = false; // used for transition between showing/hiding timeline @@ -86,7 +86,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent(){ +export class CalendarBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string = 'calendar') { return FieldView.LayoutString(CalendarBox, fieldKey); } - componentDidMount(): void { - - } + componentDidMount(): void {} - componentWillUnmount(): void { - - } + componentWillUnmount(): void {} - _calendarRef = React.createRef() + _calendarRef = React.createRef(); - get dateRangeStr (){ + get dateRangeStr() { return StrCast(this.Document.date_range); } - // Choose a calendar view based on the date range - get calendarViewType (): CalendarView { + // Choose a calendar view based on the date range + get calendarViewType(): CalendarView { const [fromDate, toDate] = dateRangeStrToDates(this.dateRangeStr); if (fromDate.getFullYear() !== toDate.getFullYear() || fromDate.getMonth() !== toDate.getMonth()) return 'multi-month'; @@ -43,92 +38,83 @@ export class CalendarBox extends ViewBoxBaseComponent(){ return 'week'; } - get calendarStartDate () { - return this.dateRangeStr.split("|")[0]; + get calendarStartDate() { + return this.dateRangeStr.split('|')[0]; } - get calendarToDate () { - return this.dateRangeStr.split("|")[1]; + get calendarToDate() { + return this.dateRangeStr.split('|')[1]; } - get childDocs (): Doc[] { + get childDocs(): Doc[] { return this.childDocs; // get all sub docs for a calendar } - docBackgroundColor (type: string): string { + docBackgroundColor(type: string): string { // TODO: Return a different color based on the event type return 'blue'; } - get calendarEvents (): EventSourceInput | undefined { + get calendarEvents(): EventSourceInput | undefined { if (this.childDocs.length === 0) return undefined; return this.childDocs.map((doc, idx) => { const docTitle = StrCast(doc.title); const docDateRange = StrCast(doc.date_range); const [startDate, endDate] = dateRangeStrToDates(docDateRange); const docType = doc.type; - const docDescription = doc.description ? StrCast(doc.description): ""; + const docDescription = doc.description ? StrCast(doc.description) : ''; return { title: docTitle, start: startDate, end: endDate, allDay: false, - classNames:[StrCast(docType)], // will determine the style + classNames: [StrCast(docType)], // will determine the style editable: false, // subject to change in the future backgroundColor: this.docBackgroundColor(StrCast(doc.type)), color: 'white', extendedProps: { - description: docDescription + description: docDescription, }, - - } - - }) + }; + }); } handleEventClick = (arg: EventClickArg) => { // TODO: open popover with event description, option to open CalendarManager and change event date, delete event, etc. - } + }; calendarEl: HTMLElement = document.getElementById('calendar-box-v1')!; // https://fullcalendar.io get calendar() { - return new Calendar(this.calendarEl, - { - plugins: [this.calendarViewType === 'multi-month' ? multiMonthPlugin : dayGridPlugin], - headerToolbar: { - left: 'prev,next today', - center: 'title', - right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek' - }, - initialDate: this.calendarStartDate, - navLinks: true, - editable: false, - displayEventTime: false, - displayEventEnd: false, - events: this.calendarEvents, - eventClick: this.handleEventClick - } - ) - + return new Calendar(this.calendarEl, { + plugins: [this.calendarViewType === 'multi-month' ? multiMonthPlugin : dayGridPlugin], + headerToolbar: { + left: 'prev,next today', + center: 'title', + right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek', + }, + initialDate: this.calendarStartDate, + navLinks: true, + editable: false, + displayEventTime: false, + displayEventEnd: false, + events: this.calendarEvents, + eventClick: this.handleEventClick, + }); } - - constructor(props: any){ + constructor(props: any) { super(props); makeObservable(this); } - render(){ + render() { return ( -
-
- -
-
+
+
+
); - } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 6332b200d..1002ee403 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -1,17 +1,17 @@ import { action, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { NodeSelection } from 'prosemirror-state'; +import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import { Doc } from '../../../../fields/Doc'; import { Height, Width } from '../../../../fields/DocSymbols'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, returnFalse, returnTrue, Utils } from '../../../../Utils'; +import { emptyFunction, returnFalse, Utils } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { Docs, DocUtils } from '../../../documents/Documents'; import { Transform } from '../../../util/Transform'; import { DocFocusOptions, DocumentView } from '../DocumentView'; import { FormattedTextBox } from './FormattedTextBox'; -import * as React from 'react'; export class DashDocView { dom: HTMLSpanElement; // container for label and value @@ -83,7 +83,7 @@ export class DashDocViewInternal extends React.Component { _disposers: { [name: string]: IReactionDisposer } = {}; _textBox: FormattedTextBox; @observable _dashDoc: Doc | undefined = undefined; - @observable _finalLayout: any; + @observable _finalLayout: any = undefined; @observable _width: number = 0; @observable _height: number = 0; diff --git a/src/client/views/nodes/formattedText/EquationView.tsx b/src/client/views/nodes/formattedText/EquationView.tsx index 331ed1980..7e655531e 100644 --- a/src/client/views/nodes/formattedText/EquationView.tsx +++ b/src/client/views/nodes/formattedText/EquationView.tsx @@ -1,14 +1,13 @@ -import EquationEditor from './EquationEditor'; -import { IReactionDisposer, trace } from 'mobx'; +import { IReactionDisposer } from 'mobx'; import { observer } from 'mobx-react'; import { TextSelection } from 'prosemirror-state'; +import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import { Doc } from '../../../../fields/Doc'; import { StrCast } from '../../../../fields/Types'; import './DashFieldView.scss'; +import EquationEditor from './EquationEditor'; import { FormattedTextBox } from './FormattedTextBox'; -import * as React from 'react'; -import { AnyArray } from 'mongoose'; export class EquationView { dom: HTMLDivElement; // container for label and value diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index ad2fab8b0..8bf8abafa 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -11,6 +11,7 @@ import { keymap } from 'prosemirror-keymap'; import { Fragment, Mark, Node, Slice } from 'prosemirror-model'; import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from 'prosemirror-state'; import { EditorView } from 'prosemirror-view'; +import * as React from 'react'; import { BsMarkdownFill } from 'react-icons/bs'; import { DateField } from '../../../../fields/DateField'; import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc'; @@ -70,9 +71,8 @@ import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu'; import { RichTextRules } from './RichTextRules'; import { schema } from './schema_rts'; import { SummaryView } from './SummaryView'; -// import * as applyDevTools from 'prosemirror-dev-tools'; -import * as React from 'react'; export const GoogleRef = 'googleDocId'; +// import * as applyDevTools from 'prosemirror-dev-tools'; type PullHandler = (exportState: Opt, dataDoc: Doc) => void; export interface FormattedTextBoxProps {} diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 4881070fd..3b31f2d17 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -32,7 +32,7 @@ export class RichTextMenu extends AntimodeMenu { private _linkToRef = React.createRef(); layoutDoc: Doc | undefined; - @observable public view?: EditorView; + @observable public view?: EditorView = undefined; public editorProps: FieldViewProps | undefined; public _brushMap: Map> = new Map(); diff --git a/src/client/views/nodes/importBox/ImportElementBox.tsx b/src/client/views/nodes/importBox/ImportElementBox.tsx index 9dc0c5180..b573f7c48 100644 --- a/src/client/views/nodes/importBox/ImportElementBox.tsx +++ b/src/client/views/nodes/importBox/ImportElementBox.tsx @@ -1,13 +1,11 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { returnFalse } from '../../../../Utils'; import { Doc } from '../../../../fields/Doc'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue } from '../../../../Utils'; -import { Transform } from '../../../util/Transform'; import { ViewBoxBaseComponent } from '../../DocComponent'; -import { DefaultStyleProvider } from '../../StyleProvider'; -import { DocumentView, DocumentViewInternal } from '../DocumentView'; +import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; -import * as React from 'react'; @observer export class ImportElementBox extends ViewBoxBaseComponent() { diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index e213b2fc5..0305689e7 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1,8 +1,8 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast, FieldResult, NumListCast, Opt, StrListCast } from '../../../../fields/Doc'; import { Animation } from '../../../../fields/DocSymbols'; import { Copy, Id } from '../../../../fields/FieldSymbols'; @@ -24,7 +24,7 @@ import { SerializationHelper } from '../../../util/SerializationHelper'; import { SettingsManager } from '../../../util/SettingsManager'; import { undoBatch, UndoManager } from '../../../util/UndoManager'; import { CollectionDockingView } from '../../collections/CollectionDockingView'; -import { CollectionFreeFormView, computeTimelineLayout, MarqueeViewBounds } from '../../collections/collectionFreeForm'; +import { CollectionFreeFormView, MarqueeViewBounds } from '../../collections/collectionFreeForm'; import { CollectionStackedTimeline } from '../../collections/CollectionStackedTimeline'; import { CollectionView } from '../../collections/CollectionView'; import { TreeView } from '../../collections/TreeView'; @@ -83,12 +83,12 @@ export class PresBox extends ViewBoxBaseComponent() { _batch: UndoManager.Batch | undefined = undefined; // undo batch for dragging sliders which generate multiple scene edit events as the cursor moves _keyTimer: NodeJS.Timeout | undefined; // timer for turning off transition flag when key frame change has completed. Need to clear this if you do a second navigation before first finishes, or else first timer can go off during second naviation. _unmounting = false; // flag that view is unmounting used to block RemFromMap from deleting things + _presTimer: NodeJS.Timeout | undefined; @observable public static Instance: PresBox; @observable _isChildActive = false; @observable _moveOnFromAudio: boolean = true; - @observable _presTimer!: NodeJS.Timeout; @observable _eleArray: HTMLElement[] = []; @observable _dragArray: HTMLElement[] = []; diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index cf19ff6bc..5ea9e9979 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -1,18 +1,17 @@ -import * as React from 'react'; import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types'; import { LinkFollower } from '../../util/LinkFollower'; +import { LinkManager } from '../../util/LinkManager'; import { undoBatch } from '../../util/UndoManager'; import { OpenWhere } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { AnchorMenu } from './AnchorMenu'; import './Annotation.scss'; -import { LinkManager } from '../../util/LinkManager'; -import { Rect } from 'react-measure'; interface IAnnotationProps extends FieldViewProps { anno: Doc; diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index db21d9a3d..da8a88803 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -1,20 +1,20 @@ -import * as React from 'react'; -import './GPTPopup.scss'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Button, IconButton, Type } from 'browndash-components'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { CgClose } from 'react-icons/cg'; import ReactLoading from 'react-loading'; import { TypeAnimation } from 'react-type-animation'; +import { Utils } from '../../../../Utils'; import { Doc } from '../../../../fields/Doc'; -import { DocUtils, Docs } from '../../../documents/Documents'; -import { Button, IconButton, Type } from 'browndash-components'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { CgClose } from 'react-icons/cg'; -import { AnchorMenu } from '../AnchorMenu'; -import { gptImageCall } from '../../../apis/gpt/GPT'; import { Networking } from '../../../Network'; -import { Utils } from '../../../../Utils'; +import { gptImageCall } from '../../../apis/gpt/GPT'; +import { DocUtils, Docs } from '../../../documents/Documents'; import { ObservableReactComponent } from '../../ObservableReactComponent'; +import { AnchorMenu } from '../AnchorMenu'; +import './GPTPopup.scss'; export enum GPTPopupMode { SUMMARY, diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index e342c25b3..b6d027d30 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -302,7 +302,7 @@ export class PDFViewer extends ObservableReactComponent { } }; - @observable private _scrollTimer: any; + @observable private _scrollTimer: any = undefined; onScroll = (e: React.UIEvent) => { if (this._mainCont.current && !this._forcedScroll) { diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index ccfccb771..14187833f 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -2,24 +2,23 @@ import { Tooltip } from '@mui/material'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../../fields/Doc'; +import { Doc, DocListCastAsync, Field } from '../../../fields/Doc'; import { DirectLinks } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { DocCast, StrCast } from '../../../fields/Types'; -import { DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; +import { DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { LinkManager } from '../../util/LinkManager'; +import { SearchUtil } from '../../util/SearchUtil'; +import { SettingsManager } from '../../util/SettingsManager'; import { undoBatch } from '../../util/UndoManager'; -import { CollectionDockingView } from '../collections/CollectionDockingView'; import { ViewBoxBaseComponent } from '../DocComponent'; +import { CollectionDockingView } from '../collections/CollectionDockingView'; +import { IRecommendation, Recommendation } from '../newlightbox/components'; +import { fetchRecommendations } from '../newlightbox/utils'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import './SearchBox.scss'; -import { fetchRecommendations } from '../newlightbox/utils'; -import { IRecommendation, Recommendation } from '../newlightbox/components'; -import { Colors } from '../global/globalEnums'; -import { SettingsManager } from '../../util/SettingsManager'; -import { SearchUtil } from '../../util/SearchUtil'; const DAMPENING_FACTOR = 0.9; const MAX_ITERATIONS = 25; diff --git a/src/client/views/selectedDoc/SelectedDocView.tsx b/src/client/views/selectedDoc/SelectedDocView.tsx index 39e778b76..daacb368b 100644 --- a/src/client/views/selectedDoc/SelectedDocView.tsx +++ b/src/client/views/selectedDoc/SelectedDocView.tsx @@ -1,14 +1,14 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ListBox } from 'browndash-components'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { emptyFunction } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { StrCast } from '../../../fields/Types'; import { DocumentManager } from '../../util/DocumentManager'; -import { DocFocusOptions } from '../nodes/DocumentView'; -import { emptyFunction } from '../../../Utils'; import { SettingsManager } from '../../util/SettingsManager'; +import { DocFocusOptions } from '../nodes/DocumentView'; export interface SelectedDocViewProps { selectedDocs: Doc[]; diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 0f3487cd1..575d5849e 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -16,15 +16,15 @@ import { ReportManager } from '../../util/reportManager/ReportManager'; import { ServerStats } from '../../util/ServerStats'; import { SettingsManager } from '../../util/SettingsManager'; import { SharingManager } from '../../util/SharingManager'; +import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { CollectionDockingView } from '../collections/CollectionDockingView'; import { CollectionLinearView } from '../collections/collectionLinear'; import { DashboardView } from '../DashboardView'; import { Colors } from '../global/globalEnums'; -import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; +import { DocumentViewInternal } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; import './TopBar.scss'; -import { SnappingManager } from '../../util/SnappingManager'; /** * ABOUT: This is the topbar in Dash, which included the current Dashboard as well as access to information on the user diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx index f1739a41a..94458563e 100644 --- a/src/client/views/webcam/DashWebRTCVideo.tsx +++ b/src/client/views/webcam/DashWebRTCVideo.tsx @@ -3,16 +3,15 @@ import { faPhoneSlash, faSync } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; +import { SnappingManager } from '../../util/SnappingManager'; import '../../views/nodes/WebBox.scss'; import { CollectionFreeFormDocumentViewProps } from '../nodes/CollectionFreeFormDocumentView'; -import { DocumentView } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import './DashWebRTCVideo.scss'; import { hangup, initialize, refreshVideos } from './WebCamLogic'; -import * as React from 'react'; -import { SnappingManager } from '../../util/SnappingManager'; /** * This models the component that will be rendered, that can be used as a doc that will reflect the video cams. diff --git a/src/debug/Repl.tsx b/src/debug/Repl.tsx index b8081648f..a9f7c085f 100644 --- a/src/debug/Repl.tsx +++ b/src/debug/Repl.tsx @@ -1,13 +1,13 @@ +import { computed, observable } from 'mobx'; +import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; -import { observer } from 'mobx-react'; -import { observable, computed } from 'mobx'; +import { DocServer } from '../client/DocServer'; +import { resolvedPorts } from '../client/util/CurrentUserUtils'; import { CompileScript } from '../client/util/Scripting'; -import { makeInterface } from '../fields/Schema'; import { ObjectField } from '../fields/ObjectField'; import { RefField } from '../fields/RefField'; -import { DocServer } from '../client/DocServer'; -import { resolvedPorts } from '../client/util/CurrentUserUtils'; +import { makeInterface } from '../fields/Schema'; @observer class Repl extends React.Component { diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index 02038c426..f46adef77 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -1,19 +1,19 @@ -import { action, configure, observable, ObservableMap, Lambda } from 'mobx'; +import { action, configure, observable } from 'mobx'; +import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import { observer } from 'mobx-react'; -import { Doc, Field, FieldResult, Opt } from '../fields/Doc'; import { DocServer } from '../client/DocServer'; +import { resolvedPorts } from '../client/util/CurrentUserUtils'; +import { CompileScript } from '../client/util/Scripting'; +import { EditableView } from '../client/views/EditableView'; +import CursorField from '../fields/CursorField'; +import { DateField } from '../fields/DateField'; +import { Doc, Field, FieldResult } from '../fields/Doc'; import { Id } from '../fields/FieldSymbols'; import { List } from '../fields/List'; -import { URLField } from '../fields/URLField'; -import { EditableView } from '../client/views/EditableView'; -import { CompileScript } from '../client/util/Scripting'; import { RichTextField } from '../fields/RichTextField'; -import { DateField } from '../fields/DateField'; import { ScriptField } from '../fields/ScriptField'; -import CursorField from '../fields/CursorField'; -import { resolvedPorts } from '../client/util/CurrentUserUtils'; +import { URLField } from '../fields/URLField'; DateField; URLField; diff --git a/src/fields/CursorField.ts b/src/fields/CursorField.ts index 46f5a8e1c..84917ae53 100644 --- a/src/fields/CursorField.ts +++ b/src/fields/CursorField.ts @@ -1,8 +1,7 @@ -import { ObjectField } from './ObjectField'; -import { observable } from 'mobx'; +import { createSimpleSchema, object, serializable } from 'serializr'; import { Deserializable } from '../client/util/SerializationHelper'; -import { serializable, createSimpleSchema, object, date } from 'serializr'; -import { FieldChanged, ToScriptString, ToString, Copy } from './FieldSymbols'; +import { Copy, FieldChanged, ToScriptString, ToString } from './FieldSymbols'; +import { ObjectField } from './ObjectField'; export type CursorPosition = { x: number; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 8903a9f97..9dc3c173d 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -265,8 +265,8 @@ export class Doc extends RefField { @observable public [DocAcl]: { [key: string]: symbol } = {}; @observable public [DocCss]: number = 0; // incrementer denoting a change to CSS layout @observable public [DirectLinks] = new ObservableSet(); - @observable public [AudioPlay]: any; // meant to store sound object from Howl - @observable public [Animation]: Opt; + @observable public [AudioPlay]: any = undefined; // meant to store sound object from Howl + @observable public [Animation]: Opt = undefined; @observable public [Highlight]: boolean = false; @observable public [Brushed]: boolean = false; @observable public [DocViews] = new ObservableSet(); diff --git a/src/fields/List.ts b/src/fields/List.ts index 8c8ff1ea3..b8ad552d2 100644 --- a/src/fields/List.ts +++ b/src/fields/List.ts @@ -2,7 +2,7 @@ import { action, computed, makeObservable, observable } from 'mobx'; import { alias, list, serializable } from 'serializr'; import { DocServer } from '../client/DocServer'; import { ScriptingGlobals } from '../client/util/ScriptingGlobals'; -import { afterDocDeserialize, autoObject, Deserializable } from '../client/util/SerializationHelper'; +import { Deserializable, afterDocDeserialize, autoObject } from '../client/util/SerializationHelper'; import { Field } from './Doc'; import { FieldTuples, Self, SelfProxy } from './DocSymbols'; import { Copy, FieldChanged, Parent, ToScriptString, ToString } from './FieldSymbols'; @@ -11,7 +11,7 @@ import { ProxyField } from './Proxy'; import { RefField } from './RefField'; import { listSpec } from './Schema'; import { Cast } from './Types'; -import { deleteProperty, getter, setter, containedFieldChangedHandler } from './util'; +import { containedFieldChangedHandler, deleteProperty, getter, setter } from './util'; function toObjectField(field: Field) { return field instanceof RefField ? new ProxyField(field) : field; @@ -102,8 +102,8 @@ class ListImpl extends ObjectField { items.length === 0 && deleteCount ? { op: '$remFromSet', items: removed, hint: { start, deleteCount }, length: list.__fieldTuples.length } : items.length && !deleteCount && start === list.__fieldTuples.length - ? { op: '$addToSet', items, length: list.__fieldTuples.length } - : undefined + ? { op: '$addToSet', items, length: list.__fieldTuples.length } + : undefined ); return res.map(toRealField); }), diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts index c076f5fe1..3a46e3581 100644 --- a/src/fields/Proxy.ts +++ b/src/fields/Proxy.ts @@ -1,12 +1,12 @@ -import { Deserializable } from '../client/util/SerializationHelper'; -import { Field, FieldWaiting, Opt } from './Doc'; +import { action, computed, observable, runInAction } from 'mobx'; import { primitive, serializable } from 'serializr'; -import { observable, action, runInAction, computed } from 'mobx'; import { DocServer } from '../client/DocServer'; -import { RefField } from './RefField'; -import { ObjectField } from './ObjectField'; -import { Id, Copy, ToScriptString, ToString, ToValue } from './FieldSymbols'; import { scriptingGlobal } from '../client/util/ScriptingGlobals'; +import { Deserializable } from '../client/util/SerializationHelper'; +import { Field, FieldWaiting, Opt } from './Doc'; +import { Copy, Id, ToScriptString, ToString, ToValue } from './FieldSymbols'; +import { ObjectField } from './ObjectField'; +import { RefField } from './RefField'; function deserializeProxy(field: any) { if (!field.cache.field) { diff --git a/src/fields/util.ts b/src/fields/util.ts index 545fe4478..b73520999 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -1,11 +1,11 @@ import { $mobx, action, observable, runInAction, trace } from 'mobx'; import { computedFn } from 'mobx-utils'; +import { returnZero } from '../Utils'; import { DocServer } from '../client/DocServer'; import { LinkManager } from '../client/util/LinkManager'; import { SerializationHelper } from '../client/util/SerializationHelper'; import { UndoManager } from '../client/util/UndoManager'; -import { returnZero } from '../Utils'; -import { aclLevel, Doc, DocListCast, Field, FieldResult, HierarchyMapping, ReverseHierarchyMap, StrListCast, updateCachedAcls } from './Doc'; +import { Doc, DocListCast, Field, FieldResult, HierarchyMapping, ReverseHierarchyMap, StrListCast, aclLevel, updateCachedAcls } from './Doc'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, DocAcl, DocData, DocLayout, FieldKeys, ForceServerWrite, Height, Initializing, SelfProxy, UpdatingFromServer, Width } from './DocSymbols'; import { FieldChanged, Id, Parent, ToValue } from './FieldSymbols'; import { List } from './List'; diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index d2598c2db..e333e6a2e 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -1,19 +1,19 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import * as rp from 'request-promise'; +import { Utils } from '../Utils'; import { DocServer } from '../client/DocServer'; -import { Docs } from '../client/documents/Documents'; import { Networking } from '../client/Network'; +import { Docs } from '../client/documents/Documents'; import { MainViewModal } from '../client/views/MainViewModal'; import { Doc, Opt } from '../fields/Doc'; import { List } from '../fields/List'; import { listSpec } from '../fields/Schema'; import { Cast } from '../fields/Types'; -import { Utils } from '../Utils'; import './ImageUpload.scss'; import { MobileInterface } from './MobileInterface'; -import * as React from 'react'; const { default: { DFLT_IMAGE_NATIVE_DIM } } = require('../client/views/global/globalCssVariables.module.scss'); // prettier-ignore export interface ImageUploadProps { Document: Doc; // Target document for upload (upload location) diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 2e595e4bc..23e19585a 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { DocServer } from '../client/DocServer'; import { DragManager } from '../client/util/DragManager'; import { Doc } from '../fields/Doc'; diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index bdd657575..e3d8f9394 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -1,52 +1,33 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { - faTasks, - faReply, - faQuoteLeft, - faHandPointLeft, - faFolderOpen, + faAddressCard, + faAlignLeft, + faAlignRight, faAngleDoubleLeft, - faExternalLinkSquareAlt, - faMobile, - faThLarge, - faWindowClose, - faEdit, - faTrashAlt, - faPalette, faAngleRight, + faArrowDown, + faArrowLeft, + faArrowRight, + faArrowUp, + faArrowsAltH, + faAsterisk, + faBars, faBell, - faTrash, + faBolt, + faBook, + faBrain, + faBullseye, + faCalculator, faCamera, - faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, - faArrowsAltH, - faPlus, - faMinus, - faTerminal, - faToggleOn, - faFile as fileSolid, - faExternalLinkAlt, - faLocationArrow, - faSearch, - faFileDownload, - faStop, - faCalculator, - faWindowMaximize, - faAddressCard, - faQuestionCircle, - faArrowLeft, - faArrowRight, - faArrowDown, - faArrowUp, - faBolt, - faBullseye, faCaretUp, faCat, faCheck, + faChevronLeft, faChevronRight, faClipboard, faClone, @@ -54,76 +35,95 @@ import { faCommentAlt, faCompressArrowsAlt, faCut, + faEdit, faEllipsisV, faEraser, faExclamation, + faExpand, + faExternalLinkAlt, + faExternalLinkSquareAlt, + faEye, faFileAlt, faFileAudio, + faFileDownload, faFilePdf, faFilm, faFilter, + faFolderOpen, faFont, faGlobeAsia, + faHandPointLeft, faHighlighter, + faHome, + faImage, + faLocationArrow, + faLongArrowAltLeft, faLongArrowAltRight, faMicrophone, + faMinus, + faMobile, faMousePointer, faMusic, faObjectGroup, + faPaintBrush, + faPalette, faPause, faPen, faPenNib, faPhone, faPlay, + faPlus, faPortrait, + faQuestionCircle, + faQuoteLeft, faRedoAlt, + faReply, + faSearch, faStamp, faStickyNote, + faStop, + faTasks, + faTerminal, + faTh, + faThLarge, faThumbtack, + faTimes, + faToggleOn, + faTrash, + faTrashAlt, faTree, faTv, - faBook, faUndoAlt, faVideo, - faAsterisk, - faBrain, - faImage, - faPaintBrush, - faTimes, - faEye, - faHome, - faLongArrowAltLeft, - faBars, - faTh, - faChevronLeft, - faAlignRight, - faAlignLeft, + faWindowClose, + faWindowMaximize, + faFile as fileSolid, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Docs, DocumentOptions, DocUtils } from '../client/documents/Documents'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../Utils'; import { CollectionViewType, DocumentType } from '../client/documents/DocumentTypes'; +import { Docs, DocumentOptions } from '../client/documents/Documents'; import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; import { ScriptingGlobals } from '../client/util/ScriptingGlobals'; -import { SettingsManager, ColorScheme } from '../client/util/SettingsManager'; +import { SettingsManager } from '../client/util/SettingsManager'; import { Transform } from '../client/util/Transform'; import { UndoManager } from '../client/util/UndoManager'; -import { TabDocView } from '../client/views/collections/TabDocView'; import { GestureOverlay } from '../client/views/GestureOverlay'; +import { TabDocView } from '../client/views/collections/TabDocView'; import { AudioBox } from '../client/views/nodes/AudioBox'; import { DocumentView } from '../client/views/nodes/DocumentView'; -import { RichTextMenu } from '../client/views/nodes/formattedText/RichTextMenu'; import { RadialMenu } from '../client/views/nodes/RadialMenu'; +import { RichTextMenu } from '../client/views/nodes/formattedText/RichTextMenu'; import { Doc, DocListCast } from '../fields/Doc'; import { InkTool } from '../fields/InkField'; import { List } from '../fields/List'; import { ScriptField } from '../fields/ScriptField'; import { Cast, FieldValue, StrCast } from '../fields/Types'; -import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero } from '../Utils'; -import { Uploader } from './ImageUpload'; import './AudioUpload.scss'; +import { Uploader } from './ImageUpload'; import './ImageUpload.scss'; import './MobileInterface.scss'; diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts index 8f21966ae..d46977816 100644 --- a/src/typings/index.d.ts +++ b/src/typings/index.d.ts @@ -14,9 +14,7 @@ declare module 'pdfjs-dist/web/pdf_viewer'; declare module 'react-jsx-parser'; declare module 'express-flash'; -declare module 'connect-flash' { - interface flash {} -} +declare module 'connect-flash'; declare module 'connect-mongo'; declare module '@mui/material'; diff --git a/test/test.ts b/test/test.ts index 489aa3025..ee14a9340 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,37 +1,41 @@ import { expect } from 'chai'; import 'mocha'; const { JSDOM } = require('jsdom'); -const dom = new JSDOM("", { - url: `http://localhost:${resolvedPorts.server}` +const dom = new JSDOM('', { + url: `http://localhost:${resolvedPorts.server}`, }); (global as any).window = dom.window; - -import { autorun, reaction } from "mobx"; +import { reaction } from 'mobx'; +import { resolvedPorts } from '../src/client/util/CurrentUserUtils'; import { Doc } from '../src/fields/Doc'; +import { createSchema, defaultSpec, makeInterface } from '../src/fields/Schema'; import { Cast } from '../src/fields/Types'; -import { createSchema, makeInterface, defaultSpec } from '../src/fields/Schema'; import { ImageField } from '../src/fields/URLField'; -import { resolvedPorts } from '../src/client/util/CurrentUserUtils'; -describe("Document", () => { +describe('Document', () => { it('should hold fields', () => { - const key = "Test"; - const key2 = "Test2"; + const key = 'Test'; + const key2 = 'Test2'; const field = 15; const doc = new Doc(); doc[key] = field; - const getField = Cast(doc[key], "number"); - const getField2 = Cast(doc[key2], "number"); + const getField = Cast(doc[key], 'number'); + const getField2 = Cast(doc[key2], 'number'); expect(getField).to.equal(field); expect(getField2).to.equal(undefined); }); it('should update', () => { const doc = new Doc(); - const key = "Test"; - const key2 = "Test2"; + const key = 'Test'; + const key2 = 'Test2'; let ran = false; - reaction(() => doc[key], (field) => { ran = true; }); + reaction( + () => doc[key], + field => { + ran = true; + } + ); expect(ran).to.equal(false); doc[key2] = 4; @@ -44,55 +48,55 @@ describe("Document", () => { }); const testSchema1 = createSchema({ - a: "number", - b: "string", - c: "boolean", + a: 'number', + b: 'string', + c: 'boolean', d: ImageField, - e: Doc + e: Doc, }); type TestDoc = makeInterface<[typeof testSchema1]>; const TestDoc = makeInterface(testSchema1); const testSchema2 = createSchema({ - a: defaultSpec("boolean", true), - b: defaultSpec("number", 5), - c: defaultSpec("string", "hello world") + a: defaultSpec('boolean', true), + b: defaultSpec('number', 5), + c: defaultSpec('string', 'hello world'), }); type TestDoc2 = makeInterface<[typeof testSchema2]>; const TestDoc2 = makeInterface(testSchema2); const testSchema3 = createSchema({ - a: TestDoc2 + a: TestDoc2, }); type TestDoc3 = makeInterface<[typeof testSchema3]>; const TestDoc3 = makeInterface(testSchema3); -describe("Schema", () => { - it("should do the right thing 1", () => { - const test1 = new Doc; - const test2 = new Doc; - const ifield = new ImageField(new URL("http://google.com")); +describe('Schema', () => { + it('should do the right thing 1', () => { + const test1 = new Doc(); + const test2 = new Doc(); + const ifield = new ImageField(new URL('http://google.com')); test1.a = 5; - test1.b = "hello"; + test1.b = 'hello'; test1.c = true; test1.d = ifield; test1.e = test2; const doc = TestDoc(test1); expect(doc.a).to.equal(5); - expect(doc.b).to.equal("hello"); + expect(doc.b).to.equal('hello'); expect(doc.c).to.equal(true); expect(doc.d).to.equal(ifield); expect(doc.e).to.equal(test2); }); - it("should do the right thing 2", () => { - const test1 = new Doc; - const test2 = new Doc; - const ifield = new ImageField(new URL("http://google.com")); - test1.a = "hello"; + it('should do the right thing 2', () => { + const test1 = new Doc(); + const test2 = new Doc(); + const ifield = new ImageField(new URL('http://google.com')); + test1.a = 'hello'; test1.b = 5; test1.c = test2; test1.d = true; @@ -105,11 +109,11 @@ describe("Schema", () => { expect(doc.e).to.equal(undefined); }); - it("should do the right thing 3", () => { - const test1 = new Doc; - const test2 = new Doc; - const ifield = new ImageField(new URL("http://google.com")); - test1.a = "hello"; + it('should do the right thing 3', () => { + const test1 = new Doc(); + const test2 = new Doc(); + const ifield = new ImageField(new URL('http://google.com')); + test1.a = 'hello'; test1.b = 5; test1.c = test2; test1.d = true; @@ -122,40 +126,40 @@ describe("Schema", () => { expect(doc.e).to.equal(undefined); }); - it("should do the right thing 4", () => { + it('should do the right thing 4', () => { const doc = TestDoc2(); expect(doc.a).to.equal(true); expect(doc.b).to.equal(5); - expect(doc.c).to.equal("hello world"); + expect(doc.c).to.equal('hello world'); - const d2 = new Doc; + const d2 = new Doc(); d2.a = false; d2.b = 4; - d2.c = "goodbye"; + d2.c = 'goodbye'; const doc2 = TestDoc2(d2); expect(doc2.a).to.equal(false); expect(doc2.b).to.equal(4); - expect(doc2.c).to.equal("goodbye"); + expect(doc2.c).to.equal('goodbye'); - const d3 = new Doc; - d3.a = "hello"; + const d3 = new Doc(); + d3.a = 'hello'; d3.b = false; d3.c = 5; const doc3 = TestDoc2(d3); expect(doc3.a).to.equal(true); expect(doc3.b).to.equal(5); - expect(doc3.c).to.equal("hello world"); + expect(doc3.c).to.equal('hello world'); }); - it("should do the right thing 5", async () => { - const test1 = new Doc; - const test2 = new Doc; + it('should do the right thing 5', async () => { + const test1 = new Doc(); + const test2 = new Doc(); const doc = TestDoc3(test1); expect(doc.a).to.equal(undefined); test1.a = test2; const doc2 = (await doc.a)!; expect(doc2.a).to.equal(true); expect(doc2.b).to.equal(5); - expect(doc2.c).to.equal("hello world"); + expect(doc2.c).to.equal('hello world'); }); }); -- cgit v1.2.3-70-g09d2 From ae27dd1689ae1716591aab094e6d41f3a0160fef Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 4 Jan 2024 13:11:22 -0500 Subject: fixed ffmpeg for uploading videos. fixed getView() to take focus options so that if a sidebar or timeline has to be opened, the didMove flag can be set properly. added video snapshot frame to top menu. fixed using '^' to stop and start a selection region on timelines. --- src/client/documents/Documents.ts | 2 +- src/client/util/CurrentUserUtils.ts | 12 +- src/client/util/DocumentManager.ts | 2 +- src/client/util/PingManager.ts | 20 +-- src/client/views/GlobalKeyHandler.ts | 8 +- src/client/views/UndoStack.tsx | 10 +- .../views/collections/CollectionDockingView.tsx | 2 +- .../collections/CollectionStackedTimeline.tsx | 40 ++++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- .../collectionLinear/CollectionLinearView.tsx | 2 +- src/client/views/global/globalScripts.ts | 11 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 9 +- src/client/views/nodes/DocumentView.tsx | 9 +- src/client/views/nodes/MapBox/MapBox.tsx | 9 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 9 +- src/client/views/nodes/PDFBox.tsx | 7 +- src/client/views/nodes/VideoBox.scss | 6 +- src/client/views/nodes/VideoBox.tsx | 158 +++------------------ src/client/views/nodes/WebBox.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 7 +- src/server/DashUploadUtils.ts | 15 +- 21 files changed, 129 insertions(+), 215 deletions(-) (limited to 'src/client/util/CurrentUserUtils.ts') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 79285deb5..92a9ddfe8 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -209,7 +209,7 @@ export class DocumentOptions { 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); annotationOn?: DOCt = new DocInfo('document annotated by this document', false); - embedContainer?: DOCt = new DocInfo('document that displays (contains) this discument', false); + _embedContainer?: DOCt = new DocInfo('document that displays (contains) this discument', false); rootDocument?: DOCt = new DocInfo('document that supplies the information needed for a rendering template (eg, pres slide for PresElement)'); color?: STRt = new StrInfo('foreground color data doc', false); hidden?: BOOLt = new BoolInfo('whether the document is not rendered by its collection', false); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 3f28f44fc..4391e87d6 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -309,7 +309,7 @@ export class CurrentUserUtils { { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "file", dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize",dragFactory: doc.emptyHeader as Doc,clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true, funcs: { hidden: "IsNoviceMode()"} }, { toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '' as any, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script - // { toolTip: "Toggle an UndoStack", title: "undostacker", icon: "calculator", clickFactory: "" as any, openFactoryLocation: OpenWhere.overlay}, + // { toolTip: "Toggle an UndoStack", title: "undostacker", icon: "calculator", clickFactory: "" as any, openFactoryLocation: OpenWhere.overlay}, ].map(tuple => ( { openFactoryLocation: OpenWhere.addRight, scripts: { onClick: 'openDoc(copyDragFactory(this.clickFactory,this.openFactoryAsDelegate), this.openFactoryLocation)', @@ -695,11 +695,16 @@ export class CurrentUserUtils { static webTools() { return [ - { title: "Back", toolTip: "Go back", btnType: ButtonType.ClickButton, icon: "arrow-left", scripts: { onClick: '{ return webBack(_readOnly_); }' }}, - { title: "Forward", toolTip: "Go forward", btnType: ButtonType.ClickButton, icon: "arrow-right", scripts: { onClick: '{ return webForward(_readOnly_); }'}}, + { title: "Back", toolTip: "Go back", btnType: ButtonType.ClickButton, icon: "arrow-left", scripts: { onClick: '{ return webBack(); }' }}, + { title: "Forward", toolTip: "Go forward", btnType: ButtonType.ClickButton, icon: "arrow-right", scripts: { onClick: '{ return webForward(); }'}}, { title: "URL", toolTip: "URL", width: 250, btnType: ButtonType.EditableText, icon: "lock", ignoreClick: true, scripts: { script: '{ return webSetURL(value, _readOnly_); }'} }, ]; } + static videoTools() { + return [ + { title: "Snapshot",toolTip: "Take snapshot of current frame", btnType: ButtonType.ClickButton, icon: "camera", scripts: { onClick: '{ return videoSnapshot(); }' }}, + ]; + } static contextMenuTools():Button[] { return [ { btnList: new List([CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Tree, @@ -721,6 +726,7 @@ export class CurrentUserUtils { { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected + { title: "Video", icon: "Video", toolTip: "Video functions", subMenu: CurrentUserUtils.videoTools(), expertMode: false, toolType:DocumentType.VID, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Schema is selected ]; } diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 0fab42895..7fef5cc79 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -281,7 +281,7 @@ export class DocumentManager { docContextPath.shift(); const childViewIterator = async (docView: DocumentView) => { const innerDoc = docContextPath.shift(); - return { focused: false, viewSpec: innerDoc, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc)) ?? this.getDocumentView(innerDoc) : undefined }; + return { focused: false, viewSpec: innerDoc, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc, options)) ?? this.getDocumentView(innerDoc) : undefined }; }; if (rootContextView) { diff --git a/src/client/util/PingManager.ts b/src/client/util/PingManager.ts index 865f8bc02..7638e2ce0 100644 --- a/src/client/util/PingManager.ts +++ b/src/client/util/PingManager.ts @@ -4,11 +4,20 @@ import { CurrentUserUtils } from './CurrentUserUtils'; export class PingManager { // create static instance and getter for global use @observable static _instance: PingManager; + @observable IsBeating = true; static get Instance(): PingManager { return PingManager._instance; } - @observable IsBeating = true; + // not used now, but may need to clear interval + private _interval: NodeJS.Timeout | null = null; + INTERVAL_SECONDS = 1; + constructor() { + makeObservable(this); + PingManager._instance = this; + this._interval = setInterval(this.sendPing, this.INTERVAL_SECONDS * 1000); + } + private setIsBeating = action((status: boolean) => { this.IsBeating = status; setTimeout(this.showAlert, 100); @@ -28,13 +37,4 @@ export class PingManager { } } }; - - // not used now, but may need to clear interval - private _interval: NodeJS.Timeout | null = null; - INTERVAL_SECONDS = 1; - constructor() { - makeObservable(this); - PingManager._instance = this; - this._interval = setInterval(this.sendPing, this.INTERVAL_SECONDS * 1000); - } } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 77b831e51..d134d9e7b 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -128,10 +128,12 @@ export class KeyManager { var doDeselect = true; if (SnappingManager.IsDragging) { DragManager.AbortDrag(); - } else if (CollectionDockingView.Instance?.HasFullScreen) { + } + if (CollectionDockingView.Instance?.HasFullScreen) { CollectionDockingView.Instance?.CloseFullScreen(); - } else if (CollectionStackedTimeline.SelectingRegion) { - CollectionStackedTimeline.SelectingRegion = undefined; + } + if (CollectionStackedTimeline.SelectingRegions.size) { + CollectionStackedTimeline.StopSelecting(); doDeselect = false; } else { doDeselect = !ContextMenu.Instance.closeMenu(); diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx index ea038250e..068143225 100644 --- a/src/client/views/UndoStack.tsx +++ b/src/client/views/UndoStack.tsx @@ -8,19 +8,13 @@ import { SettingsManager } from '../util/SettingsManager'; import { UndoManager } from '../util/UndoManager'; import './UndoStack.scss'; -interface UndoStackProps { - width?: number; - height?: number; - inline?: boolean; -} +interface UndoStackProps {} @observer export class UndoStack extends React.Component { - @observable static HideInline: boolean = false; - @observable static Expand: boolean = false; render() { const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.userVariantColor; const color = UndoManager.batchCounter.get() ? 'black' : SettingsManager.userColor; - return this.props.inline && UndoStack.HideInline ? null : ( + return (
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index c46f54c70..874cdffd9 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -615,7 +615,7 @@ ScriptingGlobals.add( // prettier-ignore switch (doc) { case '': return OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' }); - case "": return OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' }); + case "": return OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: 'Undo stack' }); } Doc.AddToMyOverlay(doc); } diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index d99b4f9de..22a67c501 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -56,8 +56,11 @@ export enum TrimScope { @observer export class CollectionStackedTimeline extends CollectionSubView() { - @observable static SelectingRegion: CollectionStackedTimeline | undefined = undefined; - @observable public static CurrentlyPlaying: DocumentView[] = []; + public static SelectingRegions: Set = new Set(); + public static StopSelecting() { + this.SelectingRegions.forEach(action(region => (region._selectingRegion = false))); + this.SelectingRegions.clear(); + } constructor(props: any) { super(props); makeObservable(this); @@ -69,6 +72,8 @@ export class CollectionStackedTimeline extends CollectionSubView (CollectionStackedTimeline.SelectingRegion = undefined)); + if (this._selectingRegion) { + runInAction(() => (this._selectingRegion = false)); + CollectionStackedTimeline.SelectingRegions.delete(this); } } @@ -154,6 +160,15 @@ export class CollectionStackedTimeline extends CollectionSubView this.childDocList?.some(item => item === doc); + + getView = async (doc: Doc, options: DocFocusOptions): Promise> => + new Promise>(res => { + if (doc.hidden) options.didMove = !(doc.hidden = false); + const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv)); + findDoc(dv => res(dv)); + }); + anchorStart = (anchor: Doc) => NumCast(anchor._timecodeToShow, NumCast(anchor[this._props.startTag])); anchorEnd = (anchor: Doc, val: any = null) => NumCast(anchor._timecodeToHide, NumCast(anchor[this._props.endTag], val) ?? null); @@ -191,14 +206,16 @@ export class CollectionStackedTimeline extends CollectionSubView ({ - level: this.getLevel(anchor, overlaps), - anchor, + const drawAnchors = this.childLayoutPairs.map(pair => ({ + level: this.getLevel(pair.layout, overlaps), + anchor: pair.layout, })); const maxLevel = overlaps.reduce((m, o) => Math.max(m, o.level), 0) + 2; return this.clipDuration === 0 ? null : ( diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a3cedb9a0..8268a47d8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -321,9 +321,9 @@ export class CollectionFreeFormView extends CollectionSubView> => + getView = async (doc: Doc, options: DocFocusOptions): Promise> => new Promise>(res => { - if (doc.hidden && this._lightboxDoc !== doc) doc.hidden = false; + if (doc.hidden && this._lightboxDoc !== doc) options.didMove = !(doc.hidden = false); const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv)); findDoc(dv => res(dv)); }); diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index f1fb68003..d105b04f7 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -147,7 +147,7 @@ export class CollectionLinearView extends CollectionSubView() { switch (doc.layout) { case '': return this.getLinkUI(); case '': return this.getCurrentlyPlayingUI(); - case '': return ; + case '': return ; case '': return Doc.UserDoc().isBranchingMode ? : null; } diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 989dd1db0..e57ef4871 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -19,6 +19,7 @@ import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocum import { DocumentView } from '../nodes/DocumentView'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; import { WebBox } from '../nodes/WebBox'; +import { VideoBox } from '../nodes/VideoBox'; ScriptingGlobals.add(function IsNoneSelected() { return SelectionManager.Views.length <= 0; @@ -390,14 +391,16 @@ ScriptingGlobals.add(function webForward(checkResult?: boolean) { } selected?.forward(); }); -ScriptingGlobals.add(function webBack(checkResult?: boolean) { +ScriptingGlobals.add(function webBack() { const selected = SelectionManager.Views.lastElement()?.ComponentView as WebBox; - if (checkResult) { - return selected?.back(checkResult) ? undefined : 'lightGray'; - } selected?.back(); }); +ScriptingGlobals.add(function videoSnapshot() { + const selected = SelectionManager.Views.lastElement()?.ComponentView as VideoBox; + selected?.Snapshot(); +}); + /** Schema * toggleSchemaPreview **/ diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 76cc010f6..5a55ca764 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -20,7 +20,7 @@ import { SidebarAnnos } from '../../SidebarAnnos'; import { CollectionFreeFormView } from '../../collections/collectionFreeForm'; import { AnchorMenu } from '../../pdf/AnchorMenu'; import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup'; -import { DocumentView } from '../DocumentView'; +import { DocFocusOptions, DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { PinProps } from '../trails'; import './DataVizBox.scss'; @@ -228,8 +228,11 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { () => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar') ); }; - getView = async (doc: Doc) => { - if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(); + getView = async (doc: Doc, options: DocFocusOptions) => { + if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { + options.didMove = true; + this.toggleSidebar(); + } return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); }; @computed get sidebarWidthPercent() { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7f1e547e4..6cc61ec62 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -43,7 +43,6 @@ import { GestureOverlay } from '../GestureOverlay'; import { LightboxView } from '../LightboxView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; -import { UndoStack } from '../UndoStack'; import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView'; import { DocumentContentsView, ObserverJsxParser } from './DocumentContentsView'; import { DocumentLinksButton } from './DocumentLinksButton'; @@ -119,7 +118,7 @@ export interface DocComponentView { restoreView?: (viewSpec: Doc) => boolean; scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: DocFocusOptions) => Opt; // returns the duration of the focus brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number, holdTime: number) => void; // highlight a region of a view (used by freeforms) - getView?: (doc: Doc) => Promise>; // returns a nested DocumentView for the specified doc or undefined + getView?: (doc: Doc, options: DocFocusOptions) => Promise>; // returns a nested DocumentView for the specified doc or undefined addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections) select?: (ctrlKey: boolean, shiftKey: boolean) => void; @@ -520,11 +519,7 @@ export class DocumentViewInternal extends DocComponent { if (DocumentView.LongPress) { - if (this.Document.undoIgnoreFields) { - runInAction(() => (UndoStack.HideInline = !UndoStack.HideInline)); - } else { - this._props.select(false); - } + this._props.select(false); } }, 1000); if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this._props.DocumentView(); diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 41befbbfe..3575b21e4 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -27,7 +27,7 @@ import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocC import { SidebarAnnos } from '../../SidebarAnnos'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { Colors } from '../../global/globalEnums'; -import { DocumentView } from '../DocumentView'; +import { DocFocusOptions, DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; @@ -504,8 +504,11 @@ export class MapBox extends ViewBoxAnnotatableComponent { - if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(); + getView = async (doc: Doc, options: DocFocusOptions) => { + if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { + this.toggleSidebar(); + options.didMove = true; + } return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); }; /* diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index 8b22a1531..ea8496c99 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -20,7 +20,7 @@ import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocC import { SidebarAnnos } from '../../SidebarAnnos'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { Colors } from '../../global/globalEnums'; -import { DocumentView } from '../DocumentView'; +import { DocFocusOptions, DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { MapAnchorMenu } from '../MapBox/MapAnchorMenu'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; @@ -374,8 +374,11 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { - if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(); + getView = async (doc: Doc, options: DocFocusOptions) => { + if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { + this.toggleSidebar(); + options.didMove = true; + } return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); }; /* diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 55a459a5c..959d5d88d 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -224,8 +224,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent { - if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(false); + getView = async (doc: Doc, options: DocFocusOptions) => { + if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { + options.didMove = true; + this.toggleSidebar(false); + } return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); }; diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss index ae923ad60..460155446 100644 --- a/src/client/views/nodes/VideoBox.scss +++ b/src/client/views/nodes/VideoBox.scss @@ -180,9 +180,9 @@ } } -video::-webkit-media-controls { - display: none !important; -} +// video::-webkit-media-controls { +// display: none !important; +// } input[type='range'] { -webkit-appearance: none; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index ce73d9f37..fb42286af 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -1,9 +1,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction, untracked } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { basename } from 'path'; import * as React from 'react'; -import { Doc, StrListCast } from '../../../fields/Doc'; +import { Doc, Opt, StrListCast } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; @@ -12,23 +12,20 @@ import { AudioField, ImageField, VideoField } from '../../../fields/URLField'; import { emptyFunction, formatTime, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; -import { Networking } from '../../Network'; import { DocumentManager } from '../../util/DocumentManager'; import { FollowLinkScript } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; import { ReplayMovements } from '../../util/ReplayMovements'; -import { SelectionManager } from '../../util/SelectionManager'; -import { SnappingManager } from '../../util/SnappingManager'; import { undoBatch } from '../../util/UndoManager'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionStackedTimeline'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { AnchorMenu } from '../pdf/AnchorMenu'; import { StyleProp } from '../StyleProvider'; -import { DocFocusOptions, DocumentView, OpenWhere } from './DocumentView'; +import { DocFocusOptions, DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { RecordingBox } from './RecordingBox'; import { PinProps, PresBox } from './trails'; @@ -40,7 +37,7 @@ import './VideoBox.scss'; * Supporting Components: CollectionStackedTimeline * * VideoBox is a node that supports the playback of video files in Dash. - * When a video file or YouTube video is importeed into Dash, it is immediately rendered as a VideoBox document. + * When a video file is importeed into Dash, it is immediately rendered as a VideoBox document. * CollectionStackedTimline handles AudioBox and VideoBox shared behavior, but VideoBox handles playing, pausing, etc because it contains