aboutsummaryrefslogtreecommitdiff
path: root/src/client/documents/Documents.ts
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-05-14 23:15:24 -0400
committerbobzel <zzzman@gmail.com>2024-05-14 23:15:24 -0400
commit3534aaf88a3c30a474b3b5a5b7f04adfe6f15fac (patch)
tree47fb7a8671b209bd4d76e0f755a5b035c6936607 /src/client/documents/Documents.ts
parent87bca251d87b5a95da06b2212400ce9427152193 (diff)
parent5cb7ad90e120123ca572e8ef5b1aa6ca41581134 (diff)
Merge branch 'restoringEslint' into sarah-ai-visualization
Diffstat (limited to 'src/client/documents/Documents.ts')
-rw-r--r--src/client/documents/Documents.ts1266
1 files changed, 77 insertions, 1189 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index b160379df..1c18c0d84 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,68 +1,26 @@
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { action, reaction, runInAction } from 'mobx';
+/* eslint-disable prefer-destructuring */
+/* eslint-disable default-param-last */
+/* eslint-disable no-use-before-define */
+import { reaction } from 'mobx';
import { basename } from 'path';
-import { OmitKeys, Utils } from '../../Utils';
+import { ClientUtils, OmitKeys } from '../../ClientUtils';
import { DateField } from '../../fields/DateField';
-import { Doc, DocListCast, Field, LinkedTo, Opt, StrListCast, updateCachedAcls } from '../../fields/Doc';
-import { DocData, Initializing } from '../../fields/DocSymbols';
-import { Id } from '../../fields/FieldSymbols';
+import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, CreateLinkToActiveAudio, Doc, FieldType, Opt, updateCachedAcls } from '../../fields/Doc';
+import { Initializing } from '../../fields/DocSymbols';
import { HtmlField } from '../../fields/HtmlField';
-import { InkField, PointData } from '../../fields/InkField';
+import { InkField } from '../../fields/InkField';
import { List } from '../../fields/List';
import { RichTextField } from '../../fields/RichTextField';
import { SchemaHeaderField } from '../../fields/SchemaHeaderField';
import { ComputedField, ScriptField } from '../../fields/ScriptField';
-import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../fields/Types';
-import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField, YoutubeField } from '../../fields/URLField';
-import { SharingPermissions, inheritParentAcls } from '../../fields/util';
-import { Upload } from '../../server/SharedMediaTypes';
+import { ScriptCast, StrCast } from '../../fields/Types';
+import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from '../../fields/URLField';
+import { SharingPermissions } from '../../fields/util';
+import { PointData } from '../../pen-gestures/GestureTypes';
import { DocServer } from '../DocServer';
-import { Networking } from '../Network';
-import { YoutubeBox } from '../apis/youtube/YoutubeBox';
-import { DragManager, dropActionType } from '../util/DragManager';
-import { FollowLinkScript } from '../util/LinkFollower';
-import { LinkManager } from '../util/LinkManager';
-import { ScriptingGlobals } from '../util/ScriptingGlobals';
-import { UndoManager, undoable } from '../util/UndoManager';
-import { ContextMenu } from '../views/ContextMenu';
-import { ContextMenuProps } from '../views/ContextMenuItem';
-import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke } from '../views/InkingStroke';
-import { CollectionDockingView } from '../views/collections/CollectionDockingView';
-import { CollectionView } from '../views/collections/CollectionView';
-import { DimUnit } from '../views/collections/collectionMulticolumn/CollectionMulticolumnView';
-import { AudioBox, media_state } from '../views/nodes/AudioBox';
-import { ComparisonBox } from '../views/nodes/ComparisonBox';
-import { DataVizBox } from '../views/nodes/DataVizBox/DataVizBox';
-import { OpenWhere } from '../views/nodes/DocumentView';
-import { EquationBox } from '../views/nodes/EquationBox';
-import { FieldViewProps } from '../views/nodes/FieldView';
-import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
-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 { LoadingBox } from '../views/nodes/LoadingBox';
-import { MapBox } from '../views/nodes/MapBox/MapBox';
-import { MapPushpinBox } from '../views/nodes/MapBox/MapPushpinBox';
-import { PDFBox } from '../views/nodes/PDFBox';
-import { PhysicsSimulationBox } from '../views/nodes/PhysicsBox/PhysicsSimulationBox';
-import { RecordingBox } from '../views/nodes/RecordingBox/RecordingBox';
-import { ScreenshotBox } from '../views/nodes/ScreenshotBox';
-import { ScriptingBox } from '../views/nodes/ScriptingBox';
-import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox';
-import { VideoBox } from '../views/nodes/VideoBox';
-import { WebBox } from '../views/nodes/WebBox';
-import { CalendarBox } from '../views/nodes/calendarBox/CalendarBox';
-import { FormattedTextBox } from '../views/nodes/formattedText/FormattedTextBox';
-import { PresBox } from '../views/nodes/trails/PresBox';
-import { PresElementBox } from '../views/nodes/trails/PresElementBox';
-import { SearchBox } from '../views/search/SearchBox';
+import { dropActionType } from '../util/DropActionTypes';
import { CollectionViewType, DocumentType } from './DocumentTypes';
-const { DFLT_IMAGE_NATIVE_DIM } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore
-const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace('px', ''));
class EmptyBox {
public static LayoutString() {
return '';
@@ -73,6 +31,7 @@ export enum FInfoFieldType {
string = 'string',
boolean = 'boolean',
number = 'number',
+ // eslint-disable-next-line @typescript-eslint/no-shadow
Doc = 'Doc',
enumeration = 'enum',
date = 'date',
@@ -83,7 +42,7 @@ export class FInfo {
description: string = '';
readOnly: boolean = false;
fieldType?: FInfoFieldType;
- values?: Field[];
+ values?: FieldType[];
filterable?: boolean = true; // can be used as a Filter in FilterPanel
// format?: string; // format to display values (e.g, decimal places, $, etc)
@@ -134,7 +93,7 @@ class DocInfo extends FInfo {
}
class DimInfo extends FInfo {
fieldType? = FInfoFieldType.enumeration;
- values? = [DimUnit.Pixel, DimUnit.Ratio];
+ values? = []; // DimUnit.Pixel, DimUnit.Ratio];
readOnly = false;
filterable = false;
override searchable = () => false;
@@ -190,7 +149,7 @@ type STRt = StrInfo | string;
type LISTt = ListInfo | List<any>;
type DOCt = DocInfo | Doc;
type RTFt = RtfInfo | RichTextField;
-type DIMt = DimInfo | typeof DimUnit.Pixel | typeof DimUnit.Ratio;
+type DIMt = DimInfo; // | typeof DimUnit.Pixel | typeof DimUnit.Ratio;
type PEVt = PEInfo | 'none' | 'all';
type COLLt = CTypeInfo | CollectionViewType;
type DROPt = DAInfo | dropActionType;
@@ -233,14 +192,16 @@ export class DocumentOptions {
_nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)', false);
_nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)', false);
- 'acl-Guest'?: STRt = new StrInfo("permissions granted to users logged in as 'guest' (either view, or private)"); // public permissions
- '_acl-Guest'?: string; // public permissions
+ acl?: STRt = new StrInfo('unused except as a display category in KeyValueBox');
+ acl_Guest?: STRt = new StrInfo("permissions granted to users logged in as 'guest' (either view, or private)"); // public permissions
+ _acl_Guest?: string; // public permissions
type?: DTYPEt = new DTypeInfo('type of document', true);
type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection
_type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection
title?: STRt = new StrInfo('title of document', true);
title_custom?: BOOLt = new BoolInfo('whether title is a default or has been intentionally set');
caption?: RichTextField;
+ systemIcon?: STRt = new StrInfo("name of icon to use to represent document's type");
author?: string; // STRt = new StrInfo('creator of document'); // bcz: don't change this. Otherwise, the userDoc's field Infos will have a FieldInfo assigned to its author field which will render it unreadable
author_date?: DATEt = new DateInfo('date the document was created', true);
annotationOn?: DOCt = new DocInfo('document annotated by this document', false);
@@ -252,14 +213,20 @@ export class DocumentOptions {
opacity?: NUMt = new NumInfo('document opacity', false);
viewTransitionTime?: NUMt = new NumInfo('transition duration for view parameters', false);
dontRegisterView?: BOOLt = new BoolInfo('are views of this document registered so that they can be found when following links, etc', false);
- _undoIgnoreFields?: List<string>; //'fields that should not be added to the undo stack (opacity for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)'
- undoIgnoreFields?: List<string>; //'fields that should not be added to the undo stack (opacity for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)'
+ _undoIgnoreFields?: List<string>; // 'fields that should not be added to the undo stack (opacity for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)'
+ undoIgnoreFields?: List<string>; // 'fields that should not be added to the undo stack (opacity for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)'
_header_height?: NUMt = new NumInfo('height of document header used for displaying title', false);
_header_fontSize?: NUMt = new NumInfo('font size of header of custom notes', false);
_header_pointerEvents?: PEVt = new PEInfo('types of events the header of a custom text document can consume');
_lockedPosition?: BOOLt = new BoolInfo("lock the x,y coordinates of the document so that it can't be dragged");
_lockedTransform?: BOOLt = new BoolInfo('lock the freeform_panx,freeform_pany and scale parameters of the document so that it be panned/zoomed');
+ dataViz_title?: string;
+ dataViz_line?: string;
+ dataViz_pie?: string;
+ dataViz_histogram?: string;
+ dataViz?: string;
+
layout?: string | Doc; // default layout string or template document
layout_isSvg?: BOOLt = new BoolInfo('whether document decorations and other selections should handle pointerEvents for svg content or use doc bounding box');
layout_keyValue?: STRt = new StrInfo('layout definition for showing keyValue view of document', false);
@@ -313,6 +280,7 @@ export class DocumentOptions {
_text_fontSize?: string;
_text_fontFamily?: string;
_text_fontWeight?: string;
+ fontSize?: string;
_pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views
infoWindowOpen?: BOOLt = new BoolInfo('whether info window corresponding to pin is open (on MapDocuments)');
@@ -321,7 +289,7 @@ export class DocumentOptions {
_label_maxFontSize?: NUMt = new NumInfo('maximum font size for labelBoxes', false);
stroke_width?: NUMt = new NumInfo('width of an ink stroke', false);
stroke_showLabel?: BOOLt = new BoolInfo('show label inside of stroke');
- mediaState?: STRt = new StrInfo(`status of audio/video media document: ${media_state.PendingRecording}, ${media_state.Recording}, ${media_state.Paused}, ${media_state.Playing}`, false);
+ mediaState?: STRt = new StrInfo(`status of audio/video media document:`); // ${mediaState.PendingRecording}, ${mediaState.Recording}, ${mediaState.Paused}, ${mediaState.Playing}`, false);
recording?: BOOLt = new BoolInfo('whether WebCam is recording or not');
slides?: DOCt = new DocInfo('presentation slide associated with video recording (bcz: should be renamed!!)');
autoPlayAnchors?: BOOLt = new BoolInfo('whether to play audio/video when an anchor is clicked in a stackedTimeline.');
@@ -391,6 +359,7 @@ export class DocumentOptions {
// STOPPING HERE
// freeform properties
+ freeform?: STRt = new StrInfo('');
_freeform_backgroundGrid?: BOOLt = new BoolInfo('whether background grid is shown on freeform collections');
_freeform_scale_min?: NUMt = new NumInfo('how far out a view can zoom (used by image/videoBoxes that are clipped');
_freeform_scale_max?: NUMt = new NumInfo('how far in a view can zoom (used by sidebar freeform views');
@@ -401,7 +370,7 @@ export class DocumentOptions {
_freeform_noZoom?: BOOLt = new BoolInfo('disables zooming (used by Pile docs)');
_freeform_fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content');
- //BUTTONS
+ // BUTTONS
buttonText?: string;
btnType?: string;
btnList?: List<string>;
@@ -413,7 +382,7 @@ export class DocumentOptions {
switchToggle?: boolean;
badgeValue?: ScriptField;
- //LINEAR VIEW
+ // LINEAR VIEW
linearView_IsOpen?: BOOLt = new BoolInfo('is linear view open');
linearView_Expandable?: BOOLt = new BoolInfo('can linear view be expanded');
linearView_Dropdown?: BOOLt = new BoolInfo('can linear view be opened as a dropdown');
@@ -421,9 +390,9 @@ export class DocumentOptions {
flexGap?: NUMt = new NumInfo('Linear view flex gap');
flexDirection?: 'unset' | 'row' | 'column' | 'row-reverse' | 'column-reverse';
+ link?: string;
link_description?: string; // added for links
link_relationship?: string; // type of relatinoship a link represents
- link_displayLine?: BOOLt = new BoolInfo('whether a link line should be dipslayed between the two link anchors');
link_displayArrow?: BOOLt = new BoolInfo("whether to display link's directional arrowhead");
link_anchor_1?: DOCt = new DocInfo('start anchor of a link');
link_anchor_2?: DOCt = new DocInfo('end anchor of a link');
@@ -431,7 +400,7 @@ export class DocumentOptions {
link_anchor_1_useSmallAnchor?: BOOLt = new BoolInfo('whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)');
link_anchor_2_useSmallAnchor?: BOOLt = new BoolInfo('whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection)');
link_relationshipList?: List<string>; // for storing different link relationships (when set by user in the link editor)
- link_relationshipSizes?: List<number>; //stores number of links contained in each relationship
+ link_relationshipSizes?: List<number>; // stores number of links contained in each relationship
link_colorList?: List<string>; // colors of links corresponding to specific link relationships
followLinkZoom?: BOOLt = new BoolInfo('whether to zoom to the target of a link');
followLinkToggle?: BOOLt = new BoolInfo('whether target of link should be toggled on and off when following a link to it');
@@ -463,7 +432,7 @@ export class DocumentOptions {
dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', false, true);
dragFactory?: DOCt = new DocInfo('document to create when dragging with a suitable onDragStart script', false);
clickFactory?: DOCt = new DocInfo('document to create when clicking on a button with a suitable onClick script', false);
- onDragStart?: ScriptField; //script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop
+ onDragStart?: ScriptField; // script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop
target?: Doc; // available for use in scripts. used to provide a document parameter to the script (Note, this is a convenience entry since any field could be used for parameterizing a script)
tags?: LISTt = new ListInfo('hashtags added to document, typically using a text view', true);
treeView_HideTitle?: BOOLt = new BoolInfo('whether to hide the top document title of a tree view');
@@ -502,8 +471,6 @@ export class DocumentOptions {
export const DocOptions = new DocumentOptions();
export namespace Docs {
- export let newAccount: boolean = false;
-
export namespace Prototypes {
type LayoutSource = { LayoutString: (key: string) => string };
type PrototypeTemplate = {
@@ -518,117 +485,12 @@ export namespace Docs {
type PrototypeMap = Map<DocumentType, Doc>;
const defaultDataKey = 'data';
- const TemplateMap: TemplateMap = new Map([
- [
- DocumentType.RTF,
- {
- layout: { view: FormattedTextBox, dataField: 'text' },
- options: {
- _height: 35,
- _xMargin: 10,
- _yMargin: 10,
- layout_nativeDimEditable: true,
- layout_reflowVertical: true,
- layout_reflowHorizontal: true,
- defaultDoubleClick: 'ignore',
- systemIcon: 'BsFileEarmarkTextFill',
- },
- },
- ],
- [
- DocumentType.SEARCH,
- {
- layout: { view: SearchBox, dataField: defaultDataKey },
- options: { _width: 400 },
- },
- ],
- [
- DocumentType.IMG,
- {
- layout: { view: ImageBox, dataField: defaultDataKey },
- options: { freeform: '', systemIcon: 'BsFileEarmarkImageFill' },
- },
- ],
- [
- DocumentType.WEB,
- {
- layout: { view: WebBox, dataField: defaultDataKey },
- options: { _height: 300, _layout_fitWidth: true, layout_nativeDimEditable: true, layout_reflowVertical: true, waitForDoubleClickToClick: 'always', systemIcon: 'BsGlobe' },
- },
- ],
+ export const TemplateMap: TemplateMap = new Map([
[
- DocumentType.COL,
- {
- layout: { view: CollectionView, dataField: defaultDataKey },
- options: {
- _layout_fitWidth: true,
- freeform: '',
- _freeform_panX: 0,
- _freeform_panY: 0,
- _freeform_scale: 1,
- layout_nativeDimEditable: true,
- layout_reflowHorizontal: true,
- layout_reflowVertical: true,
- systemIcon: 'BsFillCollectionFill',
- },
- },
- ],
- [
- DocumentType.KVP,
- {
- layout: { view: KeyValueBox, dataField: defaultDataKey },
- options: { _layout_fitWidth: true, _height: 150 },
- },
- ],
- [
- DocumentType.VID,
- {
- layout: { view: VideoBox, dataField: defaultDataKey },
- options: { _layout_currentTimecode: 0, systemIcon: 'BsFileEarmarkPlayFill' },
- },
- ],
- [
- DocumentType.AUDIO,
- {
- layout: { view: AudioBox, dataField: defaultDataKey },
- options: { _height: 100, layout_fitWidth: true, layout_reflowHorizontal: true, layout_reflowVertical: true, layout_nativeDimEditable: true, systemIcon: 'BsFillVolumeUpFill' },
- },
- ],
- [
- DocumentType.REC,
- {
- layout: { view: VideoBox, dataField: defaultDataKey },
- options: { _height: 100, backgroundColor: 'pink', systemIcon: 'BsFillMicFill' },
- },
- ],
- [
- DocumentType.PDF,
- {
- layout: { view: PDFBox, dataField: defaultDataKey },
- options: { _layout_curPage: 1, _layout_fitWidth: true, layout_nativeDimEditable: true, layout_reflowVertical: true, systemIcon: 'BsFileEarmarkPdfFill' },
- },
- ],
- [
- DocumentType.MAP,
- {
- layout: { view: MapBox, dataField: defaultDataKey },
- options: { map: '', _height: 600, _width: 800, layout_reflowHorizontal: true, layout_reflowVertical: true, layout_nativeDimEditable: true, systemIcon: 'BsFillPinMapFill' },
- },
- ],
- [
- DocumentType.LINK,
+ DocumentType.GROUPDB,
{
- layout: { view: LinkBox, dataField: 'link' },
- options: {
- childDontRegisterViews: true,
- layout_hideLinkAnchors: true,
- _height: 1,
- _width: 1,
- link: '',
- link_description: '',
- color: 'lightBlue', // lightblue is default color for linking dot and link documents text comment area
- _dropPropertiesToRemove: new List(['onClick']),
- },
+ layout: { view: EmptyBox, dataField: defaultDataKey },
+ options: { acl: '', title: 'Global Group Database' },
},
],
[
@@ -636,195 +498,22 @@ export namespace Docs {
{
data: new List<Doc>(),
layout: { view: EmptyBox, dataField: defaultDataKey },
- options: { title: 'Global Script Database' },
- },
- ],
- [
- DocumentType.SCRIPTING,
- {
- layout: { view: ScriptingBox, dataField: defaultDataKey },
- options: { systemIcon: 'BsFileEarmarkCodeFill' },
- },
- ],
- [
- DocumentType.YOUTUBE,
- {
- layout: { view: YoutubeBox, dataField: defaultDataKey },
- },
- ],
- [
- DocumentType.LABEL,
- {
- layout: { view: LabelBox, dataField: 'title' },
- options: { _singleLine: true, layout_nativeDimEditable: true, layout_reflowHorizontal: true, layout_reflowVertical: true },
- },
- ],
- [
- DocumentType.EQUATION,
- {
- layout: { view: EquationBox, dataField: 'text' },
- options: {
- fontSize: '14px',
- layout_reflowHorizontal: true,
- layout_reflowVertical: true,
- layout_nativeDimEditable: true,
- layout_hideDecorationTitle: true,
- systemIcon: 'BsCalculatorFill',
- }, ///systemIcon: 'BsSuperscript' + BsSubscript
- },
- ],
- [
- DocumentType.FUNCPLOT,
- {
- layout: { view: FunctionPlotBox, dataField: defaultDataKey },
- options: {
- layout_reflowHorizontal: true,
- layout_reflowVertical: true,
- layout_nativeDimEditable: true,
- },
- },
- ],
- [
- DocumentType.BUTTON,
- {
- layout: { view: LabelBox, dataField: 'title' },
- options: { layout_nativeDimEditable: true, layout_reflowHorizontal: true, layout_reflowVertical: true },
- },
- ],
- [
- DocumentType.PRES,
- {
- layout: { view: PresBox, dataField: defaultDataKey },
- options: { defaultDoubleClick: 'ignore', hideClickBehaviors: true, layout_hideLinkAnchors: true },
- },
- ],
- [
- DocumentType.FONTICON,
- {
- layout: { view: FontIconBox, dataField: 'icon' },
- options: { defaultDoubleClick: 'ignore', waitForDoubleClickToClick: 'never', layout_hideContextMenu: true, layout_hideLinkButton: true, _width: 40, _height: 40 },
- },
- ],
- [
- DocumentType.WEBCAM,
- {
- layout: { view: RecordingBox, dataField: defaultDataKey },
- options: { systemIcon: 'BsFillCameraVideoFill' },
- },
- ],
- [
- DocumentType.PRESELEMENT,
- {
- layout: { view: PresElementBox, dataField: defaultDataKey },
- options: { title: 'pres element template', _layout_fitWidth: true, _xMargin: 0, isTemplateDoc: true, isTemplateForField: 'data' },
+ options: { acl: '', title: 'Global Script Database' },
},
],
+
[
DocumentType.CONFIG,
{
- layout: { view: CollectionView, dataField: defaultDataKey },
- options: { config: '', layout_hideLinkButton: true, layout_unrendered: true },
- },
- ],
- [
- DocumentType.INK,
- {
- // NOTE: this is unused!! ink fields are filled in directly within the InkDocument() method
- layout: { view: InkingStroke, dataField: 'stroke' },
- options: {
- systemIcon: 'BsFillPencilFill', //
- layout_nativeDimEditable: true,
- layout_reflowVertical: true,
- layout_reflowHorizontal: true,
- layout_hideDecorationTitle: true, // don't show title when selected
- fitWidth: false,
- layout_isSvg: true,
- },
- },
- ],
- [
- DocumentType.SCREENSHOT,
- {
- layout: { view: ScreenshotBox, dataField: defaultDataKey },
- options: { layout_nativeDimEditable: true, systemIcon: 'BsCameraFill' },
- },
- ],
- [
- DocumentType.COMPARISON,
- {
- data: '',
- layout: { view: ComparisonBox, dataField: defaultDataKey },
- options: { backgroundColor: 'gray', dropAction: dropActionType.move, waitForDoubleClickToClick: 'always', layout_reflowHorizontal: true, layout_reflowVertical: true, layout_nativeDimEditable: true, systemIcon: 'BsLayoutSplit' },
- },
- ],
- [
- DocumentType.GROUPDB,
- {
layout: { view: EmptyBox, dataField: defaultDataKey },
- options: { title: 'Global Group Database' },
- },
- ],
- [
- DocumentType.GROUP,
- {
- layout: { view: EmptyBox, dataField: defaultDataKey },
- options: {},
- },
- ],
- [
- DocumentType.DATAVIZ,
- {
- layout: { view: DataVizBox, dataField: defaultDataKey },
- options: { dataViz_title: '', dataViz_line: '', dataViz_pie: '', dataViz_histogram: '', dataViz: 'table', _layout_fitWidth: true, layout_reflowHorizontal: true, layout_reflowVertical: true, layout_nativeDimEditable: true },
- },
- ],
- [
- DocumentType.LOADING,
- {
- layout: { view: LoadingBox, dataField: '' },
- options: { _layout_fitWidth: true, _fitHeight: true, layout_nativeDimEditable: true },
- },
- ],
- [
- DocumentType.SIMULATION,
- {
- data: '',
- layout: { view: PhysicsSimulationBox, dataField: defaultDataKey, _width: 1000, _height: 800 },
- options: {
- _height: 100,
- mass1: '',
- mass2: '',
- layout_nativeDimEditable: true,
- position: '',
- acceleration: '',
- pendulum: '',
- spring: '',
- wedge: '',
- simulation: '',
- review: '',
- systemIcon: 'BsShareFill',
- },
- },
- ],
- [
- DocumentType.PUSHPIN,
- {
- layout: { view: MapPushpinBox, dataField: defaultDataKey },
- options: {},
+ options: { acl: '', config: '', layout_hideLinkButton: true, layout_unrendered: true },
},
],
[
DocumentType.MAPROUTE,
{
- layout: { view: CollectionView, dataField: defaultDataKey },
- options: {},
- },
- ],
- [
- DocumentType.CALENDAR,
- {
- layout: { view: CalendarBox, dataField: defaultDataKey },
- options: {},
+ layout: { view: EmptyBox, dataField: defaultDataKey },
+ options: { acl: '' },
},
],
]);
@@ -850,7 +539,7 @@ export namespace Docs {
// fetch the actual prototype documents from the server
const actualProtos = await DocServer.GetRefFields(prototypeIds);
// update this object to include any default values: DocumentOptions for all prototypes
- prototypeIds.map(id => {
+ prototypeIds.forEach(id => {
const existing = actualProtos[id] as Doc;
const type = id.replace(suffix, '') as DocumentType;
// get or create prototype of the specified type...
@@ -908,7 +597,7 @@ export namespace Docs {
if (!template) {
return undefined;
}
- const layout = template.layout;
+ const { layout } = template;
// create title
const upper = suffix.toUpperCase();
const title = prototypeId.toUpperCase().replace(upper, `_${upper}`);
@@ -921,14 +610,14 @@ export namespace Docs {
type,
isBaseProto: true,
_width: 300,
- 'acl-Guest': SharingPermissions.View,
+ acl_Guest: SharingPermissions.View,
...(template.options || {}),
layout: layout.view?.LayoutString(layout.dataField),
data: template.data,
};
Object.entries(options)
.filter(pair => typeof pair[1] === 'string' && pair[1].startsWith('@'))
- .map(pair => {
+ .forEach(pair => {
if (!existing || ScriptCast(existing[pair[0]])?.script.originalScript !== pair[1].substring(1)) {
(options as any)[pair[0]] = ComputedField.MakeFunction(pair[1].substring(1));
}
@@ -960,15 +649,17 @@ export namespace Docs {
* only when creating a DockDocument from the current user's already existing
* main document.
*/
- function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = 'data', protoId?: string, placeholderDoc?: Doc, noView?: boolean) {
+ // eslint-disable-next-line default-param-last
+ function InstanceFromProto(proto: Doc, data: FieldType | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = 'data', protoId?: string, placeholderDocIn?: Doc, noView?: boolean) {
+ const placeholderDoc = placeholderDocIn;
const viewKeys = ['x', 'y', 'isSystem']; // keys that should be addded to the view document even though they don't begin with an "_"
const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, '^_');
- // dataProps['acl-Override'] = SharingPermissions.Unset;
- dataProps['acl-Guest'] = options['acl-Guest'] ?? (Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View);
+ // dataProps.acl_Override = SharingPermissions.Unset;
+ dataProps.acl_Guest = options.acl_Guest ?? (Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View);
dataProps.isSystem = viewProps.isSystem;
dataProps.isDataDoc = true;
- dataProps.author = Doc.CurrentUserEmail;
+ dataProps.author = ClientUtils.CurrentUserEmail();
dataProps.author_date = new DateField();
if (fieldKey) {
dataProps[`${fieldKey}_modificationDate`] = new DateField();
@@ -988,8 +679,8 @@ export namespace Docs {
}
if (!noView) {
- const viewFirstProps: { [id: string]: any } = { author: Doc.CurrentUserEmail };
- viewFirstProps['acl-Guest'] = options['_acl-Guest'] ?? (Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View);
+ const viewFirstProps: { [id: string]: any } = { author: ClientUtils.CurrentUserEmail() };
+ viewFirstProps.acl_Guest = options._acl_Guest ?? (Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View);
let viewDoc: Doc;
// determines whether viewDoc should be created using placeholder Doc or default
if (placeholderDoc) {
@@ -997,14 +688,16 @@ export namespace Docs {
placeholderDoc._width = options._width !== undefined ? Number(options._width) : undefined;
viewDoc = Doc.assign(placeholderDoc, viewFirstProps, true, true);
Array.from(Object.keys(placeholderDoc))
- .filter(key => key.startsWith('acl'))
- .forEach(key => (dataDoc[key] = viewDoc[key] = placeholderDoc[key]));
+ .filter(key => key.startsWith('acl_'))
+ .forEach(key => {
+ dataDoc[key] = viewDoc[key] = placeholderDoc[key];
+ });
} else {
viewDoc = Doc.assign(Doc.MakeDelegate(dataDoc, delegId), viewFirstProps, true, true);
}
Doc.assign(viewDoc, viewProps, true, true);
if (![DocumentType.LINK, DocumentType.CONFIG, DocumentType.LABEL].includes(viewDoc.type as any)) {
- DocUtils.MakeLinkToActiveAudio(() => viewDoc);
+ CreateLinkToActiveAudio(() => viewDoc);
}
updateCachedAcls(dataDoc);
updateCachedAcls(viewDoc);
@@ -1017,6 +710,7 @@ export namespace Docs {
return dataDoc;
}
+ // eslint-disable-next-line default-param-last
export function ImageDocument(url: string | ImageField, options: DocumentOptions = {}, overwriteDoc?: Doc) {
const imgField = url instanceof ImageField ? url : url ? new ImageField(url) : undefined;
return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: basename(imgField?.url.href ?? '-no image-'), ...options }, undefined, undefined, undefined, overwriteDoc);
@@ -1035,18 +729,16 @@ export namespace Docs {
* @param fieldKey the field that the compiled script is written into.
* @returns the Scripting Doc
*/
+ // eslint-disable-next-line default-param-last
export function ScriptingDocument(script: Opt<ScriptField> | null, options: DocumentOptions = {}, fieldKey?: string) {
- return InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), script ? script : undefined, { ...options, layout: fieldKey ? ScriptingBox.LayoutString(fieldKey) : undefined });
+ return InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), script || undefined, { ...options, layout: fieldKey ? `<ScriptingBox {...props} fieldKey={'${fieldKey}'}/>` /* ScriptingBox.LayoutString(fieldKey) */ : undefined });
}
+ // eslint-disable-next-line default-param-last
export function VideoDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) {
return InstanceFromProto(Prototypes.get(DocumentType.VID), new VideoField(url), options, undefined, undefined, undefined, overwriteDoc);
}
- export function YoutubeDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) {
- return InstanceFromProto(Prototypes.get(DocumentType.YOUTUBE), new YoutubeField(url), options, undefined, undefined, undefined, overwriteDoc);
- }
-
export function WebCamDocument(url: string, options: DocumentOptions = {}) {
return InstanceFromProto(Prototypes.get(DocumentType.WEBCAM), '', options);
}
@@ -1059,6 +751,7 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.COMPARISON), undefined, options);
}
+ // eslint-disable-next-line default-param-last
export function AudioDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) {
return InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(url), options, undefined, undefined, undefined, overwriteDoc);
}
@@ -1072,7 +765,7 @@ export namespace Docs {
}
export function LoadingDocument(file: File | string, options: DocumentOptions) {
- return InstanceFromProto(Prototypes.get(DocumentType.LOADING), undefined, { _height: 150, _width: 200, title: typeof file == 'string' ? file : file.name, ...options }, undefined, '');
+ return InstanceFromProto(Prototypes.get(DocumentType.LOADING), undefined, { _height: 150, _width: 200, title: typeof file === 'string' ? file : file.name, ...options }, undefined, '');
}
export function RTFDocument(field: RichTextField, options: DocumentOptions = {}, fieldKey: string = 'text') {
@@ -1101,6 +794,7 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.RTF), field, options, undefined, fieldKey);
}
+ // eslint-disable-next-line default-param-last
export function LinkDocument(source: Doc, target: Doc, options: DocumentOptions = {}, id?: string) {
const linkDoc = InstanceFromProto(
Prototypes.get(DocumentType.LINK),
@@ -1114,7 +808,7 @@ export namespace Docs {
'link'
);
- LinkManager.Instance.addLink(linkDoc);
+ Doc.AddLink(linkDoc);
return linkDoc;
}
@@ -1124,7 +818,7 @@ export namespace Docs {
options: DocumentOptions = {},
strokeWidth = ActiveInkWidth(),
color = ActiveInkColor(),
- stroke_bezier = ActiveInkBezierApprox(),
+ strokeBezier = ActiveInkBezierApprox(),
fillColor = ActiveFillColor(),
arrowStart = ActiveArrowStart(),
arrowEnd = ActiveArrowEnd(),
@@ -1138,7 +832,7 @@ export namespace Docs {
I.fillColor = fillColor;
I.stroke = new InkField(points);
I.stroke_width = strokeWidth;
- I.stroke_bezier = stroke_bezier;
+ I.stroke_bezier = strokeBezier;
I.stroke_startMarker = arrowStart;
I.stroke_endMarker = arrowEnd;
I.stroke_dash = dash;
@@ -1147,13 +841,14 @@ export namespace Docs {
I.rotation = 0;
I.defaultDoubleClick = 'ignore';
I.author_date = new DateField();
- I['acl-Guest'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View;
- //I['acl-Override'] = SharingPermissions.Unset;
+ I.acl_Guest = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View;
+ // I.acl_Override = SharingPermissions.Unset;
I[Initializing] = false;
return ink;
}
+ // eslint-disable-next-line default-param-last
export function PdfDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) {
const width = options._width || undefined;
const height = options._height || undefined;
@@ -1169,7 +864,7 @@ export namespace Docs {
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), new WebField(url ? url : 'https://www.wikipedia.org/'), options);
+ return InstanceFromProto(Prototypes.get(DocumentType.WEB), new WebField(url || 'https://www.wikipedia.org/'), options);
}
export function HtmlDocument(html: string, options: DocumentOptions = {}) {
@@ -1306,34 +1001,6 @@ export namespace Docs {
return ret;
}
- export type DocConfig = {
- doc: Doc;
- initialWidth?: number;
- path?: Doc[];
- };
-
- export function StandardCollectionDockingDocument(configs: Array<DocConfig>, options: DocumentOptions, id?: string, type: string = 'row') {
- const layoutConfig = {
- content: [
- {
- type: type,
- content: [...configs.map(config => CollectionDockingView.makeDocumentConfig(config.doc, undefined, config.initialWidth))],
- },
- ],
- };
- const doc = DockDocument(
- configs.map(c => c.doc),
- JSON.stringify(layoutConfig),
- Doc.CurrentUserEmail === 'guest' ? options : { 'acl-Guest': SharingPermissions.View, ...options },
- id
- );
- configs.map(c => {
- Doc.SetContainer(c.doc, doc);
- inheritParentAcls(doc, c.doc, false);
- });
- return doc;
- }
-
export function DelegateDocument(proto: Doc, options: DocumentOptions = {}) {
return InstanceFromProto(proto, undefined, options);
}
@@ -1343,782 +1010,3 @@ export namespace Docs {
}
}
}
-
-export namespace DocUtils {
- function matchFieldValue(doc: Doc, key: string, value: any): boolean {
- const hasFunctionFilter = Utils.HasFunctionFilter(value);
- if (hasFunctionFilter) {
- return hasFunctionFilter(StrCast(doc[key]));
- }
- if (key === LinkedTo) {
- // links are not a field value, so handled here. value is an expression of form ([field=]idToDoc("..."))
- const allLinks = LinkManager.Instance.getAllRelatedLinks(doc);
- const matchLink = (value: string, anchor: Doc) => {
- const linkedToExp = (value ?? '').split('=');
- if (linkedToExp.length === 1) return Field.toScriptString(anchor) === value;
- return Field.toScriptString(DocCast(anchor[linkedToExp[0]])) === linkedToExp[1];
- };
- // prettier-ignore
- return (value === Doc.FilterNone && !allLinks.length) ||
- (value === Doc.FilterAny && !!allLinks.length) ||
- (allLinks.some(link => matchLink(value,DocCast(link.link_anchor_1)) ||
- matchLink(value,DocCast(link.link_anchor_2)) ));
- }
- if (typeof value === 'string') {
- value = value.replace(`,${Utils.noRecursionHack}`, '');
- }
- const fieldVal = doc[key];
- // prettier-ignore
- if ((value === Doc.FilterAny && fieldVal !== undefined) ||
- (value === Doc.FilterNone && fieldVal === undefined)) {
- return true;
- }
- const vals = StrListCast(fieldVal); // list typing is very imperfect. casting to a string list doesn't mean that the entries will actually be strings
- if (vals.length) {
- return vals.some(v => typeof v === 'string' && v.includes(value)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
- }
- return Field.toString(fieldVal as Field).includes(value); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
- }
- /**
- * @param docs
- * @param childFilters
- * @param childFiltersByRanges
- * @param parentCollection
- * Given a list of docs and childFilters, @returns the list of Docs that match those filters
- */
- export function FilterDocs(childDocs: Doc[], childFilters: string[], childFiltersByRanges: string[], parentCollection?: Doc) {
- if (!childFilters?.length && !childFiltersByRanges?.length) {
- return childDocs.filter(d => !d.cookies); // remove documents that need a cookie if there are no filters to provide one
- }
-
- const filterFacets: { [key: string]: { [value: string]: string } } = {}; // maps each filter key to an object with value=>modifier fields
- childFilters.forEach(filter => {
- const fields = filter.split(Doc.FilterSep);
- const key = fields[0];
- const value = fields[1];
- const modifiers = fields[2];
- if (!filterFacets[key]) {
- filterFacets[key] = {};
- }
- filterFacets[key][value] = modifiers;
- });
-
- const filteredDocs = childFilters.length
- ? childDocs.filter(d => {
- if (d.z) return true;
- // if the document needs a cookie but no filter provides the cookie, then the document does not pass the filter
- if (d.cookies && (!filterFacets.cookies || !Object.keys(filterFacets.cookies).some(key => d.cookies === key))) {
- return false;
- }
- for (const facetKey of Object.keys(filterFacets).filter(fkey => fkey !== 'cookies' && fkey !== Utils.noDragDocsFilter.split(Doc.FilterSep)[0])) {
- const facet = filterFacets[facetKey];
-
- // facets that match some value in the field of the document (e.g. some text field)
- const matches = Object.keys(facet).filter(value => value !== 'cookies' && facet[value] === 'match');
-
- // 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 unset metadata (a hack for making cookies work)
- const unsets = Object.keys(facet).filter(value => facet[value] === 'unset');
-
- // facets that specify that a field must not match a specific value
- const xs = Object.keys(facet).filter(value => facet[value] === 'x');
-
- if (!unsets.length && !exists.length && !xs.length && !checks.length && !matches.length) return true;
- const failsNotEqualFacets = !xs.length ? false : xs.some(value => matchFieldValue(d, facetKey, value));
- const satisfiesCheckFacets = !checks.length ? true : checks.some(value => matchFieldValue(d, facetKey, value));
- const satisfiesExistsFacets = !exists.length ? true : exists.some(value => (facetKey !== LinkedTo ? d[facetKey] !== undefined : LinkManager.Instance.getAllRelatedLinks(d).length));
- const satisfiesUnsetsFacets = !unsets.length ? true : unsets.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, *modificationDate will match text_modificationDate, data_modificationDate, etc
- const allKeys = Array.from(Object.keys(d));
- allKeys.push(...Object.keys(Doc.GetProto(d)));
- const keys = allKeys.filter(key => key.includes(facetKey.substring(1)));
- return keys.some(key => Field.toString(d[key] as Field).includes(value));
- }
- return Field.toString(d[facetKey] as Field).includes(value);
- });
- // 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?.childFilters_boolean === 'OR') {
- if (satisfiesUnsetsFacets && 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 (!satisfiesUnsetsFacets || !satisfiesExistsFacets || !satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false;
- }
- }
- return parentCollection?.childFilters_boolean === 'OR' ? false : true;
- })
- : childDocs;
- const rangeFilteredDocs = filteredDocs.filter(d => {
- for (let i = 0; i < childFiltersByRanges.length; i += 3) {
- const key = childFiltersByRanges[i];
- const min = Number(childFiltersByRanges[i + 1]);
- const max = Number(childFiltersByRanges[i + 2]);
- const val = typeof d[key] === 'string' ? (Number(StrCast(d[key])).toString() === StrCast(d[key]) ? Number(StrCast(d[key])) : undefined) : Cast(d[key], 'number', null);
- if (val === undefined) {
- //console.log("Should 'undefined' pass range filter or not?")
- } else if (val < min || val > max) return false;
- }
- return true;
- });
- return rangeFilteredDocs;
- }
-
- export let ActiveRecordings: { props: FieldViewProps; getAnchor: (addAsAnnotation: boolean) => Doc }[] = [];
-
- export function MakeLinkToActiveAudio(getSourceDoc: () => Doc | undefined, broadcastEvent = true) {
- broadcastEvent && runInAction(() => (Doc.RecordingEvent = Doc.RecordingEvent + 1));
- return DocUtils.ActiveRecordings.map(audio => {
- const sourceDoc = getSourceDoc();
- return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { link_displayLine: false, link_relationship: 'recording annotation:linked recording', link_description: 'recording timeline' });
- });
- }
-
- export function MakeLink(source: Doc, target: Doc, linkSettings: { link_relationship?: string; link_description?: string; link_displayLine?: boolean }, id?: string, showPopup?: number[]) {
- if (!linkSettings.link_relationship) linkSettings.link_relationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link';
- if (target.doc === Doc.UserDoc()) return undefined;
-
- const makeLink = action((linkDoc: Doc, showPopup?: number[]) => {
- if (showPopup) {
- LinkManager.Instance.currentLink = linkDoc;
-
- TaskCompletionBox.textDisplayed = 'Link Created';
- TaskCompletionBox.popupX = showPopup[0];
- TaskCompletionBox.popupY = showPopup[1] - 33;
- TaskCompletionBox.taskCompleted = true;
-
- LinkDescriptionPopup.Instance.popupX = showPopup[0];
- LinkDescriptionPopup.Instance.popupY = showPopup[1];
- LinkDescriptionPopup.Instance.display = true;
-
- const rect = document.body.getBoundingClientRect();
- if (LinkDescriptionPopup.Instance.popupX + 200 > rect.width) {
- LinkDescriptionPopup.Instance.popupX -= 190;
- TaskCompletionBox.popupX -= 40;
- }
- if (LinkDescriptionPopup.Instance.popupY + 100 > rect.height) {
- LinkDescriptionPopup.Instance.popupY -= 40;
- TaskCompletionBox.popupY -= 40;
- }
-
- setTimeout(
- action(() => (TaskCompletionBox.taskCompleted = false)),
- 2500
- );
- }
- return linkDoc;
- });
-
- const a = source.layout_unrendered ? 'link_anchor_1?.annotationOn' : 'link_anchor_1';
- const b = target.layout_unrendered ? 'link_anchor_2?.annotationOn' : 'link_anchor_2';
-
- return makeLink(
- Docs.Create.LinkDocument(
- source,
- target,
- {
- 'acl-Guest': SharingPermissions.Augment,
- '_acl-Guest': SharingPermissions.Augment,
- title: ComputedField.MakeFunction('generateLinkTitle(this)') as any,
- link_anchor_1_useSmallAnchor: source.useSmallAnchor ? true : undefined,
- link_anchor_2_useSmallAnchor: target.useSmallAnchor ? true : undefined,
- link_displayLine: linkSettings.link_displayLine,
- link_relationship: linkSettings.link_relationship,
- link_description: linkSettings.link_description,
- x: ComputedField.MakeFunction(`((this.${a}?.x||0)+(this.${b}?.x||0))/2`) as any,
- y: ComputedField.MakeFunction(`((this.${a}?.y||0)+(this.${b}?.y||0))/2`) as any,
- link_autoMoveAnchors: true,
- _lockedPosition: true,
- _layout_showCaption: '', // removed since they conflict with showing a link with a LinkBox (ie, line, not comparison box)
- _layout_showTitle: '',
- // _layout_showCaption: 'link_description',
- // _layout_showTitle: 'link_relationship',
- },
- id
- ),
- showPopup
- );
- }
-
- export function AssignScripts(doc: Doc, scripts?: { [key: string]: string | undefined }, funcs?: { [key: string]: string }) {
- scripts &&
- Object.keys(scripts).map(key => {
- const script = scripts[key];
- if (ScriptCast(doc[key])?.script.originalScript !== scripts[key] && script) {
- (key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = ScriptField.MakeScript(script, {
- self: Doc.name,
- this: Doc.name,
- dragData: DragManager.DocumentDragData.name,
- value: 'any',
- _readOnly_: 'boolean',
- scriptContext: 'any',
- documentView: Doc.name,
- heading: Doc.name,
- checked: 'boolean',
- containingTreeView: Doc.name,
- altKey: 'boolean',
- ctrlKey: 'boolean',
- shiftKey: 'boolean',
- });
- }
- });
- funcs &&
- Object.keys(funcs)
- .filter(key => !key.endsWith('-setter'))
- .map(key => {
- const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
- if (ScriptCast(cfield)?.script.originalScript !== funcs[key]) {
- const setFunc = Cast(funcs[key + '-setter'], 'string', null);
- (key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = funcs[key] ? ComputedField.MakeFunction(funcs[key], { dragData: DragManager.DocumentDragData.name }, { _readOnly_: true }, setFunc) : undefined;
- }
- });
- return doc;
- }
- export function AssignOpts(doc: Doc | undefined, reqdOpts: DocumentOptions, items?: Doc[]) {
- if (doc) {
- const compareValues = (val1: any, val2: any) => {
- if (val1 instanceof List && val2 instanceof List && val1.length === val2.length) {
- return !val1.some(v => !val2.includes(v)) || !val2.some(v => val1.includes(v));
- }
- return val1 === val2;
- };
- Object.entries(reqdOpts).forEach(pair => {
- const targetDoc = pair[0].startsWith('_') ? doc : Doc.GetProto(doc as Doc);
- if (!Object.getOwnPropertyNames(targetDoc).includes(pair[0].replace(/^_/, '')) || !compareValues(pair[1], targetDoc[pair[0]])) {
- targetDoc[pair[0]] = pair[1];
- }
- });
- items?.forEach(item => !DocListCast(doc.data).includes(item) && Doc.AddDocToList(Doc.GetProto(doc), 'data', item));
- items && DocListCast(doc.data).forEach(item => Doc.IsSystem(item) && !items.includes(item) && Doc.RemoveDocFromList(Doc.GetProto(doc), 'data', item));
- }
- return doc;
- }
- export function AssignDocField(doc: Doc, field: string, creator: (reqdOpts: DocumentOptions, items?: Doc[]) => Doc, reqdOpts: DocumentOptions, items?: Doc[], scripts?: { [key: string]: string }, funcs?: { [key: string]: string }) {
- return DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(doc[field]), reqdOpts, items) ?? (doc[field] = creator(reqdOpts, items)), scripts, funcs);
- }
-
- export function DocumentFromField(target: Doc, fieldKey: string, proto?: Doc, options?: DocumentOptions): Doc | undefined {
- let created: Doc | undefined;
- const field = target[fieldKey];
- const resolved = options ?? {};
- if (field instanceof ImageField) {
- created = Docs.Create.ImageDocument(field.url.href, resolved);
- created.layout = ImageBox.LayoutString(fieldKey);
- } else if (field instanceof Doc) {
- created = field;
- } else if (field instanceof VideoField) {
- created = Docs.Create.VideoDocument(field.url.href, resolved);
- created.layout = VideoBox.LayoutString(fieldKey);
- } else if (field instanceof PdfField) {
- created = Docs.Create.PdfDocument(field.url.href, resolved);
- created.layout = PDFBox.LayoutString(fieldKey);
- } else if (field instanceof AudioField) {
- created = Docs.Create.AudioDocument(field.url.href, resolved);
- created.layout = AudioBox.LayoutString(fieldKey);
- } else if (field instanceof InkField) {
- created = Docs.Create.InkDocument(field.inkData, resolved);
- created.layout = InkingStroke.LayoutString(fieldKey);
- } else if (field instanceof List && field[0] instanceof Doc) {
- created = Docs.Create.StackingDocument(DocListCast(field), resolved);
- created.layout = CollectionView.LayoutString(fieldKey);
- } else {
- created = Docs.Create.TextDocument('', { ...{ _width: 200, _height: 25, _layout_autoHeight: true }, ...resolved });
- created.layout = FormattedTextBox.LayoutString(fieldKey);
- }
- if (created) {
- created.title = fieldKey;
- proto && created.proto && (created.proto = Doc.GetProto(proto));
- }
- return created;
- }
-
- /**
- *
- * @param type the type of file.
- * @param path the path to the file.
- * @param options the document options.
- * @param overwriteDoc the placeholder loading doc.
- * @returns
- */
- export async function DocumentFromType(type: string, path: string, options: DocumentOptions, overwriteDoc?: Doc): Promise<Opt<Doc>> {
- let ctor: ((path: string, options: DocumentOptions, overwriteDoc?: Doc) => Doc | Promise<Doc | undefined>) | undefined = undefined;
- if (type.indexOf('image') !== -1) {
- ctor = Docs.Create.ImageDocument;
- if (!options._width) options._width = 300;
- }
- if (type.indexOf('video') !== -1) {
- ctor = Docs.Create.VideoDocument;
- if (!options._width) options._width = 600;
- if (!options._height) options._height = ((options._width as number) * 2) / 3;
- }
- if (type.indexOf('audio') !== -1) {
- ctor = Docs.Create.AudioDocument;
- }
- if (type.indexOf('pdf') !== -1) {
- ctor = Docs.Create.PdfDocument;
- if (!options._width) options._width = 400;
- if (!options._height) options._height = ((options._width as number) * 1200) / 927;
- }
- if (type.indexOf('csv') !== -1) {
- ctor = Docs.Create.DataVizDocument;
- if (!options._width) options._width = 400;
- if (!options._height) options._height = ((options._width as number) * 1200) / 927;
- }
- //TODO:al+glr
- // if (type.indexOf("map") !== -1) {
- // ctor = Docs.Create.MapDocument;
- // if (!options._width) options._width = 800;
- // if (!options._height) options._height = (options._width as number) * 3 / 4;
- // }
- if (type.indexOf('html') !== -1) {
- if (path.includes(window.location.hostname)) {
- const s = path.split('/');
- const id = s[s.length - 1];
- return DocServer.GetRefField(id).then(field => {
- if (field instanceof Doc) {
- const embedding = Doc.MakeEmbedding(field);
- embedding.x = (options.x as number) || 0;
- embedding.y = (options.y as number) || 0;
- embedding._width = (options._width as number) || 300;
- embedding._height = (options._height as number) || (options._width as number) || 300;
- return embedding;
- }
- return undefined;
- });
- }
- ctor = Docs.Create.WebDocument;
- options = { ...options, _width: 400, _height: 512, title: path };
- }
-
- return ctor ? ctor(path, overwriteDoc ? { ...options, title: StrCast(overwriteDoc.title, path) } : options, overwriteDoc) : undefined;
- }
-
- export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number, simpleMenu: boolean = false, pivotField?: string, pivotValue?: string): void {
- const documentList: ContextMenuProps[] = DocListCast(DocListCast(Doc.MyTools?.data)[0]?.data)
- .filter(btnDoc => !btnDoc.hidden)
- .map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null))
- .filter(doc => doc && doc !== Doc.UserDoc().emptyTrail && doc.title)
- .map((dragDoc, i) => ({
- description: ':' + StrCast(dragDoc.title).replace('Untitled ', ''),
- event: undoable((args: { x: number; y: number }) => {
- const newDoc = DocUtils.copyDragFactory(dragDoc);
- if (newDoc) {
- newDoc.author = Doc.CurrentUserEmail;
- newDoc.x = x;
- newDoc.y = y;
- EquationBox.SelectOnLoad = newDoc[Id];
- if (newDoc.type === DocumentType.RTF) FormattedTextBox.SetSelectOnLoad(newDoc);
- if (pivotField) {
- newDoc[pivotField] = pivotValue;
- }
- docAdder?.(newDoc);
- }
- }, StrCast(dragDoc.title)),
- icon: Doc.toIcon(dragDoc),
- })) as ContextMenuProps[];
- ContextMenu.Instance.addItem({
- description: 'Create document',
- subitems: documentList,
- icon: 'file',
- });
- !simpleMenu &&
- ContextMenu.Instance.addItem({
- description: 'Styled Notes',
- subitems: DocListCast((Doc.UserDoc().template_notes as Doc).data).map((note, i) => ({
- description: ':' + StrCast(note.title),
- event: undoable((args: { x: number; y: number }) => {
- const textDoc = Docs.Create.TextDocument('', {
- _width: 200,
- x,
- y,
- _layout_autoHeight: note._layout_autoHeight !== false,
- title: StrCast(note.title) + '#' + (note.embeddingCount = NumCast(note.embeddingCount) + 1),
- });
- textDoc.layout_fieldKey = 'layout_' + note.title;
- textDoc[textDoc.layout_fieldKey] = note;
- if (pivotField) {
- textDoc[pivotField] = pivotValue;
- }
- docTextAdder(textDoc);
- }, 'create quick note'),
- icon: StrCast(note.icon) as IconProp,
- })) as ContextMenuProps[],
- icon: 'sticky-note',
- });
- const userDocList: ContextMenuProps[] = DocListCast(DocListCast(Doc.MyTools?.data)[1]?.data)
- .filter(btnDoc => !btnDoc.hidden)
- .map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null))
- .filter(doc => doc && doc !== Doc.UserDoc().emptyTrail && doc !== Doc.UserDoc().emptyNote && doc.title)
- .map((dragDoc, i) => ({
- description: ':' + StrCast(dragDoc.title).replace('Untitled ', ''),
- event: undoable((args: { x: number; y: number }) => {
- const newDoc = DocUtils.delegateDragFactory(dragDoc);
- if (newDoc) {
- newDoc.author = Doc.CurrentUserEmail;
- newDoc.x = x;
- newDoc.y = y;
- EquationBox.SelectOnLoad = newDoc[Id];
- if (newDoc.type === DocumentType.RTF) FormattedTextBox.SetSelectOnLoad(newDoc);
- if (pivotField) {
- newDoc[pivotField] = pivotValue;
- }
- docAdder?.(newDoc);
- }
- }, StrCast(dragDoc.title)),
- icon: Doc.toIcon(dragDoc),
- })) as ContextMenuProps[];
- ContextMenu.Instance.addItem({
- description: 'User Templates',
- subitems: userDocList,
- icon: 'file',
- });
- }
-
- // applies a custom template to a document. the template is identified by it's short name (e.g, slideView not layout_slideView)
-
- /**
- * Applies a template to a Doc and logs the action with the UndoManager
- * If the template already exists and has been registered, it can be specified by it's signature name (e.g., 'icon' not 'layout_icon').
- * Alternatively, the signature can be omitted and the template can be provided.
- * @param doc the Doc to apply the template to.
- * @param creator a function that will create the template if it doesn't exist
- * @param templateSignature the signature name for a template that has already been created and registered on the userDoc. (can be "" if template is provide)
- * @param template the template to use (optional if templateSignature is provided)
- * @returns doc
- */
- export function makeCustomViewClicked(doc: Doc, creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = 'custom', template?: Doc) {
- const batch = UndoManager.StartBatch('makeCustomViewClicked');
- createCustomView(doc, creator, templateSignature || StrCast(template?.title), template);
- batch.end();
- return doc;
- }
- export function findTemplate(templateName: string, type: string, signature: string) {
- let docLayoutTemplate: Opt<Doc>;
- const iconViews = DocListCast(Cast(Doc.UserDoc()['template_icons'], Doc, null)?.data);
- const templBtns = DocListCast(Cast(Doc.UserDoc()['template_buttons'], Doc, null)?.data);
- const noteTypes = DocListCast(Cast(Doc.UserDoc()['template_notes'], Doc, null)?.data);
- const userTypes = DocListCast(Cast(Doc.UserDoc()['template_user'], Doc, null)?.data);
- const clickFuncs = DocListCast(Cast(Doc.UserDoc()['template_clickFuncs'], Doc, null)?.data);
- const allTemplates = iconViews
- .concat(templBtns)
- .concat(noteTypes)
- .concat(userTypes)
- .concat(clickFuncs)
- .map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc)
- .filter(doc => doc.isTemplateDoc);
- // bcz: this is hacky -- want to have different templates be applied depending on the "type" of a document. but type is not reliable and there could be other types of template searches so this should be generalized
- // first try to find a template that matches the specific document type (<typeName>_<templateName>). otherwise, fallback to a general match on <templateName>
- !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName + '_' + type && (docLayoutTemplate = tempDoc));
- !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName && (docLayoutTemplate = tempDoc));
- return docLayoutTemplate;
- }
- export function createCustomView(doc: Doc, creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = 'custom', docLayoutTemplate?: Doc) {
- const templateName = templateSignature.replace(/\(.*\)/, '');
- doc.layout_fieldKey = 'layout_' + (templateSignature || docLayoutTemplate?.title);
- docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc.isGroup && doc.transcription ? 'transcription' : doc.type), templateSignature);
-
- const customName = 'layout_' + templateSignature;
- const _width = NumCast(doc._width);
- const _height = NumCast(doc._height);
- const options = { title: 'data', backgroundColor: StrCast(doc.backgroundColor), _layout_autoHeight: true, _width, x: -_width / 2, y: -_height / 2, _layout_showSidebar: false };
-
- if (docLayoutTemplate) {
- if (docLayoutTemplate !== doc[customName]) {
- Doc.ApplyTemplateTo(docLayoutTemplate, doc, customName, undefined);
- }
- } else {
- let fieldTemplate: Opt<Doc>;
- if (doc.data instanceof RichTextField || typeof doc.data === 'string') {
- fieldTemplate = Docs.Create.TextDocument('', options);
- } else if (doc.data instanceof PdfField) {
- fieldTemplate = Docs.Create.PdfDocument('http://www.msn.com', options);
- } else if (doc.data instanceof VideoField) {
- fieldTemplate = Docs.Create.VideoDocument('http://www.cs.brown.edu', options);
- } else if (doc.data instanceof AudioField) {
- fieldTemplate = Docs.Create.AudioDocument('http://www.cs.brown.edu', options);
- } else if (doc.data instanceof ImageField) {
- fieldTemplate = Docs.Create.ImageDocument('http://www.cs.brown.edu', options);
- }
- const docTemplate = creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + '(' + doc.title + ')', isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) });
- fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, docTemplate ? Doc.GetProto(docTemplate) : docTemplate);
- docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined);
- }
- }
- export function makeCustomView(doc: Doc, custom: boolean, layout: string) {
- Doc.setNativeView(doc);
- if (custom) {
- makeCustomViewClicked(doc, Docs.Create.StackingDocument, layout, undefined);
- }
- }
- export function iconify(doc: Doc) {
- const layout_fieldKey = Cast(doc.layout_fieldKey, 'string', null);
- DocUtils.makeCustomViewClicked(doc, Docs.Create.StackingDocument, 'icon', undefined);
- if (layout_fieldKey && layout_fieldKey !== 'layout' && layout_fieldKey !== 'layout_icon') doc.deiconifyLayout = layout_fieldKey.replace('layout_', '');
- }
-
- export function pileup(docList: Doc[], x?: number, y?: number, size: number = 55, create: boolean = true) {
- runInAction(() => {
- docList.forEach((d, i) => {
- DocUtils.iconify(d);
- d.x = Math.cos((Math.PI * 2 * i) / docList.length) * size - size;
- d.y = Math.sin((Math.PI * 2 * i) / docList.length) * size - size;
- d._timecodeToShow = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
- });
- });
- if (create) {
- const newCollection = Docs.Create.PileDocument(docList, { title: 'pileup', _freeform_noZoom: true, x: (x || 0) - size, y: (y || 0) - size, _width: size * 2, _height: size * 2, dragWhenActive: true, _layout_fitWidth: false });
- newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - size;
- newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - size;
- newCollection._width = newCollection._height = size * 2;
- return newCollection;
- }
- }
- export function makeIntoPortal(doc: Doc, layoutDoc: Doc, allLinks: Doc[]) {
- const portalLink = allLinks.find(d => d.link_anchor_1 === doc && d.link_relationship === 'portal to:portal from');
- if (!portalLink) {
- DocUtils.MakeLink(
- doc,
- Docs.Create.FreeformDocument([], {
- _width: NumCast(layoutDoc._width) + 10,
- _height: Math.max(NumCast(layoutDoc._height), NumCast(layoutDoc._width) + 10),
- _isLightbox: true,
- _layout_fitWidth: true,
- title: StrCast(doc.title) + ' [Portal]',
- }),
- { link_relationship: 'portal to:portal from' }
- );
- }
- doc.followLinkLocation = OpenWhere.lightbox;
- doc.onClick = FollowLinkScript();
- }
-
- export function LeavePushpin(doc: Doc, annotationField: string) {
- if (doc.followLinkToggle) return undefined;
- const context = Cast(doc.embedContainer, Doc, null) ?? Cast(doc.annotationOn, Doc, null);
- const hasContextAnchor = LinkManager.Links(doc).some(l => (l.link_anchor_2 === doc && Cast(l.link_anchor_1, Doc, null)?.annotationOn === context) || (l.link_anchor_1 === doc && Cast(l.link_anchor_2, Doc, null)?.annotationOn === context));
- if (context && !hasContextAnchor && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) {
- const pushpin = Docs.Create.FontIconDocument({
- title: '',
- annotationOn: Cast(doc.annotationOn, Doc, null),
- followLinkToggle: true,
- icon: 'map-pin',
- x: Cast(doc.x, 'number', null),
- y: Cast(doc.y, 'number', null),
- backgroundColor: '#ACCEF7',
- layout_hideAllLinks: true,
- _width: 15,
- _height: 15,
- _xPadding: 0,
- onClick: FollowLinkScript(),
- _timecodeToShow: Cast(doc._timecodeToShow, 'number', null),
- });
- Doc.AddDocToList(context, annotationField, pushpin);
- const pushpinLink = DocUtils.MakeLink(pushpin, doc, { link_relationship: 'pushpin' }, '');
- doc._timecodeToShow = undefined;
- return pushpin;
- }
- return undefined;
- }
-
- // /**
- // *
- // * @param dms Degree Minute Second format exif gps data
- // * @param ref ref that determines negativity of decimal coordinates
- // * @returns a decimal format of gps latitude / longitude
- // */
- // function getDecimalfromDMS(dms?: number[], ref?: string) {
- // if (dms && ref) {
- // 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);
- // }
- // }
-
- function ConvertDMSToDD(degrees: number, minutes: number, seconds: number, direction: string) {
- var dd = degrees + minutes / 60 + seconds / (60 * 60);
- if (direction === 'S' || direction === 'W') {
- dd = dd * -1;
- } // Don't do anything for N or E
- return dd;
- }
-
- export function assignImageInfo(result: Upload.FileInformation, proto: Doc) {
- if (Upload.isImageInformation(result)) {
- const maxNativeDim = Math.min(Math.max(result.nativeHeight, result.nativeWidth), defaultNativeImageDim);
- const exifRotation = StrCast((result.exifData?.data as any)?.Orientation).toLowerCase();
- proto['data-nativeOrientation'] = result.exifData?.data?.image?.Orientation ?? (exifRotation.includes('rotate 90') || exifRotation.includes('rotate 270') ? 5 : undefined);
- proto['data_nativeWidth'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim;
- proto['data_nativeHeight'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight);
- if (NumCast(proto['data-nativeOrientation']) >= 5) {
- proto['data_nativeHeight'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim;
- proto['data_nativeWidth'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight);
- }
- proto.data_exif = JSON.stringify(result.exifData?.data);
- proto.data_contentSize = result.contentSize;
- // exif gps data coordinates are stored in DMS (Degrees Minutes Seconds), the following operation converts that to decimal coordinates
- const latitude = result.exifData?.data?.GPSLatitude;
- const latitudeDirection = result.exifData?.data?.GPSLatitudeRef;
- const longitude = result.exifData?.data?.GPSLongitude;
- const longitudeDirection = result.exifData?.data?.GPSLongitudeRef;
- if (latitude !== undefined && longitude !== undefined && latitudeDirection !== undefined && longitudeDirection !== undefined) {
- proto.latitude = ConvertDMSToDD(latitude[0], latitude[1], latitude[2], latitudeDirection);
- proto.longitude = ConvertDMSToDD(longitude[0], longitude[1], longitude[2], longitudeDirection);
- }
- }
- }
-
- async function processFileupload(generatedDocuments: Doc[], name: string, type: string, result: Error | Upload.FileInformation, options: DocumentOptions, overwriteDoc?: Doc) {
- if (result instanceof Error) {
- alert(`Upload failed: ${result.message}`);
- return;
- }
- const full = { ...options, _width: 400, title: name };
- const pathname = result.accessPaths.agnostic.client;
- const doc = await DocUtils.DocumentFromType(type, pathname, full, overwriteDoc);
- if (doc) {
- const proto = Doc.GetProto(doc);
- proto.text = result.rawText;
- !(result instanceof Error) && DocUtils.assignImageInfo(result, proto);
- if (Upload.isVideoInformation(result)) {
- proto.data_duration = result.duration;
- }
- if (overwriteDoc) {
- LoadingBox.removeCurrentlyLoading(overwriteDoc);
- }
- generatedDocuments.push(doc);
- }
- }
-
- export function GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, annotationOn?: Doc, backgroundColor?: string) {
- const defaultTextTemplate = DocCast(Doc.UserDoc().defaultTextLayout);
- const tbox = Docs.Create.TextDocument('', {
- annotationOn,
- backgroundColor,
- x,
- y,
- title,
- ...(defaultTextTemplate
- ? {} // if the new doc will inherit from a template, don't set any layout fields since that would block the inheritance
- : {
- _width: width || 200,
- _height: 35,
- _layout_centered: BoolCast(Doc.UserDoc()._layout_centered),
- _layout_fitWidth: true,
- _layout_autoHeight: true,
- }),
- });
-
- if (defaultTextTemplate) {
- tbox.layout_fieldKey = 'layout_' + StrCast(defaultTextTemplate.title);
- Doc.GetProto(tbox)[StrCast(tbox.layout_fieldKey)] = defaultTextTemplate; // set the text doc's layout to render with the text template
- tbox[DocData].proto = defaultTextTemplate; // and also set the text doc to inherit from the template (this allows the template to specify default field values)
- }
- return tbox;
- }
-
- export function uploadYoutubeVideoLoading(videoId: string, options: DocumentOptions, overwriteDoc?: Doc) {
- const generatedDocuments: Doc[] = [];
- Networking.UploadYoutubeToServer(videoId, overwriteDoc?.[Id]).then(upfiles => {
- const {
- source: { newFilename, originalFilename, mimetype },
- result,
- } = upfiles.lastElement();
- if ((result as any).message) {
- if (overwriteDoc) {
- overwriteDoc.isLoading = false;
- overwriteDoc.loadingError = (result as any).message;
- LoadingBox.removeCurrentlyLoading(overwriteDoc);
- }
- } else newFilename && processFileupload(generatedDocuments, newFilename, mimetype ?? '', result, options, overwriteDoc);
- });
- }
-
- /**
- * uploadFilesToDocs will take in an array of Files, and creates documents for the
- * new files.
- *
- * @param files an array of files that will be uploaded
- * @param options options to use while uploading
- * @returns
- */
- export async function uploadFilesToDocs(files: File[], options: DocumentOptions) {
- const generatedDocuments: Doc[] = [];
-
- // These files do not have overwriteDocs, so we do not set the guid and let the client generate one.
- const fileNoGuidPairs: Networking.FileGuidPair[] = files.map(file => ({ file }));
-
- const upfiles = await Networking.UploadFilesToServer(fileNoGuidPairs);
- for (const {
- source: { newFilename, mimetype },
- result,
- } of upfiles) {
- newFilename && mimetype && processFileupload(generatedDocuments, newFilename, mimetype, result, options);
- }
- return generatedDocuments;
- }
-
- export function uploadFileToDoc(file: File, options: DocumentOptions, overwriteDoc: Doc) {
- const generatedDocuments: Doc[] = [];
- // Since this file has an overwriteDoc, we can set the client tracking guid to the overwriteDoc's guid.
- Networking.UploadFilesToServer([{ file, guid: overwriteDoc[Id] }]).then(upfiles => {
- const {
- source: { newFilename, mimetype },
- result,
- } = upfiles.lastElement() ?? { source: { newFilename: '', mimetype: '' }, result: { message: 'upload failed' } };
- if ((result as any).message) {
- if (overwriteDoc) {
- overwriteDoc.loadingError = (result as any).message;
- LoadingBox.removeCurrentlyLoading(overwriteDoc);
- }
- } else newFilename && mimetype && processFileupload(generatedDocuments, newFilename, mimetype, result, options, overwriteDoc);
- });
- }
-
- // copies the specified drag factory document
- export function copyDragFactory(dragFactory: Doc) {
- if (!dragFactory) return undefined;
- const ndoc = dragFactory.isTemplateDoc ? Doc.ApplyTemplate(dragFactory) : Doc.MakeCopy(dragFactory, true);
- if (ndoc && dragFactory['dragFactory_count'] !== undefined) {
- dragFactory['dragFactory_count'] = NumCast(dragFactory['dragFactory_count']) + 1;
- Doc.SetInPlace(ndoc, 'title', ndoc.title + ' ' + NumCast(dragFactory['dragFactory_count']).toString(), true);
- }
-
- return ndoc;
- }
- export function delegateDragFactory(dragFactory: Doc) {
- const ndoc = Doc.MakeDelegateWithProto(dragFactory);
- if (ndoc && dragFactory['dragFactory_count'] !== undefined) {
- dragFactory['dragFactory_count'] = NumCast(dragFactory['dragFactory_count']) + 1;
- Doc.GetProto(ndoc).title = ndoc.title + ' ' + NumCast(dragFactory['dragFactory_count']).toString();
- }
- return ndoc;
- }
-}
-
-ScriptingGlobals.add('Docs', Docs);
-ScriptingGlobals.add(function copyDragFactory(dragFactory: Doc, asDelegate?: boolean) {
- return dragFactory instanceof Doc ? (asDelegate ? DocUtils.delegateDragFactory(dragFactory) : DocUtils.copyDragFactory(dragFactory)) : dragFactory;
-});
-ScriptingGlobals.add(function makeDelegate(proto: any) {
- const d = Docs.Create.DelegateDocument(proto, { title: 'child of ' + proto.title });
- return d;
-});
-ScriptingGlobals.add(function generateLinkTitle(link: Doc) {
- const link_anchor_1title = link.link_anchor_1 && link.link_anchor_1 !== link ? Cast(link.link_anchor_1, Doc, null)?.title : '<?>';
- const link_anchor_2title = link.link_anchor_2 && link.link_anchor_2 !== link ? Cast(link.link_anchor_2, Doc, null)?.title : '<?>';
- const relation = link.link_relationship || 'to';
- return `${link_anchor_1title} (${relation}) ${link_anchor_2title}`;
-});