From abab63f89344e5bbbf0731e81e3ab7ddb0942664 Mon Sep 17 00:00:00 2001 From: ljungster Date: Tue, 15 Feb 2022 16:35:47 -0500 Subject: added commits --- src/client/views/nodes/trails/PresElementBox.tsx | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/client/views/nodes/trails/PresElementBox.tsx') diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 238d025dc..b30e8cc13 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -169,6 +169,7 @@ export class PresElementBox extends ViewBoxBaseComponent { const miniView: boolean = this.toolbarWidth <= 100; const activeItem = this.rootDoc; @@ -291,6 +292,7 @@ export class PresElementBox extends ViewBoxBaseComponent Date: Thu, 21 Jul 2022 13:36:27 -0400 Subject: fixed dragging preselements by updating dragManger pointerup --- src/client/util/DragManager.ts | 323 ++++++++++++----------- src/client/views/nodes/trails/PresElementBox.tsx | 6 +- 2 files changed, 166 insertions(+), 163 deletions(-) (limited to 'src/client/views/nodes/trails/PresElementBox.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 09b463c2f..4338072df 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,41 +1,35 @@ -import { action } from "mobx"; -import { DateField } from "../../fields/DateField"; -import { Doc, Field, Opt } from "../../fields/Doc"; -import { List } from "../../fields/List"; -import { PrefetchProxy } from "../../fields/Proxy"; -import { listSpec } from "../../fields/Schema"; -import { SchemaHeaderField } from "../../fields/SchemaHeaderField"; -import { ScriptField } from "../../fields/ScriptField"; -import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../fields/Types"; -import { emptyFunction, Utils } from "../../Utils"; -import { Docs, DocUtils } from "../documents/Documents"; -import * as globalCssVariables from "../views/global/globalCssVariables.scss"; -import { DocumentView } from "../views/nodes/DocumentView"; -import { SnappingManager } from "./SnappingManager"; -import { UndoManager } from "./UndoManager"; - -export type dropActionType = "alias" | "copy" | "move" | "same" | "proto" | "none" | undefined; // undefined = move, "same" = move but don't call removeDropProperties +import { action } from 'mobx'; +import { DateField } from '../../fields/DateField'; +import { Doc, Field, Opt } from '../../fields/Doc'; +import { List } from '../../fields/List'; +import { PrefetchProxy } from '../../fields/Proxy'; +import { listSpec } from '../../fields/Schema'; +import { SchemaHeaderField } from '../../fields/SchemaHeaderField'; +import { ScriptField } from '../../fields/ScriptField'; +import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../fields/Types'; +import { emptyFunction, Utils } from '../../Utils'; +import { Docs, DocUtils } from '../documents/Documents'; +import * as globalCssVariables from '../views/global/globalCssVariables.scss'; +import { DocumentView } from '../views/nodes/DocumentView'; +import { SnappingManager } from './SnappingManager'; +import { UndoManager } from './UndoManager'; + +export type dropActionType = 'alias' | 'copy' | 'move' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call removeDropProperties /** * Initialize drag - * @param _reference: The HTMLElement that is being dragged + * @param _reference: The HTMLElement that is being dragged * @param docFunc: The Dash document being moved * @param moveFunc: The function called when the document is moved * @param dropAction: What to do with the document when it is dropped * @param dragStarted: Method to call when the drag is started */ -export function SetupDrag( - _reference: React.RefObject, - docFunc: () => Doc | Promise | undefined, - moveFunc?: DragManager.MoveFunction, - dropAction?: dropActionType, - dragStarted?: () => void -) { +export function SetupDrag(_reference: React.RefObject, docFunc: () => Doc | Promise | undefined, moveFunc?: DragManager.MoveFunction, dropAction?: dropActionType, dragStarted?: () => void) { const onRowMove = async (e: PointerEvent) => { e.stopPropagation(); e.preventDefault(); - document.removeEventListener("pointermove", onRowMove); + document.removeEventListener('pointermove', onRowMove); document.removeEventListener('pointerup', onRowUp); const doc = await docFunc(); if (doc) { @@ -47,7 +41,7 @@ export function SetupDrag( } }; const onRowUp = (): void => { - document.removeEventListener("pointermove", onRowMove); + document.removeEventListener('pointermove', onRowMove); document.removeEventListener('pointerup', onRowUp); }; const onItemDown = async (e: React.PointerEvent) => { @@ -58,8 +52,8 @@ export function SetupDrag( const dragDoc = await docFunc(); dragDoc && DragManager.StartWindowDrag?.(e, [dragDoc]); } else { - document.addEventListener("pointermove", onRowMove); - document.addEventListener("pointerup", onRowUp); + document.addEventListener('pointermove', onRowMove); + document.addEventListener('pointerup', onRowUp); } } }; @@ -69,15 +63,19 @@ export function SetupDrag( export namespace DragManager { let dragDiv: HTMLDivElement; let dragLabel: HTMLDivElement; - export let StartWindowDrag: Opt<((e: { pageX: number, pageY: number }, dragDocs: Doc[], finishDrag?: (aborted: boolean) => void) => void)>; + export let StartWindowDrag: Opt<(e: { pageX: number; pageY: number }, dragDocs: Doc[], finishDrag?: (aborted: boolean) => void) => void>; export let CompleteWindowDrag: Opt<(aborted: boolean) => void>; - export function GetRaiseWhenDragged() { return BoolCast(Doc.UserDoc()._raiseWhenDragged); } - export function SetRaiseWhenDragged(val:boolean) { Doc.UserDoc()._raiseWhenDragged = val } + export function GetRaiseWhenDragged() { + return BoolCast(Doc.UserDoc()._raiseWhenDragged); + } + export function SetRaiseWhenDragged(val: boolean) { + Doc.UserDoc()._raiseWhenDragged = val; + } export function Root() { - const root = document.getElementById("root"); + const root = document.getElementById('root'); if (!root) { - throw new Error("No root element found"); + throw new Error('No root element found'); } return root; } @@ -85,27 +83,20 @@ export namespace DragManager { export type MoveFunction = (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; export type RemoveFunction = (document: Doc | Doc[]) => boolean; - export interface DragDropDisposer { (): void; } + export interface DragDropDisposer { + (): void; + } export interface DragOptions { dragComplete?: (e: DragCompleteEvent) => void; // function to invoke when drag has completed - hideSource?: boolean; // hide source document during drag - offsetX?: number; // offset of top left of source drag visual from cursor + hideSource?: boolean; // hide source document during drag + offsetX?: number; // offset of top left of source drag visual from cursor offsetY?: number; noAutoscroll?: boolean; } // event called when the drag operation results in a drop action export class DropEvent { - constructor( - readonly x: number, - readonly y: number, - readonly complete: DragCompleteEvent, - readonly shiftKey: boolean, - readonly altKey: boolean, - readonly metaKey: boolean, - readonly ctrlKey: boolean, - readonly embedKey: boolean, - ) { } + constructor(readonly x: number, readonly y: number, readonly complete: DragCompleteEvent, readonly shiftKey: boolean, readonly altKey: boolean, readonly metaKey: boolean, readonly ctrlKey: boolean, readonly embedKey: boolean) {} } // event called when the drag operation has completed (aborted or completed a drop) -- this will be after any drop event has been generated @@ -137,20 +128,22 @@ export namespace DragManager { treeViewDoc?: Doc; offset: number[]; canEmbed?: boolean; - userDropAction: dropActionType; // the user requested drop action -- this will be honored as specified by modifier keys - defaultDropAction?: dropActionType; // an optionally specified default drop action when there is no user drop actionl - this will be honored if there is no user drop action - dropAction: dropActionType; // a drop action request by the initiating code. the actual drop action may be different -- eg, if the request is 'alias', but the document is dropped within the same collection, the drop action will be switched to 'move' + userDropAction: dropActionType; // the user requested drop action -- this will be honored as specified by modifier keys + defaultDropAction?: dropActionType; // an optionally specified default drop action when there is no user drop actionl - this will be honored if there is no user drop action + dropAction: dropActionType; // a drop action request by the initiating code. the actual drop action may be different -- eg, if the request is 'alias', but the document is dropped within the same collection, the drop action will be switched to 'move' removeDropProperties?: string[]; moveDocument?: MoveFunction; removeDocument?: RemoveFunction; isDocDecorationMove?: boolean; // Flags that Document decorations are used to drag document which allows suppression of onDragStart scripts } export class LinkDragData { - constructor(dragView: DocumentView, linkSourceGetAnchor: () => Doc,) { + constructor(dragView: DocumentView, linkSourceGetAnchor: () => Doc) { this.linkDragView = dragView; this.linkSourceGetAnchor = linkSourceGetAnchor; } - get dragDocument() { return this.linkDragView.props.Document; } + get dragDocument() { + return this.linkDragView.props.Document; + } linkSourceGetAnchor: () => Doc; linkSourceDoc?: Doc; linkDragView: DocumentView; @@ -177,43 +170,29 @@ export namespace DragManager { userDropAction: dropActionType; } - export function MakeDropTarget( - element: HTMLElement, - dropFunc: (e: Event, de: DropEvent) => void, - doc?: Doc, - preDropFunc?: (e: Event, de: DropEvent, targetAction: dropActionType) => void, - ): DragDropDisposer { - if ("canDrop" in element.dataset) { - throw new Error( - "Element is already droppable, can't make it droppable again" - ); + export function MakeDropTarget(element: HTMLElement, dropFunc: (e: Event, de: DropEvent) => void, doc?: Doc, preDropFunc?: (e: Event, de: DropEvent, targetAction: dropActionType) => void): DragDropDisposer { + if ('canDrop' in element.dataset) { + throw new Error("Element is already droppable, can't make it droppable again"); } - element.dataset.canDrop = "true"; + element.dataset.canDrop = 'true'; const handler = (e: Event) => dropFunc(e, (e as CustomEvent).detail); const preDropHandler = (e: Event) => { const de = (e as CustomEvent).detail; preDropFunc?.(e, de, StrCast(doc?.targetDropAction) as dropActionType); }; - element.addEventListener("dashOnDrop", handler); - doc && element.addEventListener("dashPreDrop", preDropHandler); + element.addEventListener('dashOnDrop', handler); + doc && element.addEventListener('dashPreDrop', preDropHandler); return () => { - element.removeEventListener("dashOnDrop", handler); - doc && element.removeEventListener("dashPreDrop", preDropHandler); + element.removeEventListener('dashOnDrop', handler); + doc && element.removeEventListener('dashPreDrop', preDropHandler); delete element.dataset.canDrop; }; } // drag a document and drop it (or make an alias/copy on drop) - export function StartDocumentDrag( - eles: HTMLElement[], - dragData: DocumentDragData, - downX: number, - downY: number, - options?: DragOptions, - dropEvent?: () => any - ) { + export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions, dropEvent?: () => any) { const addAudioTag = (dropDoc: any) => { - dropDoc && !dropDoc.creationDate && (dropDoc.creationDate = new DateField); + dropDoc && !dropDoc.creationDate && (dropDoc.creationDate = new DateField()); dropDoc instanceof Doc && DocUtils.MakeLinkToActiveAudio(() => dropDoc); return dropDoc; }; @@ -222,19 +201,27 @@ export namespace DragManager { dropEvent?.(); // glr: optional additional function to be called - in this case with presentation trails if (docDragData && !docDragData.droppedDocuments.length) { docDragData.dropAction = dragData.userDropAction || dragData.dropAction; - docDragData.droppedDocuments = - await Promise.all(dragData.draggedDocuments.map(async d => - !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? - addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) : - docDragData.dropAction === "alias" ? Doc.MakeAlias(d) : - docDragData.dropAction === "proto" ? Doc.GetProto(d) : - docDragData.dropAction === "copy" ? - (await Doc.MakeClone(d)).clone : d)); - !["same", "proto"].includes(docDragData.dropAction as any) && docDragData.droppedDocuments.forEach((drop: Doc, i: number) => { - const dragProps = Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), []); - const remProps = (dragData?.removeDropProperties || []).concat(Array.from(dragProps)); - remProps.map(prop => drop[prop] = undefined); - }); + docDragData.droppedDocuments = await Promise.all( + dragData.draggedDocuments.map(async d => + !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) + ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) + : docDragData.dropAction === 'alias' + ? Doc.MakeAlias(d) + : docDragData.dropAction === 'proto' + ? Doc.GetProto(d) + : docDragData.dropAction === 'copy' + ? ( + await Doc.MakeClone(d) + ).clone + : d + ) + ); + !['same', 'proto'].includes(docDragData.dropAction as any) && + docDragData.droppedDocuments.forEach((drop: Doc, i: number) => { + const dragProps = Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec('string'), []); + const remProps = (dragData?.removeDropProperties || []).concat(Array.from(dragProps)); + remProps.map(prop => (drop[prop] = undefined)); + }); } return e; }; @@ -243,23 +230,22 @@ export namespace DragManager { return true; } - // drag a button template and drop a new button - export function - StartButtonDrag(eles: HTMLElement[], script: string, title: string, vars: { [name: string]: Field }, params: string[], initialize: (button: Doc) => void, downX: number, downY: number, options?: DragOptions) { + // drag a button template and drop a new button + export function StartButtonDrag(eles: HTMLElement[], script: string, title: string, vars: { [name: string]: Field }, params: string[], initialize: (button: Doc) => void, downX: number, downY: number, options?: DragOptions) { const finishDrag = (e: DragCompleteEvent) => { const bd = Docs.Create.ButtonDocument({ toolTip: title, z: 1, _width: 150, _height: 50, title, onClick: ScriptField.MakeScript(script) }); params.map(p => Object.keys(vars).indexOf(p) !== -1 && (Doc.GetProto(bd)[p] = new PrefetchProxy(vars[p] as Doc))); // copy all "captured" arguments into document parameterfields initialize?.(bd); - Doc.GetProto(bd)["onClick-paramFieldKeys"] = new List(params); + Doc.GetProto(bd)['onClick-paramFieldKeys'] = new List(params); e.docDragData && (e.docDragData.droppedDocuments = [bd]); return e; }; options = options ?? {}; - options.noAutoscroll = true; // these buttons are being dragged on the overlay layer, so scrollin the underlay is not appropriate + options.noAutoscroll = true; // these buttons are being dragged on the overlay layer, so scrollin the underlay is not appropriate StartDrag(eles, new DragManager.DocumentDragData([]), downX, downY, options, finishDrag); } - // drag&drop the pdf annotation anchor which will create a text note on drop via a dropCompleted() DragOption + // drag&drop the pdf annotation anchor which will create a text note on drop via a dropCompleted() DragOption export function StartAnchorAnnoDrag(eles: HTMLElement[], dragData: AnchorAnnoDragData, downX: number, downY: number, options?: DragOptions) { StartDrag(eles, dragData, downX, downY, options); } @@ -286,8 +272,8 @@ export namespace DragManager { let near = dragPt; const intersect = (x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, dragx: number, dragy: number) => { if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) return undefined; // Check if none of the lines are of length 0 - const denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)); - if (denominator === 0) return undefined; // Lines are parallel + const denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); + if (denominator === 0) return undefined; // Lines are parallel const ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator; // let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator; @@ -315,14 +301,14 @@ export namespace DragManager { }); return { x: near[0], y: near[1] }; } - // snap to the active snap lines - if oneAxis is set (eg, for maintaining aspect ratios), then it only snaps to the nearest horizontal/vertical line + // snap to the active snap lines - if oneAxis is set (eg, for maintaining aspect ratios), then it only snaps to the nearest horizontal/vertical line export function snapDrag(e: PointerEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number) { const snapThreshold = Utils.SNAP_THRESHOLD; const snapVal = (pts: number[], drag: number, snapLines: number[]) => { if (snapLines.length) { - const offs = [pts[0], (pts[0] - pts[1]) / 2, -pts[1]]; // offsets from drag pt + const offs = [pts[0], (pts[0] - pts[1]) / 2, -pts[1]]; // offsets from drag pt const rangePts = [drag - offs[0], drag - offs[1], drag - offs[2]]; // left, mid, right or top, mid, bottom pts to try to snap to snaplines - const closestPts = rangePts.map(pt => snapLines.reduce((nearest, curr) => Math.abs(nearest - pt) > Math.abs(curr - pt) ? curr : nearest)); + const closestPts = rangePts.map(pt => snapLines.reduce((nearest, curr) => (Math.abs(nearest - pt) > Math.abs(curr - pt) ? curr : nearest))); const closestDists = rangePts.map((pt, i) => Math.abs(pt - closestPts[i])); const minIndex = closestDists[0] < closestDists[1] && closestDists[0] < closestDists[2] ? 0 : closestDists[1] < closestDists[2] ? 1 : 2; return closestDists[minIndex] < snapThreshold ? closestPts[minIndex] + offs[minIndex] : drag; @@ -331,55 +317,61 @@ export namespace DragManager { }; return { x: snapVal([xFromLeft, xFromRight], e.pageX, SnappingManager.vertSnapLines()), - y: snapVal([yFromTop, yFromBottom], e.pageY, SnappingManager.horizSnapLines()) + y: snapVal([yFromTop, yFromBottom], e.pageY, SnappingManager.horizSnapLines()), }; } export let docsBeingDragged: Doc[] = []; export let CanEmbed = false; export let DocDragData: DocumentDragData | undefined; export function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) { - if (dragData.dropAction === "none") return; + if (dragData.dropAction === 'none') return; DocDragData = dragData instanceof DocumentDragData ? dragData : undefined; - const batch = UndoManager.StartBatch("dragging"); + const batch = UndoManager.StartBatch('dragging'); eles = eles.filter(e => e); CanEmbed = dragData.canEmbed || false; if (!dragDiv) { - dragDiv = document.createElement("div"); - dragDiv.className = "dragManager-dragDiv"; - dragDiv.style.pointerEvents = "none"; - dragLabel = document.createElement("div"); - dragLabel.className = "dragManager-dragLabel"; - dragLabel.style.zIndex = "100001"; - dragLabel.style.fontSize = "10px"; - dragLabel.style.position = "absolute"; - dragLabel.innerText = "drag titlebar to embed on drop"; // bcz: need to move this to a status bar + dragDiv = document.createElement('div'); + dragDiv.className = 'dragManager-dragDiv'; + dragDiv.style.pointerEvents = 'none'; + dragLabel = document.createElement('div'); + dragLabel.className = 'dragManager-dragLabel'; + dragLabel.style.zIndex = '100001'; + dragLabel.style.fontSize = '10px'; + dragLabel.style.position = 'absolute'; + dragLabel.innerText = 'drag titlebar to embed on drop'; // bcz: need to move this to a status bar dragDiv.appendChild(dragLabel); DragManager.Root().appendChild(dragDiv); } - Object.assign(dragDiv.style, { width: "", height: "", overflow: "" }); + Object.assign(dragDiv.style, { width: '', height: '', overflow: '' }); dragDiv.hidden = false; - const scaleXs: number[] = [], scaleYs: number[] = [], xs: number[] = [], ys: number[] = []; + const scaleXs: number[] = [], + scaleYs: number[] = [], + xs: number[] = [], + ys: number[] = []; docsBeingDragged = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof AnchorAnnoDragData ? [dragData.dragDocument] : []; const elesCont = { - left: Number.MAX_SAFE_INTEGER, right: Number.MIN_SAFE_INTEGER, - top: Number.MAX_SAFE_INTEGER, bottom: Number.MIN_SAFE_INTEGER + left: Number.MAX_SAFE_INTEGER, + right: Number.MIN_SAFE_INTEGER, + top: Number.MAX_SAFE_INTEGER, + bottom: Number.MIN_SAFE_INTEGER, }; const dragElements = eles.map(ele => { if (!ele.parentNode) dragDiv.appendChild(ele); - const dragElement = ele.parentNode === dragDiv ? ele : ele.cloneNode(true) as HTMLElement; + const dragElement = ele.parentNode === dragDiv ? ele : (ele.cloneNode(true) as HTMLElement); const children = Array.from(dragElement.children); - while (children.length) { // need to replace all the maker node reference ids with new unique ids. otherwise, the clone nodes will reference the original nodes which are all hidden during the drag + while (children.length) { + // need to replace all the maker node reference ids with new unique ids. otherwise, the clone nodes will reference the original nodes which are all hidden during the drag const next = children.pop(); next && children.push(...Array.from(next.children)); if (next) { - ["marker-start", "marker-mid", "marker-end"].forEach(field => { - if (next.localName.startsWith("path") && (next.attributes as any)[field]) { - next.setAttribute(field, (next.attributes as any)[field].value.replace("#", "#X")); + ['marker-start', 'marker-mid', 'marker-end'].forEach(field => { + if (next.localName.startsWith('path') && (next.attributes as any)[field]) { + next.setAttribute(field, (next.attributes as any)[field].value.replace('#', '#X')); } }); - if (next.localName.startsWith("marker")) { - next.id = "X" + next.id; + if (next.localName.startsWith('marker')) { + next.id = 'X' + next.id; } } } @@ -396,20 +388,31 @@ export namespace DragManager { scaleXs.push(scaleX); scaleYs.push(scaleY); Object.assign(dragElement.style, { - opacity: "0.7", position: "absolute", margin: "0", top: "0", bottom: "", left: "0", color: "black", transition: "none", - borderRadius: getComputedStyle(ele).borderRadius, zIndex: globalCssVariables.contextMenuZindex, - transformOrigin: "0 0", width: `${rect.width / scaleX}px`, height: `${rect.height / scaleY}px`, + opacity: '0.7', + position: 'absolute', + margin: '0', + top: '0', + bottom: '', + left: '0', + color: 'black', + transition: 'none', + borderRadius: getComputedStyle(ele).borderRadius, + zIndex: globalCssVariables.contextMenuZindex, + transformOrigin: '0 0', + width: `${rect.width / scaleX}px`, + height: `${rect.height / scaleY}px`, transform: `translate(${rect.left + (options?.offsetX || 0)}px, ${rect.top + (options?.offsetY || 0)}px) scale(${scaleX}, ${scaleY})`, }); dragLabel.style.transform = `translate(${rect.left + (options?.offsetX || 0)}px, ${rect.top + (options?.offsetY || 0) - 20}px)`; if (docsBeingDragged.length) { - const pdfBox = dragElement.getElementsByTagName("canvas"); - const pdfBoxSrc = ele.getElementsByTagName("canvas"); - Array.from(pdfBox).filter(pb => pb.width && pb.height).map((pb, i) => pb.getContext('2d')!.drawImage(pdfBoxSrc[i], 0, 0)); + const pdfBox = dragElement.getElementsByTagName('canvas'); + const pdfBoxSrc = ele.getElementsByTagName('canvas'); + Array.from(pdfBox) + .filter(pb => pb.width && pb.height) + .map((pb, i) => pb.getContext('2d')!.drawImage(pdfBoxSrc[i], 0, 0)); } - [dragElement, ...Array.from(dragElement.getElementsByTagName('*'))].forEach(ele => - (ele as any).style && ((ele as any).style.pointerEvents = "none")); + [dragElement, ...Array.from(dragElement.getElementsByTagName('*'))].forEach(ele => (ele as any).style && ((ele as any).style.pointerEvents = 'none')); dragDiv.appendChild(dragElement); if (dragElement !== ele) { @@ -427,9 +430,9 @@ export namespace DragManager { }); const hideDragShowOriginalElements = (hide: boolean) => { - dragLabel.style.display = hide ? "" : "none"; + dragLabel.style.display = hide ? '' : 'none'; !hide && dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement)); - eles.forEach(ele => ele.hidden = hide); + eles.forEach(ele => (ele.hidden = hide)); }; options?.hideSource && hideDragShowOriginalElements(true); @@ -448,8 +451,8 @@ export namespace DragManager { const cleanupDrag = action(() => { hideDragShowOriginalElements(false); - document.removeEventListener("pointermove", moveHandler, true); - document.removeEventListener("pointerup", upHandler); + document.removeEventListener('pointermove', moveHandler, true); + document.removeEventListener('pointerup', upHandler, true); SnappingManager.SetIsDragging(false); SnappingManager.clearSnapLines(); batch.end(); @@ -458,17 +461,17 @@ export namespace DragManager { const moveHandler = (e: PointerEvent) => { e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop if (dragData instanceof DocumentDragData) { - dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : dragData.defaultDropAction; + dragData.userDropAction = e.ctrlKey && e.altKey ? 'copy' : e.ctrlKey ? 'alias' : dragData.defaultDropAction; } - if (((e.target as any)?.className === "lm_tabs" || (e.target as any)?.className === "lm_header" || e?.shiftKey) && dragData.draggedDocuments.length === 1) { + if (((e.target as any)?.className === 'lm_tabs' || (e.target as any)?.className === 'lm_header' || e?.shiftKey) && dragData.draggedDocuments.length === 1) { if (!startWindowDragTimer) { startWindowDragTimer = setTimeout(async () => { startWindowDragTimer = undefined; - dragData.dropAction = dragData.userDropAction || "same"; + dragData.dropAction = dragData.userDropAction || 'same'; AbortDrag(); await finishDrag?.(new DragCompleteEvent(true, dragData)); - DragManager.StartWindowDrag?.(e, dragData.droppedDocuments, (aborted) => { - if (!aborted && (dragData.dropAction === "move" || dragData.dropAction === "same")) { + DragManager.StartWindowDrag?.(e, dragData.droppedDocuments, aborted => { + if (!aborted && (dragData.dropAction === 'move' || dragData.dropAction === 'same')) { dragData.removeDocument?.(dragData.draggedDocuments[0]); } }); @@ -484,7 +487,7 @@ export namespace DragManager { if (target && !Doc.UserDoc()._noAutoscroll && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._noAutoscroll)) { const autoScrollHandler = () => { target.dispatchEvent( - new CustomEvent("dashDragAutoScroll", { + new CustomEvent('dashDragAutoScroll', { bubbles: true, detail: { shiftKey: e.shiftKey, @@ -493,7 +496,7 @@ export namespace DragManager { ctrlKey: e.ctrlKey, clientX: e.clientX, clientY: e.clientY, - dataTransfer: new DataTransfer, + dataTransfer: new DataTransfer(), button: e.button, buttons: e.buttons, getModifierState: e.getModifierState, @@ -505,8 +508,8 @@ export namespace DragManager { screenX: e.screenX, screenY: e.screenY, detail: e.detail, - view: e.view ? e.view : new Window as any, - nativeEvent: new DragEvent("dashDragAutoScroll"), + view: e.view ? e.view : (new Window() as any), + nativeEvent: new DragEvent('dashDragAutoScroll'), currentTarget: target, target: target, bubbles: true, @@ -514,14 +517,14 @@ export namespace DragManager { defaultPrevented: true, eventPhase: e.eventPhase, isTrusted: true, - preventDefault: () => "not implemented for this event" ? false : false, - isDefaultPrevented: () => "not implemented for this event" ? false : false, - stopPropagation: () => "not implemented for this event" ? false : false, - isPropagationStopped: () => "not implemented for this event" ? false : false, + preventDefault: () => ('not implemented for this event' ? false : false), + isDefaultPrevented: () => ('not implemented for this event' ? false : false), + stopPropagation: () => ('not implemented for this event' ? false : false), + isPropagationStopped: () => ('not implemented for this event' ? false : false), persist: emptyFunction, timeStamp: e.timeStamp, - type: "dashDragAutoScroll" - } + type: 'dashDragAutoScroll', + }, }) ); @@ -537,20 +540,18 @@ export namespace DragManager { lastPt = { x, y }; dragLabel.style.transform = `translate(${xs[0] + moveVec.x + (options?.offsetX || 0)}px, ${ys[0] + moveVec.y + (options?.offsetY || 0) - 20}px)`; - dragElements.map((dragElement, i) => (dragElement.style.transform = - `translate(${(xs[i] += moveVec.x) + (options?.offsetX || 0)}px, ${(ys[i] += moveVec.y) + (options?.offsetY || 0)}px) scale(${scaleXs[i]}, ${scaleYs[i]})`) - ); + dragElements.map((dragElement, i) => (dragElement.style.transform = `translate(${(xs[i] += moveVec.x) + (options?.offsetX || 0)}px, ${(ys[i] += moveVec.y) + (options?.offsetY || 0)}px) scale(${scaleXs[i]}, ${scaleYs[i]})`)); }; const upHandler = (e: PointerEvent) => { clearTimeout(startWindowDragTimer); startWindowDragTimer = undefined; dispatchDrag(document.elementFromPoint(e.x, e.y) || document.body, e, new DragCompleteEvent(false, dragData), snapDrag(e, xFromLeft, yFromTop, xFromRight, yFromBottom), finishDrag, options, cleanupDrag); }; - document.addEventListener("pointermove", moveHandler, true); - document.addEventListener("pointerup", upHandler); + document.addEventListener('pointermove', moveHandler, true); + document.addEventListener('pointerup', upHandler, true); } - async function dispatchDrag(target: Element, e: PointerEvent, complete: DragCompleteEvent, pos: { x: number, y: number }, finishDrag?: (e: DragCompleteEvent) => void, options?: DragOptions, endDrag?: () => void) { + async function dispatchDrag(target: Element, e: PointerEvent, complete: DragCompleteEvent, pos: { x: number; y: number }, finishDrag?: (e: DragCompleteEvent) => void, options?: DragOptions, endDrag?: () => void) { const dropArgs = { bubbles: true, detail: { @@ -560,13 +561,13 @@ export namespace DragManager { altKey: e.altKey, metaKey: e.metaKey, ctrlKey: e.ctrlKey, - embedKey: CanEmbed - } + embedKey: CanEmbed, + }, }; - target.dispatchEvent(new CustomEvent("dashPreDrop", dropArgs)); + target.dispatchEvent(new CustomEvent('dashPreDrop', dropArgs)); await finishDrag?.(complete); - target.dispatchEvent(new CustomEvent("dashOnDrop", dropArgs)); + target.dispatchEvent(new CustomEvent('dashOnDrop', dropArgs)); options?.dragComplete?.(complete); endDrag?.(); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 1a2054676..bd5e8caab 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -219,8 +219,10 @@ export class PresElementBox extends ViewBoxBaseComponent() { const dragItem: HTMLElement[] = []; if (dragArray.length === 1) { const doc = this._itemRef.current || dragArray[0]; - doc.className = miniView ? 'presItem-miniSlide' : 'presItem-slide'; - dragItem.push(doc); + if (doc) { + doc.className = miniView ? 'presItem-miniSlide' : 'presItem-slide'; + dragItem.push(doc); + } } else if (dragArray.length >= 1) { const doc = document.createElement('div'); doc.className = 'presItem-multiDrag'; -- cgit v1.2.3-70-g09d2 From 358f9e266ef264442aea1e2c7d5d959a19f7624c Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 22 Jul 2022 14:11:30 -0400 Subject: adjusted native dim scaling slightly combining props.scaling and props.ContentScaling into props.NativeDimScaling and fixing some resizing behaviors for fitWidth freeformviews and native-sized text boxes. Also fixed clicking on presboxe elements to not drag. --- src/client/views/DocumentDecorations.tsx | 3 +- src/client/views/InkingStroke.tsx | 536 +++++++++++++-------- src/client/views/SidebarAnnos.tsx | 4 +- src/client/views/StyleProvider.tsx | 4 +- .../collections/CollectionStackedTimeline.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 11 +- src/client/views/collections/TreeView.tsx | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 30 +- .../CollectionMulticolumnView.tsx | 187 +++---- .../CollectionMultirowView.tsx | 180 +++---- src/client/views/nodes/DocumentContentsView.tsx | 5 +- src/client/views/nodes/DocumentLinksButton.tsx | 384 ++++++++------- src/client/views/nodes/DocumentView.tsx | 24 +- src/client/views/nodes/EquationBox.tsx | 90 ++-- src/client/views/nodes/FieldView.tsx | 55 ++- src/client/views/nodes/ImageBox.tsx | 10 +- src/client/views/nodes/MapBox/MapBox.tsx | 9 +- src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 12 +- src/client/views/nodes/ScreenshotBox.tsx | 4 +- src/client/views/nodes/VideoBox.tsx | 6 +- src/client/views/nodes/WebBox.tsx | 25 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 10 +- src/client/views/nodes/trails/PresElementBox.tsx | 8 +- src/client/views/pdf/PDFViewer.tsx | 17 +- 25 files changed, 883 insertions(+), 741 deletions(-) (limited to 'src/client/views/nodes/trails/PresElementBox.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 780dcfb6d..964fd36c8 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -521,7 +521,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P } else doc._height = actualdH; } } else { - dH && (doc._height = actualdH); + const maxHeight = Math.max(nheight, NumCast(doc.scrollHeight)) * docView.NativeDimScaling(); + dH && (doc._height = actualdH > maxHeight ? maxHeight : actualdH); dW && (doc._width = actualdW); dH && (doc._autoHeight = false); } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index dace9716a..e5de7a0c5 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -20,35 +20,37 @@ Most of the operations that can be performed on an InkStroke (eg delete a point, rotate, stretch) are implemented in the InkStrokeProperties helper class */ -import React = require("react"); -import { action, IReactionDisposer, observable, reaction } from "mobx"; -import { observer } from "mobx-react"; -import { Doc, WidthSym } from "../../fields/Doc"; -import { InkData, InkField, InkTool } from "../../fields/InkField"; -import { Cast, NumCast, RTFCast, StrCast } from "../../fields/Types"; -import { TraceMobx } from "../../fields/util"; -import { OmitKeys, returnFalse, setupMoveUpEvents } from "../../Utils"; -import { CognitiveServices } from "../cognitive_services/CognitiveServices"; -import { InteractionUtils } from "../util/InteractionUtils"; -import { SnappingManager } from "../util/SnappingManager"; -import { Transform } from "../util/Transform"; -import { UndoManager } from "../util/UndoManager"; -import { ContextMenu } from "./ContextMenu"; -import { ViewBoxBaseComponent } from "./DocComponent"; -import { Colors } from "./global/globalEnums"; -import { InkControlPtHandles, InkEndPtHandles } from "./InkControlPtHandles"; -import { InkStrokeProperties } from "./InkStrokeProperties"; -import { InkTangentHandles } from "./InkTangentHandles"; -import { DocComponentView } from "./nodes/DocumentView"; -import { FieldView, FieldViewProps } from "./nodes/FieldView"; -import { FormattedTextBox } from "./nodes/formattedText/FormattedTextBox"; -import "./InkStroke.scss"; -import Color = require("color"); +import React = require('react'); +import { action, IReactionDisposer, observable, reaction } from 'mobx'; +import { observer } from 'mobx-react'; +import { Doc, WidthSym } from '../../fields/Doc'; +import { InkData, InkField, InkTool } from '../../fields/InkField'; +import { Cast, NumCast, RTFCast, StrCast } from '../../fields/Types'; +import { TraceMobx } from '../../fields/util'; +import { OmitKeys, returnFalse, setupMoveUpEvents } from '../../Utils'; +import { CognitiveServices } from '../cognitive_services/CognitiveServices'; +import { InteractionUtils } from '../util/InteractionUtils'; +import { SnappingManager } from '../util/SnappingManager'; +import { Transform } from '../util/Transform'; +import { UndoManager } from '../util/UndoManager'; +import { ContextMenu } from './ContextMenu'; +import { ViewBoxBaseComponent } from './DocComponent'; +import { Colors } from './global/globalEnums'; +import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles'; +import { InkStrokeProperties } from './InkStrokeProperties'; +import { InkTangentHandles } from './InkTangentHandles'; +import { DocComponentView } from './nodes/DocumentView'; +import { FieldView, FieldViewProps } from './nodes/FieldView'; +import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import './InkStroke.scss'; +import Color = require('color'); @observer export class InkingStroke extends ViewBoxBaseComponent() { static readonly MaskDim = 50000; // choose a really big number to make sure mask fits over container (which in theory can be arbitrarily big) - public static LayoutString(fieldStr: string) { return FieldView.LayoutString(InkingStroke, fieldStr); } + public static LayoutString(fieldStr: string) { + return FieldView.LayoutString(InkingStroke, fieldStr); + } public static IsClosed(inkData: InkData) { return inkData && inkData.lastElement().X === inkData[0].X && inkData.lastElement().Y === inkData[0].Y; } @@ -56,13 +58,15 @@ export class InkingStroke extends ViewBoxBaseComponent() { private _selDisposer?: IReactionDisposer; @observable _nearestSeg?: number; // nearest Bezier segment along the ink stroke to the cursor (used for displaying the Add Point highlight) - @observable _nearestT?: number; // nearest t value within the nearest Bezier segment " - @observable _nearestScrPt?: { X: number, Y: number }; // nearst screen point on the ink stroke "" + @observable _nearestT?: number; // nearest t value within the nearest Bezier segment " + @observable _nearestScrPt?: { X: number; Y: number }; // nearst screen point on the ink stroke "" componentDidMount() { this.props.setContentView?.(this); - this._selDisposer = reaction(() => this.props.isSelected(), // react to stroke being deselected by turning off ink handles - selected => !selected && (InkStrokeProperties.Instance._controlButton = false)); + this._selDisposer = reaction( + () => this.props.isSelected(), // react to stroke being deselected by turning off ink handles + selected => !selected && (InkStrokeProperties.Instance._controlButton = false) + ); } componentWillUnmount() { this._selDisposer?.(); @@ -70,36 +74,36 @@ export class InkingStroke extends ViewBoxBaseComponent() { // transform is the inherited screentolocal xf plus any scaling that was done to make the stroke // fit within its panel (e.g., for content fitting views like Lightbox or multicolumn, etc) - screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1); + screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.NativeDimScaling?.() || 1); getAnchor = () => { console.log(document.activeElement); return this._subContentView?.getAnchor?.() || this.rootDoc; - } + }; scrollFocus = (textAnchor: Doc, smooth: boolean) => { return this._subContentView?.scrollFocus?.(textAnchor, smooth); - } + }; /** - * @returns the center of the ink stroke in the ink document's coordinate space (not screen space, and not the ink data coordinate space); - * DocumentDecorations calls getBounds() on DocumentViews which call getCenter() if defined - in the case of ink it needs to be defined since - * the center of the ink stroke changes as the stroke is rotated. - */ + * @returns the center of the ink stroke in the ink document's coordinate space (not screen space, and not the ink data coordinate space); + * DocumentDecorations calls getBounds() on DocumentViews which call getCenter() if defined - in the case of ink it needs to be defined since + * the center of the ink stroke changes as the stroke is rotated. + */ getCenter = (xf: Transform) => { const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); const angle = -NumCast(this.layoutDoc.rotation); const newPoints = inkData.map(pt => { - const newX = Math.cos(angle) * pt.X - Math.sin(angle) * pt.Y * inkScaleY / inkScaleX; - const newY = Math.sin(angle) * pt.X * inkScaleX / inkScaleY + Math.cos(angle) * pt.Y; + const newX = Math.cos(angle) * pt.X - (Math.sin(angle) * pt.Y * inkScaleY) / inkScaleX; + const newY = (Math.sin(angle) * pt.X * inkScaleX) / inkScaleY + Math.cos(angle) * pt.Y; return { X: newX, Y: newY }; }); const crx = (Math.max(...newPoints.map(np => np.X)) + Math.min(...newPoints.map(np => np.X))) / 2; const cry = (Math.max(...newPoints.map(np => np.Y)) + Math.min(...newPoints.map(np => np.Y))) / 2; - const cx = Math.cos(-angle) * crx - Math.sin(-angle) * cry * inkScaleY / inkScaleX; - const cy = Math.sin(-angle) * crx * inkScaleX / inkScaleY + Math.cos(-angle) * cry; + const cx = Math.cos(-angle) * crx - (Math.sin(-angle) * cry * inkScaleY) / inkScaleX; + const cy = (Math.sin(-angle) * crx * inkScaleX) / inkScaleY + Math.cos(-angle) * cry; const tc = xf.transformPoint((cx - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (cy - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2); return { X: tc[0], Y: tc[1] }; - } + }; /** * analyzes the ink stroke and saves the analysis of the stroke to the 'inkAnalysis' field, @@ -107,7 +111,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { */ analyzeStrokes() { const data: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? []; - CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.dataDoc, ["inkAnalysis", "handwriting"], [data]); + CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.dataDoc, ['inkAnalysis', 'handwriting'], [data]); } /** @@ -115,12 +119,12 @@ export class InkingStroke extends ViewBoxBaseComponent() { * When displayed as a mask, the stroke is rendered with mixBlendMode set to multiply so that the stroke will * appear to illuminate what it covers up. At the same time, all pixels that are not under the stroke will be * dimmed by a semi-opaque overlay mask. - */ + */ public static toggleMask = action((inkDoc: Doc) => { inkDoc.isInkMask = !inkDoc.isInkMask; - inkDoc._backgroundColor = inkDoc.isInkMask ? "rgba(0,0,0,0.7)" : undefined; - inkDoc.mixBlendMode = inkDoc.isInkMask ? "hard-light" : undefined; - inkDoc.color = "#9b9b9bff"; + inkDoc._backgroundColor = inkDoc.isInkMask ? 'rgba(0,0,0,0.7)' : undefined; + inkDoc.mixBlendMode = inkDoc.isInkMask ? 'hard-light' : undefined; + inkDoc.color = '#9b9b9bff'; inkDoc._stayInCollection = inkDoc.isInkMask ? true : undefined; }); /** @@ -132,46 +136,60 @@ export class InkingStroke extends ViewBoxBaseComponent() { this._handledClick = false; const inkView = this.props.docViewPath().lastElement(); const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); - const screenPts = inkData.map(point => this.screenToLocal().inverse().transformPoint( - (point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, - (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)).map(p => ({ X: p[0], Y: p[1] })); + const screenPts = inkData + .map(point => + this.screenToLocal() + .inverse() + .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2) + ) + .map(p => ({ X: p[0], Y: p[1] })); const { nearestSeg } = InkStrokeProperties.nearestPtToStroke(screenPts, { X: e.clientX, Y: e.clientY }); const controlIndex = nearestSeg; const wasSelected = InkStrokeProperties.Instance._currentPoint === controlIndex; var controlUndo: UndoManager.Batch | undefined; const isEditing = InkStrokeProperties.Instance._controlButton && this.props.isSelected(); - setupMoveUpEvents(this, e, - !isEditing ? returnFalse : action((e: PointerEvent, down: number[], delta: number[]) => { - if (!controlUndo) controlUndo = UndoManager.StartBatch("drag ink ctrl pt"); - const inkMoveEnd = this.ptFromScreen({ X: delta[0], Y: delta[1] }); - const inkMoveStart = this.ptFromScreen({ X: 0, Y: 0 }); - InkStrokeProperties.Instance.moveControlPtHandle(inkView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex); - InkStrokeProperties.Instance.moveControlPtHandle(inkView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex + 3); - return false; - }), - !isEditing ? returnFalse : action(() => { - controlUndo?.end(); - controlUndo = undefined; - UndoManager.FilterBatches(["data", "x", "y", "width", "height"]); - }), + setupMoveUpEvents( + this, + e, + !isEditing + ? returnFalse + : action((e: PointerEvent, down: number[], delta: number[]) => { + if (!controlUndo) controlUndo = UndoManager.StartBatch('drag ink ctrl pt'); + const inkMoveEnd = this.ptFromScreen({ X: delta[0], Y: delta[1] }); + const inkMoveStart = this.ptFromScreen({ X: 0, Y: 0 }); + InkStrokeProperties.Instance.moveControlPtHandle(inkView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex); + InkStrokeProperties.Instance.moveControlPtHandle(inkView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex + 3); + return false; + }), + !isEditing + ? returnFalse + : action(() => { + controlUndo?.end(); + controlUndo = undefined; + UndoManager.FilterBatches(['data', 'x', 'y', 'width', 'height']); + }), action((e: PointerEvent, doubleTap: boolean | undefined) => { doubleTap = doubleTap || this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick; if (doubleTap) { InkStrokeProperties.Instance._controlButton = true; InkStrokeProperties.Instance._currentPoint = -1; - this._handledClick = true; // mark the double-click pseudo pointerevent so we can block the real mouse event from propagating to DocumentView + this._handledClick = true; // mark the double-click pseudo pointerevent so we can block the real mouse event from propagating to DocumentView if (isEditing) { this._nearestT && this._nearestSeg !== undefined && InkStrokeProperties.Instance.addPoints(this.props.docViewPath().lastElement(), this._nearestT, this._nearestSeg, this.inkScaledData().inkData.slice()); } } - }), isEditing, isEditing, action(() => wasSelected && (InkStrokeProperties.Instance._currentPoint = -1))); - } + }), + isEditing, + isEditing, + action(() => wasSelected && (InkStrokeProperties.Instance._currentPoint = -1)) + ); + }; /** * @param scrPt a point in the screen coordinate space * @returns the point in the ink data's coordinate space. */ - ptFromScreen = (scrPt: { X: number, Y: number }) => { + ptFromScreen = (scrPt: { X: number; Y: number }) => { const { inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); const docPt = this.screenToLocal().transformPoint(scrPt.X, scrPt.Y); const inkPt = { @@ -179,39 +197,39 @@ export class InkingStroke extends ViewBoxBaseComponent() { Y: (docPt[1] - inkStrokeWidth / 2) / inkScaleY + inkStrokeWidth / 2 + inkTop, }; return inkPt; - } + }; /** * @param inkPt a point in the ink data's coordinate space * @returns the screen point corresponding to the ink point */ - ptToScreen = (inkPt: { X: number, Y: number }) => { + ptToScreen = (inkPt: { X: number; Y: number }) => { const { inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); const docPt = { X: (inkPt.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, - Y: (inkPt.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2 + Y: (inkPt.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2, }; const scrPt = this.screenToLocal().inverse().transformPoint(docPt.X, docPt.Y); return { X: scrPt[0], Y: scrPt[1] }; - } + }; /** - * Snaps a screen space point to this stroke, optionally skipping bezier segments indicated by 'excludeSegs' - * @param scrPt - the point to snap to this stroke - * @param excludeSegs - optional segments in this stroke to skip (this is used when dragging a point on the stroke and not wanting the drag point to snap to its neighboring segments) - * - * @returns the nearest ink space point on this stroke to the screen point AND the screen space distance from the snapped point to the nearest point - */ - snapPt = (scrPt: { X: number, Y: number }, excludeSegs?: number[]) => { + * Snaps a screen space point to this stroke, optionally skipping bezier segments indicated by 'excludeSegs' + * @param scrPt - the point to snap to this stroke + * @param excludeSegs - optional segments in this stroke to skip (this is used when dragging a point on the stroke and not wanting the drag point to snap to its neighboring segments) + * + * @returns the nearest ink space point on this stroke to the screen point AND the screen space distance from the snapped point to the nearest point + */ + snapPt = (scrPt: { X: number; Y: number }, excludeSegs?: number[]) => { const { inkData } = this.inkScaledData(); const { nearestPt, distance } = InkStrokeProperties.nearestPtToStroke(inkData, this.ptFromScreen(scrPt), excludeSegs ?? []); return { nearestPt, distance: distance * this.screenToLocal().inverse().Scale }; - } + }; /** - * extracts key features from the inkData, including: the data points, the ink width, the ink bounds (top,left, width, height), and the scale - * factor for converting between ink and screen space. - */ + * extracts key features from the inkData, including: the data points, the ink width, the ink bounds (top,left, width, height), and the scale + * factor for converting between ink and screen space. + */ inkScaledData = () => { const inkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? []; const inkStrokeWidth = NumCast(this.rootDoc.strokeWidth, 1); @@ -228,27 +246,31 @@ export class InkingStroke extends ViewBoxBaseComponent() { inkLeft, inkWidth, inkHeight, - inkScaleX: ((this.props.PanelWidth() - inkStrokeWidth) / ((inkWidth - inkStrokeWidth) || 1) || 1), - inkScaleY: ((this.props.PanelHeight() - inkStrokeWidth) / ((inkHeight - inkStrokeWidth) || 1) || 1) + inkScaleX: (this.props.PanelWidth() - inkStrokeWidth) / (inkWidth - inkStrokeWidth || 1) || 1, + inkScaleY: (this.props.PanelHeight() - inkStrokeWidth) / (inkHeight - inkStrokeWidth || 1) || 1, }; - } + }; // - // this updates the highlight for the nearest point on the curve to the cursor. + // this updates the highlight for the nearest point on the curve to the cursor. // if the user double clicks, this highlighted point will be added as a control point in the curve. // @action onPointerMove = (e: React.PointerEvent) => { const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); - const screenPts = inkData.map(point => this.screenToLocal().inverse().transformPoint( - (point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, - (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)).map(p => ({ X: p[0], Y: p[1] })); + const screenPts = inkData + .map(point => + this.screenToLocal() + .inverse() + .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2) + ) + .map(p => ({ X: p[0], Y: p[1] })); const { distance, nearestT, nearestSeg, nearestPt } = InkStrokeProperties.nearestPtToStroke(screenPts, { X: e.clientX, Y: e.clientY }); this._nearestT = nearestT; this._nearestSeg = nearestSeg; this._nearestScrPt = nearestPt; - } + }; /** * @returns the nearest screen point to the cursor (to render a highlight for the point to be added) @@ -263,50 +285,66 @@ export class InkingStroke extends ViewBoxBaseComponent() { componentUI = (boundsLeft: number, boundsTop: number) => { const inkDoc = this.props.Document; const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); - const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.screenToLocal().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke + const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.screenToLocal().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke const screenInkWidth = this.screenToLocal().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); - const screenPts = inkData.map(point => this.screenToLocal().inverse().transformPoint( - (point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, - (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)).map(p => ({ X: p[0], Y: p[1] })); + const screenPts = inkData + .map(point => + this.screenToLocal() + .inverse() + .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2) + ) + .map(p => ({ X: p[0], Y: p[1] })); const screenHdlPts = screenPts; const startMarker = StrCast(this.layoutDoc.strokeStartMarker); const endMarker = StrCast(this.layoutDoc.strokeEndMarker); const markerScale = NumCast(this.layoutDoc.strokeMarkerScale); - return SnappingManager.GetIsDragging() ? (null) : - !InkStrokeProperties.Instance._controlButton ? - (!this.props.isSelected() || InkingStroke.IsClosed(inkData) ? (null) : -
- -
) : + return SnappingManager.GetIsDragging() ? null : !InkStrokeProperties.Instance._controlButton ? ( + !this.props.isSelected() || InkingStroke.IsClosed(inkData) ? null : (
- {InteractionUtils.CreatePolyline(screenPts, 0, 0, Colors.MEDIUM_BLUE, screenInkWidth[0], screenSpaceCenterlineStrokeWidth, - StrCast(inkDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), StrCast(inkDoc.strokeBezier), - "none", startMarker, endMarker, markerScale * Math.min(screenSpaceCenterlineStrokeWidth, screenInkWidth[0] / screenSpaceCenterlineStrokeWidth), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false)} - - -
; - } + + + ) + ) : ( +
+ {InteractionUtils.CreatePolyline( + screenPts, + 0, + 0, + Colors.MEDIUM_BLUE, + screenInkWidth[0], + screenSpaceCenterlineStrokeWidth, + StrCast(inkDoc.strokeLineJoin), + StrCast(this.layoutDoc.strokeLineCap), + StrCast(inkDoc.strokeBezier), + 'none', + startMarker, + endMarker, + markerScale * Math.min(screenSpaceCenterlineStrokeWidth, screenInkWidth[0] / screenSpaceCenterlineStrokeWidth), + StrCast(inkDoc.strokeDash), + 1, + 1, + '', + 'none', + 1.0, + false + )} + + +
+ ); + }; _subContentView: DocComponentView | undefined; - setSubContentView = (doc: DocComponentView) => this._subContentView = doc; + setSubContentView = (doc: DocComponentView) => (this._subContentView = doc); render() { TraceMobx(); const { inkData, inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = this.inkScaledData(); @@ -315,105 +353,181 @@ export class InkingStroke extends ViewBoxBaseComponent() { const endMarker = StrCast(this.layoutDoc.strokeEndMarker); const markerScale = NumCast(this.layoutDoc.strokeMarkerScale, 1); const closed = InkingStroke.IsClosed(inkData); - const fillColor = StrCast(this.layoutDoc.fillColor, "transparent"); - const strokeColor = !closed && fillColor && fillColor !== "transparent" ? fillColor : StrCast(this.layoutDoc.color); + const fillColor = StrCast(this.layoutDoc.fillColor, 'transparent'); + const strokeColor = !closed && fillColor && fillColor !== 'transparent' ? fillColor : StrCast(this.layoutDoc.color); // Visually renders the polygonal line made by the user. - const inkLine = InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, strokeColor, inkStrokeWidth, inkStrokeWidth, - StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), - StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" ? "none" : fillColor, startMarker, endMarker, - markerScale, StrCast(this.layoutDoc.strokeDash), inkScaleX, inkScaleY, "", "none", 1.0, false); + const inkLine = InteractionUtils.CreatePolyline( + inkData, + inkLeft, + inkTop, + strokeColor, + inkStrokeWidth, + inkStrokeWidth, + StrCast(this.layoutDoc.strokeLineJoin), + StrCast(this.layoutDoc.strokeLineCap), + StrCast(this.layoutDoc.strokeBezier), + !closed ? 'none' : fillColor === 'transparent' ? 'none' : fillColor, + startMarker, + endMarker, + markerScale, + StrCast(this.layoutDoc.strokeDash), + inkScaleX, + inkScaleY, + '', + 'none', + 1.0, + false + ); const highlightIndex = /*BoolCast(this.props.Document.isLinkButton) && */ Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString - const highlightColor = !highlightIndex ? - StrCast(this.layoutDoc.strokeOutlineColor, !closed && fillColor && fillColor !== "transparent" ? StrCast(this.layoutDoc.color, "transparent") : "transparent") : - ["transparent", "rgb(68, 118, 247)", "rgb(68, 118, 247)", "yellow", "magenta", "cyan", "orange"][highlightIndex]; + const highlightColor = !highlightIndex + ? StrCast(this.layoutDoc.strokeOutlineColor, !closed && fillColor && fillColor !== 'transparent' ? StrCast(this.layoutDoc.color, 'transparent') : 'transparent') + : ['transparent', 'rgb(68, 118, 247)', 'rgb(68, 118, 247)', 'yellow', 'magenta', 'cyan', 'orange'][highlightIndex]; // Invisible polygonal line that enables the ink to be selected by the user. - const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, suppressFill: boolean = false) => InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, highlightColor, - inkStrokeWidth, fillColor && closed && highlightIndex ? highlightIndex / 2 : inkStrokeWidth + (fillColor ? closed ? 0 : (highlightIndex + 2) : 0), - StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), - StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" || suppressFill ? "none" : fillColor, startMarker, endMarker, - markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents?.() ?? (this.rootDoc._lockedPosition ? "none" : "visiblepainted"), 0.0, - false, downHdlr); - const fsize = +(StrCast(this.props.Document.fontSize, "12px").replace("px", "")); - // bootsrap 3 style sheet sets line height to be 20px for default 14 point font size. + const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, suppressFill: boolean = false) => + InteractionUtils.CreatePolyline( + inkData, + inkLeft, + inkTop, + highlightColor, + inkStrokeWidth, + fillColor && closed && highlightIndex ? highlightIndex / 2 : inkStrokeWidth + (fillColor ? (closed ? 0 : highlightIndex + 2) : 0), + StrCast(this.layoutDoc.strokeLineJoin), + StrCast(this.layoutDoc.strokeLineCap), + StrCast(this.layoutDoc.strokeBezier), + !closed ? 'none' : fillColor === 'transparent' || suppressFill ? 'none' : fillColor, + startMarker, + endMarker, + markerScale, + undefined, + inkScaleX, + inkScaleY, + '', + this.props.pointerEvents?.() ?? (this.rootDoc._lockedPosition ? 'none' : 'visiblepainted'), + 0.0, + false, + downHdlr + ); + const fsize = +StrCast(this.props.Document.fontSize, '12px').replace('px', ''); + // bootsrap 3 style sheet sets line height to be 20px for default 14 point font size. // this attempts to figure out the lineHeight ratio by inquiring the body's lineHeight and dividing by the fontsize which should yield 1.428571429 // see: https://bibwild.wordpress.com/2019/06/10/bootstrap-3-to-4-changes-in-how-font-size-line-height-and-spacing-is-done-or-what-happened-to-line-height-computed/ - const lineHeightGuess = (+getComputedStyle(document.body).lineHeight.replace("px", "")) / (+getComputedStyle(document.body).fontSize.replace("px", "")); + const lineHeightGuess = +getComputedStyle(document.body).lineHeight.replace('px', '') / +getComputedStyle(document.body).fontSize.replace('px', ''); const interactions = { - onPointerLeave: action(() => this._nearestScrPt = undefined), + onPointerLeave: action(() => (this._nearestScrPt = undefined)), onPointerMove: this.props.isSelected() ? this.onPointerMove : undefined, onClick: (e: React.MouseEvent) => this._handledClick && e.stopPropagation(), onContextMenu: () => { const cm = ContextMenu.Instance; - !Doc.noviceMode && cm?.addItem({ description: "Recognize Writing", event: this.analyzeStrokes, icon: "paint-brush" }); - cm?.addItem({ description: "Toggle Mask", event: () => InkingStroke.toggleMask(this.rootDoc), icon: "paint-brush" }); - cm?.addItem({ description: "Edit Points", event: action(() => InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton), icon: "paint-brush" }); - } + !Doc.noviceMode && cm?.addItem({ description: 'Recognize Writing', event: this.analyzeStrokes, icon: 'paint-brush' }); + cm?.addItem({ description: 'Toggle Mask', event: () => InkingStroke.toggleMask(this.rootDoc), icon: 'paint-brush' }); + cm?.addItem({ description: 'Edit Points', event: action(() => (InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton)), icon: 'paint-brush' }); + }, }; - return
- - {closed ? inkLine : clickableLine(this.onPointerDown)} - {closed ? clickableLine(this.onPointerDown) : inkLine} - - {!closed || (!RTFCast(this.rootDoc.text)?.Text && !this.props.isSelected()) ? (null) : -
- -
- } - {!closed ? null : - {clickableLine(this.onPointerDown, true)} - } -
; + return ( +
+ + {closed ? inkLine : clickableLine(this.onPointerDown)} + {closed ? clickableLine(this.onPointerDown) : inkLine} + + {!closed || (!RTFCast(this.rootDoc.text)?.Text && !this.props.isSelected()) ? null : ( +
+ +
+ )} + {!closed ? null : ( + + {clickableLine(this.onPointerDown, true)} + + )} +
+ ); } } - -export function SetActiveInkWidth(width: string): void { !isNaN(parseInt(width)) && ActiveInkPen() && (ActiveInkPen().activeInkWidth = width); } -export function SetActiveBezierApprox(bezier: string): void { ActiveInkPen() && (ActiveInkPen().activeInkBezier = isNaN(parseInt(bezier)) ? "" : bezier); } -export function SetActiveInkColor(value: string) { ActiveInkPen() && (ActiveInkPen().activeInkColor = value); } -export function SetActiveFillColor(value: string) { ActiveInkPen() && (ActiveInkPen().activeFillColor = value); } -export function SetActiveArrowStart(value: string) { ActiveInkPen() && (ActiveInkPen().activeArrowStart = value); } -export function SetActiveArrowEnd(value: string) { ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value); } -export function SetActiveArrowScale(value: number) { ActiveInkPen() && (ActiveInkPen().activeArrowScale = value); } -export function SetActiveDash(dash: string): void { !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash); } -export function ActiveInkPen(): Doc { return Doc.UserDoc(); } -export function ActiveInkColor(): string { return StrCast(ActiveInkPen()?.activeInkColor, "black"); } -export function ActiveFillColor(): string { return StrCast(ActiveInkPen()?.activeFillColor, ""); } -export function ActiveArrowStart(): string { return StrCast(ActiveInkPen()?.activeArrowStart, ""); } -export function ActiveArrowEnd(): string { return StrCast(ActiveInkPen()?.activeArrowEnd, ""); } -export function ActiveArrowScale(): number { return NumCast(ActiveInkPen()?.activeArrowScale, 1); } -export function ActiveDash(): string { return StrCast(ActiveInkPen()?.activeDash, "0"); } -export function ActiveInkWidth(): number { return Number(ActiveInkPen()?.activeInkWidth); } -export function ActiveInkBezierApprox(): string { return StrCast(ActiveInkPen()?.activeInkBezier); } +export function SetActiveInkWidth(width: string): void { + !isNaN(parseInt(width)) && ActiveInkPen() && (ActiveInkPen().activeInkWidth = width); +} +export function SetActiveBezierApprox(bezier: string): void { + ActiveInkPen() && (ActiveInkPen().activeInkBezier = isNaN(parseInt(bezier)) ? '' : bezier); +} +export function SetActiveInkColor(value: string) { + ActiveInkPen() && (ActiveInkPen().activeInkColor = value); +} +export function SetActiveFillColor(value: string) { + ActiveInkPen() && (ActiveInkPen().activeFillColor = value); +} +export function SetActiveArrowStart(value: string) { + ActiveInkPen() && (ActiveInkPen().activeArrowStart = value); +} +export function SetActiveArrowEnd(value: string) { + ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value); +} +export function SetActiveArrowScale(value: number) { + ActiveInkPen() && (ActiveInkPen().activeArrowScale = value); +} +export function SetActiveDash(dash: string): void { + !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash); +} +export function ActiveInkPen(): Doc { + return Doc.UserDoc(); +} +export function ActiveInkColor(): string { + return StrCast(ActiveInkPen()?.activeInkColor, 'black'); +} +export function ActiveFillColor(): string { + return StrCast(ActiveInkPen()?.activeFillColor, ''); +} +export function ActiveArrowStart(): string { + return StrCast(ActiveInkPen()?.activeArrowStart, ''); +} +export function ActiveArrowEnd(): string { + return StrCast(ActiveInkPen()?.activeArrowEnd, ''); +} +export function ActiveArrowScale(): number { + return NumCast(ActiveInkPen()?.activeArrowScale, 1); +} +export function ActiveDash(): string { + return StrCast(ActiveInkPen()?.activeDash, '0'); +} +export function ActiveInkWidth(): number { + return Number(ActiveInkPen()?.activeInkWidth); +} +export function ActiveInkBezierApprox(): string { + return StrCast(ActiveInkPen()?.activeInkBezier); +} diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index e81a9c40f..9fdf9d2be 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -93,7 +93,7 @@ export class SidebarAnnos extends React.Component { this.props .ScreenToLocalTransform() .translate(Doc.NativeWidth(this.props.dataDoc), 0) - .scale(this.props.scaling?.() || 1); + .scale(this.props.NativeDimScaling?.() || 1); // panelWidth = () => !this.props.layoutDoc._showSidebar ? 0 : // this.props.usePanelWidth ? this.props.PanelWidth() : // (NumCast(this.props.layoutDoc.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth() / NumCast(this.props.layoutDoc.nativeWidth); @@ -164,7 +164,7 @@ export class SidebarAnnos extends React.Component { setHeight={this.setHeightCallback} isAnnotationOverlay={false} select={emptyFunction} - scaling={returnOne} + NativeDimScaling={returnOne} childShowTitle={this.showTitle} childDocumentsActive={this.props.isContentActive} whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 340a5df45..334f381be 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -250,9 +250,9 @@ export function DefaultStyleProvider(doc: Opt, props: Opt (this.layoutDoc?.[HeightSym]() || 0) - NumCast(this.layoutDoc.autoHeightMargins); truncateTitleWidth = () => this.treeViewtruncateTitleWidth; onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick); - panelWidth = () => Math.max(0, this.props.PanelWidth() - this.marginX() - CollectionTreeView.expandViewLabelSize) * (this.props.scaling?.() || 1); + panelWidth = () => Math.max(0, this.props.PanelWidth() - this.marginX() - CollectionTreeView.expandViewLabelSize) * (this.props.NativeDimScaling?.() || 1); addAnnotationDocument = (doc: Doc | Doc[]) => this.props.CollectionView?.addDocument(doc, `${this.props.fieldKey}-annotations`) || false; remAnnotationDocument = (doc: Doc | Doc[]) => this.props.CollectionView?.removeDocument(doc, `${this.props.fieldKey}-annotations`) || false; @@ -389,9 +390,9 @@ export class CollectionTreeView extends CollectionSubView {!this.buttonMenu && !this.noviceExplainer ? null : ( diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 5a2103e98..aa1330762 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -403,7 +403,7 @@ export class TreeView extends React.Component { const aspect = Doc.NativeAspect(layoutDoc); if (layoutDoc._fitWidth) return Math.min(this.props.panelWidth() - treeBulletWidth(), layoutDoc[WidthSym]()); if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.panelWidth() - treeBulletWidth())); - return Math.min((this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.scaling?.() || 1), Doc.NativeWidth(layoutDoc) ? layoutDoc[WidthSym]() : this.layoutDoc[WidthSym]()); + return Math.min((this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.NativeDimScaling?.() || 1), Doc.NativeWidth(layoutDoc) ? layoutDoc[WidthSym]() : this.layoutDoc[WidthSym]()); }; docHeight = () => { const layoutDoc = this.layoutDoc; @@ -514,7 +514,7 @@ export class TreeView extends React.Component { rtfWidth = () => { const layout = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ''))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc; - return Math.min(layout[WidthSym](), this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.scaling?.() || 1); + return Math.min(layout[WidthSym](), this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.NativeDimScaling?.() || 1); }; rtfHeight = () => { const layout = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ''))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc; @@ -921,7 +921,6 @@ export class TreeView extends React.Component { searchFilterDocs={returnEmptyDoclist} ContainingCollectionView={undefined} ContainingCollectionDoc={this.props.treeView.props.Document} - ContentScaling={returnOne} /> ); @@ -992,7 +991,6 @@ export class TreeView extends React.Component { hideResizeHandles={this.props.treeView.outlineMode} onClick={this.onChildClick} focus={this.refocus} - ContentScaling={returnOne} onKey={this.onKeyDown} hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)} dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 5d7a12122..3e938ec1c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -58,7 +58,7 @@ import e = require('connect-flash'); export type collectionFreeformViewProps = { annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox) viewDefDivClick?: ScriptField; - childPointerEvents?: boolean; + childPointerEvents?: string; scaleField?: string; noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale) engineProps?: any; @@ -150,11 +150,11 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; + if (this.layoutDoc._Transform || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming e.stopPropagation(); @@ -1251,7 +1251,7 @@ export class CollectionFreeFormView extends CollectionSubView { const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); - const pointerEvents = this.props.isContentActive() === false ? 'none' : this.props.childPointerEvents ? 'all' : this.props.viewDefDivClick || (engine === 'pass' && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.(); + const pointerEvents = this.props.isContentActive() === false ? 'none' : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === 'pass' && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.()); return pointerEvents; }; getChildDocView(entry: PoolData) { @@ -1631,9 +1631,11 @@ export class CollectionFreeFormView extends CollectionSubView {this._firstRender ? this.placeholder : this.marqueeView} {this.props.noOverlay ? null : } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 777ef464f..465dbfe6d 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -1,6 +1,6 @@ import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; -import * as React from "react"; +import * as React from 'react'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; @@ -11,11 +11,10 @@ import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; import { DocumentView } from '../../nodes/DocumentView'; import { CollectionSubView } from '../CollectionSubView'; -import "./CollectionMulticolumnView.scss"; +import './CollectionMulticolumnView.scss'; import ResizeBar from './MulticolumnResizer'; import WidthLabel from './MulticolumnWidthLabel'; - interface WidthSpecifier { magnitude: number; unit: string; @@ -27,8 +26,8 @@ interface LayoutData { } export const DimUnit = { - Pixel: "px", - Ratio: "*" + Pixel: 'px', + Ratio: '*', }; const resolvedUnits = Object.values(DimUnit); @@ -36,14 +35,13 @@ const resizerWidth = 8; @observer export class CollectionMulticolumnView extends CollectionSubView() { - /** * @returns the list of layout documents whose width unit is * *, denoting that it will be displayed with a ratio, not fixed pixel, value */ @computed private get ratioDefinedDocs() { - return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, "*") === DimUnit.Ratio); + return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, '*') === DimUnit.Ratio); } @computed @@ -65,10 +63,10 @@ export class CollectionMulticolumnView extends CollectionSubView() { let starSum = 0; const widthSpecifiers: WidthSpecifier[] = []; this.childLayoutPairs.map(pair => { - const unit = StrCast(pair.layout._dimUnit, "*"); + const unit = StrCast(pair.layout._dimUnit, '*'); const magnitude = NumCast(pair.layout._dimMagnitude, this.minimumDim); if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { - (unit === DimUnit.Ratio) && (starSum += magnitude); + unit === DimUnit.Ratio && (starSum += magnitude); widthSpecifiers.push({ magnitude, unit }); } /** @@ -100,14 +98,13 @@ export class CollectionMulticolumnView extends CollectionSubView() { * This returns the total quantity, in pixels, that this * view needs to reserve for child documents that have * (with higher priority) requested a fixed pixel width. - * + * * If the underlying resolvedLayoutInformation returns null * because we're waiting on promises to resolve, this value will be undefined as well. */ @computed private get totalFixedAllocation(): number | undefined { - return this.resolvedLayoutInformation?.widthSpecifiers.reduce( - (sum, { magnitude, unit }) => sum + (unit === DimUnit.Pixel ? magnitude : 0), 0); + return this.resolvedLayoutInformation?.widthSpecifiers.reduce((sum, { magnitude, unit }) => sum + (unit === DimUnit.Pixel ? magnitude : 0), 0); } /** @@ -115,7 +112,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { * view needs to reserve for child documents that have * (with lower priority) requested a certain relative proportion of the * remaining pixel width not allocated for fixed widths. - * + * * If the underlying totalFixedAllocation returns undefined * because we're waiting indirectly on promises to resolve, this value will be undefined as well. */ @@ -135,7 +132,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { * this accessor returns 1000 / (2 + 2 + 1), or 200px. * Elsewhere, this is then multiplied by each relative-width * document's (potentially decimal) * count to compute its actual width (400px, 400px and 200px). - * + * * If the underlying totalRatioAllocation or this.resolveLayoutInformation return undefined * because we're waiting indirectly on promises to resolve, this value will be undefined as well. */ @@ -165,17 +162,17 @@ export class CollectionMulticolumnView extends CollectionSubView() { return 0; // we're still waiting on promises to resolve } let width = NumCast(layout._dimMagnitude, this.minimumDim); - if (StrCast(layout._dimUnit, "*") === DimUnit.Ratio) { + if (StrCast(layout._dimUnit, '*') === DimUnit.Ratio) { width *= columnUnitLength; } return width; - } + }; /** * @returns the transform that will correctly place * the document decorations box, shifted to the right by * the sum of all the resolved column widths of the - * documents before the target. + * documents before the target. */ private lookupIndividualTransform = (layout: Doc) => { const columnUnitLength = this.columnUnitLength; @@ -185,12 +182,12 @@ export class CollectionMulticolumnView extends CollectionSubView() { let offset = 0; for (const { layout: candidate } of this.childLayoutPairs) { if (candidate === layout) { - return this.props.ScreenToLocalTransform().translate(-offset / (this.props.scaling?.() || 1), 0); + return this.props.ScreenToLocalTransform().translate(-offset / (this.props.NativeDimScaling?.() || 1), 0); } offset += this.lookupPixels(candidate) + resizerWidth; } return Transform.Identity(); // type coersion, this case should never be hit - } + }; @undoBatch @action @@ -198,16 +195,17 @@ export class CollectionMulticolumnView extends CollectionSubView() { let dropInd = -1; if (de.complete.docDragData && this._mainCont) { let curInd = -1; - de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => { - curInd = this.childDocs.indexOf(d); - })); + de.complete.docDragData?.droppedDocuments.forEach( + action((d: Doc) => { + curInd = this.childDocs.indexOf(d); + }) + ); Array.from(this._mainCont.children).forEach((child, index) => { const brect = child.getBoundingClientRect(); if (brect.x < de.x && brect.x + brect.width > de.x) { if (curInd !== -1 && curInd === Math.floor(index / 2)) { dropInd = curInd; - } - else if (child.className === "multiColumnResizer") { + } else if (child.className === 'multiColumnResizer') { dropInd = Math.floor(index / 2); } else { dropInd = Math.ceil(index / 2 + (de.x - brect.x > brect.width / 2 ? 0 : -1)); @@ -215,76 +213,80 @@ export class CollectionMulticolumnView extends CollectionSubView() { } }); if (super.onInternalDrop(e, de)) { - de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => { - d._dimUnit = "*"; - d._dimMagnitude = 1; - if (dropInd !== curInd || dropInd === -1) { - if (this.childDocs.includes(d)) { - if (dropInd > this.childDocs.indexOf(d)) dropInd--; + de.complete.docDragData?.droppedDocuments.forEach( + action((d: Doc) => { + d._dimUnit = '*'; + d._dimMagnitude = 1; + if (dropInd !== curInd || dropInd === -1) { + if (this.childDocs.includes(d)) { + if (dropInd > this.childDocs.indexOf(d)) dropInd--; + } + Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d); + Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1); } - Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d); - Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1); - } - })); + }) + ); } } return false; - } - + }; onChildClickHandler = () => ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick); addDocTab = (doc: Doc, where: string) => { - if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { + if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) { this.dataDoc[this.props.fieldKey] = new List([doc]); return true; } return this.props.addDocTab(doc, where); - } + }; isContentActive = () => this.props.isSelected() || this.props.isContentActive(); - isChildContentActive = () => ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false; + isChildContentActive = () => + ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false; getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => { - return ; - } + return ( + + ); + }; /** * @returns the resolved list of rendered child documents, displayed - * at their resolved pixel widths, each separated by a resizer. + * at their resolved pixel widths, each separated by a resizer. */ @computed private get contents(): JSX.Element[] | null { @@ -293,22 +295,20 @@ export class CollectionMulticolumnView extends CollectionSubView() { const collector: JSX.Element[] = []; for (let i = 0; i < childLayoutPairs.length; i++) { const { layout } = childLayoutPairs[i]; - const dxf = () => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin)).scale((this.props.scaling?.() || 1)); + const dxf = () => + this.lookupIndividualTransform(layout) + .translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin)) + .scale(this.props.NativeDimScaling?.() || 1); const width = () => this.lookupPixels(layout); const height = () => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); collector.push( -
+
{this.getDisplayDoc(layout, dxf, width, height)} - +
, + marginLeft: NumCast(this.props.Document._xMargin), + marginRight: NumCast(this.props.Document._xMargin), + marginTop: NumCast(this.props.Document._yMargin), + marginBottom: NumCast(this.props.Document._yMargin), + }}> {this.contents}
); } - -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 08385bcb5..f8de4e5de 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -1,6 +1,6 @@ import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; -import * as React from "react"; +import * as React from 'react'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; @@ -11,7 +11,7 @@ import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; import { DocumentView } from '../../nodes/DocumentView'; import { CollectionSubView } from '../CollectionSubView'; -import "./CollectionMultirowView.scss"; +import './CollectionMultirowView.scss'; import HeightLabel from './MultirowHeightLabel'; import ResizeBar from './MultirowResizer'; @@ -26,8 +26,8 @@ interface LayoutData { } export const DimUnit = { - Pixel: "px", - Ratio: "*" + Pixel: 'px', + Ratio: '*', }; const resolvedUnits = Object.values(DimUnit); @@ -35,14 +35,13 @@ const resizerHeight = 8; @observer export class CollectionMultirowView extends CollectionSubView() { - /** * @returns the list of layout documents whose width unit is * *, denoting that it will be displayed with a ratio, not fixed pixel, value */ @computed private get ratioDefinedDocs() { - return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, "*") === DimUnit.Ratio); + return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, '*') === DimUnit.Ratio); } @computed @@ -64,10 +63,10 @@ export class CollectionMultirowView extends CollectionSubView() { let starSum = 0; const heightSpecifiers: HeightSpecifier[] = []; this.childLayoutPairs.map(pair => { - const unit = StrCast(pair.layout._dimUnit, "*"); + const unit = StrCast(pair.layout._dimUnit, '*'); const magnitude = NumCast(pair.layout._dimMagnitude, this.minimumDim); if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { - (unit === DimUnit.Ratio) && (starSum += magnitude); + unit === DimUnit.Ratio && (starSum += magnitude); heightSpecifiers.push({ magnitude, unit }); } /** @@ -99,14 +98,13 @@ export class CollectionMultirowView extends CollectionSubView() { * This returns the total quantity, in pixels, that this * view needs to reserve for child documents that have * (with higher priority) requested a fixed pixel width. - * + * * If the underlying resolvedLayoutInformation returns null * because we're waiting on promises to resolve, this value will be undefined as well. */ @computed private get totalFixedAllocation(): number | undefined { - return this.resolvedLayoutInformation?.heightSpecifiers.reduce( - (sum, { magnitude, unit }) => sum + (unit === DimUnit.Pixel ? magnitude : 0), 0); + return this.resolvedLayoutInformation?.heightSpecifiers.reduce((sum, { magnitude, unit }) => sum + (unit === DimUnit.Pixel ? magnitude : 0), 0); } /** @@ -114,7 +112,7 @@ export class CollectionMultirowView extends CollectionSubView() { * view needs to reserve for child documents that have * (with lower priority) requested a certain relative proportion of the * remaining pixel width not allocated for fixed widths. - * + * * If the underlying totalFixedAllocation returns undefined * because we're waiting indirectly on promises to resolve, this value will be undefined as well. */ @@ -134,7 +132,7 @@ export class CollectionMultirowView extends CollectionSubView() { * this accessor returns 1000 / (2 + 2 + 1), or 200px. * Elsewhere, this is then multiplied by each relative-width * document's (potentially decimal) * count to compute its actual width (400px, 400px and 200px). - * + * * If the underlying totalRatioAllocation or this.resolveLayoutInformation return undefined * because we're waiting indirectly on promises to resolve, this value will be undefined as well. */ @@ -164,17 +162,17 @@ export class CollectionMultirowView extends CollectionSubView() { return 0; // we're still waiting on promises to resolve } let height = NumCast(layout._dimMagnitude, this.minimumDim); - if (StrCast(layout._dimUnit, "*") === DimUnit.Ratio) { + if (StrCast(layout._dimUnit, '*') === DimUnit.Ratio) { height *= rowUnitLength; } return height; - } + }; /** * @returns the transform that will correctly place * the document decorations box, shifted to the right by * the sum of all the resolved row widths of the - * documents before the target. + * documents before the target. */ private lookupIndividualTransform = (layout: Doc) => { const rowUnitLength = this.rowUnitLength; @@ -184,13 +182,12 @@ export class CollectionMultirowView extends CollectionSubView() { let offset = 0; for (const { layout: candidate } of this.childLayoutPairs) { if (candidate === layout) { - return this.props.ScreenToLocalTransform().translate(0, -offset / (this.props.scaling?.() || 1)); + return this.props.ScreenToLocalTransform().translate(0, -offset / (this.props.NativeDimScaling?.() || 1)); } offset += this.lookupPixels(candidate) + resizerHeight; } return Transform.Identity(); // type coersion, this case should never be hit - } - + }; @undoBatch @action @@ -198,16 +195,17 @@ export class CollectionMultirowView extends CollectionSubView() { let dropInd = -1; if (de.complete.docDragData && this._mainCont) { let curInd = -1; - de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => { - curInd = this.childDocs.indexOf(d); - })); + de.complete.docDragData?.droppedDocuments.forEach( + action((d: Doc) => { + curInd = this.childDocs.indexOf(d); + }) + ); Array.from(this._mainCont.children).forEach((child, index) => { const brect = child.getBoundingClientRect(); if (brect.y < de.y && brect.y + brect.height > de.y) { if (curInd !== -1 && curInd === Math.floor(index / 2)) { dropInd = curInd; - } - else if (child.className === "multiColumnResizer") { + } else if (child.className === 'multiColumnResizer') { dropInd = Math.floor(index / 2); } else { dropInd = Math.ceil(index / 2 + (de.y - brect.y > brect.height / 2 ? 0 : -1)); @@ -215,75 +213,79 @@ export class CollectionMultirowView extends CollectionSubView() { } }); if (super.onInternalDrop(e, de)) { - de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => { - d._dimUnit = "*"; - d._dimMagnitude = 1; - if (dropInd !== curInd || dropInd === -1) { - if (this.childDocs.includes(d)) { - if (dropInd > this.childDocs.indexOf(d)) dropInd--; + de.complete.docDragData?.droppedDocuments.forEach( + action((d: Doc) => { + d._dimUnit = '*'; + d._dimMagnitude = 1; + if (dropInd !== curInd || dropInd === -1) { + if (this.childDocs.includes(d)) { + if (dropInd > this.childDocs.indexOf(d)) dropInd--; + } + Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d); + Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1); } - Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d); - Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1); - } - })); + }) + ); } } return false; - } - + }; onChildClickHandler = () => ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick); addDocTab = (doc: Doc, where: string) => { - if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { + if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) { this.dataDoc[this.props.fieldKey] = new List([doc]); return true; } return this.props.addDocTab(doc, where); - } + }; isContentActive = () => this.props.isSelected() || this.props.isContentActive(); - isChildContentActive = () => ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false; + isChildContentActive = () => + ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false; getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => { - return ; - } + return ( + + ); + }; /** * @returns the resolved list of rendered child documents, displayed - * at their resolved pixel widths, each separated by a resizer. + * at their resolved pixel widths, each separated by a resizer. */ @computed private get contents(): JSX.Element[] | null { @@ -292,13 +294,14 @@ export class CollectionMultirowView extends CollectionSubView() { const collector: JSX.Element[] = []; for (let i = 0; i < childLayoutPairs.length; i++) { const { layout } = childLayoutPairs[i]; - const dxf = () => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin)).scale((this.props.scaling?.() || 1)); + const dxf = () => + this.lookupIndividualTransform(layout) + .translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin)) + .scale(this.props.NativeDimScaling?.() || 1); const height = () => this.lookupPixels(layout); const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); collector.push( -
+
{this.getDisplayDoc(layout, dxf, width, height)}
, @@ -306,7 +309,7 @@ export class CollectionMultirowView extends CollectionSubView() { height={resizerHeight} styleProvider={this.props.styleProvider} isContentActive={this.props.isContentActive} - key={"resizer" + i} + key={'resizer' + i} columnUnitLength={this.getRowUnitLength} toTop={layout} toBottom={childLayoutPairs[i + 1]?.layout} @@ -319,16 +322,19 @@ export class CollectionMultirowView extends CollectionSubView() { render(): JSX.Element { return ( -
+ marginLeft: NumCast(this.props.Document._xMargin), + marginRight: NumCast(this.props.Document._xMargin), + marginTop: NumCast(this.props.Document._yMargin), + marginBottom: NumCast(this.props.Document._yMargin), + }} + ref={this.createDashEventsTarget}> {this.contents}
); } - -} \ No newline at end of file +} diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index f1d8123da..381436a56 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -118,7 +118,7 @@ export class DocumentContentsView extends React.Component< FormattedTextBoxProps & { isSelected: (outsideReaction: boolean) => boolean; select: (ctrl: boolean) => void; - scaling?: () => number; + NativeDimScaling?: () => number; setHeight?: (height: number) => void; layoutKey: string; } @@ -161,7 +161,6 @@ export class DocumentContentsView extends React.Component< 'LayoutTemplateString', 'LayoutTemplate', 'dontCenter', - 'ContentScaling', 'contextMenuItems', 'onClick', 'onDoubleClick', @@ -195,7 +194,7 @@ export class DocumentContentsView extends React.Component< // replace HTML with corresponding HTML tag as in: becomes const replacer2 = (match: any, p1: string, offset: any, string: any) => { - return ` number; + scaling?: () => number; // how uch doc is scaled so that link buttons can invert it } @observer export class DocumentLinksButton extends React.Component { @@ -42,53 +42,71 @@ export class DocumentLinksButton extends React.Component; public static invisibleWebRef = React.createRef(); - @action @undoBatch + @action + @undoBatch onLinkButtonMoved = (e: PointerEvent) => { if (this.props.InMenu && this.props.StartLink) { if (this._linkButton.current !== null) { - const linkDrag = UndoManager.StartBatch("Drag Link"); - this.props.View && DragManager.StartLinkDrag(this._linkButton.current, this.props.View, this.props.View.ComponentView?.getAnchor, e.pageX, e.pageY, { - dragComplete: dropEv => { - if (this.props.View && dropEv.linkDocument) {// dropEv.linkDocument equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop - !dropEv.linkDocument.linkRelationship && (Doc.GetProto(dropEv.linkDocument).linkRelationship = "hyperlink"); - } - linkDrag?.end(); - }, - hideSource: false - }); + const linkDrag = UndoManager.StartBatch('Drag Link'); + this.props.View && + DragManager.StartLinkDrag(this._linkButton.current, this.props.View, this.props.View.ComponentView?.getAnchor, e.pageX, e.pageY, { + dragComplete: dropEv => { + if (this.props.View && dropEv.linkDocument) { + // dropEv.linkDocument equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop + !dropEv.linkDocument.linkRelationship && (Doc.GetProto(dropEv.linkDocument).linkRelationship = 'hyperlink'); + } + linkDrag?.end(); + }, + hideSource: false, + }); return true; } return false; } return false; - } + }; onLinkMenuOpen = (e: React.PointerEvent): void => { - setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, action((e, doubleTap) => { - if (doubleTap) { - DocumentView.showBackLinks(this.props.View.rootDoc); - } - }), undefined, undefined, - action(() => DocumentLinksButton.LinkEditorDocView = this.props.View)); - } + setupMoveUpEvents( + this, + e, + this.onLinkButtonMoved, + emptyFunction, + action((e, doubleTap) => { + if (doubleTap) { + DocumentView.showBackLinks(this.props.View.rootDoc); + } + }), + undefined, + undefined, + action(() => (DocumentLinksButton.LinkEditorDocView = this.props.View)) + ); + }; @undoBatch onLinkButtonDown = (e: React.PointerEvent): void => { - setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, action((e, doubleTap) => { - if (doubleTap && this.props.InMenu && this.props.StartLink) { - //action(() => Doc.BrushDoc(this.props.View.Document)); - if (DocumentLinksButton.StartLink === this.props.View.props.Document) { - DocumentLinksButton.StartLink = undefined; - DocumentLinksButton.StartLinkView = undefined; - } else { - DocumentLinksButton.StartLink = this.props.View.props.Document; - DocumentLinksButton.StartLinkView = this.props.View; + setupMoveUpEvents( + this, + e, + this.onLinkButtonMoved, + emptyFunction, + action((e, doubleTap) => { + if (doubleTap && this.props.InMenu && this.props.StartLink) { + //action(() => Doc.BrushDoc(this.props.View.Document)); + if (DocumentLinksButton.StartLink === this.props.View.props.Document) { + DocumentLinksButton.StartLink = undefined; + DocumentLinksButton.StartLinkView = undefined; + } else { + DocumentLinksButton.StartLink = this.props.View.props.Document; + DocumentLinksButton.StartLinkView = this.props.View; + } } - } - })); - } + }) + ); + }; - @action @undoBatch + @action + @undoBatch onLinkClick = (e: React.MouseEvent): void => { if (this.props.InMenu && this.props.StartLink) { DocumentLinksButton.AnnotationId = undefined; @@ -96,108 +114,125 @@ export class DocumentLinksButton extends React.Component Doc.BrushDoc(this.props.View.Document)); } - } - + }; completeLink = (e: React.PointerEvent): void => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action((e, doubleTap) => { - if (doubleTap && !this.props.StartLink) { - if (DocumentLinksButton.StartLink === this.props.View.props.Document) { - DocumentLinksButton.StartLink = undefined; - DocumentLinksButton.StartLinkView = undefined; - DocumentLinksButton.AnnotationId = undefined; - } else if (DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document) { - const sourceDoc = DocumentLinksButton.StartLink; - const targetDoc = this.props.View.ComponentView?.getAnchor?.() || this.props.View.Document; - const linkDoc = DocUtils.MakeLink({ doc: sourceDoc }, { doc: targetDoc }, "links"); //why is long drag here when this is used for completing links by clicking? + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + undoBatch( + action((e, doubleTap) => { + if (doubleTap && !this.props.StartLink) { + if (DocumentLinksButton.StartLink === this.props.View.props.Document) { + DocumentLinksButton.StartLink = undefined; + DocumentLinksButton.StartLinkView = undefined; + DocumentLinksButton.AnnotationId = undefined; + } else if (DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document) { + const sourceDoc = DocumentLinksButton.StartLink; + const targetDoc = this.props.View.ComponentView?.getAnchor?.() || this.props.View.Document; + const linkDoc = DocUtils.MakeLink({ doc: sourceDoc }, { doc: targetDoc }, 'links'); //why is long drag here when this is used for completing links by clicking? - LinkManager.currentLink = linkDoc; + LinkManager.currentLink = linkDoc; - runInAction(() => { - if (linkDoc) { - TaskCompletionBox.textDisplayed = "Link Created"; - TaskCompletionBox.popupX = e.screenX; - TaskCompletionBox.popupY = e.screenY - 133; - TaskCompletionBox.taskCompleted = true; + runInAction(() => { + if (linkDoc) { + TaskCompletionBox.textDisplayed = 'Link Created'; + TaskCompletionBox.popupX = e.screenX; + TaskCompletionBox.popupY = e.screenY - 133; + TaskCompletionBox.taskCompleted = true; - LinkDescriptionPopup.popupX = e.screenX; - LinkDescriptionPopup.popupY = e.screenY - 100; - LinkDescriptionPopup.descriptionPopup = true; + LinkDescriptionPopup.popupX = e.screenX; + LinkDescriptionPopup.popupY = e.screenY - 100; + LinkDescriptionPopup.descriptionPopup = true; - const rect = document.body.getBoundingClientRect(); - if (LinkDescriptionPopup.popupX + 200 > rect.width) { - LinkDescriptionPopup.popupX -= 190; - TaskCompletionBox.popupX -= 40; - } - if (LinkDescriptionPopup.popupY + 100 > rect.height) { - LinkDescriptionPopup.popupY -= 40; - TaskCompletionBox.popupY -= 40; - } + const rect = document.body.getBoundingClientRect(); + if (LinkDescriptionPopup.popupX + 200 > rect.width) { + LinkDescriptionPopup.popupX -= 190; + TaskCompletionBox.popupX -= 40; + } + if (LinkDescriptionPopup.popupY + 100 > rect.height) { + LinkDescriptionPopup.popupY -= 40; + TaskCompletionBox.popupY -= 40; + } - setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2500); + setTimeout( + action(() => (TaskCompletionBox.taskCompleted = false)), + 2500 + ); + } + }); } - }); - } - } - }))); - } + } + }) + ) + ); + }; - public static finishLinkClick = undoBatch(action((screenX: number, screenY: number, startLink: Doc, endLink: Doc, startIsAnnotation: boolean, endLinkView?: DocumentView,) => { - if (startLink === endLink) { - DocumentLinksButton.StartLink = undefined; - DocumentLinksButton.StartLinkView = undefined; - DocumentLinksButton.AnnotationId = undefined; - DocumentLinksButton.AnnotationUri = undefined; - //!this.props.StartLink - } else if (startLink !== endLink) { - endLink = endLinkView?.docView?._componentView?.getAnchor?.() || endLink; - startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.() || startLink; - const linkDoc = DocUtils.MakeLink({ doc: startLink }, { doc: endLink }, - DocumentLinksButton.AnnotationId ? "hypothes.is annotation" : undefined, undefined, undefined, true); + public static finishLinkClick = undoBatch( + action((screenX: number, screenY: number, startLink: Doc, endLink: Doc, startIsAnnotation: boolean, endLinkView?: DocumentView) => { + if (startLink === endLink) { + DocumentLinksButton.StartLink = undefined; + DocumentLinksButton.StartLinkView = undefined; + DocumentLinksButton.AnnotationId = undefined; + DocumentLinksButton.AnnotationUri = undefined; + //!this.props.StartLink + } else if (startLink !== endLink) { + endLink = endLinkView?.docView?._componentView?.getAnchor?.() || endLink; + startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.() || startLink; + const linkDoc = DocUtils.MakeLink({ doc: startLink }, { doc: endLink }, DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined, undefined, undefined, true); - LinkManager.currentLink = linkDoc; + LinkManager.currentLink = linkDoc; - if (DocumentLinksButton.AnnotationId && DocumentLinksButton.AnnotationUri) { // if linking from a Hypothes.is annotation - Doc.GetProto(linkDoc as Doc).linksToAnnotation = true; - Doc.GetProto(linkDoc as Doc).annotationId = DocumentLinksButton.AnnotationId; - Doc.GetProto(linkDoc as Doc).annotationUri = DocumentLinksButton.AnnotationUri; - const dashHyperlink = Doc.globalServerPath(startIsAnnotation ? endLink : startLink); - Hypothesis.makeLink(StrCast(startIsAnnotation ? endLink.title : startLink.title), dashHyperlink, DocumentLinksButton.AnnotationId, - (startIsAnnotation ? startLink : endLink)); // edit annotation to add a Dash hyperlink to the linked doc - } + if (DocumentLinksButton.AnnotationId && DocumentLinksButton.AnnotationUri) { + // if linking from a Hypothes.is annotation + Doc.GetProto(linkDoc as Doc).linksToAnnotation = true; + Doc.GetProto(linkDoc as Doc).annotationId = DocumentLinksButton.AnnotationId; + Doc.GetProto(linkDoc as Doc).annotationUri = DocumentLinksButton.AnnotationUri; + const dashHyperlink = Doc.globalServerPath(startIsAnnotation ? endLink : startLink); + Hypothesis.makeLink(StrCast(startIsAnnotation ? endLink.title : startLink.title), dashHyperlink, DocumentLinksButton.AnnotationId, startIsAnnotation ? startLink : endLink); // edit annotation to add a Dash hyperlink to the linked doc + } - if (linkDoc) { - TaskCompletionBox.textDisplayed = "Link Created"; - TaskCompletionBox.popupX = screenX; - TaskCompletionBox.popupY = screenY - 133; - TaskCompletionBox.taskCompleted = true; + if (linkDoc) { + TaskCompletionBox.textDisplayed = 'Link Created'; + TaskCompletionBox.popupX = screenX; + TaskCompletionBox.popupY = screenY - 133; + TaskCompletionBox.taskCompleted = true; - if (LinkDescriptionPopup.showDescriptions === "ON" || !LinkDescriptionPopup.showDescriptions) { - LinkDescriptionPopup.popupX = screenX; - LinkDescriptionPopup.popupY = screenY - 100; - LinkDescriptionPopup.descriptionPopup = true; - } + if (LinkDescriptionPopup.showDescriptions === 'ON' || !LinkDescriptionPopup.showDescriptions) { + LinkDescriptionPopup.popupX = screenX; + LinkDescriptionPopup.popupY = screenY - 100; + LinkDescriptionPopup.descriptionPopup = true; + } - const rect = document.body.getBoundingClientRect(); - if (LinkDescriptionPopup.popupX + 200 > rect.width) { - LinkDescriptionPopup.popupX -= 190; - TaskCompletionBox.popupX -= 40; - } - if (LinkDescriptionPopup.popupY + 100 > rect.height) { - LinkDescriptionPopup.popupY -= 40; - TaskCompletionBox.popupY -= 40; - } + const rect = document.body.getBoundingClientRect(); + if (LinkDescriptionPopup.popupX + 200 > rect.width) { + LinkDescriptionPopup.popupX -= 190; + TaskCompletionBox.popupX -= 40; + } + if (LinkDescriptionPopup.popupY + 100 > rect.height) { + LinkDescriptionPopup.popupY -= 40; + TaskCompletionBox.popupY -= 40; + } - setTimeout(action(() => { TaskCompletionBox.taskCompleted = false; }), 2500); + setTimeout( + action(() => { + TaskCompletionBox.taskCompleted = false; + }), + 2500 + ); + } } - } - })); + }) + ); @action clearLinks() { DocumentLinksButton.StartLink = undefined; @@ -208,9 +243,7 @@ export class DocumentLinksButton extends React.Component(this.props.View.allLinks)).forEach(link => { - if (DocUtils.FilterDocs([link], filters, []).length || - DocUtils.FilterDocs([link.anchor2 as Doc], filters, []).length || - DocUtils.FilterDocs([link.anchor1 as Doc], filters, []).length) { + if (DocUtils.FilterDocs([link], filters, []).length || DocUtils.FilterDocs([link.anchor2 as Doc], filters, []).length || DocUtils.FilterDocs([link.anchor1 as Doc], filters, []).length) { results.push(link); } }); @@ -219,48 +252,45 @@ export class DocumentLinksButton extends React.Component; - const isActive = (DocumentLinksButton.StartLink === this.props.View.props.Document) && this.props.StartLink; - return (!this.props.InMenu ? -
-
; + const isActive = DocumentLinksButton.StartLink === this.props.View.props.Document && this.props.StartLink; + return !this.props.InMenu ? ( +
+
{Array.from(this.filteredLinks).length}
- : -
- {this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document ? //if the origin node is not this node -
+ {this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document ? ( //if the origin node is not this node +
DocumentLinksButton.StartLink && DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.props.View.props.Document, true, this.props.View)}>
- : (null) - } - { - this.props.InMenu && this.props.StartLink ? //if link has been started from current node, then set behavior of link button to deactivate linking when clicked again -
- -
- : - (null) - } + ) : null} + {this.props.InMenu && this.props.StartLink ? ( //if link has been started from current node, then set behavior of link button to deactivate linking when clicked again +
+ +
+ ) : null}
); } @@ -268,25 +298,23 @@ export class DocumentLinksButton extends React.Component - { - (this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink)) || - (!DocumentLinksButton.LinkEditorDocView && !this.props.InMenu) ? - {title}
}> - {this.linkButtonInner} - - : this.linkButtonInner - } -
; + transform: this.props.InMenu ? undefined : `scale(${this.props.scaling})`, + }}> + {(this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink)) || (!DocumentLinksButton.LinkEditorDocView && !this.props.InMenu) ? ( + {title}
}>{this.linkButtonInner} + ) : ( + this.linkButtonInner + )} +
+ ); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 3a8552325..6bf0c365a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -175,7 +175,6 @@ export interface DocumentViewProps extends DocumentViewSharedProps { LayoutTemplateString?: string; dontCenter?: 'x' | 'y' | 'xy'; dontScaleFilter?: (doc: Doc) => boolean; // decides whether a document can be scaled to fit its container vs native size with scrolling - ContentScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NativeWidth?: () => number; NativeHeight?: () => number; LayoutTemplate?: () => Opt; @@ -192,6 +191,7 @@ export interface DocumentViewProps extends DocumentViewSharedProps { export interface DocumentViewInternalProps extends DocumentViewProps { NativeWidth: () => number; NativeHeight: () => number; + NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to FieldViewProps isSelected: (outsideReaction?: boolean) => boolean; select: (ctrlPressed: boolean) => void; DocumentView: () => DocumentView; @@ -235,8 +235,8 @@ export class DocumentViewInternal extends DocComponent; } - @computed get ContentScale() { - return this.props.ContentScaling?.() || 1; + @computed get NativeDimScaling() { + return this.props.NativeDimScaling?.() || 1; } @computed get thumb() { return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url.href.replace('.png', '_m.png'); @@ -428,7 +428,7 @@ export class DocumentViewInternal extends DocComponent this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false; panelHeight = () => this.props.PanelHeight() - this.headerMargin; screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin); - contentScaling = () => this.ContentScale; onClickFunc = () => this.onClickHandler; setHeight = (height: number) => (this.layoutDoc._height = height); setContentView = action((view: { getAnchor?: () => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view)); @@ -989,6 +988,7 @@ export class DocumentViewInternal extends DocComponent (this.props.NativeDimScaling?.() || 1) * this.props.DocumentView().screenToLocalTransform().Scale; @computed get contents() { TraceMobx(); const audioView = !this.layoutDoc._showAudio ? null : ( @@ -1041,7 +1041,7 @@ export class DocumentViewInternal extends DocComponent )} @@ -1503,7 +1503,7 @@ export class DocumentView extends React.Component { return this.props.dontCenter?.includes('y') ? 0 : this.Yshift; } - toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.ContentScale, this.props.PanelWidth(), this.props.PanelHeight()); + toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight()); focus = (doc: Doc, options?: DocFocusOptions) => this.docView?.focus(doc, options); getBounds = () => { if (!this.docView || !this.docView.ContentDiv || this.props.Document.presBox || this.docView.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { @@ -1564,7 +1564,7 @@ export class DocumentView extends React.Component { NativeHeight = () => this.effectiveNativeHeight; PanelWidth = () => this.panelWidth; PanelHeight = () => this.panelHeight; - ContentScale = () => this.nativeScaling; + NativeDimScaling = () => this.nativeScaling; selfView = () => this; screenToLocalTransform = () => this.props @@ -1620,9 +1620,9 @@ export class DocumentView extends React.Component { PanelHeight={this.PanelHeight} NativeWidth={this.NativeWidth} NativeHeight={this.NativeHeight} + NativeDimScaling={this.NativeDimScaling} isSelected={this.isSelected} select={this.select} - ContentScaling={this.ContentScale} ScreenToLocalTransform={this.screenToLocalTransform} focus={this.props.focus || emptyFunction} ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))} diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index c170f9867..a714518cc 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -12,11 +12,12 @@ import { LightboxView } from '../LightboxView'; import './EquationBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; - @observer export class EquationBox extends ViewBoxBaseComponent() { - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(EquationBox, fieldKey); } - public static SelectOnLoad: string = ""; + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(EquationBox, fieldKey); + } + public static SelectOnLoad: string = ''; _ref: React.RefObject = React.createRef(); componentDidMount() { if (EquationBox.SelectOnLoad === this.rootDoc[Id] && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()))) { @@ -25,75 +26,82 @@ export class EquationBox extends ViewBoxBaseComponent() { this._ref.current!.mathField.focus(); this._ref.current!.mathField.select(); } - reaction(() => StrCast(this.dataDoc.text), + reaction( + () => StrCast(this.dataDoc.text), text => { if (text && text !== this._ref.current!.mathField.latex()) { this._ref.current!.mathField.latex(text); } - }); - reaction(() => this.props.isSelected(), + } + ); + reaction( + () => this.props.isSelected(), selected => { if (this._ref.current) { - if (selected) this._ref.current.element.current.children[0].addEventListener("keydown", this.keyPressed, true); - else this._ref.current.element.current.children[0].removeEventListener("keydown", this.keyPressed); + if (selected) this._ref.current.element.current.children[0].addEventListener('keydown', this.keyPressed, true); + else this._ref.current.element.current.children[0].removeEventListener('keydown', this.keyPressed); } - }, { fireImmediately: true }); + }, + { fireImmediately: true } + ); } plot: any; @action keyPressed = (e: KeyboardEvent) => { - const _height = Number(getComputedStyle(this._ref.current!.element.current).height.replace("px", "")); - const _width = Number(getComputedStyle(this._ref.current!.element.current).width.replace("px", "")); - if (e.key === "Enter") { + const _height = Number(getComputedStyle(this._ref.current!.element.current).height.replace('px', '')); + const _width = Number(getComputedStyle(this._ref.current!.element.current).width.replace('px', '')); + if (e.key === 'Enter') { const nextEq = Docs.Create.EquationDocument({ - title: "# math", text: StrCast(this.dataDoc.text), _width, _height: 25, - x: NumCast(this.layoutDoc.x), y: NumCast(this.layoutDoc.y) + _height + 10 + title: '# math', + text: StrCast(this.dataDoc.text), + _width, + _height: 25, + x: NumCast(this.layoutDoc.x), + y: NumCast(this.layoutDoc.y) + _height + 10, }); EquationBox.SelectOnLoad = nextEq[Id]; this.props.addDocument?.(nextEq); e.stopPropagation(); - } - if (e.key === "Tab") { + if (e.key === 'Tab') { const graph = Docs.Create.FunctionPlotDocument([this.rootDoc], { x: NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym](), y: NumCast(this.layoutDoc.y), - _width: 400, _height: 300, backgroundColor: "white" + _width: 400, + _height: 300, + backgroundColor: 'white', }); this.props.addDocument?.(graph); e.stopPropagation(); } - if (e.key === "Backspace" && !this.dataDoc.text) this.props.removeDocument?.(this.rootDoc); - } + if (e.key === 'Backspace' && !this.dataDoc.text) this.props.removeDocument?.(this.rootDoc); + }; onChange = (str: string) => { this.dataDoc.text = str; const style = this._ref.current && getComputedStyle(this._ref.current.element.current); if (style) { - const _height = Number(style.height.replace("px", "")); - const _width = Number(style.width.replace("px", "")); + const _height = Number(style.height.replace('px', '')); + const _width = Number(style.width.replace('px', '')); this.layoutDoc._width = Math.max(35, _width); this.layoutDoc._height = Math.max(25, _height); } - } + }; render() { TraceMobx(); - const scale = (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); - return (
!e.ctrlKey && e.stopPropagation()} - style={{ - transform: `scale(${scale})`, - width: `${100 / scale}%`, - height: `${100 / scale}%`, - pointerEvents: !this.props.isSelected() ? "none" : undefined, - }} - onKeyDown={e => e.stopPropagation()} - > - -
); + const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); + return ( +
!e.ctrlKey && e.stopPropagation()} + style={{ + transform: `scale(${scale})`, + width: `${100 / scale}%`, + height: `${100 / scale}%`, + pointerEvents: !this.props.isSelected() ? 'none' : undefined, + }} + onKeyDown={e => e.stopPropagation()}> + +
+ ); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 67cf18d8b..5a6c49809 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,18 +1,18 @@ -import React = require("react"); -import { computed } from "mobx"; -import { observer } from "mobx-react"; -import { DateField } from "../../../fields/DateField"; -import { Doc, Field, FieldResult, Opt } from "../../../fields/Doc"; -import { List } from "../../../fields/List"; -import { WebField } from "../../../fields/URLField"; -import { DocumentView, DocumentViewSharedProps } from "./DocumentView"; -import { ScriptField } from "../../../fields/ScriptField"; -import { RecordingBox } from "./RecordingBox"; +import React = require('react'); +import { computed } from 'mobx'; +import { observer } from 'mobx-react'; +import { DateField } from '../../../fields/DateField'; +import { Doc, Field, FieldResult, Opt } from '../../../fields/Doc'; +import { List } from '../../../fields/List'; +import { WebField } from '../../../fields/URLField'; +import { DocumentView, DocumentViewSharedProps } from './DocumentView'; +import { ScriptField } from '../../../fields/ScriptField'; +import { RecordingBox } from './RecordingBox'; // // these properties get assigned through the render() method of the DocumentView when it creates this node. // However, that only happens because the properties are "defined" in the markup for the field view. -// See the LayoutString method on each field view : ImageBox, FormattedTextBox, etc. +// See the LayoutString method on each field view : ImageBox, FormattedTextBox, etc. // export interface FieldViewProps extends DocumentViewSharedProps { // FieldView specific props that are not part of DocumentView props @@ -23,10 +23,10 @@ export interface FieldViewProps extends DocumentViewSharedProps { isContentActive: (outsideReaction?: boolean) => boolean | undefined; isDocumentActive?: () => boolean; isSelected: (outsideReaction?: boolean) => boolean; - scaling?: () => number; setHeight?: (height: number) => void; - onBrowseClick?: () => (ScriptField | undefined); - onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => (boolean | undefined); + NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to DocumentViewInternalsProps + onBrowseClick?: () => ScriptField | undefined; + onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined; // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) pointerEvents?: () => Opt; @@ -42,7 +42,7 @@ export interface FieldViewProps extends DocumentViewSharedProps { @observer export class FieldView extends React.Component { public static LayoutString(fieldType: { name: string }, fieldStr: string) { - return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "" + return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "" } @computed @@ -75,23 +75,22 @@ export class FieldView extends React.Component { //} else if (field instanceof DateField) { return

