aboutsummaryrefslogtreecommitdiff
path: root/src/client/documents/Documents.ts
diff options
context:
space:
mode:
authorSophie Zhang <sophie_zhang@brown.edu>2024-01-25 11:35:26 -0500
committerSophie Zhang <sophie_zhang@brown.edu>2024-01-25 11:35:26 -0500
commitf3dab2a56db5e4a6a3dca58185d94e1ff7d1dc32 (patch)
treea7bc895266b53bb620dbd2dd71bad2e83b555446 /src/client/documents/Documents.ts
parentb5c5410b4af5d2c68d2107d3f064f6e3ec4ac3f2 (diff)
parent136f3d9f349d54e8bdd73b6380ea47c19e5edebf (diff)
Merge branch 'master' into sophie-ai-images
Diffstat (limited to 'src/client/documents/Documents.ts')
-rw-r--r--src/client/documents/Documents.ts272
1 files changed, 180 insertions, 92 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 4086ede20..a0870ba43 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { action, reaction, runInAction } from 'mobx';
import { basename } from 'path';
import { DateField } from '../../fields/DateField';
-import { Doc, DocListCast, Field, LinkedTo, Opt, updateCachedAcls } from '../../fields/Doc';
+import { Doc, DocListCast, Field, LinkedTo, Opt, StrListCast, updateCachedAcls } from '../../fields/Doc';
import { Initializing } from '../../fields/DocSymbols';
import { Id } from '../../fields/FieldSymbols';
import { HtmlField } from '../../fields/HtmlField';
@@ -20,7 +20,6 @@ import { YoutubeBox } from '../apis/youtube/YoutubeBox';
import { DocServer } from '../DocServer';
import { Networking } from '../Network';
import { DragManager, dropActionType } from '../util/DragManager';
-import { DirectoryImportBox } from '../util/Import & Export/DirectoryImportBox';
import { FollowLinkScript } from '../util/LinkFollower';
import { LinkManager } from '../util/LinkManager';
import { ScriptingGlobals } from '../util/ScriptingGlobals';
@@ -30,10 +29,8 @@ import { DimUnit } from '../views/collections/collectionMulticolumn/CollectionMu
import { CollectionView } from '../views/collections/CollectionView';
import { ContextMenu } from '../views/ContextMenu';
import { ContextMenuProps } from '../views/ContextMenuItem';
-import { DFLT_IMAGE_NATIVE_DIM } from '../views/global/globalCssVariables.scss';
import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke } from '../views/InkingStroke';
import { AudioBox, media_state } from '../views/nodes/AudioBox';
-import { ColorBox } from '../views/nodes/ColorBox';
import { ComparisonBox } from '../views/nodes/ComparisonBox';
import { DataVizBox } from '../views/nodes/DataVizBox/DataVizBox';
import { EquationBox } from '../views/nodes/EquationBox';
@@ -61,6 +58,8 @@ import { VideoBox } from '../views/nodes/VideoBox';
import { WebBox } from '../views/nodes/WebBox';
import { SearchBox } from '../views/search/SearchBox';
import { CollectionViewType, DocumentType } from './DocumentTypes';
+import { CalendarBox } from '../views/nodes/calendarBox/CalendarBox';
+const { default: { DFLT_IMAGE_NATIVE_DIM } } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore
const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace('px', ''));
class EmptyBox {
@@ -168,15 +167,28 @@ type DTYPEt = DTypeInfo | string;
export class DocumentOptions {
// coordinate and dimensions depending on view
x?: NUMt = new NumInfo('x coordinate of document in a freeform view', false);
- y?: NUMt = new NumInfo('y coordinage of document in a freeform view', false);
+ y?: NUMt = new NumInfo('y coordinate of document in a freeform view', false);
z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', false, false, [1, 0]);
+ overlayX?: NUMt = new NumInfo('x coordinate of document in a overlay view', false);
+ overlayY?: NUMt = new NumInfo('y coordinate of document in a overlay view', false);
_dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height", false);
_dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units");
latitude?: NUMt = new NumInfo('latitude coordinate for map views', false);
longitude?: NUMt = new NumInfo('longitude coordinate for map views', false);
+ routeCoordinates?: STRt = new StrInfo("stores a route's/direction's coordinates (stringified version)"); // for a route document, this stores the route's coordinates
+ markerType?: STRt = new StrInfo('Defines the marker type for a pushpin document');
+ markerColor?: STRt = new StrInfo('Defines the marker color for a pushpin document');
map?: STRt = new StrInfo('text location of map');
map_type?: STRt = new StrInfo('type of map view', false);
map_zoom?: NUMt = new NumInfo('zoom of a map view', false);
+ map_pitch?: NUMt = new NumInfo('pitch of a map view', false);
+ map_bearing?: NUMt = new NumInfo('bearing of a map view', false);
+ map_style?: STRt = new StrInfo('mapbox style for a map view', false);
+
+ date_range?: STRt = new StrInfo('date range for calendar', false);
+
+ wikiData?: STRt = new StrInfo('WikiData ID related to map location');
+ description?: STRt = new StrInfo('A description of the document');
_timecodeToShow?: NUMt = new NumInfo('the time that a document should be displayed (e.g., when an annotation shows up as a video plays)', false);
_timecodeToHide?: NUMt = new NumInfo('the time that a document should be hidden', false);
_width?: NUMt = new NumInfo('displayed width of a document');
@@ -186,8 +198,6 @@ export class DocumentOptions {
linearBtnWidth?: NUMt = new NumInfo('unexpanded width of a linear menu button (button "width" changes when it expands)', false);
_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);
- _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false);
- _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers');
'acl-Guest'?: STRt = new StrInfo("permissions granted to users logged in as 'guest' (either view, or private)"); // public permissions
'_acl-Guest'?: string; // public permissions
@@ -195,11 +205,13 @@ export class DocumentOptions {
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;
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);
- embedContainer?: DOCt = new DocInfo('document that displays (contains) this discument', false);
+ _embedContainer?: DOCt = new DocInfo('document that displays (contains) this discument', false);
+ rootDocument?: DOCt = new DocInfo('document that supplies the information needed for a rendering template (eg, pres slide for PresElement)');
color?: STRt = new StrInfo('foreground color data doc', false);
hidden?: BOOLt = new BoolInfo('whether the document is not rendered by its collection', false);
backgroundColor?: STRt = new StrInfo('background color for data doc', false);
@@ -228,13 +240,16 @@ export class DocumentOptions {
layout_hideResizeHandles?: BOOLt = new BoolInfo('whether to hide the resize handles when selected');
layout_hideLinkButton?: BOOLt = new BoolInfo('whether the blue link counter button should be hidden');
layout_hideDecorationTitle?: BOOLt = new BoolInfo('whether to suppress the document decortations title when selected');
+ _layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown');
layout_borderRounding?: string;
+ _layout_nativeDimEditable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false);
+ _layout_reflowVertical?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers');
+ _layout_reflowHorizontal?: BOOLt = new BoolInfo('whether a doc with a native size can be horizonally resized, causing some form of reflow');
layout_boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow
- layout_maxAutoHeight?: NUMt = new NumInfo('maximum height for newly created (eg, from pasting) text documents', false);
_layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents');
_layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document', false);
_layout_currentTimecode?: NUMt = new NumInfo('the current timecode of a time-based document (e.g., current time of a video) value is in seconds', false);
- _layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown');
+ _layout_centered?: BOOLt = new BoolInfo('whether text should be vertically centered in Doc');
_layout_fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)');
_layout_fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content');
_layout_fieldKey?: STRt = new StrInfo('the field key containing the current layout definition', false);
@@ -244,6 +259,7 @@ export class DocumentOptions {
_layout_showCaption?: string; // which field to display in the caption area. leave empty to have no caption
_chromeHidden?: BOOLt = new BoolInfo('whether the editing chrome for a document is hidden');
+ hideClickBehaviors?: BOOLt = new BoolInfo('whether to hide click behaviors in context menu');
_gridGap?: NUMt = new NumInfo('gap between items in masonry view', false);
_xMargin?: NUMt = new NumInfo('gap between left edge of document and start of masonry/stacking layouts', false);
_yMargin?: NUMt = new NumInfo('gap between top edge of dcoument and start of masonry/stacking layouts', false);
@@ -270,26 +286,28 @@ export class DocumentOptions {
icon_label?: STRt = new StrInfo('label to use for a fontIcon doc (otherwise, the title is used)', false);
mediaState?: STRt = new StrInfo(`status of audio/video media document: ${media_state.PendingRecording}, ${media_state.Recording}, ${media_state.Paused}, ${media_state.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.');
dontPlayLinkOnSelect?: BOOLt = new BoolInfo('whether an audio/video should start playing when a link is followed to it.');
openFactoryLocation?: string; // an OpenWhere value to place the factory created document
openFactoryAsDelegate?: boolean; //
- updateContentsScript?: ScriptField; // reactive script invoked when viewing a document that can update contents of a collection (or do anything)
+ onViewMounted?: ScriptField; // reactive script invoked Doc is viewed (used by showBackLinks view to update collection of links to Doc)
toolTip?: string; // tooltip to display on hover
toolType?: string; // type of pen tool
expertMode?: BOOLt = new BoolInfo('something available only in expert (not novice) mode');
- contentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
contextMenuFilters?: List<ScriptField>;
contextMenuScripts?: List<ScriptField>;
contextMenuLabels?: List<string>;
contextMenuIcons?: List<string>;
+ childContentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
childFilters_boolean?: string;
childFilters?: List<string>;
childLimitHeight?: NUMt = new NumInfo('whether to limit the height of collection children. 0 - means height can be no bigger than width', false);
childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox layout in tree view)
childLayoutString?: string; // template string for collection to use to render its children
childDocumentsActive?: BOOLt = new BoolInfo('whether child documents are active when parent is document active');
+ childLayoutFitWidth?: BOOLt = new BoolInfo("whether a child doc's fitWith should be overriden by collection");
childDontRegisterViews?: BOOLt = new BoolInfo('whether child document views should be registered so that they can be found when following links, etc');
childHideLinkButton?: BOOLt = new BoolInfo('hide link buttons on all children');
childContextMenuFilters?: List<ScriptField>;
@@ -402,7 +420,7 @@ export class DocumentOptions {
_dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
_dropPropertiesToRemove?: 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
cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
- dragWhenActive?: BOOLt = new BoolInfo('should document drag when it is active - e.g., pileView, group');
+ dragWhenActive?: BOOLt = new BoolInfo('should document drag when it is active instead of interacting with its contents - e.g., pileView, group');
dragAction?: DROPt = new DAInfo('how to drag document when it is active (e.g., tree, groups)');
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);
@@ -472,9 +490,9 @@ export namespace Docs {
_height: 35,
_xMargin: 10,
_yMargin: 10,
- nativeDimModifiable: true,
- nativeHeightUnfrozen: true,
- layout_forceReflow: true,
+ layout_nativeDimEditable: true,
+ layout_reflowVertical: true,
+ layout_reflowHorizontal: true,
defaultDoubleClick: 'ignore',
systemIcon: 'BsFileEarmarkTextFill',
},
@@ -488,13 +506,6 @@ export namespace Docs {
},
],
[
- DocumentType.COLOR,
- {
- layout: { view: ColorBox, dataField: defaultDataKey },
- options: { _nativeWidth: 220, _nativeHeight: 300 },
- },
- ],
- [
DocumentType.IMG,
{
layout: { view: ImageBox, dataField: defaultDataKey },
@@ -505,14 +516,24 @@ export namespace Docs {
DocumentType.WEB,
{
layout: { view: WebBox, dataField: defaultDataKey },
- options: { _height: 300, _layout_fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true, waitForDoubleClickToClick: 'always', systemIcon: 'BsGlobe' },
+ options: { _height: 300, _layout_fitWidth: true, layout_nativeDimEditable: true, layout_reflowVertical: true, waitForDoubleClickToClick: 'always', systemIcon: 'BsGlobe' },
},
],
[
DocumentType.COL,
{
layout: { view: CollectionView, dataField: defaultDataKey },
- options: { _layout_fitWidth: true, freeform: '', _freeform_panX: 0, _freeform_panY: 0, _freeform_scale: 1, systemIcon: 'BsFillCollectionFill' },
+ 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',
+ },
},
],
[
@@ -533,7 +554,7 @@ export namespace Docs {
DocumentType.AUDIO,
{
layout: { view: AudioBox, dataField: defaultDataKey },
- options: { _height: 100, layout_fitWidth: true, layout_forceReflow: true, nativeDimModifiable: true, systemIcon: 'BsFillVolumeUpFill' },
+ options: { _height: 100, layout_fitWidth: true, layout_reflowHorizontal: true, layout_reflowVertical: true, layout_nativeDimEditable: true, systemIcon: 'BsFillVolumeUpFill' },
},
],
[
@@ -547,21 +568,14 @@ export namespace Docs {
DocumentType.PDF,
{
layout: { view: PDFBox, dataField: defaultDataKey },
- options: { _layout_curPage: 1, _layout_fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true, systemIcon: 'BsFileEarmarkPdfFill' },
+ 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, nativeDimModifiable: true, systemIcon: 'BsFillPinMapFill' },
- },
- ],
- [
- DocumentType.IMPORT,
- {
- layout: { view: DirectoryImportBox, dataField: defaultDataKey },
- options: { _height: 150 },
+ options: { map: '', _height: 600, _width: 800, layout_reflowHorizontal: true, layout_reflowVertical: true, layout_nativeDimEditable: true, systemIcon: 'BsFillPinMapFill' },
},
],
[
@@ -613,14 +627,25 @@ export namespace Docs {
DocumentType.EQUATION,
{
layout: { view: EquationBox, dataField: 'text' },
- options: { nativeDimModifiable: true, fontSize: '14px', layout_hideResizeHandles: true, layout_hideDecorationTitle: true, systemIcon: 'BsCalculatorFill' }, ///systemIcon: 'BsSuperscript' + BsSubscript
+ 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: { nativeDimModifiable: true },
+ options: {
+ layout_reflowHorizontal: true,
+ layout_reflowVertical: true,
+ layout_nativeDimEditable: true,
+ },
},
],
[
@@ -634,7 +659,7 @@ export namespace Docs {
DocumentType.PRES,
{
layout: { view: PresBox, dataField: defaultDataKey },
- options: { defaultDoubleClick: 'ignore', layout_hideLinkAnchors: true },
+ options: { defaultDoubleClick: 'ignore', hideClickBehaviors: true, layout_hideLinkAnchors: true },
},
],
[
@@ -672,12 +697,12 @@ export namespace Docs {
layout: { view: InkingStroke, dataField: 'stroke' },
options: {
systemIcon: 'BsFillPencilFill', //
- nativeDimModifiable: true,
- nativeHeightUnfrozen: true,
+ layout_nativeDimEditable: true,
+ layout_reflowVertical: true,
+ layout_reflowHorizontal: true,
layout_hideDecorationTitle: true, // don't show title when selected
fitWidth: false,
layout_isSvg: true,
- layout_forceReflow: true,
},
},
],
@@ -685,7 +710,7 @@ export namespace Docs {
DocumentType.SCREENSHOT,
{
layout: { view: ScreenshotBox, dataField: defaultDataKey },
- options: { nativeDimModifiable: true, nativeHeightUnfrozen: true, systemIcon: 'BsCameraFill' },
+ options: { layout_nativeDimEditable: true, systemIcon: 'BsCameraFill' },
},
],
[
@@ -693,7 +718,7 @@ export namespace Docs {
{
data: '',
layout: { view: ComparisonBox, dataField: defaultDataKey },
- options: { backgroundColor: 'gray', dropAction: 'move', waitForDoubleClickToClick: 'always', systemIcon: 'BsLayoutSplit' },
+ options: { backgroundColor: 'gray', dropAction: 'move', waitForDoubleClickToClick: 'always', layout_reflowHorizontal: true, layout_reflowVertical: true, layout_nativeDimEditable: true, systemIcon: 'BsLayoutSplit' },
},
],
[
@@ -714,14 +739,14 @@ export namespace Docs {
DocumentType.DATAVIZ,
{
layout: { view: DataVizBox, dataField: defaultDataKey },
- options: { dataViz_title: '', dataViz_line: '', dataViz_pie: '', dataViz_histogram: '', dataViz: 'table', _layout_fitWidth: true, nativeDimModifiable: true },
+ 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, nativeDimModifiable: true },
+ options: { _layout_fitWidth: true, _fitHeight: true, layout_nativeDimEditable: true },
},
],
[
@@ -731,11 +756,9 @@ export namespace Docs {
layout: { view: PhysicsSimulationBox, dataField: defaultDataKey, _width: 1000, _height: 800 },
options: {
_height: 100,
- layout_forceReflow: true,
- nativeHeightUnfrozen: true,
mass1: '',
mass2: '',
- nativeDimModifiable: true,
+ layout_nativeDimEditable: true,
position: '',
acceleration: '',
pendulum: '',
@@ -754,6 +777,20 @@ export namespace Docs {
options: {},
},
],
+ [
+ DocumentType.MAPROUTE,
+ {
+ layout: { view: CollectionView, dataField: defaultDataKey },
+ options: {},
+ },
+ ],
+ [
+ DocumentType.CALENDAR,
+ {
+ layout: { view: CalendarBox, dataField: defaultDataKey },
+ options: {},
+ },
+ ],
]);
const suffix = 'Proto';
@@ -948,7 +985,7 @@ export namespace Docs {
export function ImageDocument(url: string | ImageField, options: DocumentOptions = {}, overwriteDoc?: Doc) {
const imgField = url instanceof ImageField ? url : new ImageField(url);
- return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { _nativeDimModifiable: false, _nativeHeightUnfrozen: false, title: basename(imgField.url.href), ...options }, undefined, undefined, undefined, overwriteDoc);
+ return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: basename(imgField.url.href), ...options }, undefined, undefined, undefined, overwriteDoc);
}
export function PresDocument(options: DocumentOptions = {}) {
@@ -991,9 +1028,6 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.SEARCH), new List<Doc>([]), options);
}
- export function ColorDocument(options: DocumentOptions = {}) {
- return InstanceFromProto(Prototypes.get(DocumentType.COLOR), '', options);
- }
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, '');
}
@@ -1042,7 +1076,18 @@ export namespace Docs {
return linkDoc;
}
- export function InkDocument(color: string, strokeWidth: number, stroke_bezier: string, fillColor: string, arrowStart: string, arrowEnd: string, dash: string, points: PointData[], isInkMask: boolean, options: DocumentOptions = {}) {
+ export function InkDocument(
+ points: PointData[],
+ options: DocumentOptions = {},
+ strokeWidth = ActiveInkWidth(),
+ color = ActiveInkColor(),
+ stroke_bezier = ActiveInkBezierApprox(),
+ fillColor = ActiveFillColor(),
+ arrowStart = ActiveArrowStart(),
+ arrowEnd = ActiveArrowEnd(),
+ dash = ActiveDash(),
+ isInkMask = ActiveIsInkMask()
+ ) {
const ink = InstanceFromProto(Prototypes.get(DocumentType.INK), '', { title: 'ink', ...options });
const I = Doc.GetProto(ink);
// I.layout_hideOpenButton = true; // don't show open full screen button when selected
@@ -1096,13 +1141,21 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.PUSHPIN), new List(documents), { latitude, longitude, infoWindowOpen, ...options }, id);
}
+ export function MapRouteDocument(infoWindowOpen: boolean, documents: Array<Doc>, options: DocumentOptions, id?: string) {
+ return InstanceFromProto(Prototypes.get(DocumentType.MAPROUTE), new List(documents), { infoWindowOpen, ...options }, id);
+ }
+
+ export function CalendarDocument(options: DocumentOptions, documents: Array<Doc>) {
+ return InstanceFromProto(Prototypes.get(DocumentType.CALENDAR), new List(documents), { ...options });
+ }
+
// shouldn't ever need to create a KVP document-- instead set the LayoutTemplateString to be a KeyValueBox for the DocumentView (see addDocTab in TabDocView)
// export function KVPDocument(document: Doc, options: DocumentOptions = {}) {
// return InstanceFromProto(Prototypes.get(DocumentType.KVP), document, { title: document.title + '.kvp', ...options });
// }
export function FreeformDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
- const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xPadding: 20, _yPadding: 20, ...options, _type_collection: CollectionViewType.Freeform }, id);
+ const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _type_collection: CollectionViewType.Freeform }, id);
documents.forEach(d => Doc.SetContainer(d, inst));
return inst;
}
@@ -1150,6 +1203,10 @@ export namespace Docs {
return doc;
}
+ export function CalendarCollectionDocument(documents: Array<Doc>, options: DocumentOptions) {
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _type_collection: CollectionViewType.Calendar });
+ }
+
export function StackingDocument(documents: Array<Doc>, options: DocumentOptions, id?: string, protoId?: string) {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _type_collection: CollectionViewType.Stacking }, id, undefined, protoId);
}
@@ -1185,7 +1242,7 @@ export namespace Docs {
}
export function FunctionPlotDocument(documents: Array<Doc>, options?: DocumentOptions) {
- return InstanceFromProto(Prototypes.get(DocumentType.FUNCPLOT), new List(documents), { ...(options || {}) });
+ return InstanceFromProto(Prototypes.get(DocumentType.FUNCPLOT), new List(documents), { title: 'func plot', ...(options || {}) });
}
export function ButtonDocument(options?: DocumentOptions) {
@@ -1210,10 +1267,6 @@ export namespace Docs {
return ret;
}
- export function DirectoryImportDocument(options: DocumentOptions = {}) {
- return InstanceFromProto(Prototypes.get(DocumentType.IMPORT), new List<Doc>(), options);
- }
-
export type DocConfig = {
doc: Doc;
initialWidth?: number;
@@ -1253,6 +1306,40 @@ 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
@@ -1284,7 +1371,7 @@ export namespace DocUtils {
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.noDragsDocFilter.split(Doc.FilterSep)[0])) {
+ 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)
@@ -1303,8 +1390,8 @@ export namespace DocUtils {
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 => Doc.matchFieldValue(d, facetKey, value));
- const satisfiesCheckFacets = !checks.length ? true : checks.some(value => Doc.matchFieldValue(d, facetKey, value));
+ 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
@@ -1369,17 +1456,17 @@ export namespace DocUtils {
TaskCompletionBox.popupY = showPopup[1] - 33;
TaskCompletionBox.taskCompleted = true;
- LinkDescriptionPopup.popupX = showPopup[0];
- LinkDescriptionPopup.popupY = showPopup[1];
- LinkDescriptionPopup.descriptionPopup = true;
+ LinkDescriptionPopup.Instance.popupX = showPopup[0];
+ LinkDescriptionPopup.Instance.popupY = showPopup[1];
+ LinkDescriptionPopup.Instance.display = true;
const rect = document.body.getBoundingClientRect();
- if (LinkDescriptionPopup.popupX + 200 > rect.width) {
- LinkDescriptionPopup.popupX -= 190;
+ if (LinkDescriptionPopup.Instance.popupX + 200 > rect.width) {
+ LinkDescriptionPopup.Instance.popupX -= 190;
TaskCompletionBox.popupX -= 40;
}
- if (LinkDescriptionPopup.popupY + 100 > rect.height) {
- LinkDescriptionPopup.popupY -= 40;
+ if (LinkDescriptionPopup.Instance.popupY + 100 > rect.height) {
+ LinkDescriptionPopup.Instance.popupY -= 40;
TaskCompletionBox.popupY -= 40;
}
@@ -1398,7 +1485,7 @@ export namespace DocUtils {
{
'acl-Guest': SharingPermissions.Augment,
'_acl-Guest': SharingPermissions.Augment,
- title: ComputedField.MakeFunction('generateLinkTitle(self)') as any,
+ 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,
@@ -1421,7 +1508,7 @@ export namespace DocUtils {
Object.keys(scripts).map(key => {
const script = scripts[key];
if (ScriptCast(doc[key])?.script.originalScript !== scripts[key] && script) {
- doc[key] = ScriptField.MakeScript(script, {
+ (key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = ScriptField.MakeScript(script, {
self: Doc.name,
this: Doc.name,
dragData: DragManager.DocumentDragData.name,
@@ -1445,7 +1532,7 @@ export namespace DocUtils {
const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
if (ScriptCast(cfield)?.script.originalScript !== funcs[key]) {
const setFunc = Cast(funcs[key + '-setter'], 'string', null);
- doc[key] = funcs[key] ? ComputedField.MakeFunction(funcs[key], { dragData: DragManager.DocumentDragData.name }, { _readOnly_: true }, setFunc) : undefined;
+ (key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = funcs[key] ? ComputedField.MakeFunction(funcs[key], { dragData: DragManager.DocumentDragData.name }, { _readOnly_: true }, setFunc) : undefined;
}
});
return doc;
@@ -1492,7 +1579,7 @@ export namespace DocUtils {
created = Docs.Create.AudioDocument(field.url.href, resolved);
created.layout = AudioBox.LayoutString(fieldKey);
} else if (field instanceof InkField) {
- created = Docs.Create.InkDocument(ActiveInkColor(), ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), field.inkData, ActiveIsInkMask(), resolved);
+ 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);
@@ -1566,7 +1653,7 @@ export namespace DocUtils {
options = { ...options, _width: 400, _height: 512, title: path };
}
- return ctor ? ctor(path, options, overwriteDoc) : undefined;
+ 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 {
@@ -1607,7 +1694,7 @@ export namespace DocUtils {
newDoc.x = x;
newDoc.y = y;
EquationBox.SelectOnLoad = newDoc[Id];
- if (newDoc.type === DocumentType.RTF) FormattedTextBox.SelectOnLoad = newDoc[Id];
+ if (newDoc.type === DocumentType.RTF) FormattedTextBox.SetSelectOnLoad(newDoc);
if (pivotField) {
newDoc[pivotField] = pivotValue;
}
@@ -1651,7 +1738,7 @@ export namespace DocUtils {
}
export function createCustomView(doc: Doc, creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = 'custom', docLayoutTemplate?: Doc) {
const templateName = templateSignature.replace(/\(.*\)/, '');
- docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc._isGroup && doc.transcription ? 'transcription' : doc.type), templateSignature);
+ docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc.isGroup && doc.transcription ? 'transcription' : doc.type), templateSignature);
const customName = 'layout_' + templateSignature;
const _width = NumCast(doc._width);
@@ -1787,6 +1874,7 @@ export namespace DocUtils {
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;
@@ -1802,23 +1890,23 @@ export namespace DocUtils {
proto.data_duration = result.duration;
}
if (overwriteDoc) {
- Doc.removeCurrentlyLoading(overwriteDoc);
+ LoadingBox.removeCurrentlyLoading(overwriteDoc);
}
generatedDocuments.push(doc);
}
}
- export function GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, noMargins?: boolean, annotationOn?: Doc, maxHeight?: number, backgroundColor?: string) {
+ export function GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, noMargins?: boolean, annotationOn?: Doc, backgroundColor?: string) {
const tbox = Docs.Create.TextDocument('', {
_xMargin: noMargins ? 0 : undefined,
_yMargin: noMargins ? 0 : undefined,
annotationOn,
- layout_maxAutoHeight: maxHeight,
backgroundColor,
_width: width || 200,
_height: 35,
x: x,
y: y,
+ _layout_centered: BoolCast(Doc.UserDoc().layout_centered),
_layout_fitWidth: true,
_layout_autoHeight: true,
_layout_enableAltContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards),
@@ -1837,16 +1925,16 @@ export namespace DocUtils {
const generatedDocuments: Doc[] = [];
Networking.UploadYoutubeToServer(videoId, overwriteDoc?.[Id]).then(upfiles => {
const {
- source: { name, type },
+ source: { newFilename, originalFilename, mimetype },
result,
} = upfiles.lastElement();
if ((result as any).message) {
if (overwriteDoc) {
overwriteDoc.isLoading = false;
overwriteDoc.loadingError = (result as any).message;
- Doc.removeCurrentlyLoading(overwriteDoc);
+ LoadingBox.removeCurrentlyLoading(overwriteDoc);
}
- } else name && processFileupload(generatedDocuments, name, type, result, options, overwriteDoc);
+ } else newFilename && processFileupload(generatedDocuments, newFilename, mimetype ?? '', result, options, overwriteDoc);
});
}
@@ -1866,10 +1954,10 @@ export namespace DocUtils {
const upfiles = await Networking.UploadFilesToServer(fileNoGuidPairs);
for (const {
- source: { name, type },
+ source: { newFilename, mimetype },
result,
} of upfiles) {
- name && type && processFileupload(generatedDocuments, name, type, result, options);
+ newFilename && mimetype && processFileupload(generatedDocuments, newFilename, mimetype, result, options);
}
return generatedDocuments;
}
@@ -1879,15 +1967,15 @@ export namespace DocUtils {
// 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: { name, type },
+ source: { newFilename, mimetype },
result,
- } = upfiles.lastElement() ?? { source: { name: '', type: '' }, result: { message: 'upload failed' } };
+ } = upfiles.lastElement() ?? { source: { newFilename: '', mimetype: '' }, result: { message: 'upload failed' } };
if ((result as any).message) {
if (overwriteDoc) {
overwriteDoc.loadingError = (result as any).message;
- Doc.removeCurrentlyLoading(overwriteDoc);
+ LoadingBox.removeCurrentlyLoading(overwriteDoc);
}
- } else name && type && processFileupload(generatedDocuments, name, type, result, options, overwriteDoc);
+ } else newFilename && mimetype && processFileupload(generatedDocuments, newFilename, mimetype, result, options, overwriteDoc);
});
}
@@ -1920,9 +2008,9 @@ ScriptingGlobals.add(function makeDelegate(proto: any) {
const d = Docs.Create.DelegateDocument(proto, { title: 'child of ' + proto.title });
return d;
});
-ScriptingGlobals.add(function generateLinkTitle(self: Doc) {
- const link_anchor_1title = self.link_anchor_1 && self.link_anchor_1 !== self ? Cast(self.link_anchor_1, Doc, null)?.title : '<?>';
- const link_anchor_2title = self.link_anchor_2 && self.link_anchor_2 !== self ? Cast(self.link_anchor_2, Doc, null)?.title : '<?>';
- const relation = self.link_relationship || 'to';
+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}`;
});