From 2a1d6793d33d9c72295d23965aefd23f2004bbcb Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 8 Aug 2022 11:48:27 -0400
Subject: cleaning up link ui.   linkPreviews (not from linkMenu) have an edit
 button.  link lines work when in lightboxview.

---
 src/client/views/linking/LinkEditor.tsx | 141 ++++++++++++++++++--------------
 1 file changed, 80 insertions(+), 61 deletions(-)

(limited to 'src/client/views/linking/LinkEditor.tsx')

diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index ba301962b..d23d38854 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -9,11 +9,12 @@ import { undoBatch } from '../../util/UndoManager';
 import './LinkEditor.scss';
 import { LinkRelationshipSearch } from './LinkRelationshipSearch';
 import React = require('react');
+import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils';
 
 interface LinkEditorProps {
     sourceDoc: Doc;
     linkDoc: Doc;
-    showLinks: () => void;
+    showLinks?: () => void;
     hideback?: boolean;
 }
 @observer
@@ -22,13 +23,6 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
     @observable relationship = StrCast(LinkManager.currentLink?.linkRelationship);
     @observable zoomFollow = StrCast(this.props.sourceDoc.followLinkZoom);
     @observable openDropdown: boolean = false;
-    @observable showInfo: boolean = false;
-    @computed get infoIcon() {
-        if (this.showInfo) {
-            return 'chevron-up';
-        }
-        return 'chevron-down';
-    }
     @observable private buttonColor: string = '';
     @observable private relationshipButtonColor: string = '';
     @observable private relationshipSearchVisibility: string = 'none';
@@ -36,12 +30,6 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
 
     //@observable description = this.props.linkDoc.description ? StrCast(this.props.linkDoc.description) : "DESCRIPTION";
 
