aboutsummaryrefslogtreecommitdiff
path: root/src/client/documents/Documents.ts
diff options
context:
space:
mode:
authorAubrey Li <Aubrey-Li>2021-09-15 14:41:24 -0400
committerAubrey Li <Aubrey-Li>2021-09-15 14:41:24 -0400
commiteb63330e172935343767d0dcc7ffad9bfa1a75c4 (patch)
tree031bf155df50200f9652e881aec18002bc9e399e /src/client/documents/Documents.ts
parentb7a88c6292c2e7bfffc3cdc4f7c7037922b3de25 (diff)
parent8386ad690c10d5c76bbd1b4f85314514b7f11b55 (diff)
merge master into trails-aubrey
Diffstat (limited to 'src/client/documents/Documents.ts')
-rw-r--r--src/client/documents/Documents.ts143
1 files changed, 96 insertions, 47 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index f112bad38..369876428 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,7 +1,7 @@
import { action, runInAction } from "mobx";
-import { basename, extname } from "path";
+import { basename } from "path";
import { DateField } from "../../fields/DateField";
-import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym, Initializing, updateCachedAcls } from "../../fields/Doc";
+import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Initializing, Opt, updateCachedAcls, WidthSym } from "../../fields/Doc";
import { Id } from "../../fields/FieldSymbols";
import { HtmlField } from "../../fields/HtmlField";
import { InkField } from "../../fields/InkField";
@@ -13,20 +13,20 @@ import { ComputedField, ScriptField } from "../../fields/ScriptField";
import { Cast, NumCast, StrCast } from "../../fields/Types";
import { AudioField, ImageField, MapField, PdfField, VideoField, WebField, YoutubeField } from "../../fields/URLField";
import { SharingPermissions } from "../../fields/util";
-import { MessageStore } from "../../server/Message";
import { Upload } from "../../server/SharedMediaTypes";
import { OmitKeys, Utils } from "../../Utils";
import { YoutubeBox } from "../apis/youtube/YoutubeBox";
import { DocServer } from "../DocServer";
import { Networking } from "../Network";
+import { CurrentUserUtils } from "../util/CurrentUserUtils";
import { DocumentManager } from "../util/DocumentManager";
import { dropActionType } from "../util/DragManager";
import { DirectoryImportBox } from "../util/Import & Export/DirectoryImportBox";
import { LinkManager } from "../util/LinkManager";
import { Scripting } from "../util/Scripting";
import { undoBatch, UndoManager } from "../util/UndoManager";
-import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView";
import { CollectionDockingView } from "../views/collections/CollectionDockingView";
+import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView";
import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
import { ContextMenu } from "../views/ContextMenu";
import { ContextMenuProps } from "../views/ContextMenuItem";
@@ -36,30 +36,30 @@ import { AudioBox } from "../views/nodes/AudioBox";
import { ColorBox } from "../views/nodes/ColorBox";
import { ComparisonBox } from "../views/nodes/ComparisonBox";
import { DocFocusOptions } from "../views/nodes/DocumentView";
+import { EquationBox } from "../views/nodes/EquationBox";
+import { FieldViewProps } from "../views/nodes/FieldView";
import { FilterBox } from "../views/nodes/FilterBox";
-import { FontIconBox } from "../views/nodes/FontIconBox";
+import { FontIconBox } from "../views/nodes/button/FontIconBox";
import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox";
+import { FunctionPlotBox } from "../views/nodes/FunctionPlotBox";
import { ImageBox } from "../views/nodes/ImageBox";
import { KeyValueBox } from "../views/nodes/KeyValueBox";
import { LabelBox } from "../views/nodes/LabelBox";
import { LinkBox } from "../views/nodes/LinkBox";
import { LinkDescriptionPopup } from "../views/nodes/LinkDescriptionPopup";
import { PDFBox } from "../views/nodes/PDFBox";
-import { PresBox } from "../views/nodes/trails/PresBox";
import { ScreenshotBox } from "../views/nodes/ScreenshotBox";
import { ScriptingBox } from "../views/nodes/ScriptingBox";
import { SliderBox } from "../views/nodes/SliderBox";
import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox";
+import { PresBox } from "../views/nodes/trails/PresBox";
+import { PresElementBox } from "../views/nodes/trails/PresElementBox";
import { VideoBox } from "../views/nodes/VideoBox";
import { WebBox } from "../views/nodes/WebBox";
-import { PresElementBox } from "../views/nodes/trails/PresElementBox";
import { SearchBox } from "../views/search/SearchBox";
import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
import { DocumentType } from "./DocumentTypes";
-import { EquationBox } from "../views/nodes/EquationBox";
-import { FunctionPlotBox } from "../views/nodes/FunctionPlotBox";
-import { CurrentUserUtils } from "../util/CurrentUserUtils";
-import { FieldViewProps } from "../views/nodes/FieldView";
+import { IconProp } from "@fortawesome/fontawesome-svg-core";
import { MapBox } from "../views/nodes/MapBox/MapBox";
const path = require('path');
@@ -160,6 +160,7 @@ export class DocumentOptions {
lng?: number;
author?: string;
_layoutKey?: string;
+ unrendered?: boolean; // denotes an annotation that is not rendered with a DocumentView (e.g, rtf/pdf text selections and links to scroll locations in web/pdf)
type?: string;
title?: string;
"acl-Public"?: string; // public permissions
@@ -218,7 +219,33 @@ export class DocumentOptions {
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
+
+ // BACKGROUND GRID
+ _backgroundGridShow?: boolean;
+
+ //BUTTONS
+ buttonText?: string;
iconShape?: string; // shapes of the fonticon border
+ btnType?: string;
+ btnList?: List<string>;
+ docColorBtn?: string;
+ userColorBtn?: string;
+ canClick?: string;
+ script?: string;
+ numBtnType?: string;
+ numBtnMax?: number;
+ numBtnMin?: number;
+ switchToggle?: boolean;
+
+ //LINEAR VIEW
+ linearViewIsExpanded?: boolean; // is linear view expanded
+ linearViewExpandable?: boolean; // can linear view be expanded
+ linearViewToggleButton?: string; // button to open close linear view group
+ linearViewSubMenu?: boolean;
+ linearViewFloating?: boolean;
+ flexGap?: number; // Linear view flex gap
+ flexDirection?: "unset" | "row" | "column" | "row-reverse" | "column-reverse";
+
layout_linkView?: Doc; // view template for a link document
layout_keyValue?: string; // view tempalte for key value docs
linkRelationship?: string; // type of relatinoship a link represents
@@ -250,7 +277,12 @@ export class DocumentOptions {
treeViewHideTitle?: boolean; // whether to hide the top document title of a tree view
treeViewHideHeader?: boolean; // whether to hide the header for a document in a tree view
treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items.
- treeViewShowClearButton?: boolean; // whether a clear button should be displayed
+
+ // Action Button
+ buttonMenu?: boolean; // whether a action button should be displayed
+ buttonMenuDoc?: Doc;
+ explainer?: string;
+
treeViewOpenIsTransient?: boolean; // ignores the treeViewOpen Doc flag, allowing a treeViewItem's expand/collapse state to be independent of other views of the same document in the same or any other tree view
_treeViewOpen?: boolean; // whether this document is expanded in a tree view (note: need _ and regular versions since this can be specified for both proto and layout docs)
treeViewOpen?: boolean; // whether this document is expanded in a tree view
@@ -265,14 +297,14 @@ export class DocumentOptions {
text?: string;
textTransform?: string; // is linear view expanded
letterSpacing?: string; // is linear view expanded
- flexDirection?: "unset" | "row" | "column" | "row-reverse" | "column-reverse";
selectedIndex?: number; // which item in a linear view has been selected using the "thumb doc" ui
clipboard?: Doc;
searchQuery?: string; // for quersyBox
- linearViewIsExpanded?: boolean; // is linear view expanded
useLinkSmallAnchor?: boolean; // whether links to this document should use a miniature linkAnchorBox
border?: string; //for searchbox
hoverBackgroundColor?: string; // background color of a label when hovered
+ linkRelationshipList?: List<string>; // for storing different link relationships (when set by user in the link editor)
+ linkColorList?: List<string>; // colors of links corresponding to specific link relationships
}
export namespace Docs {
@@ -359,7 +391,7 @@ export namespace Docs {
}],
[DocumentType.AUDIO, {
layout: { view: AudioBox, dataField: defaultDataKey },
- options: { _height: 35, backgroundColor: "lightGray", links: ComputedField.MakeFunction("links(self)") as any }
+ options: { _height: 100, backgroundColor: "lightGray", links: ComputedField.MakeFunction("links(self)") as any }
}],
[DocumentType.PDF, {
layout: { view: PDFBox, dataField: defaultDataKey },
@@ -685,14 +717,14 @@ export namespace Docs {
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 = {}) {
+ export function InkDocument(color: string, tool: string, strokeWidth: number, strokeBezier: string, fillColor: string, arrowStart: string, arrowEnd: string, dash: string, points: { X: number, Y: number }[], options: DocumentOptions = {}) {
const I = new Doc();
I[Initializing] = true;
I.type = DocumentType.INK;
I.layout = InkingStroke.LayoutString("data");
I.color = color;
I.fillColor = fillColor;
- I.strokeWidth = Number(strokeWidth);
+ I.strokeWidth = strokeWidth;
I.strokeBezier = strokeBezier;
I.strokeStartMarker = arrowStart;
I.strokeEndMarker = arrowEnd;
@@ -701,7 +733,6 @@ export namespace Docs {
I.title = "ink";
I.x = options.x;
I.y = options.y;
- I._backgroundColor = "transparent";
I._width = options._width as number;
I._height = options._height as number;
I._fontFamily = "cursive";
@@ -710,15 +741,26 @@ export namespace Docs {
I.data = new InkField(points);
I["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
I["acl-Override"] = "None";
+ I.links = ComputedField.MakeFunction("links(self)") as any;
I[Initializing] = false;
return I;
}
export function PdfDocument(url: string, options: DocumentOptions = {}) {
+ const width = options._width || undefined;
+ const height = options._height || undefined;
+ const nwid = options._nativeWidth || undefined;
+ const nhght = options._nativeHeight || undefined;
+ if (!nhght && width && height && nwid) options._nativeHeight = Number(nwid) * Number(height) / Number(width);
return InstanceFromProto(Prototypes.get(DocumentType.PDF), new PdfField(url), options);
}
export function WebDocument(url: string, options: DocumentOptions = {}) {
+ const width = options._width || undefined;
+ const height = options._height || undefined;
+ const nwid = options._nativeWidth || undefined;
+ const nhght = options._nativeHeight || undefined;
+ if (!nhght && width && height && nwid) options._nativeHeight = Number(nwid) * Number(height) / Number(width);
return InstanceFromProto(Prototypes.get(DocumentType.WEB), url ? new WebField(url) : undefined, options);
}
@@ -731,9 +773,9 @@ export namespace Docs {
}
export function MapMarkerDocument(lat: number, lng: number, documents: Array<Doc>, options: DocumentOptions, id?: string) {
- return InstanceFromProto(Prototypes.get(DocumentType.MARKER), new List(documents), {lat, lng, ...options}, id);
+ return InstanceFromProto(Prototypes.get(DocumentType.MARKER), new List(documents), { lat, lng, ...options }, id);
}
-
+
export function KVPDocument(document: Doc, options: DocumentOptions = {}) {
return InstanceFromProto(Prototypes.get(DocumentType.KVP), document, { title: document.title + ".kvp", ...options });
}
@@ -932,12 +974,16 @@ export namespace DocUtils {
// facets that have a check next to them
const checks = Object.keys(facet).filter(value => facet[value] === "check");
+ // metadata facets that exist
+ const exists = Object.keys(facet).filter(value => facet[value] === "exists");
+
// facets that have an x next to them
const xs = Object.keys(facet).filter(value => facet[value] === "x");
- if (!xs.length && !checks.length && !matches.length) return true;
+ if (!exists.length && !xs.length && !checks.length && !matches.length) return true;
const failsNotEqualFacets = !xs.length ? false : xs.some(value => Doc.matchFieldValue(d, facetKey, value));
const satisfiesCheckFacets = !checks.length ? true : checks.some(value => Doc.matchFieldValue(d, facetKey, value));
+ const satisfiesExistsFacets = !exists.length ? true : exists.some(value => d[facetKey] !== undefined);
const satisfiesMatchFacets = !matches.length ? true : matches.some(value => {
if (facetKey.startsWith("*")) { // fields starting with a '*' are used to match families of related fields. ie, *lastModified will match text-lastModified, data-lastModified, etc
const allKeys = Array.from(Object.keys(d));
@@ -949,11 +995,11 @@ export namespace DocUtils {
});
// if we're ORing them together, the default return is false, and we return true for a doc if it satisfies any one set of criteria
if ((parentCollection?.currentFilter as Doc)?.filterBoolean === "OR") {
- if (satisfiesCheckFacets && !failsNotEqualFacets && satisfiesMatchFacets) return true;
+ if (satisfiesExistsFacets && satisfiesCheckFacets && !failsNotEqualFacets && satisfiesMatchFacets) return true;
}
// if we're ANDing them together, the default return is true, and we return false for a doc if it doesn't satisfy any set of criteria
else {
- if (!satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false;
+ if (!satisfiesExistsFacets || !satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false;
}
}
@@ -1155,11 +1201,12 @@ export namespace DocUtils {
export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number, simpleMenu: boolean = false): void {
!simpleMenu && ContextMenu.Instance.addItem({
- description: "Add Note ...",
+ description: "Quick Notes",
subitems: DocListCast((Doc.UserDoc()["template-notes"] as Doc).data).map((note, i) => ({
description: ":" + StrCast(note.title),
event: undoBatch((args: { x: number, y: number }) => {
const textDoc = Docs.Create.TextDocument("", {
+ _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize),
_width: 200, x, y, _autoHeight: note._autoHeight !== false,
title: StrCast(note.title) + "#" + (note.aliasCount = NumCast(note.aliasCount) + 1)
});
@@ -1167,12 +1214,12 @@ export namespace DocUtils {
textDoc[textDoc.layoutKey] = note;
docTextAdder(textDoc);
}),
- icon: "eye"
+ icon: StrCast(note.icon) as IconProp
})) as ContextMenuProps[],
- icon: "eye"
+ icon: "sticky-note"
});
- ContextMenu.Instance.addItem({
- description: ":=math", event: () => {
+ const math: ContextMenuProps = ({
+ description: ":Math", event: () => {
const created = Docs.Create.EquationDocument();
if (created) {
created.author = Doc.CurrentUserEmail;
@@ -1183,25 +1230,27 @@ export namespace DocUtils {
EquationBox.SelectOnLoad = created[Id];
docAdder?.(created);
}
- }, icon: "compress-arrows-alt"
+ }, icon: "calculator"
});
+ const documentList: ContextMenuProps[] = DocListCast(Cast(Doc.UserDoc().myItemCreators, Doc, null)?.data).filter(btnDoc => !btnDoc.hidden).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc && doc !== Doc.UserDoc().emptyPresentation).map((dragDoc, i) => ({
+ description: ":" + StrCast(dragDoc.title),
+ event: undoBatch((args: { x: number, y: number }) => {
+ const newDoc = Doc.copyDragFactory(dragDoc);
+ if (newDoc) {
+ newDoc.author = Doc.CurrentUserEmail;
+ newDoc.x = x;
+ newDoc.y = y;
+ if (newDoc.type === DocumentType.RTF) FormattedTextBox.SelectOnLoad = newDoc[Id];
+ docAdder?.(newDoc);
+ }
+ }),
+ icon: Doc.toIcon(dragDoc),
+ })) as ContextMenuProps[];
+ documentList.push(math);
ContextMenu.Instance.addItem({
- description: "Add Template Doc ...",
- subitems: DocListCast(Cast(Doc.UserDoc().myItemCreators, Doc, null)?.data).filter(btnDoc => !btnDoc.hidden).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc && doc !== Doc.UserDoc().emptyPresentation).map((dragDoc, i) => ({
- description: ":" + StrCast(dragDoc.title),
- event: undoBatch((args: { x: number, y: number }) => {
- const newDoc = Doc.copyDragFactory(dragDoc);
- if (newDoc) {
- newDoc.author = Doc.CurrentUserEmail;
- newDoc.x = x;
- newDoc.y = y;
- if (newDoc.type === DocumentType.RTF) FormattedTextBox.SelectOnLoad = newDoc[Id];
- docAdder?.(newDoc);
- }
- }),
- icon: "eye"
- })) as ContextMenuProps[],
- icon: "eye"
+ description: "Create document",
+ subitems: documentList,
+ icon: "file"
});
}// applies a custom template to a document. the template is identified by it's short name (e.g, slideView not layout_slideView)
export function makeCustomViewClicked(doc: Doc, creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) {
@@ -1345,12 +1394,12 @@ export namespace DocUtils {
let degrees = dms[0] / dms[1];
let minutes = dms[2] / dms[3] / 60.0;
let seconds = dms[4] / dms[5] / 3600.0;
-
+
if (['S', 'W'].includes(ref)) {
degrees = -degrees; minutes = -minutes; seconds = -seconds
}
return (degrees + minutes + seconds).toFixed(5);
- }
+ }
}
async function processFileupload(generatedDocuments: Doc[], name: string, type: string, result: Error | Upload.FileInformation, options: DocumentOptions) {