aboutsummaryrefslogtreecommitdiff
path: root/src/client/documents/Documents.ts
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2021-03-18 00:08:13 -0400
committerbobzel <zzzman@gmail.com>2021-03-18 00:08:13 -0400
commit188e1e57860f58e9ebe3536a0e1f7cd84ea0db80 (patch)
tree72d1824332295c6a58b7b5933125133b19c5c0f3 /src/client/documents/Documents.ts
parent6f4f0ffb9f4ab816cf6055c62afc6f79b8e4961f (diff)
cleaned up link making. Documents don't add to the Undo stack when being created and Initializing is set. Links to text regions automatically update their link line endpoints even if autoMove isn't set. regularized initialization fields to avoid special cases about setting delegate keys without a leading "_"
Diffstat (limited to 'src/client/documents/Documents.ts')
-rw-r--r--src/client/documents/Documents.ts227
1 files changed, 106 insertions, 121 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 8aa478cc1..24409933e 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -58,7 +58,6 @@ import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
import { DocumentType } from "./DocumentTypes";
import { EquationBox } from "../views/nodes/EquationBox";
import { FunctionPlotBox } from "../views/nodes/FunctionPlotBox";
-import { script } from "googleapis/build/src/apis/script";
import { CurrentUserUtils } from "../util/CurrentUserUtils";
const path = require('path');
@@ -93,7 +92,7 @@ type PEVt = PEInfo | "none" | "all";
type DROPt = DAInfo | dropActionType;
export class DocumentOptions {
system?: BOOLt = new BoolInfo("is this a system created/owned doc");
- dropAction?: DROPt = new DAInfo("what should happen to the source document when it's dropped onto this doc ");
+ _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
childDropAction?: DROPt = new DAInfo("what should happen to the source document when it's dropped onto a child of a collection ");
targetDropAction?: DROPt = new DAInfo("what should happen to the source document when ??? ");
color?: string; // foreground color data doc
@@ -156,9 +155,11 @@ export class DocumentOptions {
y?: number;
z?: number; // whether document is in overlay (1) or not (0 or undefined)
author?: string;
- layoutKey?: string;
+ _layoutKey?: string;
type?: string;
title?: string;
+ "acl-Public"?: string; // public permissions
+ "_acl-Public"?: string; // public permissions
version?: string; // version identifier for a document
label?: string;
hidden?: boolean;
@@ -182,7 +183,7 @@ export class DocumentOptions {
caption?: RichTextField;
opacity?: number;
defaultBackgroundColor?: string;
- isLinkButton?: boolean;
+ _isLinkButton?: boolean; // marks a document as a button that will follow its primary link when clicked
isFolder?: boolean;
lastFrame?: number; // the last frame of a frame-based collection (e.g., progressive slide)
activeFrame?: number; // the active frame of a document in a frame base collection
@@ -206,9 +207,15 @@ export class DocumentOptions {
dockingConfig?: string;
annotationOn?: Doc;
isPushpin?: boolean;
- removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
+ _removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
iconShape?: string; // shapes of the fonticon border
+ layout_linkView?: Doc; // view template for a link document
linkRelationship?: string; // type of relatinoship a link represents
+ linkDisplay?: boolean; // whether a link line should be dipslayed between the two link anchors
+ anchor1?: Doc;
+ anchor2?: Doc;
+ "anchor1-useLinkSmallAnchor"?: boolean; // whether anchor1 of a link should use a miniature anchor dot (as when the anchor is a text selection)
+ "anchor2-useLinkSmallAnchor"?: boolean; // whether anchor1 of a link should use a miniature anchor dot (as when the anchor is a text selection)
ignoreClick?: boolean;
onClick?: ScriptField;
onDoubleClick?: ScriptField;
@@ -304,31 +311,31 @@ export namespace Docs {
const TemplateMap: TemplateMap = new Map([
[DocumentType.RTF, {
layout: { view: FormattedTextBox, dataField: "text" },
- options: { _height: 150, _xMargin: 10, _yMargin: 10 }
+ options: { _height: 150, _xMargin: 10, _yMargin: 10, links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.SEARCH, {
layout: { view: SearchBox, dataField: defaultDataKey },
- options: { _width: 400 }
+ options: { _width: 400, links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.FILTER, {
layout: { view: FilterBox, dataField: defaultDataKey },
- options: { _width: 400 }
+ options: { _width: 400, links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.COLOR, {
layout: { view: ColorBox, dataField: defaultDataKey },
- options: { _nativeWidth: 220, _nativeHeight: 300 }
+ options: { _nativeWidth: 220, _nativeHeight: 300, links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.IMG, {
layout: { view: ImageBox, dataField: defaultDataKey },
- options: {}
+ options: { links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.WEB, {
layout: { view: WebBox, dataField: defaultDataKey },
- options: { _height: 300, _fitWidth: true }
+ options: { _height: 300, _fitWidth: true, links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.COL, {
layout: { view: CollectionView, dataField: defaultDataKey },
- options: { _panX: 0, _panY: 0, _viewScale: 1 } // , _width: 500, _height: 500 }
+ options: { _panX: 0, _panY: 0, _viewScale: 1, links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.KVP, {
layout: { view: KeyValueBox, dataField: defaultDataKey },
@@ -336,15 +343,15 @@ export namespace Docs {
}],
[DocumentType.VID, {
layout: { view: VideoBox, dataField: defaultDataKey },
- options: { _currentTimecode: 0 },
+ options: { _currentTimecode: 0, links: ComputedField.MakeFunction("links(self)") as any },
}],
[DocumentType.AUDIO, {
layout: { view: AudioBox, dataField: defaultDataKey },
- options: { _height: 35, backgroundColor: "lightGray" }
+ options: { _height: 35, backgroundColor: "lightGray", links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.PDF, {
layout: { view: PDFBox, dataField: defaultDataKey },
- options: { _curPage: 1, _fitWidth: true }
+ options: { _curPage: 1, _fitWidth: true, links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.IMPORT, {
layout: { view: DirectoryImportBox, dataField: defaultDataKey },
@@ -352,7 +359,11 @@ export namespace Docs {
}],
[DocumentType.LINK, {
layout: { view: LinkBox, dataField: defaultDataKey },
- options: { _height: 150, description: "" }
+ options: {
+ _height: 150, description: "", links: ComputedField.MakeFunction("links(self)") as any,
+ linkBoxExcludedKeys: new List(["treeViewExpandedView", "aliases", "treeViewHideTitle", "_removeDropProperties",
+ "linkBoxExcludedKeys", "treeViewOpen", "aliasNumber", "isPrototype", "creationDate", "author"])
+ }
}],
[DocumentType.LINKDB, {
data: new List<Doc>(),
@@ -365,53 +376,58 @@ export namespace Docs {
options: { childDropAction: "alias", title: "Global Script Database" }
}],
[DocumentType.SCRIPTING, {
- layout: { view: ScriptingBox, dataField: defaultDataKey }
+ layout: { view: ScriptingBox, dataField: defaultDataKey },
+ options: { links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.YOUTUBE, {
layout: { view: YoutubeBox, dataField: defaultDataKey }
}],
[DocumentType.LABEL, {
layout: { view: LabelBox, dataField: defaultDataKey },
+ options: { links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.EQUATION, {
layout: { view: EquationBox, dataField: defaultDataKey },
+ options: { links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.FUNCPLOT, {
layout: { view: FunctionPlotBox, dataField: defaultDataKey },
+ options: { links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.BUTTON, {
layout: { view: LabelBox, dataField: "onClick" },
+ options: { links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.SLIDER, {
layout: { view: SliderBox, dataField: defaultDataKey },
+ options: { links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.PRES, {
layout: { view: PresBox, dataField: defaultDataKey },
- options: {}
+ options: { links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.FONTICON, {
layout: { view: FontIconBox, dataField: defaultDataKey },
- options: { _width: 40, _height: 40, borderRounding: "100%" },
+ options: { _width: 40, _height: 40, borderRounding: "100%", links: ComputedField.MakeFunction("links(self)") as any },
}],
- // [DocumentType.RECOMMENDATION, {
- // layout: { view: RecommendationsBox, dataField: defaultDataKey },
- // options: { _width: 200, _height: 200 },
- // }],
[DocumentType.WEBCAM, {
- layout: { view: DashWebRTCVideo, dataField: defaultDataKey }
+ layout: { view: DashWebRTCVideo, dataField: defaultDataKey },
+ options: { links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.PRESELEMENT, {
layout: { view: PresElementBox, dataField: defaultDataKey }
}],
[DocumentType.INK, {
layout: { view: InkingStroke, dataField: defaultDataKey },
- options: { _fontFamily: "cursive", backgroundColor: "transparent" }
+ options: { _fontFamily: "cursive", backgroundColor: "transparent", links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.SCREENSHOT, {
layout: { view: ScreenshotBox, dataField: defaultDataKey },
+ options: { links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.COMPARISON, {
layout: { view: ComparisonBox, dataField: defaultDataKey },
+ options: { links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.GROUPDB, {
data: new List<Doc>(),
@@ -419,10 +435,12 @@ export namespace Docs {
options: { childDropAction: "alias", title: "Global Group Database" }
}],
[DocumentType.GROUP, {
- layout: { view: EmptyBox, dataField: defaultDataKey }
+ layout: { view: EmptyBox, dataField: defaultDataKey },
+ options: { links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.TEXTANCHOR, {
- layout: { view: EmptyBox, dataField: defaultDataKey }
+ layout: { view: EmptyBox, dataField: defaultDataKey },
+ options: { links: ComputedField.MakeFunction("links(self)") as any }
}]
]);
@@ -611,8 +629,6 @@ export namespace Docs {
Scripting.addGlobal(Buxton);
- const delegateKeys = ["x", "y", "system", "layoutKey", "dropAction", "lockedPosiiton", "childDropAction", "isLinkButton", "removeDropProperties", "treeViewOpen"];
-
/**
* This function receives the relevant document prototype and uses
* it to create a new of that base-level prototype, or the
@@ -632,59 +648,33 @@ export namespace Docs {
* main document.
*/
export function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = "data", protoId?: string) {
- const { omit: protoProps, extract: delegateProps } = OmitKeys(options, delegateKeys, "^_");
-
- protoProps.system = delegateProps.system;
-
- if (!("author" in protoProps)) {
- protoProps.author = Doc.CurrentUserEmail;
- }
-
- if (!("creationDate" in protoProps)) {
- protoProps.creationDate = new DateField;
- protoProps[`${fieldKey}-lastModified`] = new DateField;
- }
-
- protoProps.isPrototype = true;
-
- const dataDoc = MakeDataDelegate(proto, protoProps, data, fieldKey, protoId);
- const viewDoc = Doc.MakeDelegate(dataDoc, delegId);
-
+ const viewKeys = ["x", "y", "system"];
+ const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, "^_");
+
+ dataProps.system = viewProps.system;
+ dataProps.isPrototype = true;
+ dataProps.author = Doc.CurrentUserEmail;
+ dataProps.creationDate = new DateField;
+ dataProps[`${fieldKey}-lastModified`] = new DateField;
+ dataProps["acl-Override"] = "None";
+ dataProps["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Add;
+ dataProps[fieldKey] = data;
// so that the list of annotations is already initialised, prevents issues in addonly.
// without this, if a doc has no annotations but the user has AddOnly privileges, they won't be able to add an annotation because they would have needed to create the field's list which they don't have permissions to do.
+ dataProps[fieldKey + "-annotations"] = new List<Doc>();
+ const dataDoc = Doc.assign(Doc.MakeDelegate(proto, protoId), dataProps as any, undefined, true);
- dataDoc[fieldKey + "-annotations"] = new List<Doc>();
-
- proto.links = ComputedField.MakeFunction("links(self)");
-
- viewDoc.author = Doc.CurrentUserEmail;
- viewDoc.type !== DocumentType.LINK && viewDoc.type !== DocumentType.LABEL && DocUtils.MakeLinkToActiveAudio(viewDoc);
-
- viewDoc["acl-Public"] = dataDoc["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Add;
- viewDoc["acl-Override"] = dataDoc["acl-Override"] = "None";
+ const viewDoc = Doc.MakeDelegate(dataDoc, delegId);
+ viewProps.author = Doc.CurrentUserEmail;
+ viewProps.type !== DocumentType.LINK && viewDoc.type !== DocumentType.LABEL && DocUtils.MakeLinkToActiveAudio(viewDoc);
+ viewProps["acl-Override"] = "None";
+ viewProps["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Add;
+ Doc.assign(viewDoc, viewProps, true, true);
!Doc.IsSystem(dataDoc) && ![DocumentType.PDFANNO, DocumentType.KVP, DocumentType.LINK, DocumentType.LINKANCHOR, DocumentType.TEXTANCHOR].includes(proto.type as any) &&
- !dataDoc.isFolder && !protoProps.annotationOn && Doc.AddDocToList(Cast(Doc.UserDoc().myFileOrphans, Doc, null), "data", dataDoc);
-
- return Doc.assign(viewDoc, delegateProps, true);
- }
+ !dataDoc.isFolder && !dataProps.annotationOn && Doc.AddDocToList(Cast(Doc.UserDoc().myFileOrphans, Doc, null), "data", dataDoc);
- /**
- * This function receives the relevant top level document prototype
- * and models a new instance by delegating from it.
- *
- * Note that it stores the data it recieves at the delegate's data key,
- * and applies any document options to this new delegate / instance.
- * @param proto the prototype from which to model this new delegate
- * @param options initial values to apply to this new delegate
- * @param value the data to store in this new delegate
- */
- function MakeDataDelegate<D extends Field>(proto: Doc, options: DocumentOptions, value?: D, fieldKey: string = "data", id: string | undefined = undefined) {
- const deleg = Doc.MakeDelegate(proto, id);
- if (value !== undefined) {
- deleg[fieldKey] = value;
- }
- return Doc.assign(deleg, options as any);
+ return viewDoc;
}
export function ImageDocument(url: string, options: DocumentOptions = {}) {
@@ -763,24 +753,15 @@ export namespace Docs {
}
export function LinkDocument(source: { doc: Doc, ctx?: Doc }, target: { doc: Doc, ctx?: Doc }, options: DocumentOptions = {}, id?: string) {
- const doc = InstanceFromProto(Prototypes.get(DocumentType.LINK), undefined, {
- childDontRegisterViews: true,
- isLinkButton: true, treeViewHideTitle: true, backgroundColor: "lightblue", // lightblue is default color for linking dot and link documents text comment area
- treeViewExpandedView: "fields", removeDropProperties: new List(["_layerTags", "isLinkButton"]), ...options
+ const linkDoc = InstanceFromProto(Prototypes.get(DocumentType.LINK), undefined, {
+ childDontRegisterViews: true, treeViewOpen: true, anchor1: source.doc, anchor2: target.doc,
+ _isLinkButton: true, treeViewHideTitle: true, backgroundColor: "lightblue", // lightblue is default color for linking dot and link documents text comment area
+ treeViewExpandedView: "fields", _removeDropProperties: new List(["_layerTags", "isLinkButton"]), ...options
}, id);
- const linkDocProto = Doc.GetProto(doc);
- linkDocProto.treeViewOpen = true;// setting this in the instance creator would set it on the view document.
- linkDocProto.anchor1 = source.doc;
- linkDocProto.anchor2 = target.doc;
-
- if (linkDocProto.linkBoxExcludedKeys === undefined) {
- Cast(linkDocProto.proto, Doc, null).linkBoxExcludedKeys = new List(["treeViewExpandedView", "aliases", "treeViewHideTitle", "removeDropProperties", "linkBoxExcludedKeys", "treeViewOpen", "aliasNumber", "isPrototype", "creationDate", "author"]);
- Cast(linkDocProto.proto, Doc, null).layoutKey = undefined;
- }
- LinkManager.Instance.addLink(doc);
+ LinkManager.Instance.addLink(linkDoc);
- return doc;
+ return linkDoc;
}
export function InkDocument(color: string, tool: string, strokeWidth: string, strokeBezier: string, fillColor: string, arrowStart: string, arrowEnd: string, dash: string, points: { X: number, Y: number }[], options: DocumentOptions = {}) {
@@ -1093,42 +1074,46 @@ export namespace DocUtils {
if (!allowParCollectionLink && sv?.props.ContainingCollectionDoc === target.doc) return;
if (target.doc === Doc.UserDoc()) return undefined;
+ const makeLink = action((linkDoc: Doc, showPopup?: number[]) => {
+ if (showPopup) {
+ LinkManager.currentLink = linkDoc;
- const makeLink = action((linkDoc: Doc, showPopup: number[]) => {
- LinkManager.currentLink = linkDoc;
+ TaskCompletionBox.textDisplayed = "Link Created";
+ TaskCompletionBox.popupX = showPopup[0];
+ TaskCompletionBox.popupY = showPopup[1] - 33;
+ TaskCompletionBox.taskCompleted = true;
- TaskCompletionBox.textDisplayed = "Link Created";
- TaskCompletionBox.popupX = showPopup[0];
- TaskCompletionBox.popupY = showPopup[1] - 33;
- TaskCompletionBox.taskCompleted = true;
+ LinkDescriptionPopup.popupX = showPopup[0];
+ LinkDescriptionPopup.popupY = showPopup[1];
+ LinkDescriptionPopup.descriptionPopup = true;
- LinkDescriptionPopup.popupX = showPopup[0];
- LinkDescriptionPopup.popupY = showPopup[1];
- LinkDescriptionPopup.descriptionPopup = true;
+ const rect = document.body.getBoundingClientRect();
+ if (LinkDescriptionPopup.popupX + 200 > rect.width) {
+ LinkDescriptionPopup.popupX -= 190;
+ TaskCompletionBox.popupX -= 40;
+ }
+ if (LinkDescriptionPopup.popupY + 100 > rect.height) {
+ LinkDescriptionPopup.popupY -= 40;
+ TaskCompletionBox.popupY -= 40;
+ }
- const rect = document.body.getBoundingClientRect();
- if (LinkDescriptionPopup.popupX + 200 > rect.width) {
- LinkDescriptionPopup.popupX -= 190;
- TaskCompletionBox.popupX -= 40;
- }
- if (LinkDescriptionPopup.popupY + 100 > rect.height) {
- LinkDescriptionPopup.popupY -= 40;
- TaskCompletionBox.popupY -= 40;
+ setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2500);
}
-
- setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2500);
+ return linkDoc;
});
- const linkDoc = Docs.Create.LinkDocument(source, target, { linkRelationship, layoutKey: "layout_linkView", description }, id);
- Doc.GetProto(linkDoc)["anchor1-useLinkSmallAnchor"] = source.doc.useLinkSmallAnchor;
- Doc.GetProto(linkDoc)["anchor2-useLinkSmallAnchor"] = target.doc.useLinkSmallAnchor;
- linkDoc.linkDisplay = true;
- linkDoc.hidden = true;
- Doc.GetProto(linkDoc)["acl-Public"] = linkDoc["acl-Public"] = SharingPermissions.Add;
- linkDoc.layout_linkView = Cast(Cast(Doc.UserDoc()["template-button-link"], Doc, null).dragFactory, Doc, null);
- Doc.GetProto(linkDoc).title = ComputedField.MakeFunction("generateLinkTitle(self)");
- showPopup && makeLink(linkDoc, showPopup);
- return linkDoc;
+ return makeLink(Docs.Create.LinkDocument(source, target, {
+ title: ComputedField.MakeFunction("generateLinkTitle(self)") as any,
+ "anchor1-useLinkSmallAnchor": source.doc.useLinkSmallAnchor ? true : undefined,
+ "anchor2-useLinkSmallAnchor": target.doc.useLinkSmallAnchor ? true : undefined,
+ "acl-Public": SharingPermissions.Add,
+ "_acl-Public": SharingPermissions.Add,
+ layout_linkView: Cast(Cast(Doc.UserDoc()["template-button-link"], Doc, null).dragFactory, Doc, null),
+ linkDisplay: true, hidden: true,
+ linkRelationship,
+ _layoutKey: "layout_linkView",
+ description
+ }, id), showPopup);
}
export function DocumentFromField(target: Doc, fieldKey: string, proto?: Doc, options?: DocumentOptions): Doc | undefined {
@@ -1357,7 +1342,7 @@ export namespace DocUtils {
const pushpin = Docs.Create.FontIconDocument({
title: "pushpin", label: "", annotationOn: Cast(doc.annotationOn, Doc, null), isPushpin: true,
icon: "map-pin", x: Cast(doc.x, "number", null), y: Cast(doc.y, "number", null), backgroundColor: "#ACCEF7",
- _width: 15, _height: 15, _xPadding: 0, isLinkButton: true, _timecodeToShow: Cast(doc._timecodeToShow, "number", null)
+ _width: 15, _height: 15, _xPadding: 0, _isLinkButton: true, _timecodeToShow: Cast(doc._timecodeToShow, "number", null)
});
Doc.AddDocToList(context, Doc.LayoutFieldKey(context) + "-annotations", pushpin);
const pushpinLink = DocUtils.MakeLink({ doc: pushpin }, { doc: doc }, "pushpin", "");