aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts7
-rw-r--r--src/client/views/DocumentButtonBar.tsx22
-rw-r--r--src/client/views/MarqueeAnnotator.tsx2
-rw-r--r--src/client/views/StyleProvider.tsx2
-rw-r--r--src/client/views/nodes/DocumentView.tsx4
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx12
6 files changed, 40 insertions, 9 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 332f7304b..a2850fd98 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -420,6 +420,10 @@ export namespace Docs {
[DocumentType.PRESELEMENT, {
layout: { view: PresElementBox, dataField: defaultDataKey }
}],
+ [DocumentType.PDFANNO, {
+ layout: { view: CollectionView, dataField: defaultDataKey },
+ options: { hideLinkButton: true }
+ }],
[DocumentType.INK, {
layout: { view: InkingStroke, dataField: defaultDataKey },
options: { _fontFamily: "cursive", backgroundColor: "transparent", links: ComputedField.MakeFunction("links(self)") as any }
@@ -801,6 +805,9 @@ export namespace Docs {
documents.map(d => d.context = inst);
return inst;
}
+ export function PdfAnnoDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
+ return InstanceFromProto(Prototypes.get(DocumentType.PDFANNO), new List(documents), { _chromeStatus: "collapsed", ...options, _viewType: CollectionViewType.Freeform }, id);
+ }
export function PileDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", _noAutoscroll: true, ...options, _viewType: CollectionViewType.Pile }, id);
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 4a1ec4d6c..07b419e5f 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -184,6 +184,18 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
</div></Tooltip>;
}
@computed
+ get followLinkButton() {
+ const targetDoc = this.view0?.props.Document;
+ return !targetDoc ? (null) : <Tooltip title={
+ <div className="dash-tooltip">{"follow primary link on click"}</div>}>
+ <div className="documentButtonBar-linker"
+ style={{ color: targetDoc.isLinkButton ? "black" : "white", backgroundColor: targetDoc.isLinkButton ? "white" : "black" }}
+ onClick={undoBatch(e => this.props.views().map(view => view?.docView?.toggleFollowLink(undefined, false, false)))}>
+ <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="hand-point-right" />
+ </div>
+ </Tooltip>;
+ }
+ @computed
get pinButton() {
const targetDoc = this.view0?.props.Document;
return !targetDoc ? (null) : <Tooltip title={
@@ -231,9 +243,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ margin: "auto", width: 17, transform: 'translate(0, 1px)' }} />;
const targetDoc = this.view0?.props.Document;
return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin with current view"}</div></>}>
- <div
- className="documentButtonBar-linker"
- onClick={() => this.pinWithView(targetDoc)}>
+ <div className="documentButtonBar-linker" onClick={() => this.pinWithView(targetDoc)}>
{presPinWithViewIcon}
</div>
</Tooltip>;
@@ -244,8 +254,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
const targetDoc = this.view0?.props.Document;
return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Open Sharing Manager"}</div></>}>
<div className="documentButtonBar-linker" style={{ color: "white" }} onClick={e => SharingManager.Instance.open(this.view0, targetDoc)}>
- <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="users"
- />
+ <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="users" />
</div></Tooltip >;
}
@@ -357,6 +366,9 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
<div className="documentButtonBar-button">
{this.contextButton}
</div> */}
+ {!SelectionManager.Views()?.some(v => v.allLinks.length) ? (null) : <div className="documentButtonBar-button">
+ {this.followLinkButton}
+ </div>}
<div className="documentButtonBar-button">
{this.pinButton}
</div>
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 2e50c9b6d..046f327fc 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -114,7 +114,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
return marqueeAnno;
}
- const textRegionAnno = Docs.Create.FreeformDocument([], { type: DocumentType.PDFANNO, annotationOn: this.props.rootDoc, title: "Selection on " + this.props.rootDoc.title, _width: 1, _height: 1 });
+ const textRegionAnno = Docs.Create.PdfAnnoDocument([], { annotationOn: this.props.rootDoc, title: "Selection on " + this.props.rootDoc.title, _width: 1, _height: 1 });
let maxX = -Number.MAX_VALUE;
let minY = Number.MAX_VALUE;
const annoDocs: Doc[] = [];
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index d9ab0d397..5cbbcce79 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -74,7 +74,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps |
case StyleProp.DocContents: return undefined;
case StyleProp.WidgetColor: return isAnnotated ? "lightBlue" : darkScheme() ? "lightgrey" : "dimgrey";
case StyleProp.Opacity: return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null));
- case StyleProp.HideLinkButton: return isAnchor || props?.dontRegisterView || ((!selected || doc?.type === DocumentType.PDFANNO) && (doc?.isLinkButton || doc?.hideLinkButton));
+ case StyleProp.HideLinkButton: return props?.dontRegisterView || doc?.type === DocumentType.PDFANNO || (!selected && (doc?.isLinkButton || doc?.hideLinkButton));
case StyleProp.ShowTitle: return doc && !doc.presentationTargetDoc && StrCast(doc._showTitle,
!Doc.IsSystem(doc) && doc.type === DocumentType.RTF ?
(doc.author === Doc.CurrentUserEmail ? StrCast(Doc.UserDoc().showTitle) : "author;creationDate") : "") || "";
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a9372aa64..0e759c780 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -791,7 +791,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
onClick={this.onClickFunc}
focus={this.focus}
layoutKey={this.finalLayoutKey} />
- {this.layoutDoc.hideAllLinks ? (null) : this.allAnchors}
+ {this.layoutDoc.hideAllLinks ? (null) : this.allLinkEndpoints}
{this.hideLinkButton ? (null) :
<DocumentLinksButton View={this.props.DocumentView()} links={this.allLinks} Offset={[this.topMost ? 0 : -15, undefined, undefined, this.topMost ? 10 : -20]} />}
@@ -808,7 +808,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
@computed get directLinks() { TraceMobx(); return LinkManager.Instance.getAllDirectLinks(this.rootDoc); }
@computed get allLinks() { TraceMobx(); return LinkManager.Instance.getAllRelatedLinks(this.rootDoc); }
- @computed get allAnchors() {
+ @computed get allLinkEndpoints() { // the small blue dots that mark the endpoints of links
TraceMobx();
if (this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return null;
if (this.layoutDoc.presBox || this.rootDoc.type === DocumentType.LINK || this.props.dontRegisterView) return (null);
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index d44867541..af9aeea00 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -250,6 +250,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
json?.replace(/"selection":.*/, "") : json?.replace(/"selection":"\"storedMarks\""/, "\"storedMarks\"");
if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) {
+ const accumTags = [] as string[]
+ state.tr.doc.nodesBetween(0, state.doc.content.size, (node: any, pos: number, parent: any) => {
+ if (node.type === schema.nodes.dashField && node.attrs.fieldKey.startsWith("#")) {
+ accumTags.push(node.attrs.fieldKey)
+ }
+ });
+ const curTags = Object.keys(this.dataDoc).filter(key => key.startsWith("#"));
+ const added = accumTags.filter(tag => !curTags.includes(tag));
+ const removed = curTags.filter(tag => !accumTags.includes(tag));
+ removed.forEach(r => this.dataDoc[r] = undefined);
+ added.forEach(a => this.dataDoc[a] = a);
+
let unchanged = true;
if (this._applyingChange !== this.fieldKey && removeSelection(json) !== removeSelection(curProto?.Data)) {
this._applyingChange = this.fieldKey;