-    @undoBatch
-    deleteLink = (): void => {
-        LinkManager.Instance.deleteLink(this.props.linkDoc);
-        this.props.showLinks();
-    };
-
     @undoBatch
     setRelationshipValue = action((value: string) => {
         if (LinkManager.currentLink) {
@@ -173,7 +161,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
         //NOTE: confusingly, the classnames for the following relationship JSX elements are the same as the for the description elements for shared CSS
         return (
             <div className="linkEditor-description">
-                <div className="linkEditor-description-label">Link Relationship:</div>
+                <div className="linkEditor-description-label">Relationship:</div>
                 <div className="linkEditor-description-input">
                     <div className="linkEditor-description-editing">
                         <input
@@ -214,7 +202,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
     get editDescription() {
         return (
             <div className="linkEditor-description">
-                <div className="linkEditor-description-label">Link Description:</div>
+                <div className="linkEditor-description-label">Description:</div>
                 <div className="linkEditor-description-input">
                     <div className="linkEditor-description-editing">
                         <input style={{ width: '100%' }} autoComplete={'off'} id="input" value={this.description} placeholder={'Enter link description'} onKeyDown={this.onDescriptionKey} onChange={this.handleDescriptionChange}></input>
@@ -284,68 +272,99 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
         );
     }
 
-    @action
-    changeInfo = () => {
-        this.showInfo = !this.showInfo;
+    autoMove = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => (this.props.linkDoc.linkAutoMove = !this.props.linkDoc.linkAutoMove))));
+    };
+
+    showAnchor = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => (this.props.linkDoc.hidden = !this.props.linkDoc.hidden))));
+    };
+
+    showLink = (e: React.PointerEvent) => {
+        setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => (this.props.linkDoc.linkDisplay = !this.props.linkDoc.linkDisplay))));
+    };
+
+    deleteLink = (e: React.PointerEvent): void => {
+        setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => LinkManager.Instance.deleteLink(this.props.linkDoc))));
     };
 
     render() {
         const destination = LinkManager.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
 
         return !destination ? null : (
-            <div className="linkEditor" tabIndex={0} onKeyDown={e => e.stopPropagation()}>
+            <div className="linkEditor" tabIndex={0} onKeyDown={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                 <div className="linkEditor-info">
-                    <Tooltip
-                        title={
-                            <>
-                                <div className="dash-tooltip">Return to link menu</div>
-                            </>
-                        }
-                        placement="top">
-                        <button className="linkEditor-button-back" style={{ display: this.props.hideback ? 'none' : '' }} onClick={this.props.showLinks}>
-                            <FontAwesomeIcon icon="arrow-left" size="sm" />{' '}
-                        </button>
-                    </Tooltip>
+                    {!this.props.showLinks ? null : (
+                        <Tooltip title={<div className="dash-tooltip">Return to link menu</div>} placement="top">
+                            <button className="linkEditor-button-back" style={{ display: this.props.hideback ? 'none' : '' }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.props.showLinks?.())}>
+                                <FontAwesomeIcon icon="arrow-left" size="sm" />{' '}
+                            </button>
+                        </Tooltip>
+                    )}
                     <p className="linkEditor-linkedTo">
                         Editing Link to: <b>{StrCast(destination.proto?.title, StrCast(destination.title, 'untitled'))}</b>
                     </p>
-                    <Tooltip
-                        title={
-                            <>
-                                <div className="dash-tooltip">Show more link information</div>
-                            </>
-                        }
-                        placement="top">
-                        <div className="linkEditor-downArrow">
-                            <FontAwesomeIcon className="button" icon={this.infoIcon} size="lg" onPointerDown={this.changeInfo} />
+                    <Tooltip title={<div className="dash-tooltip">Delete Link</div>}>
+                        <div className="linkEditor-deleteBtn" onPointerDown={this.deleteLink} onClick={e => e.stopPropagation()}>
+                            <FontAwesomeIcon className="fa-icon" icon="trash" size="sm" />
                         </div>
                     </Tooltip>
                 </div>
-                {this.showInfo ? (
-                    <div className="linkEditor-moreInfo">
-                        <div>
-                            {this.props.linkDoc.author ? (
-                                <div>
-                                    {' '}
-                                    <b>Author:</b> {StrCast(this.props.linkDoc.author)}
-                                </div>
-                            ) : null}
-                        </div>
-                        <div>
-                            {this.props.linkDoc.creationDate ? (
-                                <div>
-                                    {' '}
-                                    <b>Creation Date:</b>
-                                    {DateCast(this.props.linkDoc.creationDate).toString()}
-                                </div>
-                            ) : null}
-                        </div>
-                    </div>
-                ) : null}
+                <div className="linkEditor-moreInfo">
+                    {this.props.linkDoc.author ? (
+                        <>
+                            {' '}
+                            <b>Author:</b> {StrCast(this.props.linkDoc.author)}
+                        </>
+                    ) : null}
+                    {this.props.linkDoc.creationDate ? (
+                        <>
+                            {' '}
+                            <b>Creation Date:</b>
+                            {DateCast(this.props.linkDoc.creationDate).toString()}
+                        </>
+                    ) : null}
+                </div>
 
                 {this.editDescription}
                 {this.editRelationship}
                 {this.editZoomFollow}
+                <div className="linkEditor-description">
+                    Show Anchor:
+                    <Tooltip title={<div className="dash-tooltip">{this.props.linkDoc.hidden ? 'Show Link Anchor' : 'Hide Link Anchor'}</div>}>
+                        <div
+                            className="linkEditor-button"
+                            style={{ background: this.props.linkDoc.hidden ? 'gray' : '#4476f7' /* $medium-blue                                       */ }}
+                            onPointerDown={this.showAnchor}
+                            onClick={e => e.stopPropagation()}>
+                            <FontAwesomeIcon className="fa-icon" icon={'eye'} size="sm" />
+                        </div>
+                    </Tooltip>
+                </div>
+                <div className="linkEditor-description">
+                    Show Link Line:
+                    <Tooltip title={<div className="dash-tooltip">{this.props.linkDoc.linkDisplay ? 'Hide Link Line' : 'Show Link Line'}</div>}>
+                        <div
+                            className="linkEditor-button"
+                            style={{ background: this.props.linkDoc.hidden ? 'gray' : this.props.linkDoc.linkDisplay ? '#4476f7' /* $medium-blue */ : '' }}
+                            onPointerDown={this.showLink}
+                            onClick={e => e.stopPropagation()}>
+                            <FontAwesomeIcon className="fa-icon" icon={'project-diagram'} size="sm" />
+                        </div>
+                    </Tooltip>
+                </div>
+                <div className="linkEditor-description">
+                    Freeze Anchor:
+                    <Tooltip title={<div className="dash-tooltip">{this.props.linkDoc.linkAutoMove ? 'Click to freeze link anchor position' : 'Click to auto move link anchor'}</div>}>
+                        <div
+                            className="linkEditor-button"
+                            style={{ background: this.props.linkDoc.hidden ? 'gray' : this.props.linkDoc.linkAutoMove ? '' : '#4476f7' /* $medium-blue */ }}
+                            onPointerDown={this.autoMove}
+                            onClick={e => e.stopPropagation()}>
+                            <FontAwesomeIcon className="fa-icon" icon={'play'} size="sm" />
+                        </div>
+                    </Tooltip>
+                </div>
                 {this.followingDropdown}
             </div>
         );
-- 
cgit v1.2.3-70-g09d2


From af0e9bcc4cea84b3f837847143ea8f0a281856df Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 9 Aug 2022 10:37:44 -0400
Subject: added audio annotation play option for following links

---
 src/client/util/DocumentManager.ts      | 17 +++++++++++++++++
 src/client/views/linking/LinkEditor.tsx | 32 +++++++++++++++++++++++++++-----
 2 files changed, 44 insertions(+), 5 deletions(-)

(limited to 'src/client/views/linking/LinkEditor.tsx')

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index d3ac2f03f..52b643c04 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -12,6 +12,9 @@ import { CollectionFreeFormView } from '../views/collections/collectionFreeForm'
 import { CollectionView } from '../views/collections/CollectionView';
 import { ScriptingGlobals } from './ScriptingGlobals';
 import { SelectionManager } from './SelectionManager';
+import { listSpec } from '../../fields/Schema';
+import { AudioField } from '../../fields/URLField';
+const { Howl } = require('howler');
 
 export class DocumentManager {
     //global holds all of the nodes (regardless of which collection they're in)
@@ -186,6 +189,20 @@ export class DocumentManager {
             } else {
                 finalTargetDoc.hidden && (finalTargetDoc.hidden = undefined);
                 !noSelect && docView?.select(false);
+                if (originatingDoc?.followLinkAudio) {
+                    const anno = Cast(finalTargetDoc[Doc.LayoutFieldKey(finalTargetDoc) + '-audioAnnotations'], listSpec(AudioField), null).lastElement();
+                    if (anno) {
+                        if (anno instanceof AudioField) {
+                            new Howl({
+                                src: [anno.url.href],
+                                format: ['mp3'],
+                                autoplay: true,
+                                loop: false,
+                                volume: 0.5,
+                            });
+                        }
+                    }
+                }
             }
             finished?.();
         };
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index d23d38854..1697062f4 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -3,7 +3,7 @@ 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 } from '../../../fields/Types';
+import { DateCast, StrCast, Cast, BoolCast } from '../../../fields/Types';
 import { LinkManager } from '../../util/LinkManager';
 import { undoBatch } from '../../util/UndoManager';
 import './LinkEditor.scss';
