aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/linking
diff options
context:
space:
mode:
authorbrynnchernosky <56202540+brynnchernosky@users.noreply.github.com>2023-01-19 14:33:22 -0500
committerbrynnchernosky <56202540+brynnchernosky@users.noreply.github.com>2023-01-19 14:33:22 -0500
commit0ef7050b0792ce183c7d5cda637cb79b7a92b704 (patch)
treed1dca8f09ddc2954c2ce88439172aeded672c0b6 /src/client/views/linking
parentceb338752aacc383c97a0e3a9b608365a1cf39b6 (diff)
parentd5f796b433d7e72130d4109a3775347ccb10c454 (diff)
Merge branch 'master' of github.com:brown-dash/Dash-Web into master
Diffstat (limited to 'src/client/views/linking')
-rw-r--r--src/client/views/linking/LinkEditor.scss334
-rw-r--r--src/client/views/linking/LinkEditor.tsx394
-rw-r--r--src/client/views/linking/LinkMenu.scss8
-rw-r--r--src/client/views/linking/LinkMenu.tsx50
-rw-r--r--src/client/views/linking/LinkMenuGroup.tsx71
-rw-r--r--src/client/views/linking/LinkMenuItem.scss30
-rw-r--r--src/client/views/linking/LinkMenuItem.tsx89
-rw-r--r--src/client/views/linking/LinkPopup.scss5
-rw-r--r--src/client/views/linking/LinkPopup.tsx13
9 files changed, 134 insertions, 860 deletions
diff --git a/src/client/views/linking/LinkEditor.scss b/src/client/views/linking/LinkEditor.scss
deleted file mode 100644
index b0ee4e46d..000000000
--- a/src/client/views/linking/LinkEditor.scss
+++ /dev/null
@@ -1,334 +0,0 @@
-@import '../global/globalCssVariables';
-
-.linkEditor {
- width: 100%;
- height: auto;
- font-size: 13px; // TODO
- user-select: none;
- max-width: 280px;
-}
-
-.linkEditor-button-back {
- //margin-bottom: 6px;
- border-radius: 10px;
- width: 18px;
- height: 18px;
- padding: 0;
-
- &:hover {
- cursor: pointer;
- }
-}
-
-.linkEditor-info {
- padding-top: 12px;
- padding-left: 5px;
- padding-bottom: 3px;
- //margin-bottom: 6px;
- display: flex;
- justify-content: space-between;
- color: black;
-
- .linkEditor-linkedTo {
- width: calc(100% - 46px);
- overflow: hidden;
- position: relative;
- text-overflow: ellipsis;
- white-space: pre;
-
- .linkEditor-downArrow {
- &:hover {
- cursor: pointer;
- }
- }
- }
-}
-
-.linkEditor-moreInfo {
- margin-left: 12px;
- padding-left: 13px;
- padding-right: 6.5px;
- padding-bottom: 4px;
- font-size: 9px;
- //font-style: italic;
- text-decoration-color: grey;
-
- .button {
- color: black;
-
- &:hover {
- cursor: pointer;
- }
- }
-}
-
-.linkEditor-zoomFollow {
- padding-left: 26px;
- padding-right: 6.5px;
- padding-bottom: 3.5px;
- display: flex;
-
- .linkEditor-zoomFollow-label {
- text-decoration-color: black;
- color: black;
- line-height: 1.7;
- }
-
- .linkEditor-zoomFollow-input {
- display: block;
- width: 20px;
- }
-}
-.linkEditor-deleteBtn {
- padding-left: 3px;
-}
-
-.linkEditor-description {
- padding-left: 26px;
- padding-bottom: 3.5px;
- display: flex;
-
- .linkEditor-description-label {
- text-decoration-color: black;
- color: black;
- }
-
- .linkEditor-description-input {
- display: flex;
-
- .linkEditor-description-editing {
- min-width: 85%;
- //border: 1px solid grey;
- //border-radius: 4px;
- padding-left: 2px;
- //margin-right: 4px;
- color: black;
- text-decoration-color: grey;
- }
-
- .linkEditor-description-add-button {
- display: inline;
- border-radius: 7px;
- font-size: 9px;
- background: black;
- height: 80%;
- color: white;
- padding: 3px;
- margin-left: 3px;
-
- &:hover {
- cursor: pointer;
- background: grey;
- }
- }
- }
-}
-
-.linkEditor-relationship-dropdown {
- position: absolute;
- width: 154px;
- max-height: 90px;
- overflow: auto;
- background: white;
-
- p {
- padding: 3px;
- cursor: pointer;
- border: 1px solid $medium-gray;
- }
-
- p:hover {
- background: $light-blue;
- }
-}
-
-.linkEditor-followingDropdown {
- padding-left: 26px;
- padding-right: 6.5px;
- padding-bottom: 15px;
- display: flex;
-
- &:hover {
- cursor: pointer;
- }
-
- .linkEditor-followingDropdown-label {
- color: black;
- padding-right: 3px;
- }
-
- .linkEditor-followingDropdown-dropdown {
- .linkEditor-followingDropdown-header {
- border: 1px solid grey;
- border-radius: 4px;
- //background-color: rgb(236, 236, 236);
- padding-left: 2px;
- padding-right: 2px;
- text-decoration-color: black;
- color: rgb(94, 94, 94);
-
- .linkEditor-followingDropdown-icon {
- float: right;
- color: black;
- }
- }
-
- .linkEditor-followingDropdown-optionsList {
- padding-left: 3px;
- padding-right: 3px;
-
- &:last-child {
- border-bottom: none;
- }
-
- .linkEditor-followingDropdown-option {
- border: 0.25px solid grey;
- //background-color: rgb(236, 236, 236);
- padding-left: 2px;
- padding-right: 2px;
- color: grey;
- text-decoration-color: grey;
- font-size: 9px;
- border-top: none;
-
- &:hover {
- background-color: rgb(187, 220, 231);
- }
- }
- }
- }
-}
-
-.linkEditor-button,
-.linkEditor-addbutton {
- width: 15%;
- border-radius: 7px;
- font-size: 9px;
- background: black;
- padding: 3px;
- height: 80%;
- color: white;
- text-align: center;
- margin: auto;
- margin-left: 3px;
- > svg {
- margin: auto;
- }
- &:disabled {
- background-color: gray;
- }
-}
-
-.linkEditor-addbutton {
- margin-left: 0px;
-}
-
-.linkEditor-groupsLabel {
- display: flex;
- justify-content: space-between;
-}
-
-.linkEditor-group {
- background-color: $light-gray;
- padding: 6px;
- margin: 3px 0;
- border-radius: 3px;
-
- .linkEditor-group-row {
- display: flex;
- margin-bottom: 3px;
- }
-
- .linkEditor-group-row-label {
- margin-right: 6px;
- display: inline-block;
- }
-
- .linkEditor-metadata-row {
- display: flex;
- justify-content: space-between;
- margin-bottom: 6px;
-
- .linkEditor-error {
- border-color: red;
- }
-
- input {
- width: calc(50% - 16px);
- height: 20px;
- }
-
- button {
- width: 20px;
- height: 20px;
- margin-left: 3px;
- padding: 0;
- font-size: 10px;
- }
- }
-}
-
-.linkEditor-dropdown {
- width: 100%;
- position: relative;
- z-index: 999;
-
- input {
- width: 100%;
- }
-
- .linkEditor-options-wrapper {
- width: 100%;
- position: absolute;
- top: 19px;
- left: 0;
- display: flex;
- flex-direction: column;
- }
-
- .linkEditor-option {
- background-color: $light-gray;
- border: 1px solid $medium-gray;
- border-top: 0;
- padding: 3px;
- cursor: pointer;
-
- &:hover {
- background-color: lightgray;
- }
-
- &.onDown {
- background-color: gray;
- }
- }
-}
-
-.linkEditor-typeButton {
- background-color: transparent;
- color: $dark-gray;
- height: 20px;
- padding: 0 3px;
- padding-bottom: 2px;
- text-align: left;
- text-transform: none;
- letter-spacing: normal;
- font-size: 12px;
- font-weight: bold;
- display: inline-block;
- width: calc(100% - 40px);
-
- &:hover {
- background-color: $white;
- }
-}
-
-.linkEditor-group-buttons {
- height: 20px;
- display: flex;
- justify-content: flex-end;
- margin-top: 5px;
-
- .linkEditor-button {
- margin-left: 3px;
- }
-}
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
deleted file mode 100644
index 1697062f4..000000000
--- a/src/client/views/linking/LinkEditor.tsx
+++ /dev/null
@@ -1,394 +0,0 @@
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-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 { 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';
-
-interface LinkEditorProps {
- sourceDoc: Doc;
- linkDoc: Doc;
- showLinks?: () => void;
- hideback?: boolean;
-}
-@observer
-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 = BoolCast(this.props.sourceDoc.followLinkZoom);
- @observable audioFollow = BoolCast(this.props.sourceDoc.followLinkAudio);
- @observable openDropdown: boolean = false;
- @observable private buttonColor: string = '';
- @observable private relationshipButtonColor: string = '';
- @observable private relationshipSearchVisibility: string = 'none';
- @observable private searchIsActive: boolean = false;
-
- //@observable description = this.props.linkDoc.description ? StrCast(this.props.linkDoc.description) : "DESCRIPTION";
-
- @undoBatch
- setRelationshipValue = action((value: string) => {
- if (LinkManager.currentLink) {
- const prevRelationship = LinkManager.currentLink.linkRelationship as string;
- LinkManager.currentLink.linkRelationship = value;
- Doc.GetProto(LinkManager.currentLink).linkRelationship = value;
- const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList);
- const linkRelationshipSizes = NumListCast(Doc.UserDoc().linkRelationshipSizes);
- const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
-
- // if the relationship does not exist in the list, add it and a corresponding unique randomly generated color
- if (!linkRelationshipList?.includes(value)) {
- linkRelationshipList.push(value);
- linkRelationshipSizes.push(1);
- const randColor = 'rgb(' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ')';
- linkColorList.push(randColor);
- // if the relationship is already in the list AND the new rel is different from the prev rel, update the rel sizes
- } else if (linkRelationshipList && value !== prevRelationship) {
- const index = linkRelationshipList.indexOf(value);
- //increment size of new relationship size
- if (index !== -1 && index < linkRelationshipSizes.length) {
- const pvalue = linkRelationshipSizes[index];
- linkRelationshipSizes[index] = pvalue === undefined || !Number.isFinite(pvalue) ? 1 : pvalue + 1;
- }
- //decrement the size of the previous relationship if it already exists (i.e. not default 'link' relationship upon link creation)
- if (linkRelationshipList.includes(prevRelationship)) {
- const pindex = linkRelationshipList.indexOf(prevRelationship);
- if (pindex !== -1 && pindex < linkRelationshipSizes.length) {
- const pvalue = linkRelationshipSizes[pindex];
- linkRelationshipSizes[pindex] = Math.max(0, pvalue === undefined || !Number.isFinite(pvalue) ? 1 : pvalue - 1);
- }
- }
- }
- this.relationshipButtonColor = 'rgb(62, 133, 55)';
- setTimeout(
- action(() => (this.relationshipButtonColor = '')),
- 750
- );
- return true;
- }
- });
-
- /**
- * returns list of strings with possible existing relationships that contain what is currently in the input field
- */
- @action
- getRelationshipResults = () => {
- const query = this.relationship; //current content in input box
- const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList);
- if (linkRelationshipList) {
- return linkRelationshipList.filter(rel => rel.includes(query));
- }
- };
-
- /**
- * toggles visibility of the relationship search results when the input field is focused on
- */
- @action
- toggleRelationshipResults = () => {
- this.relationshipSearchVisibility = this.relationshipSearchVisibility === 'none' ? 'block' : 'none';
- };
-
- @undoBatch
- setDescripValue = action((value: string) => {
- if (LinkManager.currentLink) {
- Doc.GetProto(LinkManager.currentLink).description = value;
- this.buttonColor = 'rgb(62, 133, 55)';
- setTimeout(
- action(() => (this.buttonColor = '')),
- 750
- );
- return true;
- }
- });
-
- onDescriptionKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
- if (e.key === 'Enter') {
- this.setDescripValue(this.description);
- document.getElementById('input')?.blur();
- }
- e.stopPropagation();
- };
-
- onRelationshipKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
- if (e.key === 'Enter') {
- this.setRelationshipValue(this.relationship);
- document.getElementById('input')?.blur();
- }
- e.stopPropagation();
- };
-
- onDescriptionDown = () => this.setDescripValue(this.description);
- onRelationshipDown = () => this.setRelationshipValue(this.relationship);
-
- onBlur = () => {
- //only hide the search results if the user clicks out of the input AND not on any of the search results
- // i.e. if search is not active
- if (!this.searchIsActive) {
- this.toggleRelationshipResults();
- }
- };
- onFocus = () => {
- this.toggleRelationshipResults();
- };
- toggleSearchIsActive = () => {
- this.searchIsActive = !this.searchIsActive;
- };
-
- @action
- handleDescriptionChange = (e: React.ChangeEvent<HTMLInputElement>) => {
- this.description = e.target.value;
- };
- @action
- handleRelationshipChange = (e: React.ChangeEvent<HTMLInputElement>) => {
- this.relationship = e.target.value;
- };
- @action
- handleZoomFollowChange = () => {
- this.props.sourceDoc.followLinkZoom = !this.props.sourceDoc.followLinkZoom;
- };
- @action
- handleAudioFollowChange = () => {
- this.props.sourceDoc.followLinkAudio = !this.props.sourceDoc.followLinkAudio;
- };
- @action
- handleRelationshipSearchChange = (result: string) => {
- this.setRelationshipValue(result);
- this.toggleRelationshipResults();
- this.relationship = result;
- };
- @computed
- get editRelationship() {
- //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">Relationship:</div>
- <div className="linkEditor-description-input">
- <div className="linkEditor-description-editing">
- <input
- style={{ width: '100%' }}
- id="input"
- value={this.relationship}
- autoComplete={'off'}
- placeholder={'Enter link relationship'}
- onKeyDown={this.onRelationshipKey}
- onChange={this.handleRelationshipChange}
- onFocus={this.onFocus}
- onBlur={this.onBlur}></input>
- <LinkRelationshipSearch results={this.getRelationshipResults()} display={this.relationshipSearchVisibility} handleRelationshipSearchChange={this.handleRelationshipSearchChange} toggleSearch={this.toggleSearchIsActive} />
- </div>
- <div className="linkEditor-description-add-button" style={{ background: this.relationshipButtonColor }} onPointerDown={this.onRelationshipDown}>
- Set
- </div>
- </div>
- </div>
- );
- }
- @computed
- get editZoomFollow() {
- //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-zoomFollow">
- <div className="linkEditor-zoomFollow-label">Zoom To Link Target:</div>
- <div className="linkEditor-zoomFollow-input">
- <div className="linkEditor-zoomFollow-editing">
- <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>
- );
- }
-
- @computed
- get editDescription() {
- return (
- <div className="linkEditor-description">
- <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>
- </div>
- <div className="linkEditor-description-add-button" style={{ background: this.buttonColor }} onPointerDown={this.onDescriptionDown}>
- Set
- </div>
- </div>
- </div>
- );
- }
-
- @action
- changeDropdown = () => {
- this.openDropdown = !this.openDropdown;
- };
-
- @undoBatch
- changeFollowBehavior = action((follow: string) => {
- this.openDropdown = false;
- Doc.GetProto(this.props.linkDoc).followLinkLocation = follow;
- });
-
- @computed
- get followingDropdown() {
- return (
- <div className="linkEditor-followingDropdown">
- <div className="linkEditor-followingDropdown-label">Follow Behavior:</div>
- <div className="linkEditor-followingDropdown-dropdown">
- <div className="linkEditor-followingDropdown-header" onPointerDown={this.changeDropdown}>
- {StrCast(this.props.linkDoc.followLinkLocation, 'default')}
- <FontAwesomeIcon className="linkEditor-followingDropdown-icon" icon={this.openDropdown ? 'chevron-up' : 'chevron-down'} size={'lg'} />
- </div>
- <div className="linkEditor-followingDropdown-optionsList" style={{ display: this.openDropdown ? '' : 'none' }}>
- <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior('default')}>
- Default
- </div>
- <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior('add:left')}>
- Always open in new left pane
- </div>
- <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior('add:right')}>
- Always open in new right pane
- </div>
- <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior('replace:right')}>
- Always replace right tab
- </div>
- <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior('replace:left')}>
- Always replace left tab
- </div>
- <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior('fullScreen')}>
- Always open full screen
- </div>
- <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior('add')}>
- Always open in a new tab
- </div>
- <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior('replace')}>
- Replace Tab
- </div>
- {this.props.linkDoc.linksToAnnotation ? (
- <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeFollowBehavior('openExternal')}>
- Always open in external page
- </div>
- ) : null}
- </div>
- </div>
- </div>
- );
- }
-
- 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()} onPointerDown={e => e.stopPropagation()}>
- <div className="linkEditor-info">
- {!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">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>
- <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}
- {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>}>
- <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>
- );
- }
-}
diff --git a/src/client/views/linking/LinkMenu.scss b/src/client/views/linking/LinkMenu.scss
index 77c16a28f..80cf93ed8 100644
--- a/src/client/views/linking/LinkMenu.scss
+++ b/src/client/views/linking/LinkMenu.scss
@@ -1,4 +1,4 @@
-@import "../global/globalCssVariables";
+@import '../global/globalCssVariables';
.linkMenu {
width: auto;
@@ -13,7 +13,6 @@
border: 1px solid #e4e4e4;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
background: white;
- min-width: 170px;
max-height: 230px;
overflow-y: scroll;
z-index: 10;
@@ -22,7 +21,7 @@
.linkMenu-list {
white-space: nowrap;
overflow-x: hidden;
- width: 240px;
+ width: 100%;
scrollbar-color: white;
&:last-child {
@@ -39,7 +38,6 @@
border-bottom: 0.5px solid lightgray;
//@extend: 5px 0;
-
&:last-child {
border-bottom: none;
}
@@ -76,4 +74,4 @@
display: none;
}
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index 0096a58bd..c9112eec3 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -1,19 +1,19 @@
-import { action, computed, observable } from 'mobx';
+import { action, observable } from 'mobx';
import { observer } from 'mobx-react';
import { Doc } from '../../../fields/Doc';
+import { DocCast } from '../../../fields/Types';
import { LinkManager } from '../../util/LinkManager';
import { DocumentView } from '../nodes/DocumentView';
import { LinkDocPreview } from '../nodes/LinkDocPreview';
-import { LinkEditor } from './LinkEditor';
import './LinkMenu.scss';
import { LinkMenuGroup } from './LinkMenuGroup';
import React = require('react');
interface Props {
docView: DocumentView;
- position?: { x?: number; y?: number };
+ style?: { left: number; top: number };
itemHandler?: (doc: Doc) => void;
- clearLinkEditor: () => void;
+ clearLinkEditor?: () => void;
}
/**
@@ -22,23 +22,15 @@ interface Props {
@observer
export class LinkMenu extends React.Component<Props> {
_editorRef = React.createRef<HTMLDivElement>();
- @observable _editingLink?: Doc;
@observable _linkMenuRef = React.createRef<HTMLDivElement>();
- @computed get position() {
- return this.props.position ?? (dv => ({ x: dv?.left || 0, y: (dv?.bottom || 0) + 15 }))(this.props.docView.getBounds());
- }
-
- clear = action(() => {
- this.props.clearLinkEditor();
- this._editingLink = undefined;
- });
+ clear = () => this.props.clearLinkEditor?.();
componentDidMount() {
- document.addEventListener('pointerdown', this.onPointerDown, true);
+ this.props.clearLinkEditor && document.addEventListener('pointerdown', this.onPointerDown, true);
}
componentWillUnmount() {
- document.removeEventListener('pointerdown', this.onPointerDown, true);
+ this.props.clearLinkEditor && document.removeEventListener('pointerdown', this.onPointerDown, true);
}
onPointerDown = action((e: PointerEvent) => {
@@ -55,32 +47,20 @@ export class LinkMenu extends React.Component<Props> {
*/
renderAllGroups = (groups: Map<string, Array<Doc>>): Array<JSX.Element> => {
const linkItems = Array.from(groups.entries()).map(group => (
- <LinkMenuGroup
- key={group[0]}
- itemHandler={this.props.itemHandler}
- docView={this.props.docView}
- sourceDoc={this.props.docView.props.Document}
- group={group[1]}
- groupType={group[0]}
- clearLinkEditor={this.clear}
- showEditor={action(linkDoc => (this._editingLink = linkDoc))}
- />
+ <LinkMenuGroup key={group[0]} itemHandler={this.props.itemHandler} docView={this.props.docView} sourceDoc={this.props.docView.props.Document} group={group[1]} groupType={group[0]} clearLinkEditor={this.clear} />
));
- return linkItems.length ? linkItems : this.props.position ? [<></>] : [<p key="">No links have been created yet. Drag the linking button onto another document to create a link.</p>];
+ return linkItems.length ? linkItems : this.props.style ? [<></>] : [<p key="">No links have been created yet. Drag the linking button onto another document to create a link.</p>];
};
render() {
- const sourceDoc = this.props.docView.props.Document;
+ const sourceDoc = this.props.docView.rootDoc;
+ const sourceAnchor = this.props.docView.anchorViewDoc ?? sourceDoc;
+ const style = this.props.style ?? (dv => ({ left: dv?.left || 0, top: this.props.docView.topMost ? undefined : (dv?.bottom || 0) + 15, bottom: this.props.docView.topMost ? 20 : undefined, maxWidth: 200 }))(this.props.docView.getBounds());
+
return (
- <div className="linkMenu" ref={this._linkMenuRef} style={{ left: this.position.x, top: this.props.docView.topMost ? undefined : this.position.y, bottom: this.props.docView.topMost ? 20 : undefined }}>
- {this._editingLink ? (
- <div className="linkMenu-listEditor">
- <LinkEditor sourceDoc={sourceDoc} linkDoc={this._editingLink} showLinks={action(() => (this._editingLink = undefined))} />
- </div>
- ) : (
- <div className="linkMenu-list">{this.renderAllGroups(LinkManager.Instance.getRelatedGroupedLinks(sourceDoc))}</div>
- )}
+ <div className="linkMenu" ref={this._linkMenuRef} style={{ ...style }}>
+ <div className="linkMenu-list">{this.renderAllGroups(LinkManager.Instance.getRelatedGroupedLinks(sourceAnchor))}</div>
</div>
);
}
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index fa6a2f506..d02a1c4eb 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -1,20 +1,20 @@
-import { observer } from "mobx-react";
-import { observable, action } from "mobx";
-import { Doc, StrListCast } from "../../../fields/Doc";
-import { Id } from "../../../fields/FieldSymbols";
-import { Cast } from "../../../fields/Types";
-import { LinkManager } from "../../util/LinkManager";
-import { DocumentView } from "../nodes/DocumentView";
+import { observer } from 'mobx-react';
+import { observable, action } from 'mobx';
+import { Doc, StrListCast } from '../../../fields/Doc';
+import { Id } from '../../../fields/FieldSymbols';
+import { Cast, DocCast } from '../../../fields/Types';
+import { LinkManager } from '../../util/LinkManager';
+import { DocumentView } from '../nodes/DocumentView';
import './LinkMenu.scss';
-import { LinkMenuItem } from "./LinkMenuItem";
-import React = require("react");
+import { LinkMenuItem } from './LinkMenuItem';
+import React = require('react');
+import { DocumentType } from '../../documents/DocumentTypes';
interface LinkMenuGroupProps {
sourceDoc: Doc;
group: Doc[];
groupType: string;
- clearLinkEditor: () => void;
- showEditor: (linkDoc: Doc) => void;
+ clearLinkEditor?: () => void;
docView: DocumentView;
itemHandler?: (doc: Doc) => void;
}
@@ -26,49 +26,60 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
getBackgroundColor = (): string => {
const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList);
const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
- let color = "white";
+ let color = 'white';
// if this link's relationship property is not default "link", set its color
if (linkRelationshipList) {
const relationshipIndex = linkRelationshipList.indexOf(this.props.groupType);
const RGBcolor: string = linkColorList[relationshipIndex];
if (RGBcolor) {
//set opacity to 0.25 by modifiying the rgb string
- color = RGBcolor.slice(0, RGBcolor.length - 1) + ", 0.25)";
+ color = RGBcolor.slice(0, RGBcolor.length - 1) + ', 0.25)';
}
}
return color;
- }
+ };
@observable _collapsed = false;
render() {
const set = new Set<Doc>(this.props.group);
const groupItems = Array.from(set.keys()).map(linkDoc => {
- const destination = LinkManager.getOppositeAnchor(linkDoc, this.props.sourceDoc) ||
- LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, null).annotationOn === this.props.sourceDoc ? Cast(linkDoc.anchor2, Doc, null) : Cast(linkDoc.anchor1, Doc, null));
- if (destination && this.props.sourceDoc) {
- return <LinkMenuItem key={linkDoc[Id]}
+ const sourceDoc =
+ this.props.docView.anchorViewDoc ??
+ (this.props.docView.rootDoc.type === DocumentType.LINK //
+ ? this.props.docView.props.LayoutTemplateString?.includes('anchor1')
+ ? DocCast(linkDoc.anchor1)
+ : DocCast(linkDoc.anchor2)
+ : this.props.sourceDoc);
+ const destDoc = !sourceDoc
+ ? undefined
+ : this.props.docView.rootDoc.type === DocumentType.LINK
+ ? this.props.docView.props.LayoutTemplateString?.includes('anchor1')
+ ? DocCast(linkDoc.anchor2)
+ : DocCast(linkDoc.anchor1)
+ : LinkManager.getOppositeAnchor(linkDoc, sourceDoc) || LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, null).annotationOn === sourceDoc ? Cast(linkDoc.anchor2, Doc, null) : Cast(linkDoc.anchor1, Doc, null));
+ return !destDoc || !sourceDoc ? null : (
+ <LinkMenuItem
+ key={linkDoc[Id]}
itemHandler={this.props.itemHandler}
groupType={this.props.groupType}
docView={this.props.docView}
linkDoc={linkDoc}
- sourceDoc={this.props.sourceDoc}
- destinationDoc={destination}
+ sourceDoc={sourceDoc}
+ destinationDoc={destDoc}
clearLinkEditor={this.props.clearLinkEditor}
- showEditor={this.props.showEditor}
- menuRef={this._menuRef} />;
- }
+ menuRef={this._menuRef}
+ />
+ );
});
return (
<div className="linkMenu-group" ref={this._menuRef}>
- <div className="linkMenu-group-name" onClick={action(() => this._collapsed = !this._collapsed)} style={{ background: this.getBackgroundColor() }}>
- <p className={this.props.groupType === "*" || this.props.groupType === "" ? "" : "expand-one"}> {this.props.groupType}:</p>
+ <div className="linkMenu-group-name" onClick={action(() => (this._collapsed = !this._collapsed))} style={{ background: this.getBackgroundColor() }}>
+ <p className={this.props.groupType === '*' || this.props.groupType === '' ? '' : 'expand-one'}> {this.props.groupType}:</p>
</div>
- {this._collapsed ? (null) : <div className="linkMenu-group-wrapper">
- {groupItems}
- </div>}
- </div >
+ {this._collapsed ? null : <div className="linkMenu-group-wrapper">{groupItems}</div>}
+ </div>
);
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/linking/LinkMenuItem.scss b/src/client/views/linking/LinkMenuItem.scss
index 8333aa374..806a2c381 100644
--- a/src/client/views/linking/LinkMenuItem.scss
+++ b/src/client/views/linking/LinkMenuItem.scss
@@ -1,7 +1,7 @@
-@import "../global/globalCssVariables";
+@import '../global/globalCssVariables';
.linkMenu-item {
- // border-top: 0.5px solid $medium-gray;
+ // border-top: 0.5px solid $medium-gray;
position: relative;
display: flex;
border-top: 0.5px solid #cdcdcd;
@@ -14,7 +14,6 @@
background-color: white;
-
.linkMenu-name {
position: relative;
width: auto;
@@ -22,9 +21,7 @@
display: flex;
.linkMenu-text {
-
- // padding: 4px 2px;
- //display: inline;
+ width: 100%;
.linkMenu-source-title {
text-decoration: none;
@@ -35,9 +32,7 @@
margin-left: 20px;
}
-
.linkMenu-title-wrapper {
-
display: flex;
align-items: center;
min-height: 20px;
@@ -59,7 +54,7 @@
.linkMenu-destination-title {
text-decoration: none;
- color: #4476F7;
+ color: #4476f7;
font-size: 13px;
line-height: 0.9;
padding-bottom: 2px;
@@ -84,7 +79,6 @@
font-size: 9px;
line-height: 0.9;
margin-left: 20px;
- max-width: 125px;
height: auto;
white-space: break-spaces;
}
@@ -96,9 +90,7 @@
//overflow-wrap: break-word;
user-select: none;
}
-
}
-
}
.linkMenu-item-content {
@@ -114,15 +106,13 @@
}
&:hover {
-
background-color: rgb(201, 239, 252);
.linkMenu-item-buttons {
- display: flex;
+ opacity: 1;
}
.linkMenu-item-content {
-
.linkMenu-destination-title {
text-decoration: underline;
color: rgb(60, 90, 156);
@@ -135,11 +125,9 @@
.linkMenu-item-buttons {
//@extend: right;
- position: absolute;
- top: 50%;
- right: 0;
- transform: translateY(-50%);
- display: none;
+ position: relative;
+ display: flex;
+ opacity: 0;
.button {
width: 20px;
@@ -172,4 +160,4 @@
cursor: pointer;
}
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 3f9db2612..91b63c1a6 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -1,17 +1,20 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@material-ui/core';
-import { action, observable } from 'mobx';
+import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, DocListCast } from '../../../fields/Doc';
-import { Cast, StrCast } from '../../../fields/Types';
+import { Cast, DocCast, StrCast } from '../../../fields/Types';
import { WebField } from '../../../fields/URLField';
-import { emptyFunction, setupMoveUpEvents } from '../../../Utils';
+import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils';
import { DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager } from '../../util/DragManager';
import { LinkFollower } from '../../util/LinkFollower';
import { LinkManager } from '../../util/LinkManager';
+import { SelectionManager } from '../../util/SelectionManager';
+import { SettingsManager } from '../../util/SettingsManager';
+import { undoBatch } from '../../util/UndoManager';
import { DocumentView } from '../nodes/DocumentView';
import { LinkDocPreview } from '../nodes/LinkDocPreview';
import './LinkMenuItem.scss';
@@ -23,8 +26,7 @@ interface LinkMenuItemProps {
docView: DocumentView;
sourceDoc: Doc;
destinationDoc: Doc;
- clearLinkEditor: () => void;
- showEditor: (linkDoc: Doc) => void;
+ clearLinkEditor?: () => void;
menuRef: React.Ref<HTMLDivElement>;
itemHandler?: (doc: Doc) => void;
}
@@ -68,7 +70,6 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
private _drag = React.createRef<HTMLDivElement>();
_editRef = React.createRef<HTMLDivElement>();
- _buttonRef = React.createRef<HTMLDivElement>();
@observable private _showMore: boolean = false;
@action toggleShowMore(e: React.PointerEvent) {
@@ -76,8 +77,18 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
this._showMore = !this._showMore;
}
- onEdit = (e: React.PointerEvent): void => {
- LinkManager.currentLink = this.props.linkDoc;
+ @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
+ onEdit = (e: React.PointerEvent) => {
+ LinkManager.currentLink = this.props.linkDoc === LinkManager.currentLink ? undefined : this.props.linkDoc;
+ LinkManager.currentLinkAnchor = this.sourceAnchor;
setupMoveUpEvents(
this,
e,
@@ -88,7 +99,12 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
return true;
},
emptyFunction,
- () => this.props.showEditor(this.props.linkDoc)
+ action(() => {
+ SelectionManager.SelectView(this.props.docView, false);
+ if ((SettingsManager.propertiesWidth ?? 0) < 100) {
+ SettingsManager.propertiesWidth = 250;
+ }
+ })
);
};
@@ -100,12 +116,12 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
const eleClone: any = this._drag.current!.cloneNode(true);
eleClone.style.transform = `translate(${e.x}px, ${e.y}px)`;
StartLinkTargetsDrag(eleClone, this.props.docView, e.x, e.y, this.props.sourceDoc, [this.props.linkDoc]);
- this.props.clearLinkEditor();
+ this.props.clearLinkEditor?.();
return true;
},
emptyFunction,
() => {
- this.props.clearLinkEditor();
+ this.props.clearLinkEditor?.();
if (this.props.itemHandler) {
this.props.itemHandler?.(this.props.linkDoc);
} else {
@@ -116,21 +132,20 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
? Cast(this.props.linkDoc.anchor12, Doc, null)
: undefined;
- if (focusDoc) this.props.docView.ComponentView?.scrollFocus?.(focusDoc, true);
+ if (focusDoc) this.props.docView.ComponentView?.scrollFocus?.(focusDoc, { instant: true });
LinkFollower.FollowLink(this.props.linkDoc, this.props.sourceDoc, this.props.docView.props, false);
}
}
);
};
+ deleteLink = (e: React.PointerEvent): void => setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => LinkManager.Instance.deleteLink(this.props.linkDoc))));
+
render() {
const destinationIcon = Doc.toIcon(this.props.destinationDoc) as any as IconProp;
const title = StrCast(this.props.destinationDoc.title).length > 18 ? StrCast(this.props.destinationDoc.title).substr(0, 14) + '...' : this.props.destinationDoc.title;
- // ...
- // from anika to bob: here's where the text that is specifically linked would show up (linkDoc.storedText)
- // ...
const source =
this.props.sourceDoc.type === DocumentType.RTF
? this.props.linkDoc.storedText
@@ -141,24 +156,34 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
: undefined;
return (
- <div className="linkMenu-item">
+ <div className="linkMenu-item" style={{ background: LinkManager.currentLink === this.props.linkDoc ? 'lightBlue' : undefined }}>
<div className={'linkMenu-item-content expand-two'}>
<div
ref={this._drag}
className="linkMenu-name" //title="drag to view target. click to customize."
- onPointerLeave={LinkDocPreview.Clear}
- onPointerEnter={e =>
- this.props.linkDoc &&
- LinkDocPreview.SetLinkInfo({
- docProps: this.props.docView.props,
- linkSrc: this.props.sourceDoc,
- linkDoc: this.props.linkDoc,
- showHeader: false,
- location: [this._drag.current?.getBoundingClientRect().right ?? 100, this._drag.current?.getBoundingClientRect().top ?? e.clientY],
- })
- }
onPointerDown={this.onLinkButtonDown}>
- <div className="linkMenu-text">
+ <div className="linkMenu-item-buttons">
+ <Tooltip title={<div className="dash-tooltip">Edit Link</div>}>
+ <div className="button" style={{ background: LinkManager.currentLink === this.props.linkDoc ? 'black' : 'gray' }} ref={this._editRef} onPointerDown={this.onEdit} onClick={e => e.stopPropagation()}>
+ <FontAwesomeIcon className="fa-icon" icon="edit" size="sm" />
+ </div>
+ </Tooltip>
+ </div>
+ <div
+ className="linkMenu-text"
+ onPointerLeave={LinkDocPreview.Clear}
+ onPointerEnter={e =>
+ this.props.linkDoc &&
+ this.props.clearLinkEditor &&
+ LinkDocPreview.SetLinkInfo({
+ docProps: this.props.docView.props,
+ linkSrc: this.props.sourceDoc,
+ linkDoc: this.props.linkDoc,
+ showHeader: false,
+ location: [this._drag.current?.getBoundingClientRect().right ?? 100, this._drag.current?.getBoundingClientRect().top ?? e.clientY],
+ noPreview: false,
+ })
+ }>
{source ? (
<p className="linkMenu-source-title">
{' '}
@@ -176,10 +201,10 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
{!this.props.linkDoc.description ? null : <p className="linkMenu-description">{StrCast(this.props.linkDoc.description)}</p>}
</div>
- <div className="linkMenu-item-buttons" ref={this._buttonRef}>
- <Tooltip title={<div className="dash-tooltip">Edit Link</div>}>
- <div className="button" ref={this._editRef} onPointerDown={this.onEdit} onClick={e => e.stopPropagation()}>
- <FontAwesomeIcon className="fa-icon" icon="edit" size="sm" />
+ <div className="linkMenu-item-buttons">
+ <Tooltip title={<div className="dash-tooltip">Delete Link</div>}>
+ <div className="button" style={{ background: 'red' }} onPointerDown={this.deleteLink} onClick={e => e.stopPropagation()}>
+ <FontAwesomeIcon className="fa-icon" icon="trash" size="sm" />
</div>
</Tooltip>
</div>
diff --git a/src/client/views/linking/LinkPopup.scss b/src/client/views/linking/LinkPopup.scss
index 60c9ebfcd..b20ad9476 100644
--- a/src/client/views/linking/LinkPopup.scss
+++ b/src/client/views/linking/LinkPopup.scss
@@ -1,7 +1,7 @@
.linkPopup-container {
background: white;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
- top: 35px;
+ top: 0;
height: 200px;
width: 200px;
position: absolute;
@@ -38,8 +38,7 @@
}
}
-
.searchBox-container {
background: pink;
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 0bcb68f82..7bdace2b6 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -11,10 +11,13 @@ import { SearchBox } from '../search/SearchBox';
import { DefaultStyleProvider } from '../StyleProvider';
import './LinkPopup.scss';
import React = require('react');
+import { OpenWhere } from '../nodes/DocumentView';
interface LinkPopupProps {
showPopup: boolean;
linkFrom?: () => Doc | undefined;
+ linkCreateAnchor?: () => Doc | undefined;
+ linkCreated?: (link: Doc) => void;
// groupType: string;
// linkDoc: Doc;
// docView: DocumentView;
@@ -32,14 +35,10 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
// TODO: should check for valid URL
@undoBatch
- makeLinkToURL = (target: string, lcoation: string) => {
- ((this.view as any)?.TextView as FormattedTextBox).makeLinkAnchor(undefined, 'onRadd:rightight', target, target);
- };
+ makeLinkToURL = (target: string, lcoation: string) => ((this.view as any)?.TextView as FormattedTextBox).makeLinkAnchor(undefined, OpenWhere.addRight, target, target);
@action
- onLinkChange = (e: React.ChangeEvent<HTMLInputElement>) => {
- this.linkURL = e.target.value;
- };
+ onLinkChange = (e: React.ChangeEvent<HTMLInputElement>) => (this.linkURL = e.target.value);
getPWidth = () => 500;
getPHeight = () => 500;
@@ -67,7 +66,9 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
Document={Doc.MySearcher}
DataDoc={Doc.MySearcher}
linkFrom={linkDoc}
+ linkCreateAnchor={this.props.linkCreateAnchor}
linkSearch={true}
+ linkCreated={this.props.linkCreated}
fieldKey="data"
dropAction="move"
isSelected={returnTrue}