{field.date.toLocaleString()}

; - } - else if (field instanceof Doc) { - return

{field.title?.toString()}

; - } - else if (field instanceof List) { - return
{field.length ? field.map(f => Field.toString(f)).join(", ") : ""}
; + } else if (field instanceof Doc) { + return ( +

+ {field.title?.toString()} +

+ ); + } else if (field instanceof List) { + return
{field.length ? field.map(f => Field.toString(f)).join(', ') : ''}
; } // bcz: this belongs here, but it doesn't render well so taking it out for now else if (field instanceof WebField) { return

{Field.toString(field.url.href)}

; - } - else if (!(field instanceof Promise)) { + } else if (!(field instanceof Promise)) { return

{Field.toString(field)}

; - } - else { - return

{"Waiting for server..."}

; + } else { + return

{'Waiting for server...'}

; } } - -} \ No newline at end of file +} diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index ffa839fcb..9590bcb15 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -148,8 +148,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent { const localDelta = this.props .ScreenToLocalTransform() - .scale(this.props.scaling?.() || 1) + .scale(this.props.NativeDimScaling?.() || 1) .transformDirection(delta[0], delta[1]); const fullWidth = this.layoutDoc[WidthSym](); const mapWidth = fullWidth - this.sidebarWidth(); @@ -559,8 +559,8 @@ export class MapBox extends ViewBoxAnnotatableComponent this.props.PanelWidth() / (this.props.scaling?.() || 1) - this.sidebarWidth(); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0); - panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document); + panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth(); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0); + panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document); scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop)); transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()]; opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()]; @@ -589,13 +589,12 @@ export class MapBox extends ViewBoxAnnotatableComponent; return (
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx index 72569135b..630ae18f5 100644 --- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx +++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx @@ -62,7 +62,7 @@ export class MapBoxInfoWindow extends React.Component { const localDelta = this.props .ScreenToLocalTransform() - .scale(this.props.scaling?.() || 1) + .scale(this.props.NativeDimScaling?.() || 1) .transformDirection(delta[0], delta[1]); const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']); const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); - const ratio = (curNativeWidth + ((onButton ? 1 : -1) * localDelta[0]) / (this.props.scaling?.() || 1)) / nativeWidth; + const ratio = (curNativeWidth + ((onButton ? 1 : -1) * localDelta[0]) / (this.props.NativeDimScaling?.() || 1)) / nativeWidth; if (ratio >= 1) { this.layoutDoc.nativeWidth = nativeWidth * ratio; onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]); @@ -433,12 +433,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent 1; isPdfContentActive = () => this.isAnyChildContentActive() || this.props.isSelected(); @computed get renderPdfView() { TraceMobx(); const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; - const scale = previewScale * (this.props.scaling?.() || 1); + const scale = previewScale * (this.props.NativeDimScaling?.() || 1); return (
[this.youtubeVideoId ? this.youtubeContent : this.content]; - scaling = () => this.props.scaling?.() || 1; + scaling = () => this.props.NativeDimScaling?.() || 1; panelWidth = () => (this.props.PanelWidth() * this.heightPercent) / 100; panelHeight = () => (this.layoutDoc._fitWidth ? this.panelWidth() / (Doc.NativeAspect(this.rootDoc) || 1) : (this.props.PanelHeight() * this.heightPercent) / 100); @@ -911,7 +911,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent ((this.props.scaling?.() || 1) * this.heightPercent) / 100; + marqueeFitScaling = () => ((this.props.NativeDimScaling?.() || 1) * this.heightPercent) / 100; marqueeOffset = () => [((this.panelWidth() / 2) * (1 - this.heightPercent / 100)) / (this.heightPercent / 100), 0]; timelineDocFilter = () => [`_timelineLabel:true,${Utils.noRecursionHack}:x`]; @@ -1124,7 +1124,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent { if (autoHeight) { this.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']); - this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']) * (this.props.scaling?.() || 1)); + this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']) * (this.props.NativeDimScaling?.() || 1)); } } ); @@ -276,7 +276,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.createTextAnnotation(sel, !sel.isCollapsed ? sel.getRangeAt(0) : undefined); @@ -322,7 +322,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { const sel = this._iframe?.contentWindow?.getSelection?.(); const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!); - const scale = (this.props.scaling?.() || 1) * mainContBounds.scale; + const scale = (this.props.NativeDimScaling?.() || 1) * mainContBounds.scale; const word = getWordAtPoint(e.target, e.clientX, e.clientY); this._setPreviewCursor?.(e.clientX, e.clientY, false, true); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); @@ -604,7 +604,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { - const nw = !this.layoutDoc.forceReflow ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.scaling?.() || 1); + const nw = !this.layoutDoc.forceReflow ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.NativeDimScaling?.() || 1); this.layoutDoc.forceReflow = !nw; if (nw) { Doc.SetInPlace(this.layoutDoc, this.fieldKey + '-nativeWidth', nw, true); @@ -717,12 +717,12 @@ export class WebBox extends ViewBoxAnnotatableComponent= 1) { this.layoutDoc.nativeWidth = nativeWidth * ratio; this.layoutDoc.nativeHeight = nativeHeight * (1 + ratio); @@ -834,8 +834,8 @@ export class WebBox extends ViewBoxAnnotatableComponent) => (this._searchString = e.currentTarget.value); showInfo = action((anno: Opt) => (this._overlayAnnoInfo = anno)); setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => (this._setPreviewCursor = func); - panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1) - this.sidebarWidth() + WebBox.sidebarResizerWidth; // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0); - panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document); + panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth() + WebBox.sidebarResizerWidth; // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0); + panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document); scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop)); anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter('textInlineAnnotations')]; @@ -852,7 +852,7 @@ export class WebBox extends ViewBoxAnnotatableComponent string[]) => ( this.props.Document._fitContentsToBox; - sidebarContentScaling = () => (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); + sidebarContentScaling = () => (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => { if (!this.layoutDoc._showSidebar) this.toggleSidebar(); // console.log("printting allSideBarDocs"); @@ -1705,7 +1705,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this.props .ScreenToLocalTransform() - .translate(-(this.props.PanelWidth() - this.sidebarWidth()) / (this.props.scaling?.() || 1), 0) + .translate(-(this.props.PanelWidth() - this.sidebarWidth()) / (this.props.NativeDimScaling?.() || 1), 0) .scale(1 / NumCast(this.layoutDoc._viewScale, 1)); @computed get audioHandle() { @@ -1768,7 +1768,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent() { } }; - headerUp = (e: React.PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - }; - /** * Function to drag and drop the pres element to a diferent location */ @@ -477,8 +472,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { })} onPointerOver={this.onPointerOver} onPointerLeave={this.onPointerLeave} - onPointerDown={this.headerDown} - onPointerUp={this.headerUp}> + onPointerDown={this.headerDown}> {/* {miniView ? // when width is LESS than 110 px
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 837734edf..2c83082b7 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -41,7 +41,6 @@ interface IViewerProps extends FieldViewProps { url: string; loaded?: (nw: number, nh: number, np: number) => void; setPdfViewer: (view: PDFViewer) => void; - ContentScaling?: () => number; anchorMenuClick?: () => undefined | ((anchor: Doc) => void); crop: (region: Doc | undefined, addCrop?: boolean) => Doc | undefined; } @@ -97,7 +96,7 @@ export class PDFViewer extends React.Component { autoHeight => { if (autoHeight) { this.props.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']); - this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']) * (this.props.scaling?.() || 1)); + this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']) * (this.props.NativeDimScaling?.() || 1)); } } ); @@ -162,7 +161,7 @@ export class PDFViewer extends React.Component { const mainCont = this._mainCont.current; let focusSpeed: Opt; if (doc !== this.props.rootDoc && mainCont) { - const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1); + const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, 0.1 * windowHeight, NumCast(this.props.Document.scrollHeight)); if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._scrollTop) { focusSpeed = 500; @@ -486,8 +485,8 @@ export class PDFViewer extends React.Component { showInfo = action((anno: Opt) => (this._overlayAnnoInfo = anno)); overlayTransform = () => this.scrollXf().scale(1 / NumCast(this.props.layoutDoc._viewScale, 1)); - panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0); - panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document); + panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0); + panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document); basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter('textInlineAnnotations')]; transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()]; opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()]; @@ -509,7 +508,6 @@ export class PDFViewer extends React.Component { PanelWidth={this.panelWidth} dropAction={'alias'} select={emptyFunction} - ContentScaling={this.contentZoom} bringToFront={emptyFunction} docFilters={docFilters || this.basicFilter} styleProvider={this.childStyleProvider} @@ -556,10 +554,6 @@ export class PDFViewer extends React.Component { @computed get pdfViewerDiv() { return
; } - @computed get contentScaling() { - return this.props.ContentScaling?.() || 1; - } - contentZoom = () => NumCast(this.props.layoutDoc._viewScale, 1); savedAnnotations = () => this._savedAnnotations; render() { TraceMobx(); @@ -574,8 +568,7 @@ export class PDFViewer extends React.Component { onClick={this.onClick} style={{ overflowX: NumCast(this.props.layoutDoc._viewScale, 1) !== 1 ? 'scroll' : undefined, - height: !this.props.Document._fitWidth && window.screen.width > 600 ? Doc.NativeHeight(this.props.Document) : `${100 / this.contentScaling}%`, - transform: `scale(${this.contentScaling})`, + height: !this.props.Document._fitWidth && window.screen.width > 600 ? Doc.NativeHeight(this.props.Document) : `100%`, }}> {this.pdfViewerDiv} {this.annotationLayer} -- cgit v1.2.3-70-g09d2 From e48286293fb37e8af5c448c65c1926e813e8ee1f Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 3 Aug 2022 09:27:21 -0400 Subject: from last --- src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx | 6 +++--- src/client/views/nodes/trails/PresBox.tsx | 1 - src/client/views/nodes/trails/PresElementBox.tsx | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes/trails/PresElementBox.tsx') diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx index 697f8f47f..00bedafbe 100644 --- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx +++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx @@ -42,9 +42,9 @@ export class MapBoxInfoWindow extends React.Component doc.type === DocumentType.RTF; - addDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.AddDocToList(this.props.place, "data", d), true as boolean); - removeDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.RemoveDocFromList(this.props.place, "data", d), true as boolean); + childFitWidth = (doc: Doc) => doc.type === DocumentType.RTF; + addDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.AddDocToList(this.props.place, 'data', d), true as boolean); + removeDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.RemoveDocFromList(this.props.place, 'data', d), true as boolean); render() { return ( diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index dc01d8305..6e5eb3300 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -144,7 +144,6 @@ export class PresBox extends ViewBoxBaseComponent() { return Cast(this.activeItem?.presentationTargetDoc, Doc, null); } @computed get scrollable(): boolean { - //TODO: likely do NOT have to update this for note-taking view, but still worth putting here if (this.targetDoc.type === DocumentType.PDF || this.targetDoc.type === DocumentType.WEB || this.targetDoc.type === DocumentType.RTF || this.targetDoc._viewType === CollectionViewType.Stacking) return true; else return false; } diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 5ac506f21..0cf15d297 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -202,7 +202,6 @@ export class PresElementBox extends ViewBoxBaseComponent() { /** * Function to drag and drop the pres element to a diferent location */ - //TODO: this is what you need to look into startDrag = (e: PointerEvent) => { const miniView: boolean = this.toolbarWidth <= 100; const activeItem = this.rootDoc; -- cgit v1.2.3-70-g09d2 From 5a425e5cf18115921ecb4e7cf931e65f45dab8e2 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 18 Aug 2022 11:18:14 -0400 Subject: fixed up presboxelement to not reference presbox.instance. fixing layout of presboxelement in treeview. fixing "removing" an inkMask without removing it from the collection so that it can be turned on and off. --- src/client/util/CurrentUserUtils.ts | 9 +- src/client/views/DocumentDecorations.tsx | 6 +- src/client/views/PropertiesView.tsx | 5 +- .../views/collections/CollectionTreeView.scss | 11 +- src/client/views/collections/TabDocView.tsx | 4 +- src/client/views/collections/TreeView.scss | 17 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/client/views/nodes/trails/PresBox.tsx | 137 +++++++++------------ src/client/views/nodes/trails/PresElementBox.tsx | 73 ++++++----- 9 files changed, 132 insertions(+), 131 deletions(-) (limited to 'src/client/views/nodes/trails/PresElementBox.tsx') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index dcf4a71c8..f7d072d80 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -289,11 +289,12 @@ export class CurrentUserUtils { { toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, }, { toolTip: "Tap or drag to create a screen grabber", title: "Grab", icon: "photo-video", dragFactory: doc.emptyScreengrab as Doc, scripts: { onClick: 'openInOverlay(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'},funcs: { hidden: 'IsNoviceMode()'} }, { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc, scripts: { onClick: 'openInOverlay(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'},funcs: { hidden: 'IsNoviceMode()'}}, - { toolTip: "Tap or drag to create a button", title: "Button", icon: "bolt", dragFactory: doc.emptyButton as Doc, funcs: { hidden: 'IsNoviceMode()'} }, - { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, funcs: { hidden: 'IsNoviceMode()'}}, + { toolTip: "Tap or drag to create a button", title: "Button", icon: "bolt", dragFactory: doc.emptyButton as Doc, funcs: { hidden: 'IsNoviceMode()'} }, + { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, funcs: { hidden: 'IsNoviceMode()'}}, { toolTip: "Tap or drag to create a data viz node", title: "DataViz", icon: "file", dragFactory: doc.emptyDataViz as Doc, }, - { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize", dragFactory: doc.emptyHeader as Doc, scripts: {onClick: 'openOnRight(delegateDragFactory(this.dragFactory))', onDragStart: '{ return delegateDragFactory(this.dragFactory);}'}, }, - { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", scripts: {onClick: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' } }, + { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "file", dragFactory: doc.emptySlide as Doc, funcs: { hidden: 'IsNoviceMode()'}}, + { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize", dragFactory: doc.emptyHeader as Doc,scripts: { onClick: 'openOnRight(delegateDragFactory(this.dragFactory))', onDragStart: '{ return delegateDragFactory(this.dragFactory);}'}, }, + { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", scripts: { onClick: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' } }, ].map(tuple => ({scripts: {onClick: 'openOnRight(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, ...tuple, })) } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 3544f74b4..6d1397395 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -203,7 +203,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if (this._deleteAfterIconify) { views.forEach(iconView => { Doc.setNativeView(iconView.props.Document); - iconView.props.removeDocument?.(iconView.props.Document); + if (iconView.props.Document.isInkMask && iconView.props.Document.activeFrame !== undefined) { + iconView.props.Document.opacity = 0; // bcz: hacky ... allows inkMaks to be "turned off" without removing them from the collection which allows them to function properly in a presenation. + } else { + iconView.props.removeDocument?.(iconView.props.Document); + } }); SelectionManager.DeselectAll(); } diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index ef0e057dc..33f17047b 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -15,7 +15,7 @@ import { ComputedField } from '../../fields/ScriptField'; import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { denormalizeEmail, GetEffectiveAcl, SharingPermissions } from '../../fields/util'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from '../../Utils'; -import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; +import { DocumentType } from '../documents/DocumentTypes'; import { DocumentManager } from '../util/DocumentManager'; import { LinkManager } from '../util/LinkManager'; import { SelectionManager } from '../util/SelectionManager'; @@ -1614,9 +1614,6 @@ export class PropertiesView extends React.Component { if (this.isPres) { const selectedItem: boolean = PresBox.Instance?._selectedArray.size > 0; const type = PresBox.Instance.activeItem?.type; - const viewType = PresBox.Instance.activeItem?._viewType; - const pannable: boolean = (type === DocumentType.COL && viewType === CollectionViewType.Freeform) || type === DocumentType.IMG; - const scrollable: boolean = type === DocumentType.PDF || type === DocumentType.WEB || type === DocumentType.RTF || viewType === CollectionViewType.Stacking || viewType === CollectionViewType.NoteTaking; return (
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 93523a6cf..c0561e42c 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -1,6 +1,5 @@ -@import "../global/globalCssVariables"; +@import '../global/globalCssVariables'; - .collectionTreeView-container { transform-origin: top left; height: 100%; @@ -28,7 +27,7 @@ list-style: none; padding-left: $TREE_BULLET_WIDTH; margin-bottom: 1px; // otherwise vertical scrollbars may pop up for no apparent reason.... - > .contentFittingDocumentView { + > .contentFittingDocumentView { width: unset; height: unset; } @@ -39,7 +38,7 @@ .no-indent { padding-left: 0; - width: max-content; + //width: max-content; } .no-indent-outline { @@ -85,7 +84,7 @@ width: 100%; height: max-content; .contentFittingDocumentView { - display: block; // makes titleBar take up full width of the treeView (flex doesn't for some reason) + display: block; // makes titleBar take up full width of the treeView (flex doesn't for some reason) } } @@ -114,4 +113,4 @@ padding-left: 3px; padding-right: 3px; padding-bottom: 2px; -} \ No newline at end of file +} diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index ff4b1e2ce..e147f34d2 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -299,8 +299,8 @@ export class TabDocView extends React.Component { pinDoc.presMovement = PresMovement.None; } if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; - PresBox.Instance?._selectedArray.clear(); - pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array + PresBox.Instance?.clearSelectedArray(); + pinDoc && PresBox.Instance?.addToSelectedArray(pinDoc); //Update selected array }); if ( CollectionDockingView.Instance && diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss index f587dbbf6..ce87e6f89 100644 --- a/src/client/views/collections/TreeView.scss +++ b/src/client/views/collections/TreeView.scss @@ -1,4 +1,4 @@ -@import "../global/globalCssVariables"; +@import '../global/globalCssVariables'; .treeView-label { max-height: 1.5em; @@ -21,7 +21,7 @@ } .treeView-bulletIcons { - // width: $TREE_BULLET_WIDTH; + // width: $TREE_BULLET_WIDTH; width: 100%; height: 100%; @@ -101,6 +101,9 @@ .treeView-border { display: flex; overflow: hidden; + > ul { + width: 100%; + } } .treeView-border { @@ -118,7 +121,6 @@ } .formattedTextBox-cont { - .formattedTextbox-sidebar, .formattedTextbox-sidebar-inking { overflow: visible !important; @@ -144,12 +146,12 @@ pointer-events: all; cursor: pointer; - >svg { + > svg { margin-left: 0.25rem; margin-right: 0.25rem; } - >svg { + > svg { //display: none; opacity: 0; pointer-events: none; @@ -176,8 +178,7 @@ } .treeView-rightButtons { - - >svg, + > svg, .styleProvider-treeView-icon { display: inherit; opacity: unset; @@ -196,4 +197,4 @@ .treeView-header-inside { border: black 1px solid; -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 45a5e30ff..0fd326091 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -251,6 +251,7 @@ export class CollectionFreeFormView extends CollectionSubView() { delay: presDoc.presTransition, // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc, }; + //prettier-ignore switch (presDoc.presEffect) { - case PresEffect.Zoom: - return {renderDoc}; - case PresEffect.Fade: - return {renderDoc}; - case PresEffect.Flip: - return {renderDoc}; - case PresEffect.Rotate: - return {renderDoc}; - case PresEffect.Bounce: - return {renderDoc}; - case PresEffect.Roll: - return {renderDoc}; - case PresEffect.Lightspeed: - return {renderDoc}; - case PresEffect.None: - default: - return renderDoc; + default: + case PresEffect.None: return renderDoc; + case PresEffect.Zoom: return {renderDoc}; + case PresEffect.Fade: return {renderDoc}; + case PresEffect.Flip: return {renderDoc}; + case PresEffect.Rotate: return {renderDoc}; + case PresEffect.Bounce: return {renderDoc}; + case PresEffect.Roll: return {renderDoc}; + case PresEffect.Lightspeed: return {renderDoc}; } } public static EffectsProvider(layoutDoc: Doc, renderDoc: any) { return PresBox.Instance && layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc ? PresBox.renderEffectsDoc(renderDoc, layoutDoc, PresBox.Instance.childDocs[PresBox.Instance.itemIndex]) : renderDoc; } + private _disposers: { [name: string]: IReactionDisposer } = {}; + + constructor(props: any) { + super(props); + if ((Doc.ActivePresentation = this.rootDoc)) runInAction(() => (PresBox.Instance = this)); + this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox + } + @observable public static Instance: PresBox; @observable _isChildActive = false; @@ -98,14 +99,11 @@ export class PresBox extends ViewBoxBaseComponent() { @observable _presTimer!: NodeJS.Timeout; @observable _presKeyEventsActive: boolean = false; - @observable _selectedArray: ObservableMap = new ObservableMap(); @observable _eleArray: HTMLElement[] = []; @observable _dragArray: HTMLElement[] = []; @observable _pathBoolean: boolean = false; @observable _expandBoolean: boolean = false; - private _disposers: { [name: string]: IReactionDisposer } = {}; - @observable static startMarquee: boolean = false; // onclick "+ new slide" in presentation mode, set as true, then when marquee selection finish, onPointerUp automatically triggers PinWithView @observable private transitionTools: boolean = false; @observable private newDocumentTools: boolean = false; @@ -152,11 +150,6 @@ export class PresBox extends ViewBoxBaseComponent() { if ((this.targetDoc.type === DocumentType.COL && this.targetDoc._viewType === CollectionViewType.Freeform) || this.targetDoc.type === DocumentType.IMG) return true; else return false; } - constructor(props: any) { - super(props); - if ((Doc.ActivePresentation = this.rootDoc)) runInAction(() => (PresBox.Instance = this)); - this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox - } @computed get selectedDocumentView() { if (SelectionManager.Views().length) return SelectionManager.Views()[0]; if (this._selectedArray.size) return DocumentManager.Instance.getDocumentView(this.rootDoc); @@ -173,6 +166,10 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; } + _selectedArray = new ObservableSet(); + clearSelectedArray = () => this._selectedArray.clear(); + addToSelectedArray = (doc: Doc) => this._selectedArray.add(doc); + removeFromSelectedArray = (doc: Doc) => this._selectedArray.delete(doc); _unmounting = false; @action @@ -188,6 +185,7 @@ export class PresBox extends ViewBoxBaseComponent() { @action componentDidMount() { + this.props.setContentView?.(this); this._unmounting = false; this.rootDoc._forceRenderEngine = 'timeline'; this.layoutDoc.presStatus = PresStatus.Edit; @@ -344,8 +342,8 @@ export class PresBox extends ViewBoxBaseComponent() { if (targetDoc?.lastFrame !== undefined) { targetDoc._currentFrame = 0; } - if (!group) this._selectedArray.clear(); - this.childDocs[index] && this._selectedArray.set(this.childDocs[index], undefined); //Update selected array + if (!group) this.clearSelectedArray(); + this.childDocs[index] && this.addToSelectedArray(this.childDocs[index]); //Update selected array this.navigateToElement(this.childDocs[index]); //Handles movement to element only when presTrail is list this.onHideDocument(); //Handles hide after/before } @@ -415,7 +413,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.layoutDoc.presCollection = srcContext; } const presStatus = this.rootDoc.presStatus; - const selViewCache = Array.from(this._selectedArray.keys()); + const selViewCache = Array.from(this._selectedArray); const dragViewCache = Array.from(this._dragArray); const eleViewCache = Array.from(this._eleArray); const self = this; @@ -423,8 +421,8 @@ export class PresBox extends ViewBoxBaseComponent() { const presDocView = DocumentManager.Instance.getDocumentView(self.rootDoc); if (presDocView) SelectionManager.SelectView(presDocView, false); self.rootDoc.presStatus = presStatus; - self._selectedArray.clear(); - selViewCache.forEach(doc => self._selectedArray.set(doc, undefined)); + self.clearSelectedArray(); + selViewCache.forEach(doc => self.addToSelectedArray(doc)); self._dragArray.splice(0, self._dragArray.length, ...dragViewCache); self._eleArray.splice(0, self._eleArray.length, ...eleViewCache); }); @@ -792,7 +790,7 @@ export class PresBox extends ViewBoxBaseComponent() { * Method to get the list of selected items in the order in which they have been selected */ @computed get listOfSelected() { - const list = Array.from(this._selectedArray.keys()).map((doc: Doc, index: any) => { + return Array.from(this._selectedArray).map((doc: Doc, index: any) => { const curDoc = Cast(doc, Doc, null); const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); if (curDoc && curDoc === this.activeItem) @@ -816,7 +814,6 @@ export class PresBox extends ViewBoxBaseComponent() {
); }); - return list; } @action @@ -838,11 +835,11 @@ export class PresBox extends ViewBoxBaseComponent() { @action multiSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => { if (!this._selectedArray.has(doc)) { - this._selectedArray.set(doc, undefined); + this.addToSelectedArray(doc); this._eleArray.push(ref); this._dragArray.push(drag); } else { - this._selectedArray.delete(doc); + this.removeFromSelectedArray(doc); this.removeFromArray(this._eleArray, doc); this.removeFromArray(this._dragArray, doc); } @@ -858,11 +855,11 @@ export class PresBox extends ViewBoxBaseComponent() { //Shift click @action shiftSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => { - this._selectedArray.clear(); + this.clearSelectedArray(); // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); if (this.activeItem) { for (let i = Math.min(this.itemIndex, this.childDocs.indexOf(doc)); i <= Math.max(this.itemIndex, this.childDocs.indexOf(doc)); i++) { - this._selectedArray.set(this.childDocs[i], undefined); + this.addToSelectedArray(this.childDocs[i]); this._eleArray.push(ref); this._dragArray.push(drag); } @@ -873,8 +870,8 @@ export class PresBox extends ViewBoxBaseComponent() { //regular click @action regularSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean, selectPres = true) => { - this._selectedArray.clear(); - this._selectedArray.set(doc, undefined); + this.clearSelectedArray(); + this.addToSelectedArray(doc); this._eleArray.splice(0, this._eleArray.length, ref); this._dragArray.splice(0, this._dragArray.length, drag); focus && this.selectElement(doc); @@ -903,10 +900,10 @@ export class PresBox extends ViewBoxBaseComponent() { if (this.layoutDoc.presStatus === 'edit') { undoBatch( action(() => { - for (const doc of Array.from(this._selectedArray.keys())) { + for (const doc of this._selectedArray) { this.removeDocument(doc); } - this._selectedArray.clear(); + this.clearSelectedArray(); this._eleArray.length = 0; this._dragArray.length = 0; }) @@ -918,7 +915,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) { this.updateMinimize(); } else if (this.layoutDoc.presStatus === 'edit') { - this._selectedArray.clear(); + this.clearSelectedArray(); this._eleArray.length = this._dragArray.length = 0; } else this.layoutDoc.presStatus = 'edit'; if (this._presTimer) clearTimeout(this._presTimer); @@ -931,7 +928,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (e.shiftKey && this.itemIndex < this.childDocs.length - 1) { // TODO: update to work properly this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) + 1; - this._selectedArray.set(this.childDocs[this.rootDoc._itemIndex], undefined); + this.addToSelectedArray(this.childDocs[this.rootDoc._itemIndex]); } else { this.next(); if (this._presTimer) { @@ -948,7 +945,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (e.shiftKey && this.itemIndex !== 0) { // TODO: update to work properly this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) - 1; - this._selectedArray.set(this.childDocs[this.rootDoc._itemIndex], undefined); + this.addToSelectedArray(this.childDocs[this.rootDoc._itemIndex]); } else { this.back(); if (this._presTimer) { @@ -966,8 +963,8 @@ export class PresBox extends ViewBoxBaseComponent() { break; case 'a': if ((e.metaKey || e.altKey) && this.layoutDoc.presStatus === 'edit') { - this._selectedArray.clear(); - this.childDocs.forEach(doc => this._selectedArray.set(doc, undefined)); + this.clearSelectedArray(); + this.childDocs.forEach(doc => this.addToSelectedArray(doc)); handled = true; } default: @@ -1115,7 +1112,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; if (timeInMS > 10000) timeInMS = 10000; - Array.from(this._selectedArray.keys()).forEach(doc => (doc.presTransition = timeInMS)); + this._selectedArray.forEach(doc => (doc.presTransition = timeInMS)); }; // Converts seconds to ms and updates presTransition @@ -1124,7 +1121,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (change) scale += change; if (scale < 0.01) scale = 0.01; if (scale > 1.5) scale = 1.5; - Array.from(this._selectedArray.keys()).forEach(doc => (doc.presZoom = scale)); + this._selectedArray.forEach(doc => (doc.presZoom = scale)); }; // Converts seconds to ms and updates presDuration @@ -1133,7 +1130,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; if (timeInMS > 20000) timeInMS = 20000; - Array.from(this._selectedArray.keys()).forEach(doc => (doc.presDuration = timeInMS)); + this._selectedArray.forEach(doc => (doc.presDuration = timeInMS)); }; /** @@ -1141,8 +1138,7 @@ export class PresBox extends ViewBoxBaseComponent() { */ @undoBatch updateMovement = action((movement: any, all?: boolean) => { - const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys()); - array.forEach(doc => { + (all ? this.childDocs : this._selectedArray).forEach(doc => { switch (movement) { case PresMovement.Zoom: //Pan and zoom doc.presMovement = PresMovement.Zoom; @@ -1166,21 +1162,21 @@ export class PresBox extends ViewBoxBaseComponent() { @action updateHideBefore = (activeItem: Doc) => { activeItem.presHideBefore = !activeItem.presHideBefore; - Array.from(this._selectedArray.keys()).forEach(doc => (doc.presHideBefore = activeItem.presHideBefore)); + this._selectedArray.forEach(doc => (doc.presHideBefore = activeItem.presHideBefore)); }; @undoBatch @action updateHideAfter = (activeItem: Doc) => { activeItem.presHideAfter = !activeItem.presHideAfter; - Array.from(this._selectedArray.keys()).forEach(doc => (doc.presHideAfter = activeItem.presHideAfter)); + this._selectedArray.forEach(doc => (doc.presHideAfter = activeItem.presHideAfter)); }; @undoBatch @action updateOpenDoc = (activeItem: Doc) => { activeItem.openDocument = !activeItem.openDocument; - Array.from(this._selectedArray.keys()).forEach(doc => { + this._selectedArray.forEach(doc => { doc.openDocument = activeItem.openDocument; }); }; @@ -1188,8 +1184,7 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch @action updateEffectDirection = (effect: any, all?: boolean) => { - const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys()); - array.forEach(doc => { + (all ? this.childDocs : this._selectedArray).forEach(doc => { const tagDoc = doc; // Cast(doc.presentationTargetDoc, Doc, null); switch (effect) { case PresEffect.Left: @@ -1215,29 +1210,17 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch @action updateEffect = (effect: any, all?: boolean) => { - const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys()); - array.forEach(doc => { + (all ? this.childDocs : this._selectedArray).forEach(doc => { const tagDoc = doc; //Cast(doc.presentationTargetDoc, Doc, null); + //prettier-ignore switch (effect) { - case PresEffect.Bounce: - tagDoc.presEffect = PresEffect.Bounce; - break; - case PresEffect.Fade: - tagDoc.presEffect = PresEffect.Fade; - break; - case PresEffect.Flip: - tagDoc.presEffect = PresEffect.Flip; - break; - case PresEffect.Roll: - tagDoc.presEffect = PresEffect.Roll; - break; - case PresEffect.Rotate: - tagDoc.presEffect = PresEffect.Rotate; - break; - case PresEffect.None: default: - tagDoc.presEffect = PresEffect.None; - break; + case PresEffect.None: tagDoc.presEffect = PresEffect.None; break; + case PresEffect.Bounce: tagDoc.presEffect = PresEffect.Bounce; break; + case PresEffect.Fade: tagDoc.presEffect = PresEffect.Fade; break; + case PresEffect.Flip: tagDoc.presEffect = PresEffect.Flip; break; + case PresEffect.Roll: tagDoc.presEffect = PresEffect.Roll; break; + case PresEffect.Rotate: tagDoc.presEffect = PresEffect.Rotate; break; } }); }; diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 0cf15d297..3af8cad9a 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -47,6 +47,13 @@ export class PresElementBox extends ViewBoxBaseComponent() { @computed get presStatus() { return this.presBox.presStatus; } + @computed get selectedArray() { + return this.presBoxView?._selectedArray; + } + @computed get presBoxView() { + const vpath = this.props.docViewPath(); + return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as PresBox) : undefined; + } @computed get presBox() { return (this.props.DocumentView?.().props.treeViewDoc ?? this.props.ContainingCollectionDoc)!; } @@ -129,10 +136,9 @@ export class PresElementBox extends ViewBoxBaseComponent() {
{ - console.log('Clicked on slide with index: ', ind); e.stopPropagation(); e.preventDefault(); - PresBox.Instance.modifierSelect(doc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey); + this.presBoxView?.modifierSelect(doc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey); this.presExpandDocumentClick(); }}>
{`${ind + 1}.`}
@@ -181,15 +187,15 @@ export class PresElementBox extends ViewBoxBaseComponent() { e.stopPropagation(); e.preventDefault(); if (element && !(e.ctrlKey || e.metaKey)) { - if (PresBox.Instance._selectedArray.has(this.rootDoc)) { - PresBox.Instance._selectedArray.size === 1 && PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false, false); + if (this.selectedArray?.has(this.rootDoc)) { + this.selectedArray.size === 1 && this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false, false); setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction); } else { setupMoveUpEvents( this, e, (e: PointerEvent) => { - PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false, false); + this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false, false); return this.startDrag(e); }, emptyFunction, @@ -205,8 +211,8 @@ export class PresElementBox extends ViewBoxBaseComponent() { startDrag = (e: PointerEvent) => { const miniView: boolean = this.toolbarWidth <= 100; const activeItem = this.rootDoc; - const dragArray = PresBox.Instance._dragArray; - const dragData = new DragManager.DocumentDragData(PresBox.Instance.sortArray()); + const dragArray = this.presBoxView?._dragArray ?? []; + const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []); if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.rootDoc); dragData.dropAction = 'move'; dragData.treeViewDoc = this.props.docViewPath().lastElement()?.props.treeViewDoc; @@ -221,7 +227,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { } else if (dragArray.length >= 1) { const doc = document.createElement('div'); doc.className = 'presItem-multiDrag'; - doc.innerText = 'Move ' + PresBox.Instance._selectedArray.size + ' slides'; + doc.innerText = 'Move ' + this.selectedArray?.size + ' slides'; doc.style.position = 'absolute'; doc.style.top = e.clientY + 'px'; doc.style.left = e.clientX - 50 + 'px'; @@ -286,10 +292,11 @@ export class PresElementBox extends ViewBoxBaseComponent() { @undoBatch removeItem = action((e: React.MouseEvent) => { e.stopPropagation(); - this.props.removeDocument?.(this.rootDoc); - if (PresBox.Instance._selectedArray.has(this.rootDoc)) { - PresBox.Instance._selectedArray.delete(this.rootDoc); + if (this.indexInPres < (this.presBoxView?.itemIndex || 0)) { + this.presBox.itemIndex = (this.presBoxView?.itemIndex || 0) - 1; } + this.props.removeDocument?.(this.rootDoc); + this.presBoxView?.removeFromSelectedArray(this.rootDoc); this.removeAllRecordingInOverlay(); }); @@ -441,7 +448,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { } @computed get mainItem() { - const isSelected: boolean = PresBox.Instance?._selectedArray.has(this.rootDoc); + const isSelected: boolean = this.selectedArray?.has(this.rootDoc) ? true : false; const toolbarWidth: number = this.toolbarWidth; const showMore: boolean = this.toolbarWidth >= 300; const miniView: boolean = this.toolbarWidth <= 110; @@ -463,12 +470,12 @@ export class PresElementBox extends ViewBoxBaseComponent() { onClick={e => { e.stopPropagation(); e.preventDefault(); - PresBox.Instance.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey); + this.presBoxView?.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey); this.showRecording(activeItem); }} onDoubleClick={action(e => { this.toggleProperties(); - PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true); + this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true); })} onPointerOver={this.onPointerOver} onPointerLeave={this.onPointerLeave} @@ -542,21 +549,29 @@ export class PresElementBox extends ViewBoxBaseComponent() { )} - {/* {this.indexInPres === 0 ? (null) :
{activeItem.groupWithUp ? "Ungroup" : "Group with up"}
}> -
activeItem.groupWithUp = !activeItem.groupWithUp} - style={{ - zIndex: 1000 - this.indexInPres, - fontWeight: 700, - backgroundColor: activeItem.groupWithUp ? presColorBool ? presBoxColor : Colors.MEDIUM_BLUE : undefined, - height: activeItem.groupWithUp ? 53 : 18, - transform: activeItem.groupWithUp ? "translate(0, -17px)" : undefined - }}> -
- e.stopPropagation()} /> -
-
-
} */} + {this.indexInPres === 0 ? null : ( + +
{activeItem.groupWithUp ? 'Ungroup' : 'Group with up'}
+ + }> +
(activeItem.groupWithUp = !activeItem.groupWithUp)} + style={{ + zIndex: 1000 - this.indexInPres, + fontWeight: 700, + backgroundColor: activeItem.groupWithUp ? (presColorBool ? presBoxColor : Colors.MEDIUM_BLUE) : undefined, + height: activeItem.groupWithUp ? 53 : 18, + transform: activeItem.groupWithUp ? 'translate(0, -17px)' : undefined, + }}> +
+ e.stopPropagation()} /> +
+
+
+ )} -- cgit v1.2.3-70-g09d2 From 53dc1ae6077774a7235f2fe7f56ffa03f8a9aa5a Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 19 Aug 2022 09:21:28 -0400 Subject: fixed undo bug in dragManager where batches weren't being closed. fixed schemaheader copy method to copy all parameters. fixed notetaking columnresizer to create an UndoBatch. fixed notetakingview's columnHeaders to return the actual headers list, not a copy. fixed document decorations to not modify docsBeingDragged --- src/client/util/DragManager.ts | 2 +- src/client/views/DocumentDecorations.tsx | 4 +- .../views/collections/CollectionNoteTakingView.tsx | 20 ++--- .../CollectionNoteTakingViewDivider.tsx | 37 +++++---- .../views/collections/CollectionStackingView.tsx | 2 - src/client/views/nodes/trails/PresElementBox.tsx | 5 +- src/fields/SchemaHeaderField.ts | 92 +++++++++++----------- 7 files changed, 75 insertions(+), 87 deletions(-) (limited to 'src/client/views/nodes/trails/PresElementBox.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 947882958..eef5b9ce1 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -457,7 +457,7 @@ export namespace DragManager { document.removeEventListener('pointerup', upHandler, true); SnappingManager.SetIsDragging(false); SnappingManager.clearSnapLines(); - if (undo && batch.end()) UndoManager.Undo(); + if (batch.end() && undo) UndoManager.Undo(); docsBeingDragged.length = 0; }); var startWindowDragTimer: any; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 0db9eab69..a8dacff51 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -351,8 +351,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P @action onPointerDown = (e: React.PointerEvent): void => { - DragManager.docsBeingDragged.push(...SelectionManager.Views().map(dv => dv.rootDoc)); - this._inkDragDocs = DragManager.docsBeingDragged + const views = SelectionManager.Views().map(dv => dv.rootDoc); + this._inkDragDocs = views .filter(doc => doc.type === DocumentType.INK) .map(doc => { if (InkStrokeProperties.Instance._lock) { diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 447e1f0c8..0c5f69db0 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -53,7 +53,7 @@ export class CollectionNoteTakingView extends CollectionSubView !d[this.notetakingCategoryField] && !columnHeaders.find(sh => sh.heading === 'unset')); // @#Oberable draggedColIndex = ... @@ -142,17 +142,11 @@ export class CollectionNoteTakingView extends CollectionSubView !DragManager.docsBeingDragged.includes(d)); const sections = new Map(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []])); const rowCol = this.docsDraggedRowCol; - // filter out the currently dragged docs from the child docs, since we will insert them later - if (rowCol.length && DragManager.docsBeingDragged.length) { - const docIdsToRemove = new Set(); - DragManager.docsBeingDragged.forEach(d => docIdsToRemove.add(d[Id])); - docs = docs.filter(d => !docIdsToRemove.has(d[Id])); - } - // this will sort the docs into the correct columns (minus the ones you're currently dragging) docs.map(d => { const sectionValue = (d[this.notetakingCategoryField] as object) ?? `unset`; @@ -165,11 +159,10 @@ export class CollectionNoteTakingView extends CollectionSubView { + setColumnStartXCoords = (movementXScreen: number, colIndex: number) => { + const movementX = this.props.ScreenToLocalTransform().transformDirection(movementXScreen, 0)[0]; const leftHeader = this.columnHeaders[colIndex]; const rightHeader = this.columnHeaders[colIndex + 1]; leftHeader.setWidth(leftHeader.width + movementX / this.availableWidth); diff --git a/src/client/views/collections/CollectionNoteTakingViewDivider.tsx b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx index 7d31b3193..2633bffeb 100644 --- a/src/client/views/collections/CollectionNoteTakingViewDivider.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx @@ -1,5 +1,8 @@ import { action, observable } from 'mobx'; import * as React from 'react'; +import { emptyFunction, setupMoveUpEvents } from '../../../Utils'; +import { Transform } from '../../util/Transform'; +import { UndoManager } from '../../util/UndoManager'; interface DividerProps { index: number; @@ -13,28 +16,24 @@ export class CollectionNoteTakingViewDivider extends React.Component) => { - e.stopPropagation(); - e.preventDefault(); - window.removeEventListener('pointermove', this.onPointerMove); - window.removeEventListener('pointerup', this.onPointerUp); - window.addEventListener('pointermove', this.onPointerMove); - window.addEventListener('pointerup', this.onPointerUp); + const batch = UndoManager.StartBatch('resizing'); + setupMoveUpEvents( + this, + e, + (e, down, delta) => { + this.props.setColumnStartXCoords(delta[0], this.props.index); + return false; + }, + action(() => { + this.isResizingActive = false; + this.isHoverActive = false; + batch.end(); + }), + emptyFunction + ); this.isResizingActive = true; }; - @action - private onPointerUp = () => { - this.isResizingActive = false; - this.isHoverActive = false; - window.removeEventListener('pointermove', this.onPointerMove); - window.removeEventListener('pointerup', this.onPointerUp); - }; - - @action - onPointerMove = ({ movementX }: PointerEvent) => { - this.props.setColumnStartXCoords(movementX, this.props.index); - }; - render() { return (
docs.indexOf(ndoc) !== -1).forEach(ndoc => docs.splice(docs.indexOf(ndoc), 1)); docs.splice(insertInd - offset, 0, ...newDocs); } - // reset drag manager docs, because we just dropped - DragManager.docsBeingDragged.length = 0; } } else if (de.complete.linkDragData?.dragDocument.context === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) { const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _fitWidth: true, title: 'dropped annotation' }); diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 0cf15d297..c578f8bcf 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -250,10 +250,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { onPointerMove = (e: PointerEvent) => { const slide = this._itemRef.current!; - let dragIsPresItem: boolean = DragManager.docsBeingDragged.length > 0 ? true : false; - for (const doc of DragManager.docsBeingDragged) { - if (!doc.presentationTargetDoc) dragIsPresItem = false; - } + const dragIsPresItem = DragManager.docsBeingDragged.some(d => d.presentationTargetDoc); if (slide && dragIsPresItem) { const rect = slide.getBoundingClientRect(); const y = e.clientY - rect.top; //y position within the element. diff --git a/src/fields/SchemaHeaderField.ts b/src/fields/SchemaHeaderField.ts index 3b02d0cfe..1321bc327 100644 --- a/src/fields/SchemaHeaderField.ts +++ b/src/fields/SchemaHeaderField.ts @@ -1,60 +1,60 @@ -import { Deserializable } from "../client/util/SerializationHelper"; -import { serializable, primitive } from "serializr"; -import { ObjectField } from "./ObjectField"; -import { Copy, ToScriptString, ToString, OnUpdate } from "./FieldSymbols"; -import { scriptingGlobal } from "../client/util/ScriptingGlobals"; -import { ColumnType } from "../client/views/collections/collectionSchema/CollectionSchemaView"; +import { Deserializable } from '../client/util/SerializationHelper'; +import { serializable, primitive } from 'serializr'; +import { ObjectField } from './ObjectField'; +import { Copy, ToScriptString, ToString, OnUpdate } from './FieldSymbols'; +import { scriptingGlobal } from '../client/util/ScriptingGlobals'; +import { ColumnType } from '../client/views/collections/collectionSchema/CollectionSchemaView'; export const PastelSchemaPalette = new Map([ // ["pink1", "#FFB4E8"], - ["pink2", "#ff9cee"], - ["pink3", "#ffccf9"], - ["pink4", "#fcc2ff"], - ["pink5", "#f6a6ff"], - ["purple1", "#b28dff"], - ["purple2", "#c5a3ff"], - ["purple3", "#d5aaff"], - ["purple4", "#ecd4ff"], + ['pink2', '#ff9cee'], + ['pink3', '#ffccf9'], + ['pink4', '#fcc2ff'], + ['pink5', '#f6a6ff'], + ['purple1', '#b28dff'], + ['purple2', '#c5a3ff'], + ['purple3', '#d5aaff'], + ['purple4', '#ecd4ff'], // ["purple5", "#fb34ff"], - ["purple6", "#dcd3ff"], - ["purple7", "#a79aff"], - ["purple8", "#b5b9ff"], - ["purple9", "#97a2ff"], - ["bluegreen1", "#afcbff"], - ["bluegreen2", "#aff8db"], - ["bluegreen3", "#c4faf8"], - ["bluegreen4", "#85e3ff"], - ["bluegreen5", "#ace7ff"], + ['purple6', '#dcd3ff'], + ['purple7', '#a79aff'], + ['purple8', '#b5b9ff'], + ['purple9', '#97a2ff'], + ['bluegreen1', '#afcbff'], + ['bluegreen2', '#aff8db'], + ['bluegreen3', '#c4faf8'], + ['bluegreen4', '#85e3ff'], + ['bluegreen5', '#ace7ff'], // ["bluegreen6", "#6eb5ff"], - ["bluegreen7", "#bffcc6"], - ["bluegreen8", "#dbffd6"], - ["yellow1", "#f3ffe3"], - ["yellow2", "#e7ffac"], - ["yellow3", "#ffffd1"], - ["yellow4", "#fff5ba"], + ['bluegreen7', '#bffcc6'], + ['bluegreen8', '#dbffd6'], + ['yellow1', '#f3ffe3'], + ['yellow2', '#e7ffac'], + ['yellow3', '#ffffd1'], + ['yellow4', '#fff5ba'], // ["red1", "#ffc9de"], - ["red2", "#ffabab"], - ["red3", "#ffbebc"], - ["red4", "#ffcbc1"], - ["orange1", "#ffd5b3"], - ["gray", "#f1efeb"] + ['red2', '#ffabab'], + ['red3', '#ffbebc'], + ['red4', '#ffcbc1'], + ['orange1', '#ffd5b3'], + ['gray', '#f1efeb'], ]); export const RandomPastel = () => Array.from(PastelSchemaPalette.values())[Math.floor(Math.random() * PastelSchemaPalette.size)]; export const DarkPastelSchemaPalette = new Map([ - ["pink2", "#c932b0"], - ["purple4", "#913ad6"], - ["bluegreen1", "#3978ed"], - ["bluegreen7", "#2adb3e"], - ["bluegreen5", "#21b0eb"], - ["yellow4", "#edcc0c"], - ["red2", "#eb3636"], - ["orange1", "#f2740f"], + ['pink2', '#c932b0'], + ['purple4', '#913ad6'], + ['bluegreen1', '#3978ed'], + ['bluegreen7', '#2adb3e'], + ['bluegreen5', '#21b0eb'], + ['yellow4', '#edcc0c'], + ['red2', '#eb3636'], + ['orange1', '#f2740f'], ]); @scriptingGlobal -@Deserializable("schemaheader") +@Deserializable('schemaheader') export class SchemaHeaderField extends ObjectField { @serializable(primitive()) heading: string; @@ -69,7 +69,7 @@ export class SchemaHeaderField extends ObjectField { @serializable(primitive()) desc: boolean | undefined; // boolean determines sort order, undefined when no sort - constructor(heading: string = "", color: string = RandomPastel(), type?: ColumnType, width?: number, desc?: boolean, collapsed?: boolean) { + constructor(heading: string = '', color: string = RandomPastel(), type?: ColumnType, width?: number, desc?: boolean, collapsed?: boolean) { super(); this.heading = heading; @@ -111,7 +111,7 @@ export class SchemaHeaderField extends ObjectField { } [Copy]() { - return new SchemaHeaderField(this.heading, this.color, this.type); + return new SchemaHeaderField(this.heading, this.color, this.type, this.width, this.desc, this.collapsed); } [ToScriptString]() { @@ -120,4 +120,4 @@ export class SchemaHeaderField extends ObjectField { [ToString]() { return `SchemaHeaderField`; } -} \ No newline at end of file +} -- cgit v1.2.3-70-g09d2 From 94dbcc40067cb6637f7a535ff305d9452a3f40d1 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 24 Aug 2022 14:07:41 -0400 Subject: made text boxes support animation frames. fixed dragging on unselected pres element ttitles. cleaned up setting ink to have animation frames. --- src/client/documents/Documents.ts | 3 ++- src/client/views/InkStrokeProperties.ts | 10 +--------- src/client/views/InkingStroke.tsx | 11 ----------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 19 ++++++++++++++++--- src/client/views/nodes/trails/PresElementBox.tsx | 8 +++++++- src/fields/ScriptField.ts | 12 +++++++++++- 6 files changed, 37 insertions(+), 26 deletions(-) (limited to 'src/client/views/nodes/trails/PresElementBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index e579bfd8a..7c50f21a5 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1716,7 +1716,8 @@ export namespace DocUtils { .replace(/\.[a-z0-9]*$/, ''); if (Upload.isImageInformation(result)) { const maxNativeDim = Math.min(Math.max(result.nativeHeight, result.nativeWidth), defaultNativeImageDim); - proto['data-nativeOrientation'] = result.exifData?.data?.image?.Orientation ?? (StrCast((result.exifData?.data as any)?.Orientation).includes('Rotate 90') ? 5 : undefined); + const exifRotation = StrCast((result.exifData?.data as any)?.Orientation).toLowerCase(); + proto['data-nativeOrientation'] = result.exifData?.data?.image?.Orientation ?? (exifRotation.includes('rotate 90') || exifRotation.includes('rotate 270') ? 5 : undefined); proto['data-nativeWidth'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim; proto['data-nativeHeight'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight); if (NumCast(proto['data-nativeOrientation']) >= 5) { diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 1f5f16592..d19a916f9 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -4,7 +4,6 @@ import { Doc, NumListCast, Opt } from '../../fields/Doc'; import { InkData, InkField, InkTool, PointData } from '../../fields/InkField'; import { List } from '../../fields/List'; import { listSpec } from '../../fields/Schema'; -import { ComputedField } from '../../fields/ScriptField'; import { Cast, NumCast } from '../../fields/Types'; import { Point } from '../../pen-gestures/ndollar'; import { DocumentType } from '../documents/DocumentTypes'; @@ -12,7 +11,6 @@ import { FitOneCurve } from '../util/bezierFit'; import { DocumentManager } from '../util/DocumentManager'; import { undoBatch } from '../util/UndoManager'; import { InkingStroke } from './InkingStroke'; -import { CollectionFreeFormDocumentView } from './nodes/CollectionFreeFormDocumentView'; import { DocumentView } from './nodes/DocumentView'; export class InkStrokeProperties { @@ -67,13 +65,7 @@ export class InkStrokeProperties { doc._height = (newYrange.max - newYrange.min) * ptsYscale + NumCast(doc.strokeWidth); doc.x = oldXrange.coord + (newXrange.min - oldXrange.min) * ptsXscale; doc.y = oldYrange.coord + (newYrange.min - oldYrange.min) * ptsYscale; - if (doc.activeFrame !== undefined) { - const findexed = Cast(doc[`data-indexed`], listSpec(InkField), []).slice(); - findexed[NumCast(doc.activeFrame)] = new InkField(newPoints); - doc[`data-indexed`] = new List(findexed); - } else { - Doc.GetProto(doc).data = new InkField(newPoints); - } + Doc.GetProto(doc).data = new InkField(newPoints); appliedFunc = true; } } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index ceaabd0e1..dae1c10bb 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -68,17 +68,6 @@ export class InkingStroke extends ViewBoxBaseComponent() { componentDidMount() { this.props.setContentView?.(this); - this._disposers.activeFrame = reaction( - () => this.rootDoc.activeFrame !== undefined && !(ComputedField.WithoutComputed(() => FieldValue(this.rootDoc[this.fieldKey])) instanceof ComputedField), - () => { - const newPoints = Cast(this.rootDoc[this.fieldKey], InkField, null).inkData; - this.rootDoc[this.fieldKey] = ComputedField.MakeInterpolated(this.fieldKey, 'activeFrame', this.rootDoc, NumCast(this.rootDoc.activeFrame)); - const findexed = Cast(this.rootDoc[`data-indexed`], listSpec(InkField), []).slice(); - findexed[NumCast(this.rootDoc.activeFrame)] = new InkField(newPoints); - this.rootDoc[this.fieldKey + '-indexed'] = new List(findexed); - }, - { fireImmediately: true } - ); this._disposers.selfDisper = reaction( () => this.props.isSelected(), // react to stroke being deselected by turning off ink handles selected => !selected && (InkStrokeProperties.Instance._controlButton = false) diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 45f68e0f0..86566ac6a 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -16,6 +16,11 @@ import { StyleProp } from '../StyleProvider'; import './CollectionFreeFormDocumentView.scss'; import { DocumentView, DocumentViewProps } from './DocumentView'; import React = require('react'); +import { InkField } from '../../../fields/InkField'; +import { DocumentType } from '../../documents/DocumentTypes'; +import { Field } from '../../util/ProsemirrorCopy/prompt'; +import { RefField } from '../../../fields/RefField'; +import { ObjectField } from '../../../fields/ObjectField'; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { dataProvider?: (doc: Doc, replica: string) => { x: number; y: number; zIndex?: number; color?: string; backgroundColor?: string; opacity?: number; highlight?: boolean; z: number; transition?: string } | undefined; @@ -33,6 +38,7 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { export class CollectionFreeFormDocumentView extends DocComponent() { public static animFields = ['_height', '_width', 'x', 'y', '_scrollTop', 'opacity']; // fields that are configured to be animatable using animation frames public static animStringFields = ['backgroundColor', 'color']; // fields that are configured to be animatable using animation frames + public static animDataFields = ['data', 'text']; // fields that are configured to be animatable using animation frames @observable _animPos: number[] | undefined = undefined; @observable _contentView: DocumentView | undefined | null; get displayName() { @@ -118,6 +124,10 @@ export class CollectionFreeFormDocumentView extends DocComponent { + const findexed = Cast(doc[`${val}-indexed`], listSpec(InkField), null); + findexed?.length <= timecode + 1 && findexed.push(undefined as any); + }); }) ); setTimeout( @@ -164,10 +174,13 @@ export class CollectionFreeFormDocumentView extends DocComponent(numberRange(currTimecode + 1).map(t => (!doc.z && makeAppear && t < NumCast(doc.appearFrame) ? 0 : 1))); } - CollectionFreeFormDocumentView.animFields.forEach(val => (doc[val] = ComputedField.MakeInterpolated(val, 'activeFrame', doc, currTimecode))); + CollectionFreeFormDocumentView.animFields.forEach(val => (doc[val] = ComputedField.MakeInterpolatedNumber(val, 'activeFrame', doc, currTimecode))); CollectionFreeFormDocumentView.animStringFields.forEach(val => (doc[val] = ComputedField.MakeInterpolatedString(val, 'activeFrame', doc, currTimecode))); - doc.activeFrame = ComputedField.MakeFunction('self.context?._currentFrame||0'); - doc.dataTransition = 'inherit'; + CollectionFreeFormDocumentView.animDataFields.forEach(val => (Doc.GetProto(doc)[val] = ComputedField.MakeInterpolatedDataField(val, 'activeFrame', Doc.GetProto(doc), currTimecode))); + const targetDoc = doc.type === DocumentType.RTF ? Doc.GetProto(doc) : doc; // data fields, like rtf 'text' exist on the data doc, so + doc !== targetDoc && (targetDoc.context = doc.context); // the computed fields don't see the layout doc -- need to copy the context to the data doc (HACK!!!) and set the activeFrame on the data doc (HACK!!!) + targetDoc.activeFrame = ComputedField.MakeFunction('self.context?._currentFrame||0'); + targetDoc.dataTransition = 'inherit'; }); } diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 3af8cad9a..7888d0841 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -501,7 +501,13 @@ export class PresElementBox extends ViewBoxBaseComponent() { backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor), boxShadow: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isSelected ? '0 0 0px 1.5px' + presBoxColor : undefined) : undefined, }}> -
+
{`${this.indexInPres + 1}. `}
StrCast(activeItem.title)} SetValue={this.onSetValue} />
diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 0fd992d3b..48d5c5563 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -189,7 +189,7 @@ export class ComputedField extends ScriptField { const compiled = ScriptField.CompileScript(script, params, true, capturedVariables); return compiled.compiled ? new ComputedField(compiled) : undefined; } - public static MakeInterpolated(fieldKey: string, interpolatorKey: string, doc: Doc, curTimecode: number) { + public static MakeInterpolatedNumber(fieldKey: string, interpolatorKey: string, doc: Doc, curTimecode: number) { if (!doc[`${fieldKey}-indexed`]) { const flist = new List(numberRange(curTimecode + 1).map(i => undefined) as any as number[]); flist[curTimecode] = NumCast(doc[fieldKey]); @@ -209,6 +209,16 @@ export class ComputedField extends ScriptField { const setField = ScriptField.CompileScript(`setIndexVal(self['${fieldKey}-indexed'], self.${interpolatorKey}, value)`, { value: 'any' }, true, {}); return getField.compiled ? new ComputedField(getField, setField?.compiled ? setField : undefined) : undefined; } + public static MakeInterpolatedDataField(fieldKey: string, interpolatorKey: string, doc: Doc, curTimecode: number) { + if (!doc[`${fieldKey}-indexed`]) { + const flist = new List(numberRange(curTimecode + 1).map(i => undefined) as any as Field[]); + flist[curTimecode] = Field.Copy(doc[fieldKey]); + doc[`${fieldKey}-indexed`] = flist; + } + const getField = ScriptField.CompileScript(`getIndexVal(self['${fieldKey}-indexed'], self.${interpolatorKey})`, {}, true, {}); + const setField = ScriptField.CompileScript(`setIndexVal(self['${fieldKey}-indexed'], self.${interpolatorKey}, value)`, { value: 'any' }, true, {}); + return getField.compiled ? new ComputedField(getField, setField?.compiled ? setField : undefined) : undefined; + } } export namespace ComputedField { let useComputed = true; -- cgit v1.2.3-70-g09d2 From 7278aaa71a13f57cdc371bd771f5fcc6419707b7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 26 Aug 2022 13:25:23 -0400 Subject: added x,y,w,h view pinning for all documents. --- src/client/views/DocumentButtonBar.tsx | 3 +- src/client/views/nodes/trails/PresBox.tsx | 59 +++++++++++++++--------- src/client/views/nodes/trails/PresElementBox.tsx | 15 +++++- 3 files changed, 52 insertions(+), 25 deletions(-) (limited to 'src/client/views/nodes/trails/PresElementBox.tsx') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 40fc8dae6..76e2d64a2 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -26,6 +26,7 @@ import { DashFieldView } from './nodes/formattedText/DashFieldView'; import { GoogleRef } from './nodes/formattedText/FormattedTextBox'; import { TemplateMenu } from './TemplateMenu'; import React = require('react'); +import { DocumentType } from '../documents/DocumentTypes'; const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -243,7 +244,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV .views() .filter(v => v) .map(dv => dv!.rootDoc); - TabDocView.PinDoc(docs, { pinDocView: true, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); + TabDocView.PinDoc(docs, { pinDocView: !docs.some(doc => !e.shiftKey && doc.type === DocumentType.RTF), activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) }); }}>
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index f254eaba6..eb6dad327 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -6,8 +6,10 @@ import { observer } from 'mobx-react'; import { ColorState, SketchPicker } from 'react-color'; import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal'; import { Doc, DocListCast, DocListCastAsync, FieldResult } from '../../../../fields/Doc'; +import { Copy } from '../../../../fields/FieldSymbols'; import { InkField, InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; +import { ObjectField } from '../../../../fields/ObjectField'; import { listSpec } from '../../../../fields/Schema'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents } from '../../../../Utils'; @@ -29,8 +31,6 @@ import { CollectionFreeFormDocumentView } from '../CollectionFreeFormDocumentVie import { FieldView, FieldViewProps } from '../FieldView'; import './PresBox.scss'; import { PresEffect, PresMovement, PresStatus } from './PresEnums'; -import { Copy } from '../../../../fields/FieldSymbols'; -import { CollectionFreeFormViewChrome } from '../../collections/CollectionMenu'; export interface PinProps { audioRange?: boolean; @@ -370,7 +370,8 @@ export class PresBox extends ViewBoxBaseComponent() { const temporal = [DocumentType.AUDIO, DocumentType.VID].includes(target.type as any); const clippable = [DocumentType.COMPARISON].includes(target.type as any); const dataview = [DocumentType.INK].includes(target.type as any) && target.activeFrame === undefined; - return { scrollable, pannable, temporal, clippable, dataview }; + const textview = [DocumentType.RTF].includes(target.type as any) && target.activeFrame === undefined; + return { scrollable, pannable, temporal, clippable, dataview, textview }; } // navigates to the bestTarget document by making sure it is on screen, // then it applies the view specs stored in activeItem to @@ -378,20 +379,18 @@ export class PresBox extends ViewBoxBaseComponent() { static navigateToDoc(bestTarget: Doc, activeItem: Doc, jumpToDoc: boolean) { const transTime = NumCast(activeItem.presDuration, 500); const presTransitionTime = `all ${transTime}ms`; + const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(bestTarget); bestTarget._viewTransition = presTransitionTime; - const { scrollable, pannable, temporal, clippable, dataview } = this.pinDataTypes(bestTarget); + bestTarget._dataTransition = dataview || textview ? presTransitionTime : undefined; + bestTarget.x = NumCast(activeItem.presX); + bestTarget.y = NumCast(activeItem.presY); + bestTarget.width = NumCast(activeItem.presWidth); + bestTarget.height = NumCast(activeItem.presHeight); if (clippable) bestTarget._clipWidth = activeItem.presPinClipWidth; if (temporal) bestTarget._currentTimecode = activeItem.presStartTime; if (scrollable) bestTarget._scrollTop = activeItem.presPinViewScroll; - if (dataview) { - bestTarget._dataTransition = presTransitionTime; - bestTarget.data = (activeItem.presData as any as InkField)[Copy](); - bestTarget.x = NumCast(activeItem.presX); - bestTarget.y = NumCast(activeItem.presY); - bestTarget.width = NumCast(activeItem.presWidth); - bestTarget.height = NumCast(activeItem.presHeight); - } - + if (dataview) Doc.GetProto(bestTarget).data = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; + if (textview) Doc.GetProto(bestTarget).text = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; if (pannable) { const contentBounds = Cast(activeItem.contentBounds, listSpec('number')); if (contentBounds) { @@ -409,7 +408,7 @@ export class PresBox extends ViewBoxBaseComponent() { } return setTimeout(() => { bestTarget._viewTransition = undefined; - if (dataview) bestTarget._dataTransition = undefined; + if (dataview || textview) bestTarget._dataTransition = undefined; }, transTime + 10); } @@ -428,19 +427,18 @@ export class PresBox extends ViewBoxBaseComponent() { pinDoc.contentBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); } if (pinProps?.pinDocView) { - const { scrollable, pannable, temporal, clippable, dataview } = this.pinDataTypes(pinDoc); - pinDoc.presPinView = (pinProps?.pinWithView ? true : false) || scrollable || temporal || pannable || clippable || dataview || pinProps.activeFrame !== undefined; + const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(pinDoc); + pinDoc.presPinView = (pinProps?.pinWithView ? true : false) || scrollable || temporal || pannable || clippable || dataview || textview || pinProps.activeFrame !== undefined; + pinDoc.presX = NumCast(targetDoc.x); + pinDoc.presY = NumCast(targetDoc.y); + pinDoc.presWidth = NumCast(targetDoc.width); + pinDoc.presHeight = NumCast(targetDoc.height); if (scrollable) pinDoc.presPinViewScroll = pinDoc._scrollTop; if (clippable) pinDoc.presPinClipWidth = pinDoc._clipWidth; if (temporal) pinDoc.presEndTime = NumCast((pinDoc.presStartTime = pinDoc._currentTimecode)) + 0.1; - if (dataview) { - pinDoc.presData = (targetDoc.data as InkField)[Copy](); - pinDoc.presX = NumCast(targetDoc.x); - pinDoc.presY = NumCast(targetDoc.y); - pinDoc.presWidth = NumCast(targetDoc.width); - pinDoc.presHeight = NumCast(targetDoc.height); - } + if (textview) pinDoc.presData = targetDoc.text instanceof ObjectField ? targetDoc.text[Copy]() : targetDoc.text; + if (dataview) pinDoc.presData = targetDoc.data instanceof ObjectField ? targetDoc.data[Copy]() : targetDoc.data; if (pannable) { const panX = NumCast(pinDoc._panX); const panY = NumCast(pinDoc._panY); @@ -512,9 +510,24 @@ export class PresBox extends ViewBoxBaseComponent() { // openInTab(targetDoc); } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) { LightboxView.SetLightboxDoc(undefined); + const transTime = NumCast(activeItem.presDuration, 500); + const presTransitionTime = `all ${transTime}ms`; + targetDoc._dataTransition = presTransitionTime; + targetDoc.x = NumCast(activeItem.presX); + targetDoc.y = NumCast(activeItem.presY); + targetDoc.width = NumCast(activeItem.presWidth); + targetDoc.height = NumCast(activeItem.presHeight); await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) { LightboxView.SetLightboxDoc(undefined); + + const transTime = NumCast(activeItem.presDuration, 500); + const presTransitionTime = `all ${transTime}ms`; + targetDoc._dataTransition = presTransitionTime; + targetDoc.x = NumCast(activeItem.presX); + targetDoc.y = NumCast(activeItem.presY); + targetDoc.width = NumCast(activeItem.presWidth); + targetDoc.height = NumCast(activeItem.presHeight); //awaiting jump so that new scale can be found, since jumping is async await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right } diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 91196ca21..38a87c34b 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -3,7 +3,7 @@ import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../../fields/Doc'; -import { Id } from '../../../../fields/FieldSymbols'; +import { Copy, Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; import { Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../Utils'; @@ -24,6 +24,8 @@ import { PresBox } from './PresBox'; import './PresElementBox.scss'; import { PresMovement } from './PresEnums'; import React = require('react'); +import { InkField } from '../../../../fields/InkField'; +import { RichTextField } from '../../../../fields/RichTextField'; /** * This class models the view a document added to presentation will have in the presentation. * It involves some functionality for its buttons and options. @@ -320,6 +322,12 @@ export class PresElementBox extends ViewBoxBaseComponent() { case DocumentType.RTF: const scroll = targetDoc._scrollTop; activeItem.presPinViewScroll = scroll; + if (targetDoc.type === DocumentType.RTF) { + activeItem.presData = targetDoc.text instanceof RichTextField ? targetDoc.text[Copy]() : targetDoc.text; + } + break; + case DocumentType.INK: + activeItem.presData = targetDoc.data instanceof InkField ? targetDoc.data[Copy]() : targetDoc.data; break; case DocumentType.VID: case DocumentType.AUDIO: @@ -337,6 +345,11 @@ export class PresElementBox extends ViewBoxBaseComponent() { activeItem.presPinViewY = y; activeItem.presPinViewScale = scale; } + + activeItem.presX = NumCast(targetDoc.x); + activeItem.presY = NumCast(targetDoc.y); + activeItem.presWidth = NumCast(targetDoc.width); + activeItem.presHeight = NumCast(targetDoc.height); }; @computed get recordingIsInOverlay() { -- cgit v1.2.3-70-g09d2 From b1044d1d79c1e06769f74df514e12557426b67be Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 26 Aug 2022 16:16:21 -0400 Subject: trying to clean up transition times for presbox / jumptoDoc, etc. --- src/client/util/DocumentManager.ts | 18 +- .../views/collections/CollectionNoteTakingView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 5 +- src/client/views/collections/TabDocView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 5 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 1 + src/client/views/nodes/trails/PresBox.tsx | 662 +++++++++------------ src/client/views/nodes/trails/PresElementBox.tsx | 9 - 8 files changed, 287 insertions(+), 417 deletions(-) (limited to 'src/client/views/nodes/trails/PresElementBox.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 52b643c04..2ca5d1095 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -154,7 +154,7 @@ export class DocumentManager { CollectionDockingView.AddSplit(doc, 'right'); finished?.(); }; - public jumpToDocument = async ( + public jumpToDocument = ( targetDoc: Doc, // document to display willZoom: boolean, // whether to zoom doc to take up most of screen createViewFunc = DocumentManager.addView, // how to create a view of the doc if it doesn't exist @@ -165,8 +165,8 @@ export class DocumentManager { finished?: () => void, originalTarget?: Doc, noSelect?: boolean, - presZoom?: number - ): Promise => { + presZoomScale?: number + ): void => { originalTarget = originalTarget ?? targetDoc; const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView; const docView = getFirstDocView(targetDoc, originatingDoc); @@ -207,7 +207,7 @@ export class DocumentManager { finished?.(); }; const annoContainerView = (!wasHidden || resolvedTarget !== annotatedDoc) && annotatedDoc && getFirstDocView(annotatedDoc); - const contextDocs = docContext.length ? await DocListCastAsync(docContext[0].data) : undefined; + const contextDocs = docContext.length ? DocListCast(docContext[0].data) : undefined; const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext.lastElement() : undefined; const targetDocContext = contextDoc || annotatedDoc; const targetDocContextView = (targetDocContext && getFirstDocView(targetDocContext)) || (wasHidden && annoContainerView); // if we have an annotation container and the target was hidden, then try again because we just un-hid the document above @@ -218,7 +218,7 @@ export class DocumentManager { annoContainerView.focus(targetDoc, { originalTarget, willZoom, - scale: presZoom, + scale: presZoomScale, afterFocus: (didFocus: boolean) => new Promise(res => { focusAndFinish(true); @@ -237,7 +237,7 @@ export class DocumentManager { focusView.focus(originalTarget ?? targetDoc, { originalTarget, willZoom, - scale: presZoom, + scale: presZoomScale, afterFocus: (didFocus: boolean) => new Promise(res => { focusAndFinish(forceDidFocus || didFocus); @@ -265,7 +265,9 @@ export class DocumentManager { afterFocus: async () => { targetDocContext._viewTransition = undefined; if (targetDocContext.layoutKey === 'layout_icon') { - targetDocContextView.iconify(() => this.jumpToDocument(resolvedTarget ?? targetDoc, willZoom, createViewFunc, docContext, linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoom)); + targetDocContextView.iconify(() => + this.jumpToDocument(resolvedTarget ?? targetDoc, willZoom, createViewFunc, docContext, linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoomScale) + ); } return ViewAdjustment.doNothing; }, @@ -309,7 +311,7 @@ export class DocumentManager { const docContextView = this.getFirstDocumentView(docContext[0]); if (docContextView) { return docContextView.iconify(() => - this.jumpToDocument(targetDoc, willZoom, createViewFunc, docContext.slice(1, docContext.length), linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoom) + this.jumpToDocument(targetDoc, willZoom, createViewFunc, docContext.slice(1, docContext.length), linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoomScale) ); } } diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 615141485..92c0bc341 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -201,7 +201,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { const top = found.getBoundingClientRect().top; const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top); if (Math.floor(localTop[1]) !== 0) { - smoothScroll((focusSpeed = doc.presTransition || doc.presTransition === 0 ? NumCast(doc.presTransition) : 500), this._mainCont!, localTop[1] + this._mainCont!.scrollTop); + smoothScroll((focusSpeed = NumCast(doc.focusSpeed, 500)), this._mainCont!, localTop[1] + this._mainCont!.scrollTop); } } const endFocus = async (moved: boolean) => (options?.afterFocus ? options?.afterFocus(moved) : ViewAdjustment.doNothing); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 71834607c..7f142727c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -259,7 +259,7 @@ export class CollectionStackingView extends CollectionSubView options?.afterFocus?.(moved) ?? ViewAdjustment.doNothing; @@ -494,8 +494,7 @@ export class CollectionStackingView extends CollectionSubView { if (targInd === -1) { this.addDocument(docs); - } - else { + } else { const childDocs = this.childDocList; if (childDocs) { childDocs.splice(targInd, 0, ...docs); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index f7b48adf6..49228a808 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -366,7 +366,7 @@ export class TabDocView extends React.Component { focusFunc = (doc: Doc, options?: DocFocusOptions) => { const shrinkwrap = options?.originalTarget === this._document && this.view?.ComponentView?.shrinkWrap; if (shrinkwrap && this._document) { - const focusSpeed = 1000; + const focusSpeed = NumCast(this._document.focusSpeed, 500); shrinkwrap(); this._document._viewTransition = `transform ${focusSpeed}ms`; setTimeout( diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 210370d39..ede113a9f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1146,7 +1146,7 @@ export class CollectionFreeFormView extends CollectionSubView() { constructor(props: any) { super(props); if ((Doc.ActivePresentation = this.rootDoc)) runInAction(() => (PresBox.Instance = this)); - this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox } @observable public static Instance: PresBox; @@ -127,12 +126,7 @@ export class PresBox extends ViewBoxBaseComponent() { @observable _treeViewMap: Map = new Map(); @computed get tagDocs() { - const tagDocs: Doc[] = []; - for (const doc of this.childDocs) { - const tagDoc = Cast(doc.presentationTargetDoc, Doc, null); - tagDocs.push(tagDoc); - } - return tagDocs; + return this.childDocs.map(doc => Cast(doc.presentationTargetDoc, Doc, null)); } @computed get itemIndex() { return NumCast(this.rootDoc._itemIndex); @@ -145,11 +139,11 @@ export class PresBox extends ViewBoxBaseComponent() { } @computed get scrollable(): boolean { if (this.targetDoc.type === DocumentType.PDF || this.targetDoc.type === DocumentType.WEB || this.targetDoc.type === DocumentType.RTF || this.targetDoc._viewType === CollectionViewType.Stacking) return true; - else return false; + return false; } @computed get panable(): boolean { if ((this.targetDoc.type === DocumentType.COL && this.targetDoc._viewType === CollectionViewType.Freeform) || this.targetDoc.type === DocumentType.IMG) return true; - else return false; + return false; } @computed get selectedDocumentView() { if (SelectionManager.Views().length) return SelectionManager.Views()[0]; @@ -202,8 +196,7 @@ export class PresBox extends ViewBoxBaseComponent() { @action updateCurrentPresentation = (pres?: Doc) => { - if (pres) Doc.ActivePresentation = pres; - else Doc.ActivePresentation = this.rootDoc; + Doc.ActivePresentation = pres ?? this.rootDoc; document.removeEventListener('keydown', PresBox.keyEventsWrapper, true); document.addEventListener('keydown', PresBox.keyEventsWrapper, true); this._presKeyEventsActive = true; @@ -318,7 +311,7 @@ export class PresBox extends ViewBoxBaseComponent() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; if (activeItem.presActiveFrame !== undefined) { - const transTime = NumCast(activeItem.presDuration, 500); + const transTime = NumCast(activeItem.presTransition, 500); const context = DocCast(DocCast(activeItem.presentationTargetDoc).context); if (context) { const contextView = DocumentManager.Instance.getFirstDocumentView(context); @@ -340,12 +333,8 @@ export class PresBox extends ViewBoxBaseComponent() { } if (targetDoc) { Doc.linkFollowHighlight(targetDoc.annotationOn instanceof Doc ? [targetDoc, targetDoc.annotationOn] : targetDoc); - targetDoc && - runInAction(() => { - if (activeItem.presMovement === PresMovement.Jump) targetDoc.focusSpeed = 0; - else targetDoc.focusSpeed = activeItem.presTransition ? activeItem.presTransition : 500; - }); - setTimeout(() => (targetDoc.focusSpeed = 500), this.activeItem.presTransition ? NumCast(this.activeItem.presTransition) + 10 : 510); + targetDoc && runInAction(() => (targetDoc.focusSpeed = activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500))); + setTimeout(() => (targetDoc.focusSpeed = undefined), NumCast(targetDoc.focusSpeed) + 10); } if (targetDoc?.lastFrame !== undefined) { targetDoc._currentFrame = 0; @@ -356,14 +345,6 @@ export class PresBox extends ViewBoxBaseComponent() { this.onHideDocument(); //Handles hide after/before } }); - - _navTimer!: NodeJS.Timeout; - navigateToView = (targetDoc: Doc, activeItem: Doc) => { - clearTimeout(this._navTimer); - const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document; - if (bestTarget) this._navTimer = PresBox.navigateToDoc(bestTarget, activeItem, false); - }; - static pinDataTypes(target: Doc) { const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(target.type as any) || target._viewType === CollectionViewType.Stacking; const pannable = [DocumentType.IMG].includes(target.type as any) || (target.type === DocumentType.COL && target._viewType === CollectionViewType.Freeform); @@ -373,43 +354,29 @@ export class PresBox extends ViewBoxBaseComponent() { const textview = [DocumentType.RTF].includes(target.type as any) && target.activeFrame === undefined; return { scrollable, pannable, temporal, clippable, dataview, textview }; } - // navigates to the bestTarget document by making sure it is on screen, - // then it applies the view specs stored in activeItem to + @action - static navigateToDoc(bestTarget: Doc, activeItem: Doc, jumpToDoc: boolean) { - const transTime = NumCast(activeItem.presDuration, 500); + static restoreTargetDocView(bestTarget: Doc, activeItem: Doc, jumpToDoc: boolean) { + const transTime = NumCast(activeItem.presTransition, 500); const presTransitionTime = `all ${transTime}ms`; const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(bestTarget); bestTarget._viewTransition = presTransitionTime; - bestTarget._dataTransition = dataview || textview ? presTransitionTime : undefined; - bestTarget.x = NumCast(activeItem.presX); - bestTarget.y = NumCast(activeItem.presY); - bestTarget.width = NumCast(activeItem.presWidth); - bestTarget.height = NumCast(activeItem.presHeight); if (clippable) bestTarget._clipWidth = activeItem.presPinClipWidth; if (temporal) bestTarget._currentTimecode = activeItem.presStartTime; if (scrollable) bestTarget._scrollTop = activeItem.presPinViewScroll; if (dataview) Doc.GetProto(bestTarget).data = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; if (textview) Doc.GetProto(bestTarget).text = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; if (pannable) { - const contentBounds = Cast(activeItem.contentBounds, listSpec('number')); + bestTarget._panX = activeItem.presPinViewX; + bestTarget._panY = activeItem.presPinViewY; + bestTarget._viewScale = activeItem.presPinViewScale; + const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number')); if (contentBounds) { - bestTarget._panX = (contentBounds[0] + contentBounds[2]) / 2; - bestTarget._panY = (contentBounds[1] + contentBounds[3]) / 2; const dv = DocumentManager.Instance.getDocumentView(bestTarget); - if (dv) { - bestTarget._viewScale = Math.min(dv.props.PanelHeight() / (contentBounds[3] - contentBounds[1]), dv.props.PanelWidth() / (contentBounds[2] - contentBounds[0])); - } - } else { - bestTarget._panX = activeItem.presPinViewX; - bestTarget._panY = activeItem.presPinViewY; - bestTarget._viewScale = activeItem.presPinViewScale; + dv && (bestTarget._viewScale = Math.min(dv.props.PanelHeight() / (contentBounds[3] - contentBounds[1]), dv.props.PanelWidth() / (contentBounds[2] - contentBounds[0]))); } } - return setTimeout(() => { - bestTarget._viewTransition = undefined; - if (dataview || textview) bestTarget._dataTransition = undefined; - }, transTime + 10); + return setTimeout(() => (bestTarget._viewTransition = undefined), transTime + 10); } /// copies values from the targetDoc (which is the prototype of the pinDoc) to @@ -424,7 +391,7 @@ export class PresBox extends ViewBoxBaseComponent() { pinDoc.presPinViewX = bounds.left + bounds.width / 2; pinDoc.presPinViewY = bounds.top + bounds.height / 2; pinDoc.presPinViewScale = pinProps.pinWithView.scale; - pinDoc.contentBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); + pinDoc.presPinViewBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); } if (pinProps?.pinDocView) { const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(pinDoc); @@ -446,7 +413,7 @@ export class PresBox extends ViewBoxBaseComponent() { const ph = NumCast(pinProps.panelHeight); const ps = NumCast(pinDoc._viewScale); if (pw && ph && ps) { - pinDoc.contentBounds = new List([panX - pw / 2 / ps, panY - ph / 2 / ps, panX + pw / 2 / ps, panY + ph / 2 / ps]); + pinDoc.presPinViewBounds = new List([panX - pw / 2 / ps, panY - ph / 2 / ps, panX + pw / 2 / ps, panY + ph / 2 / ps]); } pinDoc.presPinViewX = panX; pinDoc.presPinViewY = panY; @@ -455,6 +422,7 @@ export class PresBox extends ViewBoxBaseComponent() { } } + _navTimer!: NodeJS.Timeout; /** * This method makes sure that cursor navigates to the element that * has the option open and last in the group. @@ -504,38 +472,31 @@ export class PresBox extends ViewBoxBaseComponent() { finished?.(); } }; - // If openDocument is selected then it should open the document for the user - if (activeItem.openDocument) { - LightboxView.SetLightboxDoc(targetDoc); - // openInTab(targetDoc); - } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) { - LightboxView.SetLightboxDoc(undefined); - const transTime = NumCast(activeItem.presDuration, 500); + if (activeItem.presPinView && DocCast(targetDoc.context)?._currentFrame === undefined) { + const transTime = NumCast(activeItem.presTransition, 500); const presTransitionTime = `all ${transTime}ms`; targetDoc._dataTransition = presTransitionTime; - targetDoc.x = NumCast(activeItem.presX); - targetDoc.y = NumCast(activeItem.presY); - targetDoc.width = NumCast(activeItem.presWidth); - targetDoc.height = NumCast(activeItem.presHeight); - await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right - } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) { + targetDoc.x = NumCast(activeItem.presX, NumCast(targetDoc.x)); + targetDoc.y = NumCast(activeItem.presY, NumCast(targetDoc.y)); + targetDoc.width = NumCast(activeItem.presWidth, NumCast(targetDoc.width)); + targetDoc.height = NumCast(activeItem.presHeight, NumCast(targetDoc.height)); + setTimeout(() => (targetDoc._dataTransition = undefined), transTime + 10); + } + // If openDocument is selected then it should open the document for the user + if (activeItem.openDocument) { + LightboxView.SetLightboxDoc(targetDoc); // openInTab(targetDoc); + } else if (targetDoc && curDoc.presMovement !== PresMovement.None && targetDoc) { LightboxView.SetLightboxDoc(undefined); - - const transTime = NumCast(activeItem.presDuration, 500); - const presTransitionTime = `all ${transTime}ms`; - targetDoc._dataTransition = presTransitionTime; - targetDoc.x = NumCast(activeItem.presX); - targetDoc.y = NumCast(activeItem.presY); - targetDoc.width = NumCast(activeItem.presWidth); - targetDoc.height = NumCast(activeItem.presHeight); - //awaiting jump so that new scale can be found, since jumping is async - await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right + const zooming = curDoc.presMovement !== PresMovement.Pan; + DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); } // After navigating to the document, if it is added as a presPinView then it will // adjust the pan and scale to that of the pinView when it was added. if (activeItem.presPinView) { // if targetDoc is not displayed but one of its aliases is, then we need to modify that alias, not the original target - this.navigateToView(targetDoc, activeItem); + clearTimeout(this._navTimer); + const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document; + if (bestTarget) this._navTimer = PresBox.restoreTargetDocView(bestTarget, activeItem, false); } }; @@ -1488,12 +1449,8 @@ export class PresBox extends ViewBoxBaseComponent() { style={{ display: targetDoc.type === DocumentType.AUDIO ? 'none' : 'block' }} className={'toolbar-slider'} id="duration-slider" - onPointerDown={() => { - this._batch = UndoManager.StartBatch('presDuration'); - }} - onPointerUp={() => { - if (this._batch) this._batch.end(); - }} + onPointerDown={() => (this._batch = UndoManager.StartBatch('presDuration'))} + onPointerUp={() => this._batch?.end()} onChange={(e: React.ChangeEvent) => { e.stopPropagation(); this.setDurationTime(e.target.value); @@ -1650,28 +1607,12 @@ export class PresBox extends ViewBoxBaseComponent() { }); }; - @computed get mediaStopSlides() { - const activeItem: Doc = this.activeItem; - const list = this.childDocs.map((doc, i) => { - if (i > this.itemIndex) { - return ( - - ); - } - }); - return list; - } - @computed get mediaOptionsDropdown() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; const clipStart: number = NumCast(activeItem.clipStart); const clipEnd: number = NumCast(activeItem.clipEnd); - const duration = Math.round(NumCast(activeItem[`${Doc.LayoutFieldKey(activeItem)}-duration`]) * 10); const mediaStopDocInd: number = NumCast(activeItem.mediaStopDoc); - const mediaStopDocStr: string = mediaStopDocInd ? mediaStopDocInd + '. ' + this.childDocs[mediaStopDocInd - 1].title : ''; if (activeItem && targetDoc) { return (
@@ -1842,55 +1783,53 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get newDocumentToolbarDropdown() { return ( -
-
e.stopPropagation()} - onPointerUp={e => e.stopPropagation()} - onPointerDown={e => e.stopPropagation()}> -
-
{ - this.layout = 'blank'; - this.createNewSlide(this.layout); - })} - /> -
{ - this.layout = 'title'; - this.createNewSlide(this.layout); - })}> -
Title
-
Subtitle
-
-
{ - this.layout = 'header'; - this.createNewSlide(this.layout); - })}> -
- Section header -
+
e.stopPropagation()} + onPointerUp={e => e.stopPropagation()} + onPointerDown={e => e.stopPropagation()}> +
+
{ + this.layout = 'blank'; + this.createNewSlide(this.layout); + })} + /> +
{ + this.layout = 'title'; + this.createNewSlide(this.layout); + })}> +
Title
+
Subtitle
+
+
{ + this.layout = 'header'; + this.createNewSlide(this.layout); + })}> +
+ Section header
-
{ - this.layout = 'content'; - this.createNewSlide(this.layout); - })}> -
- Title -
-
Text goes here
+
+
{ + this.layout = 'content'; + this.createNewSlide(this.layout); + })}> +
+ Title
+
Text goes here
@@ -1904,73 +1843,71 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get newDocumentDropdown() { return ( -
-
e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> -
- Slide Title:

- { - e.stopPropagation(); - e.preventDefault(); - runInAction(() => (this.title = e.target.value)); - }}> +
e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> +
+ Slide Title:

+ { + e.stopPropagation(); + e.preventDefault(); + runInAction(() => (this.title = e.target.value)); + }}> +
+
+ Choose type: +
+
(this.addFreeform = !this.addFreeform))}> + Text +
+
(this.addFreeform = !this.addFreeform))}> + Freeform +
-
- Choose type: -
-
(this.addFreeform = !this.addFreeform))}> - Text -
-
(this.addFreeform = !this.addFreeform))}> - Freeform +
+
+ Preset layouts: +
+
(this.layout = 'blank'))} /> +
(this.layout = 'title'))}> +
Title
+
Subtitle
+
+
(this.layout = 'header'))}> +
+ Section header
-
-
- Preset layouts: -
-
(this.layout = 'blank'))} /> -
(this.layout = 'title'))}> -
Title
-
Subtitle
+
(this.layout = 'content'))}> +
+ Title
-
(this.layout = 'header'))}> -
- Section header -
+
Text goes here
+
+
(this.layout = 'twoColumns'))}> +
+ Title
-
(this.layout = 'content'))}> -
- Title -
-
Text goes here
+
+ Column one text
-
(this.layout = 'twoColumns'))}> -
- Title -
-
- Column one text -
-
- Column two text -
+
+ Column two text
-
(this.openLayouts = !this.openLayouts))}> - -
-
-
this.createNewSlide(this.layout, this.title, this.addFreeform)}> - Create New Slide -
+
(this.openLayouts = !this.openLayouts))}> + +
+
+
+
this.createNewSlide(this.layout, this.title, this.addFreeform)}> + Create New Slide
@@ -2105,115 +2042,109 @@ export class PresBox extends ViewBoxBaseComponent() { const activeFontColor = targetDoc['pres-text-color'] ? StrCast(targetDoc['pres-text-color']) : 'Black'; const viewedFontColor = targetDoc['pres-text-viewed-color'] ? StrCast(targetDoc['pres-text-viewed-color']) : 'Black'; return ( -
-
e.stopPropagation()} - onPointerUp={e => e.stopPropagation()} - onPointerDown={e => e.stopPropagation()}> -
- {this.stringType} selected -
-
- Contents -
-
- Edit -
-
-
-
Active text color
-
{ - this.openActiveColorPicker = !this.openActiveColorPicker; - })}>
+
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> +
+ {this.stringType} selected +
+
+ Contents
- {this.activeColorPicker} -
-
Viewed font color
-
(this.openViewedColorPicker = !this.openViewedColorPicker))}>
+
+ Edit
- {this.viewedColorPicker} +
+
+
Active text color
-
- Zoom -
-
- Edit -
+ className="ribbon-colorBox" + style={{ backgroundColor: activeFontColor, height: 15, width: 15 }} + onClick={action(() => { + this.openActiveColorPicker = !this.openActiveColorPicker; + })}>
+
+ {this.activeColorPicker} +
+
Viewed font color
+
(this.openViewedColorPicker = !this.openViewedColorPicker))}>
+
+ {this.viewedColorPicker} +
+
+ Zoom
-
-
- Scroll -
-
- Edit -
+
+ Edit
-
- Frames -
-
-
{ - e.stopPropagation(); - this.prevKeyframe(targetDoc, activeItem); - }}> - -
-
(targetDoc.keyFrameEditing = !targetDoc.keyFrameEditing))}> - {NumCast(targetDoc._currentFrame)} -
-
{ - e.stopPropagation(); - this.nextKeyframe(targetDoc, activeItem); - }}> - -
-
- -
{'Last frame'}
- - }> -
{NumCast(targetDoc.lastFrame)}
-
+
+
+ Scroll
-
- {this.frameListHeader} - {this.frameList} +
+ Edit
-
console.log(' TODO: play frames')}> - Play +
+
+
+ Frames +
+
+
{ + e.stopPropagation(); + this.prevKeyframe(targetDoc, activeItem); + }}> + +
+
(targetDoc.keyFrameEditing = !targetDoc.keyFrameEditing))}> + {NumCast(targetDoc._currentFrame)} +
+
{ + e.stopPropagation(); + this.nextKeyframe(targetDoc, activeItem); + }}> + +
+ +
{'Last frame'}
+ + }> +
{NumCast(targetDoc.lastFrame)}
+
+
+
+ {this.frameListHeader} + {this.frameList} +
+
console.log(' TODO: play frames')}> + Play
@@ -2233,7 +2164,6 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch @action switchPresented = (color: ColorState) => { - const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; const val = String(color.hex); targetDoc['pres-text-viewed-color'] = val; @@ -2241,25 +2171,21 @@ export class PresBox extends ViewBoxBaseComponent() { }; @computed get activeColorPicker() { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; return !this.openActiveColorPicker ? null : ( ); } @computed get viewedColorPicker() { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; return !this.openViewedColorPicker ? null : ( ); } @@ -2422,10 +2348,7 @@ export class PresBox extends ViewBoxBaseComponent() { }; @observable - toggleDisplayMovement = (doc: Doc) => { - if (doc.displayMovement) doc.displayMovement = false; - else doc.displayMovement = true; - }; + toggleDisplayMovement = (doc: Doc) => (doc.displayMovement = !doc.displayMovement); @action checkList = (doc: Doc, list: any): number => { @@ -2538,24 +2461,13 @@ export class PresBox extends ViewBoxBaseComponent() { } }; - @computed get moreInfoDropdown() { - return
; - } - @computed get toolbarWidth(): number { - const width = this.props.PanelWidth(); - return width; + return this.props.PanelWidth(); } @action - toggleProperties = () => { - if (SettingsManager.propertiesWidth > 0) { - SettingsManager.propertiesWidth = 0; - } else { - SettingsManager.propertiesWidth = 250; - } - }; + toggleProperties = () => (SettingsManager.propertiesWidth = SettingsManager.propertiesWidth > 0 ? 0 : 250); @computed get toolbar() { const propIcon = SettingsManager.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left'; @@ -2677,10 +2589,7 @@ export class PresBox extends ViewBoxBaseComponent() { } @action - getList = (list: any): List => { - const x: List = list; - return x; - }; + getList = (list: any): List => list; @action updateList = (list: any): List => { @@ -2709,12 +2618,7 @@ export class PresBox extends ViewBoxBaseComponent() {
  Frames {this.panable ? Panable : this.scrollable ? Scrollable : null}
- -
{'Add frame by example'}
- - }> + {'Add frame by example'}
}>
{ @@ -2724,12 +2628,7 @@ export class PresBox extends ViewBoxBaseComponent() { e.stopPropagation()} />
- -
{'Edit in collection'}
- - }> + {'Edit in collection'}
}>
{ @@ -2746,7 +2645,6 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get frameList() { const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; const frameList: List = this.getList(activeItem.frameList); if (frameList) { const frameItems = frameList.map(value =>
); @@ -2755,18 +2653,14 @@ export class PresBox extends ViewBoxBaseComponent() { } @computed get playButtonFrames() { - const targetDoc: Doc = this.targetDoc; - return ( - <> - {this.targetDoc ? ( -
= 0 ? 'inline-flex' : 'none' }}> -
{NumCast(targetDoc._currentFrame)}
-
-
{NumCast(targetDoc.lastFrame)}
-
- ) : null} - - ); + const targetDoc = this.targetDoc; + return this.targetDoc ? ( +
= 0 ? 'inline-flex' : 'none' }}> +
{NumCast(targetDoc._currentFrame)}
+
+
{NumCast(targetDoc.lastFrame)}
+
+ ) : null; } @computed get playButtons() { @@ -2775,12 +2669,7 @@ export class PresBox extends ViewBoxBaseComponent() { // Case 1: There are still other frames and should go through all frames before going to next slide return (
- -
{'Loop'}
- - }> + {'Loop'}
}>
(this.layoutDoc.presLoop = !this.layoutDoc.presLoop)}>
@@ -2798,12 +2687,7 @@ export class PresBox extends ViewBoxBaseComponent() { }}>
- -
{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
- - }> + {this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
}>
@@ -2821,12 +2705,7 @@ export class PresBox extends ViewBoxBaseComponent() {
- -
{'Click to return to 1st slide'}
- - }> + {'Click to return to 1st slide'}
}>
this.gotoDocument(0, this.activeItem)}> 1
@@ -2931,12 +2810,7 @@ export class PresBox extends ViewBoxBaseComponent() { return DocListCast(Doc.MyOverlayDocs?.data).includes(this.rootDoc) ? (
e.stopPropagation()}>
- -
{'Loop'}
- - }> + {'Loop'}
}>
() {
setupMoveUpEvents(this, e, returnFalse, returnFalse, this.prevClicked, false, false)}>
- -
{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
- - }> + {this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
}>
setupMoveUpEvents(this, e, returnFalse, returnFalse, this.startOrPause, false, false)}>
@@ -2962,12 +2831,7 @@ export class PresBox extends ViewBoxBaseComponent() {
- -
{'Click to return to 1st slide'}
- - }> + {'Click to return to 1st slide'}
}>
setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.gotoDocument(0, this.activeItem), false, false)}> 1
@@ -3033,5 +2897,17 @@ ScriptingGlobals.add(function navigateToDoc(bestTarget: Doc, activeItem: Doc) { CollectionDockingView.AddSplit(doc, 'right'); finished?.(); }; - DocumentManager.Instance.jumpToDocument(bestTarget, true, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, () => PresBox.navigateToDoc(bestTarget, activeItem, true), undefined, true, NumCast(activeItem.presZoom)); + DocumentManager.Instance.jumpToDocument( + bestTarget, + true, + openInTab, + srcContext ? [srcContext] : [], + undefined, + undefined, + undefined, + () => PresBox.restoreTargetDocView(bestTarget, activeItem, true), + undefined, + true, + NumCast(activeItem.presZoom) + ); }); diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 38a87c34b..c78828a78 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -162,15 +162,6 @@ export class PresElementBox extends ViewBoxBaseComponent() { )); return groupSlides; } - @computed get duration() { - let durationInS: number; - if (this.rootDoc.type === DocumentType.AUDIO || this.rootDoc.type === DocumentType.VID) { - durationInS = NumCast(this.rootDoc.presEndTime) - NumCast(this.rootDoc.presStartTime); - durationInS = Math.round(durationInS * 10) / 10; - } else if (this.rootDoc.presDuration) durationInS = NumCast(this.rootDoc.presDuration) / 1000; - else durationInS = 2; - return 'D: ' + durationInS + 's'; - } @computed get transition() { let transitionInS: number; -- cgit v1.2.3-70-g09d2 From a4ce2913b8a15cdd4670002a4a74f1d86601348e Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 26 Aug 2022 18:34:41 -0400 Subject: a bunch of mostly decorative cleanup to presBox --- src/client/views/PropertiesView.tsx | 6 +- src/client/views/collections/TabDocView.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 558 +++++++---------------- src/client/views/nodes/trails/PresElementBox.tsx | 2 +- src/client/views/nodes/trails/PresEnums.ts | 42 +- 5 files changed, 186 insertions(+), 424 deletions(-) (limited to 'src/client/views/nodes/trails/PresElementBox.tsx') diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 33f17047b..2708c561d 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -58,7 +58,7 @@ export class PropertiesView extends React.Component { } @computed get selectedDocumentView() { if (SelectionManager.Views().length) return SelectionManager.Views()[0]; - if (PresBox.Instance?._selectedArray.size) return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc); + if (PresBox.Instance?.selectedArray.size) return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc); return undefined; } @computed get isPres(): boolean { @@ -1612,7 +1612,7 @@ export class PropertiesView extends React.Component { ); } if (this.isPres) { - const selectedItem: boolean = PresBox.Instance?._selectedArray.size > 0; + const selectedItem: boolean = PresBox.Instance?.selectedArray.size > 0; const type = PresBox.Instance.activeItem?.type; return (
@@ -1622,7 +1622,7 @@ export class PropertiesView extends React.Component {
{this.editableTitle}
-
{PresBox.Instance?._selectedArray.size} selected
+
{PresBox.Instance?.selectedArray.size} selected
{PresBox.Instance?.listOfSelected}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 49228a808..bead5825c 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -239,7 +239,7 @@ export class TabDocView extends React.Component { pinDoc.treeViewGrowsHorizontally = true; // the document expands horizontally when displayed as a tree view header pinDoc.treeViewHideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header const presArray: Doc[] = PresBox.Instance?.sortArray(); - const size: number = PresBox.Instance?._selectedArray.size; + const size: number = PresBox.Instance?.selectedArray.size; const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined; const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], null); diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index ade098917..ac68ea281 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -12,7 +12,7 @@ import { List } from '../../../../fields/List'; import { ObjectField } from '../../../../fields/ObjectField'; import { listSpec } from '../../../../fields/Schema'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents } from '../../../../Utils'; +import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents, StopEvent } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; import { DocumentManager } from '../../../util/DocumentManager'; @@ -86,6 +86,7 @@ export class PresBox extends ViewBoxBaseComponent() { } private _disposers: { [name: string]: IReactionDisposer } = {}; + public selectedArray = new ObservableSet(); constructor(props: any) { super(props); @@ -93,6 +94,7 @@ export class PresBox extends ViewBoxBaseComponent() { } @observable public static Instance: PresBox; + @observable static startMarquee: boolean = false; // onclick "+ new slide" in presentation mode, set as true, then when marquee selection finish, onPointerUp automatically triggers PinWithView @observable _isChildActive = false; @observable _moveOnFromAudio: boolean = true; @@ -103,14 +105,13 @@ export class PresBox extends ViewBoxBaseComponent() { @observable _dragArray: HTMLElement[] = []; @observable _pathBoolean: boolean = false; @observable _expandBoolean: boolean = false; - - @observable static startMarquee: boolean = false; // onclick "+ new slide" in presentation mode, set as true, then when marquee selection finish, onPointerUp automatically triggers PinWithView - @observable private transitionTools: boolean = false; - @observable private newDocumentTools: boolean = false; - @observable private progressivizeTools: boolean = false; - @observable private openMovementDropdown: boolean = false; - @observable private openEffectDropdown: boolean = false; - @observable private presentTools: boolean = false; + @observable _transitionTools: boolean = false; + @observable _newDocumentTools: boolean = false; + @observable _progressivizeTools: boolean = false; + @observable _openMovementDropdown: boolean = false; + @observable _openEffectDropdown: boolean = false; + @observable _presentTools: boolean = false; + @observable _treeViewMap: Map = new Map(); @computed get isTreeOrStack() { return [CollectionViewType.Tree, CollectionViewType.Stacking].includes(StrCast(this.layoutDoc._viewType) as any); } @@ -123,8 +124,6 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get childDocs() { return DocListCast(this.rootDoc[this.presFieldKey]); } - @observable _treeViewMap: Map = new Map(); - @computed get tagDocs() { return this.childDocs.map(doc => Cast(doc.presentationTargetDoc, Doc, null)); } @@ -137,22 +136,21 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get targetDoc() { return Cast(this.activeItem?.presentationTargetDoc, Doc, null); } - @computed get scrollable(): boolean { + @computed get scrollable() { if (this.targetDoc.type === DocumentType.PDF || this.targetDoc.type === DocumentType.WEB || this.targetDoc.type === DocumentType.RTF || this.targetDoc._viewType === CollectionViewType.Stacking) return true; return false; } - @computed get panable(): boolean { + @computed get panable() { if ((this.targetDoc.type === DocumentType.COL && this.targetDoc._viewType === CollectionViewType.Freeform) || this.targetDoc.type === DocumentType.IMG) return true; return false; } @computed get selectedDocumentView() { if (SelectionManager.Views().length) return SelectionManager.Views()[0]; - if (this._selectedArray.size) return DocumentManager.Instance.getDocumentView(this.rootDoc); + if (this.selectedArray.size) return DocumentManager.Instance.getDocumentView(this.rootDoc); } - @computed get isPres(): boolean { + @computed get isPres() { document.removeEventListener('keydown', PresBox.keyEventsWrapper, true); if (this.selectedDoc?.type === DocumentType.PRES) { - document.removeEventListener('keydown', PresBox.keyEventsWrapper, true); document.addEventListener('keydown', PresBox.keyEventsWrapper, true); return true; } @@ -161,10 +159,9 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; } - _selectedArray = new ObservableSet(); - clearSelectedArray = () => this._selectedArray.clear(); - addToSelectedArray = (doc: Doc) => this._selectedArray.add(doc); - removeFromSelectedArray = (doc: Doc) => this._selectedArray.delete(doc); + clearSelectedArray = () => this.selectedArray.clear(); + addToSelectedArray = (doc: Doc) => this.selectedArray.add(doc); + removeFromSelectedArray = (doc: Doc) => this.selectedArray.delete(doc); _unmounting = false; @action @@ -448,7 +445,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.layoutDoc.presCollection = srcContext; } const presStatus = this.rootDoc.presStatus; - const selViewCache = Array.from(this._selectedArray); + const selViewCache = Array.from(this.selectedArray); const dragViewCache = Array.from(this._dragArray); const eleViewCache = Array.from(this._eleArray); const self = this; @@ -756,27 +753,11 @@ export class PresBox extends ViewBoxBaseComponent() { } }); - setMovementName = action((movement: any, activeItem: Doc): string => { - let output: string = 'none'; - switch (movement) { - case PresMovement.Zoom: - output = 'Pan & Zoom'; - break; //Pan and zoom - case PresMovement.Pan: - output = 'Pan'; - break; //Pan - case PresMovement.Jump: - output = 'Jump cut'; - break; //Jump Cut - case PresMovement.None: - output = 'None'; - break; //None - default: - output = 'Zoom'; - activeItem.presMovement = 'zoom'; - break; //default set as zoom + movementName = action((activeItem: Doc) => { + if (![PresMovement.Zoom, PresMovement.Pan, PresMovement.Jump, PresMovement.None].includes(StrCast(activeItem.presMovement) as any)) { + activeItem.presMovement = 'zoom'; } - return output; + return StrCast(activeItem.presMovement); }); whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isChildActive = isActive))); @@ -822,16 +803,13 @@ export class PresBox extends ViewBoxBaseComponent() { /** * For sorting the array so that the order is maintained when it is dropped. */ - @action - sortArray = (): Doc[] => { - return this.childDocs.filter(doc => this._selectedArray.has(doc)); - }; + sortArray = () => this.childDocs.filter(doc => this.selectedArray.has(doc)); /** * Method to get the list of selected items in the order in which they have been selected */ @computed get listOfSelected() { - return Array.from(this._selectedArray).map((doc: Doc, index: any) => { + return Array.from(this.selectedArray).map((doc: Doc, index: any) => { const curDoc = Cast(doc, Doc, null); const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); if (curDoc && curDoc === this.activeItem) @@ -874,24 +852,18 @@ export class PresBox extends ViewBoxBaseComponent() { //Command click @action multiSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => { - if (!this._selectedArray.has(doc)) { + if (!this.selectedArray.has(doc)) { this.addToSelectedArray(doc); this._eleArray.push(ref); this._dragArray.push(drag); } else { this.removeFromSelectedArray(doc); - this.removeFromArray(this._eleArray, doc); - this.removeFromArray(this._dragArray, doc); + this._eleArray.splice(this._eleArray.indexOf(ref)); + this._dragArray.splice(this._dragArray.indexOf(drag)); } this.selectPres(); }; - removeFromArray = (arr: any[], val: any) => { - const index: number = arr.indexOf(val); - const ret: any[] = arr.splice(index, 1); - arr = ret; - }; - //Shift click @action shiftSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => { @@ -924,9 +896,7 @@ export class PresBox extends ViewBoxBaseComponent() { else this.regularSelect(doc, ref, drag, focus); }; - static keyEventsWrapper = (e: KeyboardEvent) => { - PresBox.Instance.keyEvents(e); - }; + static keyEventsWrapper = (e: KeyboardEvent) => PresBox.Instance.keyEvents(e); // Key for when the presentaiton is active @action @@ -940,7 +910,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (this.layoutDoc.presStatus === 'edit') { undoBatch( action(() => { - for (const doc of this._selectedArray) { + for (const doc of this.selectedArray) { this.removeDocument(doc); } this.clearSelectedArray(); @@ -1027,13 +997,7 @@ export class PresBox extends ViewBoxBaseComponent() { } }; - getAllIndexes = (arr: Doc[], val: Doc): number[] => { - const indexes = []; - for (let i = 0; i < arr.length; i++) { - arr[i] === val && indexes.push(i); - } - return indexes; - }; + getAllIndexes = (arr: Doc[], val: Doc) => arr.map((doc, i) => (doc === val ? i : -1)).filter(i => i !== -1); // Adds the index in the pres path graphically @computed get order() { @@ -1152,7 +1116,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; if (timeInMS > 10000) timeInMS = 10000; - this._selectedArray.forEach(doc => (doc.presTransition = timeInMS)); + this.selectedArray.forEach(doc => (doc.presTransition = timeInMS)); }; // Converts seconds to ms and updates presTransition @@ -1161,7 +1125,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (change) scale += change; if (scale < 0.01) scale = 0.01; if (scale > 1.5) scale = 1.5; - this._selectedArray.forEach(doc => (doc.presZoom = scale)); + this.selectedArray.forEach(doc => (doc.presZoom = scale)); }; // Converts seconds to ms and updates presDuration @@ -1170,100 +1134,43 @@ export class PresBox extends ViewBoxBaseComponent() { if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; if (timeInMS > 20000) timeInMS = 20000; - this._selectedArray.forEach(doc => (doc.presDuration = timeInMS)); + this.selectedArray.forEach(doc => (doc.presDuration = timeInMS)); }; /** * When the movement dropdown is changes */ @undoBatch - updateMovement = action((movement: any, all?: boolean) => { - (all ? this.childDocs : this._selectedArray).forEach(doc => { - switch (movement) { - case PresMovement.Zoom: //Pan and zoom - doc.presMovement = PresMovement.Zoom; - break; - case PresMovement.Pan: //Pan - doc.presMovement = PresMovement.Pan; - break; - case PresMovement.Jump: //Jump Cut - doc.presJump = true; - doc.presMovement = PresMovement.Jump; - break; - case PresMovement.None: - default: - doc.presMovement = PresMovement.None; - break; - } - }); - }); + updateMovement = action((movement: PresMovement, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presMovement = movement))); @undoBatch @action updateHideBefore = (activeItem: Doc) => { activeItem.presHideBefore = !activeItem.presHideBefore; - this._selectedArray.forEach(doc => (doc.presHideBefore = activeItem.presHideBefore)); + this.selectedArray.forEach(doc => (doc.presHideBefore = activeItem.presHideBefore)); }; @undoBatch @action updateHideAfter = (activeItem: Doc) => { activeItem.presHideAfter = !activeItem.presHideAfter; - this._selectedArray.forEach(doc => (doc.presHideAfter = activeItem.presHideAfter)); + this.selectedArray.forEach(doc => (doc.presHideAfter = activeItem.presHideAfter)); }; @undoBatch @action updateOpenDoc = (activeItem: Doc) => { activeItem.openDocument = !activeItem.openDocument; - this._selectedArray.forEach(doc => { - doc.openDocument = activeItem.openDocument; - }); + this.selectedArray.forEach(doc => (doc.openDocument = activeItem.openDocument)); }; @undoBatch @action - updateEffectDirection = (effect: any, all?: boolean) => { - (all ? this.childDocs : this._selectedArray).forEach(doc => { - const tagDoc = doc; // Cast(doc.presentationTargetDoc, Doc, null); - switch (effect) { - case PresEffect.Left: - tagDoc.presEffectDirection = PresEffect.Left; - break; - case PresEffect.Right: - tagDoc.presEffectDirection = PresEffect.Right; - break; - case PresEffect.Top: - tagDoc.presEffectDirection = PresEffect.Top; - break; - case PresEffect.Bottom: - tagDoc.presEffectDirection = PresEffect.Bottom; - break; - case PresEffect.Center: - default: - tagDoc.presEffectDirection = PresEffect.Center; - break; - } - }); - }; + updateEffectDirection = (effect: PresEffect, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffectDirection = effect)); @undoBatch @action - updateEffect = (effect: any, all?: boolean) => { - (all ? this.childDocs : this._selectedArray).forEach(doc => { - const tagDoc = doc; //Cast(doc.presentationTargetDoc, Doc, null); - //prettier-ignore - switch (effect) { - default: - case PresEffect.None: tagDoc.presEffect = PresEffect.None; break; - case PresEffect.Bounce: tagDoc.presEffect = PresEffect.Bounce; break; - case PresEffect.Fade: tagDoc.presEffect = PresEffect.Fade; break; - case PresEffect.Flip: tagDoc.presEffect = PresEffect.Flip; break; - case PresEffect.Roll: tagDoc.presEffect = PresEffect.Roll; break; - case PresEffect.Rotate: tagDoc.presEffect = PresEffect.Rotate; break; - } - }); - }; + updateEffect = (effect: PresEffect, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffect = effect)); _batch: UndoManager.Batch | undefined = undefined; @@ -1272,6 +1179,46 @@ export class PresBox extends ViewBoxBaseComponent() { const targetDoc: Doc = this.targetDoc; const isPresCollection: boolean = targetDoc === this.layoutDoc.presCollection; const isPinWithView: boolean = BoolCast(activeItem.presPinView); + const presEffect = (effect: PresEffect) => ( +
this.updateEffect(effect)}> + {effect} +
+ ); + const presMovement = (movement: PresMovement) => ( +
this.updateMovement(movement)}> + {movement} +
+ ); + const presDirection = (diretion: PresEffect, icon: string, gridColumn: number, gridRow: number, opts: object) => { + const color = this.activeItem.presEffectDirection === diretion || (diretion === PresEffect.Center && !this.activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; + return ( + {diretion}
}> +
this.updateEffectDirection(diretion)}> + {icon ? : null} +
+ + ); + }; + const inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void) => { + return ( + (this._batch = UndoManager.StartBatch('pres slider'))} + onPointerUp={() => this._batch?.end()} + onChange={e => { + e.stopPropagation(); + change(e.target.value); + }} + /> + ); + }; if (activeItem && targetDoc) { const type = targetDoc.type; const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5; @@ -1282,13 +1229,13 @@ export class PresBox extends ViewBoxBaseComponent() { activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom'; return (
e.stopPropagation()} - onPointerUp={e => e.stopPropagation()} + className={`presBox-ribbon ${this._transitionTools && this.layoutDoc.presStatus === PresStatus.Edit ? 'active' : ''}`} + onPointerDown={StopEvent} + onPointerUp={StopEvent} onClick={action(e => { e.stopPropagation(); - this.openMovementDropdown = false; - this.openEffectDropdown = false; + this._openMovementDropdown = false; + this._openEffectDropdown = false; })}>
Movement @@ -1301,24 +1248,16 @@ export class PresBox extends ViewBoxBaseComponent() { className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); - this.openMovementDropdown = !this.openMovementDropdown; + this._openMovementDropdown = !this._openMovementDropdown; })} - style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}> - {this.setMovementName(activeItem.presMovement, activeItem)} - -
e.stopPropagation()} style={{ display: this.openMovementDropdown ? 'grid' : 'none' }}> -
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None)}> - None -
-
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom)}> - Pan {'&'} Zoom -
-
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan)}> - Pan -
-
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump)}> - Jump cut -
+ style={{ borderBottomLeftRadius: this._openMovementDropdown ? 0 : 5, border: this._openMovementDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}> + {this.movementName(activeItem)} + +
+ {presMovement(PresMovement.None)} + {presMovement(PresMovement.Zoom)} + {presMovement(PresMovement.Pan)} + {presMovement(PresMovement.Jump)}
)} @@ -1336,21 +1275,7 @@ export class PresBox extends ViewBoxBaseComponent() {
- (this._batch = UndoManager.StartBatch('presZoom'))} - onPointerUp={() => this._batch?.end()} - onChange={(e: React.ChangeEvent) => { - e.stopPropagation(); - this.setZoom(e.target.value); - }} - /> + {inputter('0', '1', '150', zoom, activeItem.presMovement === PresMovement.Zoom, this.setZoom)}
Movement Speed
@@ -1365,21 +1290,7 @@ export class PresBox extends ViewBoxBaseComponent() {
- (this._batch = UndoManager.StartBatch('presTransition'))} - onPointerUp={() => this._batch?.end()} - onChange={(e: React.ChangeEvent) => { - e.stopPropagation(); - this.setTransitionTime(e.target.value); - }} - /> + {inputter('0.1', '0.1', '10', transitionSpeed, [PresMovement.Pan, PresMovement.Zoom].includes(activeItem.presMovement as any), this.setTransitionTime)}
Fast
Medium
@@ -1390,35 +1301,20 @@ export class PresBox extends ViewBoxBaseComponent() { Visibility {'&'} Duration
{isPresCollection ? null : ( - -
{'Hide before presented'}
- - }> + {'Hide before presented'}
}>
this.updateHideBefore(activeItem)}> Hide before
)} {isPresCollection ? null : ( - -
{'Hide after presented'}
- - }> + {'Hide after presented'}
}>
this.updateHideAfter(activeItem)}> Hide after
)} - -
{'Open in lightbox view'}
- - }> + {'Open in lightbox view'}
}>
this.updateOpenDoc(activeItem)}> Lightbox
@@ -1440,22 +1336,7 @@ export class PresBox extends ViewBoxBaseComponent() {
- (this._batch = UndoManager.StartBatch('presDuration'))} - onPointerUp={() => this._batch?.end()} - onChange={(e: React.ChangeEvent) => { - e.stopPropagation(); - this.setDurationTime(e.target.value); - }} - /> + {inputter('0.1', '0.1', '20', duration, targetDoc.type !== DocumentType.AUDIO, this.setDurationTime)}
Short
Medium
@@ -1471,98 +1352,30 @@ export class PresBox extends ViewBoxBaseComponent() { className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); - this.openEffectDropdown = !this.openEffectDropdown; + this._openEffectDropdown = !this._openEffectDropdown; })} - style={{ borderBottomLeftRadius: this.openEffectDropdown ? 0 : 5, border: this.openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}> + style={{ borderBottomLeftRadius: this._openEffectDropdown ? 0 : 5, border: this._openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}> {effect.toString()} - -
e.stopPropagation()}> -
e.stopPropagation()} - onClick={() => this.updateEffect(PresEffect.None)}> - None -
-
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Fade)}> - Fade In -
-
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Flip)}> - Flip -
-
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Rotate)}> - Rotate -
-
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Bounce)}> - Bounce -
-
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Roll)}> - Roll -
+ +
e.stopPropagation()}> + {presEffect(PresEffect.None)} + {presEffect(PresEffect.Fade)} + {presEffect(PresEffect.Flip)} + {presEffect(PresEffect.Rotate)} + {presEffect(PresEffect.Bounce)} + {presEffect(PresEffect.Roll)}
Effect direction
-
{this.effectDirection}
+
{StrCast(this.activeItem.presEffectDirection)}
- {'Enter from left'}
}> -
this.updateEffectDirection(PresEffect.Left)}> - -
- - {'Enter from right'}
}> -
this.updateEffectDirection(PresEffect.Right)}> - -
- - -
{'Enter from top'}
- - }> -
this.updateEffectDirection(PresEffect.Top)}> - -
-
- -
{'Enter from bottom'}
- - }> -
this.updateEffectDirection(PresEffect.Bottom)}> - -
-
- -
{'Enter from center'}
- - }> -
this.updateEffectDirection(PresEffect.Center)}>
-
+ {presDirection(PresEffect.Left, 'angle-right', 1, 2, {})} + {presDirection(PresEffect.Right, 'angle-left', 3, 2, {})} + {presDirection(PresEffect.Top, 'angle-down', 2, 1, {})} + {presDirection(PresEffect.Bottom, 'angle-up', 2, 3, {})} + {presDirection(PresEffect.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
)} @@ -1576,34 +1389,18 @@ export class PresBox extends ViewBoxBaseComponent() { } } - @computed get effectDirection() { - // prettier-ignore - switch (this.activeItem.presEffectDirection) { - case 'left': return 'Enter from left'; - case 'right': return 'Enter from right'; - case 'top': return'Enter from top'; - case 'bottom': return 'Enter from bottom'; - } - return 'Enter from center'; - } - @undoBatch @action applyTo = (array: Doc[]) => { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - this.updateMovement(activeItem.presMovement, true); - this.updateEffect(activeItem.presEffect, true); - this.updateEffectDirection(activeItem.presEffectDirection, true); - array.forEach(doc => { - const curDoc = Cast(doc, Doc, null); - const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); - if (tagDoc && targetDoc) { - curDoc.presTransition = activeItem.presTransition; - curDoc.presDuration = activeItem.presDuration; - curDoc.presHideBefore = activeItem.presHideBefore; - curDoc.presHideAfter = activeItem.presHideAfter; - } + this.updateMovement(this.activeItem.presMovement as PresMovement, true); + this.updateEffect(this.activeItem.presEffect as PresEffect, true); + this.updateEffectDirection(this.activeItem.presEffectDirection as PresEffect, true); + const { presTransition, presDuration, presHideBefore, presHideAfter } = this.activeItem; + array.forEach(curDoc => { + curDoc.presTransition = presTransition; + curDoc.presDuration = presDuration; + curDoc.presHideBefore = presHideBefore; + curDoc.presHideAfter = presHideAfter; }); }; @@ -1785,7 +1582,7 @@ export class PresBox extends ViewBoxBaseComponent() { return (
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> @@ -1956,7 +1753,7 @@ export class PresBox extends ViewBoxBaseComponent() { // Dropdown that appears when the user wants to begin presenting (either minimize or sidebar view) @computed get presentDropdown() { return ( -
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> +
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
() { const activeFontColor = targetDoc['pres-text-color'] ? StrCast(targetDoc['pres-text-color']) : 'Black'; const viewedFontColor = targetDoc['pres-text-viewed-color'] ? StrCast(targetDoc['pres-text-viewed-color']) : 'Black'; return ( -
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> +
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
{this.stringType} selected
() { @undoBatch @action switchActive = (color: ColorState) => { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - const val = String(color.hex); - targetDoc['pres-text-color'] = val; + this.targetDoc['pres-text-color'] = String(color.hex); return true; }; @undoBatch @action switchPresented = (color: ColorState) => { - const targetDoc: Doc = this.targetDoc; - const val = String(color.hex); - targetDoc['pres-text-viewed-color'] = val; + this.targetDoc['pres-text-viewed-color'] = String(color.hex); return true; }; @@ -2228,12 +2020,11 @@ export class PresBox extends ViewBoxBaseComponent() { //Toggle whether the user edits or not @action editScrollProgressivize = (e: React.MouseEvent) => { - const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; if (!targetDoc.editScrollProgressivize) { if (!targetDoc.scrollProgressivize) { targetDoc.scrollProgressivize = true; - activeItem.scrollProgressivize = true; + this.activeItem.scrollProgressivize = true; } targetDoc.editScrollProgressivize = true; } else { @@ -2245,8 +2036,7 @@ export class PresBox extends ViewBoxBaseComponent() { @action progressivizeScroll = (e: React.MouseEvent) => { e.stopPropagation(); - const activeItem: Doc = this.activeItem; - activeItem.scrollProgressivize = !activeItem.scrollProgressivize; + this.activeItem.scrollProgressivize = !this.activeItem.scrollProgressivize; const targetDoc: Doc = this.targetDoc; targetDoc.scrollProgressivize = !targetDoc.scrollProgressivize; // CollectionFreeFormDocumentView.setupScroll(targetDoc, NumCast(targetDoc._currentFrame)); @@ -2353,13 +2143,14 @@ export class PresBox extends ViewBoxBaseComponent() { @action checkList = (doc: Doc, list: any): number => { const x: List = list; - if (x && x.length >= NumCast(doc._currentFrame) + 1) { + if (x?.length >= NumCast(doc._currentFrame) + 1) { return x[NumCast(doc._currentFrame)]; } else if (x) { x.length = NumCast(doc._currentFrame) + 1; x[NumCast(doc._currentFrame)] = x[NumCast(doc._currentFrame) - 1]; return x[NumCast(doc._currentFrame)]; - } else return 100; + } + return 100; }; @computed get progressivizeChildDocs() { @@ -2413,26 +2204,14 @@ export class PresBox extends ViewBoxBaseComponent() { } @action - nextAppearFrame = (doc: Doc, i: number): void => { - // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); - // const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); - const appearFrame = Cast(doc.appearFrame, 'number', null); - if (appearFrame === undefined) { - doc.appearFrame = 0; - } - doc.appearFrame = appearFrame + 1; + nextAppearFrame = (doc: Doc, i: number) => { + doc.appearFrame = (Cast(doc.appearFrame, 'number', null) ?? 0) + 1; this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame)); }; @action - prevAppearFrame = (doc: Doc, i: number): void => { - // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); - // const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); - const appearFrame = Cast(doc.appearFrame, 'number', null); - if (appearFrame === undefined) { - doc.appearFrame = 0; - } - doc.appearFrame = Math.max(0, appearFrame - 1); + prevAppearFrame = (doc: Doc, i: number) => { + doc.appearFrame = Math.max(0, (Cast(doc.appearFrame, 'number', null) ?? 0) - 1); this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame)); }; @@ -2483,12 +2262,7 @@ export class PresBox extends ViewBoxBaseComponent() {
*/} - -
{'View paths'}
- - }> + {'View paths'}
}>
1 && this.layoutDoc.presCollection ? 1 : 0.3, color: this._pathBoolean ? Colors.MEDIUM_BLUE : 'white', width: isMini ? '100%' : undefined }} className={'toolbar-button'} @@ -2507,22 +2281,12 @@ export class PresBox extends ViewBoxBaseComponent() {
*/} - -
{presKeyEvents ? 'Keys are active' : 'Keys are not active - click anywhere on the presentation trail to activate keys'}
- - }> + {presKeyEvents ? 'Keys are active' : 'Keys are not active - click anywhere on the presentation trail to activate keys'}
}>
- -
{propTitle}
- - }> + {propTitle}
}>
0 ? activeColor : inactiveColor }} />
@@ -2545,14 +2309,14 @@ export class PresBox extends ViewBoxBaseComponent() {
{isMini ? null : (