aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/DocServer.ts80
-rw-r--r--src/client/util/DocumentManager.ts44
-rw-r--r--src/client/util/GroupManager.tsx36
-rw-r--r--src/client/util/SharingManager.tsx46
-rw-r--r--src/client/views/DocComponent.tsx5
-rw-r--r--src/client/views/DocumentDecorations.scss5
-rw-r--r--src/client/views/DocumentDecorations.tsx4
-rw-r--r--src/client/views/MainView.tsx4
-rw-r--r--src/client/views/collections/CollectionView.tsx12
-rw-r--r--src/client/views/collections/ParentDocumentSelector.tsx22
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx8
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx4
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx20
-rw-r--r--src/client/views/nodes/DocumentView.tsx25
-rw-r--r--src/client/views/nodes/LinkCreatedBox.tsx31
-rw-r--r--src/client/views/nodes/LinkDescriptionPopup.tsx4
-rw-r--r--src/client/views/nodes/TaskCompletedBox.scss (renamed from src/client/views/nodes/LinkCreatedBox.scss)3
-rw-r--r--src/client/views/nodes/TaskCompletedBox.tsx32
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx9
19 files changed, 230 insertions, 164 deletions
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index bac324c77..8ded43468 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -1,13 +1,14 @@
import * as io from 'socket.io-client';
import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent } from "./../server/Message";
-import { Opt, Doc, fetchProto } from '../fields/Doc';
+import { Opt, Doc, fetchProto, FieldsSym } from '../fields/Doc';
import { Utils, emptyFunction } from '../Utils';
import { SerializationHelper } from './util/SerializationHelper';
import { RefField } from '../fields/RefField';
-import { Id, HandleUpdate } from '../fields/FieldSymbols';
+import { Id, HandleUpdate, Parent } from '../fields/FieldSymbols';
import GestureOverlay from './views/GestureOverlay';
import MobileInkOverlay from '../mobile/MobileInkOverlay';
import { runInAction } from 'mobx';
+import { ObjectField } from '../fields/ObjectField';
/**
* This class encapsulates the transfer and cross-client synchronization of
@@ -207,12 +208,12 @@ export namespace DocServer {
* the server if the document has not been cached.
* @param id the id of the requested document
*/
- const _GetRefFieldImpl = (id: string): Promise<Opt<RefField>> => {
+ const _GetRefFieldImpl = (id: string, force: boolean = false): Promise<Opt<RefField>> => {
// an initial pass through the cache to determine whether the document needs to be fetched,
// is already in the process of being fetched or already exists in the
// cache
const cached = _cache[id];
- if (cached === undefined) {
+ if (cached === undefined || force) {
// NOT CACHED => we'll have to send a request to the server
// synchronously, we emit a single callback to the server requesting the serialized (i.e. represented by a string)
@@ -226,7 +227,16 @@ export namespace DocServer {
const deserializeField = getSerializedField.then(async fieldJson => {
// deserialize
const field = await SerializationHelper.Deserialize(fieldJson);
- if (field !== undefined) {
+ if (force && field instanceof Doc && cached instanceof Doc) {
+ Array.from(Object.keys(field)).forEach(key => {
+ const fieldval = field[key];
+ if (fieldval instanceof ObjectField) {
+ fieldval[Parent] = undefined;
+ }
+ cached[key] = field[key];
+ });
+ }
+ else if (field !== undefined) {
_cache[id] = field;
} else {
delete _cache[id];
@@ -238,8 +248,8 @@ export namespace DocServer {
});
// here, indicate that the document associated with this id is currently
// being retrieved and cached
- _cache[id] = deserializeField;
- return deserializeField;
+ !force && (_cache[id] = deserializeField);
+ return force ? cached as any : deserializeField;
} else if (cached instanceof Promise) {
// BEING RETRIEVED AND CACHED => some other caller previously (likely recently) called GetRefField(s),
// and requested the document I'm looking for. Shouldn't fetch again, just
@@ -260,11 +270,11 @@ export namespace DocServer {
}
};
- let _GetRefField: (id: string) => Promise<Opt<RefField>> = errorFunc;
+ let _GetRefField: (id: string, force: boolean) => Promise<Opt<RefField>> = errorFunc;
let _GetCachedRefField: (id: string) => Opt<RefField> = errorFunc;
- export function GetRefField(id: string): Promise<Opt<RefField>> {
- return _GetRefField(id);
+ export function GetRefField(id: string, force = false): Promise<Opt<RefField>> {
+ return _GetRefField(id, force);
}
export function GetCachedRefField(id: string): Opt<RefField> {
return _GetCachedRefField(id);
@@ -330,29 +340,35 @@ export namespace DocServer {
const proms: Promise<void>[] = [];
runInAction(() => {
for (const field of fields) {
- if (field !== undefined && field !== null) {
+ if (field !== undefined && field !== null && !_cache[field.id]) {
// deserialize
- const prom = SerializationHelper.Deserialize(field).then(deserialized => {
- fieldMap[field.id] = deserialized;
-
- //overwrite or delete any promises (that we inserted as flags
- // to indicate that the field was in the process of being fetched). Now everything
- // should be an actual value within or entirely absent from the cache.
- if (deserialized !== undefined) {
- _cache[field.id] = deserialized;
- } else {
- delete _cache[field.id];
- }
- return deserialized;
- });
- // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache)
- // we set the value at the field's id to a promise that will resolve to the field.
- // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method).
- // The mapping in the .then call ensures that when other callers await these promises, they'll
- // get the resolved field
- _cache[field.id] = prom;
- // adds to a list of promises that will be awaited asynchronously
- proms.push(prom);
+ const cached = _cache[field.id];
+ if (!cached) {
+ const prom = SerializationHelper.Deserialize(field).then(deserialized => {
+ fieldMap[field.id] = deserialized;
+
+ //overwrite or delete any promises (that we inserted as flags
+ // to indicate that the field was in the process of being fetched). Now everything
+ // should be an actual value within or entirely absent from the cache.
+ if (deserialized !== undefined) {
+ _cache[field.id] = deserialized;
+ } else {
+ delete _cache[field.id];
+ }
+ return deserialized;
+ });
+ // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache)
+ // we set the value at the field's id to a promise that will resolve to the field.
+ // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method).
+ // The mapping in the .then call ensures that when other callers await these promises, they'll
+ // get the resolved field
+ _cache[field.id] = prom;
+
+ // adds to a list of promises that will be awaited asynchronously
+ proms.push(prom);
+ } else if (cached instanceof Promise) {
+ proms.push(cached as any);
+ }
}
}
});
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 51b50878d..523dbfca0 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -152,18 +152,18 @@ export class DocumentManager {
const first = getFirstDocView(annotatedDoc);
if (first) {
annotatedDoc = first.props.Document;
- if (docView) {
- docView.props.focus(annotatedDoc, false);
- }
+ docView?.props.focus(annotatedDoc, false);
}
}
if (docView) { // we have a docView already and aren't forced to create a new one ... just focus on the document. TODO move into view if necessary otherwise just highlight?
- if (originatingDoc?.isPushpin) docView.props.Document.hidden = !docView.props.Document.hidden;
+ if (originatingDoc?.isPushpin) {
+ docView.props.Document.hidden = !docView.props.Document.hidden;
+ }
else {
docView.props.Document.hidden && (docView.props.Document.hidden = undefined);
docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish);
+ highlight();
}
- highlight();
} else {
const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined;
const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc)) ? docContext : undefined;
@@ -218,25 +218,27 @@ export class DocumentManager {
const backLinkWithoutTargetView = secondDocs.find(d => DocumentManager.Instance.getDocumentViews(d.anchor1 as Doc).length === 0);
const linkWithoutTargetDoc = traverseBacklink === undefined ? fwdLinkWithoutTargetView || backLinkWithoutTargetView : traverseBacklink ? backLinkWithoutTargetView : fwdLinkWithoutTargetView;
const linkDocList = linkWithoutTargetDoc ? [linkWithoutTargetDoc] : (traverseBacklink === undefined ? firstDocs.concat(secondDocs) : traverseBacklink ? secondDocs : firstDocs);
- const linkDoc = linkDocList.length && linkDocList[0];
- if (linkDoc) {
- const target = (doc === linkDoc.anchor1 ? linkDoc.anchor2 : doc === linkDoc.anchor2 ? linkDoc.anchor1 :
- (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? linkDoc.anchor2 : linkDoc.anchor1)) as Doc;
- const targetTimecode = (doc === linkDoc.anchor1 ? Cast(linkDoc.anchor2_timecode, "number") :
- doc === linkDoc.anchor2 ? Cast(linkDoc.anchor1_timecode, "number") :
- (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? Cast(linkDoc.anchor2_timecode, "number") : Cast(linkDoc.anchor1_timecode, "number")));
- if (target) {
- const containerDoc = (await Cast(target.annotationOn, Doc)) || target;
- containerDoc.currentTimecode = targetTimecode;
- const targetContext = await target?.context as Doc;
- const targetNavContext = !Doc.AreProtosEqual(targetContext, currentContext) ? targetContext : undefined;
- DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "onRight"), finished), targetNavContext, linkDoc, undefined, doc, finished);
+ const followLinks = linkDocList.length ? (doc.isPushpin ? linkDocList : [linkDocList[0]]) : [];
+ followLinks.forEach(async linkDoc => {
+ if (linkDoc) {
+ const target = (doc === linkDoc.anchor1 ? linkDoc.anchor2 : doc === linkDoc.anchor2 ? linkDoc.anchor1 :
+ (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? linkDoc.anchor2 : linkDoc.anchor1)) as Doc;
+ const targetTimecode = (doc === linkDoc.anchor1 ? Cast(linkDoc.anchor2_timecode, "number") :
+ doc === linkDoc.anchor2 ? Cast(linkDoc.anchor1_timecode, "number") :
+ (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? Cast(linkDoc.anchor2_timecode, "number") : Cast(linkDoc.anchor1_timecode, "number")));
+ if (target) {
+ const containerDoc = (await Cast(target.annotationOn, Doc)) || target;
+ containerDoc.currentTimecode = targetTimecode;
+ const targetContext = await target?.context as Doc;
+ const targetNavContext = !Doc.AreProtosEqual(targetContext, currentContext) ? targetContext : undefined;
+ DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "onRight"), finished), targetNavContext, linkDoc, undefined, doc, finished);
+ } else {
+ finished?.();
+ }
} else {
finished?.();
}
- } else {
- finished?.();
- }
+ });
}
}
Scripting.addGlobal(function DocFocus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)); }); \ No newline at end of file
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index 2e5ecc543..72fba5c1b 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -16,6 +16,7 @@ import { StrCast, Cast } from "../../fields/Types";
import GroupMemberView from "./GroupMemberView";
import { setGroups } from "../../fields/util";
import { DocServer } from "../DocServer";
+import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox";
library.add(fa.faPlus, fa.faTimes, fa.faInfoCircle);
@@ -36,11 +37,13 @@ export default class GroupManager extends React.Component<{}> {
@observable currentGroup: Opt<Doc>; // the currently selected group.
@observable private createGroupModalOpen: boolean = false;
private inputRef: React.RefObject<HTMLInputElement> = React.createRef(); // the ref for the input box.
+ private createGroupButtonRef: React.RefObject<HTMLButtonElement> = React.createRef();
private currentUserGroups: string[] = [];
@observable private buttonColour: "#979797" | "black" = "#979797";
@observable private groupSort: "ascending" | "descending" | "none" = "none";
+
constructor(props: Readonly<{}>) {
super(props);
GroupManager.Instance = this;
@@ -48,6 +51,7 @@ export default class GroupManager extends React.Component<{}> {
componentDidMount() {
this.populateUsers();
+ this.populateGroups();
}
/**
@@ -74,6 +78,17 @@ export default class GroupManager extends React.Component<{}> {
return Promise.all(evaluating);
}
+ populateGroups = () => {
+ DocListCastAsync(this.GroupManagerDoc?.data).then(groups => {
+ groups?.forEach(group => {
+ const members: string[] = JSON.parse(StrCast(group.members));
+ if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(StrCast(group.groupName));
+ });
+
+ setGroups(this.currentUserGroups);
+ });
+ }
+
/**
* @returns the options to be rendered in the dropdown menu to add users and create a group.
*/
@@ -89,14 +104,7 @@ export default class GroupManager extends React.Component<{}> {
SelectionManager.DeselectAll();
this.isOpen = true;
this.populateUsers();
- DocListCastAsync(this.GroupManagerDoc?.data).then(groups => {
- groups?.forEach(group => {
- const members: string[] = JSON.parse(StrCast(group.members));
- if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(StrCast(group.groupName));
- });
-
- setGroups(this.currentUserGroups);
- });
+ this.populateGroups();
}
/**
@@ -298,6 +306,14 @@ export default class GroupManager extends React.Component<{}> {
this.selectedUsers = null;
this.inputRef.current.value = "";
this.buttonColour = "#979797";
+
+ const { left, width, top } = this.createGroupButtonRef.current!.getBoundingClientRect();
+ TaskCompletionBox.popupX = left - 2 * width;
+ TaskCompletionBox.popupY = top;
+ TaskCompletionBox.textDisplayed = "Group created!";
+ TaskCompletionBox.taskCompleted = true;
+ setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2000);
+
}
private get groupCreationModal() {
@@ -340,7 +356,9 @@ export default class GroupManager extends React.Component<{}> {
})
}}
/>
- <button onClick={this.createGroup}
+ <button
+ ref={this.createGroupButtonRef}
+ onClick={this.createGroup}
style={{ background: this.buttonColour }}
disabled={this.buttonColour === "#979797"}
>
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 9c857a7c0..452a58d21 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -20,7 +20,8 @@ import GroupMemberView from "./GroupMemberView";
import Select from "react-select";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { List } from "../../fields/List";
-import { distributeAcls } from "../../fields/util";
+import { distributeAcls, SharingPermissions } from "../../fields/util";
+import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox";
library.add(fa.faCopy, fa.faTimes);
@@ -29,13 +30,6 @@ export interface User {
userDocumentId: string;
}
-export enum SharingPermissions {
- Edit = "Can Edit",
- Add = "Can Add",
- View = "Can View",
- None = "Not Shared"
-}
-
interface GroupOptions {
label: string;
options: UserOptions[];
@@ -69,6 +63,8 @@ export default class SharingManager extends React.Component<{}> {
@observable private permissions: SharingPermissions = SharingPermissions.Edit;
@observable private individualSort: "ascending" | "descending" | "none" = "none";
@observable private groupSort: "ascending" | "descending" | "none" = "none";
+ private shareDocumentButtonRef: React.RefObject<HTMLButtonElement> = React.createRef();
+
// private get linkVisible() {
@@ -90,6 +86,8 @@ export default class SharingManager extends React.Component<{}> {
public close = action(() => {
this.isOpen = false;
this.users = [];
+ this.selectedUsers = null;
+
setTimeout(action(() => {
// this.copied = false;
DictationOverlay.Instance.hasActiveModal = false;
@@ -235,7 +233,7 @@ export default class SharingManager extends React.Component<{}> {
private get sharingOptions() {
return Object.values(SharingPermissions).map(permission => {
return (
- <option key={permission} value={permission}>
+ <option key={permission} value={permission} selected={permission === SharingPermissions.Edit}>
{permission}
</option>
);
@@ -284,15 +282,25 @@ export default class SharingManager extends React.Component<{}> {
@action
share = () => {
- this.selectedUsers?.forEach(user => {
- if (user.value.includes(indType)) {
- this.setInternalSharing(this.users.find(u => u.user.email === user.label)!, this.permissions);
- }
- else {
- this.setInternalGroupSharing(GroupManager.Instance.getGroup(user.label)!, this.permissions);
- }
- });
- this.selectedUsers = null;
+ if (this.selectedUsers) {
+ this.selectedUsers.forEach(user => {
+ if (user.value.includes(indType)) {
+ this.setInternalSharing(this.users.find(u => u.user.email === user.label)!, this.permissions);
+ }
+ else {
+ this.setInternalGroupSharing(GroupManager.Instance.getGroup(user.label)!, this.permissions);
+ }
+ });
+
+ const { left, width, top, height } = this.shareDocumentButtonRef.current!.getBoundingClientRect();
+ TaskCompletionBox.popupX = left - 1.5 * width;
+ TaskCompletionBox.popupY = top - height;
+ TaskCompletionBox.textDisplayed = "Document shared!";
+ TaskCompletionBox.taskCompleted = true;
+ setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2000);
+
+ this.selectedUsers = null;
+ }
}
sortUsers = (u1: ValidatedUser, u2: ValidatedUser) => {
@@ -456,7 +464,7 @@ export default class SharingManager extends React.Component<{}> {
<select className="permissions-select" onChange={this.handlePermissionsChange}>
{this.sharingOptions}
</select>
- <button className="share-button" onClick={this.share}>
+ <button ref={this.shareDocumentButtonRef} className="share-button" onClick={this.share}>
Share
</button>
</div>
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 95c1bcda8..cfabae8a1 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -7,8 +7,7 @@ import { InteractionUtils } from '../util/InteractionUtils';
import { List } from '../../fields/List';
import { DateField } from '../../fields/DateField';
import { ScriptField } from '../../fields/ScriptField';
-import { GetEffectiveAcl, getPlaygroundMode } from '../../fields/util';
-import { SharingPermissions } from '../util/SharingManager';
+import { GetEffectiveAcl, getPlaygroundMode, SharingPermissions } from '../../fields/util';
/// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView)
@@ -151,7 +150,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
const effectiveAcl = GetEffectiveAcl(this.dataDoc);
if (added.length) {
- if (effectiveAcl === AclReadonly && !getPlaygroundMode()) {
+ if (effectiveAcl === AclPrivate || (effectiveAcl === AclReadonly && !getPlaygroundMode())) {
return false;
}
else {
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 5948ada88..424a06431 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -157,6 +157,7 @@ $linkGap : 3px;
grid-column-end: 2;
pointer-events: all;
padding-left: 5px;
+ cursor: pointer;
}
.documentDecorations-title {
@@ -204,7 +205,7 @@ $linkGap : 3px;
width: 20px;
}
-.documentDecorations-closeButton {
+.documentDecorations-openInTab {
opacity: 1;
grid-column-start: 4;
grid-column-end: 5;
@@ -216,7 +217,7 @@ $linkGap : 3px;
margin-top: auto;
}
-.documentDecorations-minimizeButton {
+.documentDecorations-closeButton {
opacity: 1;
grid-column-start: 1;
grid-column-end: 3;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index d30adc5a2..d92b1366b 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -550,8 +550,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
<div className="documentDecorations-contextMenu" onPointerDown={this.onSettingsDown}>
<FontAwesomeIcon size="lg" icon="cog" />
</div></Tooltip>) : (
- <Tooltip title={<><div className="dash-tooltip">Iconify</div></>} placement="top">
- <div className="documentDecorations-minimizeButton" onClick={this.onCloseClick}>
+ <Tooltip title={<><div className="dash-tooltip">Delete</div></>} placement="top">
+ <div className="documentDecorations-closeButton" onClick={this.onCloseClick}>
{/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
<FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
</div></Tooltip>);
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 734b45dd0..7bb2524a7 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -61,7 +61,7 @@ import { DocumentManager } from '../util/DocumentManager';
import { DocumentLinksButton } from './nodes/DocumentLinksButton';
import { LinkMenu } from './linking/LinkMenu';
import { LinkDocPreview } from './nodes/LinkDocPreview';
-import { LinkCreatedBox } from './nodes/LinkCreatedBox';
+import { TaskCompletionBox } from './nodes/TaskCompletedBox';
import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup';
import FormatShapePane from "./collections/collectionFreeForm/FormatShapePane";
import HypothesisAuthenticationManager from '../apis/HypothesisAuthenticationManager';
@@ -808,7 +808,7 @@ export class MainView extends React.Component {
{this.mainContent}
</GestureOverlay>
<PreviewCursor />
- <LinkCreatedBox />
+ <TaskCompletionBox />
<ContextMenu />
<FormatShapePane />
<RadialMenu />
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 9c83cca19..2ea391b19 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -8,7 +8,7 @@ import * as React from 'react';
import Lightbox from 'react-image-lightbox-with-rotate';
import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app
import { DateField } from '../../../fields/DateField';
-import { AclAddonly, AclReadonly, DataSym, Doc, DocListCast, Field, Opt, AclEdit, AclSym, AclPrivate } from '../../../fields/Doc';
+import { AclAddonly, AclReadonly, DataSym, Doc, DocListCast, Field, Opt, AclEdit, AclSym, AclPrivate, AclAdmin } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
@@ -17,7 +17,7 @@ import { listSpec } from '../../../fields/Schema';
import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
-import { TraceMobx, GetEffectiveAcl, getPlaygroundMode, distributeAcls } from '../../../fields/util';
+import { TraceMobx, GetEffectiveAcl, getPlaygroundMode, distributeAcls, SharingPermissions } from '../../../fields/util';
import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
import { DocumentType } from '../../documents/DocumentTypes';
@@ -113,7 +113,8 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
[AclPrivate, SharingPermissions.None],
[AclReadonly, SharingPermissions.View],
[AclAddonly, SharingPermissions.Add],
- [AclEdit, SharingPermissions.Edit]
+ [AclEdit, SharingPermissions.Edit],
+ [AclAdmin, SharingPermissions.Admin]
]);
get collectionViewType(): CollectionViewType | undefined {
@@ -146,7 +147,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
const effectiveAcl = GetEffectiveAcl(this.props.Document);
if (added.length) {
- if (effectiveAcl === AclReadonly && !getPlaygroundMode()) {
+ if (effectiveAcl === AclPrivate || (effectiveAcl === AclReadonly && !getPlaygroundMode())) {
return false;
}
else {
@@ -193,7 +194,8 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
@action.bound
removeDocument = (doc: any): boolean => {
- if (GetEffectiveAcl(this.props.Document) === AclEdit || getPlaygroundMode()) {
+ const effectiveAcl = GetEffectiveAcl(this.props.Document);
+ if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin || getPlaygroundMode()) {
const docs = doc instanceof Doc ? [doc] : doc as Doc[];
const targetDataDoc = this.props.Document[DataSym];
const value = DocListCast(targetDataDoc[this.props.fieldKey]);
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 649406e6c..8c0b8de9d 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -40,15 +40,21 @@ export class SelectorContextMenu extends React.Component<SelectorProps> {
this._reaction?.();
}
async fetchDocuments() {
- const aliases = (await SearchUtil.GetAliasesOfDocument(this.props.Document)).filter(doc => doc !== this.props.Document);
- const { docs } = await SearchUtil.Search("", true, { fq: `data_l:"${this.props.Document[Id]}"` });
- const map: Map<Doc, Doc> = new Map;
- const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search("", true, { fq: `data_l:"${doc[Id]}"` }).then(result => result.docs)));
- allDocs.forEach((docs, index) => docs.forEach(doc => map.set(doc, aliases[index])));
- docs.forEach(doc => map.delete(doc));
+ const aliases = (await SearchUtil.GetAliasesOfDocument(this.props.Document));
+ const containerProtoSets = await Promise.all(aliases.map(async alias =>
+ await Promise.all((await SearchUtil.Search("", true, { fq: `data_l:"${alias[Id]}"` })).docs)));
+ const containerProtos = containerProtoSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set<Doc>());
+ const containerSets = await Promise.all(Array.from(containerProtos.keys()).map(async container => {
+ return (await SearchUtil.GetAliasesOfDocument(container));
+ }));
+ const containers = containerSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set<Doc>());
+ const doclayoutSets = await Promise.all(Array.from(containers.keys()).map(async (dp) => {
+ return (await SearchUtil.GetAliasesOfDocument(dp));
+ }));
+ const doclayouts = Array.from(doclayoutSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set<Doc>()).keys());
runInAction(() => {
- this._docs = docs.filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document)).map(doc => ({ col: doc, target: this.props.Document }));
- this._otherDocs = Array.from(map.entries()).filter(entry => !Doc.AreProtosEqual(entry[0], CollectionDockingView.Instance.props.Document)).map(([col, target]) => ({ col, target }));
+ this._docs = doclayouts.filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document)).map(doc => ({ col: doc, target: this.props.Document }));
+ this._otherDocs = [];
});
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 979b21321..079add4b0 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -944,7 +944,11 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.backgroundActive ? true : false;
getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps {
return {
- ...this.props,
+ addDocument: this.props.addDocument,
+ removeDocument: this.props.removeDocument,
+ moveDocument: this.props.moveDocument,
+ pinToPres: this.props.pinToPres,
+ whenActiveChanged: this.props.whenActiveChanged,
NativeHeight: returnZero,
NativeWidth: returnZero,
fitToBox: false,
@@ -1145,7 +1149,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@action
componentDidMount() {
super.componentDidMount?.();
- this._layoutComputeReaction = reaction(() => this.doLayoutComputation,
+ this._layoutComputeReaction = reaction(() => { TraceMobx(); return this.doLayoutComputation },
(elements) => this._layoutElements = elements || [],
{ fireImmediately: true, name: "doLayout" });
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index aa9a3b4ae..764758eee 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,6 +1,6 @@
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { Doc, Opt, DocListCast, DataSym, AclEdit, AclAddonly } from "../../../../fields/Doc";
+import { Doc, Opt, DocListCast, DataSym, AclEdit, AclAddonly, AclAdmin } from "../../../../fields/Doc";
import { GetEffectiveAcl, getPlaygroundMode } from "../../../../fields/util";
import { InkData, InkField, InkTool } from "../../../../fields/InkField";
import { List } from "../../../../fields/List";
@@ -281,7 +281,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this._downX = x;
this._downY = y;
const effectiveAcl = GetEffectiveAcl(this.props.Document);
- if (effectiveAcl === AclEdit || effectiveAcl === AclAddonly || getPlaygroundMode()) PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge);
+ if ([AclAdmin, AclEdit, AclAddonly].includes(effectiveAcl) || getPlaygroundMode()) PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge);
this.clearSelection();
}
});
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index fa7fe64f3..748d5bbd0 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -10,7 +10,7 @@ import React = require("react");
import { DocUtils } from "../../documents/Documents";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { LinkDocPreview } from "./LinkDocPreview";
-import { LinkCreatedBox } from "./LinkCreatedBox";
+import { TaskCompletionBox } from "./TaskCompletedBox";
import { LinkDescriptionPopup } from "./LinkDescriptionPopup";
import { LinkManager } from "../../util/LinkManager";
import { Tooltip } from "@material-ui/core";
@@ -99,15 +99,16 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
runInAction(() => {
if (linkDoc) {
- LinkCreatedBox.popupX = e.screenX;
- LinkCreatedBox.popupY = e.screenY - 133;
- LinkCreatedBox.linkCreated = true;
+ TaskCompletionBox.textDisplayed = "Link Created";
+ TaskCompletionBox.popupX = e.screenX;
+ TaskCompletionBox.popupY = e.screenY - 133;
+ TaskCompletionBox.taskCompleted = true;
LinkDescriptionPopup.popupX = e.screenX;
LinkDescriptionPopup.popupY = e.screenY - 100;
LinkDescriptionPopup.descriptionPopup = true;
- setTimeout(action(() => { LinkCreatedBox.linkCreated = false; }), 2500);
+ setTimeout(action(() => { TaskCompletionBox.taskCompleted = false; }), 2500);
}
});
@@ -132,9 +133,10 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
runInAction(() => {
if (linkDoc) {
- LinkCreatedBox.popupX = e.screenX;
- LinkCreatedBox.popupY = e.screenY - 133;
- LinkCreatedBox.linkCreated = true;
+ TaskCompletionBox.textDisplayed = "Link Created";
+ TaskCompletionBox.popupX = e.screenX;
+ TaskCompletionBox.popupY = e.screenY - 133;
+ TaskCompletionBox.taskCompleted = true;
if (LinkDescriptionPopup.showDescriptions === "ON" || !LinkDescriptionPopup.showDescriptions) {
LinkDescriptionPopup.popupX = e.screenX;
@@ -142,7 +144,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
LinkDescriptionPopup.descriptionPopup = true;
}
- setTimeout(action(() => { LinkCreatedBox.linkCreated = false; }), 2500);
+ setTimeout(action(() => { TaskCompletionBox.taskCompleted = false; }), 2500);
}
});
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index ed3a9a4f3..85e8409d1 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -3,7 +3,7 @@ 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 } from "../../../fields/Doc";
+import { Doc, DocListCast, HeightSym, Opt, WidthSym, DataSym, AclPrivate, AclEdit, AclAdmin } from "../../../fields/Doc";
import { Document } from '../../../fields/documentSchemas';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
@@ -11,7 +11,7 @@ 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 } from '../../../fields/util';
+import { TraceMobx, GetEffectiveAcl, SharingPermissions } from '../../../fields/util';
import { GestureUtils } from '../../../pen-gestures/GestureUtils';
import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils, emptyPath } from "../../../Utils";
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
@@ -25,7 +25,7 @@ import { InteractionUtils } from '../../util/InteractionUtils';
import { Scripting } from '../../util/Scripting';
import { SearchUtil } from '../../util/SearchUtil';
import { SelectionManager } from "../../util/SelectionManager";
-import SharingManager, { SharingPermissions } from '../../util/SharingManager';
+import SharingManager from '../../util/SharingManager';
import { Transform } from "../../util/Transform";
import { undoBatch, UndoManager } from "../../util/UndoManager";
import { CollectionView, CollectionViewType } from '../collections/CollectionView';
@@ -41,7 +41,7 @@ import { RadialMenu } from './RadialMenu';
import React = require("react");
import { DocumentLinksButton } from './DocumentLinksButton';
import { MobileInterface } from '../../../mobile/MobileInterface';
-import { LinkCreatedBox } from './LinkCreatedBox';
+import { TaskCompletionBox } from './TaskCompletedBox';
import { LinkDescriptionPopup } from './LinkDescriptionPopup';
import { LinkManager } from '../../util/LinkManager';
@@ -630,15 +630,16 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const makeLink = action((linkDoc: Doc) => {
LinkManager.currentLink = linkDoc;
- LinkCreatedBox.popupX = de.x;
- LinkCreatedBox.popupY = de.y - 33;
- LinkCreatedBox.linkCreated = true;
+ TaskCompletionBox.textDisplayed = "Link Created";
+ TaskCompletionBox.popupX = de.x;
+ TaskCompletionBox.popupY = de.y - 33;
+ TaskCompletionBox.taskCompleted = true;
LinkDescriptionPopup.popupX = de.x;
LinkDescriptionPopup.popupY = de.y;
LinkDescriptionPopup.descriptionPopup = true;
- setTimeout(action(() => LinkCreatedBox.linkCreated = false), 2500);
+ setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2500);
});
if (de.complete.annoDragData) {
/// this whole section for handling PDF annotations looks weird. Need to rethink this to make it cleaner
@@ -818,7 +819,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "fingerprint" });
}
- GetEffectiveAcl(this.props.Document) === AclEdit && moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" });
+ //GetEffectiveAcl(this.props.Document) === AclEdit && moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" });
+
+ const effectiveAcl = GetEffectiveAcl(this.props.Document);
+ (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) && moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" });
!more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" });
cm.moveAfter(cm.findByDescription("More...")!, cm.findByDescription("OnClick...")!);
@@ -829,6 +833,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
!Doc.UserDoc().novice && helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
//cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" });
+ // to be removed for baseline
+ cm.addItem({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" });
+
// 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" });
diff --git a/src/client/views/nodes/LinkCreatedBox.tsx b/src/client/views/nodes/LinkCreatedBox.tsx
deleted file mode 100644
index 648ae23c8..000000000
--- a/src/client/views/nodes/LinkCreatedBox.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import React = require("react");
-import { observer } from "mobx-react";
-import { documentSchema } from "../../../fields/documentSchemas";
-import { makeInterface } from "../../../fields/Schema";
-import "./LinkCreatedBox.scss";
-import { observable, action } from "mobx";
-import { Fade } from "@material-ui/core";
-
-
-@observer
-export class LinkCreatedBox extends React.Component<{}> {
-
- @observable public static linkCreated: boolean = false;
- @observable public static popupX: number = 500;
- @observable public static popupY: number = 150;
-
- @action
- public static changeLinkCreated = () => {
- LinkCreatedBox.linkCreated = !LinkCreatedBox.linkCreated;
- }
-
- render() {
- return <Fade in={LinkCreatedBox.linkCreated}>
- <div className="linkCreatedBox-fade"
- style={{
- left: LinkCreatedBox.popupX ? LinkCreatedBox.popupX : 500,
- top: LinkCreatedBox.popupY ? LinkCreatedBox.popupY : 150,
- }}>Link Created</div>
- </Fade>;
- }
-} \ No newline at end of file
diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx
index 06e8d30d1..d8fe47f4e 100644
--- a/src/client/views/nodes/LinkDescriptionPopup.tsx
+++ b/src/client/views/nodes/LinkDescriptionPopup.tsx
@@ -4,7 +4,7 @@ import "./LinkDescriptionPopup.scss";
import { observable, action } from "mobx";
import { EditableView } from "../EditableView";
import { LinkManager } from "../../util/LinkManager";
-import { LinkCreatedBox } from "./LinkCreatedBox";
+import { TaskCompletionBox } from "./TaskCompletedBox";
@observer
@@ -31,7 +31,7 @@ export class LinkDescriptionPopup extends React.Component<{}> {
onClick = (e: PointerEvent) => {
if (this.popupRef && !!!this.popupRef.current?.contains(e.target as any)) {
LinkDescriptionPopup.descriptionPopup = false;
- LinkCreatedBox.linkCreated = false;
+ TaskCompletionBox.taskCompleted = false;
}
}
diff --git a/src/client/views/nodes/LinkCreatedBox.scss b/src/client/views/nodes/TaskCompletedBox.scss
index 3cbd38b55..80b750b39 100644
--- a/src/client/views/nodes/LinkCreatedBox.scss
+++ b/src/client/views/nodes/TaskCompletedBox.scss
@@ -1,7 +1,6 @@
-.linkCreatedBox-fade {
+.taskCompletedBox-fade {
border: 1px solid rgb(100, 100, 100);
-
width: auto;
position: absolute;
diff --git a/src/client/views/nodes/TaskCompletedBox.tsx b/src/client/views/nodes/TaskCompletedBox.tsx
new file mode 100644
index 000000000..89602f219
--- /dev/null
+++ b/src/client/views/nodes/TaskCompletedBox.tsx
@@ -0,0 +1,32 @@
+import React = require("react");
+import { observer } from "mobx-react";
+import { documentSchema } from "../../../fields/documentSchemas";
+import { makeInterface } from "../../../fields/Schema";
+import "./TaskCompletedBox.scss";
+import { observable, action } from "mobx";
+import { Fade } from "@material-ui/core";
+
+
+@observer
+export class TaskCompletionBox extends React.Component<{}> {
+
+ @observable public static taskCompleted: boolean = false;
+ @observable public static popupX: number = 500;
+ @observable public static popupY: number = 150;
+ @observable public static textDisplayed: string;
+
+ @action
+ public static toggleTaskCompleted = () => {
+ TaskCompletionBox.taskCompleted = !TaskCompletionBox.taskCompleted;
+ }
+
+ render() {
+ return <Fade in={TaskCompletionBox.taskCompleted}>
+ <div className="taskCompletedBox-fade"
+ style={{
+ left: TaskCompletionBox.popupX ? TaskCompletionBox.popupX : 500,
+ top: TaskCompletionBox.popupY ? TaskCompletionBox.popupY : 150,
+ }}>{TaskCompletionBox.textDisplayed}</div>
+ </Fade>;
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 38fa66d65..966aaa895 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -13,7 +13,7 @@ import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from "
import { ReplaceStep } from 'prosemirror-transform';
import { EditorView } from "prosemirror-view";
import { DateField } from '../../../../fields/DateField';
-import { DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym, AclEdit } from "../../../../fields/Doc";
+import { DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym, AclEdit, AclAdmin } from "../../../../fields/Doc";
import { documentSchema } from '../../../../fields/documentSchemas';
import applyDevTools = require("prosemirror-dev-tools");
import { removeMarkWithAttrs } from "./prosemirrorPatches";
@@ -233,7 +233,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const curLayout = this.rootDoc !== this.layoutDoc ? Cast(this.layoutDoc[this.fieldKey], RichTextField, null) : undefined; // the default text stored in a layout template
const json = JSON.stringify(state.toJSON());
let unchanged = true;
- if (GetEffectiveAcl(this.dataDoc) === AclEdit) {
+ const effectiveAcl = GetEffectiveAcl(this.dataDoc);
+ if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) {
if (!this._applyingChange && json.replace(/"selection":.*/, "") !== curProto?.Data.replace(/"selection":.*/, "")) {
this._applyingChange = true;
(curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())));
@@ -689,7 +690,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
);
this._disposers.editorState = reaction(
() => {
- if (this.dataDoc[this.props.fieldKey + "-noTemplate"] || !this.layoutDoc[this.props.fieldKey + "-textTemplate"]) {
+ if (this.dataDoc?.[this.props.fieldKey + "-noTemplate"] || !this.layoutDoc[this.props.fieldKey + "-textTemplate"]) {
return Cast(this.dataDoc[this.props.fieldKey], RichTextField, null)?.Data;
}
return Cast(this.layoutDoc[this.props.fieldKey + "-textTemplate"], RichTextField, null)?.Data;
@@ -1405,7 +1406,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
<div className={`formattedTextBox-inner${rounded}${selclass}`} ref={this.createDropTarget}
style={{
padding: this.layoutDoc._textBoxPadding ? StrCast(this.layoutDoc._textBoxPadding) : `${Math.max(0, NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0) + selPad)}px ${NumCast(this.layoutDoc._xMargin, this.props.xMargin || 0) + selPad}px`,
- pointerEvents: !this.props.isSelected() ? ((this.layoutDoc.isLinkButton || this.props.onClick) ? "none" : "all") : undefined
+ pointerEvents: !this.props.isSelected() ? ((this.layoutDoc.isLinkButton || this.props.onClick) ? "none" : undefined) : undefined
}}
/>
</div>