aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts4
-rw-r--r--src/client/util/DragManager.ts4
-rw-r--r--src/client/util/LinkFollower.ts10
-rw-r--r--src/client/views/DocComponent.tsx7
-rw-r--r--src/client/views/DocumentButtonBar.tsx2
-rw-r--r--src/client/views/InkingStroke.tsx4
-rw-r--r--src/client/views/LightboxView.tsx56
-rw-r--r--src/client/views/MarqueeAnnotator.tsx8
-rw-r--r--src/client/views/PropertiesView.tsx10
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx18
-rw-r--r--src/client/views/collections/CollectionSubView.tsx2
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx14
-rw-r--r--src/client/views/collections/TabDocView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx12
-rw-r--r--src/client/views/nodes/AudioBox.tsx7
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx6
-rw-r--r--src/client/views/nodes/DocumentView.tsx14
-rw-r--r--src/client/views/nodes/FunctionPlotBox.tsx7
-rw-r--r--src/client/views/nodes/ImageBox.tsx8
-rw-r--r--src/client/views/nodes/LabelBox.tsx4
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx2
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx5
-rw-r--r--src/client/views/nodes/PDFBox.tsx8
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx4
-rw-r--r--src/client/views/nodes/VideoBox.tsx11
-rw-r--r--src/client/views/nodes/WebBox.tsx6
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx39
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts2
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx13
-rw-r--r--src/client/views/pdf/AnchorMenu.tsx13
-rw-r--r--src/client/views/pdf/Annotation.tsx8
-rw-r--r--src/client/views/pdf/PDFViewer.tsx4
33 files changed, 157 insertions, 159 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index b51fcb454..80b040cc0 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1310,13 +1310,13 @@ export namespace DocUtils {
options?.afterFocus?.(false);
}
- export let ActiveRecordings: { props: FieldViewProps; getAnchor: () => Doc }[] = [];
+ export let ActiveRecordings: { props: FieldViewProps; getAnchor: (addAsAnnotation: boolean) => Doc }[] = [];
export function MakeLinkToActiveAudio(getSourceDoc: () => Doc | undefined, broadcastEvent = true) {
broadcastEvent && runInAction(() => (DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1));
return DocUtils.ActiveRecordings.map(audio => {
const sourceDoc = getSourceDoc();
- const link = sourceDoc && DocUtils.MakeLink({ doc: sourceDoc }, { doc: audio.getAnchor() || audio.props.Document }, 'recording annotation:linked recording', 'recording timeline');
+ const link = sourceDoc && DocUtils.MakeLink({ doc: sourceDoc }, { doc: audio.getAnchor(true) || audio.props.Document }, 'recording annotation:linked recording', 'recording timeline');
link && (link.followLinkLocation = OpenWhere.addRight);
return link;
});
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index d0690fa10..a56f87075 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -251,8 +251,8 @@ export namespace DragManager {
}
// drags a linker button and creates a link on drop
- export function StartLinkDrag(ele: HTMLElement, sourceView: DocumentView, sourceDocGetAnchor: undefined | (() => Doc), downX: number, downY: number, options?: DragOptions) {
- StartDrag([ele], new DragManager.LinkDragData(sourceView, () => sourceDocGetAnchor?.() ?? sourceView.rootDoc), downX, downY, options);
+ export function StartLinkDrag(ele: HTMLElement, sourceView: DocumentView, sourceDocGetAnchor: undefined | ((addAsAnnotation: boolean) => Doc), downX: number, downY: number, options?: DragOptions) {
+ StartDrag([ele], new DragManager.LinkDragData(sourceView, () => sourceDocGetAnchor?.(true) ?? sourceView.rootDoc), downX, downY, options);
}
// drags a column from a schema view
diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts
index 0f216e349..5bdfca54a 100644
--- a/src/client/util/LinkFollower.ts
+++ b/src/client/util/LinkFollower.ts
@@ -111,15 +111,9 @@ export class LinkFollower {
easeFunc: StrCast(sourceDoc.followLinkEase, 'ease') as any,
effect: sourceDoc,
originatingDoc: sourceDoc,
- zoomTextSelections: false,
+ zoomTextSelections: BoolCast(sourceDoc.followLinkZoomText),
};
- if (target.TourMap) {
- const fieldKey = Doc.LayoutFieldKey(target);
- const tour = DocListCast(target[fieldKey]).reverse();
- LightboxView.SetLightboxDoc(currentContext, undefined, tour);
- setTimeout(LightboxView.Next);
- allFinished();
- } else if (target.type === DocumentType.PRES) {
+ if (target.type === DocumentType.PRES) {
const containerAnnoDoc = Cast(sourceDoc, Doc, null);
const containerDoc = containerAnnoDoc || sourceDoc;
var containerDocContext = containerDoc?.context ? [Cast(await containerDoc?.context, Doc, null)] : ([] as Doc[]);
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index c9c09b63b..78ab2b3d4 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -130,6 +130,13 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
isAnyChildContentActive = () => this._isAnyChildContentActive;
+ isContentActive = (outsideReaction?: boolean) =>
+ this.props.isContentActive?.() === false
+ ? false
+ : Doc.ActiveTool !== InkTool.None || this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.rootSelected(outsideReaction) || this.isAnyChildContentActive()
+ ? true
+ : undefined;
+
lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result;
protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 90c6c040c..f06dc93e3 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -501,7 +501,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
key="popup"
showPopup={this._showLinkPopup}
linkCreated={link => (link.linkDisplay = !this.props.views().lastElement()?.rootDoc.isLinkButton)}
- linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.()}
+ linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.(true)}
linkFrom={() => this.props.views().lastElement()?.rootDoc}
/>
</div>
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index a6fa2f04b..319a9419e 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -78,8 +78,8 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
// fit within its panel (e.g., for content fitting views like Lightbox or multicolumn, etc)
screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.NativeDimScaling?.() || 1);
- getAnchor = () => {
- return this._subContentView?.getAnchor?.() || this.rootDoc;
+ getAnchor = (addAsAnnotation: boolean) => {
+ return this._subContentView?.getAnchor?.(addAsAnnotation) || this.rootDoc;
};
scrollFocus = (textAnchor: Doc, options: DocFocusOptions) => {
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index d79b696a3..3627aa783 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -37,7 +37,6 @@ export class LightboxView extends React.Component<LightboxViewProps> {
@observable private static _doc: Opt<Doc>;
@observable private static _docTarget: Opt<Doc>;
@observable private static _docFilters: string[] = []; // filters
- @observable private static _tourMap: Opt<Doc[]> = []; // list of all tours available from the current target
private static _savedState: Opt<{ panX: Opt<number>; panY: Opt<number>; scale: Opt<number>; scrollTop: Opt<number> }>;
private static _history: Opt<{ doc: Doc; target?: Doc }[]> = [];
@observable private static _future: Opt<Doc[]> = [];
@@ -90,13 +89,6 @@ export class LightboxView extends React.Component<LightboxViewProps> {
this._doc = doc;
this._layoutTemplate = layoutTemplate;
this._docTarget = target || doc;
- this._tourMap = DocListCast(doc?.links)
- .map(link => {
- const opp = LinkManager.getOppositeAnchor(link, doc!);
- return opp?.TourMap ? opp : undefined;
- })
- .filter(m => m)
- .map(m => m!);
return true;
}
@@ -164,7 +156,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
const target = (LightboxView._docTarget = this._future?.pop());
const targetDocView = target && DocumentManager.Instance.getLightboxDocumentView(target);
if (targetDocView && target) {
- const l = DocUtils.MakeLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.() || target).lastElement();
+ const l = DocUtils.MakeLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.(true) || target).lastElement();
l && (Cast(l.anchor2, Doc, null).backgroundColor = 'lightgreen');
targetDocView.focus(target, { originalTarget: target, willPanZoom: true, zoomScale: 0.9 });
if (LightboxView._history?.lastElement().target !== target) LightboxView._history?.push({ doc, target });
@@ -189,13 +181,6 @@ export class LightboxView extends React.Component<LightboxViewProps> {
LightboxView.SetLightboxDoc(target);
}
}
- LightboxView._tourMap = DocListCast(LightboxView._docTarget?.links)
- .map(link => {
- const opp = LinkManager.getOppositeAnchor(link, LightboxView._docTarget!);
- return opp?.TourMap ? opp : undefined;
- })
- .filter(m => m)
- .map(m => m!);
}
@action public static Previous() {
@@ -214,13 +199,6 @@ export class LightboxView extends React.Component<LightboxViewProps> {
LightboxView.SetLightboxDoc(doc, target);
}
if (LightboxView._future?.lastElement() !== previous.target || previous.doc) LightboxView._future?.push(previous.target || previous.doc);
- LightboxView._tourMap = DocListCast(LightboxView._docTarget?.links)
- .map(link => {
- const opp = LinkManager.getOppositeAnchor(link, LightboxView._docTarget!);
- return opp?.TourMap ? opp : undefined;
- })
- .filter(m => m)
- .map(m => m!);
}
@action
stepInto = () => {
@@ -231,27 +209,20 @@ export class LightboxView extends React.Component<LightboxViewProps> {
history: LightboxView._history,
saved: LightboxView._savedState,
});
- const tours = LightboxView._tourMap;
- if (tours && tours.length) {
- const fieldKey = Doc.LayoutFieldKey(tours[0]);
- LightboxView._future?.push(...DocListCast(tours[0][fieldKey]).reverse());
- } else {
- const coll = LightboxView._docTarget;
- if (coll) {
- const fieldKey = Doc.LayoutFieldKey(coll);
- const contents = [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + '-annotations'])];
- const links = DocListCast(coll.links)
- .map(link => LinkManager.getOppositeAnchor(link, coll))
- .filter(doc => doc)
- .map(doc => doc!);
- LightboxView.SetLightboxDoc(coll, undefined, contents.length ? contents : links);
- TabDocView.PinDoc(coll, { hidePresBox: true });
- }
+ const coll = LightboxView._docTarget;
+ if (coll) {
+ const fieldKey = Doc.LayoutFieldKey(coll);
+ const contents = [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + '-annotations'])];
+ const links = DocListCast(coll.links)
+ .map(link => LinkManager.getOppositeAnchor(link, coll))
+ .filter(doc => doc)
+ .map(doc => doc!);
+ LightboxView.SetLightboxDoc(coll, undefined, contents.length ? contents : links);
+ TabDocView.PinDoc(coll, { hidePresBox: true });
}
};
future = () => LightboxView._future;
- tourMap = () => LightboxView._tourMap;
render() {
let downx = 0,
downy = 0;
@@ -345,7 +316,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
},
this.future()?.length.toString()
)}
- <LightboxTourBtn navBtn={this.navBtn} future={this.future} stepInto={this.stepInto} tourMap={this.tourMap} />
+ <LightboxTourBtn navBtn={this.navBtn} future={this.future} stepInto={this.stepInto} />
<div
className="lightboxView-navBtn"
title={'toggle fit width'}
@@ -393,7 +364,6 @@ export class LightboxView extends React.Component<LightboxViewProps> {
}
interface LightboxTourBtnProps {
navBtn: (left: Opt<string | number>, bottom: Opt<number>, top: number, icon: string, display: () => string, click: (e: React.MouseEvent) => void, color?: string) => JSX.Element;
- tourMap: () => Opt<Doc[]>;
future: () => Opt<Doc[]>;
stepInto: () => void;
}
@@ -410,7 +380,7 @@ export class LightboxTourBtn extends React.Component<LightboxTourBtnProps> {
e.stopPropagation();
this.props.stepInto();
},
- StrCast(this.props.tourMap()?.lastElement()?.TourMap)
+ ''
);
}
}
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index bf1242346..b1965c5c8 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -52,8 +52,8 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
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<number, HTMLDivElement[]>) => this.highlight('rgba(173, 216, 230, 0.75)', true, savedAnnotations);
- AnchorMenu.Instance.onMakeAnchor = AnchorMenu.Instance.GetAnchor;
+ AnchorMenu.Instance.GetAnchor = (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>, addAsAnnotation?: boolean) => this.highlight('rgba(173, 216, 230, 0.75)', true, savedAnnotations, addAsAnnotation);
+ AnchorMenu.Instance.onMakeAnchor = () => AnchorMenu.Instance.GetAnchor(undefined, true);
}
@action
@@ -194,11 +194,11 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
return textRegionAnno;
};
@action
- highlight = (color: string, isLinkButton: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => {
+ highlight = (color: string, isLinkButton: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>, addAsAnnotation?: boolean) => {
// creates annotation documents for current highlights
const effectiveAcl = GetEffectiveAcl(this.props.rootDoc[DataSym]);
const annotationDoc = [AclAugment, AclSelfEdit, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color, isLinkButton, savedAnnotations);
- !savedAnnotations && annotationDoc && this.props.addDocument(annotationDoc);
+ addAsAnnotation && !savedAnnotations && annotationDoc && this.props.addDocument(annotationDoc);
return (annotationDoc as Doc) ?? undefined;
};
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 8d495d286..af50478b0 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1680,6 +1680,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</button>
</div>
<div className="propertiesView-input inline">
+ <p>Zoom Text Selections</p>
+ <button
+ style={{ background: !this.sourceAnchor?.followLinkZoomText ? '' : '#4476f7', borderRadius: 3 }}
+ onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoomText', this.sourceAnchor)}
+ onClick={e => e.stopPropagation()}
+ className="propertiesButton">
+ <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+ </button>
+ </div>
+ <div className="propertiesView-input inline">
<p>Toggle Target (Show/Hide)</p>
<button
style={{ background: !this.sourceAnchor?.followLinkToggle ? '' : '#4476f7', borderRadius: 3 }}
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index e9bf03208..b7ea26b44 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -190,7 +190,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
CollectionStackedTimeline.SelectingRegion = this;
} else {
this._markerEnd = this.currentTime;
- CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.props.startTag, this.props.endTag, this._markerStart, this._markerEnd);
+ CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.props.startTag, this.props.endTag, this._markerStart, this._markerEnd, undefined, true);
this._markerEnd = undefined;
CollectionStackedTimeline.SelectingRegion = undefined;
}
@@ -257,7 +257,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
this._markerEnd = tmp;
}
if (!isClick && Math.abs(movement[0]) > 15 && !this.IsTrimming) {
- const anchor = CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.props.startTag, this.props.endTag, this._markerStart, this._markerEnd);
+ const anchor = CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.props.startTag, this.props.endTag, this._markerStart, this._markerEnd, undefined, true);
setTimeout(() => DocumentManager.Instance.getDocumentView(anchor)?.select(false));
}
(!isClick || !wasSelecting) && (this._markerEnd = undefined);
@@ -273,7 +273,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
undefined,
() => {
if (shiftKey) {
- CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.props.startTag, this.props.endTag, this.currentTime);
+ CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.props.startTag, this.props.endTag, this.currentTime, undefined, undefined, true);
} else {
!wasPlaying && this.props.setTime(this.toTimeline(clientX - rect.x, rect.width));
}
@@ -388,7 +388,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
// creates marker on timeline
@undoBatch
@action
- static createAnchor(rootDoc: Doc, dataDoc: Doc, fieldKey: string, startTag: string, endTag: string, anchorStartTime?: number, anchorEndTime?: number, docAnchor?: Doc) {
+ static createAnchor(rootDoc: Doc, dataDoc: Doc, fieldKey: string, startTag: string, endTag: string, anchorStartTime: Opt<number>, anchorEndTime: Opt<number>, docAnchor: Opt<Doc>, addAsAnnotation: boolean) {
if (anchorStartTime === undefined) return rootDoc;
const anchor =
docAnchor ??
@@ -407,10 +407,12 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
});
Doc.GetProto(anchor)[startTag] = anchorStartTime;
Doc.GetProto(anchor)[endTag] = anchorEndTime;
- if (Cast(dataDoc[fieldKey], listSpec(Doc), null)) {
- Cast(dataDoc[fieldKey], listSpec(Doc), []).push(anchor);
- } else {
- dataDoc[fieldKey] = new List<Doc>([anchor]);
+ if (addAsAnnotation) {
+ if (Cast(dataDoc[fieldKey], listSpec(Doc), null)) {
+ Cast(dataDoc[fieldKey], listSpec(Doc), []).push(anchor);
+ } else {
+ dataDoc[fieldKey] = new List<Doc>([anchor]);
+ }
}
return anchor;
}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index d2074219a..27ae3041f 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -334,7 +334,7 @@ export function CollectionSubView<X>(moreProps?: X) {
const iframe = SelectionManager.Views()[0].ContentDiv?.getElementsByTagName('iframe')?.[0];
const focusNode = iframe?.contentDocument?.getSelection()?.focusNode as any;
if (focusNode) {
- const anchor = srcWeb?.ComponentView?.getAnchor?.();
+ const anchor = srcWeb?.ComponentView?.getAnchor?.(true);
anchor && DocUtils.MakeLink({ doc: htmlDoc }, { doc: anchor });
}
}
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index a1466bcd0..8c613198d 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -32,7 +32,7 @@ export class CollectionTimeView extends CollectionSubView() {
@observable _viewDefDivClick: Opt<ScriptField>;
@observable _focusPivotField: Opt<string>;
- getAnchor = () => {
+ getAnchor = (addAsAnnotation: boolean) => {
const anchor = Docs.Create.HTMLAnchorDocument([], {
title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as any,
annotationOn: this.rootDoc,
@@ -45,11 +45,13 @@ export class CollectionTimeView extends CollectionSubView() {
proto.docRangeFilters = ObjectField.MakeCopy(this.layoutDoc._docRangeFilters as ObjectField) || new List<string>([]);
proto[ViewSpecPrefix + '_viewType'] = this.layoutDoc._viewType;
- // store anchor in annotations list of document (not technically needed since these anchors are never drawn)
- if (Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), null) !== undefined) {
- Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), []).push(anchor);
- } else {
- this.dataDoc[this.props.fieldKey + '-annotations'] = new List<Doc>([anchor]);
+ if (addAsAnnotation) {
+ // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered
+ if (Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), null) !== undefined) {
+ Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), []).push(anchor);
+ } else {
+ this.dataDoc[this.props.fieldKey + '-annotations'] = new List<Doc>([anchor]);
+ }
}
return anchor;
};
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 5c05b5c13..f6e4b45ee 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -247,7 +247,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
alert('Cannot pin presentation document to itself');
return;
}
- const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.();
+ const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(false);
const pinDoc = Doc.MakeAlias(anchorDoc ?? doc);
pinDoc.presentationTargetDoc = anchorDoc ?? doc;
pinDoc.title = doc.title + ' - Slide';
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 8919b1c01..9811c239b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -290,7 +290,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
stroke="antiquewhite"
strokeWidth="4"
className="collectionfreeformlinkview-linkLine"
- style={{ pointerEvents: 'all', opacity: this._opacity, stroke, strokeWidth }}
+ style={{ pointerEvents: 'visibleStroke', opacity: this._opacity, stroke, strokeWidth }}
onClick={this.onClickLine}
d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`}
markerEnd={link.linkDisplayArrow ? `url(#${link[Id] + 'arrowhead'})` : ''}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index dc0eb69f3..5cf4cb31f 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1565,7 +1565,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
: undefined;
}; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document
- getAnchor = () => {
+ getAnchor = (addAsAnnotation: boolean) => {
if (this.props.Document.annotationOn) {
return this.rootDoc;
}
@@ -1574,10 +1574,12 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const proto = Doc.GetProto(anchor);
proto[ViewSpecPrefix + '_viewType'] = this.layoutDoc._viewType;
proto.docFilters = ObjectField.MakeCopy(this.layoutDoc.docFilters as ObjectField) || new List<string>([]);
- if (Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), null) !== undefined) {
- Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), []).push(anchor);
- } else {
- this.dataDoc[this.props.fieldKey + '-annotations'] = new List<Doc>([anchor]);
+ if (addAsAnnotation) {
+ if (Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), null) !== undefined) {
+ Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), []).push(anchor);
+ } else {
+ this.dataDoc[this.props.fieldKey + '-annotations'] = new List<Doc>([anchor]);
+ }
}
return anchor;
};
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index d95668c89..1d59d3356 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -136,7 +136,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
return { la1, la2, linkTime };
}
- getAnchor = () => {
+ getAnchor = (addAsAnnotation: boolean) => {
return (
CollectionStackedTimeline.createAnchor(
this.rootDoc,
@@ -144,7 +144,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
this.annotationKey,
'_timecodeToShow' /* audioStart */,
'_timecodeToHide' /* audioEnd */,
- this._ele?.currentTime || Cast(this.props.Document._currentTimecode, 'number', null) || (this.mediaState === media_state.Recording ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined)
+ this._ele?.currentTime || Cast(this.props.Document._currentTimecode, 'number', null) || (this.mediaState === media_state.Recording ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined),
+ undefined,
+ undefined,
+ addAsAnnotation
) || this.rootDoc
);
};
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 6f3152981..a39e0f65f 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -135,7 +135,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
DocumentLinksButton.AnnotationId = undefined;
} else if (DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document) {
const sourceDoc = DocumentLinksButton.StartLink;
- const targetDoc = this.props.View.ComponentView?.getAnchor?.() || this.props.View.Document;
+ const targetDoc = this.props.View.ComponentView?.getAnchor?.(true) || this.props.View.Document;
const linkDoc = DocUtils.MakeLink({ doc: sourceDoc }, { doc: targetDoc }, 'links'); //why is long drag here when this is used for completing links by clicking?
LinkManager.currentLink = linkDoc;
@@ -183,8 +183,8 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
DocumentLinksButton.AnnotationUri = undefined;
//!this.props.StartLink
} else if (startLink !== endLink) {
- endLink = endLinkView?.docView?._componentView?.getAnchor?.() || endLink;
- startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.() || startLink;
+ endLink = endLinkView?.docView?._componentView?.getAnchor?.(true) || endLink;
+ startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.(true) || startLink;
const linkDoc = DocUtils.MakeLink({ doc: startLink }, { doc: endLink }, DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined, undefined, undefined, true);
LinkManager.currentLink = linkDoc;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 1df46488b..054d01d8e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -121,7 +121,7 @@ export type DocFocusFunc = (doc: Doc, options: DocFocusOptions) => void;
export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => any;
export interface DocComponentView {
updateIcon?: () => void; // updates the icon representation of the document
- getAnchor?: () => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box)
+ getAnchor?: (addAsAnnotation: boolean) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box)
scrollFocus?: (doc: Doc, options: DocFocusOptions) => Opt<number>; // returns the duration of the focus
brushView?: (view: { width: number; height: number; panX: number; panY: number }) => void;
setViewSpec?: (anchor: Doc, preview: boolean) => void; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document
@@ -783,9 +783,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
@undoBatch
@action
- toggleFollowLink = (location: Opt<string>, zoom?: boolean, setPushpin?: boolean): void => {
+ toggleFollowLink = (location: Opt<string>, zoom?: boolean, setTargetToggle?: boolean): void => {
this.Document.ignoreClick = false;
- if (setPushpin) {
+ if (setTargetToggle) {
this.Document.followLinkToggle = !this.Document.followLinkToggle;
this.Document._isLinkButton = this.Document.followLinkToggle || this.Document._isLinkButton;
} else {
@@ -854,7 +854,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
de.complete.annoDragData.dropDocument = de.complete.annoDragData.dropDocCreator(undefined);
}
if (de.complete.annoDragData || this.rootDoc !== linkdrag.linkSourceDoc.context) {
- const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.() ?? this.props.Document;
+ const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.props.Document;
de.complete.linkDocument = DocUtils.MakeLink({ doc: linkdrag.linkSourceDoc }, { doc: dropDoc }, undefined, undefined, undefined, undefined, [de.x, de.y - 50]);
}
}
@@ -979,7 +979,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
onClicks.push({ description: this.Document.isLinkButton ? 'Remove Follow Behavior' : 'Follow Link in Place', event: () => this.toggleFollowLink('inPlace', false, false), icon: 'link' });
!this.Document.isLinkButton && onClicks.push({ description: 'Follow Link on Right', event: () => this.toggleFollowLink('add:right', false, false), icon: 'link' });
onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(undefined, false, false), icon: 'link' });
- onClicks.push({ description: (this.Document.followLinkToggle ? 'Remove' : 'Make') + ' Pushpin', event: () => this.toggleFollowLink(undefined, false, true), icon: 'map-pin' });
+ onClicks.push({ description: (this.Document.followLinkToggle ? 'Remove' : 'Make') + ' Target Visibility Toggle', event: () => this.toggleFollowLink(undefined, false, true), icon: 'map-pin' });
onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' });
!existingOnClick && cm.addItem({ description: 'OnClick...', addDivider: true, noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
} else if (DocListCast(this.Document.links).length) {
@@ -1091,7 +1091,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin);
onClickFunc = () => this.onClickHandler;
setHeight = (height: number) => (this.layoutDoc._height = height);
- setContentView = action((view: { getAnchor?: () => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view));
+ setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view));
isContentActive = (outsideReaction?: boolean) => {
return this.props.isContentActive() === false
? false
@@ -1264,7 +1264,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
playAnnotation = () => {
const self = this;
const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '-audioAnnotations'], listSpec(AudioField), null);
- const anno = audioAnnos.lastElement();
+ const anno = audioAnnos?.lastElement();
if (anno instanceof AudioField && this.audioAnnoState === 'stopped') {
new Howl({
src: [anno.url.href],
diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx
index 24562ccbd..5c0005dae 100644
--- a/src/client/views/nodes/FunctionPlotBox.tsx
+++ b/src/client/views/nodes/FunctionPlotBox.tsx
@@ -12,7 +12,7 @@ import { TraceMobx } from '../../../fields/util';
import { Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
import { undoBatch } from '../../util/UndoManager';
-import { ViewBoxBaseComponent } from '../DocComponent';
+import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { DocFocusOptions } from './DocumentView';
import { FieldView, FieldViewProps } from './FieldView';
@@ -22,7 +22,7 @@ type EquationDocument = makeInterface<[typeof EquationSchema, typeof documentSch
const EquationDocument = makeInterface(EquationSchema, documentSchema);
@observer
-export class FunctionPlotBox extends ViewBoxBaseComponent<FieldViewProps>() {
+export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(FunctionPlotBox, fieldKey);
}
@@ -41,10 +41,11 @@ export class FunctionPlotBox extends ViewBoxBaseComponent<FieldViewProps>() {
() => this.createGraph()
);
}
- getAnchor = () => {
+ getAnchor = (addAsAnnotation: boolean) => {
const anchor = Docs.Create.TextanchorDocument({ annotationOn: this.rootDoc });
anchor.xRange = new List<number>(Array.from(this._plot.options.xAxis.domain));
anchor.yRange = new List<number>(Array.from(this._plot.options.yAxis.domain));
+ if (addAsAnnotation) this.addDocument(anchor);
return anchor;
};
@action
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index ac953d13b..e2ecca0b6 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -52,7 +52,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
private _dropDisposer?: DragManager.DragDropDisposer;
private _disposers: { [name: string]: IReactionDisposer } = {};
- private _getAnchor: (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => Opt<Doc> = () => undefined;
+ private _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined;
@observable _curSuffix = '';
@observable _uploadIcon = uploadIcons.idle;
@@ -86,13 +86,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
: undefined;
}; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document
- getAnchor = () => {
+ getAnchor = (addAsAnnotation: boolean) => {
const anchor =
- this._getAnchor?.(this._savedAnnotations) ?? // use marquee anchor, otherwise, save zoom/pan as anchor
+ this._getAnchor?.(this._savedAnnotations, false) ?? // use marquee anchor, otherwise, save zoom/pan as anchor
Docs.Create.ImageanchorDocument({ presTransition: 1000, unrendered: true, annotationOn: this.rootDoc });
if (anchor) {
PresBox.pinDocView(anchor, { pinData: { pannable: true, dataview: true, dataannos: true } }, this.rootDoc);
- this.addDocument(anchor);
+ addAsAnnotation && this.addDocument(anchor);
return anchor;
}
return this.rootDoc;
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 10897b48f..a2143f629 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -36,9 +36,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
this._timeout && clearTimeout(this._timeout);
}
- getAnchor = () => {
- return this.rootDoc;
- };
+ getAnchor = (addAsAnnotation: boolean) => this.rootDoc;
getTitle() {
return this.rootDoc['title-custom'] ? StrCast(this.rootDoc.title) : this.props.label ? this.props.label : typeof this.rootDoc[this.fieldKey] === 'string' ? StrCast(this.rootDoc[this.fieldKey]) : StrCast(this.rootDoc.title);
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 232c3459e..7eb42994b 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -113,7 +113,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
this._targetDoc = /*linkTarget?.type === DocumentType.MARKER &&*/ linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget;
}
this._toolTipText = '';
- if (LinkDocPreview.LinkInfo?.noPreview || this._markerTargetDoc?.type === DocumentType.PRES) this.followLink();
+ if (LinkDocPreview.LinkInfo?.noPreview || this._linkSrc?.followLinkToggle || this._markerTargetDoc?.type === DocumentType.PRES) this.followLink();
}
})
);
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index c8d5b0154..95cb49037 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -522,10 +522,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
);
}
- getAnchor = () => {
- const anchor = AnchorMenu.Instance?.GetAnchor(this._savedAnnotations) ?? this.rootDoc;
- return anchor;
- };
+ getAnchor = (addAsAnnotation: boolean) => AnchorMenu.Instance?.GetAnchor(this._savedAnnotations, addAsAnnotation) ?? this.rootDoc;
/**
* render contents in allMapMarkers (e.g. images with exifData) into google maps as map marker
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index e22ee5021..71ef9bc84 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -212,7 +212,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
PresBox.restoreTargetDocView(this.props.DocumentView?.(), {}, doc, options.zoomTime ?? 500, { pannable: doc.presPinData ? true : false });
return this._pdfViewer?.scrollFocus(doc, NumCast(doc.presPinViewScroll, NumCast(doc.y)), options) ?? (didToggle ? 1 : undefined);
};
- getAnchor = () => {
+ getAnchor = (addAsAnnotation: boolean) => {
let ele: Opt<HTMLDivElement> = undefined;
if (this._pdfViewer?.selectionContent()) {
ele = document.createElement('div');
@@ -226,10 +226,12 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
PresBox.pinDocView(anchor, { pinData: { scrollable: true, pannable: true } }, this.rootDoc);
return anchor;
};
- const anchor = this._pdfViewer?._getAnchor(this._pdfViewer.savedAnnotations()) ?? docAnchor();
+ const anchor = this._pdfViewer?._getAnchor(this._pdfViewer.savedAnnotations(), false) ?? docAnchor();
anchor.text = ele?.textContent ?? '';
anchor.textHtml = ele?.innerHTML;
- this.addDocument(anchor);
+ if (addAsAnnotation) {
+ this.addDocument(anchor);
+ }
return anchor;
};
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 76a24d831..f94996c66 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -128,9 +128,9 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
this.setupDictation();
}
}
- getAnchor = () => {
+ getAnchor = (addAsAnnotation: boolean) => {
const startTime = Cast(this.layoutDoc._currentTimecode, 'number', null) || (this._videoRec ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined);
- return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, '_timecodeToShow', '_timecodeToHide', startTime, startTime === undefined ? undefined : startTime + 3) || this.rootDoc;
+ return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, '_timecodeToShow', '_timecodeToHide', startTime, startTime === undefined ? undefined : startTime + 3, undefined, addAsAnnotation) || this.rootDoc;
};
videoLoad = () => {
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index a8f78edd5..1dfa55c64 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -385,15 +385,18 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
Doc.SetNativeWidth(Doc.GetProto(imageSummary), Doc.NativeWidth(this.layoutDoc));
Doc.SetNativeHeight(Doc.GetProto(imageSummary), Doc.NativeHeight(this.layoutDoc));
this.props.addDocument?.(imageSummary);
- const link = DocUtils.MakeLink({ doc: imageSummary }, { doc: this.getAnchor() }, 'video snapshot');
+ const link = DocUtils.MakeLink({ doc: imageSummary }, { doc: this.getAnchor(true) }, 'video snapshot');
link && (Doc.GetProto(link.anchor2 as Doc).timecodeToHide = NumCast((link.anchor2 as Doc).timecodeToShow) + 3);
setTimeout(() => downX !== undefined && downY !== undefined && DocumentManager.Instance.getFirstDocumentView(imageSummary)?.startDragging(downX, downY, 'move', true));
};
- getAnchor = () => {
+ getAnchor = (addAsAnnotation: boolean) => {
const timecode = Cast(this.layoutDoc._currentTimecode, 'number', null);
- const marquee = AnchorMenu.Instance.GetAnchor?.();
- return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, '_timecodeToShow' /* videoStart */, '_timecodeToHide' /* videoEnd */, timecode ? timecode : undefined, undefined, marquee) || this.rootDoc;
+ const marquee = AnchorMenu.Instance.GetAnchor?.(undefined, addAsAnnotation);
+ return (
+ CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, '_timecodeToShow' /* videoStart */, '_timecodeToHide' /* videoEnd */, timecode ? timecode : undefined, undefined, marquee, addAsAnnotation) ||
+ this.rootDoc
+ );
};
// sets video info on load
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 8be4884ce..acf4fe4b0 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -307,7 +307,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
return undefined;
};
- getAnchor = () => {
+ getAnchor = (addAsAnnotation: boolean) => {
let ele: Opt<HTMLDivElement> = undefined;
try {
const contents = this._iframe?.contentWindow?.getSelection()?.getRangeAt(0).cloneContents();
@@ -317,7 +317,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
} catch (e) {}
const anchor =
- this._getAnchor(this._savedAnnotations) ??
+ this._getAnchor(this._savedAnnotations, false) ??
Docs.Create.WebanchorDocument(this._url, {
title: StrCast(this.rootDoc.title + ' ' + this.layoutDoc._scrollTop),
y: NumCast(this.layoutDoc._scrollTop),
@@ -325,7 +325,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
});
anchor.text = ele?.textContent ?? '';
anchor.textHtml = ele?.innerHTML;
- this.addDocumentWrapper(anchor);
+ addAsAnnotation && this.addDocumentWrapper(anchor);
return anchor;
};
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 62e215521..deb1d68a7 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -231,7 +231,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
}
- getAnchor = () => this.makeLinkAnchor(undefined, 'add:right', undefined, 'Anchored Selection', false);
+ getAnchor = (addAsAnnotation: boolean) => this.makeLinkAnchor(undefined, OpenWhere.addRight, undefined, 'Anchored Selection', false, addAsAnnotation);
@action
setupAnchorMenu = () => {
@@ -239,23 +239,25 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
AnchorMenu.Instance.OnClick = (e: PointerEvent) => {
!this.layoutDoc.showSidebar && this.toggleSidebar();
- setTimeout(() => this._sidebarRef.current?.anchorMenuClick(this.makeLinkAnchor(undefined, 'add:right', undefined, 'Anchored Selection', true))); // give time for sidebarRef to be created
+ setTimeout(() => this._sidebarRef.current?.anchorMenuClick(this.makeLinkAnchor(undefined, OpenWhere.addRight, undefined, 'Anchored Selection', true))); // give time for sidebarRef to be created
};
AnchorMenu.Instance.OnAudio = (e: PointerEvent) => {
!this.layoutDoc.showSidebar && this.toggleSidebar();
- const anchor = this.getAnchor();
- const target = this._sidebarRef.current?.anchorMenuClick(anchor);
- if (target) {
- anchor.followLinkAudio = true;
- DocumentViewInternal.recordAudioAnnotation(Doc.GetProto(target), Doc.LayoutFieldKey(target));
- target.title = ComputedField.MakeFunction(`self["text-audioAnnotations-text"].lastElement()`);
- }
+ const anchor = this.makeLinkAnchor(undefined, OpenWhere.addRight, undefined, 'Anchored Selection', true, true);
+ setTimeout(() => {
+ const target = this._sidebarRef.current?.anchorMenuClick(anchor);
+ if (target) {
+ anchor.followLinkAudio = true;
+ DocumentViewInternal.recordAudioAnnotation(Doc.GetProto(target), Doc.LayoutFieldKey(target));
+ target.title = ComputedField.MakeFunction(`self["text-audioAnnotations-text"].lastElement()`);
+ }
+ });
};
AnchorMenu.Instance.Highlight = action((color: string, isLinkButton: boolean) => {
this._editorView?.state && RichTextMenu.Instance.setHighlight(color, this._editorView, this._editorView?.dispatch);
return undefined;
});
- AnchorMenu.Instance.onMakeAnchor = this.getAnchor;
+ AnchorMenu.Instance.onMakeAnchor = () => this.getAnchor(true);
AnchorMenu.Instance.StartCropDrag = unimplementedFunction;
/**
* This function is used by the PDFmenu to create an anchor highlight and a new linked text annotation.
@@ -270,7 +272,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return target;
};
- DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.docViewPath().lastElement(), this.getAnchor, targetCreator), e.pageX, e.pageY);
+ DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.docViewPath().lastElement(), () => this.getAnchor(true), targetCreator), e.pageX, e.pageY);
});
const coordsB = this._editorView!.coordsAtPos(this._editorView!.state.selection.to);
this.props.isSelected(true) && AnchorMenu.Instance.jumpTo(coordsB.left, coordsB.bottom);
@@ -518,7 +520,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
@undoBatch
@action
drop = (e: Event, de: DragManager.DropEvent) => {
- if (de.complete.annoDragData) de.complete.annoDragData.dropDocCreator = this.getAnchor;
+ if (de.complete.annoDragData) de.complete.annoDragData.dropDocCreator = () => this.getAnchor(true);
const dragData = de.complete.docDragData;
if (dragData) {
const draggedDoc = dragData.draggedDocuments.length && dragData.draggedDocuments[0];
@@ -689,9 +691,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
pinToPres = (anchor: Doc) => this.props.pinToPres(anchor, {});
@undoBatch
- makePushpin = (anchor: Doc) => (anchor.followLinkToggle = !anchor.followLinkToggle);
+ makeTargetToggle = (anchor: Doc) => (anchor.followLinkToggle = !anchor.followLinkToggle);
- isPushpin = (anchor: Doc) => BoolCast(anchor.followLinkToggle);
+ isTargetToggler = (anchor: Doc) => BoolCast(anchor.followLinkToggle);
specificContextMenu = (e: React.MouseEvent): void => {
const cm = ContextMenu.Instance;
@@ -714,8 +716,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
AnchorMenu.Instance.Delete = () => this.deleteAnnotation(anchor as Doc);
AnchorMenu.Instance.Pinned = false;
AnchorMenu.Instance.PinToPres = () => this.pinToPres(anchor as Doc);
- AnchorMenu.Instance.MakePushpin = () => this.makePushpin(anchor as Doc);
- AnchorMenu.Instance.IsPushpin = () => this.isPushpin(anchor as Doc);
+ AnchorMenu.Instance.MakeTargetToggle = () => this.makeTargetToggle(anchor as Doc);
+ AnchorMenu.Instance.IsTargetToggler = () => this.isTargetToggler(anchor as Doc);
AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true);
})
);
@@ -891,7 +893,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
};
// TODO: nda -- Look at how link anchors are added
- makeLinkAnchor(anchorDoc?: Doc, location?: string, targetHref?: string, title?: string, noPreview?: boolean) {
+ makeLinkAnchor(anchorDoc?: Doc, location?: string, targetHref?: string, title?: string, noPreview?: boolean, addAsAnnotation?: boolean) {
const state = this._editorView?.state;
if (state) {
let selectedText = '';
@@ -901,7 +903,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
if (sel.from !== sel.to) {
const anchor = anchorDoc ?? Docs.Create.TextanchorDocument({ title: '#' + this._editorView?.state.doc.textBetween(sel.from, sel.to), annotationOn: this.dataDoc, unrendered: true });
const href = targetHref ?? Doc.localServerPath(anchor);
- if (anchor !== anchorDoc) this.addDocument(anchor);
+ if (anchor !== anchorDoc && addAsAnnotation) this.addDocument(anchor);
tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => {
if (node.firstChild === null && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
const allAnchors = [{ href, title, anchorId: anchor[Id] }];
@@ -1476,7 +1478,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
let target = e.target as any; // hrefs are stored on the dataset of the <a> node that wraps the hyerlink <span>
while (target && !target.dataset?.targethrefs) target = target.parentElement;
FormattedTextBoxComment.update(this, editor, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc, target?.dataset.nopreview === 'true');
- if (target) return;
}
if (e.button === 0 && this.props.isSelected(true) && !e.altKey) {
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index e3c67ad2e..5675776fb 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -259,7 +259,7 @@ export class RichTextRules {
this.TextBox.EditorView?.dispatch(rstate.tr.setSelection(new TextSelection(rstate.doc.resolve(start), rstate.doc.resolve(end - 3))));
}
const target = (docx instanceof Doc && docx) || Docs.Create.FreeformDocument([], { title: docid, _width: 500, _height: 500 }, docid);
- DocUtils.MakeLink({ doc: this.TextBox.getAnchor() }, { doc: target }, 'portal to:portal from', undefined);
+ DocUtils.MakeLink({ doc: this.TextBox.getAnchor(true) }, { doc: target }, 'portal to:portal from', undefined);
const fstate = this.TextBox.EditorView?.state;
if (fstate && selection) {
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 855a7f171..226fd8d7d 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -104,7 +104,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
return NumCast(this.rootDoc._itemIndex);
}
@computed get activeItem() {
- return Cast(this.childDocs[NumCast(this.rootDoc._itemIndex)], Doc, null);
+ return DocCast(this.childDocs[NumCast(this.rootDoc._itemIndex)]);
}
@computed get targetDoc() {
return Cast(this.activeItem?.presentationTargetDoc, Doc, null);
@@ -452,7 +452,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
pinDoc.presWidth = NumCast(targetDoc.width);
pinDoc.presHeight = NumCast(targetDoc.height);
}
- if (pinProps.pinAudioPlay) pinDoc.followLinkAudio = true;
+ if (pinProps.pinAudioPlay) pinDoc.presPlayAudio = true;
if (pinProps.pinData) {
pinDoc.presPinData =
pinProps.pinData.scrollable ||
@@ -577,7 +577,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
noSelect: true,
originatingDoc: activeItem,
easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any,
- zoomTextSelections: true,
+ zoomTextSelections: BoolCast(activeItem.presZoomText),
+ playAudio: BoolCast(activeItem.presPlayAudio),
};
if (activeItem.presentationTargetDoc instanceof Doc) activeItem.presentationTargetDoc[AnimationSym] = undefined;
var containerDocContext = srcContext ? [srcContext] : [];
@@ -1416,7 +1417,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
Effects
<div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
<div className="presBox-subheading">Play Audio Annotation</div>
- <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.followLinkAudio = !BoolCast(activeItem.followLinkAudio))} checked={BoolCast(activeItem.followLinkAudio)} />
+ <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} checked={BoolCast(activeItem.presPlayAudio)} />
+ </div>
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Zoom Text Selections</div>
+ <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.presZoomText = !BoolCast(activeItem.presZoomText))} checked={BoolCast(activeItem.presZoomText)} />
</div>
<div
className="presBox-dropdown"
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 265328036..2fb795b06 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -11,6 +11,7 @@ import { AntimodeMenu, AntimodeMenuProps } from '../AntimodeMenu';
import { LinkPopup } from '../linking/LinkPopup';
import { ButtonDropdown } from '../nodes/formattedText/RichTextMenu';
import './AnchorMenu.scss';
+import { truncate } from 'lodash';
@observer
export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -52,13 +53,13 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
public OnAudio: (e: PointerEvent) => void = unimplementedFunction;
public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
- public Highlight: (color: string, isPushpin: boolean) => Opt<Doc> = (color: string, isPushpin: boolean) => undefined;
- public GetAnchor: (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => Opt<Doc> = () => undefined;
+ public Highlight: (color: string, isTargetToggler: boolean) => Opt<Doc> = (color: string, isTargetToggler: boolean) => undefined;
+ public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => undefined;
public Delete: () => void = unimplementedFunction;
public AddTag: (key: string, value: string) => boolean = returnFalse;
public PinToPres: () => void = unimplementedFunction;
- public MakePushpin: () => void = unimplementedFunction;
- public IsPushpin: () => boolean = returnFalse;
+ public MakeTargetToggle: () => void = unimplementedFunction;
+ public IsTargetToggler: () => boolean = returnFalse;
public get Active() {
return this._left > 0;
}
@@ -238,8 +239,8 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
<FontAwesomeIcon icon="map-pin" size="lg" />
</button>
</Tooltip>,
- <Tooltip key="pushpin" title={<div className="dash-tooltip">{'toggle pushpin behavior'}</div>}>
- <button className="antimodeMenu-button" style={{ color: this.IsPushpin() ? 'black' : 'white', backgroundColor: this.IsPushpin() ? 'white' : 'black' }} onPointerDown={this.MakePushpin}>
+ <Tooltip key="toggle" title={<div className="dash-tooltip">{'make target visibility toggle on click'}</div>}>
+ <button className="antimodeMenu-button" style={{ color: this.IsTargetToggler() ? 'black' : 'white', backgroundColor: this.IsTargetToggler() ? 'white' : 'black' }} onPointerDown={this.MakeTargetToggle}>
<FontAwesomeIcon icon="thumbtack" size="lg" />
</button>
</Tooltip>,
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 7069ff399..d8e44ae9d 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -55,9 +55,9 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
pinToPres = () => this.props.pinToPres(this.annoTextRegion, {});
@undoBatch
- makePushpin = () => (this.annoTextRegion.followLinkToggle = !this.annoTextRegion.followLinkToggle);
+ makeTargretToggle = () => (this.annoTextRegion.followLinkToggle = !this.annoTextRegion.followLinkToggle);
- isPushpin = () => BoolCast(this.annoTextRegion.followLinkToggle);
+ isTargetToggler = () => BoolCast(this.annoTextRegion.followLinkToggle);
@action
onPointerDown = (e: React.PointerEvent) => {
@@ -67,8 +67,8 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
AnchorMenu.Instance.Pinned = false;
AnchorMenu.Instance.AddTag = this.addTag.bind(this);
AnchorMenu.Instance.PinToPres = this.pinToPres;
- AnchorMenu.Instance.MakePushpin = this.makePushpin;
- AnchorMenu.Instance.IsPushpin = this.isPushpin;
+ AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle;
+ AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler;
AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true);
e.stopPropagation();
} else if (e.button === 0) {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index f95d5ac2e..b0b7816b8 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -135,7 +135,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
copy = (e: ClipboardEvent) => {
if (this.props.isContentActive() && e.clipboardData) {
e.clipboardData.setData('text/plain', this._selectionText);
- const anchor = this._getAnchor();
+ const anchor = this._getAnchor(undefined, false);
if (anchor) {
anchor.textCopied = true;
e.clipboardData.setData('dash/pdfAnchor', anchor[Id]);
@@ -317,7 +317,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
this._ignoreScroll = false;
if (this._scrollTimer) clearTimeout(this._scrollTimer); // wait until a scrolling pause, then create an anchor to audio
this._scrollTimer = setTimeout(() => {
- DocUtils.MakeLinkToActiveAudio(() => this.props.DocumentView?.().ComponentView?.getAnchor!()!, false);
+ DocUtils.MakeLinkToActiveAudio(() => this.props.DocumentView?.().ComponentView?.getAnchor!(true)!, false);
this._scrollTimer = undefined;
}, 200);
}