From b1376d401e709515cee078cc08b05fd3fb89caeb Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 24 Apr 2024 18:12:30 -0400 Subject: completing eslint pass --- src/client/views/nodes/MapBox/AnimationUtility.ts | 57 +++++++++++------------ 1 file changed, 26 insertions(+), 31 deletions(-) (limited to 'src/client/views/nodes/MapBox/AnimationUtility.ts') diff --git a/src/client/views/nodes/MapBox/AnimationUtility.ts b/src/client/views/nodes/MapBox/AnimationUtility.ts index 35153f439..cf5315da3 100644 --- a/src/client/views/nodes/MapBox/AnimationUtility.ts +++ b/src/client/views/nodes/MapBox/AnimationUtility.ts @@ -87,25 +87,24 @@ export class AnimationUtility { @computed get currentPitch(): number { if (!this.isStreetViewAnimation) return 50; if (!this.terrainDisplayed) return 80; - else { - // const groundElevation = 0; - const heightAboveGround = this.currentAnimationAltitude; - const horizontalDistance = 500; - - let pitch; - if (heightAboveGround >= 0) { - pitch = 90 - Math.atan(heightAboveGround / horizontalDistance) * (180 / Math.PI); - } else { - pitch = 80; - } - console.log(Math.max(50, Math.min(pitch, 85))); + // const groundElevation = 0; + const heightAboveGround = this.currentAnimationAltitude; + const horizontalDistance = 500; - if (this.previousPitch) { - return this.lerp(Math.max(50, Math.min(pitch, 85)), this.previousPitch, 0.02); - } - return Math.max(50, Math.min(pitch, 85)); + let pitch; + if (heightAboveGround >= 0) { + pitch = 90 - Math.atan(heightAboveGround / horizontalDistance) * (180 / Math.PI); + } else { + pitch = 80; + } + + console.log(Math.max(50, Math.min(pitch, 85))); + + if (this.previousPitch) { + return this.lerp(Math.max(50, Math.min(pitch, 85)), this.previousPitch, 0.02); } + return Math.max(50, Math.min(pitch, 85)); } @computed get flyInEndPitch() { @@ -214,8 +213,8 @@ export class AnimationUtility { currentAnimationPhase: number; updateAnimationPhase: (newAnimationPhase: number) => void; updateFrameId: (newFrameId: number) => void; - }) => { - return new Promise(async resolve => { + }) => + new Promise(async resolve => { let startTime: number | null = null; const frame = async (currentTime: number) => { @@ -257,7 +256,7 @@ export class AnimationUtility { updateAnimationPhase(animationPhase); // compute corrected camera ground position, so that he leading edge of the path is in view - var correctedPosition = this.computeCameraPosition( + const correctedPosition = this.computeCameraPosition( this.isStreetViewAnimation, this.currentPitch, bearing, @@ -277,7 +276,7 @@ export class AnimationUtility { map.setFreeCameraOptions(camera); this.previousAltitude = this.currentAnimationAltitude; - this.previousPitch = this.previousPitch; + // this.previousPitch = this.previousPitch; // repeat! const innerFrameId = await window.requestAnimationFrame(frame); @@ -287,15 +286,14 @@ export class AnimationUtility { const outerFrameId = await window.requestAnimationFrame(frame); updateFrameId(outerFrameId); }); - }; - public flyInAndRotate = async ({ map, updateFrameId }: { map: MapRef; updateFrameId: (newFrameId: number) => void }) => { - return new Promise<{ bearing: number; altitude: number }>(async resolve => { + public flyInAndRotate = async ({ map, updateFrameId }: { map: MapRef; updateFrameId: (newFrameId: number) => void }) => + new Promise<{ bearing: number; altitude: number }>(async resolve => { let start: number | null; - var currentAltitude; - var currentBearing; - var currentPitch; + let currentAltitude; + let currentBearing; + let currentPitch; // the animation frame will run as many times as necessary until the duration has been reached const frame = async (time: number) => { @@ -319,7 +317,7 @@ export class AnimationUtility { currentPitch = this.FLY_IN_START_PITCH + (this.flyInEndPitch - this.FLY_IN_START_PITCH) * d3.easeCubicOut(animationPhase); // compute corrected camera ground position, so the start of the path is always in view - var correctedPosition = this.computeCameraPosition(false, currentPitch, currentBearing, this.FIRST_LNG_LAT, currentAltitude); + const correctedPosition = this.computeCameraPosition(false, currentPitch, currentBearing, this.FIRST_LNG_LAT, currentAltitude); // set the pitch and bearing of the camera const camera = map.getFreeCameraOptions(); @@ -349,13 +347,10 @@ export class AnimationUtility { const outerFrameId = await window.requestAnimationFrame(frame); updateFrameId(outerFrameId); }); - }; previousCameraPosition: { lng: number; lat: number } | null = null; - lerp = (start: number, end: number, amt: number) => { - return (1 - amt) * start + amt * end; - }; + lerp = (start: number, end: number, amt: number) => (1 - amt) * start + amt * end; computeCameraPosition = (isStreetViewAnimation: boolean, pitch: number, bearing: number, targetPosition: { lng: number; lat: number }, altitude: number, smooth = false) => { const bearingInRadian = (bearing * Math.PI) / 180; -- cgit v1.2.3-70-g09d2 From 9dc32440852c8af3575687d96f0442bf18542671 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 29 Apr 2024 23:51:24 -0400 Subject: more eslint --- package-lock.json | 1 + package.json | 1 + .../apis/google_docs/GoogleApiClientUtils.ts | 49 ++-- src/client/cognitive_services/CognitiveServices.ts | 46 ++-- src/client/util/CurrentUserUtils.ts | 26 +- src/client/util/DictationManager.ts | 7 +- src/client/util/HypothesisUtils.ts | 21 +- src/client/util/Scripting.ts | 4 +- src/client/util/SelectionManager.ts | 2 +- src/client/views/newlightbox/ExploreView/utils.ts | 21 +- .../newlightbox/components/Recommendation/utils.ts | 38 +-- src/client/views/nodes/MapBox/AnimationUtility.ts | 3 + src/client/views/nodes/MapBox/MapBox.tsx | 293 +++++++++++---------- src/fields/RichTextUtils.ts | 194 +++++++------- 14 files changed, 371 insertions(+), 335 deletions(-) (limited to 'src/client/views/nodes/MapBox/AnimationUtility.ts') diff --git a/package-lock.json b/package-lock.json index 642e978cd..80aef5232 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,6 +42,7 @@ "@types/find-in-files": "^0.5.3", "@types/fluent-ffmpeg": "^2.1.24", "@types/formidable": "3.4.5", + "@types/geojson": "^7946.0.14", "@types/google-maps": "^3.2.6", "@types/mapbox-gl": "^3.1.0", "@types/pdf-parse": "^1.1.4", diff --git a/package.json b/package.json index 90e3f39c0..d826c855e 100644 --- a/package.json +++ b/package.json @@ -127,6 +127,7 @@ "@types/find-in-files": "^0.5.3", "@types/fluent-ffmpeg": "^2.1.24", "@types/formidable": "3.4.5", + "@types/geojson": "^7946.0.14", "@types/google-maps": "^3.2.6", "@types/mapbox-gl": "^3.1.0", "@types/pdf-parse": "^1.1.4", diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts index 3c2f923ea..0b303eacf 100644 --- a/src/client/apis/google_docs/GoogleApiClientUtils.ts +++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts @@ -1,4 +1,7 @@ -import { docs_v1 } from 'googleapis'; +/* eslint-disable no-restricted-syntax */ +/* eslint-disable no-use-before-define */ +import { docs_v1 as docsV1 } from 'googleapis'; +// eslint-disable-next-line node/no-deprecated-api import { isArray } from 'util'; import { EditorState } from 'prosemirror-state'; import { Opt } from '../../../fields/Doc'; @@ -15,12 +18,12 @@ export namespace GoogleApiClientUtils { } export namespace Docs { - export type RetrievalResult = Opt; - export type UpdateResult = Opt; + export type RetrievalResult = Opt; + export type UpdateResult = Opt; export interface UpdateOptions { documentId: DocumentId; - requests: docs_v1.Schema$Request[]; + requests: docsV1.Schema$Request[]; } export enum WriteMode { @@ -32,7 +35,7 @@ export namespace GoogleApiClientUtils { export type Reference = DocumentId | CreateOptions; export interface Content { text: string | string[]; - requests: docs_v1.Schema$Request[]; + requests: docsV1.Schema$Request[]; } export type IdHandler = (id: DocumentId) => any; export type CreationResult = Opt; @@ -81,7 +84,7 @@ export namespace GoogleApiClientUtils { }, }; try { - const schema: docs_v1.Schema$Document = await Networking.PostToServer(path, parameters); + const schema: docsV1.Schema$Document = await Networking.PostToServer(path, parameters); return schema.documentId === null ? undefined : schema.documentId; } catch { return undefined; @@ -90,13 +93,13 @@ export namespace GoogleApiClientUtils { export namespace Utils { export type ExtractResult = { text: string; paragraphs: DeconstructedParagraph[] }; - export const extractText = (document: docs_v1.Schema$Document, removeNewlines = false): ExtractResult => { + export const extractText = (document: docsV1.Schema$Document, removeNewlines = false): ExtractResult => { const paragraphs = extractParagraphs(document); let text = paragraphs .map(paragraph => paragraph.contents .filter(content => !('inlineObjectId' in content)) - .map(run => (run as docs_v1.Schema$TextRun).content) + .map(run => (run as docsV1.Schema$TextRun).content) .join('') ) .join(''); @@ -105,9 +108,9 @@ export namespace GoogleApiClientUtils { return { text, paragraphs }; }; - export type ContentArray = (docs_v1.Schema$TextRun | docs_v1.Schema$InlineObjectElement)[]; + export type ContentArray = (docsV1.Schema$TextRun | docsV1.Schema$InlineObjectElement)[]; export type DeconstructedParagraph = { contents: ContentArray; bullet: Opt }; - const extractParagraphs = (document: docs_v1.Schema$Document, filterEmpty = true): DeconstructedParagraph[] => { + const extractParagraphs = (document: docsV1.Schema$Document, filterEmpty = true): DeconstructedParagraph[] => { const fragments: DeconstructedParagraph[] = []; if (document.body && document.body.content) { for (const element of document.body.content) { @@ -136,7 +139,7 @@ export namespace GoogleApiClientUtils { return fragments; }; - export const endOf = (schema: docs_v1.Schema$Document): number | undefined => { + export const endOf = (schema: docsV1.Schema$Document): number | undefined => { if (schema.body && schema.body.content) { const paragraphs = schema.body.content.filter(el => el.paragraph); if (paragraphs.length) { @@ -150,6 +153,7 @@ export namespace GoogleApiClientUtils { } } } + return undefined; }; export const initialize = async (reference: Reference) => (typeof reference === 'string' ? reference : create(reference)); @@ -182,26 +186,26 @@ export namespace GoogleApiClientUtils { } }; - export const read = async (options: ReadOptions): Promise> => { - return retrieve({ documentId: options.documentId }).then(document => { + export const read = async (options: ReadOptions): Promise> => + retrieve({ documentId: options.documentId }).then(document => { if (document) { const title = document.title!; const body = Utils.extractText(document, options.removeNewlines).text; return { title, body }; } + return undefined; }); - }; - export const readLines = async (options: ReadOptions): Promise> => { - return retrieve({ documentId: options.documentId }).then(document => { + export const readLines = async (options: ReadOptions): Promise> => + retrieve({ documentId: options.documentId }).then(document => { if (document) { - const title = document.title; + const { title } = document; let bodyLines = Utils.extractText(document).text.split('\n'); options.removeNewlines && (bodyLines = bodyLines.filter(line => line.length)); return { title: title ?? '', bodyLines }; } + return undefined; }); - }; export const setStyle = async (options: UpdateOptions) => { const replies: any = await update({ @@ -216,15 +220,16 @@ export namespace GoogleApiClientUtils { }; export const write = async (options: WriteOptions): Promise => { - const requests: docs_v1.Schema$Request[] = []; + const requests: docsV1.Schema$Request[] = []; const documentId = await Utils.initialize(options.reference); if (!documentId) { return undefined; } - let index = options.index; - const mode = options.mode; + let { index } = options; + const { mode } = options; if (!(index && mode === WriteMode.Insert)) { const schema = await retrieve({ documentId }); + // eslint-disable-next-line no-cond-assign if (!schema || !(index = Utils.endOf(schema))) { return undefined; } @@ -241,7 +246,7 @@ export namespace GoogleApiClientUtils { }); index = 1; } - const text = options.content.text; + const { text } = options.content; text.length && requests.push({ insertText: { diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index 4ad03aab4..9808b6a01 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -1,9 +1,14 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable camelcase */ +/* eslint-disable no-useless-catch */ +/* eslint-disable no-use-before-define */ import * as rp from 'request-promise'; import { Doc, FieldType } from '../../fields/Doc'; import { InkData } from '../../fields/InkField'; import { List } from '../../fields/List'; import { Cast } from '../../fields/Types'; import { UndoManager } from '../util/UndoManager'; +import { ClientUtils } from '../../ClientUtils'; type APIManager = { converter: BodyConverter; requester: RequestExecutor }; type RequestExecutor = (apiKey: string, body: string, service: Service) => Promise; @@ -40,7 +45,7 @@ export enum Confidence { */ export namespace CognitiveServices { const ExecuteQuery = async (service: Service, manager: APIManager, data: D): Promise => { - let apiKey = process.env[service.toUpperCase()]; + const apiKey = process.env[service.toUpperCase()]; if (!apiKey) { console.log(`No API key found for ${service}: ensure youe root directory has .env file with _CLIENT_${service.toUpperCase()}.`); return undefined; @@ -51,7 +56,6 @@ export namespace CognitiveServices { results = await manager.requester(apiKey, manager.converter(data), service).then(json => JSON.parse(json)); } catch (e) { throw e; - results = undefined; } return results; }; @@ -70,7 +74,7 @@ export namespace CognitiveServices { parameters = { returnFaceId: 'true', returnFaceLandmarks: 'false', - returnFaceAttributes: 'age,gender,headPose,smile,facialHair,glasses,' + 'emotion,hair,makeup,occlusion,accessories,blur,exposure,noise', + returnFaceAttributes: 'age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise', }; break; case Service.ComputerVision: @@ -81,6 +85,7 @@ export namespace CognitiveServices { language: 'en', }; break; + default: } const options = { @@ -109,12 +114,10 @@ export namespace CognitiveServices { const results = await ExecuteQuery(service, Manager, url); if (!results) { toStore = 'Cognitive Services could not process the given image URL.'; + } else if (!results.length) { + toStore = converter(results); } else { - if (!results.length) { - toStore = converter(results); - } else { - toStore = results.length > 0 ? converter(results) : 'Empty list returned.'; - } + toStore = results.length > 0 ? converter(results) : 'Empty list returned.'; } target[storageKey] = toStore; @@ -148,7 +151,7 @@ export namespace CognitiveServices { const endpoint = serverAddress + '/inkrecognizer/v1.0-preview/recognize'; return new Promise((resolve, reject) => { - xhttp.onreadystatechange = function () { + xhttp.onreadystatechange = function (this: XMLHttpRequest) { if (this.readyState === 4) { const result = xhttp.responseText; switch (this.status) { @@ -159,6 +162,7 @@ export namespace CognitiveServices { return reject(result); } } + return undefined; }; xhttp.open('PUT', endpoint, true); @@ -211,15 +215,13 @@ export namespace CognitiveServices { export namespace BingSearch { export const Manager: APIManager = { - converter: (data: string) => { - return data; - }, + converter: (data: string) => data, requester: async (apiKey: string, query: string) => { const xhttp = new XMLHttpRequest(); const serverAddress = 'https://api.cognitive.microsoft.com'; const endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query); const promisified = (resolve: any, reject: any) => { - xhttp.onreadystatechange = function () { + xhttp.onreadystatechange = function (this: XMLHttpRequest) { if (this.readyState === 4) { const result = xhttp.responseText; switch (this.status) { @@ -230,6 +232,7 @@ export namespace CognitiveServices { return reject(result); } } + return undefined; }; if (apiKey) { @@ -257,15 +260,13 @@ export namespace CognitiveServices { export namespace HathiTrust { export const Manager: APIManager = { - converter: (data: string) => { - return data; - }, + converter: (data: string) => data, requester: async (apiKey: string, query: string) => { const xhttp = new XMLHttpRequest(); const serverAddress = 'https://babel.hathitrust.org/cgi/htd/​'; const endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query); const promisified = (resolve: any, reject: any) => { - xhttp.onreadystatechange = function () { + xhttp.onreadystatechange = function (this: XMLHttpRequest) { if (this.readyState === 4) { const result = xhttp.responseText; switch (this.status) { @@ -276,6 +277,7 @@ export namespace CognitiveServices { return reject(result); } } + return undefined; }; if (apiKey) { @@ -303,8 +305,8 @@ export namespace CognitiveServices { export namespace Text { export const Manager: APIManager = { - converter: (data: string) => { - return JSON.stringify({ + converter: (data: string) => + JSON.stringify({ documents: [ { id: 1, @@ -312,8 +314,7 @@ export namespace CognitiveServices { text: data, }, ], - }); - }, + }), requester: async (apiKey: string, body: string, service: Service) => { const serverAddress = 'https://eastus.api.cognitive.microsoft.com'; const endpoint = serverAddress + '/text/analytics/v2.1/keyPhrases'; @@ -367,11 +368,12 @@ export namespace CognitiveServices { const { keyterms, external_recommendations, kp_string } = await converter(results, data); target[keys[0]] = keyterms; if (isInternal) { - //await vectorize([data], dataDoc, isMainDoc); + // await vectorize([data], dataDoc, isMainDoc); await vectorize(kp_string, dataDoc, isMainDoc); } else { return { recs: external_recommendations, keyterms: keyterms }; } + return undefined; }; // export async function countFrequencies() diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 65dce34a5..eae5b2d6a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -735,19 +735,19 @@ pie title Minerals in my tap water { title: "Header", icon: "heading", toolTip: "Doc Titlebar Color", btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'} }, { title: "Template",icon: "scroll", toolTip: "Default Note Template",btnType: ButtonType.ToggleButton, expertMode: false, toolType:DocumentType.RTF, scripts: { onClick: '{ return setDefaultTemplate(_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(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: "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 video is selected - { title: "Image", icon: "Image", toolTip: "Image functions", subMenu: CurrentUserUtils.imageTools(), expertMode: false, toolType:DocumentType.IMG, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when image 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 + { title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!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: '!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: '!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: '!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: `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: `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: `!SelectedDocType(this.toolType, this.expertMode, true)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `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: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when video is selected + { title: "Image", icon: "Image", toolTip: "Image functions", subMenu: CurrentUserUtils.imageTools(), expertMode: false, toolType:DocumentType.IMG, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when image is selected + { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when Schema is selected ]; } diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index 08fd80882..9026b368f 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -63,7 +63,7 @@ export namespace DictationManager { const intraSession = '. '; const interSession = ' ... '; - export let isListening = false; + let isListening = false; let isManuallyStopped = false; let current: string | undefined; @@ -235,7 +235,10 @@ export namespace DictationManager { export type DependentEntry = { expression: RegExp; action: DependentAction; restrictTo?: DocumentType[] }; export const RegisterIndependent = (key: string, value: IndependentEntry) => Independent.set(key, value); - export const RegisterDependent = (entry: DependentEntry) => Dependent.push(entry); + export const RegisterDependent = (entry: DependentEntry) => { + const { expression, action, restrictTo } = entry; + return Dependent.push({ expression, action, restrictTo: restrictTo ?? [] }); + }; export const execute = async (phrase: string) => UndoManager.RunInBatch(async () => { diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts index 6dc96f1b5..dd18b2533 100644 --- a/src/client/util/HypothesisUtils.ts +++ b/src/client/util/HypothesisUtils.ts @@ -15,6 +15,7 @@ export namespace Hypothesis { * If none exist, create and return a new WebDocument. */ export const getSourceWebDoc = async (uri: string) => { + // eslint-disable-next-line no-use-before-define const result = await findWebDoc(uri); console.log(result ? 'existing doc found' : 'existing doc NOT found'); return result || Docs.Create.WebDocument(uri, { title: uri, _nativeWidth: 850, _height: 512, _width: 400, data_useCors: true }); // create and return a new Web doc with given uri if no matching docs are found @@ -75,17 +76,19 @@ export namespace Hypothesis { /** * Send message to Hypothes.is client to edit an annotation to add a Dash hyperlink */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars export const makeLink = async (title: string, url: string, annotationId: string, annotationSourceDoc: Doc) => { // if the annotation's source webpage isn't currently loaded in Dash, we're not able to access and edit the annotation from the client // so we're loading the webpage and its annotations invisibly in a WebBox in MainView.tsx, until the editing is done - //!DocumentManager.Instance.getFirstDocumentView(annotationSourceDoc) && runInAction(() => DocumentLinksButton.invisibleWebDoc = annotationSourceDoc); + //! DocumentManager.Instance.getFirstDocumentView(annotationSourceDoc) && runInAction(() => DocumentLinksButton.invisibleWebDoc = annotationSourceDoc); - var success = false; + let success = false; const onSuccess = action(() => { console.log('Edit success!!'); success = true; + // eslint-disable-next-line no-use-before-define clearTimeout(interval); - //DocumentLinksButton.invisibleWebDoc = undefined; + // DocumentLinksButton.invisibleWebDoc = undefined; document.removeEventListener('editSuccess', onSuccess); }); @@ -107,7 +110,7 @@ export namespace Hypothesis { action(() => { if (!success) { clearInterval(interval); - //DocumentLinksButton.invisibleWebDoc = undefined; + // DocumentLinksButton.invisibleWebDoc = undefined; } }), 10000 @@ -121,12 +124,13 @@ export namespace Hypothesis { export const deleteLink = async (linkDoc: Doc, sourceDoc: Doc, destinationDoc: Doc) => { if (Cast(destinationDoc.data, WebField)?.url.href !== StrCast(linkDoc.annotationUri)) return; // check that the destinationDoc is a WebDocument containing the target annotation - //!DocumentManager.Instance.getFirstDocumentView(destinationDoc) && runInAction(() => DocumentLinksButton.invisibleWebDoc = destinationDoc); // see note in makeLink + //! DocumentManager.Instance.getFirstDocumentView(destinationDoc) && runInAction(() => DocumentLinksButton.invisibleWebDoc = destinationDoc); // see note in makeLink - var success = false; + let success = false; const onSuccess = action(() => { console.log('Edit success!'); success = true; + // eslint-disable-next-line no-use-before-define clearTimeout(interval); // DocumentLinksButton.invisibleWebDoc = undefined; document.removeEventListener('editSuccess', onSuccess); @@ -149,7 +153,7 @@ export namespace Hypothesis { action(() => { if (!success) { clearInterval(interval); - //DocumentLinksButton.invisibleWebDoc = undefined; + // DocumentLinksButton.invisibleWebDoc = undefined; } }), 10000 @@ -161,10 +165,11 @@ export namespace Hypothesis { * Send message to Hypothes.is client to scroll to an annotation when it loads */ export const scrollToAnnotation = (annotationId: string, target: Doc) => { - var success = false; + let success = false; const onSuccess = () => { console.log('Scroll success!!'); document.removeEventListener('scrollSuccess', onSuccess); + // eslint-disable-next-line no-use-before-define clearInterval(interval); success = true; }; diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index f7d7ba6a4..8df579e75 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -1,9 +1,9 @@ +/* eslint-disable import/no-unresolved */ +/* eslint-disable import/no-webpack-loader-syntax */ // export const ts = (window as any).ts; // // @ts-ignore // import * as typescriptlib from '!!raw-loader!../../../node_modules/typescript/lib/lib.d.ts' -// // @ts-ignore // import * as typescriptes5 from '!!raw-loader!../../../node_modules/typescript/lib/lib.es5.d.ts' -// @ts-ignore // eslint-disable-next-line node/no-unpublished-import import * as ts from 'typescript'; import * as typescriptlib from '!!raw-loader!./type_decls.d'; diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 1328e90e9..7e8f42de9 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -75,7 +75,7 @@ export class SelectionManager { } // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function SelectionManager_selectedDocType(type: string, expertMode: boolean, checkContext?: boolean) { +ScriptingGlobals.add(function SelectedDocType(type: string, expertMode: boolean, checkContext?: boolean) { if (Doc.noviceMode && expertMode) return false; if (type === 'tab') { return SelectionManager.Views.lastElement()?._props.renderDepth === 0; diff --git a/src/client/views/newlightbox/ExploreView/utils.ts b/src/client/views/newlightbox/ExploreView/utils.ts index 7d9cf226d..2d1bd75a9 100644 --- a/src/client/views/newlightbox/ExploreView/utils.ts +++ b/src/client/views/newlightbox/ExploreView/utils.ts @@ -1,20 +1,21 @@ -import { IRecommendation } from "../components"; +import { IRecommendation } from '../components'; export interface IExploreView { - recs?: IRecommendation[], - bounds?: IBounds + recs?: IRecommendation[]; + // eslint-disable-next-line no-use-before-define + bounds?: IBounds; } export const emptyBounds = { max_x: 0, max_y: 0, min_x: 0, - min_y: 0 -} + min_y: 0, +}; export interface IBounds { - max_x: number, - max_y: number, - min_x: number, - min_y: number -} \ No newline at end of file + max_x: number; + max_y: number; + min_x: number; + min_y: number; +} diff --git a/src/client/views/newlightbox/components/Recommendation/utils.ts b/src/client/views/newlightbox/components/Recommendation/utils.ts index 796ce0eb0..4a55d394e 100644 --- a/src/client/views/newlightbox/components/Recommendation/utils.ts +++ b/src/client/views/newlightbox/components/Recommendation/utils.ts @@ -1,23 +1,23 @@ -import { DocumentType } from "../../../../documents/DocumentTypes" +import { DocumentType } from '../../../../documents/DocumentTypes'; export interface IRecommendation { - loading?: boolean - type?: DocumentType | string, - data?: string, - title?: string, - text?: string, - source?: string, - previewUrl?: string, + loading?: boolean; + type?: DocumentType | string; + data?: string; + title?: string; + text?: string; + source?: string; + previewUrl?: string; transcript?: { - text: string, - start: number, - duration: number - }[], + text: string; + start: number; + duration: number; + }[]; embedding?: { - x: number, - y: number - }, - distance?: number, - related_concepts?: string[], - docId?: string -} \ No newline at end of file + x: number; + y: number; + }; + distance?: number; + related_concepts?: string[]; + docId?: string; +} diff --git a/src/client/views/nodes/MapBox/AnimationUtility.ts b/src/client/views/nodes/MapBox/AnimationUtility.ts index cf5315da3..3a2679ecf 100644 --- a/src/client/views/nodes/MapBox/AnimationUtility.ts +++ b/src/client/views/nodes/MapBox/AnimationUtility.ts @@ -1,6 +1,7 @@ import * as turf from '@turf/turf'; import { Position } from '@turf/turf'; import * as d3 from 'd3'; +// eslint-disable-next-line import/no-extraneous-dependencies import { Feature, GeoJsonProperties, Geometry } from 'geojson'; import mapboxgl, { MercatorCoordinate } from 'mapbox-gl'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; @@ -214,6 +215,7 @@ export class AnimationUtility { updateAnimationPhase: (newAnimationPhase: number) => void; updateFrameId: (newFrameId: number) => void; }) => + // eslint-disable-next-line no-async-promise-executor new Promise(async resolve => { let startTime: number | null = null; @@ -288,6 +290,7 @@ export class AnimationUtility { }); public flyInAndRotate = async ({ map, updateFrameId }: { map: MapRef; updateFrameId: (newFrameId: number) => void }) => + // eslint-disable-next-line no-async-promise-executor new Promise<{ bearing: number; altitude: number }>(async resolve => { let start: number | null; diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 7009977d0..6495cf440 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -1,11 +1,14 @@ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +/* eslint-disable jsx-a11y/click-events-have-key-events */ 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'; +// eslint-disable-next-line import/no-extraneous-dependencies import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, Position } from 'geojson'; -import mapboxgl, { LngLat, LngLatBoundsLike, MapLayerMouseEvent } from 'mapbox-gl'; +import mapboxgl, { LngLatBoundsLike, MapLayerMouseEvent } from 'mapbox-gl'; import { IReactionDisposer, ObservableMap, action, autorun, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -21,7 +24,6 @@ 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 { UndoManager, undoable } from '../../../util/UndoManager'; import { PinProps, ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent'; import { SidebarAnnos } from '../../SidebarAnnos'; @@ -54,8 +56,6 @@ import { MarkerIcons } from './MarkerIcons'; */ const MAPBOX_ACCESS_TOKEN = 'pk.eyJ1IjoiemF1bHRhdmFuZ2FyIiwiYSI6ImNscHgwNDd1MDA3MXIydm92ODdianp6cGYifQ.WFAqbhwxtMHOWSPtu0l2uQ'; -const MAPBOX_FORWARD_GEOCODE_BASE_URL = 'https://api.mapbox.com/geocoding/v5/mapbox.places/'; -const MAPBOX_REVERSE_GEOCODE_BASE_URL = 'https://api.mapbox.com/geocoding/v5/mapbox.places/'; type PopupInfo = { longitude: number; @@ -287,7 +287,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem setupMoveUpEvents( this, e, - (e, down, delta) => + (moveEv, down, delta) => runInAction(() => { const localDelta = this._props .ScreenToLocalTransform() @@ -362,10 +362,10 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem const docView = this.DocumentView?.(); docView && DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, { - dragComplete: e => { - if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { - e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.Document; - e.annoDragData.linkSourceDoc.followLinkZoom = false; + dragComplete: dragEv => { + if (!dragEv.aborted && dragEv.annoDragData && dragEv.annoDragData.linkSourceDoc && dragEv.annoDragData.dropDocument && dragEv.linkDocument) { + dragEv.annoDragData.linkSourceDoc.followLinkToggle = dragEv.annoDragData.dropDocument.annotationOn === this.Document; + dragEv.annoDragData.linkSourceDoc.followLinkZoom = false; } }, }); @@ -437,7 +437,9 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem this.toggleSidebar(); options.didMove = true; } - return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); + return new Promise>(res => { + DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)); + }); }; /* @@ -528,6 +530,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu); }; + // eslint-disable-next-line @typescript-eslint/no-unused-vars recolorPin = (pin: Doc, color?: string) => { // this._bingMap.current.entities.remove(this.map_docToPinMap.get(pin)); // this.map_docToPinMap.delete(pin); @@ -582,6 +585,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem MapAnchorMenu.Instance.fadeOut(true); return mapRoute; } + return undefined; // TODO: Display error that can't create route to same location }, 'createmaproute'); @@ -654,9 +658,8 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem console.error(features); if (features && features.length > 0 && features[0].properties && features[0].geometry) { - const geometry = features[0].geometry as LineString; const { routeTitle } = features[0].properties; - const routeDoc: Doc | undefined = this.allRoutes.find(routeDoc => routeDoc.title === routeTitle); + const routeDoc: Doc | undefined = this.allRoutes.find(rtDoc => rtDoc.title === routeTitle); this.deselectPinOrRoute(); // TODO: Also deselect route if selected if (routeDoc) { this._selectedPinOrRoute = routeDoc; @@ -700,7 +703,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem */ handleMapDblClick = async (e: MapLayerMouseEvent) => { e.preventDefault(); - const { lngLat }: LngLat = e; + const { lngLat } = e; const longitude: number = lngLat.lng; const latitude: number = lngLat.lat; @@ -836,6 +839,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem if (!this._isAnimating) { return this.mapboxMapViewState; } + return undefined; } @action @@ -919,69 +923,73 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem this.path = path; this._isAnimating = true; - runInAction(() => { - return new Promise(async resolve => { - const targetLngLat = { - lng: this.selectedRouteCoordinates[0][0], - lat: this.selectedRouteCoordinates[0][1], - }; - - const animationUtil = new AnimationUtility(targetLngLat, this.selectedRouteCoordinates, this._isStreetViewAnimation, this._animationSpeed, this._showTerrain, this._mapRef.current); - runInAction(() => this.setAnimationUtility(animationUtil)); + runInAction( + () => + // eslint-disable-next-line no-async-promise-executor + new Promise(async resolve => { + const targetLngLat = { + lng: this.selectedRouteCoordinates[0][0], + lat: this.selectedRouteCoordinates[0][1], + }; + + const animationUtil = new AnimationUtility(targetLngLat, this.selectedRouteCoordinates, this._isStreetViewAnimation, this._animationSpeed, this._showTerrain, this._mapRef.current); + runInAction(() => this.setAnimationUtility(animationUtil)); + + const updateFrameId = (newFrameId: number) => this.setFrameId(newFrameId); + const updateAnimationPhase = (newAnimationPhase: number) => this.setAnimationPhase(newAnimationPhase); + + if (status !== AnimationStatus.RESUME) { + const result = await animationUtil.flyInAndRotate({ + map: this._mapRef.current!, + // targetLngLat, + // duration 3000 + // startAltitude: 3000000, + // endAltitude: this.isStreetViewAnimation ? 80 : 12000, + // startBearing: 0, + // endBearing: -20, + // startPitch: 40, + // endPitch: this.isStreetViewAnimation ? 80 : 50, + updateFrameId, + }); + + console.log('Bearing: ', result.bearing); + console.log('Altitude: ', result.altitude); + } - const updateFrameId = (newFrameId: number) => this.setFrameId(newFrameId); - const updateAnimationPhase = (newAnimationPhase: number) => this.setAnimationPhase(newAnimationPhase); + runInAction(() => { + this._finishedFlyTo = true; + }); - if (status !== AnimationStatus.RESUME) { - const result = await animationUtil.flyInAndRotate({ + // follow the path while slowly rotating the camera, passing in the camera bearing and altitude from the previous animation + await animationUtil.animatePath({ map: this._mapRef.current!, - // targetLngLat, - // duration 3000 - // startAltitude: 3000000, - // endAltitude: this.isStreetViewAnimation ? 80 : 12000, - // startBearing: 0, - // endBearing: -20, - // startPitch: 40, - // endPitch: this.isStreetViewAnimation ? 80 : 50, + // path: this.path, + // startBearing: -20, + // startAltitude: this.isStreetViewAnimation ? 80 : 12000, + // pitch: this.isStreetViewAnimation ? 80: 50, + currentAnimationPhase: this._animationPhase, + updateAnimationPhase, updateFrameId, }); - console.log('Bearing: ', result.bearing); - console.log('Altitude: ', result.altitude); - } + // get the bounds of the linestring, use fitBounds() to animate to a final view + const bbox3d = turf.bbox(this.path); - runInAction(() => (this._finishedFlyTo = true)); - - // follow the path while slowly rotating the camera, passing in the camera bearing and altitude from the previous animation - await animationUtil.animatePath({ - map: this._mapRef.current!, - // path: this.path, - // startBearing: -20, - // startAltitude: this.isStreetViewAnimation ? 80 : 12000, - // pitch: this.isStreetViewAnimation ? 80: 50, - currentAnimationPhase: this._animationPhase, - updateAnimationPhase, - updateFrameId, - }); + const bbox2d: LngLatBoundsLike = [bbox3d[0], bbox3d[1], bbox3d[2], bbox3d[3]]; - // get the bounds of the linestring, use fitBounds() to animate to a final view - const bbox3d = turf.bbox(this.path); - - const bbox2d: LngLatBoundsLike = [bbox3d[0], bbox3d[1], bbox3d[2], bbox3d[3]]; - - this._mapRef.current!.fitBounds(bbox2d, { - duration: 3000, - pitch: 30, - bearing: 0, - padding: 120, - }); + this._mapRef.current!.fitBounds(bbox2d, { + duration: 3000, + pitch: 30, + bearing: 0, + padding: 120, + }); - setTimeout(() => { - this._isStreetViewAnimation = false; - resolve(); - }, 10000); - }); - }); + setTimeout(() => { + this._isStreetViewAnimation = false; + resolve(); + }, 10000); + }) + ); }; @action @@ -1010,53 +1018,49 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem } }; - getRouteAnimationOptions = (): JSX.Element => { - return ( - <> + getRouteAnimationOptions = (): JSX.Element => ( + <> + { + if (this._isAnimating && this._finishedFlyTo) { + this.pauseAnimation(); + } else if (this._animationPhase > 0) { + this.playAnimation(AnimationStatus.RESUME); // Resume from the current phase + } else { + this.playAnimation(AnimationStatus.START); // Play from the beginning + } + }} + icon={this._isAnimating && this._finishedFlyTo ? : } + color="black" + size={Size.MEDIUM} + /> + {this._isAnimating && this._finishedFlyTo && ( { - if (this._isAnimating && this._finishedFlyTo) { - this.pauseAnimation(); - } else if (this._animationPhase > 0) { - this.playAnimation(AnimationStatus.RESUME); // Resume from the current phase - } else { - this.playAnimation(AnimationStatus.START); // Play from the beginning - } + this.stopAnimation(false); + this.playAnimation(AnimationStatus.START); }} - icon={this._isAnimating && this._finishedFlyTo ? : } + icon={} color="black" size={Size.MEDIUM} /> - {this._isAnimating && this._finishedFlyTo && ( - { - this.stopAnimation(false); - this.playAnimation(AnimationStatus.START); - }} - icon={} - color="black" - size={Size.MEDIUM} - /> - )} - this.stopAnimation(true)} icon={} color="black" size={Size.MEDIUM} /> - <> -
-
|
- } /> -
|
- -
|
-
-
Select Line Color:
- this.setAnimationLineColor(color)} /> -
-
- - - ); - }; + )} + this.stopAnimation(true)} icon={} color="black" size={Size.MEDIUM} /> +
+
|
+ } /> +
|
+ +
|
+
+
Select Line Color:
+ this.setAnimationLineColor(color)} /> +
+
+ + ); @action hideRoute = () => { @@ -1068,7 +1072,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem @action toggleSettings = () => { - if (!this._isAnimating && this._animationPhase == 0) { + if (!this._isAnimating && this._animationPhase === 0) { this._featuresFromGeocodeResults = []; this._settingsOpen = !this._settingsOpen; } @@ -1125,7 +1129,9 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem }; @action - onMapZoom = (e: ViewStateChangeEvent) => (this.dataDoc.map_zoom = e.viewState.zoom); + onMapZoom = (e: ViewStateChangeEvent) => { + this.dataDoc.map_zoom = e.viewState.zoom; + }; @action onMapMove = (e: ViewStateChangeEvent) => { @@ -1134,7 +1140,9 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem }; @action - toggleShowTerrain = () => (this._showTerrain = !this._showTerrain); + toggleShowTerrain = () => { + this._showTerrain = !this._showTerrain; + }; getMarkerIcon = (pinDoc: Doc): JSX.Element | null => { const markerType = StrCast(pinDoc.markerType); @@ -1148,7 +1156,6 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem const scale = this._props.NativeDimScaling?.() || 1; const parscale = scale === 1 ? 1 : this.ScreenToLocalBoxXf().Scale ?? 1; - const renderAnnotations = (childFilters?: () => string[]) => null; return (
() implem onWheel={e => e.stopPropagation()} onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()} style={{ transformOrigin: 'top left', transform: `scale(${scale})`, width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}> -
{renderAnnotations(this.transparentFilter)}
- {renderAnnotations(this.opaqueFilter)} - {SnappingManager.IsDragging ? null : renderAnnotations()} {!this._routeToAnimate && (
this.handleSearchChange(e.target.value)} /> - } type={Type.TERT} onClick={e => this.toggleSettings()} /> + } type={Type.TERT} onClick={() => this.toggleSettings()} />
- } type={Type.TERT} onClick={e => this.toggleSettings()} /> + } type={Type.TERT} onClick={() => this.toggleSettings()} />
)} @@ -1212,22 +1216,21 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem )} {this._featuresFromGeocodeResults.length > 0 && (
- <> -

Choose a location for your pin:

- {this._featuresFromGeocodeResults - .filter(feature => feature.place_name) - .map((feature, idx) => ( -
{ - this.handleSearchChange(''); - this.addMarkerForFeature(feature); - }}> -
{feature.place_name}
-
- ))} - +

Choose a location for your pin:

+ {this._featuresFromGeocodeResults + .filter(feature => feature.place_name) + .map((feature, idx) => ( +
{ + this.handleSearchChange(''); + this.addMarkerForFeature(feature); + }}> +
{feature.place_name}
+
+ ))}
)} @@ -1254,7 +1257,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem - {!this._isAnimating && this._animationPhase == 0 && ( + {!this._isAnimating && this._animationPhase === 0 && ( )} {this._routeToAnimate && (this._isAnimating || this._animationPhase > 0) && ( @@ -1318,16 +1321,15 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem )} - <> - {!this._isAnimating && - this._animationPhase == 0 && - this.allPushpins // .filter(anno => !anno.layout_unrendered) - .map((pushpin, idx) => ( - ) => this.handleMarkerClick(e, pushpin)}> - {this.getMarkerIcon(pushpin)} - - ))} - + {!this._isAnimating && + this._animationPhase === 0 && + this.allPushpins // .filter(anno => !anno.layout_unrendered) + .map((pushpin, idx) => ( + // eslint-disable-next-line react/no-array-index-key + ) => this.handleMarkerClick(e, pushpin)}> + {this.getMarkerIcon(pushpin)} + + ))} {/* {this.mapMarkers.length > 0 && this.mapMarkers.map((marker, idx) => ( @@ -1338,12 +1340,13 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem
{ - return new RichTextField(ToProsemirrorState(plainText, oldState), plainText); - }; + export const Synthesize = (plainText: string, oldState?: RichTextField) => new RichTextField(ToProsemirrorState(plainText, oldState), plainText); export const ToPlainText = (state: EditorState) => { // Because we're working with plain text, just concatenate all paragraphs - const content = state.doc.content; + const { content } = state.doc; const paragraphs: Node[] = []; content.forEach(node => node.type.name === 'paragraph' && paragraphs.push(node)); @@ -113,9 +113,9 @@ export namespace RichTextUtils { agnostic: string; } - const parseInlineObjects = async (document: docs_v1.Schema$Document): Promise> => { + const parseInlineObjects = async (document: docsV1.Schema$Document): Promise> => { const inlineObjectMap = new Map(); - const inlineObjects = document.inlineObjects; + const { inlineObjects } = document; if (inlineObjects) { const objects = Object.keys(inlineObjects).map(objectId => inlineObjects[objectId]); @@ -171,10 +171,12 @@ export namespace RichTextUtils { const indentMap = new Map(); let globalOffset = 0; const nodes: Node[] = []; + // eslint-disable-next-line no-restricted-syntax for (const element of structured) { if (Array.isArray(element)) { lists.push(element); const positions: BulletPosition[] = []; + // eslint-disable-next-line no-loop-func const items = element.map(paragraph => { const item = listItem(state.schema, paragraph.contents); const sinks = paragraph.bullet!; @@ -188,41 +190,42 @@ export namespace RichTextUtils { }); indentMap.set(element, positions); nodes.push(list(state.schema, items)); + } else if (element.contents.some(child => 'inlineObjectId' in child)) { + const group = element.contents; + // eslint-disable-next-line no-loop-func + group.forEach((child, i) => { + let node: Opt; + if ('inlineObjectId' in child) { + node = imageNode(state.schema, inlineObjectMap.get(child.inlineObjectId!)!, textNote); + } else if ('content' in child && (i !== group.length - 1 || child.content!.removeTrailingNewlines().length)) { + node = paragraphNode(state.schema, [child]); + } + if (node) { + position += node.nodeSize; + nodes.push(node); + } + }); } else { - if (element.contents.some(child => 'inlineObjectId' in child)) { - const group = element.contents; - group.forEach((child, i) => { - let node: Opt; - if ('inlineObjectId' in child) { - node = imageNode(state.schema, inlineObjectMap.get(child.inlineObjectId!)!, textNote); - } else if ('content' in child && (i !== group.length - 1 || child.content!.removeTrailingNewlines().length)) { - node = paragraphNode(state.schema, [child]); - } - if (node) { - position += node.nodeSize; - nodes.push(node); - } - }); - } else { - const paragraph = paragraphNode(state.schema, element.contents); - nodes.push(paragraph); - position += paragraph.nodeSize; - } + const paragraph = paragraphNode(state.schema, element.contents); + nodes.push(paragraph); + position += paragraph.nodeSize; } } state = state.apply(state.tr.replaceWith(0, 2, nodes)); const sink = sinkListItem(state.schema.nodes.list_item); - const dispatcher = (tr: Transaction) => (state = state.apply(tr)); - for (const list of lists) { - for (const pos of indentMap.get(list)!) { + const dispatcher = (tr: Transaction) => { + state = state.apply(tr); + }; + lists.forEach(list => { + indentMap.get(list)?.forEach(pos => { const resolved = state.doc.resolve(pos.value); state = state.apply(state.tr.setSelection(new TextSelection(resolved))); for (let i = 0; i < pos.sinks; i++) { sink(state, dispatcher); } - } - } + }); + }); return { title, text, state }; }; @@ -234,7 +237,7 @@ export namespace RichTextUtils { const parseLists = (paragraphs: ListGroup) => { const groups: PreparedParagraphs = []; let group: ListGroup = []; - for (const paragraph of paragraphs) { + paragraphs.forEach(paragraph => { if (paragraph.bullet !== undefined) { group.push(paragraph); } else { @@ -244,26 +247,22 @@ export namespace RichTextUtils { } groups.push(paragraph); } - } + }); group.length && groups.push(group); return groups; }; - const listItem = (schema: any, runs: docs_v1.Schema$TextRun[]): Node => { - return schema.node('list_item', null, paragraphNode(schema, runs)); - }; + const listItem = (lschema: any, runs: docsV1.Schema$TextRun[]): Node => lschema.node('list_item', null, paragraphNode(lschema, runs)); - const list = (schema: any, items: Node[]): Node => { - return schema.node('ordered_list', { mapStyle: 'bullet' }, items); - }; + const list = (lschema: any, items: Node[]): Node => lschema.node('ordered_list', { mapStyle: 'bullet' }, items); - const paragraphNode = (schema: any, runs: docs_v1.Schema$TextRun[]): Node => { - const children = runs.map(run => textNode(schema, run)).filter(child => child !== undefined); + const paragraphNode = (lschema: any, runs: docsV1.Schema$TextRun[]): Node => { + const children = runs.map(run => textNode(lschema, run)).filter(child => child !== undefined); const fragment = children.length ? Fragment.from(children) : undefined; - return schema.node('paragraph', null, fragment); + return lschema.node('paragraph', null, fragment); }; - const imageNode = (schema: any, image: ImageTemplate, textNote: Doc) => { + const imageNode = (lschema: any, image: ImageTemplate, textNote: Doc) => { const { url: src, width, agnostic } = image; let docId: string; const guid = Utils.GenerateDeterministicGuid(agnostic); @@ -276,30 +275,30 @@ export namespace RichTextUtils { } else { docId = backingDocId; } - return schema.node('image', { src, agnostic, width, docId, float: null }); + return lschema.node('image', { src, agnostic, width, docId, float: null }); }; - const textNode = (schema: any, run: docs_v1.Schema$TextRun) => { + const textNode = (lschema: any, run: docsV1.Schema$TextRun) => { const text = run.content!.removeTrailingNewlines(); - return text.length ? schema.text(text, styleToMarks(schema, run.textStyle)) : undefined; + return text.length ? lschema.text(text, styleToMarks(lschema, run.textStyle)) : undefined; }; - const StyleToMark = new Map([ + const StyleToMark = new Map([ ['bold', 'strong'], ['italic', 'em'], ['foregroundColor', 'pFontColor'], ['fontSize', 'pFontSize'], ]); - const styleToMarks = (schema: any, textStyle?: docs_v1.Schema$TextStyle) => { + const styleToMarks = (lschema: any, textStyle?: docsV1.Schema$TextStyle) => { if (!textStyle) { return undefined; } const marks: Mark[] = []; Object.keys(textStyle).forEach(key => { - let value: any; - const targeted = key as keyof docs_v1.Schema$TextStyle; - if ((value = textStyle[targeted])) { + const targeted = key as keyof docsV1.Schema$TextStyle; + const value = textStyle[targeted] as any; + if (value) { const attributes: any = {}; let converted = StyleToMark.get(targeted) || targeted; @@ -316,20 +315,20 @@ export namespace RichTextUtils { converted = ImportFontFamilyMapping.get(value.fontFamily) || 'timesNewRoman'; } - const mapped = schema.marks[converted]; + const mapped = lschema.marks[converted]; if (!mapped) { alert(`No mapping found for ${converted}!`); return; } - const mark = schema.mark(mapped, attributes); + const mark = lschema.mark(mapped, attributes); mark && marks.push(mark); } }); return marks; }; - const MarkToStyle = new Map([ + const MarkToStyle = new Map([ ['strong', 'bold'], ['em', 'italic'], ['pFontColor', 'foregroundColor'], @@ -361,16 +360,18 @@ export namespace RichTextUtils { const ignored = ['user_mark']; - const marksToStyle = async (nodes: (Node | null)[]): Promise => { - const requests: docs_v1.Schema$Request[] = []; + const marksToStyle = async (nodes: (Node | null)[]): Promise => { + const requests: docsV1.Schema$Request[] = []; let position = 1; + // eslint-disable-next-line no-restricted-syntax for (const node of nodes) { if (node === null) { position += 2; + // eslint-disable-next-line no-continue continue; } const { marks, attrs, nodeSize } = node; - const textStyle: docs_v1.Schema$TextStyle = {}; + const textStyle: docsV1.Schema$TextStyle = {}; const information: LinkInformation = { startIndex: position, endIndex: position + nodeSize, @@ -378,36 +379,45 @@ export namespace RichTextUtils { }; let mark: Mark; const markMap = BuildMarkMap(marks); + // eslint-disable-next-line no-restricted-syntax for (const markName of Object.keys(schema.marks)) { + // eslint-disable-next-line no-cond-assign if (ignored.includes(markName) || !(mark = markMap[markName])) { + // eslint-disable-next-line no-continue continue; } - let converted = MarkToStyle.get(markName) || (markName as keyof docs_v1.Schema$TextStyle); + let converted = MarkToStyle.get(markName) || (markName as keyof docsV1.Schema$TextStyle); let value: any = true; if (!converted) { + // eslint-disable-next-line no-continue continue; } + // eslint-disable-next-line @typescript-eslint/no-shadow const { attrs } = mark; switch (converted) { case 'link': - let url = attrs.allLinks.length ? attrs.allLinks[0].href : ''; - const delimiter = '/doc/'; - const alreadyShared = '?sharing=true'; - if (new RegExp(window.location.origin + delimiter).test(url) && !url.endsWith(alreadyShared)) { - const linkDoc = await DocServer.GetRefField(url.split(delimiter)[1]); - if (linkDoc instanceof Doc) { - let exported = (await Cast(linkDoc.link_anchor_2, Doc))!; - if (!exported.customLayout) { - exported = Doc.MakeEmbedding(exported); - DocUtils.makeCustomViewClicked(exported, Docs.Create.FreeformDocument); - linkDoc.link_anchor_2 = exported; + { + let url = attrs.allLinks.length ? attrs.allLinks[0].href : ''; + const docDelimeter = '/doc/'; + const alreadyShared = '?sharing=true'; + if (new RegExp(window.location.origin + docDelimeter).test(url) && !url.endsWith(alreadyShared)) { + // eslint-disable-next-line no-await-in-loop + const linkDoc = await DocServer.GetRefField(url.split(docDelimeter)[1]); + if (linkDoc instanceof Doc) { + // eslint-disable-next-line no-await-in-loop + let exported = (await Cast(linkDoc.link_anchor_2, Doc))!; + if (!exported.customLayout) { + exported = Doc.MakeEmbedding(exported); + DocUtils.makeCustomViewClicked(exported, Docs.Create.FreeformDocument); + linkDoc.link_anchor_2 = exported; + } + url = ClientUtils.shareUrl(exported[Id]); } - url = ClientUtils.shareUrl(exported[Id]); } + value = { url }; + textStyle.foregroundColor = fromRgb.blue; + textStyle.bold = true; } - value = { url }; - textStyle.foregroundColor = fromRgb.blue; - textStyle.bold = true; break; case 'fontSize': value = { magnitude: attrs.fontSize, unit: 'PT' }; @@ -417,9 +427,11 @@ export namespace RichTextUtils { break; case 'weightedFontFamily': value = { fontFamily: ExportFontFamilyMapping.get(markName) }; + break; + default: } - let matches: RegExpExecArray | null; - if ((matches = /p(\d+)/g.exec(markName)) !== null) { + const matches = /p(\d+)/g.exec(markName); + if (matches !== null) { converted = 'fontSize'; value = { magnitude: parseInt(matches[1].replace('px', '')), unit: 'PT' }; } @@ -429,7 +441,7 @@ export namespace RichTextUtils { requests.push(EncodeStyleUpdate(information)); } if (node.type.name === 'image') { - const width = attrs.width; + const { width } = attrs; requests.push( await EncodeImage({ startIndex: position + nodeSize - 1, @@ -445,14 +457,16 @@ export namespace RichTextUtils { const BuildMarkMap = (marks: readonly Mark[]) => { const markMap: { [type: string]: Mark } = {}; - marks.forEach(mark => (markMap[mark.type.name] = mark)); + marks.forEach(mark => { + markMap[mark.type.name] = mark; + }); return markMap; }; interface LinkInformation { startIndex: number; endIndex: number; - textStyle: docs_v1.Schema$TextStyle; + textStyle: docsV1.Schema$TextStyle; } interface ImageInformation { @@ -462,36 +476,34 @@ export namespace RichTextUtils { } namespace fromRgb { - export const convert = (red: number, green: number, blue: number): docs_v1.Schema$OptionalColor => { - return { - color: { - rgbColor: { - red: red / 255, - green: green / 255, - blue: blue / 255, - }, + export const convert = (red: number, green: number, blue: number): docsV1.Schema$OptionalColor => ({ + color: { + rgbColor: { + red: red / 255, + green: green / 255, + blue: blue / 255, }, - }; - }; + }, + }); export const red = convert(255, 0, 0); export const green = convert(0, 255, 0); export const blue = convert(0, 0, 255); } - const fromHex = (color: string): docs_v1.Schema$OptionalColor => { + const fromHex = (color: string): docsV1.Schema$OptionalColor => { const c = DashColor(color); return fromRgb.convert(c.red(), c.green(), c.blue()); }; - const EncodeStyleUpdate = (information: LinkInformation): docs_v1.Schema$Request => { + const EncodeStyleUpdate = (information: LinkInformation): docsV1.Schema$Request => { const { startIndex, endIndex, textStyle } = information; return { updateTextStyle: { fields: '*', range: { startIndex, endIndex }, textStyle, - } as docs_v1.Schema$UpdateTextStyleRequest, + } as docsV1.Schema$UpdateTextStyleRequest, }; }; -- cgit v1.2.3-70-g09d2 From 776c9cd88fc0799426ced87f36cb215dfdc1854b Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 30 Apr 2024 17:59:40 -0400 Subject: unwinding some import cycles. added PinFuncs and .from(dv:DocumentView) for CollectionFreeForm stiuff --- package-lock.json | 1 + package.json | 1 + src/client/util/SnappingManager.ts | 3 + src/client/views/DocComponent.tsx | 34 +---- src/client/views/DocumentDecorations.tsx | 11 +- src/client/views/InkingStroke.tsx | 6 +- src/client/views/MainView.tsx | 3 +- src/client/views/PinFuncs.ts | 139 +++++++++++++++++++++ .../views/collections/CollectionStackingView.tsx | 1 + .../views/collections/CollectionTimeView.tsx | 6 +- src/client/views/collections/TabDocView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 20 +-- src/client/views/nodes/AudioBox.tsx | 6 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 5 + src/client/views/nodes/ComparisonBox.tsx | 6 +- .../nodes/DataVizBox/components/Histogram.tsx | 5 +- .../nodes/DataVizBox/components/LineChart.tsx | 6 +- .../views/nodes/DataVizBox/components/PieChart.tsx | 5 +- src/client/views/nodes/DocumentView.tsx | 18 +-- src/client/views/nodes/FunctionPlotBox.tsx | 6 +- src/client/views/nodes/ImageBox.tsx | 8 +- src/client/views/nodes/LabelBox.tsx | 6 +- src/client/views/nodes/MapBox/AnimationUtility.ts | 1 - src/client/views/nodes/MapBox/MapBox.tsx | 7 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 6 +- src/client/views/nodes/PDFBox.tsx | 8 +- src/client/views/nodes/VideoBox.tsx | 6 +- src/client/views/nodes/WebBox.tsx | 6 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 6 +- src/client/views/nodes/trails/PresBox.tsx | 121 ++---------------- src/client/views/nodes/trails/PresElementBox.tsx | 3 +- src/server/server_Initialization.ts | 1 - 32 files changed, 236 insertions(+), 229 deletions(-) create mode 100644 src/client/views/PinFuncs.ts (limited to 'src/client/views/nodes/MapBox/AnimationUtility.ts') diff --git a/package-lock.json b/package-lock.json index 80aef5232..c53a3219e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -82,6 +82,7 @@ "core-js": "^3.33.3", "cors": "^2.8.5", "css-loader": "^7.0.0", + "csstype": "^3.1.3", "csv-parser": "^3.0.0", "csv-stringify": "^6.4.4", "D": "^1.0.0", diff --git a/package.json b/package.json index d826c855e..0e7955d54 100644 --- a/package.json +++ b/package.json @@ -167,6 +167,7 @@ "core-js": "^3.33.3", "cors": "^2.8.5", "css-loader": "^7.0.0", + "csstype": "^3.1.3", "csv-parser": "^3.0.0", "csv-stringify": "^6.4.4", "D": "^1.0.0", diff --git a/src/client/util/SnappingManager.ts b/src/client/util/SnappingManager.ts index 3da85191f..5cd6ecfe1 100644 --- a/src/client/util/SnappingManager.ts +++ b/src/client/util/SnappingManager.ts @@ -18,6 +18,7 @@ export class SnappingManager { @observable _horizSnapLines: number[] = []; @observable _vertSnapLines: number[] = []; @observable _exploreMode = false; + @observable _userPanned = false; private constructor() { SnappingManager._manager = this; @@ -43,6 +44,7 @@ export class SnappingManager { 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 get UserPanned() { return this.Instance._userPanned; } // 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 SetMetaKey = (down: boolean) => runInAction(() => {this.Instance._metaKey = down}); // prettier-ignore @@ -52,6 +54,7 @@ export class SnappingManager { public static SetIsResizing = (docid?:string) => runInAction(() => {this.Instance._isResizing = docid}); // 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 + public static TriggerUserPanned = () => runInAction(() => {this.Instance._userPanned = !this.Instance._userPanned}); // prettier-ignore public static userColor: string | undefined; public static userVariantColor: string | undefined; diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index bbd902a96..391c2f694 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -11,43 +11,11 @@ import { GetEffectiveAcl, inheritParentAcls } from '../../fields/util'; import { DocumentType } from '../documents/DocumentTypes'; import { DragManager } from '../util/DragManager'; import { ObservableReactComponent } from './ObservableReactComponent'; +import { PinProps } from './PinFuncs'; import { DocumentView, OpenWhere } from './nodes/DocumentView'; import { FieldViewProps, FocusViewOptions } from './nodes/FieldView'; // import { DocUtils } from '../documents/Documents'; -export interface pinDataTypes { - scrollable?: boolean; - dataviz?: number[]; - pannable?: boolean; - type_collection?: boolean; - inkable?: boolean; - filters?: boolean; - pivot?: boolean; - temporal?: boolean; - clippable?: boolean; - datarange?: boolean; - dataview?: boolean; - poslayoutview?: boolean; - dataannos?: boolean; - map?: boolean; -} - -export interface MarqueeViewBounds { - left: number; - top: number; - width: number; - height: number; -} -export interface PinProps { - audioRange?: boolean; - activeFrame?: number; - currentFrame?: number; - hidePresBox?: boolean; - pinViewport?: MarqueeViewBounds; // pin a specific viewport on a freeform view (use MarqueeView.CurViewBounds to compute if no region has been selected) - pinDocLayout?: boolean; // pin layout info (width/height/x/y) - pinAudioPlay?: boolean; // pin audio annotation - pinData?: pinDataTypes; -} /** * Shared interface among all viewBox'es (ie, react classes that render the contents of a Doc) * Many of these methods only make sense for specific viewBox'es, but they should be written to diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 3083b9be0..1e6eb1aeb 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -6,10 +6,11 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { FaUndo } from 'react-icons/fa'; import { lightOrDark, returnFalse, setupMoveUpEvents } from '../../ClientUtils'; -import { Utils, numberValue, emptyFunction } from '../../Utils'; +import { Utils, emptyFunction, numberValue } from '../../Utils'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, FieldType, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols'; +import { Id } from '../../fields/FieldSymbols'; import { InkField } from '../../fields/InkField'; import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; @@ -31,11 +32,11 @@ import { ObservableReactComponent } from './ObservableReactComponent'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { CollectionFreeFormView } from './collections/collectionFreeForm'; import { Colors } from './global/globalEnums'; +import { CollectionFreeFormDocumentView } from './nodes/CollectionFreeFormDocumentView'; import { DocumentView, OpenWhereMod } from './nodes/DocumentView'; import { ImageBox } from './nodes/ImageBox'; import { KeyValueBox } from './nodes/KeyValueBox'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; -import { Id } from '../../fields/FieldSymbols'; interface DocumentDecorationsProps { PanelWidth: number; @@ -447,7 +448,7 @@ export class DocumentDecorations extends ObservableReactComponent docView.CollectionFreeFormView?.dragStarting(false, false)); + SelectionManager.Views.forEach(docView => CollectionFreeFormDocumentView.from(docView)?.CollectionFreeFormView?.dragStarting(false, false)); }; projectDragToAspect = (e: PointerEvent, docView: DocumentView, fixedAspect: number) => { @@ -700,7 +701,7 @@ export class DocumentDecorations extends ObservableReactComponent 135; - const useRotation = !hideResizers && seldocview.Document.type !== DocumentType.EQUATION && seldocview.CollectionFreeFormDocumentView; // when do we want an object to not rotate? + const useRotation = !hideResizers && seldocview.Document.type !== DocumentType.EQUATION && CollectionFreeFormDocumentView.from(seldocview); // when do we want an object to not rotate? const rotation = SelectionManager.Views.length === 1 ? seldocview.screenToContentsTransform().inverse().RotateDeg : 0; // Radius constants @@ -771,7 +772,7 @@ export class DocumentDecorations extends ObservableReactComponent v.CollectionFreeFormDocumentView); + const freeformDoc = SelectionManager.Views.some(v => CollectionFreeFormDocumentView.from(v)); return (
() if (anchor) { anchor.backgroundColor = 'transparent'; addAsAnnotation && this.addDocument(anchor); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), inkable: true } }, this.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), inkable: true } }, this.Document); return anchor; } return this.Document; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index be13b14f5..d3dd51ac6 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -76,6 +76,7 @@ import { PresBox } from './nodes/trails'; import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; import { TopBar } from './topbar/TopBar'; +import { CollectionFreeFormView } from './collections/collectionFreeForm'; const _global = (window /* browser */ || global) /* node */ as any; const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore @@ -964,7 +965,7 @@ export class MainView extends ObservableReactComponent<{}> { } @computed get snapLines() { const dragged = DragManager.docsBeingDragged.lastElement() ?? SelectionManager.Docs.lastElement(); - const dragPar = dragged ? DocumentManager.Instance.getDocumentView(dragged)?.CollectionFreeFormView : undefined; + const dragPar = dragged ? CollectionFreeFormView.from(DocumentManager.Instance.getDocumentView(dragged)) : undefined; return !dragPar?.layoutDoc.freeform_snapLines ? null : (
diff --git a/src/client/views/PinFuncs.ts b/src/client/views/PinFuncs.ts new file mode 100644 index 000000000..3d998ecaf --- /dev/null +++ b/src/client/views/PinFuncs.ts @@ -0,0 +1,139 @@ +import { Doc, DocListCast } from '../../fields/Doc'; +import { DocData } from '../../fields/DocSymbols'; +import { Copy, Id } from '../../fields/FieldSymbols'; +import { List } from '../../fields/List'; +import { ObjectField } from '../../fields/ObjectField'; +import { NumCast, StrCast } from '../../fields/Types'; +import { SerializationHelper } from '../util/SerializationHelper'; + +export interface MarqueeViewBounds { + left: number; + top: number; + width: number; + height: number; +} +export interface pinDataTypes { + scrollable?: boolean; + dataviz?: number[]; + pannable?: boolean; + type_collection?: boolean; + inkable?: boolean; + filters?: boolean; + pivot?: boolean; + temporal?: boolean; + clippable?: boolean; + datarange?: boolean; + dataview?: boolean; + poslayoutview?: boolean; + dataannos?: boolean; + map?: boolean; +} +export interface PinProps { + audioRange?: boolean; + activeFrame?: number; + currentFrame?: number; + hidePresBox?: boolean; + pinViewport?: MarqueeViewBounds; // pin a specific viewport on a freeform view (use MarqueeView.CurViewBounds to compute if no region has been selected) + pinDocLayout?: boolean; // pin layout info (width/height/x/y) + pinAudioPlay?: boolean; // pin audio annotation + pinData?: pinDataTypes; +} + +/// copies values from the targetDoc (which is the prototype of the pinDoc) to +/// reserved fields on the pinDoc so that those values can be restored to the +/// target doc when navigating to it. +export function PinDocView(pinDocIn: Doc, pinProps: PinProps, targetDoc: Doc) { + const pinDoc = pinDocIn; + pinDoc.presentation = true; + pinDoc.config = ''; + if (pinProps.pinDocLayout) { + pinDoc.config_pinLayout = true; + pinDoc.config_x = NumCast(targetDoc.x); + pinDoc.config_y = NumCast(targetDoc.y); + pinDoc.config_rotation = NumCast(targetDoc.rotation); + pinDoc.config_width = NumCast(targetDoc.width); + pinDoc.config_height = NumCast(targetDoc.height); + } + if (pinProps.pinAudioPlay) pinDoc.presPlayAudio = true; + if (pinProps.pinData) { + pinDoc.config_pinData = + pinProps.pinData.scrollable || + pinProps.pinData.temporal || + pinProps.pinData.pannable || + pinProps.pinData.type_collection || + pinProps.pinData.clippable || + pinProps.pinData.datarange || + pinProps.pinData.dataview || + pinProps.pinData.poslayoutview || + pinProps?.activeFrame !== undefined; + const fkey = Doc.LayoutFieldKey(targetDoc); + if (pinProps.pinData.dataview) { + pinDoc.config_usePath = targetDoc[fkey + '_usePath']; + pinDoc.config_data = targetDoc[fkey] instanceof ObjectField ? (targetDoc[fkey] as ObjectField)[Copy]() : targetDoc.data; + } + if (pinProps.pinData.dataannos) { + const fieldKey = Doc.LayoutFieldKey(targetDoc); + pinDoc.config_annotations = new List(DocListCast(targetDoc[DocData][fieldKey + '_annotations']).filter(doc => !doc.layout_unrendered)); + } + if (pinProps.pinData.inkable) { + pinDoc.config_fillColor = targetDoc.fillColor; + pinDoc.config_color = targetDoc.color; + pinDoc.config_width = targetDoc._width; + pinDoc.config_height = targetDoc._height; + } + if (pinProps.pinData.scrollable) pinDoc.config_scrollTop = targetDoc._layout_scrollTop; + if (pinProps.pinData.clippable) { + const fieldKey = Doc.LayoutFieldKey(targetDoc); + pinDoc.config_clipWidth = targetDoc[fieldKey + '_clipWidth']; + } + if (pinProps.pinData.datarange) { + pinDoc.config_xRange = undefined; // targetDoc?.xrange; + pinDoc.config_yRange = undefined; // targetDoc?.yrange; + } + if (pinProps.pinData.map) { + // pinDoc.config_latitude = targetDoc?.latitude; + // pinDoc.config_longitude = targetDoc?.longitude; + pinDoc.config_map_zoom = targetDoc?.map_zoom; + pinDoc.config_map_type = targetDoc?.map_type; + // ... + } + if (pinProps.pinData.poslayoutview) + pinDoc.config_pinLayoutData = new List( + DocListCast(targetDoc[fkey] as ObjectField).map(d => + JSON.stringify({ + id: d[Id], + x: NumCast(d.x), + y: NumCast(d.y), + w: NumCast(d._width), + h: NumCast(d._height), + fill: StrCast(d._fillColor), + back: StrCast(d._backgroundColor), + data: SerializationHelper.Serialize(d.data instanceof ObjectField ? d.data[Copy]() : ''), + text: SerializationHelper.Serialize(d.text instanceof ObjectField ? d.text[Copy]() : ''), + }) + ) + ); + if (pinProps.pinData.type_collection) pinDoc.config_viewType = targetDoc._type_collection; + if (pinProps.pinData.filters) pinDoc.config_docFilters = ObjectField.MakeCopy(targetDoc.childFilters as ObjectField); + if (pinProps.pinData.pivot) pinDoc.config_pivotField = targetDoc._pivotField; + if (pinProps.pinData.pannable) { + pinDoc.config_panX = NumCast(targetDoc._freeform_panX); + pinDoc.config_panY = NumCast(targetDoc._freeform_panY); + pinDoc.config_viewScale = NumCast(targetDoc._freeform_scale, 1); + } + if (pinProps.pinData.temporal) { + pinDoc.config_clipStart = targetDoc._layout_currentTimecode; + const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], NumCast(targetDoc.config_clipStart) + 0.1); + pinDoc.config_clipEnd = NumCast(pinDoc.config_clipStart) + NumCast(targetDoc.clipEnd, duration); + } + } + if (pinProps?.pinViewport) { + // If pinWithView option set then update scale and x / y props of slide + const bounds = pinProps.pinViewport; + pinDoc.config_pinView = true; + pinDoc.config_viewScale = NumCast(targetDoc._freeform_scale, 1); + pinDoc.config_panX = bounds.left + bounds.width / 2; + pinDoc.config_panY = bounds.top + bounds.height / 2; + pinDoc.config_viewBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); + } +} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index c47fe915a..ad9960989 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -1,5 +1,6 @@ /* eslint-disable react/jsx-props-no-spreading */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +// eslint-disable-next-line import/no-extraneous-dependencies import * as CSS from 'csstype'; import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index e1d2e3c40..b3760d4af 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -3,8 +3,8 @@ import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { emptyFunction } from '../../../Utils'; import { returnFalse, returnTrue, setupMoveUpEvents } from '../../../ClientUtils'; +import { emptyFunction } from '../../../Utils'; import { Doc, Opt, StrListCast } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; @@ -17,8 +17,8 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { FieldsDropdown } from '../FieldsDropdown'; +import { PinDocView } from '../PinFuncs'; import { DocumentView } from '../nodes/DocumentView'; -import { PresBox } from '../nodes/trails'; import { CollectionSubView } from './CollectionSubView'; import './CollectionTimeView.scss'; import { ViewDefBounds, computePivotLayout, computeTimelineLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines'; @@ -55,7 +55,7 @@ export class CollectionTimeView extends CollectionSubView() { title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as any, annotationOn: this.Document, }); - PresBox.pinDocView(anchor, { pinData: { type_collection: true, pivot: true, filters: true } }, this.Document); + 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/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index e98e444ed..e7b8237a5 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -26,9 +26,9 @@ import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { UndoManager, undoable } from '../../util/UndoManager'; import { DashboardView } from '../DashboardView'; -import { PinProps } from '../DocComponent'; import { LightboxView } from '../LightboxView'; import { ObservableReactComponent } from '../ObservableReactComponent'; +import { PinProps, PinDocView } from '../PinFuncs'; import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; import { Colors } from '../global/globalEnums'; import { DocumentView, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from '../nodes/DocumentView'; @@ -426,7 +426,7 @@ export class TabDocView extends ObservableReactComponent { pinDoc.treeView_HideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], null); - if (pinProps.pinViewport) PresBox.pinDocView(pinDoc, pinProps, anchorDoc ?? doc); + if (pinProps.pinViewport) PinDocView(pinDoc, pinProps, anchorDoc ?? doc); if (!pinProps?.audioRange && duration !== undefined) { pinDoc.presentation_mediaStart = 'manual'; pinDoc.presentation_mediaStop = 'manual'; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 69cb52233..653a01a04 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -38,7 +38,6 @@ import { Transform } from '../../../util/Transform'; import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager'; import { Timeline } from '../../animationtimeline/Timeline'; import { ContextMenu } from '../../ContextMenu'; -import { PinProps } from '../../DocComponent'; import { GestureOverlay } from '../../GestureOverlay'; import { ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke'; import { LightboxView } from '../../LightboxView'; @@ -47,13 +46,13 @@ import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; import { DocumentView, OpenWhere } from '../../nodes/DocumentView'; import { FieldViewProps, FocusViewOptions } from '../../nodes/FieldView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; -import { PresBox } from '../../nodes/trails/PresBox'; +import { PinDocView, PinProps } from '../../PinFuncs'; import { StyleProp } from '../../StyleProvider'; import { CollectionSubView } from '../CollectionSubView'; import { TreeViewType } from '../CollectionTreeView'; import { CollectionFreeFormBackgroundGrid } from './CollectionFreeFormBackgroundGrid'; -import { CollectionFreeFormInfoUI } from './CollectionFreeFormInfoUI'; import { CollectionFreeFormClusters } from './CollectionFreeFormClusters'; +import { CollectionFreeFormInfoUI } from './CollectionFreeFormInfoUI'; import { computePassLayout, computePivotLayout, computeStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from './CollectionFreeFormLayoutEngines'; import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannableContents'; import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors'; @@ -85,6 +84,9 @@ export class CollectionFreeFormView extends CollectionSubView(); + public static from(dv?: DocumentView) { + return CollectionFreeFormDocumentView.from(dv)?.CollectionFreeFormView; + } _oldWheel: any; _clusters = new CollectionFreeFormClusters(this); @@ -592,7 +594,7 @@ export class CollectionFreeFormView extends CollectionSubView { - PresBox.Instance?.pauseAutoPres(); + SnappingManager.TriggerUserPanned(); this.setPan(NumCast(this.Document[this.panXFieldKey]) - e.deltaX, NumCast(this.Document[this.panYFieldKey]) - e.deltaY, 0, true); }; @@ -600,7 +602,7 @@ export class CollectionFreeFormView extends CollectionSubView { const ctrlKey = e.ctrlKey && !e.shiftKey; const shiftKey = e.shiftKey && !e.ctrlKey; - PresBox.Instance?.pauseAutoPres(); + SnappingManager.TriggerUserPanned(); this.DocumentView?.().clearViewTransition(); const [dxi, dyi] = this.screenToFreeformContentsXf.transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); const { x: dx, y: dy } = Utils.rotPt(dxi, dyi, this.ScreenToLocalBoxXf().Rotate); @@ -834,7 +836,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.Document.isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom - PresBox.Instance?.pauseAutoPres(); + SnappingManager.TriggerUserPanned(); if (this.layoutDoc._Transform || this.Document.treeView_OutlineMode === TreeViewType.outline) return; e.stopPropagation(); const docHeight = NumCast(this.Document[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight); @@ -1289,7 +1291,7 @@ export class CollectionFreeFormView extends CollectionSubView view.CollectionFreeFormView?.bringToFront(view.Document)); + SelectionManager.Views.forEach(view => CollectionFreeFormView.from(view)?.bringToFront(view.Document)); }); // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function sendToBack() { - SelectionManager.Views.forEach(view => view.CollectionFreeFormView?.bringToFront(view.Document, true)); + SelectionManager.Views.forEach(view => CollectionFreeFormView.from(view)?.bringToFront(view.Document, true)); }); // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function datavizFromSchema() { diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 9251dca6d..1f618135f 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -21,11 +21,11 @@ import { undoBatch } from '../../util/UndoManager'; import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionStackedTimeline'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { PinProps, ViewBoxAnnotatableComponent } from '../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; +import { PinDocView, PinProps } from '../PinFuncs'; import './AudioBox.scss'; import { OpenWhere } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; -import { PresBox } from './trails'; /** * AudioBox @@ -159,7 +159,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { ) || this.Document : Docs.Create.ConfigDocument({ title: '#' + timecode, _timecodeToShow: timecode, annotationOn: this.Document }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), temporal: true } }, this.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), temporal: true } }, this.Document); return anchor; }; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 7b1847ae4..9c4d748bd 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -38,6 +38,7 @@ interface freeFormProps { highlight?: boolean; transition?: string; } + export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { RenderCutoffProvider: (doc: Doc) => boolean; CollectionFreeFormView: CollectionFreeFormView; @@ -63,6 +64,9 @@ export class CollectionFreeFormDocumentView extends DocComponent (Doc.LayoutFieldKey(doc) ? [Doc.LayoutFieldKey(doc)] : []); // fields that are configured to be animatable using animation frames + public static from(dv?: DocumentView) { + return dv?._props.parent instanceof CollectionFreeFormDocumentView ? dv._props.parent : undefined; + } constructor(props: CollectionFreeFormDocumentViewProps & freeFormProps) { super(props); @@ -273,6 +277,7 @@ export class CollectionFreeFormDocumentView extends DocComponent ) : ( val.lower)).omit} // prettier-ignore DataTransition={this.DataTransition} diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index e6fd447ac..bc151f6a5 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -11,14 +11,14 @@ import { DocUtils, Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { dropActionType } from '../../util/DropActionTypes'; import { undoBatch } from '../../util/UndoManager'; -import { PinProps, ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; +import { PinProps, PinDocView } from '../PinFuncs'; import { StyleProp } from '../StyleProvider'; import './ComparisonBox.scss'; import { DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { KeyValueBox } from './KeyValueBox'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; -import { PresBox } from './trails'; @observer export class ComparisonBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { @@ -113,7 +113,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() if (anchor) { if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; /* addAsAnnotation && */ this.addDocument(anchor); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), clippable: true } }, this.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), clippable: true } }, this.Document); return anchor; } return this.Document; diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index f0ffdbdcf..79b3e9541 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -11,9 +11,8 @@ import { listSpec } from '../../../../../fields/Schema'; import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; import { Docs } from '../../../../documents/Documents'; import { undoable } from '../../../../util/UndoManager'; -import { PinProps } from '../../../DocComponent'; import { ObservableReactComponent } from '../../../ObservableReactComponent'; -import { PresBox } from '../../trails'; +import { PinProps, PinDocView } from '../../../PinFuncs'; import { scaleCreatorNumerical, yAxisCreator } from '../utils/D3Utils'; import './Chart.scss'; @@ -117,7 +116,7 @@ export class Histogram extends ObservableReactComponent { const anchor = Docs.Create.ConfigDocument({ title: 'histogram doc selection' + this._currSelected, }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this._props.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this._props.Document); return anchor; }; diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index 8105adf1e..1c3134185 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -10,12 +10,12 @@ import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; import { Docs } from '../../../../documents/Documents'; import { DocumentManager } from '../../../../util/DocumentManager'; import { undoable } from '../../../../util/UndoManager'; +import {} from '../../../DocComponent'; import { ObservableReactComponent } from '../../../ObservableReactComponent'; -import { PresBox } from '../../trails'; +import { PinProps, PinDocView } from '../../../PinFuncs'; import { DataVizBox } from '../DataVizBox'; import { createLineGenerator, drawLine, minMaxRange, scaleCreatorNumerical, xAxisCreator, xGrid, yAxisCreator, yGrid } from '../utils/D3Utils'; import './Chart.scss'; -import { PinProps } from '../../../DocComponent'; export interface DataPoint { x: number; @@ -177,7 +177,7 @@ export class LineChart extends ObservableReactComponent { // title: 'line doc selection' + (this._currSelected?.x ?? ''), }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this._props.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this._props.Document); anchor.config_dataVizSelection = this._currSelected ? new List([this._currSelected.x, this._currSelected.y]) : undefined; return anchor; }; diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index f57070f92..ffb2f528a 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -12,9 +12,8 @@ import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; import { Docs } from '../../../../documents/Documents'; import { undoable } from '../../../../util/UndoManager'; import { ObservableReactComponent } from '../../../ObservableReactComponent'; -import { PresBox } from '../../trails'; +import { PinProps, PinDocView } from '../../../PinFuncs'; import './Chart.scss'; -import { PinProps } from '../../../DocComponent'; export interface PieChartProps { Document: Doc; @@ -109,7 +108,7 @@ export class PieChart extends ObservableReactComponent { // title: 'piechart doc selection' + this._currSelected, }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this._props.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this._props.Document); return anchor; }; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 626e3d899..a603de10b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -22,7 +22,6 @@ import { AudioField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; import { DocServer } from '../../DocServer'; import { Networking } from '../../Network'; -import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { DocUtils, Docs } from '../../documents/Documents'; import { DictationManager } from '../../util/DictationManager'; @@ -46,7 +45,6 @@ import { FieldsDropdown } from '../FieldsDropdown'; import { GestureOverlay } from '../GestureOverlay'; import { LightboxView } from '../LightboxView'; import { AudioAnnoState, StyleProp } from '../StyleProvider'; -import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView'; import { DocumentContentsView, ObserverJsxParser } from './DocumentContentsView'; import { DocumentLinksButton } from './DocumentLinksButton'; import './DocumentView.scss'; @@ -108,6 +106,8 @@ export interface DocumentViewProps extends FieldViewSharedProps { dragConfig?: (data: DragManager.DocumentDragData) => void; dragStarting?: () => void; dragEnding?: () => void; + + parent?: any; } @observer export class DocumentViewInternal extends DocComponent() { @@ -314,7 +314,7 @@ export class DocumentViewInternal extends DocComponent { - const options:FocusViewOptions = { pointFocus: {X: e.clientX, Y :e.clientY}, zoomTime: browseTransitionTime}; + const options: FocusViewOptions = { pointFocus: { X: e.clientX, Y: e.clientY }, zoomTime: browseTransitionTime }; if (!focused && this._docView) { this._docView .docViewPath() @@ -645,12 +645,6 @@ export class DocumentViewInternal extends DocComponent Doc.MakeMetadataFieldTemplate(this.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' }); moreItems.push({ description: `${this.Document._chromeHidden ? 'Show' : 'Hide'} Chrome`, event: () => { this.Document._chromeHidden = !this.Document._chromeHidden; }, icon: 'project-diagram' }); // prettier-ignore - - if (Cast(Doc.GetProto(this.Document).data, listSpec(Doc))) { - moreItems.push({ description: 'Export to Google Photos Album', event: () => GooglePhotos.Export.CollectionToAlbum({ collection: this.Document }).then(console.log), icon: 'caret-square-right' }); - moreItems.push({ description: 'Tag Child Images via Google Photos', event: () => GooglePhotos.Query.TagChildImages(this.Document), icon: 'caret-square-right' }); - moreItems.push({ description: 'Write Back Link to Album', event: () => GooglePhotos.Transactions.AddTextEnrichment(this.Document), icon: 'caret-square-right' }); - } moreItems.push({ description: 'Copy ID', event: () => ClientUtils.CopyText(Doc.globalServerPath(this.Document)), icon: 'fingerprint' }); } } @@ -1079,7 +1073,7 @@ export class DocumentViewInternal extends DocComponent CollectionFreeFormDocumentView }>() { +export class DocumentView extends DocComponent() { public static ROOT_DIV = 'documentView-effectsWrapper'; public get displayName() { return 'DocumentView(' + (this.Document?.title??"") + ')'; } // prettier-ignore public ContentRef = React.createRef(); @@ -1100,7 +1094,7 @@ export class DocumentView extends DocComponent. used by LinkBox's Xanchor to find the arrowhead locations. public DocUniqueId = DocumentView.UniquifyId(LightboxView.Contains(this), this.Document[Id]); - constructor(props: DocumentViewProps & { CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView }) { + constructor(props: DocumentViewProps) { super(props); makeObservable(this); } @@ -1227,8 +1221,6 @@ export class DocumentView extends DocComponent { diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index 180c651fb..31faa7ac3 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -11,9 +11,9 @@ import { DocUtils, Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { LinkManager } from '../../util/LinkManager'; import { undoBatch } from '../../util/UndoManager'; -import { PinProps, ViewBoxAnnotatableComponent } from '../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; +import { PinProps, PinDocView } from '../PinFuncs'; import { FieldView, FieldViewProps } from './FieldView'; -import { PresBox } from './trails'; @observer export class FunctionPlotBox extends ViewBoxAnnotatableComponent() { @@ -40,7 +40,7 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent } getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), datarange: true } }, this.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), datarange: true } }, this.Document); anchor.config_xRange = new List(Array.from(this._plot.options.xAxis.domain)); anchor.config_yRange = new List(Array.from(this._plot.options.yAxis.domain)); if (addAsAnnotation) this.addDocument(anchor); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 6d3d4be06..8bd5ab03d 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -21,18 +21,18 @@ import { Networking } from '../../Network'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; -import { ContextMenu } from '../ContextMenu'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; +import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { PinProps, ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { OverlayView } from '../OverlayView'; import { AnchorMenu } from '../pdf/AnchorMenu'; +import { PinDocView, PinProps } from '../PinFuncs'; import { StyleProp } from '../StyleProvider'; import { OpenWhere } from './DocumentView'; import { FieldView, FieldViewProps, FocusViewOptions } from './FieldView'; import './ImageBox.scss'; -import { PresBox } from './trails'; export class ImageEditorData { // eslint-disable-next-line no-use-before-define @@ -102,7 +102,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() impl if (anchor) { if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; addAsAnnotation && this.addDocument(anchor); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !visibleAnchor } }, this.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !visibleAnchor } }, this.Document); return anchor; } return this.Document; diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 9df928581..89270652c 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -10,12 +10,12 @@ import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { PinProps, ViewBoxBaseComponent } from '../DocComponent'; +import { ViewBoxBaseComponent } from '../DocComponent'; +import { PinProps, PinDocView } from '../PinFuncs'; import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import BigText from './LabelBigText'; import './LabelBox.scss'; -import { PresBox } from './trails'; @observer export class LabelBox extends ViewBoxBaseComponent() { @@ -96,7 +96,7 @@ export class LabelBox extends ViewBoxBaseComponent() { if (anchor) { if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; // addAsAnnotation && this.addDocument(anchor); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}) } }, this.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}) } }, this.Document); return anchor; } return anchor; diff --git a/src/client/views/nodes/MapBox/AnimationUtility.ts b/src/client/views/nodes/MapBox/AnimationUtility.ts index 3a2679ecf..f4bae66bb 100644 --- a/src/client/views/nodes/MapBox/AnimationUtility.ts +++ b/src/client/views/nodes/MapBox/AnimationUtility.ts @@ -1,7 +1,6 @@ import * as turf from '@turf/turf'; import { Position } from '@turf/turf'; import * as d3 from 'd3'; -// eslint-disable-next-line import/no-extraneous-dependencies import { Feature, GeoJsonProperties, Geometry } from 'geojson'; import mapboxgl, { MercatorCoordinate } from 'mapbox-gl'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 6495cf440..60dad314f 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -6,7 +6,6 @@ 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'; -// eslint-disable-next-line import/no-extraneous-dependencies import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, Position } from 'geojson'; import mapboxgl, { LngLatBoundsLike, MapLayerMouseEvent } from 'mapbox-gl'; import { IReactionDisposer, ObservableMap, action, autorun, computed, makeObservable, observable, runInAction } from 'mobx'; @@ -25,14 +24,14 @@ import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { LinkManager } from '../../../util/LinkManager'; import { UndoManager, undoable } from '../../../util/UndoManager'; -import { PinProps, ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent'; +import { PinProps, PinDocView } from '../../PinFuncs'; import { SidebarAnnos } from '../../SidebarAnnos'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { Colors } from '../../global/globalEnums'; import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps, FocusViewOptions } from '../FieldView'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; -import { PresBox } from '../trails'; import { fastSpeedIcon, mediumSpeedIcon, slowSpeedIcon } from './AnimationSpeedIcons'; import { AnimationSpeed, AnimationStatus, AnimationUtility } from './AnimationUtility'; import { MapAnchorMenu } from './MapAnchorMenu'; @@ -462,7 +461,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem if (anchor) { if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; addAsAnnotation && this.addDocument(anchor); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.Document); return anchor; } return this.Document; diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index c19528af6..d899fcb9a 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -17,7 +17,8 @@ import { DragManager } from '../../../util/DragManager'; import { LinkManager } from '../../../util/LinkManager'; import { Transform } from '../../../util/Transform'; import { UndoManager, undoable } from '../../../util/UndoManager'; -import { PinProps, ViewBoxAnnotatableComponent } from '../../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../../DocComponent'; +import { PinProps, PinDocView } from '../../PinFuncs'; import { SidebarAnnos } from '../../SidebarAnnos'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { Colors } from '../../global/globalEnums'; @@ -26,7 +27,6 @@ import { FieldView, FieldViewProps, FocusViewOptions } from '../FieldView'; import { MapAnchorMenu } from '../MapBox/MapAnchorMenu'; import '../MapBox/MapBox.scss'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; -import { PresBox } from '../trails'; /** * MapBox architecture: @@ -487,7 +487,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent if (anchor) { if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; addAsAnnotation && this.addDocument(anchor); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.Document); return anchor; } return this.Document; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 4d5013437..fbf5e018c 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -26,16 +26,16 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm'; import { CollectionStackingView } from '../collections/CollectionStackingView'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { PinProps, ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { Colors } from '../global/globalEnums'; -import { CreateImage } from './WebBoxRenderer'; import { PDFViewer } from '../pdf/PDFViewer'; +import { PinDocView, PinProps } from '../PinFuncs'; import { SidebarAnnos } from '../SidebarAnnos'; import { DocumentView, OpenWhere } from './DocumentView'; import { FieldView, FieldViewProps, FocusViewOptions } from './FieldView'; import { ImageBox } from './ImageBox'; import './PDFBox.scss'; -import { PresBox } from './trails'; +import { CreateImage } from './WebBoxRenderer'; @observer export class PDFBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { @@ -265,7 +265,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent() implem }); const visibleAnchor = this._pdfViewer?._getAnchor?.(this._pdfViewer.savedAnnotations(), true); const anchor = visibleAnchor ?? docAnchor(); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true, pannable: true } }, this.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true, pannable: true } }, this.Document); anchor.text = ele?.textContent ?? ''; anchor.text_html = ele?.innerHTML; addAsAnnotation && this.addDocument(anchor); diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index b8ec0081a..13ee3250e 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -25,14 +25,14 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm/Collec import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionStackedTimeline'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { PinProps, ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { AnchorMenu } from '../pdf/AnchorMenu'; +import { PinDocView, PinProps } from '../PinFuncs'; import { StyleProp } from '../StyleProvider'; import { DocumentView } from './DocumentView'; import { FieldView, FieldViewProps, FocusViewOptions } from './FieldView'; import { RecordingBox } from './RecordingBox'; -import { PresBox } from './trails'; import './VideoBox.scss'; /** @@ -357,7 +357,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() impl addAsAnnotation && marquee ? CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this.annotationKey, timecode || undefined, undefined, marquee, addAsAnnotation) || this.Document : Docs.Create.ConfigDocument({ title: '#' + timecode, _timecodeToShow: timecode, annotationOn: this.Document }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), temporal: true, pannable: true } }, this.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), temporal: true, pannable: true } }, this.Document); return anchor; }; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 725c5bab4..dfe237a86 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -27,19 +27,19 @@ import { MarqueeOptionsMenu } from '../collections/collectionFreeForm'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { PinProps, ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { Colors } from '../global/globalEnums'; import { LightboxView } from '../LightboxView'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { AnchorMenu } from '../pdf/AnchorMenu'; import { Annotation } from '../pdf/Annotation'; import { GPTPopup } from '../pdf/GPTPopup/GPTPopup'; +import { PinDocView, PinProps } from '../PinFuncs'; import { SidebarAnnos } from '../SidebarAnnos'; import { StyleProp } from '../StyleProvider'; import { DocumentView, OpenWhere } from './DocumentView'; import { FieldView, FieldViewProps, FocusViewOptions } from './FieldView'; import { LinkInfo } from './LinkDocPreview'; -import { PresBox } from './trails'; import './WebBox.scss'; const { CreateImage } = require('./WebBoxRenderer'); @@ -350,7 +350,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() implem y: NumCast(this.layoutDoc._layout_scrollTop), annotationOn: this.Document, }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: !!pinProps?.pinData, pannable: true } }, this.Document); + PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: !!pinProps?.pinData, pannable: true } }, this.Document); anchor.text = ele?.textContent ?? ''; anchor.text_html = ele?.innerHTML ?? this._selectionText; addAsAnnotation && this.addDocumentWrapper(anchor); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index d659d5e3c..9bcf5027f 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -45,18 +45,18 @@ import { CollectionStackingView } from '../../collections/CollectionStackingView import { CollectionTreeView } from '../../collections/CollectionTreeView'; import { ContextMenu } from '../../ContextMenu'; import { ContextMenuProps } from '../../ContextMenuItem'; -import { PinProps, ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; import { LightboxView } from '../../LightboxView'; import { AnchorMenu } from '../../pdf/AnchorMenu'; import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup'; +import { PinDocView, PinProps } from '../../PinFuncs'; import { SidebarAnnos } from '../../SidebarAnnos'; import { styleFromLayoutString, StyleProp } from '../../StyleProvider'; import { mediaState } from '../AudioBox'; import { DocumentView, DocumentViewInternal, OpenWhere } from '../DocumentView'; import { FieldView, FieldViewProps, FocusViewOptions } from '../FieldView'; import { LinkInfo } from '../LinkDocPreview'; -import { PresBox } from '../trails'; import { DashDocCommentView } from './DashDocCommentView'; import { DashDocView } from './DashDocView'; import { DashFieldView } from './DashFieldView'; @@ -252,7 +252,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent() { @@ -144,6 +145,10 @@ export class PresBox extends ViewBoxBaseComponent() { } componentDidMount() { + this._disposers.pause = reaction( + () => SnappingManager.UserPanned, + () => this.pauseAutoPres() + ); this._disposers.keyboard = reaction( () => this.selectedDoc, selected => { @@ -618,114 +623,6 @@ export class PresBox extends ViewBoxBaseComponent() { return undefined; } - /// copies values from the targetDoc (which is the prototype of the pinDoc) to - /// reserved fields on the pinDoc so that those values can be restored to the - /// target doc when navigating to it. - @action - static pinDocView(pinDocIn: Doc, pinProps: PinProps, targetDoc: Doc) { - const pinDoc = pinDocIn; - pinDoc.presentation = true; - pinDoc.config = ''; - if (pinProps.pinDocLayout) { - pinDoc.config_pinLayout = true; - pinDoc.config_x = NumCast(targetDoc.x); - pinDoc.config_y = NumCast(targetDoc.y); - pinDoc.config_rotation = NumCast(targetDoc.rotation); - pinDoc.config_width = NumCast(targetDoc.width); - pinDoc.config_height = NumCast(targetDoc.height); - } - if (pinProps.pinAudioPlay) pinDoc.presPlayAudio = true; - if (pinProps.pinData) { - pinDoc.config_pinData = - pinProps.pinData.scrollable || - pinProps.pinData.temporal || - pinProps.pinData.pannable || - pinProps.pinData.type_collection || - pinProps.pinData.clippable || - pinProps.pinData.datarange || - pinProps.pinData.dataview || - pinProps.pinData.poslayoutview || - pinProps?.activeFrame !== undefined; - const fkey = Doc.LayoutFieldKey(targetDoc); - if (pinProps.pinData.dataview) { - pinDoc.config_usePath = targetDoc[fkey + '_usePath']; - pinDoc.config_data = targetDoc[fkey] instanceof ObjectField ? (targetDoc[fkey] as ObjectField)[Copy]() : targetDoc.data; - } - if (pinProps.pinData.dataannos) { - const fieldKey = Doc.LayoutFieldKey(targetDoc); - pinDoc.config_annotations = new List(DocListCast(targetDoc[DocData][fieldKey + '_annotations']).filter(doc => !doc.layout_unrendered)); - } - if (pinProps.pinData.inkable) { - pinDoc.config_fillColor = targetDoc.fillColor; - pinDoc.config_color = targetDoc.color; - pinDoc.config_width = targetDoc._width; - pinDoc.config_height = targetDoc._height; - } - if (pinProps.pinData.scrollable) pinDoc.config_scrollTop = targetDoc._layout_scrollTop; - if (pinProps.pinData.clippable) { - const fieldKey = Doc.LayoutFieldKey(targetDoc); - pinDoc.config_clipWidth = targetDoc[fieldKey + '_clipWidth']; - } - if (pinProps.pinData.datarange) { - pinDoc.config_xRange = undefined; // targetDoc?.xrange; - pinDoc.config_yRange = undefined; // targetDoc?.yrange; - } - if (pinProps.pinData.map) { - // pinDoc.config_latitude = targetDoc?.latitude; - // pinDoc.config_longitude = targetDoc?.longitude; - pinDoc.config_map_zoom = targetDoc?.map_zoom; - pinDoc.config_map_type = targetDoc?.map_type; - // ... - } - if (pinProps.pinData.poslayoutview) - pinDoc.config_pinLayoutData = new List( - DocListCast(targetDoc[fkey] as ObjectField).map(d => - JSON.stringify({ - id: d[Id], - x: NumCast(d.x), - y: NumCast(d.y), - w: NumCast(d._width), - h: NumCast(d._height), - fill: StrCast(d._fillColor), - back: StrCast(d._backgroundColor), - data: SerializationHelper.Serialize(d.data instanceof ObjectField ? d.data[Copy]() : ''), - text: SerializationHelper.Serialize(d.text instanceof ObjectField ? d.text[Copy]() : ''), - }) - ) - ); - if (pinProps.pinData.type_collection) pinDoc.config_viewType = targetDoc._type_collection; - if (pinProps.pinData.filters) pinDoc.config_docFilters = ObjectField.MakeCopy(targetDoc.childFilters as ObjectField); - if (pinProps.pinData.pivot) pinDoc.config_pivotField = targetDoc._pivotField; - if (pinProps.pinData.pannable) { - pinDoc.config_panX = NumCast(targetDoc._freeform_panX); - pinDoc.config_panY = NumCast(targetDoc._freeform_panY); - pinDoc.config_viewScale = NumCast(targetDoc._freeform_scale, 1); - } - if (pinProps.pinData.temporal) { - pinDoc.config_clipStart = targetDoc._layout_currentTimecode; - const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], NumCast(targetDoc.config_clipStart) + 0.1); - pinDoc.config_clipEnd = NumCast(pinDoc.config_clipStart) + NumCast(targetDoc.clipEnd, duration); - } - } - if (pinProps?.pinViewport) { - // If pinWithView option set then update scale and x / y props of slide - const bounds = pinProps.pinViewport; - pinDoc.config_pinView = true; - pinDoc.config_viewScale = NumCast(targetDoc._freeform_scale, 1); - pinDoc.config_panX = bounds.left + bounds.width / 2; - pinDoc.config_panY = bounds.top + bounds.height / 2; - pinDoc.config_viewBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); - } - } - - @action - static reversePin(pinDoc: Doc, targetDoc: Doc) { - // const fkey = Doc.LayoutFieldKey(targetDoc); - pinDoc.config_data = targetDoc.data; - - console.log(pinDoc.presData); - } - /** * This method makes sure that cursor navigates to the element that * has the option open and last in the group. diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 5fa32ad12..cf78a45b7 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -22,6 +22,7 @@ import { TreeView } from '../../collections/TreeView'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; +import { PinDocView } from '../../PinFuncs'; import { StyleProp } from '../../StyleProvider'; import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; @@ -335,7 +336,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { updateCapturedViewContents = undoable( action((presTargetDoc: Doc, activeItem: Doc) => { const target = DocCast(presTargetDoc.annotationOn) ?? presTargetDoc; - PresBox.pinDocView(activeItem, { pinData: PresBox.pinDataTypes(target) }, target); + PinDocView(activeItem, { pinData: PresBox.pinDataTypes(target) }, target); }), 'updated captured view contents' ); diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index 5e6c855c9..9183688c6 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -12,7 +12,6 @@ import * as passport from 'passport'; import * as request from 'request'; import * as webpack from 'webpack'; import * as wdm from 'webpack-dev-middleware'; -// eslint-disable-next-line import/no-extraneous-dependencies import * as whm from 'webpack-hot-middleware'; import * as zlib from 'zlib'; import * as config from '../../webpack.config'; -- cgit v1.2.3-70-g09d2