@@ -21,7 +21,8 @@ interface LinkEditorProps {
 export class LinkEditor extends React.Component<LinkEditorProps> {
     @observable description = Field.toString(LinkManager.currentLink?.description as any as Field);
     @observable relationship = StrCast(LinkManager.currentLink?.linkRelationship);
-    @observable zoomFollow = StrCast(this.props.sourceDoc.followLinkZoom);
+    @observable zoomFollow = BoolCast(this.props.sourceDoc.followLinkZoom);
+    @observable audioFollow = BoolCast(this.props.sourceDoc.followLinkAudio);
     @observable openDropdown: boolean = false;
     @observable private buttonColor: string = '';
     @observable private relationshipButtonColor: string = '';
@@ -147,8 +148,12 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
         this.relationship = e.target.value;
     };
     @action
-    handleZoomFollowChange = (e: React.ChangeEvent<HTMLInputElement>) => {
-        this.props.sourceDoc.followLinkZoom = e.target.checked;
+    handleZoomFollowChange = () => {
+        this.props.sourceDoc.followLinkZoom = !this.props.sourceDoc.followLinkZoom;
+    };
+    @action
+    handleAudioFollowChange = () => {
+        this.props.sourceDoc.followLinkAudio = !this.props.sourceDoc.followLinkAudio;
     };
     @action
     handleRelationshipSearchChange = (result: string) => {
@@ -191,7 +196,23 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
                 <div className="linkEditor-zoomFollow-label">Zoom To Link Target:</div>
                 <div className="linkEditor-zoomFollow-input">
                     <div className="linkEditor-zoomFollow-editing">
-                        <input style={{ width: '100%' }} type="checkbox" value={this.zoomFollow} onChange={this.handleZoomFollowChange} />
+                        <input type="checkbox" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, this.handleZoomFollowChange)} defaultChecked={this.zoomFollow} />
+                    </div>
+                </div>
+            </div>
+        );
+    }
+
+    @computed
+    get editAudioFollow() {
+        //NOTE: confusingly, the classnames for the following relationship JSX elements are the same as the for the description elements for shared CSS
+        console.log('AudioFollow:' + this.audioFollow);
+        return (
+            <div className="linkEditor-zoomFollow">
+                <div className="linkEditor-zoomFollow-label">Play Target Audio:</div>
+                <div className="linkEditor-zoomFollow-input">
+                    <div className="linkEditor-zoomFollow-editing">
+                        <input type="checkbox" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, this.handleAudioFollowChange)} defaultChecked={this.audioFollow} />
                     </div>
                 </div>
             </div>
@@ -329,6 +350,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
                 {this.editDescription}
                 {this.editRelationship}
                 {this.editZoomFollow}
+                {this.editAudioFollow}
                 <div className="linkEditor-description">
                     Show Anchor:
                     <Tooltip title={<div className="dash-tooltip">{this.props.linkDoc.hidden ? 'Show Link Anchor' : 'Hide Link Anchor'}</div>}>
-- 
cgit v1.2.3-70-g09d2

