From 96a15ed27e9b17a77e6cab72d4087ddfe6066d2a Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 22 Aug 2022 11:02:17 -0400 Subject: made ink strokes animatable. added currentFrame to playgroundFields --- src/client/views/nodes/DocumentView.scss | 1 + 1 file changed, 1 insertion(+) (limited to 'src/client/views/nodes/DocumentView.scss') diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 6ea697a2f..9aaaf1e68 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -99,6 +99,7 @@ border-radius: inherit; width: 100%; height: 100%; + transition: inherit; .sharingIndicator { height: 30px; -- cgit v1.2.3-70-g09d2 From 0ed7131587c6739483da64a93d9f2ab6fdfbc15a Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 25 Aug 2022 11:06:38 -0400 Subject: fixed crashes in notetaking view and cleaned up code a bit. fixed undo of column deletion. --- src/client/util/CurrentUserUtils.ts | 11 ++- .../views/collections/CollectionNoteTakingView.tsx | 103 ++++++++------------- .../collections/CollectionNoteTakingViewColumn.tsx | 12 ++- .../collectionFreeForm/CollectionFreeFormView.tsx | 18 ++-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 10 +- src/client/views/nodes/DocumentView.scss | 3 + src/fields/SchemaHeaderField.ts | 2 +- src/fields/ScriptField.ts | 10 +- 8 files changed, 79 insertions(+), 90 deletions(-) (limited to 'src/client/views/nodes/DocumentView.scss') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 99a8c895f..2321d18ee 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -597,14 +597,17 @@ export class CurrentUserUtils { /// initializes the required buttons in the expanding button menu at the bottom of the Dash window static setupDockedButtons(doc: Doc, field="myDockedBtns") { const dockedBtns = DocCast(doc[field]); - const dockBtn = (opts: DocumentOptions, scripts: {[key:string]:string}) => + const dockBtn = (opts: DocumentOptions, scripts: {[key:string]:string}, funcs?: {[key:string]:string}) => DocUtils.AssignScripts(DocUtils.AssignOpts(DocListCast(dockedBtns?.data)?.find(doc => doc.title === opts.title), opts) ?? - CurrentUserUtils.createToolButton(opts), scripts); + CurrentUserUtils.createToolButton(opts), scripts, funcs); const btnDescs = [// setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet { scripts: { onClick: "undo()"}, opts: { title: "undo", icon: "undo-alt", toolTip: "Click to undo" }}, - { scripts: { onClick: "redo()"}, opts: { title: "redo", icon: "redo-alt", toolTip: "Click to redo" }} - ]; + { scripts: { onClick: "redo()"}, opts: { title: "redo", icon: "redo-alt", toolTip: "Click to redo" }}, + // { scripts: { onClick: 'prevKeyFrame(_readOnly_)'}, opts: { title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, width: 20}}, + // { scripts: { onClick:""}, opts: { title: "Num", icon: "", toolTip: "Frame Number", btnType: ButtonType.TextButton, width: 20}, funcs: { buttonText: 'selectedDocs()?.lastElement()?.currentFrame.toString()'}}, + // { scripts: { onClick: 'nextKeyFrame(_readOnly_)'}, opts:{title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, width: 20,} }, + ]; const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, dontUndo: true, _stayInCollection: true, ...desc.opts}, desc.scripts)); const dockBtnsReqdOpts = { title: "docked buttons", _height: 40, flexGap: 0, linearViewFloating: true, diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index b359ef420..5a6d899ef 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -11,7 +11,7 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Ty import { TraceMobx } from '../../../fields/util'; import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, returnZero, smoothScroll, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; -import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; +import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager, dropActionType } from '../../util/DragManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; @@ -19,7 +19,6 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { LightboxView } from '../LightboxView'; -import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; @@ -30,13 +29,6 @@ import { CollectionNoteTakingViewDivider } from './CollectionNoteTakingViewDivid import { CollectionSubView } from './CollectionSubView'; const _global = (window /* browser */ || global) /* node */ as any; -export type collectionNoteTakingViewProps = { - chromeHidden?: boolean; - viewType?: CollectionViewType; - NativeWidth?: () => number; - NativeHeight?: () => number; -}; - /** * CollectionNoteTakingView is a column-based view for displaying documents. In this view, the user can (1) * add and remove columns (2) change column sizes and (3) move documents within and between columns. This @@ -45,28 +37,32 @@ export type collectionNoteTakingViewProps = { * the rest of Dash, so it may be worthwhile to transition the headers to simple documents. */ @observer -export class CollectionNoteTakingView extends CollectionSubView>() { +export class CollectionNoteTakingView extends CollectionSubView() { _disposers: { [key: string]: IReactionDisposer } = {}; _masonryGridRef: HTMLDivElement | null = null; _draggerRef = React.createRef(); + notetakingCategoryField = 'NotetakingCategory'; + dividerWidth = 16; @observable docsDraggedRowCol: number[] = []; @observable _cursor: CursorProperty = 'grab'; @observable _scroll = 0; @computed get chromeHidden() { - return this.props.chromeHidden || BoolCast(this.layoutDoc.chromeHidden); + return BoolCast(this.layoutDoc.chromeHidden); } // columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns @computed get columnHeaders() { const columnHeaders = Cast(this.dataDoc.columnHeaders, listSpec(SchemaHeaderField), null); - const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders.find(sh => sh.heading === 'unset')); + const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders?.find(sh => sh.heading === 'unset')); if (needsUnsetCategory) { - setTimeout(() => columnHeaders.push(new SchemaHeaderField('unset', undefined, undefined, 1))); + setTimeout(() => { + const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders?.find(sh => sh.heading === 'unset')); + if (needsUnsetCategory) { + if (columnHeaders) columnHeaders.push(new SchemaHeaderField('unset', undefined, undefined, 1)); + else this.dataDoc.columnHeaders = new List(); + } + }); } - return columnHeaders; - } - // notetakingCategoryField returns the key to accessing a document's column value - @computed get notetakingCategoryField() { - return 'NotetakingCategory'; + return columnHeaders ?? ([] as SchemaHeaderField[]); } @computed get headerMargin() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin); @@ -74,10 +70,6 @@ export class CollectionNoteTakingView extends CollectionSubView([new SchemaHeaderField('New Column', undefined, undefined, 1)]); - } - } - // children is passed as a prop to the NoteTakingField, which uses this function // to render the docs you see within an individual column. children = (docs: Doc[]) => { @@ -149,7 +132,7 @@ export class CollectionNoteTakingView extends CollectionSubView rowCol[1]) { const offset = 0; sections.get(columnHeaders[rowCol[1]])?.splice(rowCol[0] - offset, 0, ...DragManager.docsBeingDragged); } @@ -236,9 +219,6 @@ export class CollectionNoteTakingView extends CollectionSubView (d[this.notetakingCategoryField] = colHeader)); // used to notify sections to re-render this.docsDraggedRowCol.length = 0; - this.docsDraggedRowCol.push(dropInd, this.getColumnFromXCoord(xCoord)); + const columnFromCoord = this.getColumnFromXCoord(xCoord); + columnFromCoord !== undefined && this.docsDraggedRowCol.push(dropInd, columnFromCoord); } }; // getColumnFromXCoord returns the column index for a given x-coordinate (currently always the client's mouse coordinate). // This function is used to know which document a column SHOULD be in while it is being dragged. - getColumnFromXCoord = (xCoord: number): number => { + getColumnFromXCoord = (xCoord: number): number | undefined => { + let colIndex: number | undefined = undefined; const numColumns = this.columnHeaders.length; const coords = []; let colStartXCoord = 0; @@ -411,7 +393,6 @@ export class CollectionNoteTakingView extends CollectionSubView coords[i] && xCoord < coords[i + 1]) { colIndex = i; @@ -423,20 +404,16 @@ export class CollectionNoteTakingView extends CollectionSubView { - const colIndex = this.getColumnFromXCoord(xCoord); - const colHeader = StrCast(this.columnHeaders[colIndex].heading); - // const docs = this.childDocList - const docs = this.childDocs; const docsMatchingHeader: Doc[] = []; - if (docs) { - docs.map(d => { - if (d instanceof Promise) return; - const sectionValue = (d[this.notetakingCategoryField] as object) ?? 'unset'; - if (sectionValue.toString() == colHeader) { - docsMatchingHeader.push(d); - } - }); - } + const colIndex = this.getColumnFromXCoord(xCoord); + const colHeader = colIndex === undefined ? 'unset' : StrCast(this.columnHeaders[colIndex].heading); + this.childDocs?.map(d => { + if (d instanceof Promise) return; + const sectionValue = (d[this.notetakingCategoryField] as object) ?? 'unset'; + if (sectionValue.toString() == colHeader) { + docsMatchingHeader.push(d); + } + }); return docsMatchingHeader; }; @@ -511,7 +488,7 @@ export class CollectionNoteTakingView extends CollectionSubView this.addDocument(doc)); const newDoc = this.childDocs.lastElement(); - const colHeader = StrCast(this.columnHeaders[colInd].heading); + const colHeader = colInd === undefined ? 'unset' : StrCast(this.columnHeaders[colInd].heading); newDoc[this.notetakingCategoryField] = colHeader; const docs = this.childDocList; if (docs && targInd !== -1) { @@ -570,9 +547,9 @@ export class CollectionNoteTakingView extends CollectionSubView { - for (const header of this.columnHeaders) { - if (header.heading == value) { - alert('You cannot use an existing column name. Please try a new column name'); - return value; + if (this.columnHeaders) { + for (const header of this.columnHeaders) { + if (header.heading == value) { + alert('You cannot use an existing column name. Please try a new column name'); + return value; + } } } const columnHeaders = Cast(this.props.Document.columnHeaders, listSpec(SchemaHeaderField), null); @@ -678,10 +657,10 @@ export class CollectionNoteTakingView extends CollectionSubView { - const columnHeaders = Cast(this.props.Document.columnHeaders, listSpec(SchemaHeaderField), null); - if (columnHeaders && this.props.headingObject) { - const index = columnHeaders.indexOf(this.props.headingObject); + const acolumnHeaders = Cast(this.props.Document.columnHeaders, listSpec(SchemaHeaderField), null); + if (acolumnHeaders && this.props.headingObject) { + const index = acolumnHeaders.indexOf(this.props.headingObject); + const columnHeaders = new List(acolumnHeaders.map(header => header[Copy]())); // needed for undo to work properly. otherwise we end up changing field values in the undo stack since they are shared by reference const newColIndex = index > 0 ? index - 1 : 1; const newColHeader = this.props.columnHeaders ? this.props.columnHeaders[newColIndex] : undefined; const newHeading = newColHeader ? newColHeader.heading : 'unset'; this.props.docList.forEach(d => (d[this.props.pivotField] = newHeading)); const colWidth = this.props.columnHeaders ? this.props.columnHeaders[index].width : 0; columnHeaders.splice(index, 1); + Doc.GetProto(this.props.Document).columnHeaders = columnHeaders; this.props.resizeColumns(false, colWidth, index); } }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 052cbd3bb..c44b33ed0 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -44,7 +44,6 @@ import { PresBox } from '../../nodes/trails/PresBox'; import { VideoBox } from '../../nodes/VideoBox'; import { CreateImage } from '../../nodes/WebBoxRenderer'; import { StyleProp } from '../../StyleProvider'; -import { CollectionDockingView } from '../CollectionDockingView'; import { CollectionSubView } from '../CollectionSubView'; import { TreeViewType } from '../CollectionTreeView'; import { TabDocView } from '../TabDocView'; @@ -233,11 +232,11 @@ export class CollectionFreeFormView extends CollectionSubView newBox[field]); - CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[`${field}-indexed`]); - CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[field]); + const vals = CollectionFreeFormDocumentView.animFields.map(field => newBox[field.key]); + CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[`${field.key}-indexed`]); + CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[field.key]); delete newBox.activeFrame; - CollectionFreeFormDocumentView.animFields.forEach((field, i) => field !== 'opacity' && (newBox[field] = vals[i])); + CollectionFreeFormDocumentView.animFields.forEach((field, i) => field.key !== 'opacity' && (newBox[field.key] = vals[i])); } } if (this.Document._currentFrame !== undefined && !this.props.isAnnotationOverlay) { @@ -275,10 +274,11 @@ export class CollectionFreeFormView extends CollectionSubView() { - public static animFields = ['_height', '_width', 'x', 'y', '_scrollTop', 'opacity']; // fields that are configured to be animatable using animation frames + public static animFields: { key: string; val?: number }[] = [{ key: '_height' }, { key: '_width' }, { key: 'x' }, { key: 'y' }, { key: '_scrollTop' }, { key: 'opacity', val: 1 }, { key: 'viewScale', val: 1 }, { key: 'panX' }, { key: 'panY' }]; // 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; @@ -88,9 +88,9 @@ export class CollectionFreeFormDocumentView extends DocComponent { - p[val] = Cast(`${val}-indexed`, listSpec('number'), [NumCast(doc[val])]).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as number); + p[val.key] = Cast(`${val}-indexed`, listSpec('number'), fillIn ? [NumCast(doc[val.key], val.val)] : []).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as number); return p; }, {} as { [val: string]: Opt }); } @@ -117,7 +117,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { doc._viewTransition = doc.dataTransition = 'all 1s'; CollectionFreeFormDocumentView.animFields.forEach(val => { - const findexed = Cast(doc[`${val}-indexed`], listSpec('number'), null); + const findexed = Cast(doc[`${val.key}-indexed`], listSpec('number'), null); findexed?.length <= timecode + 1 && findexed.push(undefined as any as number); }); CollectionFreeFormDocumentView.animStringFields.forEach(val => { @@ -174,7 +174,7 @@ 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.MakeInterpolatedNumber(val, 'activeFrame', doc, currTimecode))); + CollectionFreeFormDocumentView.animFields.forEach(val => (doc[val.key] = ComputedField.MakeInterpolatedNumber(val.key, 'activeFrame', doc, currTimecode, val.val))); CollectionFreeFormDocumentView.animStringFields.forEach(val => (doc[val] = ComputedField.MakeInterpolatedString(val, 'activeFrame', doc, currTimecode))); CollectionFreeFormDocumentView.animDataFields.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 diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 9aaaf1e68..ab7116150 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -2,6 +2,7 @@ .documentView-effectsWrapper { border-radius: inherit; + transition: inherit; } // documentViews have a docView-hack tag which is replaced by this tag when capturing bitmaps (when the dom is converted to an html string) @@ -212,10 +213,12 @@ display: flex; width: 100%; height: 100%; + transition: inherit; .contentFittingDocumentView-previewDoc { position: relative; display: inline; + transition: inherit; } .contentFittingDocumentView-input { diff --git a/src/fields/SchemaHeaderField.ts b/src/fields/SchemaHeaderField.ts index 1321bc327..0b51db70b 100644 --- a/src/fields/SchemaHeaderField.ts +++ b/src/fields/SchemaHeaderField.ts @@ -115,7 +115,7 @@ export class SchemaHeaderField extends ObjectField { } [ToScriptString]() { - return `header(${this.heading},${this.type}})`; + return `header(${this.heading},${this.type},${this.width}})`; } [ToString]() { return `SchemaHeaderField`; diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 48d5c5563..d38a019b3 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -189,13 +189,13 @@ export class ComputedField extends ScriptField { const compiled = ScriptField.CompileScript(script, params, true, capturedVariables); return compiled.compiled ? new ComputedField(compiled) : undefined; } - public static MakeInterpolatedNumber(fieldKey: string, interpolatorKey: string, doc: Doc, curTimecode: number) { + public static MakeInterpolatedNumber(fieldKey: string, interpolatorKey: string, doc: Doc, curTimecode: number, defaultVal: Opt) { if (!doc[`${fieldKey}-indexed`]) { const flist = new List(numberRange(curTimecode + 1).map(i => undefined) as any as number[]); - flist[curTimecode] = NumCast(doc[fieldKey]); + flist[curTimecode] = Cast(doc[fieldKey], 'number', null); doc[`${fieldKey}-indexed`] = flist; } - const getField = ScriptField.CompileScript(`getIndexVal(self['${fieldKey}-indexed'], self.${interpolatorKey})`, {}, true, {}); + const getField = ScriptField.CompileScript(`getIndexVal(self['${fieldKey}-indexed'], self.${interpolatorKey}, ${defaultVal})`, {}, 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; } @@ -260,8 +260,8 @@ ScriptingGlobals.add( ); ScriptingGlobals.add( - function getIndexVal(list: any[], index: number) { - return list?.reduce((p, x, i) => ((i <= index && x !== undefined) || p === undefined ? x : p), undefined as any); + function getIndexVal(list: any[], index: number, defaultVal: Opt = undefined) { + return list?.reduce((p, x, i) => ((i <= index && x !== undefined) || p === undefined ? x : p), defaultVal); }, 'returns the value at a given index of a list', '(list: any[], index: number)' -- cgit v1.2.3-70-g09d2 From 505fa1fe53b2ffc75231f2ee8a66da4be92c76c4 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 29 Aug 2022 16:40:39 -0400 Subject: fixed centering link targets in zoomed images and scrolled docs. stopped highlighting opacity=0 documents --- src/Utils.ts | 4 ++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 19 +++++++++++-------- src/client/views/nodes/DocumentView.scss | 1 - src/fields/Doc.ts | 4 ++-- 4 files changed, 15 insertions(+), 13 deletions(-) (limited to 'src/client/views/nodes/DocumentView.scss') diff --git a/src/Utils.ts b/src/Utils.ts index 9e002ebd4..6fc00040f 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -221,8 +221,8 @@ export namespace Utils { if (scrollTop + contextHgt < Math.min(scrollHeight, targetY + minSpacing + targetHgt)) { return Math.ceil(targetY + minSpacing + targetHgt - contextHgt); } - if (scrollTop >= Math.max(0, targetY - minSpacing - targetHgt)) { - return Math.max(0, Math.floor(targetY - minSpacing - targetHgt)); + if (scrollTop >= Math.max(0, targetY - minSpacing)) { + return Math.max(0, Math.floor(targetY - minSpacing)); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ede113a9f..c2bd7de54 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1141,7 +1141,7 @@ export class CollectionFreeFormView extends CollectionSubView (this._viewTransition = 0)); } + runInAction(() => (this._viewTransition = 0)); return resetView; }; const xf = !cantTransform @@ -1198,10 +1198,13 @@ export class CollectionFreeFormView extends CollectionSubView Date: Mon, 31 Oct 2022 13:26:52 -0400 Subject: cleaning up link count icon to be part of documentLinks view and to appear on tab views that have links. --- src/client/views/DocumentButtonBar.tsx | 31 ++-------- src/client/views/GlobalKeyHandler.ts | 5 -- src/client/views/nodes/DocumentLinksButton.scss | 34 +++++------ src/client/views/nodes/DocumentLinksButton.tsx | 67 ++++++++++----------- src/client/views/nodes/DocumentView.scss | 2 +- src/client/views/nodes/DocumentView.tsx | 80 ++++++++++++------------- 6 files changed, 93 insertions(+), 126 deletions(-) (limited to 'src/client/views/nodes/DocumentView.scss') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index d42ff436f..ce77b7446 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -317,24 +317,6 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV ); } - - @computed - get moreButton() { - const targetDoc = this.view0?.props.Document; - return !targetDoc ? null : ( - -
{`${SettingsManager.propertiesWidth > 0 ? 'Close' : 'Open'} Properties Panel`}
- - }> -
(SettingsManager.propertiesWidth = SettingsManager.propertiesWidth > 0 ? 0 : 250))}> - -
-
- ); - } - @computed get metadataButton() { const view0 = this.view0; @@ -463,6 +445,9 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV const considerPush = isText && this.considerGoogleDocsPush; return (
+
+ +
@@ -475,11 +460,8 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV { Doc.noviceMode ? null :
{this.templateButton}
/*
- {this.metadataButton} -
-
- {this.contextButton} -
*/ + {this.metadataButton} +
*/ } {!SelectionManager.Views()?.some(v => v.allLinks.length) ? null :
{this.followLinkButton}
}
{this.pinButton}
@@ -493,9 +475,6 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV {this.considerGoogleDocsPull}
{this.menuButton}
- {/* {Doc.noviceMode ? (null) :
- {this.moreButton} -
} */} ); } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 8e9c18cf3..c19e6831f 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -151,11 +151,6 @@ export class KeyManager { SelectionManager.DeselectAll(); } else DocumentDecorations.Instance.onCloseClick(true); }, 'backspace'); - // const selected = SelectionManager.Views().filter(dv => !dv.topMost); - // UndoManager.RunInBatch(() => { - // SelectionManager.DeselectAll(); - // selected.map(dv => !dv.props.Document._stayInCollection && dv.props.removeDocument?.(dv.props.Document)); - // }, "delete"); return { stopPropagation: true, preventDefault: true }; } break; diff --git a/src/client/views/nodes/DocumentLinksButton.scss b/src/client/views/nodes/DocumentLinksButton.scss index 0f3eb14bc..6da0b73ba 100644 --- a/src/client/views/nodes/DocumentLinksButton.scss +++ b/src/client/views/nodes/DocumentLinksButton.scss @@ -1,8 +1,9 @@ -@import "../global/globalCssVariables.scss"; +@import '../global/globalCssVariables.scss'; .documentLinksButton-wrapper { transform-origin: top left; width: 100%; + height: 100%; } .documentLinksButton-menu { @@ -21,6 +22,16 @@ position: absolute; } +.documentLinksButton-showCount { + position: absolute; + border-radius: 50%; + opacity: 0.9; + pointer-events: auto; + display: flex; + align-items: center; + background-color: $light-blue; + color: black; +} .documentLinksButton, .documentLinksButton-endLink, .documentLinksButton-startLink { @@ -34,6 +45,7 @@ text-transform: uppercase; letter-spacing: 2px; font-size: 10px; + transform-origin: top left; transition: transform 0.2s; text-align: center; display: flex; @@ -46,13 +58,10 @@ cursor: pointer; } } - .documentLinksButton { background-color: $dark-gray; color: $white; font-weight: bold; - width: 80%; - height: 80%; font-size: 100%; font-family: 'Roboto'; transition: 0.2s ease all; @@ -61,31 +70,20 @@ background-color: $black; } } - .documentLinksButton.startLink { background-color: $medium-blue; + width: 75%; + height: 75%; color: $white; font-weight: bold; - width: 80%; - height: 80%; font-size: 100%; transition: 0.2s ease all; - - &:hover { - background-color: $black; - } } .documentLinksButton-endLink { border: $medium-blue 2px dashed; color: $medium-blue; background-color: none !important; - width: 80%; - height: 80%; font-size: 100%; transition: 0.2s ease all; - - &:hover { - background-color: $light-blue; - } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 9ffbf8e37..1d455ad08 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -4,19 +4,18 @@ import { action, computed, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Opt } from '../../../fields/Doc'; import { StrCast } from '../../../fields/Types'; -import { TraceMobx } from '../../../fields/util'; import { emptyFunction, returnFalse, setupMoveUpEvents, StopEvent } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { Hypothesis } from '../../util/HypothesisUtils'; import { LinkManager } from '../../util/LinkManager'; import { undoBatch, UndoManager } from '../../util/UndoManager'; -import { Colors } from '../global/globalEnums'; import './DocumentLinksButton.scss'; import { DocumentView } from './DocumentView'; import { LinkDescriptionPopup } from './LinkDescriptionPopup'; import { TaskCompletionBox } from './TaskCompletedBox'; import React = require('react'); +import _ = require('lodash'); const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; @@ -24,10 +23,12 @@ export const Flyout = higflyout.default; interface DocumentLinksButtonProps { View: DocumentView; - Offset?: (number | undefined)[]; + Bottom?: boolean; AlwaysOn?: boolean; InMenu?: boolean; + OnHover?: boolean; StartLink?: boolean; //whether the link HAS been started (i.e. now needs to be completed) + ShowCount?: boolean; scaling?: () => number; // how uch doc is scaled so that link buttons can invert it } @observer @@ -119,7 +120,6 @@ export class DocumentLinksButton extends React.Component Doc.BrushDoc(this.props.View.Document)); } }; @@ -256,28 +256,32 @@ export class DocumentLinksButton extends React.Component; + const btnDim = 30; const isActive = DocumentLinksButton.StartLink === this.props.View.props.Document && this.props.StartLink; - return !this.props.InMenu ? ( -
-
- {Array.from(this.filteredLinks).length} -
+ const scaling = Math.min(1, this.props.scaling?.() || 1); + const showLinkCount = (onHover?: boolean, offset?: boolean) => ( +
+ {Array.from(this.filteredLinks).length}
+ ); + return this.props.ShowCount ? ( + showLinkCount(this.props.OnHover, this.props.Bottom) ) : (
- {this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document ? ( //if the origin node is not this node + {this.props.StartLink ? ( //if link has been started from current node, then set behavior of link button to deactivate linking when clicked again +
+ +
+ ) : null} + {!this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document ? ( //if the origin node is not this node
) : 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}
); } render() { - TraceMobx(); - const menuTitle = this.props.StartLink ? 'Drag or tap to start link' : 'Tap to complete link'; const buttonTitle = 'Tap to view links; double tap to open link collection'; - const title = this.props.InMenu ? menuTitle : buttonTitle; + const title = this.props.ShowCount ? buttonTitle : menuTitle; //render circular tooltip if it isn't set to invisible and show the number of doc links the node has, and render inner-menu link button for starting/stopping links if currently in menu return !Array.from(this.filteredLinks).length && !this.props.AlwaysOn ? null : (
- {(this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink)) || (!DocumentLinksButton.LinkEditorDocView && !this.props.InMenu) ? ( - {title}
}>{this.linkButtonInner} - ) : ( - this.linkButtonInner - )} + {title}
: <>}>{this.linkButtonInner} ); } diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 6cadeec41..5c95177c5 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -209,7 +209,7 @@ .contentFittingDocumentView { position: relative; - display: flex; + display: block; width: 100%; height: 100%; transition: inherit; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b5dde211b..50b76896e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,7 +1,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; -import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, Opt, StrListCast, WidthSym } from '../../../fields/Doc'; import { Document } from '../../../fields/documentSchemas'; @@ -198,6 +198,7 @@ export interface DocumentViewInternalProps extends DocumentViewProps { NativeWidth: () => number; NativeHeight: () => number; isSelected: (outsideReaction?: boolean) => boolean; + isHovering: () => boolean; select: (ctrlPressed: boolean) => void; DocumentView: () => DocumentView; viewPath: () => DocumentView[]; @@ -257,9 +258,6 @@ export class DocumentViewInternal extends DocComponent (this.props.NativeDimScaling?.() || 1) * this.props.DocumentView().screenToLocalTransform().Scale; get audioAnnoState() { return this.dataDoc.audioAnnoState ?? 'stopped'; } @@ -1066,7 +1063,7 @@ export class DocumentViewInternal extends DocComponent{audioTextAnnos?.lastElement()}}>
@@ -1074,15 +1071,6 @@ export class DocumentViewInternal extends DocComponent ); } - @computed get linkCountView() { - return this.props.renderDepth === -1 || SnappingManager.GetIsDragging() || (!this.props.isSelected() && !this._isHovering) || this.hideLinkButton ? null : ( - - ); - } @computed get contents() { TraceMobx(); return ( @@ -1119,7 +1107,7 @@ export class DocumentViewInternal extends DocComponent {this.layoutDoc.hideAllLinks ? null : this.allLinkEndpoints} - {this.linkCountView} {this.audioAnnoView}
); @@ -1149,16 +1136,13 @@ export class DocumentViewInternal extends DocComponent this.props.PanelWidth() || 1; anchorPanelHeight = () => this.props.PanelHeight() || 1; anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { + // prettier-ignore switch (property) { - case StyleProp.ShowTitle: - return ''; - case StyleProp.PointerEvents: - return 'none'; - case StyleProp.LinkSource: - return this.props.Document; // pass the LinkSource to the LinkAnchorBox - default: - return this.props.styleProvider?.(doc, props, property); + case StyleProp.ShowTitle: return ''; + case StyleProp.PointerEvents: return 'none'; + case StyleProp.LinkSource: return this.props.Document; // pass the LinkSource to the LinkAnchorBox } + return this.props.styleProvider?.(doc, props, property); }; // We need to use allrelatedLinks to get not just links to the document as a whole, but links to // anchors that are not rendered as DocumentViews (marked as 'unrendered' with their 'annotationOn' set to this document). e.g., @@ -1360,10 +1344,7 @@ export class DocumentViewInternal extends DocComponent ); } - isHovering = () => this._isHovering; - @observable _isHovering = false; @observable _: string = ''; - _hoverTimeout: any = undefined; renderDoc = (style: object) => { TraceMobx(); const thumb = ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url?.href.replace('.png', '_m.png'); @@ -1374,17 +1355,6 @@ export class DocumentViewInternal extends DocComponent { - clearTimeout(this._hoverTimeout); - this._isHovering = true; - })} - onPointerLeave={action(() => { - clearTimeout(this._hoverTimeout); - this._hoverTimeout = setTimeout( - action(() => (this._isHovering = false)), - 500 - ); - })} style={{ ...style, background: isButton || thumb ? undefined : this.backgroundColor, @@ -1535,6 +1505,18 @@ export class DocumentView extends React.Component { return this.props.fitWidth?.(this.rootDoc) || this.layoutDoc.fitWidth; } + @computed get hideLinkButton() { + return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkButton + (this.isSelected() ? ':selected' : '')); + } + linkButtonInverseScaling = () => (this.props.NativeDimScaling?.() || 1) * this.screenToLocalTransform().Scale; + + @computed get linkCountView() { + return (this.props.renderDepth === -1 || SnappingManager.GetIsDragging() || (this.isSelected() && this.props.renderDepth) || !this._isHovering || this.hideLinkButton) && + DocumentLinksButton.LinkEditorDocView?.rootDoc !== this.rootDoc ? null : ( + + ); + } + @computed get docViewPath(): DocumentView[] { return this.props.docViewPath ? [...this.props.docViewPath(), this] : [this]; } @@ -1680,6 +1662,9 @@ export class DocumentView extends React.Component { Object.values(this._disposers).forEach(disposer => disposer?.()); !BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); } + _hoverTimeout: any = undefined; + isHovering = () => this._isHovering; + @observable _isHovering = false; render() { TraceMobx(); @@ -1687,7 +1672,19 @@ export class DocumentView extends React.Component { const yshift = Math.abs(this.Yshift) <= 0.001 ? this.props.PanelHeight() : undefined; const isButton = this.props.Document.type === DocumentType.FONTICON || this.props.Document._viewType === CollectionViewType.Linear; return ( -
+
{ + clearTimeout(this._hoverTimeout); + this._isHovering = true; + })} + onPointerLeave={action(() => { + clearTimeout(this._hoverTimeout); + this._hoverTimeout = setTimeout( + action(() => (this._isHovering = false)), + 500 + ); + })}> {!this.props.Document || !this.props.PanelWidth() ? null : (
{ NativeDimScaling={this.NativeDimScaling} isSelected={this.isSelected} select={this.select} + isHovering={this.isHovering} ScreenToLocalTransform={this.screenToLocalTransform} focus={this.props.focus || emptyFunction} ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))} />
)} + + {this.linkCountView}
); } -- cgit v1.2.3-70-g09d2 From 10f6c2c56fa76100817312f9e019340ae2094289 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 1 Nov 2022 09:32:45 -0400 Subject: from last --- src/client/views/nodes/DocumentView.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/nodes/DocumentView.scss') diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 5c95177c5..6cadeec41 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -209,7 +209,7 @@ .contentFittingDocumentView { position: relative; - display: block; + display: flex; width: 100%; height: 100%; transition: inherit; -- cgit v1.2.3-70-g09d2 From 3d8bd17fa4f031f2223840b336c313a18e7e87aa Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 14 Nov 2022 14:29:48 -0500 Subject: fixed following link 'inPlace' from within lightbox to do same thing as if out of lightbox. fixed contentActive behavior for multicolumn view. removed progressivize from presbox. --- src/client/documents/Documents.ts | 1 - src/client/util/DocumentManager.ts | 24 +- src/client/util/LinkFollower.ts | 7 +- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/LightboxView.tsx | 8 +- src/client/views/MainView.tsx | 2 +- src/client/views/PropertiesView.tsx | 14 - src/client/views/collections/TabDocView.tsx | 9 +- .../collectionFreeForm/CollectionFreeFormView.scss | 50 --- .../collectionFreeForm/CollectionFreeFormView.tsx | 54 +-- .../CollectionMulticolumnView.tsx | 10 +- .../CollectionMultirowView.tsx | 8 +- src/client/views/nodes/DocumentView.scss | 6 +- src/client/views/nodes/trails/PresBox.tsx | 475 +-------------------- 14 files changed, 75 insertions(+), 595 deletions(-) (limited to 'src/client/views/nodes/DocumentView.scss') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index f1b8c3034..e44004f45 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -259,7 +259,6 @@ export class DocumentOptions { appearFrame?: number; // the frame in which the document appears presTransition?: number; //the time taken for the transition TO a document presDuration?: number; //the duration of the slide in presentation view - presProgressivize?: boolean; borderRounding?: string; boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow data?: any; diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index b046d950f..01ca24439 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -131,6 +131,7 @@ export class DocumentManager { return views?.find(view => view.ContentDiv?.getBoundingClientRect().width && view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse) || (views.length ? views[0] : undefined); }; public getFirstDocumentView = (toFind: Doc, originatingDoc: Opt = undefined): DocumentView | undefined => { + if (LightboxView.LightboxDoc) return DocumentManager.Instance.getLightboxDocumentView(toFind, originatingDoc); const views = this.getDocumentViews(toFind).filter(view => view.rootDoc !== originatingDoc); return views?.find(view => view.ContentDiv?.getBoundingClientRect().width && view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse) || (views.length ? views[0] : undefined); }; @@ -168,8 +169,7 @@ export class DocumentManager { presZoomScale?: number ): void => { originalTarget = originalTarget ?? targetDoc; - const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView; - const docView = getFirstDocView(targetDoc, originatingDoc); + const docView = this.getFirstDocumentView(targetDoc, originatingDoc); const annotatedDoc = Cast(targetDoc.annotationOn, Doc, null); const resolvedTarget = targetDoc.type === DocumentType.MARKER ? annotatedDoc ?? docView?.rootDoc ?? targetDoc : docView?.rootDoc ?? targetDoc; // if target is a marker, then focus toggling should apply to the document it's on since the marker itself doesn't have a hidden field var wasHidden = resolvedTarget.hidden; @@ -206,11 +206,11 @@ export class DocumentManager { } finished?.(); }; - const annoContainerView = (!wasHidden || resolvedTarget !== annotatedDoc) && annotatedDoc && getFirstDocView(annotatedDoc); + const annoContainerView = (!wasHidden || resolvedTarget !== annotatedDoc) && annotatedDoc && this.getFirstDocumentView(annotatedDoc); 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 + const targetDocContextView = (targetDocContext && this.getFirstDocumentView(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 const focusView = !docView && targetDoc.type === DocumentType.MARKER && annoContainerView ? annoContainerView : docView; if (annoContainerView) { if (annoContainerView.props.Document.layoutKey === 'layout_icon') { @@ -281,7 +281,7 @@ export class DocumentManager { } else { // no timecode means we need to find the context view and focus on our target const findView = (delay: number) => { - const retryDocView = getFirstDocView(resolvedTarget); // test again for the target view snce we presumably created the context above by focusing on it + const retryDocView = this.getFirstDocumentView(resolvedTarget); // test again for the target view snce we presumably created the context above by focusing on it if (retryDocView) { // we found the target in the context. Doc.linkFollowHighlight(retryDocView.rootDoc); @@ -316,10 +316,20 @@ export class DocumentManager { } } // there's no context view so we need to create one first and try again when that finishes - const finishFunc = () => this.jumpToDocument(targetDoc, true, createViewFunc, docContext, linkDoc, true /* if we don't find the target, we want to get rid of the context just created */, undefined, finished, originalTarget); createViewFunc( targetDocContext, // after creating the context, this calls the finish function that will retry looking for the target - finishFunc + () => + this.jumpToDocument( + targetDoc, + true, + (doc: Doc, finished?: () => void) => doc !== targetDocContext && createViewFunc(doc, finished), + docContext, + linkDoc, + true /* if target not found, get rid of context just created */, + undefined, + finished, + originalTarget + ) ); } } diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 1608a77f2..c09c9d1c5 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -30,11 +30,10 @@ export class LinkFollower { const createViewFunc = (doc: Doc, followLoc: string, finished?: Opt<() => void>) => { const createTabForTarget = (didFocus: boolean) => new Promise(res => { - const where = LightboxView.LightboxDoc ? 'lightbox' : StrCast(sourceDoc.followLinkLocation, followLoc); + const where = LightboxView.LightboxDoc ? 'inPlace' : StrCast(sourceDoc.followLinkLocation, followLoc); docViewProps.addDocTab(doc, where); setTimeout(() => { - const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView; - const targDocView = getFirstDocView(doc); // get first document view available within the lightbox if that's open, or anywhere otherwise. + const targDocView = DocumentManager.Instance.getFirstDocumentView(doc); // get first document view available within the lightbox if that's open, or anywhere otherwise. if (targDocView) { targDocView.props.focus(doc, { willZoom: BoolCast(sourceDoc.followLinkZoom, false), @@ -110,7 +109,7 @@ export class LinkFollower { containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext]; } const targetContexts = LightboxView.LightboxDoc ? [containerAnnoDoc || containerDocContext[0]].filter(a => a) : containerDocContext; - DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, 'lightbox'), finished), targetContexts, linkDoc, undefined, sourceDoc, allFinished); + DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, 'inPlace'), finished), targetContexts, linkDoc, undefined, sourceDoc, allFinished); } } else { allFinished(); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index a110bf51a..36875290e 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -458,7 +458,6 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
) : null} - {Doc.noviceMode ? null :
{this.recordButton}
} { Doc.noviceMode ? null :
{this.templateButton}
/*
@@ -467,6 +466,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV } {Doc.noviceMode || !SelectionManager.Views()?.some(v => v.allLinks.length) ? null :
{this.followLinkButton}
}
{this.pinButton}
+
{this.recordButton}
{!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null :
{this.shareButton}
} {!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null : (
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 91773419a..5660a34e9 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -4,7 +4,8 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { InkTool } from '../../fields/InkField'; -import { Cast, NumCast, StrCast } from '../../fields/Types'; +import { List } from '../../fields/List'; +import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../Utils'; import { DocUtils } from '../documents/Documents'; import { DocumentManager } from '../util/DocumentManager'; @@ -141,6 +142,11 @@ export class LightboxView extends React.Component { } } public static AddDocTab = (doc: Doc, location: string, layoutTemplate?: Doc, openInTabFunc?: any) => { + const inPlaceView = DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined; + if (inPlaceView) { + inPlaceView.dataDoc[Doc.LayoutFieldKey(inPlaceView.rootDoc)] = new List([doc]); + return true; + } LightboxView.openInTabFunc = openInTabFunc; SelectionManager.DeselectAll(); return LightboxView.SetLightboxDoc( diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 9648a7807..987bfc23d 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -690,11 +690,11 @@ export class MainView extends React.Component { switch (locationFields[0]) { default: case 'inPlace': + case 'lightbox': return LightboxView.AddDocTab(doc, location); case 'add': return CollectionDockingView.AddSplit(doc, locationParams); case 'dashboard': return DashboardView.openDashboard(doc); case 'close': return CollectionDockingView.CloseSplit(doc, locationParams); case 'fullScreen': return CollectionDockingView.OpenFullScreen(doc); - case 'lightbox': return LightboxView.AddDocTab(doc, location); case 'toggle': return CollectionDockingView.ToggleSplit(doc, locationParams); } }; diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 842664402..1f161c01b 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -95,7 +95,6 @@ export class PropertiesView extends React.Component { //Pres Trails booleans: @observable openPresTransitions: boolean = false; - @observable openPresProgressivize: boolean = false; @observable openAddSlide: boolean = false; @observable openSlideOptions: boolean = false; @@ -1651,19 +1650,6 @@ export class PropertiesView extends React.Component { {this.openPresTransitions ?
{PresBox.Instance.transitionDropdown}
: null}
)} - {/* {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) :
-
this.openPresProgressivize = !this.openPresProgressivize)} - style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}> -     Progressivize -
- -
-
- {this.openPresProgressivize ?
- {PresBox.Instance.progressivizeDropdown} -
: null} -
} */} {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? null : (
{ // // TabDocView.PinDoc(doc, { hidePresBox: true }); // return LightboxView.AddDocTab(doc, location, undefined, this.addDocTab); // } + case 'inPlace': + const inPlaceView = DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined; + if (inPlaceView) { + inPlaceView.dataDoc[Doc.LayoutFieldKey(inPlaceView.rootDoc)] = new List([doc]); + return true; + } case 'lightbox': return LightboxView.AddDocTab(doc, location, undefined, this.addDocTab); case 'toggle': return CollectionDockingView.ToggleSplit(doc, locationParams, this.stack); - case 'inPlace': case 'add': default: return CollectionDockingView.AddSplit(doc, locationParams, this.stack); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index d80fcdfc3..7a7ae3f40 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -96,37 +96,6 @@ border-color: #69a5db; } -.progressivizeButton { - position: absolute; - display: grid; - grid-template-columns: auto 20px auto; - transform: translate(-105%, 0); - align-items: center; - border: black solid 1px; - border-radius: 3px; - justify-content: center; - width: 40; - z-index: 30000; - height: 20; - overflow: hidden; - background-color: #d5dce2; - transition: all 1s; - - .progressivizeButton-prev:hover { - color: #5a9edd; - } - - .progressivizeButton-frame { - justify-self: center; - text-align: center; - width: 15px; - } - - .progressivizeButton-next:hover { - color: #5a9edd; - } -} - .resizable { background: rgba(0, 0, 0, 0.2); width: 100px; @@ -178,25 +147,6 @@ } } -.progressivizeMove-frame { - width: 20px; - border-radius: 2px; - z-index: 100000; - color: white; - text-align: center; - background-color: #5a9edd; - transform: translate(-110%, 110%); -} - -.progressivizeButton:hover { - box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.5); - - .progressivizeButton-frame { - background-color: #5a9edd; - color: white; - } -} - .collectionFreeform-customText { position: absolute; text-align: center; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d44c2f160..e24b116d0 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,5 +1,5 @@ import { Bezier } from 'bezier-js'; -import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import { DateField } from '../../../../fields/DateField'; @@ -71,6 +71,9 @@ export class CollectionFreeFormView extends CollectionSubView (CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.getPaths(this.rootDoc) : null); + @computed get marqueeView() { TraceMobx(); return ( @@ -1912,8 +1917,7 @@ export class CollectionFreeFormView extends CollectionSubView @@ -2039,8 +2043,7 @@ interface CollectionFreeFormViewPannableContentsProps { viewDefDivClick?: ScriptField; children: () => JSX.Element[]; transition?: string; - presPaths?: boolean; - progressivize?: boolean; + presPaths: () => JSX.Element | null; presPinView?: boolean; isAnnotationOverlay: boolean | undefined; isAnnotationOverlayScrollable: boolean | undefined; @@ -2093,42 +2096,11 @@ class CollectionFreeFormViewPannableContents extends React.Component -
-
-
-
-
-
-
- ); - } - } - - @computed get zoomProgressivize() { - return PresBox.Instance?.activeItem?.presPinView && PresBox.Instance.layoutDoc.presStatus === 'edit' ? this.zoomProgressivizeContainer : null; - } - - @computed get progressivize() { - return PresBox.Instance && this.props.progressivize ? PresBox.Instance.progressivizeChildDocs : null; - } - @computed get presPaths() { - const presPaths = 'presPaths' + (this.props.presPaths ? '' : '-hidden'); - return !PresBox.Instance || !this.props.presPaths ? null : ( + return !this.props.presPaths() ? null : ( <> -
{PresBox.Instance.order}
- +
{PresBox.Instance?.order}
+ @@ -2140,7 +2112,7 @@ class CollectionFreeFormViewPannableContents extends React.Component - {PresBox.Instance.paths} + {this.props.presPaths()} ); @@ -2180,8 +2152,6 @@ class CollectionFreeFormViewPannableContents extends React.Component )} {this.presPaths} - {this.progressivize} - {this.zoomProgressivize}
); } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 465dbfe6d..e5a2d9007 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -9,7 +9,7 @@ import { DragManager, dropActionType } from '../../../util/DragManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; -import { DocumentView } from '../../nodes/DocumentView'; +import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionMulticolumnView.scss'; import ResizeBar from './MulticolumnResizer'; @@ -241,9 +241,9 @@ export class CollectionMulticolumnView extends CollectionSubView() { } 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; + focusDocument = (doc: Doc, options: DocFocusOptions) => this.props.focus(this.rootDoc, options); + isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive(); + isChildContentActive = () => (((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.isContentActive() ? true : false); getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => { return ( 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; + focusDocument = (doc: Doc, options: DocFocusOptions) => this.props.focus(this.rootDoc, options); + isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive(); + isChildContentActive = () => (((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.isContentActive() ? true : false); getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => { return ( .documentView-titleWrapper-hover { display: inline-block; } - } - - > .documentView-styleWrapper { + > .documentView-contentsView { + opacity: 0.5; + } > .documentView-captionWrapper { opacity: 1; } diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 9e3b42cf6..b495a9399 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -93,7 +93,6 @@ export class PresBox extends ViewBoxBaseComponent() { @observable _expandBoolean: 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; @@ -206,8 +205,7 @@ export class PresBox extends ViewBoxBaseComponent() { targetDoc._viewTransition = 'all 1s'; setTimeout(() => (targetDoc._viewTransition = undefined), 1010); this.nextKeyframe(targetDoc, activeItem); - if (activeItem.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, targetDoc); - else targetDoc.keyFrameEditing = true; + targetDoc.keyFrameEditing = true; }; _mediaTimer!: [NodeJS.Timeout, Doc]; @@ -246,22 +244,13 @@ export class PresBox extends ViewBoxBaseComponent() { // Called when the user activates 'next' - to move to the next part of the pres. trail @action next = () => { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - const lastFrame = Cast(targetDoc?.lastFrame, 'number', null); - const curFrame = NumCast(targetDoc?._currentFrame); - let internalFrames: boolean = false; - if (activeItem.presProgressivize || activeItem.zoomProgressivize || targetDoc.scrollProgressivize) internalFrames = true; - if (internalFrames && lastFrame !== undefined && curFrame < lastFrame) { - // Case 1: There are still other frames and should go through all frames before going to next slide - this.nextInternalFrame(targetDoc, activeItem); - } else if (this.childDocs[this.itemIndex + 1] !== undefined) { - // Case 2: No more frames in current doc and next slide is defined, therefore move to next slide + if (this.childDocs[this.itemIndex + 1] !== undefined) { + // Case 1: No more frames in current doc and next slide is defined, therefore move to next slide const slides = DocListCast(this.rootDoc[StrCast(this.presFieldKey, 'data')]); const curLast = this.selectedArray.size ? Math.max(...Array.from(this.selectedArray).map(d => slides.indexOf(DocCast(d)))) : this.itemIndex; this.nextSlide(curLast + 1); } else if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) { - // Case 3: Last slide and presLoop is toggled ON or it is in Edit mode + // Case 2: Last slide and presLoop is toggled ON or it is in Edit mode this.nextSlide(0); } return this.itemIndex; @@ -551,51 +540,6 @@ export class PresBox extends ViewBoxBaseComponent() { } } - /** - * Uses the viewfinder to progressivize through the different views of a single collection. - * @param activeItem: document for which internal zoom is used - */ - zoomProgressivizeNext = (activeItem: Doc) => { - const targetDoc: Doc = this.targetDoc; - const srcContext = Cast(targetDoc?.context, Doc, null); - const docView = DocumentManager.Instance.getDocumentView(targetDoc); - const vfLeft = this.checkList(targetDoc, activeItem['viewfinder-left-indexed']); - const vfWidth = this.checkList(targetDoc, activeItem['viewfinder-width-indexed']); - const vfTop = this.checkList(targetDoc, activeItem['viewfinder-top-indexed']); - const vfHeight = this.checkList(targetDoc, activeItem['viewfinder-height-indexed']); - // Case 1: document that is not a Golden Layout tab - if (srcContext) { - const srcDocView = DocumentManager.Instance.getDocumentView(srcContext); - if (srcDocView) { - const layoutdoc = Doc.Layout(targetDoc); - const panelWidth: number = srcDocView.props.PanelWidth(); - const panelHeight: number = srcDocView.props.PanelHeight(); - const newPanX = NumCast(targetDoc.x) + NumCast(layoutdoc._width) / 2; - const newPanY = NumCast(targetDoc.y) + NumCast(layoutdoc._height) / 2; - const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight); - srcContext._panX = newPanX + (vfLeft + vfWidth / 2); - srcContext._panY = newPanY + (vfTop + vfHeight / 2); - srcContext._viewScale = newScale; - } - } - // Case 2: document is the containing collection - if (docView && !srcContext) { - const panelWidth: number = docView.props.PanelWidth(); - const panelHeight: number = docView.props.PanelHeight(); - const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight); - targetDoc._panX = vfLeft + vfWidth / 2; - targetDoc._panY = vfTop + vfWidth / 2; - targetDoc._viewScale = newScale; - } - const resize = document.getElementById('resizable'); - if (resize) { - resize.style.width = vfWidth + 'px'; - resize.style.height = vfHeight + 'px'; - resize.style.top = vfTop + 'px'; - resize.style.left = vfLeft + 'px'; - } - }; - /** * For 'Hide Before' and 'Hide After' buttons making sure that * they are hidden each time the presentation is updated. @@ -643,6 +587,7 @@ export class PresBox extends ViewBoxBaseComponent() { //The function that starts or resets presentaton functionally, depending on presStatus of the layoutDoc @action startAutoPres = async (startSlide: number) => { + if (!this.childDocs.length) return; this.layoutDoc.presStatus = PresStatus.Autoplay; this.startPresentation(startSlide + 1 === this.childDocs.length ? 0 : startSlide); clearTimeout(this._presTimer); @@ -682,14 +627,9 @@ export class PresBox extends ViewBoxBaseComponent() { }; // The function allows for viewing the pres path on toggle - @action togglePath = (srcContext: Doc, off?: boolean) => { - if (off) { - this._pathBoolean = false; - srcContext.presPathView = false; - } else { - runInAction(() => (this._pathBoolean = !this._pathBoolean)); - srcContext.presPathView = this._pathBoolean; - } + @action togglePath = (off?: boolean) => { + this._pathBoolean = off ? false : !this._pathBoolean; + CollectionFreeFormView.ShowPresPaths = this._pathBoolean; }; // The function allows for expanding the view of pres on toggle @@ -1014,17 +954,6 @@ export class PresBox extends ViewBoxBaseComponent() { } }; - /** - * - */ - @action - viewPaths = () => { - const srcContext = Cast(this.rootDoc.presCollection, Doc, null); - if (srcContext) { - this.togglePath(srcContext); - } - }; - 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 @@ -1104,16 +1033,14 @@ export class PresBox extends ViewBoxBaseComponent() { */ @computed get paths() { let pathPoints = ''; - const presCollection = Cast(this.rootDoc.presCollection, Doc, null); this.childDocs.forEach((doc, index) => { const tagDoc = Cast(doc.presentationTargetDoc, Doc, null); - const srcContext = Cast(tagDoc?.context, Doc, null); - if (tagDoc && presCollection === srcContext) { + if (tagDoc) { const n1x = NumCast(tagDoc.x) + NumCast(tagDoc._width) / 2; const n1y = NumCast(tagDoc.y) + NumCast(tagDoc._height) / 2; if ((index = 0)) pathPoints = n1x + ',' + n1y; else pathPoints = pathPoints + ' ' + n1x + ',' + n1y; - } else if (doc.presPinView && presCollection === tagDoc) { + } else if (doc.presPinView) { const n1x = NumCast(doc.presPinViewX); const n1y = NumCast(doc.presPinViewY); if ((index = 0)) pathPoints = n1x + ',' + n1y; @@ -1137,6 +1064,7 @@ export class PresBox extends ViewBoxBaseComponent() { /> ); } + getPaths = (collection: Doc) => this.paths; // needs to be smarter and figure out the paths to draw for this specific collection. or better yet, draw everything in an overlay layer instad of within a collection // Converts seconds to ms and updates presTransition setTransitionTime = (number: String, change?: number) => { @@ -1840,7 +1768,6 @@ export class PresBox extends ViewBoxBaseComponent() { // CollectionFreeFormDocumentView.setupScroll(tagDoc, 0); // CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0); } - // if (tagDoc.editScrollProgressivize) CollectionFreeFormDocumentView.updateScrollframe(tagDoc, currentFrame); CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, tagDoc); tagDoc._currentFrame = Math.max(0, (currentFrame || 0) + 1); tagDoc.lastFrame = Math.max(NumCast(tagDoc._currentFrame), NumCast(tagDoc.lastFrame)); @@ -1882,123 +1809,6 @@ export class PresBox extends ViewBoxBaseComponent() { @observable private openActiveColorPicker: boolean = false; @observable private openViewedColorPicker: boolean = false; - @computed get progressivizeDropdown() { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - if (activeItem && targetDoc) { - 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; - })}>
-
- {this.activeColorPicker} -
-
Viewed font color
-
(this.openViewedColorPicker = !this.openViewedColorPicker))}>
-
- {this.viewedColorPicker} -
-
- Zoom -
-
- Edit -
-
-
-
- Scroll -
-
- 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)}
-
-
-
- {this.frameListHeader} - {this.frameList} -
-
console.log(' TODO: play frames')}> - Play -
-
-
- ); - } - } - @undoBatch @action switchActive = (color: ColorState) => { @@ -2033,262 +1843,7 @@ export class PresBox extends ViewBoxBaseComponent() { } @action - turnOffEdit = (paths?: boolean) => { - // Turn off paths - if (paths) { - const srcContext = Cast(this.rootDoc.presCollection, Doc, null); - if (srcContext) this.togglePath(srcContext, true); - } - // Turn off the progressivize editors for each document - this.childDocs.forEach(doc => { - doc.editSnapZoomProgressivize = false; - doc.editZoomProgressivize = false; - const targetDoc = Cast(doc.presentationTargetDoc, Doc, null); - if (targetDoc) { - targetDoc.editZoomProgressivize = false; - // targetDoc.editScrollProgressivize = false; - } - }); - }; - - //Toggle whether the user edits or not - @action - editZoomProgressivize = (e: React.MouseEvent) => { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - if (!targetDoc.editZoomProgressivize) { - if (!activeItem.zoomProgressivize) activeItem.zoomProgressivize = true; - targetDoc.zoomProgressivize = true; - targetDoc.editZoomProgressivize = true; - activeItem.editZoomProgressivize = true; - } else { - targetDoc.editZoomProgressivize = false; - activeItem.editZoomProgressivize = false; - } - }; - - //Toggle whether the user edits or not - @action - editScrollProgressivize = (e: React.MouseEvent) => { - const targetDoc: Doc = this.targetDoc; - if (!targetDoc.editScrollProgressivize) { - if (!targetDoc.scrollProgressivize) { - targetDoc.scrollProgressivize = true; - this.activeItem.scrollProgressivize = true; - } - targetDoc.editScrollProgressivize = true; - } else { - targetDoc.editScrollProgressivize = false; - } - }; - - //Progressivize Zoom - @action - progressivizeScroll = (e: React.MouseEvent) => { - e.stopPropagation(); - this.activeItem.scrollProgressivize = !this.activeItem.scrollProgressivize; - const targetDoc: Doc = this.targetDoc; - targetDoc.scrollProgressivize = !targetDoc.scrollProgressivize; - // CollectionFreeFormDocumentView.setupScroll(targetDoc, NumCast(targetDoc._currentFrame)); - if (targetDoc.editScrollProgressivize) { - targetDoc.editScrollProgressivize = false; - targetDoc._currentFrame = 0; - targetDoc.lastFrame = 0; - } - }; - - //Progressivize Zoom - @action - progressivizeZoom = (e: React.MouseEvent) => { - e.stopPropagation(); - const activeItem: Doc = this.activeItem; - activeItem.zoomProgressivize = !activeItem.zoomProgressivize; - const targetDoc: Doc = this.targetDoc; - targetDoc.zoomProgressivize = !targetDoc.zoomProgressivize; - CollectionFreeFormDocumentView.setupZoom(activeItem, targetDoc); - if (activeItem.editZoomProgressivize) { - activeItem.editZoomProgressivize = false; - targetDoc._currentFrame = 0; - targetDoc.lastFrame = 0; - } - }; - - //Progressivize Child Docs - @action - editProgressivize = (e: React.MouseEvent) => { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - targetDoc._currentFrame = targetDoc.lastFrame; - if (!targetDoc.editProgressivize) { - if (!activeItem.presProgressivize) { - activeItem.presProgressivize = true; - targetDoc.presProgressivize = true; - } - targetDoc.editProgressivize = true; - } else { - targetDoc.editProgressivize = false; - } - }; - - @action - progressivizeChild = (e: React.MouseEvent) => { - e.stopPropagation(); - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]); - if (!activeItem.presProgressivize) { - targetDoc.keyFrameEditing = false; - activeItem.presProgressivize = true; - targetDoc.presProgressivize = true; - targetDoc._currentFrame = 0; - docs.forEach((doc, i) => CollectionFreeFormDocumentView.setupKeyframes([doc], i, true)); - targetDoc.lastFrame = targetDoc.lastFrame ? NumCast(targetDoc.lastFrame) : docs.length - 1; - } else { - // targetDoc.editProgressivize = false; - activeItem.presProgressivize = false; - targetDoc.presProgressivize = false; - targetDoc._currentFrame = 0; - targetDoc.keyFrameEditing = true; - } - }; - - @action - checkMovementLists = (doc: Doc, xlist: any, ylist: any) => { - const x: List = xlist; - const y: List = ylist; - const tags: JSX.Element[] = []; - let pathPoints = ''; //List of all of the pathpoints that need to be added - for (let i = 0; i < x.length - 1; i++) { - if (y[i] || x[i]) { - if (i === 0) pathPoints = x[i] - 11 + ',' + (y[i] + 33); - else pathPoints = pathPoints + ' ' + (x[i] - 11) + ',' + (y[i] + 33); - tags.push( -
- {i} -
- ); - } - } - tags.push( - - - - ); - return tags; - }; - - @observable - toggleDisplayMovement = (doc: Doc) => (doc.displayMovement = !doc.displayMovement); - - @action - checkList = (doc: Doc, list: any): number => { - const x: List = list; - 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)]; - } - return 100; - }; - - @computed get progressivizeChildDocs() { - const targetDoc: Doc = this.targetDoc; - const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]); - const tags: JSX.Element[] = []; - docs.forEach((doc, index) => { - if (doc['x-indexed'] && doc['y-indexed']) { - tags.push(
{this.checkMovementLists(doc, doc['x-indexed'], doc['y-indexed'])}
); - } - tags.push( -
{ - if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0; - }} - onPointerOver={() => { - if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0.5; - }} - onClick={e => { - this.toggleDisplayMovement(doc); - e.stopPropagation(); - }} - style={{ backgroundColor: doc.displayMovement ? Colors.LIGHT_BLUE : '#c8c8c8', top: NumCast(doc.y), left: NumCast(doc.x) }}> -
- { - e.stopPropagation(); - this.prevAppearFrame(doc, index); - }} - /> -
-
{NumCast(doc.appearFrame)}
-
- { - e.stopPropagation(); - this.nextAppearFrame(doc, index); - }} - /> -
-
- ); - }); - return tags; - } - - @action - 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) => { - doc.appearFrame = Math.max(0, (Cast(doc.appearFrame, 'number', null) ?? 0) - 1); - this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame)); - }; - - @action - updateOpacityList = (list: any, frame: number) => { - const x: List = list; - if (x && x.length >= frame) { - for (let i = 0; i < x.length; i++) { - if (i < frame) { - x[i] = 0; - } else if (i >= frame) { - x[i] = 1; - } - } - list = x; - } else { - x.length = frame + 1; - for (let i = 0; i < x.length; i++) { - if (i < frame) { - x[i] = 0; - } else if (i >= frame) { - x[i] = 1; - } - } - list = x; - } - }; + turnOffEdit = (paths?: boolean) => paths && this.togglePath(true); // Turn off paths @computed get toolbarWidth(): number { @@ -2311,11 +1866,11 @@ 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 }} + style={{ opacity: this.childDocs.length > 1 ? 1 : 0.3, color: this._pathBoolean ? Colors.MEDIUM_BLUE : 'white', width: isMini ? '100%' : undefined }} className={'toolbar-button'} - onClick={this.childDocs.length > 1 && this.layoutDoc.presCollection ? this.viewPaths : undefined}> + onClick={this.childDocs.length > 1 ? () => this.togglePath() : undefined}>
-- cgit v1.2.3-70-g09d2 From 51a85bae74c3d8ccddb57f6063e93b237cdf1ebd Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 15 Nov 2022 14:24:11 -0500 Subject: added playback of audio annotation on inPlace container. fixed image anchors to be marked un-rendered so link lines show up. --- src/client/util/DocumentManager.ts | 2 +- src/client/views/PropertiesButtons.tsx | 2 +- src/client/views/nodes/DocumentView.scss | 6 +++--- src/client/views/nodes/ImageBox.tsx | 11 +++++++---- 4 files changed, 12 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes/DocumentView.scss') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index ef0a339ce..519f75dbd 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -252,7 +252,7 @@ export class DocumentManager { } else { if (!targetDocContext) { // we don't have a view and there's no context specified ... create a new view of the target using the dockFunc or default - createViewFunc(Doc.BrushDoc(targetDoc), finished); // bcz: should we use this?: Doc.MakeAlias(targetDoc))); + createViewFunc(Doc.BrushDoc(targetDoc), () => focusAndFinish(true)); // bcz: should we use this?: Doc.MakeAlias(targetDoc))); } else { // otherwise try to get a view of the context of the target if (targetDocContextView) { diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index d27848a90..656a56a15 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -138,7 +138,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { DocUtils.MakeLink({ doc: dv.rootDoc }, { doc: menuDoc }, 'back link to container'); } DocListCast(menuDoc[Doc.LayoutFieldKey(menuDoc)]).forEach(menuItem => { - menuItem.followAllLinks = menuItem._isLinkButton = true; + menuItem.followLinkAudio = menuItem.followAllLinks = menuItem._isLinkButton = true; menuItem._followLinkLocation = 'inPlace'; }); } diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index e437d295e..01188d3fa 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -198,9 +198,9 @@ > .documentView-titleWrapper-hover { display: inline-block; } - > .documentView-contentsView { - opacity: 0.5; - } + // > .documentView-contentsView { + // opacity: 0.5; + // } > .documentView-captionWrapper { opacity: 1; } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index d67481b22..8ecd8104a 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -84,6 +84,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent(DocListCast(anchor._annotations)); } @@ -93,9 +94,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent { - const zoomedAnchor = () => Docs.Create.ImageanchorDocument({ viewTransitionTime: 1000, _viewScale: NumCast(this.layoutDoc._viewScale), _panX: NumCast(this.layoutDoc._panX), _panY: NumCast(this.layoutDoc._panY) }); - const anchor = this._getAnchor?.(this._savedAnnotations) ?? (this.layoutDoc.viewScale ? zoomedAnchor() : undefined); + const anchor = + this._getAnchor?.(this._savedAnnotations) ?? // use marquee anchor, otherwise, save zoom/pan as anchor + Docs.Create.ImageanchorDocument({ viewTransitionTime: 1000, unrendered: true, annotationOn: this.rootDoc, _viewScale: NumCast(this.layoutDoc._viewScale, 1), _panX: NumCast(this.layoutDoc._panX), _panY: NumCast(this.layoutDoc._panY) }); if (anchor) { + anchor._useAlt = Cast(this.layoutDoc[this.fieldKey + '-useAlt'], 'boolean', null); anchor._annotations = new List(DocListCast(this.dataDoc[this.annotationKey])); this.addDocument(anchor); return anchor; @@ -222,7 +225,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent Utils.CopyText(this.choosePath(field.url)), icon: 'expand-arrows-alt' }); if (!Doc.noviceMode) { funcs.push({ description: 'Export to Google Photos', event: () => GooglePhotos.Transactions.UploadImages([this.props.Document]), icon: 'caret-square-right' }); @@ -353,7 +356,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent Date: Wed, 16 Nov 2022 23:27:05 -0500 Subject: added presEffects to link anchors --- src/client/util/DocumentManager.ts | 2 +- src/client/views/MainView.tsx | 1 + .../views/collections/CollectionDockingView.tsx | 7 +- src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/linking/LinkEditor.tsx | 74 ++++++++++++++++++- src/client/views/nodes/DocumentView.scss | 2 +- src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/trails/PresBox.tsx | 86 ++++++++++++---------- src/fields/Doc.ts | 7 +- 9 files changed, 136 insertions(+), 49 deletions(-) (limited to 'src/client/views/nodes/DocumentView.scss') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index a60c1ed6b..00f6bc40a 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -233,7 +233,7 @@ export class DocumentManager { } } if (focusView) { - !noSelect && Doc.linkFollowHighlight(focusView.rootDoc); //TODO:glr make this a setting in PresBox + !noSelect && Doc.linkFollowHighlight(focusView.rootDoc, undefined, targetDoc); //TODO:glr make this a setting in PresBox if (originatingDoc?.followLinkAudio) DocumentManager.playAudioAnno(focusView.rootDoc); const doFocus = (forceDidFocus: boolean) => focusView.focus(originalTarget ?? targetDoc, { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 987bfc23d..392b4eeeb 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -484,6 +484,7 @@ export class MainView extends React.Component { } globalPointerDown = action((e: PointerEvent) => { + runInAction(() => (Doc.HighlightBrush.linkFollowEffect = undefined)); AudioBox.Enabled = true; const targets = document.elementsFromPoint(e.x, e.y); if (targets.length) { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 92319d080..434466505 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -452,7 +452,7 @@ export class CollectionDockingView extends CollectionSubView() { .map(id => DocServer.GetCachedRefField(id)) .filter(f => f) .map(f => f as Doc); - const changesMade = this.props.Document.dockcingConfig !== json; + const changesMade = this.props.Document.dockingConfig !== json; if (changesMade && !this._flush) { UndoManager.RunInBatch(() => { this.props.Document.dockingConfig = json; @@ -507,7 +507,12 @@ export class CollectionDockingView extends CollectionSubView() { action(() => { //if (confirm('really close this?')) { if ((!stack.parent.isRoot && !stack.parent.parent.isRoot) || stack.parent.contentItems.length > 1) { + const batch = UndoManager.StartBatch('close stack'); stack.remove(); + setTimeout(() => { + this.stateChanged(); + batch.end(); + }); } else { alert('cant delete the last stack'); } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 7bc273d7d..b66dc0aa2 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -111,7 +111,7 @@ export function CollectionSubView(moreProps?: X) { rawdocs = rootDoc && !this.props.isAnnotationOverlay ? [Doc.GetProto(rootDoc)] : []; } - const docs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate).map(d => d as Doc); + const docs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && !d.unrendered).map(d => d as Doc); const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index 3e8867c50..d90a91ab7 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -3,13 +3,14 @@ import { Tooltip } from '@material-ui/core'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, NumListCast, StrListCast, Field } from '../../../fields/Doc'; -import { DateCast, StrCast, Cast, BoolCast } from '../../../fields/Types'; +import { DateCast, StrCast, Cast, BoolCast, DocCast, NumCast } from '../../../fields/Types'; import { LinkManager } from '../../util/LinkManager'; import { undoBatch } from '../../util/UndoManager'; import './LinkEditor.scss'; import { LinkRelationshipSearch } from './LinkRelationshipSearch'; import React = require('react'); import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils'; +import { PresBox, PresEffect } from '../nodes/trails'; interface LinkEditorProps { sourceDoc: Doc; @@ -24,6 +25,7 @@ export class LinkEditor extends React.Component { @observable zoomFollow = BoolCast(this.props.sourceDoc.followLinkZoom); @observable audioFollow = BoolCast(this.props.sourceDoc.followLinkAudio); @observable openDropdown: boolean = false; + @observable openEffectDropdown: boolean = false; @observable private buttonColor: string = ''; @observable private relationshipButtonColor: string = ''; @observable private relationshipSearchVisibility: string = 'none'; @@ -295,6 +297,61 @@ export class LinkEditor extends React.Component { ); } + @computed get sourceAnchor() { + const ldoc = this.props.linkDoc; + if (this.props.sourceDoc !== ldoc.anchor1 && this.props.sourceDoc !== ldoc.anchor2) { + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor1).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor1); + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor2).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor2); + } + return this.props.sourceDoc; + } + @action + changeEffectDropdown = () => { + this.openEffectDropdown = !this.openEffectDropdown; + }; + + @undoBatch + changeEffect = action((follow: string) => { + this.openEffectDropdown = false; + this.sourceAnchor.presEffect = follow; + }); + + @computed + get effectDropdown() { + return ( +
+
Transition Effect:
+
+
+ {StrCast(this.sourceAnchor.presEffect, 'default')} + +
+
+ {[ + PresEffect.None, + PresEffect.Zoom, + PresEffect.Lightspeed, + PresEffect.Fade, + PresEffect.Flip, + PresEffect.Rotate, + PresEffect.Bounce, + PresEffect.Roll, + PresEffect.Left, + PresEffect.Right, + PresEffect.Center, + PresEffect.Top, + PresEffect.Bottom, + ].map(effect => ( +
this.changeEffect(effect.toString())}> + {effect.toString()} +
+ ))} +
+
+
+ ); + } + autoMove = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => (this.props.linkDoc.linkAutoMove = !this.props.linkDoc.linkAutoMove)))); }; @@ -348,7 +405,6 @@ export class LinkEditor extends React.Component { ) : null}
- {this.editDescription} {this.editRelationship} {this.editZoomFollow} @@ -390,6 +446,20 @@ export class LinkEditor extends React.Component {
{this.followingDropdown} + {this.effectDropdown} + {PresBox.inputter('0.1', '0.1', '10', NumCast(this.sourceAnchor.presTransition) / 1000, true, (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => (this.sourceAnchor.presTransition = timeInMS)))} +
+
Fast
+
Medium
+
Slow
+
{' '} ); } diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 01188d3fa..abf6e37ab 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -28,7 +28,7 @@ transition: outline 0.3s linear; // background: $white; //overflow: hidden; - transform-origin: left top; + transform-origin: center; &.minimized { width: 30px; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index dc468cf89..fb07f1033 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; -import { observer } from 'mobx-react'; +import { observer, renderReporter } from 'mobx-react'; import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, Opt, StrListCast, WidthSym } from '../../../fields/Doc'; import { Document } from '../../../fields/documentSchemas'; import { Id } from '../../../fields/FieldSymbols'; @@ -1394,7 +1394,7 @@ export class DocumentViewInternal extends DocComponent() { * @param presEffectDoc presentation effects document that specifies the animation effect parameters * @returns a function that will wrap a JSX animation element wrapping any JSX element */ - public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Doc) { + public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Doc, root: Doc) { const effectProps = { - left: presEffectDoc.presEffectDirection === PresEffect.Left, - right: presEffectDoc.presEffectDirection === PresEffect.Right, - top: presEffectDoc.presEffectDirection === PresEffect.Top, - bottom: presEffectDoc.presEffectDirection === PresEffect.Bottom, + left: presEffectDoc?.presEffectDirection === PresEffect.Left, + right: presEffectDoc?.presEffectDirection === PresEffect.Right, + top: presEffectDoc?.presEffectDirection === PresEffect.Top, + bottom: presEffectDoc?.presEffectDirection === PresEffect.Bottom, opposite: true, - delay: NumCast(presEffectDoc.presTransition), + delay: 0, + duration: Cast(presEffectDoc?.presTransition, 'number', null), }; //prettier-ignore - switch (StrCast(presEffectDoc.presEffect)) { + switch (StrCast(presEffectDoc?.presEffect)) { default: case PresEffect.None: return renderDoc; case PresEffect.Zoom: return {renderDoc}; @@ -386,7 +388,7 @@ export class PresBox extends ViewBoxBaseComponent() { } if (pinDataTypes.dataannos) { const fkey = Doc.LayoutFieldKey(bestTarget); - Doc.GetProto(bestTarget)[fkey + '-annotations'] = new List(DocListCast(activeItem.presAnnotations)); + Doc.GetProto(bestTarget)[fkey + '-annotations'] = new List([...DocListCast(bestTarget[fkey + '-annotations']).filter(doc => doc.unrendered), ...DocListCast(activeItem.presAnnotations)]); } if (pinDataTypes.dataview && activeItem.presData !== undefined) { const fkey = Doc.LayoutFieldKey(bestTarget); @@ -465,7 +467,7 @@ export class PresBox extends ViewBoxBaseComponent() { } if (pinProps.pinData.dataannos) { const fkey = Doc.LayoutFieldKey(targetDoc); - pinDoc.presAnnotations = new List(DocListCast(Doc.GetProto(targetDoc)[fkey + '-annotations'])); + pinDoc.presAnnotations = new List(DocListCast(Doc.GetProto(targetDoc)[fkey + '-annotations']).filter(doc => !doc.unrendered)); } if (pinProps.pinData.textview) pinDoc.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof ObjectField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as ObjectField)[Copy]() : targetDoc.text; if (pinProps.pinData.scrollable) pinDoc.presPinViewScroll = targetDoc._scrollTop; @@ -1095,12 +1097,15 @@ export class PresBox extends ViewBoxBaseComponent() { getPaths = (collection: Doc) => this.paths; // needs to be smarter and figure out the paths to draw for this specific collection. or better yet, draw everything in an overlay layer instad of within a collection // Converts seconds to ms and updates presTransition - setTransitionTime = (number: String, change?: number) => { + public static SetTransitionTime = (number: String, setter: (timeInMS: number) => void, change?: number) => { let timeInMS = Number(number) * 1000; if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; if (timeInMS > 10000) timeInMS = 10000; - this.selectedArray.forEach(doc => (doc.presTransition = timeInMS)); + setter(timeInMS); + }; + setTransitionTime = (number: String, change?: number) => { + PresBox.SetTransitionTime(number, (timeInMS: number) => this.selectedArray.forEach(doc => (doc.presTransition = timeInMS)), change); }; // Converts seconds to ms and updates presTransition @@ -1165,6 +1170,28 @@ export class PresBox extends ViewBoxBaseComponent() { _batch: UndoManager.Batch | undefined = undefined; + public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void) => { + let batch: any; + return ( + { + batch = UndoManager.StartBatch('pres slider'); + e.stopPropagation(); + }} + onPointerUp={() => batch?.end()} + onChange={e => { + e.stopPropagation(); + change(e.target.value); + }} + /> + ); + }; @computed get transitionDropdown() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; @@ -1180,39 +1207,18 @@ export class PresBox extends ViewBoxBaseComponent() { {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'; + const presDirection = (direction: PresEffect, icon: string, gridColumn: number, gridRow: number, opts: object) => { + const color = this.activeItem.presEffectDirection === direction || (direction === PresEffect.Center && !this.activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; return ( - {diretion}}> + {direction}}>
this.updateEffectDirection(diretion)}> + style={{ ...opts, border: direction === PresEffect.Center ? `solid 2px ${color}` : undefined, borderRadius: '100%', cursor: 'pointer', gridColumn, gridRow, justifySelf: 'center', color }} + onClick={() => this.updateEffectDirection(direction)}> {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'); - e.stopPropagation(); - }} - 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; @@ -1263,7 +1269,7 @@ export class PresBox extends ViewBoxBaseComponent() { - {inputter('0', '1', '100', zoom, activeItem.presMovement === PresMovement.Zoom, this.setZoom)} + {PresBox.inputter('0', '1', '100', zoom, activeItem.presMovement === PresMovement.Zoom, this.setZoom)}
Transition Speed
@@ -1278,7 +1284,7 @@ export class PresBox extends ViewBoxBaseComponent() {
- {inputter('0.1', '0.1', '10', transitionSpeed, true, this.setTransitionTime)} + {PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.setTransitionTime)}
Fast
Medium
@@ -1331,7 +1337,7 @@ export class PresBox extends ViewBoxBaseComponent() {
- {inputter('0.1', '0.1', '20', duration, targetDoc.type !== DocumentType.AUDIO, this.setDurationTime)} + {PresBox.inputter('0.1', '0.1', '20', duration, targetDoc.type !== DocumentType.AUDIO, this.setDurationTime)}
Short
Medium
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 70cb10970..75801b68c 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1263,11 +1263,15 @@ export namespace Doc { export function linkFollowUnhighlight() { Doc.UnhighlightAll(); document.removeEventListener('pointerdown', linkFollowUnhighlight); + runInAction(() => (HighlightBrush.linkFollowEffect = undefined)); } let _lastDate = 0; - export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true) { + export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true, presEffect?: Doc) { linkFollowUnhighlight(); + // runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = undefined)); + // setTimeout(() => runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = presEffect))); + runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = presEffect)); (destDoc instanceof Doc ? [destDoc] : destDoc).forEach(doc => Doc.HighlightDoc(doc, dataAndDisplayDocs)); document.removeEventListener('pointerdown', linkFollowUnhighlight); document.addEventListener('pointerdown', linkFollowUnhighlight); @@ -1277,6 +1281,7 @@ export namespace Doc { export class HighlightBrush { @observable HighlightedDoc: Map = new Map(); + @observable static linkFollowEffect: Doc | undefined; } const highlightManager = new HighlightBrush(); export function IsHighlighted(doc: Doc) { -- cgit v1.2.3-70-g09d2 From 67316c700980fe653c48840407dc9d66a7ed8a2b Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 6 Jan 2023 00:35:43 -0500 Subject: added zoom box highlighting of text anchors in pdf/web pages for link/pres following. Added serial/parallel option for presentation group with up. Added direct pinning of text seletions to trails. fixed 'hide' option for preselements to work with hidebefore/after --- src/client/util/DocumentManager.ts | 67 ++++++++++++----- src/client/util/LinkFollower.ts | 9 ++- src/client/views/MainView.tsx | 1 + src/client/views/MarqueeAnnotator.tsx | 42 ++++++----- src/client/views/collections/CollectionSubView.tsx | 2 - src/client/views/collections/TabDocView.tsx | 5 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 9 ++- src/client/views/nodes/DocumentContentsView.tsx | 2 +- src/client/views/nodes/DocumentView.scss | 16 +++++ src/client/views/nodes/DocumentView.tsx | 38 +++++++++- src/client/views/nodes/MapBox/MapBox.tsx | 9 --- src/client/views/nodes/PDFBox.tsx | 7 ++ src/client/views/nodes/WebBox.scss | 1 + src/client/views/nodes/WebBox.tsx | 27 +++++-- src/client/views/nodes/trails/PresBox.tsx | 83 ++++++++++++++-------- src/client/views/nodes/trails/PresElementBox.tsx | 3 +- src/client/views/pdf/PDFViewer.tsx | 10 ++- src/fields/Doc.ts | 16 +++-- 18 files changed, 241 insertions(+), 106 deletions(-) (limited to 'src/client/views/nodes/DocumentView.scss') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index d2e9e17b4..70fe7f2c0 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,8 +1,8 @@ -import { action, observable, runInAction } from 'mobx'; -import { Doc, Opt } from '../../fields/Doc'; +import { action, observable, ObservableSet, runInAction } from 'mobx'; +import { AnimationSym, Doc, Opt } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { listSpec } from '../../fields/Schema'; -import { Cast, DocCast } from '../../fields/Types'; +import { Cast, DocCast, StrCast } from '../../fields/Types'; import { AudioField } from '../../fields/URLField'; import { returnFalse } from '../../Utils'; import { DocumentType } from '../documents/DocumentTypes'; @@ -42,7 +42,7 @@ export class DocumentManager { callAddViewFuncs = (view: DocumentView) => { const callFuncs = this._viewRenderedCbs.filter(vc => vc.doc === view.rootDoc); if (callFuncs.length) { - this._viewRenderedCbs = this._viewRenderedCbs.filter(vc => callFuncs.includes(vc)); + this._viewRenderedCbs = this._viewRenderedCbs.filter(vc => !callFuncs.includes(vc)); const intTimer = setInterval( () => { if (!view.ComponentView?.incrementalRendering?.()) { @@ -147,14 +147,15 @@ export class DocumentManager { public getDocumentView(toFind: Doc, preferredCollection?: CollectionView): DocumentView | undefined { const found = - Array.from(DocumentManager.Instance.DocumentViews).find( - dv => - ((dv.rootDoc.data as any)?.url?.href && (dv.rootDoc.data as any)?.url?.href === (toFind.data as any)?.url?.href) || - ((DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href && (DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href === (DocCast(toFind.annotationOn)?.data as any)?.url?.href) - )?.rootDoc ?? toFind; + // Array.from(DocumentManager.Instance.DocumentViews).find( + // dv => + // ((dv.rootDoc.data as any)?.url?.href && (dv.rootDoc.data as any)?.url?.href === (toFind.data as any)?.url?.href) || + // ((DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href && (DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href === (DocCast(toFind.annotationOn)?.data as any)?.url?.href) + // )?.rootDoc ?? + toFind; return this.getDocumentViewById(found[Id], preferredCollection); } - + public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt = undefined): DocumentView | undefined => { const views: DocumentView[] = []; Array.from(DocumentManager.Instance.DocumentViews).map(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.rootDoc, toFind) && views.push(view)); @@ -167,11 +168,12 @@ export class DocumentManager { }; public getDocumentViews(toFindIn: Doc): DocumentView[] { const toFind = - Array.from(DocumentManager.Instance.DocumentViews).find( - dv => - ((dv.rootDoc.data as any)?.url?.href && (dv.rootDoc.data as any)?.url?.href === (toFindIn.data as any)?.url?.href) || - ((DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href && (DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href === (DocCast(toFindIn.annotationOn)?.data as any)?.url?.href) - )?.rootDoc ?? toFindIn; + // Array.from(DocumentManager.Instance.DocumentViews).find( + // dv => + // ((dv.rootDoc.data as any)?.url?.href && (dv.rootDoc.data as any)?.url?.href === (toFindIn.data as any)?.url?.href) || + // ((DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href && (DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href === (DocCast(toFindIn.annotationOn)?.data as any)?.url?.href) + // )?.rootDoc ?? + toFindIn; const toReturn: DocumentView[] = []; const docViews = Array.from(DocumentManager.Instance.DocumentViews).filter(view => !LightboxView.IsLightboxDocView(view.docViewPath)); @@ -203,6 +205,11 @@ export class DocumentManager { } } + public static removeOverlayViews() { + DocumentManager._overlayViews?.forEach(action(view => (view.textHtmlOverlay = undefined))); + DocumentManager._overlayViews?.clear(); + } + static _overlayViews = new ObservableSet(); static addView = (doc: Doc, finished?: () => void) => { CollectionDockingView.AddSplit(doc, OpenWhereMod.right); finished?.(); @@ -225,7 +232,7 @@ export class DocumentManager { docView?.props.bringToFront(resolvedTarget); }); } - const focusAndFinish = (didFocus: boolean) => { + const focusAndFinish = action((didFocus: boolean) => { const finalTargetDoc = resolvedTarget; if (options.toggleTarget) { if (!didFocus && !wasHidden) { @@ -236,12 +243,26 @@ export class DocumentManager { finalTargetDoc.hidden && (finalTargetDoc.hidden = undefined); !options.noSelect && docView?.select(false); } + if (targetDoc.textHtml && options.zoomTextSelections) { + const containerView = DocumentManager.Instance.getFirstDocumentView(finalTargetDoc); + if (containerView) { + containerView.htmlOverlayEffect = StrCast(options?.effect?.presEffect, StrCast(options?.effect?.followLinkAnimEffect)); + containerView.textHtmlOverlay = StrCast(targetDoc.textHtml); + DocumentManager._overlayViews.add(containerView); + if (Doc.UnhighlightTimer) { + Doc.AddUnHighlightWatcher(() => { + DocumentManager.removeOverlayViews(); + containerView.htmlOverlayEffect = ''; + }); + } else setTimeout(() => (containerView.htmlOverlayEffect = '')); + } + } finished?.(); - }; + }); const annoContainerView = (!wasHidden || resolvedTarget !== annotatedDoc) && annotatedDoc && this.getFirstDocumentView(annotatedDoc); if (annoContainerView) { if (annoContainerView.props.Document.layoutKey === 'layout_icon') { - return annoContainerView.iconify(() => DocumentManager.Instance.AddViewRenderedCb(targetDoc, () => this.jumpToDocument(resolvedTarget ?? targetDoc, { ...options, toggleTarget: false }, createViewFunc, docContextPath, finished)), 30); + return annoContainerView.iconify(() => DocumentManager.Instance.AddViewRenderedCb(targetDoc, () => this.jumpToDocument(targetDoc, { ...options, originalTarget, toggleTarget: false }, createViewFunc, docContextPath, finished)), 30); } if (!docView && targetDoc.type !== DocumentType.MARKER) { annoContainerView.focus(targetDoc, {}); // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below @@ -254,7 +275,15 @@ export class DocumentManager { const targetDocContextView = (targetDocContext && this.getFirstDocumentView(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 const focusView = !docView && targetDoc.type === DocumentType.MARKER && annoContainerView ? annoContainerView : docView; if (focusView) { - !options.noSelect && Doc.linkFollowHighlight(focusView.rootDoc, undefined, options.effect); //TODO:glr make this a setting in PresBox + if (focusView.rootDoc === originalTarget) { + if (!options.noSelect) Doc.linkFollowHighlight(focusView.rootDoc, undefined, options.effect); //TODO:glr make this a setting in PresBox + else { + focusView.rootDoc[AnimationSym] = options.effect; + if (Doc.UnhighlightTimer) { + Doc.AddUnHighlightWatcher(action(() => (focusView.rootDoc[AnimationSym] = undefined))); + } + } + } if (options.playAudio) DocumentManager.playAudioAnno(focusView.rootDoc); const doFocus = (forceDidFocus: boolean) => focusView.focus(originalTarget, { diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 94badbb44..d5ef9fab6 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -1,12 +1,10 @@ import { action, runInAction } from 'mobx'; -import { Doc, DocListCast, Opt, WidthSym } from '../../fields/Doc'; -import { listSpec } from '../../fields/Schema'; +import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { DocumentType } from '../documents/DocumentTypes'; import { DocumentDecorations } from '../views/DocumentDecorations'; import { LightboxView } from '../views/LightboxView'; import { DocFocusOptions, DocumentViewSharedProps, OpenWhere, ViewAdjustment } from '../views/nodes/DocumentView'; -import { PresEffect, PresEffectDirection } from '../views/nodes/trails'; import { DocumentManager } from './DocumentManager'; import { LinkManager } from './LinkManager'; import { UndoManager } from './UndoManager'; @@ -59,7 +57,7 @@ export class LinkFollower { createTabForTarget(false); } else { // first focus & zoom onto this (the clicked document). Then execute the function to focus on the target - docViewProps.focus(sourceDoc, { willPan: true, willPanZoom: BoolCast(sourceDoc.followLinkZoom, true), zoomScale: 1, afterFocus: createTabForTarget }); + docViewProps.focus(sourceDoc, { willPan: true, willPanZoom: BoolCast(sourceDoc.followLinkZoom, true), zoomTime: 1000, zoomScale: 1, afterFocus: createTabForTarget }); } }; runInAction(() => (DocumentDecorations.Instance.overrideBounds = true)); // turn off decoration bounds while following links since animations may occur, and DocDecorations is based on screenToLocal which is not always an observable value @@ -70,7 +68,7 @@ export class LinkFollower { docViewProps.ContainingCollectionDoc, action(() => { batch.end(); - Doc.AddUnlightWatcher(action(() => (DocumentDecorations.Instance.overrideBounds = false))); + Doc.AddUnHighlightWatcher(action(() => (DocumentDecorations.Instance.overrideBounds = false))); }), altKey ? true : undefined ); @@ -110,6 +108,7 @@ export class LinkFollower { easeFunc: StrCast(sourceDoc.followLinkEase, 'ease') as any, effect: sourceDoc, originatingDoc: sourceDoc, + zoomTextSelections: false, }; if (target.TourMap) { const fieldKey = Doc.LayoutFieldKey(target); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 42e259eed..39cc9ba8e 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -482,6 +482,7 @@ export class MainView extends React.Component { } globalPointerDown = action((e: PointerEvent) => { + DocumentManager.removeOverlayViews(); Doc.linkFollowUnhighlight(); AudioBox.Enabled = true; const targets = document.elementsFromPoint(e.x, e.y); diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 2fdb59361..bf1242346 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -18,7 +18,7 @@ const _global = (window /* browser */ || global) /* node */ as any; export interface MarqueeAnnotatorProps { rootDoc: Doc; - down: number[]; + down?: number[]; iframe?: () => undefined | HTMLIFrameElement; scrollTop: number; scaling?: () => number; @@ -45,6 +45,17 @@ export class MarqueeAnnotator extends React.Component { @observable private _width: number = 0; @observable private _height: number = 0; + constructor(props: any) { + super(props); + + AnchorMenu.Instance.OnCrop = (e: PointerEvent) => this.props.anchorMenuCrop?.(this.highlight('', true), true); + AnchorMenu.Instance.OnClick = (e: PointerEvent) => this.props.anchorMenuClick?.()?.(this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true)); + AnchorMenu.Instance.OnAudio = unimplementedFunction; + AnchorMenu.Instance.Highlight = this.highlight; + AnchorMenu.Instance.GetAnchor = (savedAnnotations?: ObservableMap) => this.highlight('rgba(173, 216, 230, 0.75)', true, savedAnnotations); + AnchorMenu.Instance.onMakeAnchor = AnchorMenu.Instance.GetAnchor; + } + @action static clearAnnotations(savedAnnotations: ObservableMap) { AnchorMenu.Instance.Status = 'marquee'; @@ -54,24 +65,21 @@ export class MarqueeAnnotator extends React.Component { savedAnnotations.clear(); } - @action componentDidMount() { - // set marquee x and y positions to the spatially transformed position - const boundingRect = this.props.mainCont.getBoundingClientRect(); - this._startX = this._left = (this.props.down[0] - boundingRect.left) * (this.props.mainCont.offsetWidth / boundingRect.width); - this._startY = this._top = (this.props.down[1] - boundingRect.top) * (this.props.mainCont.offsetHeight / boundingRect.height) + this.props.mainCont.scrollTop; - this._height = this._width = 0; + @action gotDownPoint() { + if (!this._width && !this._height) { + const downPt = this.props.down!; + // set marquee x and y positions to the spatially transformed position + const boundingRect = this.props.mainCont.getBoundingClientRect(); + this._startX = this._left = (downPt[0] - boundingRect.left) * (this.props.mainCont.offsetWidth / boundingRect.width); + this._startY = this._top = (downPt[1] - boundingRect.top) * (this.props.mainCont.offsetHeight / boundingRect.height) + this.props.mainCont.scrollTop; + } const doc = this.props.iframe?.()?.contentDocument ?? document; + doc.removeEventListener('pointermove', this.onSelectMove); + doc.removeEventListener('pointerup', this.onSelectEnd); doc.addEventListener('pointermove', this.onSelectMove); doc.addEventListener('pointerup', this.onSelectEnd); - AnchorMenu.Instance.OnCrop = (e: PointerEvent) => this.props.anchorMenuCrop?.(this.highlight('', true), true); - AnchorMenu.Instance.OnClick = (e: PointerEvent) => this.props.anchorMenuClick?.()?.(this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true)); - AnchorMenu.Instance.OnAudio = unimplementedFunction; - AnchorMenu.Instance.Highlight = this.highlight; - AnchorMenu.Instance.GetAnchor = (savedAnnotations?: ObservableMap) => this.highlight('rgba(173, 216, 230, 0.75)', true, savedAnnotations); - AnchorMenu.Instance.onMakeAnchor = AnchorMenu.Instance.GetAnchor; - /** * This function is used by the AnchorMenu to create an anchor highlight and a new linked text annotation. * It also initiates a Drag/Drop interaction to place the text annotation. @@ -125,7 +133,7 @@ export class MarqueeAnnotator extends React.Component { }); }); } - componentWillUnmount() { + releaseDownPt() { const doc = this.props.iframe?.()?.contentDocument ?? document; doc.removeEventListener('pointermove', this.onSelectMove); doc.removeEventListener('pointerup', this.onSelectEnd); @@ -259,6 +267,7 @@ export class MarqueeAnnotator extends React.Component { this.highlight('rgba(245, 230, 95, 0.75)', false); // yellowish highlight color for highlighted text (should match AnchorMenu's highlight color) } this.props.finishMarquee(undefined, undefined, e); + runInAction(() => (this._width = this._height = 0)); } else { runInAction(() => (this._width = this._height = 0)); this.props.finishMarquee(cliX, cliY, e); @@ -266,8 +275,9 @@ export class MarqueeAnnotator extends React.Component { }; render() { - return ( + return !this.props.down ? null : (
(r ? this.gotDownPoint() : this.releaseDownPt())} className="marqueeAnnotator-dragBox" style={{ left: `${this._left}px`, diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index b66dc0aa2..4f3f21cea 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -172,8 +172,6 @@ export function CollectionSubView(moreProps?: X) { // The following conditional detects a recurring bug we've seen on the server if (proto[Id] === Docs.Prototypes.get(DocumentType.COL)[Id]) { alert('COLLECTION PROTO CURSOR ISSUE DETECTED! Check console for more info...'); - console.log(doc); - console.log(proto); throw new Error(`AHA! You were trying to set a cursor on a collection's proto, which is the original collection proto! Look at the two previously printed lines for document values!`); } let cursors = Cast(proto.cursors, listSpec(CursorField)); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index e45e2a1cb..cd58319cb 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -247,8 +247,9 @@ export class TabDocView extends React.Component { alert('Cannot pin presentation document to itself'); return; } - const pinDoc = Doc.MakeAlias(doc); - pinDoc.presentationTargetDoc = doc; + const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(); + const pinDoc = Doc.MakeAlias(anchorDoc ?? doc); + pinDoc.presentationTargetDoc = anchorDoc ?? doc; pinDoc.title = doc.title + ' - Slide'; pinDoc.data = new List(); // the children of the alias' layout are the presentation slide children. the alias' data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data pinDoc.presMovement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 82b97dff0..dc0eb69f3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1146,6 +1146,7 @@ export class CollectionFreeFormView extends CollectionSubView(res => setTimeout(() => res(runInAction(() => (this._panZoomTransition = 0))), this._panZoomTransition)); // set transition to be smooth, then reset } + _focusCount = 0; focusDocument = (doc: Doc, options: DocFocusOptions) => { const state = HistoryUtil.getState(); @@ -1187,6 +1188,7 @@ export class CollectionFreeFormView extends CollectionSubView { @@ -1200,7 +1202,7 @@ export class CollectionFreeFormView extends CollectionSubView (this._panZoomTransition = 0)); + this._focusCount === focusCount && didMove && runInAction(() => (this._panZoomTransition = 0)); return resetView; }; const xf = !cantTransform @@ -2284,5 +2286,8 @@ ScriptingGlobals.add(function curKeyFrame(readOnly: boolean) { runInAction(() => selView[0].ComponentView?.setKeyFrameEditing?.(!selView[0].ComponentView?.getKeyFrameEditing?.())); }); ScriptingGlobals.add(function pinWithView(readOnly: boolean, pinDocContent: boolean) { - !readOnly && SelectionManager.Views().forEach(view => TabDocView.PinDoc(view.rootDoc, { pinDocContent, pinViewport: MarqueeView.CurViewBounds(view.rootDoc, view.props.PanelWidth(), view.props.PanelHeight()) })); + !readOnly && + SelectionManager.Views().forEach(view => + TabDocView.PinDoc(view.rootDoc, { currentFrame: Cast(view.rootDoc.currentFrame, 'number', null), pinDocContent, pinViewport: MarqueeView.CurViewBounds(view.rootDoc, view.props.PanelWidth(), view.props.PanelHeight()) }) + ); }); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 3ab7cc0bc..569579996 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -59,7 +59,7 @@ class ObserverJsxParser1 extends JsxParser { } } -const ObserverJsxParser: typeof JsxParser = ObserverJsxParser1 as any; +export const ObserverJsxParser: typeof JsxParser = ObserverJsxParser1 as any; interface HTMLtagProps { Document: Doc; diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index abf6e37ab..453bdac8e 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -51,6 +51,22 @@ height: calc(100% - 20px); } + .documentView-htmlOverlay { + position: absolute; + display: flex; + top: 0; + height: 100%; + width: 100%; + .documentView-htmlOverlayInner { + box-shadow: black 0.2vw 0.2vw 0.8vw; + background: rgb(255, 255, 255); + overflow: auto; + position: relative; + margin: auto; + padding: 20px; + } + } + .documentView-linkAnchorBoxAnchor { display: flex; overflow: hidden; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 76cc6800a..95cf08289 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -3,6 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import { ObserverJsxParser } from './DocumentContentsView'; import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal'; import { AclAdmin, AclEdit, AclPrivate, AnimationSym, DataSym, Doc, DocListCast, Field, Opt, StrListCast, WidthSym } from '../../../fields/Doc'; import { Document } from '../../../fields/documentSchemas'; @@ -110,6 +111,7 @@ export interface DocFocusOptions { effect?: Doc; // animation effect for focus noSelect?: boolean; // whether target should be selected after focusing playAudio?: boolean; // whether to play audio annotation on focus + zoomTextSelections?: boolean; // whether to display a zoomed overlay of anchor text selections toggleTarget?: boolean; // whether to toggle target on and off originatingDoc?: Doc; // document that triggered the focus easeFunc?: 'linear' | 'ease'; // transition method for scrolling @@ -590,9 +592,16 @@ export class DocumentViewInternal extends DocComponent this._componentView?.setViewSpec?.(anchor, LinkDocPreview.LinkInfo ? true : false)); const focusSpeed = this._componentView?.scrollFocus?.(anchor, { ...options, instant: options?.instant || LinkDocPreview.LinkInfo ? true : false }); const endFocus = focusSpeed === undefined ? options?.afterFocus : async (moved: boolean) => options?.afterFocus?.(true) ?? ViewAdjustment.doNothing; + const startTime = Date.now(); this.props.focus(options?.docTransform ? anchor : this.rootDoc, { ...options, - afterFocus: (didFocus: boolean) => new Promise(res => setTimeout(async () => res(endFocus ? await endFocus(didFocus || focusSpeed !== undefined) : ViewAdjustment.doNothing), focusSpeed ?? 0)), + afterFocus: (didFocus: boolean) => + new Promise(async res => + setTimeout( + async () => res(endFocus ? await endFocus(didFocus || focusSpeed !== undefined) : ViewAdjustment.doNothing), // + didFocus ? Math.max(0, (options.zoomTime ?? 500) - (Date.now() - startTime)) : 0 + ) + ), }); }; onClick = action((e: React.MouseEvent | React.PointerEvent) => { @@ -1098,11 +1107,16 @@ export class DocumentViewInternal extends DocComponent { + const childHighlighted = () => + Array.from(Doc.highlightedDocs.keys()) + .concat(Array.from(Doc.brushManager.BrushedDoc.keys())) + .some(doc => Doc.AreProtosEqual(DocCast(doc.annotationOn), this.rootDoc)); + const childOverlayed = () => Array.from(DocumentManager._overlayViews).some(view => Doc.AreProtosEqual(view.rootDoc, this.rootDoc)); return !this.props.isSelected() && LightboxView.LightboxDoc !== this.rootDoc && this.thumb && !Doc.AreProtosEqual(DocumentLinksButton.StartLink, this.rootDoc) && - (!Doc.isBrushedHighlightedDegree(this.props.Document) || this.rootDoc._viewType === CollectionViewType.Docking) && + ((!childHighlighted() && !childOverlayed() && !Doc.isBrushedHighlightedDegree(this.rootDoc)) || this.rootDoc._viewType === CollectionViewType.Docking) && !this._componentView?.isAnyChildContentActive?.() ? true : false; @@ -1754,6 +1768,7 @@ export class DocumentView extends React.Component { startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this.docView?.startDragging(x, y, dropAction, hideSource); + @observable textHtmlOverlay: Opt; @computed get anchorViewDoc() { return this.props.LayoutTemplateString?.includes('anchor2') ? DocCast(this.rootDoc['anchor2']) : this.props.LayoutTemplateString?.includes('anchor1') ? DocCast(this.rootDoc['anchor1']) : undefined; } @@ -1793,6 +1808,24 @@ export class DocumentView extends React.Component { isHovering = () => this._isHovering; @observable _isHovering = false; + htmlOverlayEffect = ''; + @computed get htmlOverlay() { + const effectProps = { + delay: 0, + duration: 500, + }; + const highlight = ( +
+ console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this.textHtmlOverlay)} /> +
+ ); + return !this.textHtmlOverlay ? null : ( +
+
{{DocumentViewInternal.AnimationEffect(highlight, { presEffect: this.htmlOverlayEffect ?? 'Zoom' } as any as Doc, this.rootDoc)} }
+
+ ); + } + render() { TraceMobx(); const xshift = Math.abs(this.Xshift) <= 0.001 ? this.props.PanelWidth() : undefined; @@ -1841,6 +1874,7 @@ export class DocumentView extends React.Component { focus={this.props.focus || emptyFunction} ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))} /> + {this.htmlOverlay}
)} diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index b0f6f8358..c8d5b0154 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -322,7 +322,6 @@ export class MapBox extends ViewBoxAnnotatableComponent { console.log('print all sidebar Docs'); - console.log(this.allSidebarDocs); if (!this.layoutDoc._showSidebar) this.toggleSidebar(); const docs = doc instanceof Doc ? [doc] : doc; docs.forEach(doc => { @@ -337,8 +336,6 @@ export class MapBox extends ViewBoxAnnotatableComponent { if (this.layoutDoc._showSidebar) this.toggleSidebar(); const docs = doc instanceof Doc ? [doc] : doc; - docs.forEach(doc => { - console.log(this.allMapMarkers); - console.log(this.allSidebarDocs); - }); return this.removeDocument(doc, sidebarKey); }; @@ -405,7 +398,6 @@ export class MapBox extends ViewBoxAnnotatableComponent { - console.log(this.searchBox); const place = this.searchBox.getPlace(); if (!place.geometry || !place.geometry.location) { @@ -416,7 +408,6 @@ export class MapBox extends ViewBoxAnnotatableComponent { + let ele: Opt = undefined; + if (this._pdfViewer?.selectionContent()) { + ele = document.createElement('div'); + ele.append(this._pdfViewer.selectionContent()!); + } const docAnchor = () => { const anchor = Docs.Create.TextanchorDocument({ title: StrCast(this.rootDoc.title + '@' + NumCast(this.layoutDoc._scrollTop)?.toFixed(0)), @@ -222,6 +227,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent = React.createRef(); private _keyInput = React.createRef(); private _initialScroll: Opt = NumCast(this.layoutDoc.thumbScrollTop, NumCast(this.layoutDoc.scrollTop)); - private _getAnchor: (savedAnnotations?: ObservableMap) => Opt = () => undefined; private _sidebarRef = React.createRef(); private _searchRef = React.createRef(); private _searchString = ''; + + private get _getAnchor() { + return AnchorMenu.Instance?.GetAnchor; + } @observable private _webUrl = ''; // url of the src parameter of the embedded iframe but not necessarily the rendered page - eg, when following a link, the rendered page changes but we don't wan the src parameter to also change as that would cause an unnecessary re-render. @observable private _hackHide = false; // apparently changing the value of the 'sandbox' prop doesn't necessarily apply it to the active iframe. so thisforces the ifrmae to be rebuilt when allowScripts is toggled @observable private _searching: boolean = false; @@ -285,7 +288,7 @@ export class WebBox extends ViewBoxAnnotatableComponent void) => (this._setBrushViewer = func); brushView = (view: { width: number; height: number; panX: number; panY: number }) => this._setBrushViewer?.(view); scrollFocus = (doc: Doc, options: DocFocusOptions) => { - if (StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl), options.instant); + if (this._url && StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl), options.instant); if (DocListCast(this.props.Document[this.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) { this.toggleSidebar(options.instant); } @@ -305,6 +308,14 @@ export class WebBox extends ViewBoxAnnotatableComponent { + let ele: Opt = undefined; + try { + const contents = this._iframe?.contentWindow?.getSelection()?.getRangeAt(0).cloneContents(); + if (contents) { + ele = document.createElement('div'); + ele.append(contents); + } + } catch (e) {} const anchor = this._getAnchor(this._savedAnnotations) ?? Docs.Create.WebanchorDocument(this._url, { @@ -312,6 +323,8 @@ export class WebBox extends ViewBoxAnnotatableComponent { + const split = s.split(''); return Math.abs( - s.split('').reduce((a: any, b: any) => { + split.reduce((a: any, b: any) => { a = (a << 5) - a + b.charCodeAt(0); return a & a; }, 0) @@ -686,7 +700,6 @@ export class WebBox extends ViewBoxAnnotatableComponent { - this._getAnchor = AnchorMenu.Instance?.GetAnchor; this._marqueeing = undefined; this._isAnnotating = false; this._iframeClick = undefined; @@ -1006,7 +1019,7 @@ export class WebBox extends ViewBoxAnnotatableComponent{' '} + />
)} @@ -1043,5 +1056,5 @@ export class WebBox extends ViewBoxAnnotatableComponent() { } private _disposers: { [name: string]: IReactionDisposer } = {}; - private _obDisposers: { [name: string]: any } = {}; public selectedArray = new ObservableSet(); @observable public static Instance: PresBox; @@ -142,20 +141,10 @@ export class PresBox extends ViewBoxBaseComponent() { // Turn of progressivize editors this.turnOffEdit(true); Object.values(this._disposers).forEach(disposer => disposer?.()); - Object.values(this._obDisposers).forEach(disposer => disposer?.()); } @action componentDidMount() { - this._obDisposers.anim = observe( - this, - 'activeItem', - change => { - change.oldValue && (DocCast((change.oldValue as Doc).presentationTargetDoc)[AnimationSym] = undefined); - change.newValue && (DocCast((change.newValue as Doc).presentationTargetDoc)[AnimationSym] = change.newValue as Doc); - }, - true - ); this._disposers.keyboard = reaction( () => this.selectedDoc, selected => { @@ -217,16 +206,37 @@ export class PresBox extends ViewBoxBaseComponent() { // TODO: to handle child slides (entering into subtrail and exiting), also the next() and back() functions // No more frames in current doc and next slide is defined, therefore move to next slide nextSlide = (slideNum?: number) => { - CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => DocumentManager.Instance.getDocumentView(clip)?.ComponentView?.Pause?.()); - let nextSelected = slideNum ?? this.itemIndex + 1; - this.gotoDocument(nextSelected, this.activeItem); - for (nextSelected = nextSelected + 1; nextSelected < this.childDocs.length; nextSelected++) { - if (this.childDocs[nextSelected].groupWithUp) { - this.gotoDocument(nextSelected, this.activeItem, true); - } else { - break; + const nextSlideInd = slideNum ?? this.itemIndex + 1; + let curSlideInd = nextSlideInd; + const resetSelection = action(() => { + this.clearSelectedArray(); + for (let i = nextSlideInd; i <= curSlideInd; i++) { + this.addToSelectedArray(this.childDocs[i]); } - } + }); + CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => DocumentManager.Instance.getDocumentView(clip)?.ComponentView?.Pause?.()); + this.clearSelectedArray(); + const doGroupWithUp = + (nextSelected: number, force = false) => + () => { + if (nextSelected < this.childDocs.length) { + if (force || this.childDocs[nextSelected].groupWithUp) { + const serial = nextSelected + 1 < this.childDocs.length && NumCast(this.childDocs[nextSelected + 1].groupWithUp) > 1; + if (serial) { + this.gotoDocument(nextSelected, this.activeItem, true, async () => { + const waitTime = NumCast(this.activeItem.presDuration) - NumCast(this.activeItem.presTransition); + await new Promise(res => setTimeout(() => res(), Math.max(0, waitTime))); + doGroupWithUp(nextSelected + 1)(); + }); + } else { + this.gotoDocument(nextSelected, this.activeItem, undefined, resetSelection); + curSlideInd = this.itemIndex; + doGroupWithUp(nextSelected + 1)(); + } + } + } + }; + doGroupWithUp(curSlideInd, true)(); }; // Called when the user activates 'next' - to move to the next part of the pres. trail @@ -270,9 +280,8 @@ export class PresBox extends ViewBoxBaseComponent() { //The function that is called when a document is clicked or reached through next or back. //it'll also execute the necessary actions if presentation is playing. @undoBatch - public gotoDocument = action((index: number, from?: Doc, group?: boolean) => { + public gotoDocument = action((index: number, from?: Doc, group?: boolean, finished?: () => void) => { Doc.UnBrushAllDocs(); - if (index >= 0 && index < this.childDocs.length) { this.rootDoc._itemIndex = index; const activeItem: Doc = this.activeItem; @@ -280,10 +289,11 @@ export class PresBox extends ViewBoxBaseComponent() { const activeFrame = activeItem.presActiveFrame ?? activeItem.presCurrentFrame; if (activeFrame !== undefined) { const transTime = NumCast(activeItem.presTransition, 500); - const context = activeItem.presActiveFrame !== undefined ? DocCast(DocCast(activeItem.presentationTargetDoc).context) : DocCast(activeItem.presentationTargetDoc); + const acontext = activeItem.presActiveFrame !== undefined ? DocCast(DocCast(activeItem.presentationTargetDoc).context) : DocCast(activeItem.presentationTargetDoc); + const context = DocCast(acontext)?.annotationOn ? DocCast(DocCast(acontext).annotationOn) : acontext; if (context) { const ffview = DocumentManager.Instance.getFirstDocumentView(context)?.ComponentView as CollectionFreeFormView; - if (ffview) { + if (ffview?.childDocs) { this._keyTimer = CollectionFreeFormDocumentView.gotoKeyframe(this._keyTimer, ffview.childDocs.slice(), transTime); context._currentFrame = NumCast(activeFrame); } @@ -302,7 +312,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (!group) this.clearSelectedArray(); this.childDocs[index] && this.addToSelectedArray(this.childDocs[index]); //Update selected array this.turnOffEdit(); - this.navigateToActiveItem(); //Handles movement to element only when presTrail is list + this.navigateToActiveItem(finished); //Handles movement to element only when presTrail is list this.onHideDocument(); //Handles hide after/before } }); @@ -489,13 +499,18 @@ export class PresBox extends ViewBoxBaseComponent() { * a new tab. If presCollection is undefined it will open the document * on the right. */ - navigateToActiveItem = () => { + navigateToActiveItem = (afterNav?: () => void) => { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; + const finished = () => { + afterNav?.(); + console.log('Finish Slide Nav: ' + targetDoc.title); + targetDoc[AnimationSym] = undefined; + }; const srcContext = Cast(targetDoc.context, Doc, null) ?? Cast(Cast(targetDoc.annotationOn, Doc, null)?.context, Doc, null); const presCollection = Cast(this.layoutDoc.presCollection, Doc, null); const collectionDocView = presCollection ? DocumentManager.Instance.getDocumentView(presCollection) : undefined; - const includesDoc: boolean = DocListCast(presCollection?.data).includes(targetDoc); + const includesDoc: boolean = DocumentManager.Instance.getDocumentView(targetDoc) ? true : false; // DocListCast(presCollection?.data).includes(targetDoc); const tabMap = CollectionDockingView.Instance?.tabMap; const tab = tabMap && Array.from(tabMap).find(tab => tab.DashDoc === srcContext || tab.DashDoc === targetDoc); // Handles the setting of presCollection @@ -517,13 +532,14 @@ export class PresBox extends ViewBoxBaseComponent() { selViewCache.forEach(doc => this.addToSelectedArray(doc)); this._dragArray.splice(0, this._dragArray.length, ...dragViewCache); this._eleArray.splice(0, this._eleArray.length, ...eleViewCache); + finished(); }); const createDocView = (doc: Doc, finished?: () => void) => { DocumentManager.Instance.AddViewRenderedCb(doc, () => finished?.()); (collectionDocView ?? this).props.addDocTab(doc, OpenWhere.lightbox); this.layoutDoc.presCollection = targetDoc; }; - PresBox.NavigateToTarget(targetDoc, activeItem, createDocView, srcContext, includesDoc || tab ? undefined : resetSelection); + PresBox.NavigateToTarget(targetDoc, activeItem, createDocView, srcContext, includesDoc || tab ? finished : resetSelection); }; static NavigateToTarget(targetDoc: Doc, activeItem: Doc, createDocView: any, srcContext: Doc, finished?: () => void) { @@ -552,11 +568,13 @@ export class PresBox extends ViewBoxBaseComponent() { willPanZoom: activeItem.presMovement === PresMovement.Zoom || activeItem.presMovement === PresMovement.Jump || activeItem.presMovement === PresMovement.Center, zoomScale: activeItem.presMovement === PresMovement.Center ? 0 : NumCast(activeItem.presZoom, 1), zoomTime: activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500), + effect: activeItem, noSelect: true, originatingDoc: activeItem, easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any, + zoomTextSelections: true }; - + if (activeItem.presentationTargetDoc instanceof Doc) activeItem.presentationTargetDoc[AnimationSym] = undefined; var containerDocContext = srcContext ? [srcContext] : []; while (containerDocContext.length && !DocumentManager.Instance.getDocumentView(containerDocContext[0]) && containerDocContext[0].context) { containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext]; @@ -577,12 +595,15 @@ export class PresBox extends ViewBoxBaseComponent() { this.childDocs.forEach((doc, index) => { const curDoc = Cast(doc, Doc, null); const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); - //if (tagDoc) tagDoc.opacity = 1; const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, tagDoc); - const curInd: number = itemIndexes.indexOf(index); if (tagDoc === this.layoutDoc.presCollection) { tagDoc.opacity = 1; } else { + if (curDoc.presHide) { + if (index !== this.itemIndex) { + tagDoc.opacity = 1; + } + } const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex); if (curDoc.presHideBefore && index === hidingIndBef) { if (index > this.itemIndex) { diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 4469be488..5e1474b89 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -507,11 +507,12 @@ export class PresElementBox extends ViewBoxBaseComponent() { {activeItem.groupWithUp ? 'Ungroup' : 'Group with up'}}>
(activeItem.groupWithUp = !activeItem.groupWithUp)} + onClick={() => (activeItem.groupWithUp = (NumCast(activeItem.groupWithUp) + 1) % 3)} style={{ zIndex: 1000 - this.indexInPres, fontWeight: 700, backgroundColor: activeItem.groupWithUp ? (presColorBool ? presBoxColor : Colors.MEDIUM_BLUE) : undefined, + outline: NumCast(activeItem.groupWithUp) > 1 ? 'solid black 1px' : undefined, height: activeItem.groupWithUp ? 53 : 18, transform: activeItem.groupWithUp ? 'translate(0, -17px)' : undefined, }}> diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 906dff377..f95d5ac2e 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -68,9 +68,9 @@ export class PDFViewer extends React.Component { private _annotationLayer: React.RefObject = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; private _viewer: React.RefObject = React.createRef(); - public _getAnchor: (savedAnnotations?: ObservableMap) => Opt = () => undefined; _mainCont: React.RefObject = React.createRef(); private _selectionText: string = ''; + private _selectionContent: DocumentFragment | undefined; private _downX: number = 0; private _downY: number = 0; private _lastSearch = false; @@ -78,8 +78,12 @@ export class PDFViewer extends React.Component { private _ignoreScroll = false; private _initialScroll: { loc: Opt; easeFunc: 'linear' | 'ease' | undefined } | undefined; private _forcedScroll = true; + get _getAnchor() { + return AnchorMenu.Instance?.GetAnchor; + } selectionText = () => this._selectionText; + selectionContent = () => this._selectionContent; @observable isAnnotating = false; // key where data is stored @@ -392,7 +396,6 @@ export class PDFViewer extends React.Component { @action finishMarquee = (x?: number, y?: number) => { - this._getAnchor = AnchorMenu.Instance?.GetAnchor; this.isAnnotating = false; this._marqueeing = undefined; this._textSelecting = true; @@ -437,7 +440,8 @@ export class PDFViewer extends React.Component { } } } - this._selectionText = selRange.cloneContents().textContent || ''; + this._selectionContent = selRange.cloneContents(); + this._selectionText = this._selectionContent?.textContent || ''; // clear selection if (sel.empty) { diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 6762665a2..19ffc5005 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1,6 +1,6 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { saveAs } from 'file-saver'; -import { action, computed, observable, ObservableMap, runInAction } from 'mobx'; +import { action, computed, observable, ObservableMap, ObservableSet, runInAction } from 'mobx'; import { computedFn } from 'mobx-utils'; import { alias, map, serializable } from 'serializr'; import { DocServer } from '../client/DocServer'; @@ -343,6 +343,10 @@ export class Doc extends RefField { @observable public [DirectLinksSym]: Set = new Set(); @observable public [AnimationSym]: Opt; @observable public [HighlightSym]: boolean = false; + static __Anim(Doc: Doc) { + // for debugging to print AnimationSym field easily. + return Doc[AnimationSym]; + } private [UpdatingFromServer]: boolean = false; private [ForceServerWrite]: boolean = false; @@ -1131,7 +1135,7 @@ export namespace Doc { BrushedDoc: ObservableMap = new ObservableMap(); SearchMatchDoc: ObservableMap = new ObservableMap(); } - const brushManager = new DocBrush(); + export const brushManager = new DocBrush(); export class DocData { @observable _user_doc: Doc = undefined!; @@ -1284,8 +1288,8 @@ export namespace Doc { } let UnhighlightWatchers: (() => void)[] = []; - let UnhighlightTimer: any; - export function AddUnlightWatcher(watcher: () => void) { + export let UnhighlightTimer: any; + export function AddUnHighlightWatcher(watcher: () => void) { if (UnhighlightTimer) { UnhighlightWatchers.push(watcher); } else watcher(); @@ -1302,16 +1306,16 @@ export namespace Doc { }, 5000); } - var highlightedDocs = new Set(); + export var highlightedDocs = new ObservableSet(); export function IsHighlighted(doc: Doc) { if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return false; return doc[HighlightSym] || Doc.GetProto(doc)[HighlightSym]; } export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true, presEffect?: Doc) { runInAction(() => { - doc[AnimationSym] = presEffect; highlightedDocs.add(doc); doc[HighlightSym] = true; + doc[AnimationSym] = presEffect; if (dataAndDisplayDocs) { highlightedDocs.add(Doc.GetProto(doc)); Doc.GetProto(doc)[HighlightSym] = true; -- cgit v1.2.3-70-g09d2 From ac6f6a19fedc9c6a9d233a43aee4ed82b620d5ad Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 2 Feb 2023 00:20:54 -0500 Subject: added initial support for equationBox font size setting --- src/client/views/nodes/DocumentView.scss | 1 + src/client/views/nodes/EquationBox.tsx | 9 +++++++++ src/client/views/nodes/button/FontIconBox.tsx | 2 +- src/client/views/nodes/formattedText/RichTextMenu.tsx | 15 +++++++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) (limited to 'src/client/views/nodes/DocumentView.scss') diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 453bdac8e..e5913d997 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -162,6 +162,7 @@ width: 100%; height: 100%; border-radius: inherit; + white-space: normal; .documentView-styleContentWrapper { width: 100%; diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index c279341cc..da9be63b8 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -21,6 +21,7 @@ export class EquationBox extends ViewBoxBaseComponent() { public static SelectOnLoad: string = ''; _ref: React.RefObject = React.createRef(); componentDidMount() { + this.props.setContentView?.(this); if (EquationBox.SelectOnLoad === this.rootDoc[Id] && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()))) { this.props.select(false); @@ -100,6 +101,13 @@ export class EquationBox extends ViewBoxBaseComponent() { if (entries[0].contentBoxSize[0].inlineSize) { this.rootDoc._width = entries[0].contentBoxSize[0].inlineSize; } + 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', '')); + this.layoutDoc._width = Math.max(35, _width); + this.layoutDoc._height = Math.max(25, _height); + } }) ).observe(r); }} @@ -110,6 +118,7 @@ export class EquationBox extends ViewBoxBaseComponent() { width: 'fit-content', // `${100 / scale}%`, height: `${100 / scale}%`, pointerEvents: !this.props.isSelected() ? 'none' : undefined, + fontSize: StrCast(this.rootDoc._fontSize), }} onKeyDown={e => e.stopPropagation()}> diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index 1de29f806..9ef32014b 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -133,7 +133,7 @@ export class FontIconBox extends DocComponent() { @computed get numberButton() { const numBtnType: string = StrCast(this.rootDoc.numBtnType); const numScript = ScriptCast(this.rootDoc.script); - const setValue = (value: number) => numScript?.script.run({ value, _readOnly_: false }); + const setValue = (value: number) => UndoManager.RunInBatch(() => numScript?.script.run({ value, _readOnly_: false }), 'set num value'); // Script for checking the outcome of the toggle const checkResult: number = numScript?.script.run({ value: 0, _readOnly_: true }).result || 0; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 6c6d26af5..b70da2e5e 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -20,6 +20,7 @@ import { FormattedTextBox } from './FormattedTextBox'; import { updateBullets } from './ProsemirrorExampleTransfer'; import './RichTextMenu.scss'; import { schema } from './schema_rts'; +import { EquationBox } from '../EquationBox'; const { toggleMark } = require('prosemirror-commands'); @observer @@ -97,6 +98,16 @@ export class RichTextMenu extends AntimodeMenu { @computed get textAlign() { return this._activeAlignment; } + _disposer: IReactionDisposer | undefined; + componentDidMount() { + this._disposer = reaction( + () => SelectionManager.Views(), + views => this.updateMenu(undefined, undefined, undefined) + ); + } + componentWillUnmount() { + this._disposer?.(); + } @action public updateMenu(view: EditorView | undefined, lastState: EditorState | undefined, props: any) { @@ -206,6 +217,8 @@ export class RichTextMenu extends AntimodeMenu { m.type === state.schema.marks.pFontSize && activeSizes.add(m.attrs.fontSize); m.type === state.schema.marks.marker && activeHighlights.add(String(m.attrs.highlight)); }); + } else if (SelectionManager.Views().some(dv => dv.ComponentView instanceof EquationBox)) { + SelectionManager.Views().forEach(dv => StrCast(dv.rootDoc._fontSize) && activeSizes.add(StrCast(dv.rootDoc._fontSize))); } return { activeFamilies: Array.from(activeFamilies), activeSizes: Array.from(activeSizes), activeColors: Array.from(activeColors), activeHighlights: Array.from(activeHighlights) }; } @@ -328,6 +341,8 @@ export class RichTextMenu extends AntimodeMenu { this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true); this.view.focus(); } + } else if (SelectionManager.Views().some(dv => dv.ComponentView instanceof EquationBox)) { + SelectionManager.Views().forEach(dv => (dv.rootDoc._fontSize = fontSize)); } else Doc.UserDoc()._fontSize = fontSize; this.updateMenu(this.view, undefined, this.props); }; -- cgit v1.2.3-70-g09d2 From 0d899471be676f6619244350982630b151bb4b41 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 28 Mar 2023 19:53:49 -0400 Subject: mostly code cleaning. small bugs --- src/client/documents/Documents.ts | 4 +- src/client/util/CurrentUserUtils.ts | 2 +- src/client/views/OverlayView.tsx | 6 +- src/client/views/StyleProvider.tsx | 12 +-- .../views/collections/CollectionTimeView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 1 + .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/nodes/DocumentView.scss | 6 +- src/client/views/nodes/DocumentView.tsx | 93 ++++++++++------------ src/client/views/nodes/LinkAnchorBox.tsx | 32 +++----- src/client/views/nodes/trails/PresBox.tsx | 5 +- 11 files changed, 76 insertions(+), 89 deletions(-) (limited to 'src/client/views/nodes/DocumentView.scss') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c484db0db..a110782b2 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -263,6 +263,7 @@ export class DocumentOptions { defaultBackgroundColor?: string; _isLinkButton?: boolean; // marks a document as a button that will follow its primary link when clicked _linkAutoMove?: boolean; // whether link endpoint should move around the edges of a document to make shortest path to other link endpoint + hideLinkAnchors?: boolean; // suppresses link anchor dots from being displayed isFolder?: boolean; lastFrame?: number; // the last frame of a frame-based collection (e.g., progressive slide) activeFrame?: number; // the active frame of a document in a frame base collection @@ -505,6 +506,7 @@ export namespace Docs { options: { childDontRegisterViews: true, _isLinkButton: true, + hideLinkAnchors: true, _height: 150, description: '', showCaption: 'description', @@ -581,7 +583,7 @@ export namespace Docs { DocumentType.PRES, { layout: { view: PresBox, dataField: defaultDataKey }, - options: { defaultDoubleClick: 'ignore' }, + options: { defaultDoubleClick: 'ignore', hideLinkAnchors: true }, }, ], [ diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index b21f53221..753cd1cb7 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -301,7 +301,7 @@ export class CurrentUserUtils { { toolTip: "Tap or drag to create a data viz node", title: "DataViz", icon: "file", dragFactory: doc.emptyDataViz as Doc, clickFactory: DocCast(doc.emptyDataViz)}, { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "file", dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay}, { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize", dragFactory: doc.emptyHeader as Doc, clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true }, - { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", clickFactory: "repl" as any, openFactoryLocation: OpenWhere.overlay}, + { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", clickFactory: 'repl' as any, openFactoryLocation: OpenWhere.overlay}, ].map(tuple => ( { openFactoryLocation: OpenWhere.addRight, scripts: { onClick: 'openDoc(copyDragFactory(this.clickFactory,this.openFactoryAsDelegate), this.openFactoryLocation)', diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 34e8cd6dd..ec22128d4 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -219,6 +219,7 @@ export class OverlayView extends React.Component { PanelHeight={d[HeightSym]} ScreenToLocalTransform={this.docScreenToLocalXf(d)} renderDepth={1} + hideDecorations={true} isDocumentActive={returnTrue} isContentActive={returnTrue} whenChildContentsActiveChanged={emptyFunction} @@ -252,8 +253,3 @@ export class OverlayView extends React.Component { ); } } -// bcz: ugh ... want to be able to pass ScriptingRepl as tag argument, but that doesn't seem to work.. runtime error -ScriptingGlobals.add(function addOverlayWindow(type: string, options: OverlayElementOptions) { - OverlayView.Instance.addWindow(, options); - addOverlayWindow('ScriptingRepl', { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' }); -}); diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index faaa4e1f9..bd0539069 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -36,10 +36,10 @@ export enum StyleProp { FillColor = 'fillColor', // fill color of an ink stroke or shape WidgetColor = 'widgetColor', // color to display UI widgets on a document view -- used for the sidebar divider dragger on a text note HideLinkButton = 'hideLinkButton', // hides the blue-dot link button. used when a document acts like a button - LinkSource = 'linkSource', // source document of a link -- used by LinkAnchorBox PointerEvents = 'pointerEvents', // pointer events for DocumentView -- inherits pointer events if not specified Decorations = 'decorations', // additional decoration to display above a DocumentView -- currently only used to display a Lock for making things background HeaderMargin = 'headerMargin', // margin at top of documentview, typically for displaying a title -- doc contents will start below that + ShowCaption = 'showCaption', TitleHeight = 'titleHeight', // Height of Title area ShowTitle = 'showTitle', // whether to display a title on a Document (optional :hover suffix) JitterRotation = 'jitterRotation', // whether documents should be randomly rotated @@ -182,6 +182,8 @@ export function DefaultStyleProvider(doc: Opt, props: Opt (props?.PanelHeight() || 0) ? 5 : 10) : 0; + case StyleProp.ShowCaption: + return doc?._viewType === CollectionViewType.Carousel || props?.hideCaptions ? undefined : StrCast(doc?._showCaption); case StyleProp.HeaderMargin: return ([CollectionViewType.Stacking, CollectionViewType.NoteTaking, CollectionViewType.Masonry, CollectionViewType.Tree].includes(doc?._viewType as any) || (doc?.type === DocumentType.RTF && !showTitle()?.includes('noMargin')) || @@ -299,12 +301,12 @@ export function DefaultStyleProvider(doc: Opt, props: Opt 0 ? ( + if (props?.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform) { + return doc?.pointerEvents !== 'none' ? null : (
toggleLockedPosition(doc)}> - +
- ) : null; + ); } } } diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 89b2fbfe3..4d5978548 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -150,7 +150,7 @@ export class CollectionTimeView extends CollectionSubView() { engineProps={{ pivotField: this.pivotField, docFilters: this.childDocFilters, docRangeFilters: this.childDocRangeFilters }} fitContentsToBox={returnTrue} childClickScript={this._childClickedScript} - viewDefDivClick={this._viewDefDivClick} + viewDefDivClick={this.layoutEngine() === computeTimelineLayout.name ? undefined : this._viewDefDivClick} //dontScaleFilter={this.dontScaleFilter} layoutEngine={this.layoutEngine} /> diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 93b816581..4ad09628f 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -422,6 +422,7 @@ export class TabDocView extends React.Component { })} renderDepth={0} LayoutTemplateString={this.props.keyValue ? KeyValueBox.LayoutString() : undefined} + hideTitle={this.props.keyValue} Document={this._document} DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined} ContainingCollectionView={undefined} diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 0714bffbc..f16371592 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -609,7 +609,7 @@ export class MarqueeView extends React.Component { const layoutDoc = Doc.Layout(doc); diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index e5913d997..1265651ad 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -17,8 +17,7 @@ top: 0; } -.documentView-node, -.documentView-node-topmost { +.documentView-node { position: inherit; top: 0; left: 0; @@ -209,8 +208,7 @@ } } -.documentView-node:hover, -.documentView-node-topmost:hover { +.documentView-node:hover { > .documentView-styleWrapper { > .documentView-titleWrapper-hover { display: inline-block; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9a3e77e6e..ab93ce87b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -268,9 +268,6 @@ export class DocumentViewInternal extends DocComponent; // milliseconds for animating between views. defaults to 300 if not uset @observable _animateScalingTo = 0; - private get topMost() { - return this.props.renderDepth === 0 && !LightboxView.LightboxDoc; - } public get animateScaleTime() { return this._animateScaleTime ?? 300; } @@ -307,8 +304,9 @@ export class DocumentViewInternal extends DocComponent { - this.props.ContainingCollectionView?.removeDocument(this.props.Document), RadialMenu.Instance.closeMenu(); + this.props.ContainingCollectionView?.removeDocument(this.props.Document); + RadialMenu.Instance.closeMenu(); }, icon: 'external-link-square-alt', selected: -1, @@ -563,13 +565,11 @@ export class DocumentViewInternal extends DocComponent { - if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) return; + if (e.buttons !== 1 || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) return; - if (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) { - if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { - this.cleanupPointerEvents(); - this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && 'alias') || ((this.Document.dropAction || this.props.dropAction || undefined) as dropActionType)); - } + if (!Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, Date.now())) { + this.cleanupPointerEvents(); + this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && 'alias') || ((this.Document.dropAction || this.props.dropAction || undefined) as dropActionType)); } }; @@ -888,7 +888,7 @@ export class DocumentViewInternal extends DocComponent d.linkDisplay); return filtered.map((link, i) => (
@@ -1059,11 +1056,13 @@ export class DocumentViewInternal extends DocComponent this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.ScreenToLocalTransform().Scale || 1; const showTitle = this.ShowTitle?.split(':')[0]; const showTitleHover = this.ShowTitle?.includes(':hover'); - const showCaption = !this.props.hideCaptions && this.Document._viewType !== CollectionViewType.Carousel ? StrCast(this.layoutDoc._showCaption) : undefined; - const captionView = !showCaption ? null : ( + const captionView = !this.showCaption ? null : (
@@ -1161,12 +1159,13 @@ export class DocumentViewInternal extends DocComponent @@ -1220,7 +1219,7 @@ export class DocumentViewInternal extends DocComponent
); - return this.props.hideTitle || (!showTitle && !showCaption) ? ( + return this.props.hideTitle || (!showTitle && !this.showCaption) ? ( this.contents ) : (
@@ -1235,31 +1234,27 @@ export class DocumentViewInternal extends DocComponent { TraceMobx(); - const thumb = ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url?.href.replace('.png', '_m.png'); - const background = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor + ':box'); - if (!(this.props.Document instanceof Doc) || GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate || this.hidden) return null; - return ( - this.docContents ?? ( -
- {this.innards} - {!this.disableClickScriptFunc && this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ?
: null} - {this.widgetDecorations ?? null} -
- ) - ); + return !DocCast(this.Document) || GetEffectiveAcl(this.Document[DataSym]) === AclPrivate || this.hidden + ? null + : this.docContents ?? ( +
+ {this.innards} + {this.widgetDecorations ?? null} +
+ ); }; /** @@ -1506,7 +1501,7 @@ export class DocumentView extends React.Component { return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this.props.PanelWidth(); } @computed get panelHeight() { - if (this.effectiveNativeHeight && !this.layoutDoc.nativeHeightUnfrozen) { + if (this.effectiveNativeHeight && (!this.fitWidth || !this.layoutDoc.nativeHeightUnfrozen)) { return Math.min(this.props.PanelHeight(), this.effectiveNativeHeight * this.nativeScaling); } return this.props.PanelHeight(); @@ -1528,7 +1523,7 @@ export class DocumentView extends React.Component { toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight()); getBounds = () => { - if (!this.docView || !this.docView.ContentDiv || this.props.Document.type === DocumentType.PRES || this.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { + if (!this.docView || !this.docView.ContentDiv || this.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { return undefined; } const xf = this.docView?.props diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index e12548f18..3feb95ce9 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -1,22 +1,19 @@ -import { action, observable } from 'mobx'; +import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../../fields/Doc'; -import { Cast, NumCast, StrCast } from '../../../fields/Types'; +import { NumCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; import { emptyFunction, setupMoveUpEvents, Utils } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; -import { ContextMenu } from '../ContextMenu'; -import { ContextMenuProps } from '../ContextMenuItem'; +import { SelectionManager } from '../../util/SelectionManager'; import { ViewBoxBaseComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import './LinkAnchorBox.scss'; import { LinkDocPreview } from './LinkDocPreview'; import React = require('react'); -import { LinkManager } from '../../util/LinkManager'; import globalCssVariables = require('../global/globalCssVariables.scss'); -import { SelectionManager } from '../../util/SelectionManager'; @observer export class LinkAnchorBox extends ViewBoxBaseComponent() { @@ -31,19 +28,15 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { @observable _x = 0; @observable _y = 0; + @computed get linkSource() { + return this.props.docViewPath()[this.props.docViewPath().length - 2].rootDoc; // this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.LinkSource); + } + onPointerDown = (e: React.PointerEvent) => { - const anchorContainerDoc = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.LinkSource); - setupMoveUpEvents( - this, - e, - this.onPointerMove, - emptyFunction, - (e, doubleTap) => { - if (doubleTap) LinkFollower.FollowLink(this.rootDoc, anchorContainerDoc, false); - else this.props.select(false); - }, - false - ); + setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => { + if (doubleTap) LinkFollower.FollowLink(this.rootDoc, this.linkSource, false); + else this.props.select(false); + }); }; onPointerMove = action((e: PointerEvent, down: number[], delta: number[]) => { const cdiv = this._ref?.current?.parentElement; @@ -73,7 +66,6 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { const small = this.props.PanelWidth() <= 1; // this happens when rendered in a treeView const x = NumCast(this.rootDoc[this.fieldKey + '_x'], 100); const y = NumCast(this.rootDoc[this.fieldKey + '_y'], 100); - const linkSource = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.LinkSource); const background = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.BackgroundColor + ':anchor'); const anchor = this.fieldKey === 'anchor1' ? 'anchor2' : 'anchor1'; const anchorScale = !this.dataDoc[this.fieldKey + '-useLinkSmallAnchor'] && (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : 0.25; @@ -87,7 +79,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { onPointerEnter={e => LinkDocPreview.SetLinkInfo({ docProps: this.props, - linkSrc: linkSource, + linkSrc: this.linkSource, linkDoc: this.rootDoc, showHeader: true, location: [e.clientX, e.clientY + 20], diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 3376c29a9..0afb36214 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -919,6 +919,7 @@ export class PresBox extends ViewBoxBaseComponent() { */ @action enterMinimize = () => { + this.updateCurrentPresentation(this.rootDoc); clearTimeout(this._presTimer); const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); this.props.removeDocument?.(this.layoutDoc); @@ -939,7 +940,7 @@ export class PresBox extends ViewBoxBaseComponent() { doc._height = 30; doc._width = PresBox.minimizedWidth; Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc); - PresBox.Instance.initializePresState(PresBox.Instance.itemIndex); + PresBox.Instance?.initializePresState(PresBox.Instance.itemIndex); return (doc.presStatus = PresStatus.Manual); } @@ -2435,7 +2436,7 @@ export class PresBox extends ViewBoxBaseComponent() {
Slide {this.itemIndex + 1} - {this.activeItem.presIndexed !== undefined ? `(${this.activeItem.presIndexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length} + {this.activeItem?.presIndexed !== undefined ? `(${this.activeItem.presIndexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length}
setupMoveUpEvents(this, e, returnFalse, returnFalse, this.exitClicked, false, false)}> -- cgit v1.2.3-70-g09d2