aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/DocComponent.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/DocComponent.tsx')
-rw-r--r--src/client/views/DocComponent.tsx143
1 files changed, 86 insertions, 57 deletions
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 169bd3873..280ca8a8c 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -8,13 +8,11 @@ import { Cast, ScriptCast } from '../../fields/Types';
import { denormalizeEmail, distributeAcls, GetEffectiveAcl, inheritParentAcls, SharingPermissions } from '../../fields/util';
import { returnFalse } from '../../Utils';
import { DocUtils } from '../documents/Documents';
-import { CurrentUserUtils } from '../util/CurrentUserUtils';
import { InteractionUtils } from '../util/InteractionUtils';
import { UndoManager } from '../util/UndoManager';
import { DocumentView } from './nodes/DocumentView';
import { Touchable } from './Touchable';
-
/// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView)
export interface DocComponentProps {
Document: Doc;
@@ -24,13 +22,21 @@ export interface DocComponentProps {
export function DocComponent<P extends DocComponentProps>() {
class Component extends Touchable<P> {
//TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
- @computed get Document() { return this.props.Document; }
+ @computed get Document() {
+ return this.props.Document;
+ }
// This is the "The Document" -- it encapsulates, data, layout, and any templates
- @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
+ @computed get rootDoc() {
+ return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document;
+ }
// This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
- @computed get layoutDoc() { return this.props.LayoutTemplateString ? this.props.Document : Doc.Layout(this.props.Document, this.props.LayoutTemplate?.()); }
+ @computed get layoutDoc() {
+ return this.props.LayoutTemplateString ? this.props.Document : Doc.Layout(this.props.Document, this.props.LayoutTemplate?.());
+ }
// This is the data part of a document -- ie, the data that is constant across all views of the document
- @computed get dataDoc() { return this.props.Document[DataSym] as Doc; }
+ @computed get dataDoc() {
+ return this.props.Document[DataSym] as Doc;
+ }
protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
}
@@ -55,32 +61,39 @@ export function ViewBoxBaseComponent<P extends ViewBoxBaseProps>() {
//@computed get Document(): T { return schemaCtor(this.props.Document); }
// This is the "The Document" -- it encapsulates, data, layout, and any templates
- @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
+ @computed get rootDoc() {
+ return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document;
+ }
// This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
- @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
+ @computed get layoutDoc() {
+ return Doc.Layout(this.props.Document);
+ }
// This is the data part of a document -- ie, the data that is constant across all views of the document
- @computed get dataDoc() { return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym]; }
+ @computed get dataDoc() {
+ return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym];
+ }
// key where data is stored
- @computed get fieldKey() { return this.props.fieldKey; }
-
- isContentActive = (outsideReaction?: boolean) => (
- this.props.isContentActive?.() === false ? false :
- (CurrentUserUtils.ActiveTool !== InkTool.None ||
- (this.props.isContentActive?.() || this.props.Document.forceActive ||
- this.props.isSelected(outsideReaction) ||
- this.props.rootSelected(outsideReaction)) ? true : undefined))
+ @computed get fieldKey() {
+ return this.props.fieldKey;
+ }
+
+ isContentActive = (outsideReaction?: boolean) =>
+ this.props.isContentActive?.() === false
+ ? false
+ : Doc.ActiveTool !== InkTool.None || this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.rootSelected(outsideReaction)
+ ? true
+ : undefined;
protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
}
return Component;
}
-
/// DocAnnotatbleComponent -return a base class for React views of document fields that are annotatable *and* interactive when selected (e.g., pdf, image)
export interface ViewBoxAnnotatableProps {
Document: Doc;
DataDoc?: Doc;
fieldKey: string;
- filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
+ filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
isContentActive: () => boolean | undefined;
select: (isCtrlPressed: boolean) => void;
whenChildContentsActiveChanged: (isActive: boolean) => void;
@@ -91,19 +104,29 @@ export interface ViewBoxAnnotatableProps {
}
export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>() {
class Component extends Touchable<P> {
- @observable _annotationKeySuffix = () => "annotations";
+ @observable _annotationKeySuffix = () => 'annotations';
@observable _isAnyChildContentActive = false;
//TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
- @computed get Document() { return this.props.Document; }
+ @computed get Document() {
+ return this.props.Document;
+ }
// This is the "The Document" -- it encapsulates, data, layout, and any templates
- @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
+ @computed get rootDoc() {
+ return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document;
+ }
// This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
- @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
+ @computed get layoutDoc() {
+ return Doc.Layout(this.props.Document);
+ }
// This is the data part of a document -- ie, the data that is constant across all views of the document
- @computed get dataDoc() { return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym]; }
+ @computed get dataDoc() {
+ return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym];
+ }
// key where data is stored
- @computed get fieldKey() { return this.props.fieldKey; }
+ @computed get fieldKey() {
+ return this.props.fieldKey;
+ }
isAnyChildContentActive = () => this._isAnyChildContentActive;
@@ -111,20 +134,23 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
styleFromLayoutString = (scale: number) => {
const style: { [key: string]: any } = {};
- const divKeys = ["width", "height", "fontSize", "transform", "left", "background", "left", "right", "top", "bottom", "pointerEvents", "position"];
- const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: this executes a script to convert a property expression string: { script } into a value
- return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: "number" })?.script.run({ self: this.rootDoc, this: this.layoutDoc, scale }).result?.toString() ?? "";
+ const divKeys = ['width', 'height', 'fontSize', 'transform', 'left', 'background', 'left', 'right', 'top', 'bottom', 'pointerEvents', 'position'];
+ const replacer = (match: any, expr: string, offset: any, string: any) => {
+ // bcz: this executes a script to convert a property expression string: { script } into a value
+ return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: 'number' })?.script.run({ self: this.rootDoc, this: this.layoutDoc, scale }).result?.toString() ?? '';
};
divKeys.map((prop: string) => {
const p = (this.props as any)[prop];
- typeof p === "string" && (style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer));
+ typeof p === 'string' && (style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer));
});
return style;
- }
+ };
protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
- @computed public get annotationKey() { return this.fieldKey + (this._annotationKeySuffix() ? "-" + this._annotationKeySuffix() : ""); }
+ @computed public get annotationKey() {
+ return this.fieldKey + (this._annotationKeySuffix() ? '-' + this._annotationKeySuffix() : '');
+ }
@action.bound
removeDocument(doc: Doc | Doc[], annotationKey?: string, leavePushpin?: boolean): boolean {
@@ -132,23 +158,26 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
const indocs = doc instanceof Doc ? [doc] : doc;
const docs = indocs.filter(doc => [AclEdit, AclAdmin].includes(effectiveAcl) || GetEffectiveAcl(doc) === AclAdmin);
if (docs.length) {
- setTimeout(() => docs.map(doc => { // this allows 'addDocument' to see the annotationOn field in order to create a pushin
- Doc.SetInPlace(doc, "isPushpin", undefined, true);
- doc.annotationOn === this.props.Document && Doc.SetInPlace(doc, "annotationOn", undefined, true);
- }));
+ setTimeout(() =>
+ docs.map(doc => {
+ // this allows 'addDocument' to see the annotationOn field in order to create a pushin
+ Doc.SetInPlace(doc, 'isPushpin', undefined, true);
+ doc.annotationOn === this.props.Document && Doc.SetInPlace(doc, 'annotationOn', undefined, true);
+ })
+ );
const targetDataDoc = this.dataDoc;
const value = DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]);
const toRemove = value.filter(v => docs.includes(v));
if (toRemove.length !== 0) {
- const recent = CurrentUserUtils.MyRecentlyClosed;
+ const recent = Doc.MyRecentlyClosed;
toRemove.forEach(doc => {
leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey);
Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
doc.context = undefined;
if (recent) {
- Doc.RemoveDocFromList(recent, "data", doc);
- Doc.AddDocToList(recent, "data", doc, undefined, true, true);
+ Doc.RemoveDocFromList(recent, 'data', doc);
+ Doc.AddDocToList(recent, 'data', doc, undefined, true, true);
}
});
this.isAnyChildContentActive() && this.props.select(false);
@@ -172,12 +201,11 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
return UndoManager.RunInTempBatch(() => this.removeDocument(doc, annotationKey, true) && addDocument(doc, annotationKey));
}
return false;
- }
+ };
@action.bound
addDocument = (doc: Doc | Doc[], annotationKey?: string): boolean => {
const docs = doc instanceof Doc ? [doc] : doc;
- if (this.props.filterAddDocument?.(docs) === false ||
- docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document) && Doc.LayoutField(doc) === Doc.LayoutField(this.props.Document))) {
+ if (this.props.filterAddDocument?.(docs) === false || docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document) && Doc.LayoutField(doc) === Doc.LayoutField(this.props.Document))) {
return false;
}
const targetDataDoc = this.props.Document[DataSym];
@@ -188,8 +216,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
if (added.length) {
if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) {
return false;
- }
- else {
+ } else {
if (this.props.Document[AclSym] && Object.keys(this.props.Document[AclSym]).length) {
added.forEach(d => {
for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
@@ -200,32 +227,34 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
if (effectiveAcl === AclAugment) {
added.map(doc => {
- if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc)) && CurrentUserUtils.ActiveDashboard) inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc);
+ if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc)) && Doc.ActiveDashboard) inheritParentAcls(Doc.ActiveDashboard, doc);
doc.context = this.props.Document;
if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document;
Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
});
- }
- else {
- added.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))).map(doc => { // only make a pushpin if we have acl's to edit the document
- //DocUtils.LeavePushpin(doc);
- doc._stayInCollection = undefined;
- doc.context = this.props.Document;
- if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document;
+ } else {
+ added
+ .filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc)))
+ .map(doc => {
+ // only make a pushpin if we have acl's to edit the document
+ //DocUtils.LeavePushpin(doc);
+ doc._stayInCollection = undefined;
+ doc.context = this.props.Document;
+ if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document;
- CurrentUserUtils.ActiveDashboard && inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc);
- });
+ Doc.ActiveDashboard && inheritParentAcls(Doc.ActiveDashboard, doc);
+ });
const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List<Doc>;
if (annoDocs instanceof List) annoDocs.push(...added);
else targetDataDoc[annotationKey ?? this.annotationKey] = new List<Doc>(added);
- targetDataDoc[(annotationKey ?? this.annotationKey) + "-lastModified"] = new DateField(new Date(Date.now()));
+ targetDataDoc[(annotationKey ?? this.annotationKey) + '-lastModified'] = new DateField(new Date(Date.now()));
}
}
}
return true;
- }
+ };
- whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive));
+ whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive)));
}
return Component;
-} \ No newline at end of file
+}