aboutsummaryrefslogtreecommitdiff
path: root/src/client/documents
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/documents')
-rw-r--r--src/client/documents/DocUtils.ts162
-rw-r--r--src/client/documents/DocumentTypes.ts27
-rw-r--r--src/client/documents/Documents.ts118
3 files changed, 229 insertions, 78 deletions
diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts
index 1130a9ae8..7f22e9376 100644
--- a/src/client/documents/DocUtils.ts
+++ b/src/client/documents/DocUtils.ts
@@ -3,14 +3,14 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { saveAs } from 'file-saver';
import * as JSZip from 'jszip';
import { action, runInAction } from 'mobx';
-import { ClientUtils } from '../../ClientUtils';
+import { ClientUtils, DashColor } from '../../ClientUtils';
import * as JSZipUtils from '../../JSZipUtils';
import { decycle } from '../../decycler/decycler';
import { DateField } from '../../fields/DateField';
import { Doc, DocListCast, Field, FieldResult, FieldType, LinkedTo, Opt, StrListCast } from '../../fields/Doc';
import { DocData } from '../../fields/DocSymbols';
import { Id } from '../../fields/FieldSymbols';
-import { InkDataFieldName, InkField } from '../../fields/InkField';
+import { InkData, InkDataFieldName, InkField } from '../../fields/InkField';
import { List, ListFieldName } from '../../fields/List';
import { ProxyField } from '../../fields/Proxy';
import { RichTextField } from '../../fields/RichTextField';
@@ -33,19 +33,22 @@ import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox';
import { DocumentType } from './DocumentTypes';
import { Docs, DocumentOptions } from './Documents';
import { DocumentView } from '../views/nodes/DocumentView';
-import { CollectionFreeFormView } from '../views/collections/collectionFreeForm';
-
-// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
-const { DFLT_IMAGE_NATIVE_DIM } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore
-
-const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace('px', ''));
+import { INode, parse } from 'svgson';
+import { SVGToBezier, SVGType } from '../util/bezierFit';
+import { SmartDrawHandler } from '../views/smartdraw/SmartDrawHandler';
+import { PointData } from '../../pen-gestures/GestureTypes';
export namespace DocUtils {
+ function HasFunctionFilter(val: string) {
+ if (val.includes(ClientUtils.isTransparentFunctionHack)) return (d: Doc, color: string) => !d.disableMixBlend && color !== '' && DashColor(color).alpha() !== 1;
+ // add other function filters here...
+ return undefined;
+ }
function matchFieldValue(doc: Doc, key: string, valueIn: unknown): boolean {
let value = valueIn;
- const hasFunctionFilter = ClientUtils.HasFunctionFilter(value as string);
+ const hasFunctionFilter = HasFunctionFilter(value as string);
if (hasFunctionFilter) {
- return hasFunctionFilter(StrCast(doc[key]));
+ return hasFunctionFilter(doc, StrCast(doc[key]));
}
if (key === LinkedTo) {
// links are not a field value, so handled here. value is an expression of form ([field=]idToDoc("..."))
@@ -72,9 +75,9 @@ export namespace DocUtils {
}
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 as string)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
+ return vals.some(v => typeof v === 'string' && v === (value as string)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
}
- return Field.toString(fieldVal as FieldType).includes(value as string); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
+ return Field.toString(fieldVal as FieldType) === (value as string); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
}
/**
* @param docs
@@ -108,7 +111,6 @@ export namespace DocUtils {
return false;
}
const facetKeys = Object.keys(filterFacets).filter(fkey => fkey !== 'cookies' && fkey !== ClientUtils.noDragDocsFilter.split(Doc.FilterSep)[0]);
- // eslint-disable-next-line no-restricted-syntax
for (const facetKey of facetKeys) {
const facet = filterFacets[facetKey];
@@ -169,7 +171,7 @@ export namespace DocUtils {
return rangeFilteredDocs;
}
- export function MakeLink(source: Doc, target: Doc, linkSettings: { link_relationship?: string; link_description?: string }, id?: string, showPopup?: number[]) {
+ export function MakeLink(source: Doc, target: Doc, linkSettings: { layout_isSvg?: boolean; link_relationship?: string; link_description?: string }, 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;
@@ -221,6 +223,7 @@ export namespace DocUtils {
link_anchor_2_useSmallAnchor: target.useSmallAnchor ? true : undefined,
link_relationship: linkSettings.link_relationship,
link_description: linkSettings.link_description,
+ layout_isSvg: linkSettings.layout_isSvg,
x: ComputedField.MakeFunction(`((this.${a}?.x||0)+(this.${b}?.x||0))/2`) as unknown as number, // x can accept functions even though type says it can't
y: ComputedField.MakeFunction(`((this.${a}?.y||0)+(this.${b}?.y||0))/2`) as unknown as number, // y can accept functions even though type says it can't
link_autoMoveAnchors: true,
@@ -293,7 +296,6 @@ export namespace DocUtils {
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 }) {
- // eslint-disable-next-line no-return-assign
return DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(doc[field]), reqdOpts, items) ?? (doc[field] = creator(reqdOpts, items)), scripts, funcs);
}
@@ -359,6 +361,16 @@ export namespace DocUtils {
return ctor ? ctor(path, overwriteDoc ? { ...options, title: StrCast(overwriteDoc.title, path) } : options, overwriteDoc) : undefined;
}
+ /**
+ * Adds items to the doc creator (':') context menu for creating each document type
+ * @param docTextAdder
+ * @param docAdder
+ * @param x
+ * @param y
+ * @param simpleMenu
+ * @param pivotField
+ * @param pivotValue
+ */
export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number, simpleMenu: boolean = false, pivotField?: string, pivotValue?: string | number | boolean): void {
const documentList: ContextMenuProps[] = DocListCast(DocListCast(Doc.MyTools?.data)[0]?.data)
.filter(btnDoc => !btnDoc.hidden)
@@ -372,6 +384,7 @@ export namespace DocUtils {
newDoc.author = ClientUtils.CurrentUserEmail();
newDoc.x = x;
newDoc.y = y;
+ newDoc[DocData].backgroundColor = Doc.UserDoc().textBackgroundColor;
Doc.SetSelectOnLoad(newDoc);
if (pivotField) {
newDoc[pivotField] = pivotValue;
@@ -383,7 +396,10 @@ export namespace DocUtils {
})) as ContextMenuProps[];
documentList.push({
description: ':Smart Drawing',
- event: e => (DocumentView.Selected().lastElement().ComponentView as CollectionFreeFormView)?.showSmartDraw(e?.x || 0, e?.y || 0),
+ event: e =>
+ DocumentView.Selected()
+ .lastElement()
+ .ComponentView?.showSmartDraw?.(e?.x || 0, e?.y || 0),
icon: 'file',
});
ContextMenu.Instance.addItem({
@@ -629,7 +645,7 @@ export namespace DocUtils {
export function assignImageInfo(result: Upload.FileInformation, protoIn: Doc) {
const proto = protoIn;
if (Upload.isImageInformation(result)) {
- const maxNativeDim = Math.min(Math.max(result.nativeHeight, result.nativeWidth), defaultNativeImageDim);
+ const maxNativeDim = Math.max(result.nativeHeight, result.nativeWidth);
const exifRotation = StrCast(result.exifData?.data?.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;
@@ -676,22 +692,51 @@ export namespace DocUtils {
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,
- }),
- });
+ const tbox =
+ StrCast(Doc.UserDoc().fontFamily) === 'Math'
+ ? Docs.Create.EquationDocument('', {
+ //
+ annotationOn,
+ backgroundColor: backgroundColor ?? StrCast(Doc.UserDoc().textBackgroundColor),
+ borderColor: Doc.UserDoc().borderColor as string,
+ borderWidth: Doc.UserDoc().borderWidth as number,
+ x,
+ y,
+ title,
+ text_fontColor: StrCast(Doc.UserDoc().fontColor),
+ _width: 50,
+ _height: 50,
+ _yMargin: 10,
+ _xMargin: 10,
+ nativeWidth: 40,
+ nativeHeight: 40,
+ })
+ : 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 || BoolCast(Doc.UserDoc().fitBox) ? Number(StrCast(Doc.UserDoc().fontSize).replace('px', '')) * 1.5 * 6 : 200,
+ _height: BoolCast(Doc.UserDoc().fitBox) ? Number(StrCast(Doc.UserDoc().fontSize).replace('px', '')) * 1.5 : 35,
+ _layout_centered: BoolCast(Doc.UserDoc()._layout_centered),
+ _layout_fitWidth: true,
+ _layout_autoHeight: true,
+ backgroundColor: StrCast(Doc.UserDoc().textBackgroundColor),
+ borderColor: Doc.UserDoc().borderColor as string,
+ borderWidth: Doc.UserDoc().borderWidth as number,
+ text_fitBox: BoolCast(Doc.UserDoc().fitBox),
+ text_align: StrCast(Doc.UserDoc().textAlign),
+ text_fontColor: StrCast(Doc.UserDoc().fontColor),
+ text_fontFamily: StrCast(Doc.UserDoc().fontFamily),
+ text_fontWeight: StrCast(Doc.UserDoc().fontWeight),
+ text_fontStyle: StrCast(Doc.UserDoc().fontStyle),
+ text_fontDecoration: StrCast(Doc.UserDoc().fontDecoration),
+ }),
+ });
if (defaultTextTemplate) {
tbox.layout_fieldKey = 'layout_' + StrCast(defaultTextTemplate.title);
@@ -739,6 +784,57 @@ export namespace DocUtils {
return generatedDocuments;
}
+ export async function openSVGfile(file: File, options: DocumentOptions) {
+ const reader = new FileReader();
+ const scale = 1;
+ const startPoint = { X: (options.x as number) ?? 0, Y: (options.y as number) ?? 0 };
+ const buffer = await new Promise<string>((res, rej) => {
+ reader.onload = event => {
+ const fileContent = event.target?.result;
+ // Process the file content here
+ console.log(fileContent);
+ typeof fileContent === 'string' ? res(fileContent) : rej();
+ };
+
+ reader.readAsText(file);
+ });
+ const svg = buffer.match(/<svg[^>]*>([\s\S]*?)<\/svg>/g);
+ if (svg) {
+ const svgObject = await parse(svg[0]);
+ const strokeData: [InkData, string, string][] = [];
+ const tl = { X: Number.MAX_SAFE_INTEGER, Y: Number.MAX_SAFE_INTEGER };
+ let last: PointData = { X: 0, Y: 0 };
+ const processStroke = (child: INode) => {
+ child.attributes.d
+ .split(/[\n]?M/)
+ .slice(1)
+ .map((d, ind) => {
+ const convertedBezier: InkData = SVGToBezier(child.name as SVGType, { ...child, d: '\nM' + d } as unknown as Record<string, string>, last);
+ last = convertedBezier.lastElement();
+ convertedBezier.forEach(point => {
+ if (point.X < tl.X) tl.X = point.X;
+ if (point.Y < tl.Y) tl.Y = point.Y;
+ });
+ strokeData.push([convertedBezier, child.attributes.stroke || 'black', ind === 0 ? child.attributes.fill : child.attributes.fill === 'none' ? child.attributes.fill : DashColor(child.attributes.fill).negate().toString()]);
+ });
+ };
+ const processNode = (parent: INode) => {
+ if (parent.children.length) parent.children.forEach(processNode);
+ else if (parent.type !== 'text') processStroke(parent);
+ };
+ processNode(svgObject);
+
+ const mapStroke = (pd: PointData): PointData => ({ X: startPoint.X + (pd.X - tl.X) * scale, Y: startPoint.Y + (pd.Y - tl.Y) * scale });
+
+ return SmartDrawHandler.CreateDrawingDoc(
+ strokeData.map(sdata => [sdata[0].map(mapStroke), sdata[1], sdata[2]] as [PointData[], string, string]),
+ { autoColor: true },
+ '',
+ undefined
+ );
+ }
+ }
+
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.
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 59a121de7..8aa844c0b 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -26,12 +26,13 @@ export enum DocumentType {
SCRIPTING = 'script', // script editor
CHAT = 'chat', // chat with GPT about files
EQUATION = 'equation', // equation editor
- FUNCPLOT = 'funcplot', // function plotter
+ FUNCPLOT = 'function plot', // function plotter
MAP = 'map',
DATAVIZ = 'dataviz',
ANNOPALETTE = 'annopalette',
LOADING = 'loading',
SIMULATION = 'simulation', // physics simulation
+ MESSAGE = 'message', // chat message
// special purpose wrappers that either take no data or are compositions of lower level types
LINK = 'link',
@@ -47,22 +48,22 @@ export enum DocumentType {
export enum CollectionViewType {
Invalid = 'invalid',
Freeform = 'freeform',
- Schema = 'schema',
- Docking = 'docking',
- Tree = 'tree',
- Stacking = 'stacking',
- Masonry = 'masonry',
- Multicolumn = 'multicolumn',
- Multirow = 'multirow',
- Time = 'time',
+ Calendar = 'calendar',
+ Card = 'card',
Carousel = 'carousel',
Carousel3D = '3D Carousel',
+ Docking = 'docking',
+ Grid = 'grid',
Linear = 'linear',
Map = 'map',
- Grid = 'grid',
+ Masonry = 'masonry',
+ Multicolumn = 'multicolumn',
+ Multirow = 'multirow',
+ NoteTaking = 'notetaking',
Pile = 'pileup',
+ Schema = 'schema',
+ Stacking = 'stacking',
StackedTimeline = 'stacked timeline',
- NoteTaking = 'notetaking',
- Calendar = 'calendar',
- Card = 'card',
+ Time = 'time',
+ Tree = 'tree',
}
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 0a7047128..1ce25165c 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -18,6 +18,7 @@ import { PointData } from '../../pen-gestures/GestureTypes';
import { DocServer } from '../DocServer';
import { dropActionType } from '../util/DropActionTypes';
import { CollectionViewType, DocumentType } from './DocumentTypes';
+import { Id } from '../../fields/FieldSymbols';
class EmptyBox {
public static LayoutString() {
@@ -196,8 +197,10 @@ export class DocumentOptions {
data_nativeWidth?: NUMt = new NumInfo('native width of data field contents (e.g., the pixel width of an image)', false);
data_nativeHeight?: NUMt = new NumInfo('native height of data field contents (e.g., the pixel height of an image)', false);
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);
+ _nativeWidth?: NUMt = new NumInfo('Deprecated: use nativeWidth. native width of document contents (e.g., the pixel width of an image)', false);
+ _nativeHeight?: NUMt = new NumInfo('Deprecated: use nativeHeight. native height of document contents (e.g., the pixel height of an image)', 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);
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
@@ -237,10 +240,9 @@ export class DocumentOptions {
dataViz?: string;
dataViz_savedTemplates?: LISTt;
- borderWidth?: STRt = new StrInfo('Width of user-added border', false);
- borderColor?: STRt = new StrInfo('Color of user-added border', false);
+ borderWidth?: NUMt = new NumInfo('Width of docuent border', false);
+ borderColor?: STRt = new StrInfo('Color of document border', false);
text_fontColor?: STRt = new StrInfo('Color of text', false);
- text_align?: STRt = new StrInfo('alignment');
hCentering?: 'h-left' | 'h-center' | 'h-right';
isDefaultTemplateDoc?: BOOLt = new BoolInfo('');
contentBold?: BOOLt = new BoolInfo('');
@@ -259,6 +261,7 @@ 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_hideDecorations?: BOOLt = new BoolInfo('whether to suppress all document decortations when selected');
_layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown');
layout_diagramEditor?: STRt = new StrInfo('specify the JSX string for a diagram editor view');
layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown');
@@ -280,7 +283,7 @@ export class DocumentOptions {
_layout_fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)');
_layout_fieldKey?: STRt = new StrInfo('the field key containing the current layout definition', false);
_layout_enableAltContentUI?: BOOLt = new BoolInfo('whether to show alternate content button');
- _layout_isFlashcard?: BOOLt = new BoolInfo('whether comparison node should be displayed as a flashcard');
+ _layout_flashcardType?: STRt = new StrInfo('flashcard style to render in ComparisonBox. currently just "flashcard".');
_layout_showTitle?: string; // field name to display in header (:hover is an optional suffix)
_layout_showSidebar?: BOOLt = new BoolInfo('whether an annotationsidebar should be displayed for text docuemnts');
_layout_showCaption?: string; // which field to display in the caption area. leave empty to have no caption
@@ -293,7 +296,6 @@ export class DocumentOptions {
_yMargin?: NUMt = new NumInfo('gap between top edge of dcoument and start of masonry/stacking layouts', false);
_xPadding?: NUMt = new NumInfo('x padding', false);
_yPadding?: NUMt = new NumInfo('y padding', false);
- _singleLine?: boolean; // whether label box is restricted to one line of text
_createDocOnCR?: boolean; // whether carriage returns and tabs create new text documents
_columnWidth?: NUMt = new NumInfo('width of table column', false);
_columnsHideIfEmpty?: BOOLt = new BoolInfo('whether stacking view column headings should be hidden');
@@ -301,9 +303,15 @@ export class DocumentOptions {
_caption_yMargin?: NUMt = new NumInfo('y margin of caption inside of a carousel collection', false, true);
icon_nativeWidth?: NUMt = new NumInfo('native width of icon view', false, true);
icon_nativeHeight?: NUMt = new NumInfo('native height of icon view', false, true);
- _text_fontSize?: string;
- _text_fontFamily?: string;
- _text_fontWeight?: string;
+ text_fontSize?: string;
+ text_fontFamily?: string;
+ text_fontWeight?: string;
+ text_fitBox?: BOOLt = new BoolInfo("whether text box should be scaled to fit it's containing render box");
+ text_align?: STRt = new StrInfo('horizontal text alignment default', undefined, undefined, ['left', 'center', 'right']);
+ title_align?: STRt = new StrInfo('horizontal title alignment in label box', undefined, undefined, ['left', 'center', 'right']);
+ title_transform?: STRt = new StrInfo('transformation to apply to title in label box (eg., uppercase)', undefined, undefined, ['uppercase', 'lowercase', 'capitalize']);
+ text_transform?: STRt = new StrInfo('transformation to apply to text in text box (eg., uppercase)', undefined, undefined, ['uppercase', 'lowercase', 'capitalize']);
+ text_placeholder?: BOOLt = new BoolInfo('makes the text act like a placeholder and automatically select when the text box is selected');
fontSize?: string;
_pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views
@@ -358,6 +366,7 @@ export class DocumentOptions {
isFolder?: BOOLt = new BoolInfo('is document a tree view folder');
_isTimelineLabel?: BOOLt = new BoolInfo('is document a timeline label');
_isLightbox?: BOOLt = new BoolInfo('whether a collection acts as a lightbox by opening lightbox links by hiding all other documents in collection besides link target');
+ cloneOnCopy?: BOOLt = new BoolInfo('if this Doc is a field of another Doc, then it should be copied when the other Doc is copied');
mapPin?: DOCt = new DocInfo('pin associated with a config anchor', false);
config_latitude?: NUMt = new NumInfo('latitude of a map', false);
@@ -368,6 +377,8 @@ export class DocumentOptions {
config_panX?: NUMt = new NumInfo('panX saved as a view spec', false);
config_panY?: NUMt = new NumInfo('panY saved as a view spec', false);
config_zoom?: NUMt = new NumInfo('zoom saved as a view spec', false);
+ config_carousel_index?: NUMt = new NumInfo('saved carousel index', false);
+ config_card_curDoc?: DOCt = new DocInfo('current doc in a collection view, e.g., cardView');
config_viewScale?: NUMt = new NumInfo('viewScale saved as a view Spec', false);
presentation_transition?: NUMt = new NumInfo('the time taken for the transition TO a document', false);
presentation_duration?: NUMt = new NumInfo('the duration of the slide in presentation view', false);
@@ -418,6 +429,12 @@ export class DocumentOptions {
flexGap?: NUMt = new NumInfo('Linear view flex gap');
flexDirection?: 'unset' | 'row' | 'column' | 'row-reverse' | 'column-reverse';
+ // Comparison
+ data_revealOp?: STRt = new StrInfo("visual reveal type for front and back of comparison - 'slide' or 'flip' ");
+ data_revealOp_hover?: BOOLt = new BoolInfo('reveal back of comparison manually or by hovering');
+ data_front?: DOCt = new DocInfo('contents of front of flashcard/comparison');
+ data_back?: DOCt = new DocInfo('contents of back of flashcard/comparison');
+
link?: string;
link_description?: string; // added for links
link_relationship?: string; // type of relatinoship a link represents
@@ -484,7 +501,6 @@ export class DocumentOptions {
sidebar_type_collection?: string; // collection type of text sidebar
data_dashboards?: List<FieldType>; // list of dashboards used in shareddocs;
- textTransform?: string;
letterSpacing?: string;
iconTemplate?: string; // name of icon template style
icon_fieldKey?: string; // specifies the icon template to use (e.g., icon_fieldKey='george', then the icon template's name is icon_george; otherwise, the template's name would be icon_<type> where type is the Doc's type(pdf,rich text, etc))
@@ -498,8 +514,12 @@ export class DocumentOptions {
userBackgroundColor?: STRt = new StrInfo('background color associated with a Dash user (seen in header fields of shared documents)');
userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
- cardSort?: STRt = new StrInfo('way cards are sorted in deck view');
- cardSort_isDesc?: BOOLt = new BoolInfo('whether the cards are sorted ascending or descending');
+ card_sort?: STRt = new StrInfo('way cards are sorted in deck view');
+ card_sort_isDesc?: BOOLt = new BoolInfo('whether the cards are sorted ascending or descending');
+
+ ai?: string; // to mark items as ai generated
+ ai_firefly_seed?: number;
+ ai_firefly_prompt?: string;
}
export const DocOptions = new DocumentOptions();
@@ -695,7 +715,7 @@ export namespace Docs {
dataProps.author_date = new DateField();
if (fieldKey) {
dataProps[`${fieldKey}_modificationDate`] = new DateField();
- dataProps[fieldKey] = options.data ?? data;
+ dataProps[fieldKey] = (options as unknown as { [key: string]: FieldType | undefined })[fieldKey] ?? data;
// so that the list of annotations is already initialised, prevents issues in addonly.
// without this, if a doc has no annotations but the user has AddOnly privileges, they won't be able to add an annotation because they would have needed to create the field's list which they don't have permissions to do.
@@ -734,6 +754,9 @@ export namespace Docs {
updateCachedAcls(dataDoc);
updateCachedAcls(viewDoc);
+ if (data instanceof List) {
+ data.map(item => item instanceof Doc && Doc.SetContainer(item, viewDoc));
+ }
return viewDoc;
}
@@ -779,11 +802,42 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.SCREENSHOT), '', options);
}
- export function ComparisonDocument(text: string, options: DocumentOptions = { title: 'Comparison Box' }) {
- return InstanceFromProto(Prototypes.get(DocumentType.COMPARISON), text, options);
+ export function ComparisonDocument(title: string, options: DocumentOptions) {
+ return InstanceFromProto(Prototypes.get(DocumentType.COMPARISON), '', options);
}
- export function DiagramDocument(options: DocumentOptions = { title: '' }) {
- return InstanceFromProto(Prototypes.get(DocumentType.DIAGRAM), undefined, options);
+ /**
+ * Creates a text box where the supplied text (and optional iimage) will be vertically
+ * and horizontally centered. If text_placeholder is set to true, then the text will be
+ * treated as placeholder text and automatically selected when the text box is selected.
+ * @param title name of text box
+ * @param text text to display in text box
+ * @param opts metadata fields to set on text box
+ * @param img optional image to add to text box
+ * @returns
+ */
+ export function CenteredTextCreator(title: string, text: string, opts: DocumentOptions, img?: Doc) {
+ return TextDocument(RichTextField.textToRtf(text, img?.[Id]), {
+ title, //
+ _layout_autoHeight: true,
+ _layout_centered: true,
+ text_align: 'center',
+ _layout_fitWidth: true,
+ ...opts,
+ });
+ }
+
+ export function FlashcardDocument(title: string, front?: Doc, back?: Doc, options: DocumentOptions = { title: 'Flashcard' }) {
+ return InstanceFromProto(Prototypes.get(DocumentType.COMPARISON), '', {
+ data_front: front ?? CenteredTextCreator('question', 'hint: Enter a topic, select this document and click the stack button to have GPT create a deck of cards', { text_placeholder: true, cloneOnCopy: true }, undefined),
+ data_back: back ?? CenteredTextCreator('answer', 'answer here', { text_placeholder: true, cloneOnCopy: true }, undefined),
+ _layout_fitWidth: true,
+ _layout_flashcardType: 'flashcard',
+ title,
+ ...options,
+ });
+ }
+ export function DiagramDocument(data?: string, options: DocumentOptions = { title: '' }) {
+ return InstanceFromProto(Prototypes.get(DocumentType.DIAGRAM), data, options);
}
export function AudioDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) {
@@ -817,7 +871,12 @@ export namespace Docs {
export function RTFDocument(field: RichTextField, options: DocumentOptions = {}, fieldKey: string = 'text') {
return InstanceFromProto(Prototypes.get(DocumentType.RTF), field, options, undefined, fieldKey);
}
- export function TextDocument(text: string, options: DocumentOptions = {}, fieldKey: string = 'text') {
+
+ export function MessageDocument(field: string, options: DocumentOptions = {}, fieldKey: string = 'data') {
+ return InstanceFromProto(Prototypes.get(DocumentType.MESSAGE), field, options, undefined, fieldKey);
+ }
+
+ export function TextDocument(text: string | RichTextField, options: DocumentOptions = {}, fieldKey: string = 'text') {
const rtf = {
doc: {
type: 'doc',
@@ -836,7 +895,7 @@ export namespace Docs {
selection: { type: 'text', anchor: 1, head: 1 },
storedMarks: [],
};
- const field = text ? new RichTextField(JSON.stringify(rtf), text) : undefined;
+ const field = text instanceof RichTextField ? text : text ? new RichTextField(JSON.stringify(rtf), text) : options.text instanceof RichTextField ? options.text : undefined;
return InstanceFromProto(Prototypes.get(DocumentType.RTF), field, options, undefined, fieldKey);
}
@@ -863,7 +922,7 @@ export namespace Docs {
const I = Doc.GetProto(ink);
// I.layout_hideOpenButton = true; // don't show open full screen button when selected
I.color = color;
- I.fillColor = fillColor;
+ I.fillColor = fillColor && fillColor !== 'transparent' ? fillColor : undefined;
I.stroke = new InkField(points);
I.stroke_width = strokeWidth;
I.stroke_bezier = strokeBezier;
@@ -873,8 +932,9 @@ export namespace Docs {
I.stroke_isInkMask = isInkMask;
I.text_align = 'center';
I.rotation = 0;
+ I.width_min = 1;
+ I.height_min = 1;
I.defaultDoubleClick = 'ignore';
- I.keepZWhenDragged = true;
I.author_date = new DateField();
I.acl_Guest = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View;
// I.acl_Override = SharingPermissions.Unset;
@@ -918,15 +978,13 @@ export namespace Docs {
}
export function CalendarDocument(options: DocumentOptions, documents: Array<Doc>) {
- const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), {
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), {
_layout_nativeDimEditable: true,
_layout_reflowHorizontal: true,
_layout_reflowVertical: true,
...options,
_type_collection: CollectionViewType.Calendar,
});
- documents.forEach(d => Doc.SetContainer(d, inst));
- return inst;
}
// shouldn't ever need to create a KVP document-- instead set the LayoutTemplateString to be a KeyValueBox for the DocumentView (see addDocTab in TabDocView)
@@ -935,9 +993,7 @@ export namespace Docs {
// }
export function FreeformDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
- 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;
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _type_collection: CollectionViewType.Freeform }, id);
}
export function ConfigDocument(options: DocumentOptions, id?: string) {
@@ -1038,13 +1094,11 @@ export namespace Docs {
}
export function AnnoPaletteDocument(options?: DocumentOptions) {
- return InstanceFromProto(Prototypes.get(DocumentType.ANNOPALETTE), new List([Doc.MyAnnos]), { ...(options || {}) });
+ return InstanceFromProto(Prototypes.get(DocumentType.ANNOPALETTE), new List([Doc.MyStickers]), { ...(options || {}) });
}
export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
- const ret = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeView_FreezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, dockingConfig: config }, id);
- documents.map(c => Doc.SetContainer(c, ret));
- return ret;
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeView_FreezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, dockingConfig: config }, id);
}
export function DelegateDocument(proto: Doc, options: DocumentOptions = {}) {