aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx2
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx24
-rw-r--r--src/client/views/nodes/DocumentView.tsx413
-rw-r--r--src/client/views/nodes/ImageBox.tsx2
-rw-r--r--src/client/views/nodes/ScriptingBox.tsx2
-rw-r--r--src/client/views/nodes/WebBox.scss23
-rw-r--r--src/client/views/nodes/WebBox.tsx305
-rw-r--r--src/client/views/nodes/formattedText/DashFieldView.tsx4
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx11
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts7
10 files changed, 398 insertions, 395 deletions
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index f140cc6e5..616cddfcf 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -24,7 +24,7 @@ const ComparisonDocument = makeInterface(comparisonSchema, documentSchema);
@observer
export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps, ComparisonDocument>(ComparisonDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ComparisonBox, fieldKey); }
- protected multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined;
+ protected _multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined;
private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined];
@observable _animating = "";
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 748d5bbd0..5f3a6e78d 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -1,19 +1,19 @@
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Tooltip } from "@material-ui/core";
import { action, computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast } from "../../../fields/Doc";
-import { emptyFunction, setupMoveUpEvents, returnFalse } from "../../../Utils";
+import { Doc } from "../../../fields/Doc";
+import { TraceMobx } from "../../../fields/util";
+import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils";
+import { DocUtils } from "../../documents/Documents";
import { DragManager } from "../../util/DragManager";
-import { UndoManager, undoBatch } from "../../util/UndoManager";
+import { LinkManager } from "../../util/LinkManager";
+import { undoBatch, UndoManager } from "../../util/UndoManager";
import './DocumentLinksButton.scss';
import { DocumentView } from "./DocumentView";
-import React = require("react");
-import { DocUtils } from "../../documents/Documents";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { LinkDocPreview } from "./LinkDocPreview";
-import { TaskCompletionBox } from "./TaskCompletedBox";
import { LinkDescriptionPopup } from "./LinkDescriptionPopup";
-import { LinkManager } from "../../util/LinkManager";
-import { Tooltip } from "@material-ui/core";
+import { TaskCompletionBox } from "./TaskCompletedBox";
+import React = require("react");
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -24,6 +24,7 @@ interface DocumentLinksButtonProps {
AlwaysOn?: boolean;
InMenu?: boolean;
StartLink?: boolean;
+ links: Doc[];
}
@observer
export class DocumentLinksButton extends React.Component<DocumentLinksButtonProps, {}> {
@@ -158,7 +159,8 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
@computed
get linkButton() {
- const links = DocListCast(this.props.View.props.Document.links);
+ TraceMobx();
+ const links = this.props.links;
const menuTitle = this.props.StartLink ? "Drag or tap to start link" : "Tap to complete link";
const buttonTitle = "Tap to view links";
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 266089a6d..856eb7246 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,31 +1,31 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import * as fa from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast, HeightSym, Opt, WidthSym, DataSym, AclPrivate, AclEdit, AclAdmin } from "../../../fields/Doc";
+import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
import { Document } from '../../../fields/documentSchemas';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { listSpec } from "../../../fields/Schema";
import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../fields/Types";
-import { TraceMobx, GetEffectiveAcl, SharingPermissions } from '../../../fields/util';
+import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
+import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
+import { MobileInterface } from '../../../mobile/MobileInterface';
import { GestureUtils } from '../../../pen-gestures/GestureUtils';
-import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils, emptyPath } from "../../../Utils";
+import { emptyFunction, emptyPath, OmitKeys, returnOne, returnTransparent, Utils } from "../../../Utils";
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
import { ClientRecommender } from '../../ClientRecommender';
import { Docs, DocUtils } from "../../documents/Documents";
import { DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from "../../util/DocumentManager";
-import { SnappingManager } from '../../util/SnappingManager';
import { DragManager, dropActionType } from "../../util/DragManager";
import { InteractionUtils } from '../../util/InteractionUtils';
+import { LinkManager } from '../../util/LinkManager';
import { Scripting } from '../../util/Scripting';
import { SearchUtil } from '../../util/SearchUtil';
import { SelectionManager } from "../../util/SelectionManager";
import SharingManager from '../../util/SharingManager';
+import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from "../../util/Transform";
import { undoBatch, UndoManager } from "../../util/UndoManager";
import { CollectionView, CollectionViewType } from '../collections/CollectionView';
@@ -35,19 +35,13 @@ import { DocComponent } from "../DocComponent";
import { EditableView } from '../EditableView';
import { KeyphraseQueryView } from '../KeyphraseQueryView';
import { DocumentContentsView } from "./DocumentContentsView";
+import { DocumentLinksButton } from './DocumentLinksButton';
import "./DocumentView.scss";
import { LinkAnchorBox } from './LinkAnchorBox';
+import { LinkDescriptionPopup } from './LinkDescriptionPopup';
import { RadialMenu } from './RadialMenu';
-import React = require("react");
-import { DocumentLinksButton } from './DocumentLinksButton';
-import { MobileInterface } from '../../../mobile/MobileInterface';
import { TaskCompletionBox } from './TaskCompletedBox';
-import { LinkDescriptionPopup } from './LinkDescriptionPopup';
-import { LinkManager } from '../../util/LinkManager';
-
-library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
- fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
- fa.faCopy, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone, fa.faKeyboard, fa.faQuestion);
+import React = require("react");
export type DocFocusFunc = () => boolean;
@@ -106,24 +100,25 @@ export interface DocumentViewProps {
@observer
export class DocumentView extends DocComponent<DocumentViewProps, Document>(Document) {
+ @observable _animateScalingTo = 0;
private _downX: number = 0;
private _downY: number = 0;
+ private _firstX: number = -1;
+ private _firstY: number = -1;
private _lastTap: number = 0;
private _doubleTap = false;
private _mainCont = React.createRef<HTMLDivElement>();
private _dropDisposer?: DragManager.DragDropDisposer;
private _showKPQuery: boolean = false;
private _queries: string = "";
- private _gestureEventDisposer?: GestureUtils.GestureEventDisposer;
private _titleRef = React.createRef<EditableView>();
+ private _gestureEventDisposer?: GestureUtils.GestureEventDisposer;
+ private _holdDisposer?: InteractionUtils.MultiTouchEventDisposer;
+ protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
- protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
- private holdDisposer?: InteractionUtils.MultiTouchEventDisposer;
-
- public get title() { return this.props.Document.title; }
public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
public get ContentDiv() { return this._mainCont.current; }
- get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
+ private get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
@computed get topMost() { return this.props.renderDepth === 0; }
@computed get freezeDimensions() { return this.props.FreezeDimensions; }
@computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
@@ -137,9 +132,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
onClickFunc = () => this.onClickHandler;
onDoubleClickFunc = () => this.onDoubleClickHandler;
- private _firstX: number = -1;
- private _firstY: number = -1;
-
handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => {
this.removeMoveListeners();
this.removeEndListeners();
@@ -153,11 +145,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this._firstX = pt.pageX;
this._firstY = pt.pageY;
}
-
}
handle1PointerHoldMove = (e: Event, me: InteractionUtils.MultiTouchEvent<TouchEvent>): void => {
-
const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1];
if (this._firstX === -1 || this._firstY === -1) {
@@ -201,7 +191,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
componentDidMount() {
this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document));
this._mainCont.current && (this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this)));
- this._mainCont.current && (this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this)));
+ this._mainCont.current && (this._multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this)));
// this._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this)));
if (!this.props.dontRegisterView) {
@@ -213,13 +203,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
componentDidUpdate() {
this._dropDisposer?.();
this._gestureEventDisposer?.();
- this.multiTouchDisposer?.();
- this.holdDisposer?.();
+ this._multiTouchDisposer?.();
+ this._holdDisposer?.();
if (this._mainCont.current) {
this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document);
this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this));
- this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this));
- this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this));
+ this._multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this));
+ this._holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this));
}
}
@@ -227,8 +217,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
componentWillUnmount() {
this._dropDisposer?.();
this._gestureEventDisposer?.();
- this.multiTouchDisposer?.();
- this.holdDisposer?.();
+ this._multiTouchDisposer?.();
+ this._holdDisposer?.();
Doc.UnBrushDoc(this.props.Document);
if (!this.props.dontRegisterView) {
const index = DocumentManager.Instance.DocumentViews.indexOf(this);
@@ -243,7 +233,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
dragData.offset = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top);
dragData.dropAction = dropAction;
dragData.removeDocument = this.props.removeDocument;
- dragData.moveDocument = this.props.moveDocument;// this.layoutDoc.onDragStart ? undefined : this.props.moveDocument;
+ dragData.moveDocument = this.props.moveDocument;
dragData.dragDivName = this.props.dragDivName;
dragData.treeViewDoc = this.props.treeViewDoc;
DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: !dropAction && !this.layoutDoc.onDragStart });
@@ -255,7 +245,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const de = new DragManager.DocumentDragData([topDoc]);
de.dragDivName = topDocView.props.dragDivName;
de.moveDocument = topDocView.props.moveDocument;
- undoBatch(action(() => topDoc.z = topDoc.z ? 0 : 1))();
setTimeout(() => {
const newDocView = DocumentManager.Instance.getDocumentView(topDoc);
if (newDocView) {
@@ -264,6 +253,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
DragManager.StartDocumentDrag([contentDiv], de, x, y, { offsetX: x - xf.left, offsetY: y - xf.top, hideSource: true });
}
}, 0);
+ UndoManager.RunInBatch(action(() => topDoc.z = topDoc.z ? 0 : 1), "float");
}
onKeyDown = (e: React.KeyboardEvent) => {
@@ -302,42 +292,40 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const func = () => this.onDoubleClickHandler.script.run({
this: this.layoutDoc,
self: this.rootDoc,
- thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey
+ thisContainer: this.props.ContainingCollectionDoc,
+ shiftKey: e.shiftKey
}, console.log);
func();
} else {
UndoManager.RunInBatch(() => {
+ let fullScreenDoc = this.props.Document;
if (StrCast(this.props.Document.layoutKey) !== "layout_fullScreen" && this.props.Document.layout_fullScreen) {
- const fullScreenAlias = Doc.MakeAlias(this.props.Document);
- fullScreenAlias.layoutKey = "layout_fullScreen";
- this.props.addDocTab(fullScreenAlias, "inTab");
- } else {
- this.props.addDocTab(this.props.Document, "inTab");
+ fullScreenDoc = Doc.MakeAlias(this.props.Document);
+ fullScreenDoc.layoutKey = "layout_fullScreen";
}
+ this.props.addDocTab(fullScreenDoc, "inTab");
}, "double tap");
SelectionManager.DeselectAll();
Doc.UnBrushDoc(this.props.Document);
}
}
} else if (this.onClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself
- //SelectionManager.DeselectAll();
const func = () => this.onClickHandler.script.run({
this: this.layoutDoc,
self: this.rootDoc,
scriptContext: this.props.scriptContext,
- thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey
+ thisContainer: this.props.ContainingCollectionDoc,
+ shiftKey: e.shiftKey
}, console.log);
if (this.props.Document !== Doc.UserDoc()["dockedBtn-undo"] && this.props.Document !== Doc.UserDoc()["dockedBtn-redo"]) {
UndoManager.RunInBatch(func, "on click");
} else func();
} else if (this.Document["onClick-rawScript"] && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) {// bcz: hack? don't edit a script if you're clicking on a scripting box itself
- const alias = Doc.MakeAlias(this.props.Document);
- DocUtils.makeCustomViewClicked(alias, undefined, "onClick");
- this.props.addDocTab(alias, "onRight");
- } else if (this.props.Document.links && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) {
- DocListCast(this.props.Document.links).length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey);
+ this.props.addDocTab(DocUtils.makeCustomViewClicked(Doc.MakeAlias(this.props.Document), undefined, "onClick"), "onRight");
+ } else if (this.allLinks && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) {
+ this.allLinks.length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey);
} else {
- if ((this.layoutDoc.onDragStart || (this.props.Document.rootDocument)) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTEmplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
+ if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template
} else {
SelectionManager.SelectDoc(this, e.ctrlKey || e.shiftKey);
@@ -409,7 +397,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers
e.preventDefault();
-
}
}
@@ -447,12 +434,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const oldPoint2 = this.prevPoints.get(pt2.identifier);
const pinching = InteractionUtils.Pinning(pt1, pt2, oldPoint1!, oldPoint2!);
if (pinching !== 0 && oldPoint1 && oldPoint2) {
- // let dX = (Math.min(pt1.clientX, pt2.clientX) - Math.min(oldPoint1.clientX, oldPoint2.clientX));
- // let dY = (Math.min(pt1.clientY, pt2.clientY) - Math.min(oldPoint1.clientY, oldPoint2.clientY));
- // let dX = Math.sign(Math.abs(pt1.clientX - oldPoint1.clientX) - Math.abs(pt2.clientX - oldPoint2.clientX));
- // let dY = Math.sign(Math.abs(pt1.clientY - oldPoint1.clientY) - Math.abs(pt2.clientY - oldPoint2.clientY));
- // let dW = -dX;
- // let dH = -dY;
const dW = (Math.abs(pt1.clientX - pt2.clientX) - Math.abs(oldPoint1.clientX - oldPoint2.clientX));
const dH = (Math.abs(pt1.clientY - pt2.clientY) - Math.abs(oldPoint1.clientY - oldPoint2.clientY));
const dX = -1 * Math.sign(dW);
@@ -535,7 +516,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
onPointerMove = (e: PointerEvent): void => {
-
if ((e as any).formattedHandled) { e.stopPropagation(); return; }
if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || Doc.GetSelectedTool() === InkTool.Highlighter || Doc.GetSelectedTool() === InkTool.Pen)) return;
if (e.cancelBubble && this.active) {
@@ -556,17 +536,15 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
onPointerUp = (e: PointerEvent): void => {
this.cleanUpInteractions();
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log);
- document.removeEventListener("pointerup", this.onPointerUp);
- return;
+ } else {
+ this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2);
+ this._lastTap = Date.now();
}
-
- document.removeEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2);
- this._lastTap = Date.now();
}
onGesture = (e: Event, ge: GestureUtils.GestureEvent) => {
@@ -588,37 +566,16 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
}
-
- @undoBatch
- toggleLinkButtonBehavior = (): void => {
- this.Document.ignoreClick = false;
- if (this.Document.isLinkButton || this.onClickHandler || this.Document.ignoreClick) {
- this.Document.isLinkButton = false;
- this.Document.onClick = this.layoutDoc.onClick = undefined;
- } else {
- this.Document.isLinkButton = true;
- this.Document.followLinkZoom = false;
- this.Document.followLinkLocation = undefined;
- }
- }
-
- @undoBatch
- toggleFollowInPlace = (): void => {
+ @undoBatch @action
+ toggleFollowLink = (location: Opt<string>, zoom: boolean, setPushpin: boolean): void => {
this.Document.ignoreClick = false;
this.Document.isLinkButton = !this.Document.isLinkButton;
- if (this.Document.isLinkButton) {
- this.Document.followLinkZoom = true;
- this.Document.followLinkLocation = "inPlace";
- }
- }
-
- @undoBatch
- toggleFollowOnRight = (): void => {
- this.Document.ignoreClick = false;
- this.Document.isLinkButton = !this.Document.isLinkButton;
- if (this.Document.isLinkButton) {
- this.Document.followLinkZoom = false;
- this.Document.followLinkLocation = "onRight";
+ setPushpin && (this.Document.isPushpin = this.Document.isLinkButton);
+ if (this.Document.isLinkButton && !this.onClickHandler) {
+ this.Document.followLinkZoom = zoom;
+ this.Document.followLinkLocation = location;
+ } else {
+ this.Document.onClick = this.layoutDoc.onClick = undefined;
}
}
@@ -634,8 +591,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`);
}
- @undoBatch
- @action
+ @undoBatch @action
drop = async (e: Event, de: DragManager.DropEvent) => {
if (this.props.Document === Doc.UserDoc().activeWorkspace) {
alert("linking to document tabs not yet supported. Drop link on document content.");
@@ -665,11 +621,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
if (de.complete.linkDragData) {
e.stopPropagation();
- if (de.complete.linkDragData.linkSourceDocument !== this.props.Document) {
- const linkDoc = DocUtils.MakeLink({ doc: de.complete.linkDragData.linkSourceDocument },
- { doc: this.props.Document }, `link`);
- de.complete.linkDragData.linkSourceDocument !== this.props.Document &&
- (de.complete.linkDragData.linkDocument = linkDoc); // TODODO this is where in text links get passed
+ const linkSource = de.complete.linkDragData.linkSourceDocument;
+ if (linkSource !== this.props.Document) {
+ const linkDoc = DocUtils.MakeLink({ doc: linkSource }, { doc: this.props.Document }, `link`);
+ linkSource !== this.props.Document && (de.complete.linkDragData.linkDocument = linkDoc); // TODODO this is where in text links get passed
linkDoc && makeLink(linkDoc);
}
@@ -684,9 +639,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@undoBatch
@action
+ toggleLockPosition = (): void => {
+ this.Document.lockedPosition = this.Document.lockedPosition ? undefined : true;
+ }
+
+ @undoBatch
+ @action
makeIntoPortal = async () => {
- console.log("into portal");
- const portalLink = DocListCast(this.Document.links).find(d => d.anchor1 === this.props.Document);
+ const portalLink = this.allLinks.find(d => d.anchor1 === this.props.Document);
if (!portalLink) {
const portal = Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), title: StrCast(this.props.Document.title) + ".portal" });
DocUtils.MakeLink({ doc: this.props.Document }, { doc: portal }, "portal to");
@@ -697,9 +657,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@undoBatch
@action
- toggleBackground = (temporary: boolean): void => {
- this.Document._overflow = temporary ? "visible" : "hidden";
- this.Document.isBackground = !temporary ? !this.Document.isBackground : (this.Document.isBackground ? undefined : true);
+ toggleBackground = () => {
+ this.Document.isBackground = (this.Document.isBackground ? undefined : true);
+ this.Document._overflow = this.Document.isBackground ? "visible" : undefined;
if (this.Document.isBackground) {
this.props.bringToFront(this.props.Document, true);
this.props.Document[DataSym][Doc.LayoutFieldKey(this.Document) + "-nativeWidth"] = this.Document[WidthSym]();
@@ -707,41 +667,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
}
- @undoBatch
- @action
- toggleLockPosition = (): void => {
- this.Document.lockedPosition = this.Document.lockedPosition ? undefined : true;
- }
-
- @undoBatch
- @action
- setAcl = (acl: SharingPermissions) => {
- this.dataDoc.ACL = this.props.Document.ACL = acl;
- DocListCast(this.dataDoc[Doc.LayoutFieldKey(this.dataDoc)]).map(d => {
- if (d.author === Doc.CurrentUserEmail) d.ACL = acl;
- const data = d[DataSym];
- if (data && data.author === Doc.CurrentUserEmail) data.ACL = acl;
- });
- }
-
- @undoBatch
- @action
- testAcl = (acl: SharingPermissions) => {
- this.dataDoc.author = this.props.Document.author = "ADMIN";
- this.dataDoc.ACL = this.props.Document.ACL = acl;
- DocListCast(this.dataDoc[Doc.LayoutFieldKey(this.dataDoc)]).map(d => {
- if (d.author === Doc.CurrentUserEmail) {
- d.author = "ADMIN";
- d.ACL = acl;
- }
- const data = d[DataSym];
- if (data && data.author === Doc.CurrentUserEmail) {
- data.author = "ADMIN";
- data.ACL = acl;
- }
- });
- }
-
@action
onCopy = () => {
const copy = Doc.MakeCopy(this.props.Document, true);
@@ -796,9 +721,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" });
onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`), icon: "window-restore" });
onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
- onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" });
- onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link on Right", event: this.toggleFollowOnRight, icon: "concierge-bell" });
- onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" });
+ onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: () => this.toggleFollowLink("inPlace", true, false), icon: "concierge-bell" });
+ !this.Document.isLinkButton && onClicks.push({ description: "Follow Link on Right", event: () => this.toggleFollowLink("onRight", false, false), icon: "concierge-bell" });
+ onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: () => this.toggleFollowLink(undefined, false, false), icon: "concierge-bell" });
+ onClicks.push({ description: (this.Document.isPushpin ? "Remove" : "Make") + " Pushpin", event: () => this.toggleFollowLink(undefined, false, true), icon: "snowflake" });
onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" });
!existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, addDivider: true, subitems: onClicks, icon: "hand-point-right" });
@@ -814,16 +740,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const moreItems = more && "subitems" in more ? more.subitems : [];
moreItems.push({ description: "Share", event: () => SharingManager.Instance.open(this), icon: "users" });
moreItems.push({ description: "Create an Alias", event: () => this.onCopy(), icon: "copy" });
- moreItems.push({
- description: "Download document", icon: "download", event: async () => {
- Doc.Zip(this.props.Document);
- // const a = document.createElement("a");
- // const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`);
- // a.href = url;
- // a.download = `DocExport-${this.props.Document[Id]}.zip`;
- // a.click();
- }
- });
+ moreItems.push({ description: "Download document", icon: "download", event: async () => Doc.Zip(this.props.Document) });
if (!Doc.UserDoc().noviceMode) {
moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" });
moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
@@ -850,179 +767,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" });
cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" });
- // const existingAcls = cm.findByDescription("Privacy...");
- // const aclItems: ContextMenuProps[] = existingAcls && "subitems" in existingAcls ? existingAcls.subitems : [];
- // aclItems.push({ description: "Make Add Only", event: () => this.setAcl(SharingPermissions.Add), icon: "concierge-bell" });
- // aclItems.push({ description: "Make Read Only", event: () => this.setAcl(SharingPermissions.View), icon: "concierge-bell" });
- // aclItems.push({ description: "Make Private", event: () => this.setAcl(SharingPermissions.None), icon: "concierge-bell" });
- // aclItems.push({ description: "Make Editable", event: () => this.setAcl(SharingPermissions.Edit), icon: "concierge-bell" });
- // aclItems.push({ description: "Test Private", event: () => this.testAcl(SharingPermissions.None), icon: "concierge-bell" });
- // aclItems.push({ description: "Test Readonly", event: () => this.testAcl(SharingPermissions.View), icon: "concierge-bell" });
- // !existingAcls && cm.addItem({ description: "Privacy...", subitems: aclItems, icon: "question" });
-
- // cm.addItem({ description: `${getPlaygroundMode() ? "Disable" : "Enable"} playground mode`, event: togglePlaygroundMode, icon: "concierge-bell" });
-
- // const recommender_subitems: ContextMenuProps[] = [];
-
- // recommender_subitems.push({
- // description: "Internal recommendations",
- // event: () => this.recommender(),
- // icon: "brain"
- // });
-
- // const ext_recommender_subitems: ContextMenuProps[] = [];
-
- // ext_recommender_subitems.push({
- // description: "arXiv",
- // event: () => this.externalRecommendation("arxiv"),
- // icon: "brain"
- // });
- // ext_recommender_subitems.push({
- // description: "Bing",
- // event: () => this.externalRecommendation("bing"),
- // icon: "brain"
- // });
-
- // recommender_subitems.push({
- // description: "External recommendations",
- // subitems: ext_recommender_subitems,
- // icon: "brain"
- // });
-
-
- //moreItems.push({ description: "Recommender System", subitems: recommender_subitems, icon: "brain" });
- //moreItems.push({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, this.Document.title || "", this.props.addDocument, this.props.removeDocument), icon: "file" });
- //moreItems.push({ description: "Undo Debug Test", event: () => UndoManager.TraceOpenBatches(), icon: "exclamation" });
-
- // runInAction(() => {
- // const setWriteMode = (mode: DocServer.WriteMode) => {
- // DocServer.AclsMode = mode;
- // const mode1 = mode;
- // const mode2 = mode === DocServer.WriteMode.Default ? mode : DocServer.WriteMode.Playground;
- // DocServer.setFieldWriteMode("x", mode1);
- // DocServer.setFieldWriteMode("y", mode1);
- // DocServer.setFieldWriteMode("_width", mode1);
- // DocServer.setFieldWriteMode("_height", mode1);
-
- // DocServer.setFieldWriteMode("_panX", mode2);
- // DocServer.setFieldWriteMode("_panY", mode2);
- // DocServer.setFieldWriteMode("scale", mode2);
- // DocServer.setFieldWriteMode("_viewType", mode2);
- // };
- // const aclsMenu: ContextMenuProps[] = [];
- // aclsMenu.push({ description: "Default (write/read all)", event: () => setWriteMode(DocServer.WriteMode.Default), icon: DocServer.AclsMode === DocServer.WriteMode.Default ? "check" : "exclamation" });
- // aclsMenu.push({ description: "Playground (write own/no read)", event: () => setWriteMode(DocServer.WriteMode.Playground), icon: DocServer.AclsMode === DocServer.WriteMode.Playground ? "check" : "exclamation" });
- // aclsMenu.push({ description: "Live Playground (write own/read others)", event: () => setWriteMode(DocServer.WriteMode.LivePlayground), icon: DocServer.AclsMode === DocServer.WriteMode.LivePlayground ? "check" : "exclamation" });
- // aclsMenu.push({ description: "Live Readonly (no write/read others)", event: () => setWriteMode(DocServer.WriteMode.LiveReadonly), icon: DocServer.AclsMode === DocServer.WriteMode.LiveReadonly ? "check" : "exclamation" });
- // cm.addItem({ description: "Collaboration ...", subitems: aclsMenu, icon: "share" });
- // });
runInAction(() => {
if (!this.topMost && !(e instanceof Touch)) {
- // DocumentViews should stop propagation of this event
- e.stopPropagation();
+ e.stopPropagation(); // DocumentViews should stop propagation of this event
}
cm.displayMenu(e.pageX - 15, e.pageY - 15);
!SelectionManager.IsSelected(this, true) && SelectionManager.SelectDoc(this, false);
});
- const path = this.props.LibraryPath.reduce((p: string, d: Doc) => p + "/" + (Doc.AreProtosEqual(d, (Doc.UserDoc()["tabs-button-library"] as Doc).sourcePanel as Doc) ? "" : d.title), "");
- const item = ({
- description: `path: ${path}`, event: () => {
- if (this.props.LibraryPath !== emptyPath) {
- this.props.LibraryPath.map(lp => Doc.GetProto(lp).treeViewOpen = lp.treeViewOpen = true);
- Doc.linkFollowHighlight(this.props.Document);
- } else {
- Doc.AddDocToList(Doc.GetProto(Doc.UserDoc().myCatalog as Doc), "data", this.props.Document[DataSym]);
- }
- }, icon: "check"
- });
- //cm.addItem(item);
- }
-
- recommender = async () => {
- if (!ClientRecommender.Instance) new ClientRecommender({ title: "Client Recommender" });
- const documents: Doc[] = [];
- const allDocs = await SearchUtil.GetAllDocs();
- // clears internal representation of documents as vectors
- ClientRecommender.Instance.reset_docs();
- //ClientRecommender.Instance.arxivrequest("electrons");
- await Promise.all(allDocs.map((doc: Doc) => {
- let isMainDoc: boolean = false;
- const dataDoc = Doc.GetProto(doc);
- if (doc.type === DocumentType.RTF) {
- if (dataDoc === Doc.GetProto(this.props.Document)) {
- isMainDoc = true;
- }
- if (!documents.includes(dataDoc)) {
- documents.push(dataDoc);
- const extdoc = doc.data_ext as Doc;
- return ClientRecommender.Instance.extractText(doc, extdoc ? extdoc : doc, true, "", isMainDoc);
- }
- }
- if (doc.type === DocumentType.IMG) {
- if (dataDoc === Doc.GetProto(this.props.Document)) {
- isMainDoc = true;
- }
- if (!documents.includes(dataDoc)) {
- documents.push(dataDoc);
- const extdoc = doc.data_ext as Doc;
- return ClientRecommender.Instance.extractText(doc, extdoc ? extdoc : doc, true, "", isMainDoc, true);
- }
- }
- }));
- const doclist = ClientRecommender.Instance.computeSimilarities("cosine");
- const recDocs: { preview: Doc, score: number }[] = [];
- // tslint:disable-next-line: prefer-for-of
- for (let i = 0; i < doclist.length; i++) {
- recDocs.push({ preview: doclist[i].actualDoc, score: doclist[i].score });
- }
-
- const data = recDocs.map(unit => {
- unit.preview.score = unit.score;
- return unit.preview;
- });
-
- console.log(recDocs.map(doc => doc.score));
-
- const title = `Showing ${data.length} recommendations for "${StrCast(this.props.Document.title)}"`;
- const recommendations = Docs.Create.RecommendationsDocument(data, { title });
- recommendations.documentIconHeight = 150;
- recommendations.sourceDoc = this.props.Document;
- recommendations.sourceDocContext = this.props.ContainingCollectionView!.props.Document;
- this.props.addDocTab(recommendations, "onRight");
-
- // RecommendationsBox.Instance.displayRecommendations(e.pageX + 100, e.pageY);
- }
-
- @action
- externalRecommendation = async (api: string) => {
- if (!ClientRecommender.Instance) new ClientRecommender({ title: "Client Recommender" });
- ClientRecommender.Instance.reset_docs();
- const doc = Doc.GetDataDoc(this.props.Document);
- const extdoc = doc.data_ext as Doc;
- const recs_and_kps = await ClientRecommender.Instance.extractText(doc, extdoc ? extdoc : doc, false, api);
- let recs: any;
- let kps: any;
- if (recs_and_kps) {
- recs = recs_and_kps.recs;
- kps = recs_and_kps.keyterms;
- }
- else {
- console.log("recommender system failed :(");
- return;
- }
- console.log("ibm keyterms: ", kps.toString());
- const headers = [new SchemaHeaderField("title"), new SchemaHeaderField("href")];
- const bodies: Doc[] = [];
- const titles = recs.title_vals;
- const urls = recs.url_vals;
- for (let i = 0; i < 5; i++) {
- const body = Docs.Create.FreeformDocument([], { title: titles[i] });
- body.href = urls[i];
- bodies.push(body);
- }
- this.props.addDocTab(Docs.Create.SchemaDocument(headers, bodies, { title: `Showing External Recommendations for "${StrCast(doc.title)}"` }), "onRight");
- this._showKPQuery = true;
- this._queries = kps.toString();
}
// does Document set a layout prop
@@ -1052,6 +803,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
return this.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false;
}
childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
+ @computed.struct get linkOffset() { return [-15, 0]; }
@computed get contents() {
const pos = this.props.relative ? "relative " : "absolute";
TraceMobx();
@@ -1096,13 +848,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
{this.layoutDoc.hideAllLinks ? (null) : this.allAnchors}
{/* {this.allAnchors} */}
{this.props.forcedBackgroundColor?.(this.Document) === "transparent" || this.layoutDoc.isLinkButton || this.layoutDoc.hideLinkButton || this.props.dontRegisterView ? (null) :
- <DocumentLinksButton View={this} Offset={[-15, 0]} />}
+ <DocumentLinksButton View={this} links={this.allLinks} Offset={this.linkOffset} />}
</div>
);
}
// used to decide whether a link anchor view should be created or not.
- // if it's a tempoarl link (currently just for Audio), then the audioBox will display the anchor and we don't want to display it here.
+ // if it's a temporal link (currently just for Audio), then the audioBox will display the anchor and we don't want to display it here.
// would be good to generalize this some way.
isNonTemporalLink = (linkDoc: Doc) => {
const anchor = Cast(Doc.AreProtosEqual(this.props.Document, Cast(linkDoc.anchor1, Doc) as Doc) ? linkDoc.anchor1 : linkDoc.anchor2, Doc) as Doc;
@@ -1110,7 +862,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
return anchor.type === DocumentType.AUDIO && NumCast(ept) ? false : true;
}
-
@observable _link: Opt<Doc>; // see DocumentButtonBar for explanation of how this works
makeLink = () => this._link; // pass the link placeholde to child views so they can react to make a specialized anchor. This is essentially a function call to the descendants since the value of the _link variable will immediately get set back to undefined.
@@ -1119,13 +870,15 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
anchorPanelWidth = () => this.props.PanelWidth() || 1;
anchorPanelHeight = () => this.props.PanelHeight() || 1;
- @computed get allAnchors() {
+ @computed.struct get directLinks() { return LinkManager.Instance.getAllDirectLinks(this.Document); }
+ @computed.struct get allLinks() { return DocListCast(this.Document.links); }
+ @computed.struct get allAnchors() {
TraceMobx();
if (this.props.LayoutTemplateString?.includes("LinkAnchorBox")) return null;
return (this.props.treeViewDoc && this.props.LayoutTemplateString) || // render nothing for: tree view anchor dots
this.layoutDoc.presBox || // presentationbox nodes
this.props.dontRegisterView ? (null) : // view that are not registered
- DocUtils.FilterDocs(LinkManager.Instance.getAllDirectLinks(this.Document), this.props.docFilters(), []).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) =>
+ DocUtils.FilterDocs(this.directLinks, this.props.docFilters(), []).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) =>
<DocumentView {...this.props} key={i + 1}
Document={d}
ContainingCollectionView={this.props.ContainingCollectionView}
@@ -1202,7 +955,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
DocUtils.makeCustomViewClicked(this.props.Document, Docs.Create.StackingDocument, layout, undefined);
}
}
- @observable _animateScalingTo = 0;
+
switchViews = action((custom: boolean, view: string) => {
this._animateScalingTo = 0.1; // shrink doc
setTimeout(action(() => {
@@ -1216,7 +969,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
return (this.Document.isBackground !== undefined || this.isSelected(false)) &&
((this.Document.type === DocumentType.COL && this.Document._viewType !== CollectionViewType.Pile) || this.Document.type === DocumentType.IMG) &&
this.props.renderDepth > 0 && !this.props.treeViewDoc ?
- <div className="documentView-lock" onClick={() => this.toggleBackground(true)}>
+ <div className="documentView-lock" onClick={this.toggleBackground}>
<FontAwesomeIcon icon={this.Document.isBackground ? "unlock" : "lock"} style={{ color: this.Document.isBackground ? "red" : undefined }} size="lg" />
</div>
: (null);
@@ -1240,7 +993,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid"];
let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc._viewType !== CollectionViewType.Linear && this.props.Document.type !== DocumentType.INK;
highlighting = highlighting && this.props.focus !== emptyFunction; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way
- return <div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
+ const topmost = this.topMost ? "-topmost" : "";
+ return <div className={`documentView-node${topmost}`}
id={this.props.Document[Id]}
ref={this._mainCont} onKeyDown={this.onKeyDown}
onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
@@ -1282,7 +1036,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this.innards}
{this.renderLock()}
</div>;
- { this._showKPQuery ? <KeyphraseQueryView keyphrases={this._queries}></KeyphraseQueryView> : undefined; }
}
}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 5f689624c..d668d332b 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -66,7 +66,7 @@ const uploadIcons = {
@observer
export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageDocument>(ImageDocument) {
- protected multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined;
+ protected _multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined;
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); }
private _imgRef: React.RefObject<HTMLImageElement> = React.createRef();
private _dropDisposer?: DragManager.DragDropDisposer;
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index bc43cd473..1a5edc1d9 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -32,7 +32,7 @@ const ScriptingDocument = makeInterface(ScriptingSchema, documentSchema);
export class ScriptingBox extends ViewBoxAnnotatableComponent<FieldViewProps, ScriptingDocument>(ScriptingDocument) {
private dropDisposer?: DragManager.DragDropDisposer;
- protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined;
+ protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined;
public static LayoutString(fieldStr: string) { return FieldView.LayoutString(ScriptingBox, fieldStr); }
private _overlayDisposer?: () => void;
private _caretPos = 0;
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index 4b2f3cc1a..875142169 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -5,7 +5,25 @@
height:100%;
position: relative;
display: flex;
- .webBox-container, .webBox-container-dragging {
+
+ .pdfViewerDash-dragAnnotationBox {
+ position:absolute;
+ background-color: transparent;
+ opacity: 0.1;
+ }
+ .webBox-annotationLayer {
+ position: absolute;
+ transform-origin: left top;
+ top: 0;
+ width: 100%;
+ pointer-events: none;
+ mix-blend-mode: multiply; // bcz: makes text fuzzy!
+ }
+ .webBox-annotationBox {
+ position: absolute;
+ background-color: rgba(245, 230, 95, 0.616);
+ }
+ .webBox-container {
transform-origin: top left;
width: 100%;
height: 100%;
@@ -46,9 +64,6 @@
top: 0;
left: 0;
overflow: auto;
- .webBox-innerContent {
- width:100%;
- }
}
div.webBox-outerContent::-webkit-scrollbar-thumb {
display:none;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 724044295..d30f1499e 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -1,53 +1,70 @@
-import { library } from "@fortawesome/fontawesome-svg-core";
-import { faStickyNote, faPen, faMousePointer } from '@fortawesome/free-solid-svg-icons';
-import { action, computed, observable, trace, IReactionDisposer, reaction, runInAction } from "mobx";
+import { faMousePointer, faPen, faStickyNote } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, FieldResult, DocListCast } from "../../../fields/Doc";
+import { Dictionary } from "typescript-collections";
+import * as WebRequest from 'web-request';
+import { Doc, DocListCast, Opt } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
+import { Id } from "../../../fields/FieldSymbols";
import { HtmlField } from "../../../fields/HtmlField";
import { InkTool } from "../../../fields/InkField";
-import { makeInterface, listSpec } from "../../../fields/Schema";
-import { Cast, NumCast, BoolCast, StrCast } from "../../../fields/Types";
+import { List } from "../../../fields/List";
+import { listSpec, makeInterface } from "../../../fields/Schema";
+import { Cast, NumCast, StrCast } from "../../../fields/Types";
import { WebField } from "../../../fields/URLField";
-import { Utils, returnOne, emptyFunction, returnZero } from "../../../Utils";
-import { Docs } from "../../documents/Documents";
+import { TraceMobx } from "../../../fields/util";
+import { addStyleSheet, clearStyleSheetRules, emptyFunction, returnOne, returnZero, Utils, returnTrue } from "../../../Utils";
+import { Docs, DocUtils } from "../../documents/Documents";
import { DragManager } from "../../util/DragManager";
import { ImageUtils } from "../../util/Import & Export/ImageUtils";
+import { undoBatch } from "../../util/UndoManager";
+import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
import { ViewBoxAnnotatableComponent } from "../DocComponent";
import { DocumentDecorations } from "../DocumentDecorations";
+import Annotation from "../pdf/Annotation";
+import PDFMenu from "../pdf/PDFMenu";
+import { PdfViewerMarquee } from "../pdf/PDFViewer";
import { FieldView, FieldViewProps } from './FieldView';
import "./WebBox.scss";
+import "../pdf/PDFViewer.scss";
import React = require("react");
-import * as WebRequest from 'web-request';
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
-import { ContextMenu } from "../ContextMenu";
-import { ContextMenuProps } from "../ContextMenuItem";
-import { undoBatch } from "../../util/UndoManager";
-import { List } from "../../../fields/List";
const htmlToText = require("html-to-text");
-library.add(faStickyNote);
-
type WebDocument = makeInterface<[typeof documentSchema]>;
const WebDocument = makeInterface(documentSchema);
@observer
export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocument>(WebDocument) {
+ private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
+ static _annotationStyle: any = addStyleSheet();
+ private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
+ private _startX: number = 0;
+ private _startY: number = 0;
+ @observable private _marqueeX: number = 0;
+ @observable private _marqueeY: number = 0;
+ @observable private _marqueeWidth: number = 0;
+ @observable private _marqueeHeight: number = 0;
+ @observable private _marqueeing: boolean = false;
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); }
get _collapsed() { return StrCast(this.layoutDoc._chromeStatus) !== "enabled"; }
set _collapsed(value) { this.layoutDoc._chromeStatus = !value ? "enabled" : "disabled"; }
@observable private _url: string = "hello";
@observable private _pressX: number = 0;
@observable private _pressY: number = 0;
+ @observable private _savedAnnotations: Dictionary<number, HTMLDivElement[]> = new Dictionary<number, HTMLDivElement[]>();
+ private _selectionReactionDisposer?: IReactionDisposer;
+ private _scrollReactionDisposer?: IReactionDisposer;
+ private _moveReactionDisposer?: IReactionDisposer;
private _keyInput = React.createRef<HTMLInputElement>();
private _longPressSecondsHack?: NodeJS.Timeout;
private _outerRef = React.createRef<HTMLDivElement>();
private _iframeRef = React.createRef<HTMLIFrameElement>();
private _iframeIndicatorRef = React.createRef<HTMLDivElement>();
private _iframeDragRef = React.createRef<HTMLDivElement>();
- private _reactionDisposer?: IReactionDisposer;
private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void);
iframeLoaded = action((e: any) => {
@@ -60,21 +77,24 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
iframe.contentDocument.children[0].scrollTop = NumCast(this.layoutDoc._scrollTop);
iframe.contentDocument.children[0].scrollLeft = NumCast(this.layoutDoc._scrollLeft);
}
- this._reactionDisposer?.();
- this._reactionDisposer = reaction(() => ({ y: this.layoutDoc._scrollY, x: this.layoutDoc._scrollX }),
- ({ x, y }) => {
- if (y !== undefined) {
- this._outerRef.current!.scrollTop = y;
- this.layoutDoc._scrollY = undefined;
- }
- if (x !== undefined) {
- this._outerRef.current!.scrollLeft = x;
- this.layoutDoc.scrollX = undefined;
- }
- },
+ this._scrollReactionDisposer?.();
+ this._scrollReactionDisposer = reaction(() => ({ y: this.layoutDoc._scrollY, x: this.layoutDoc._scrollX }),
+ ({ x, y }) => this.updateScroll(x, y),
{ fireImmediately: true }
);
});
+
+ updateScroll = (x: Opt<number>, y: Opt<number>) => {
+ if (y !== undefined) {
+ this._outerRef.current!.scrollTop = y;
+ this.layoutDoc._scrollY = undefined;
+ }
+ if (x !== undefined) {
+ this._outerRef.current!.scrollLeft = x;
+ this.layoutDoc.scrollX = undefined;
+ }
+ }
+
setPreviewCursor = (func?: (x: number, y: number, drag: boolean) => void) => this._setPreviewCursor = func;
iframedown = (e: PointerEvent) => {
this._setPreviewCursor?.(e.screenX, e.screenY, false);
@@ -89,6 +109,19 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
const urlField = Cast(this.dataDoc[this.props.fieldKey], WebField);
runInAction(() => this._url = urlField?.url.toString() || "");
+ this._moveReactionDisposer = reaction(() => this.layoutDoc.x || this.layoutDoc.y,
+ () => this.updateScroll(this.layoutDoc._scrollLeft, this.layoutDoc._scrollTop));
+
+ this._selectionReactionDisposer = reaction(() => this.props.isSelected(),
+ selected => {
+ if (!selected) {
+ this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove()));
+ this._savedAnnotations.keys().forEach(k => this._savedAnnotations.setValue(k, []));
+ PDFMenu.Instance.fadeOut(true);
+ }
+ },
+ { fireImmediately: true });
+
document.addEventListener("pointerup", this.onLongPressUp);
document.addEventListener("pointermove", this.onLongPressMove);
const field = Cast(this.rootDoc[this.props.fieldKey], WebField);
@@ -112,7 +145,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
}
componentWillUnmount() {
- this._reactionDisposer?.();
+ this._moveReactionDisposer?.();
+ this._selectionReactionDisposer?.();
+ this._scrollReactionDisposer?.();
document.removeEventListener("pointerup", this.onLongPressUp);
document.removeEventListener("pointermove", this.onLongPressMove);
this._iframeRef.current?.contentDocument?.removeEventListener('pointerdown', this.iframedown);
@@ -267,11 +302,14 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
);
}
+
@action
toggleCollapse = () => {
this._collapsed = !this._collapsed;
}
+
+
_ignore = 0;
onPreWheel = (e: React.WheelEvent) => {
this._ignore = e.timeStamp;
@@ -284,6 +322,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
e.stopPropagation();
}
}
+
onPostWheel = (e: React.WheelEvent) => {
if (this._ignore !== e.timeStamp) {
e.stopPropagation();
@@ -430,6 +469,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
return (<>
<div className={"webBox-cont" + (this.props.isSelected() && Doc.GetSelectedTool() === InkTool.None && !decInteracting ? "-interactive" : "")}
+ style={{ width: Number.isFinite(this.props.ContentScaling()) ? `${Math.max(100, 100 / this.props.ContentScaling())}% ` : "100%" }}
onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
{view}
</div>;
@@ -444,11 +484,198 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
{this.urlEditor()}
</>);
}
+
+
+
+ @computed get allAnnotations() { return DocListCast(this.dataDoc[this.props.fieldKey + "-annotations"]); }
+ @computed get nonDocAnnotations() { return this.allAnnotations.filter(a => a.annotations); }
+
+ @undoBatch
+ @action
+ makeAnnotationDocument = (color: string): Opt<Doc> => {
+ if (this._savedAnnotations.size() === 0) return undefined;
+ const anno = this._savedAnnotations.values()[0][0];
+ const annoDoc = Docs.Create.FreeformDocument([], { backgroundColor: color, annotationOn: this.props.Document, title: "Annotation on " + this.Document.title });
+ if (anno.style.left) annoDoc.x = parseInt(anno.style.left);
+ if (anno.style.top) annoDoc.y = NumCast(this.layoutDoc._scrollTop) + parseInt(anno.style.top);
+ if (anno.style.height) annoDoc._height = parseInt(anno.style.height);
+ if (anno.style.width) annoDoc._width = parseInt(anno.style.width);
+ anno.remove();
+ this._savedAnnotations.clear();
+ return annoDoc;
+ }
+ @computed get annotationLayer() {
+ TraceMobx();
+ return <div className="webBox-annotationLayer" style={{ height: NumCast(this.Document._nativeHeight) }} ref={this._annotationLayer}>
+ {this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno =>
+ <Annotation {...this.props} focus={this.props.focus} dataDoc={this.dataDoc} fieldKey={this.props.fieldKey} anno={anno} key={`${anno[Id]}-annotation`} />)
+ }
+ </div>;
+ }
+ @action
+ createAnnotation = (div: HTMLDivElement, page: number) => {
+ if (this._annotationLayer.current) {
+ if (div.style.top) {
+ div.style.top = (parseInt(div.style.top)).toString();
+ }
+ this._annotationLayer.current.append(div);
+ div.style.backgroundColor = "#ACCEF7";
+ div.style.opacity = "0.5";
+ const savedPage = this._savedAnnotations.getValue(page);
+ if (savedPage) {
+ savedPage.push(div);
+ this._savedAnnotations.setValue(page, savedPage);
+ }
+ else {
+ this._savedAnnotations.setValue(page, [div]);
+ }
+ }
+ }
+
+ @action
+ highlight = (color: string) => {
+ // creates annotation documents for current highlights
+ const annotationDoc = this.makeAnnotationDocument(color);
+ annotationDoc && Doc.AddDocToList(this.props.Document, this.annotationKey, annotationDoc);
+ return annotationDoc;
+ }
+ /**
+ * This is temporary for creating annotations from highlights. It will
+ * start a drag event and create or put the necessary info into the drag event.
+ */
+ @action
+ startDrag = async (e: PointerEvent, ele: HTMLElement) => {
+ e.preventDefault();
+ e.stopPropagation();
+
+ const clipDoc = Doc.MakeAlias(this.dataDoc);
+ clipDoc._fitWidth = true;
+ clipDoc._width = this.marqueeWidth();
+ clipDoc._height = this.marqueeHeight();
+ clipDoc._scrollTop = this.marqueeY();
+ const targetDoc = Docs.Create.TextDocument("", { _width: 125, _height: 125, title: "Note linked to " + this.props.Document.title });
+ Doc.GetProto(targetDoc).data = new List<Doc>([clipDoc]);
+ clipDoc.rootDocument = targetDoc;
+ targetDoc.layoutKey = "layout";
+ const annotationDoc = this.highlight("rgba(146, 245, 95, 0.467)"); // yellowish highlight color when dragging out a text selection
+ if (annotationDoc) {
+ DragManager.StartPdfAnnoDrag([ele], new DragManager.PdfAnnoDragData(this.props.Document, annotationDoc, targetDoc), e.pageX, e.pageY, {
+ dragComplete: e => {
+ if (!e.aborted && e.annoDragData && !e.annoDragData.linkedToDoc) {
+ DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
+ annotationDoc.isLinkButton = true;
+ }
+ }
+ });
+ }
+ }
+ @action
+ onMarqueeDown = (e: React.PointerEvent) => {
+ this._marqueeing = false;
+ if (!e.altKey && e.button === 0 && this.active(true)) {
+ // clear out old marquees and initialize menu for new selection
+ PDFMenu.Instance.StartDrag = this.startDrag;
+ PDFMenu.Instance.Highlight = this.highlight;
+ PDFMenu.Instance.Status = "pdf";
+ PDFMenu.Instance.fadeOut(true);
+ this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove()));
+ this._savedAnnotations.keys().forEach(k => this._savedAnnotations.setValue(k, []));
+ if ((e.target as any)?.parentElement.className === "textLayer") {
+ // start selecting text if mouse down on textLayer spans
+ }
+ else if (this._mainCont.current) {
+ // set marquee x and y positions to the spatially transformed position
+ const boundingRect = this._mainCont.current.getBoundingClientRect();
+ const boundingHeight = (this.Document._nativeHeight || 1) / (this.Document._nativeWidth || 1) * boundingRect.width;
+ this._startX = (e.clientX - boundingRect.left) / boundingRect.width * (this.Document._nativeWidth || 1);
+ this._startY = (e.clientY - boundingRect.top) / boundingHeight * (this.Document._nativeHeight || 1);
+ this._marqueeHeight = this._marqueeWidth = 0;
+ this._marqueeing = true;
+ }
+ document.removeEventListener("pointermove", this.onSelectMove);
+ document.addEventListener("pointermove", this.onSelectMove);
+ document.removeEventListener("pointerup", this.onSelectEnd);
+ document.addEventListener("pointerup", this.onSelectEnd);
+ }
+ }
+ @action
+ onSelectMove = (e: PointerEvent): void => {
+ if (this._marqueeing && this._mainCont.current) {
+ // transform positions and find the width and height to set the marquee to
+ const boundingRect = this._mainCont.current.getBoundingClientRect();
+ const boundingHeight = (this.Document._nativeHeight || 1) / (this.Document._nativeWidth || 1) * boundingRect.width;
+ const curX = (e.clientX - boundingRect.left) / boundingRect.width * (this.Document._nativeWidth || 1);
+ const curY = (e.clientY - boundingRect.top) / boundingHeight * (this.Document._nativeHeight || 1);
+ this._marqueeWidth = curX - this._startX;
+ this._marqueeHeight = curY - this._startY;
+ this._marqueeX = Math.min(this._startX, this._startX + this._marqueeWidth);
+ this._marqueeY = Math.min(this._startY, this._startY + this._marqueeHeight);
+ this._marqueeWidth = Math.abs(this._marqueeWidth);
+ this._marqueeHeight = Math.abs(this._marqueeHeight);
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ else if (e.target && (e.target as any).parentElement === this._mainCont.current) {
+ e.stopPropagation();
+ }
+ }
+
+ @action
+ onSelectEnd = (e: PointerEvent): void => {
+ clearStyleSheetRules(WebBox._annotationStyle);
+ this._savedAnnotations.clear();
+ if (this._marqueeWidth > 10 || this._marqueeHeight > 10) {
+ const marquees = this._mainCont.current!.getElementsByClassName("pdfViewerDash-dragAnnotationBox");
+ if (marquees?.length) { // copy the marquee and convert it to a permanent annotation.
+ const style = (marquees[0] as HTMLDivElement).style;
+ const copy = document.createElement("div");
+ copy.style.left = style.left;
+ copy.style.top = style.top;
+ copy.style.width = style.width;
+ copy.style.height = style.height;
+ copy.style.border = style.border;
+ copy.style.opacity = style.opacity;
+ (copy as any).marqueeing = true;
+ copy.className = "webBox-annotationBox";
+ this.createAnnotation(copy, 0);
+ }
+
+ if (!e.ctrlKey) {
+ PDFMenu.Instance.Marquee = { left: this._marqueeX, top: this._marqueeY, width: this._marqueeWidth, height: this._marqueeHeight };
+ }
+ PDFMenu.Instance.jumpTo(e.clientX, e.clientY);
+ }
+ //this._marqueeing = false;
+
+ if (PDFMenu.Instance.Highlighting) {// when highlighter has been toggled when menu is pinned, we auto-highlight immediately on mouse up
+ this.highlight("rgba(245, 230, 95, 0.616)"); // yellowish highlight color for highlighted text (should match PDFMenu's highlight color)
+ }
+ else {
+ PDFMenu.Instance.StartDrag = this.startDrag;
+ PDFMenu.Instance.Highlight = this.highlight;
+ }
+ document.removeEventListener("pointermove", this.onSelectMove);
+ document.removeEventListener("pointerup", this.onSelectEnd);
+ }
+ marqueeWidth = () => this._marqueeWidth;
+ marqueeHeight = () => this._marqueeHeight;
+ marqueeX = () => this._marqueeX;
+ marqueeY = () => this._marqueeY;
+ marqueeing = () => this._marqueeing;
+ visibleHeiht = () => {
+ if (this._mainCont.current) {
+ const boundingRect = this._mainCont.current.getBoundingClientRect();
+ const scalin = (this.Document._nativeWidth || 0) / boundingRect.width;
+ return Math.min(boundingRect.height * scalin, this.props.PanelHeight() * scalin);
+ }
+ return this.props.PanelHeight();
+ }
scrollXf = () => this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc._scrollLeft), NumCast(this.layoutDoc._scrollTop));
render() {
- return (<div className="webBox" style={{ width: Number.isFinite(this.props.ContentScaling()) ? `${Math.max(100, 100 / this.props.ContentScaling())}% ` : "100%" }}>
+ return (<div className="webBox" ref={this._mainCont} >
<div className={`webBox-container`}
style={{
+ position: undefined,
transform: `scale(${this.props.ContentScaling()})`,
width: Number.isFinite(this.props.ContentScaling()) ? `${100 / this.props.ContentScaling()}% ` : "100%",
height: Number.isFinite(this.props.ContentScaling()) ? `${100 / this.props.ContentScaling()}% ` : "100%",
@@ -458,8 +685,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
<base target="_blank" />
{this.content}
<div className={"webBox-outerContent"} ref={this._outerRef}
- style={{ pointerEvents: this.layoutDoc.isAnnotating && !this.layoutDoc.isBackground ? "all" : "none" }}
+ style={{
+ width: Number.isFinite(this.props.ContentScaling()) ? `${Math.max(100, 100 / this.props.ContentScaling())}% ` : "100%",
+ pointerEvents: this.layoutDoc.isAnnotating && !this.layoutDoc.isBackground ? "all" : "none"
+ }}
onWheel={e => e.stopPropagation()}
+ onPointerDown={this.onMarqueeDown}
onScroll={e => {
const iframe = this._iframeRef?.current?.contentDocument;
const outerFrame = this._outerRef.current;
@@ -473,13 +704,17 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
}
//this._outerRef.current!.scrollTop !== this._scrollTop && (this._outerRef.current!.scrollTop = this._scrollTop)
}}>
- <div className={"webBox-innerContent"} style={{ height: NumCast(this.layoutDoc.scrollHeight), width: 4000 }}>
+ <div className={"webBox-innerContent"} style={{
+ height: NumCast(this.layoutDoc.scrollHeight),
+ pointerEvents: this.layoutDoc.isBackground ? "none" : undefined
+ }}>
<CollectionFreeFormView {...this.props}
PanelHeight={this.props.PanelHeight}
PanelWidth={this.props.PanelWidth}
annotationsKey={this.annotationKey}
NativeHeight={returnZero}
NativeWidth={returnZero}
+ VisibleHeight={this.visibleHeiht}
focus={this.props.focus}
setPreviewCursor={this.setPreviewCursor}
isSelected={this.props.isSelected}
@@ -499,6 +734,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
</CollectionFreeFormView>
</div>
</div>
+ {this.annotationLayer}
+ <PdfViewerMarquee isMarqueeing={this.marqueeing} width={this.marqueeWidth} height={this.marqueeHeight} x={this.marqueeX} y={this.marqueeY} />
</div >
</div>);
}
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 8718bf329..958a37568 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -205,9 +205,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
{this._fieldKey}
</span>}
- {/* <div className="dashFieldView-fieldSpan"> */}
- {this.fieldValueContent}
- {/* </div> */}
+ {this.props.fieldKey.startsWith("#") ? (null) : this.fieldValueContent}
{!this._showEnumerables ? (null) : <div className="dashFieldView-enumerables" onPointerDown={this.onPointerDownEnumerables} />}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 974dabd5c..3d389cf87 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -223,7 +223,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
const state = this._editorView.state.apply(tx);
this._editorView.updateState(state);
- (tx.storedMarks && !this._editorView.state.storedMarks) && (this._editorView.state.storedMarks = tx.storedMarks);
const tsel = this._editorView.state.selection.$from;
tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 1000)));
@@ -741,7 +740,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._disposers.search = reaction(() => this.rootDoc.searchMatch,
search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(),
- { fireImmediately: true });
+ { fireImmediately: this.rootDoc.searchMatch ? true : false });
this._disposers.record = reaction(() => this._recording,
() => {
@@ -994,7 +993,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
clipboardTextSerializer: this.clipboardTextSerializer,
handlePaste: this.handlePaste,
});
- !Doc.UserDoc().noviceMode && applyDevTools.applyDevTools(this._editorView);
+ // !Doc.UserDoc().noviceMode && applyDevTools.applyDevTools(this._editorView);
const startupText = !rtfField && this._editorView && Field.toString(this.dataDoc[fieldKey] as Field);
if (startupText) {
const { state: { tr }, dispatch } = this._editorView;
@@ -1011,10 +1010,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
FormattedTextBox.SelectOnLoadChar = "";
}
- (selectOnLoad /* || !rtfField?.Text*/) && this._editorView!.focus();
+ selectOnLoad && this._editorView!.focus();
// add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet.
- if (!this._editorView!.state.storedMarks || !this._editorView!.state.storedMarks.some(mark => mark.type === schema.marks.user_mark)) {
- this._editorView!.state.storedMarks = [...(this._editorView!.state.storedMarks ? this._editorView!.state.storedMarks : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })];
+ if (!this._editorView!.state.storedMarks?.some(mark => mark.type === schema.marks.user_mark)) {
+ this._editorView!.state.storedMarks = [...(this._editorView!.state.storedMarks ?? []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })];
}
}
getFont(font: string) {
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index ef0fead4a..dc1d8a2c8 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -317,13 +317,12 @@ export class RichTextRules {
// create an inline view of a tag stored under the '#' field
new InputRule(
- new RegExp(/#([a-zA-Z_\-]+[a-zA-Z_;\-0-9]*)\s$/),
+ new RegExp(/#([a-zA-Z_\-]+[a-zA-Z_\-0-9]*)\s$/),
(state, match, start, end) => {
const tag = match[1];
if (!tag) return state.tr;
- const multiple = tag.split(";");
- this.Document[DataSym]["#"] = multiple.length > 1 ? new List(multiple) : tag;
- const fieldView = state.schema.nodes.dashField.create({ fieldKey: "#" });
+ this.Document[DataSym]["#" + tag] = ".";
+ const fieldView = state.schema.nodes.dashField.create({ fieldKey: "#" + tag });
return state.tr.deleteRange(start, end).insert(start, fieldView);
}),