aboutsummaryrefslogtreecommitdiff
path: root/src/client/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util')
-rw-r--r--src/client/util/CalendarManager.tsx15
-rw-r--r--src/client/util/CaptureManager.tsx2
-rw-r--r--src/client/util/CurrentUserUtils.ts251
-rw-r--r--src/client/util/DictationManager.ts45
-rw-r--r--src/client/util/DocumentManager.ts23
-rw-r--r--src/client/util/DragManager.ts45
-rw-r--r--src/client/util/DropConverter.ts14
-rw-r--r--src/client/util/GroupManager.tsx14
-rw-r--r--src/client/util/History.ts2
-rw-r--r--src/client/util/Import & Export/ImageUtils.ts14
-rw-r--r--src/client/util/LinkFollower.ts32
-rw-r--r--src/client/util/LinkManager.ts42
-rw-r--r--src/client/util/ReplayMovements.ts6
-rw-r--r--src/client/util/ScriptManager.ts9
-rw-r--r--src/client/util/Scripting.ts1
-rw-r--r--src/client/util/SearchUtil.ts11
-rw-r--r--src/client/util/SettingsManager.tsx32
-rw-r--r--src/client/util/SharingManager.tsx6
-rw-r--r--src/client/util/SnappingManager.ts54
-rw-r--r--src/client/util/reportManager/ReportManagerComponents.tsx4
-rw-r--r--src/client/util/request-image-size.ts38
21 files changed, 337 insertions, 323 deletions
diff --git a/src/client/util/CalendarManager.tsx b/src/client/util/CalendarManager.tsx
index d28b3a2c9..b50e39c02 100644
--- a/src/client/util/CalendarManager.tsx
+++ b/src/client/util/CalendarManager.tsx
@@ -8,7 +8,6 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import Select from 'react-select';
import { Doc, DocListCast } from '../../fields/Doc';
-import { DocData } from '../../fields/DocSymbols';
import { StrCast } from '../../fields/Types';
import { Docs } from '../documents/Documents';
import { MainViewModal } from '../views/MainViewModal';
@@ -51,8 +50,6 @@ export class CalendarManager extends ObservableReactComponent<object> {
@observable private targetDocView: DocumentView | undefined = undefined; // the DocumentView of the target doc
@observable private dialogueBoxOpacity = 1; // for the modal
- @observable private layoutDocAcls: boolean = false; // whether the layout doc or data doc's acls are to be used
-
@observable private creationType: CreationType = 'new-calendar';
@observable private existingCalendars: Doc[] = DocListCast(Doc.MyCalendars?.data);
@@ -97,7 +94,6 @@ export class CalendarManager extends ObservableReactComponent<object> {
}),
500
);
- this.layoutDocAcls = false;
});
constructor(props: object) {
@@ -122,9 +118,8 @@ export class CalendarManager extends ObservableReactComponent<object> {
// TODO: Make undoable
private addToCalendar = () => {
const docs = DocumentView.Selected().length < 2 ? [this.targetDoc] : DocumentView.Selected().map(docView => docView.Document);
- const targetDoc = this.layoutDocAcls ? docs[0] : docs[0]?.[DocData]; // doc to add to calendar
+ const targetDoc = docs[0];
- console.log(targetDoc);
if (targetDoc) {
let calendar: Doc;
if (this.creationType === 'new-calendar') {
@@ -167,7 +162,7 @@ export class CalendarManager extends ObservableReactComponent<object> {
console.log('my calendars: ', Doc.MyCalendars);
if (this.creationType === 'new-calendar') {
- Doc.AddDocToList(Doc.MyCalendars, 'data', calendar); // add to new calendar to dashboard calendars
+ Doc.MyCalendars && Doc.AddDocToList(Doc.MyCalendars, 'data', calendar); // add to new calendar to dashboard calendars
}
}
};
@@ -234,14 +229,14 @@ export class CalendarManager extends ObservableReactComponent<object> {
@computed
get calendarInterface() {
const docs = DocumentView.Selected().length < 2 ? [this.targetDoc] : DocumentView.Selected().map(docView => docView.Document);
- const targetDoc = this.layoutDocAcls ? docs[0] : docs[0]?.[DocData];
+ const targetDoc = docs[0];
return (
<div
className="calendar-interface"
style={{
background: SnappingManager.userBackgroundColor,
- color: StrCast(Doc.UserDoc().userColor),
+ color: SnappingManager.userColor,
}}>
<p className="selected-doc-title" style={{ color: SnappingManager.userColor }}>
<b>{this.focusOn(docs.length < 2 ? StrCast(targetDoc?.title, 'this document') : '-multiple-')}</b>
@@ -324,7 +319,7 @@ export class CalendarManager extends ObservableReactComponent<object> {
<div className="date-range-picker-container">
<div>Select a date range: </div>
<Provider theme={defaultTheme}>
- <DateRangePicker aria-label="Select a date range" value={this.selectedDateRange} onChange={v => this.setSelectedDateRange(v)} />
+ <DateRangePicker aria-label="Select a date range" value={this.selectedDateRange} onChange={v => v && this.setSelectedDateRange(v)} />
</Provider>
</div>
{this.createButtonActive && (
diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx
index 47f31612f..80af78898 100644
--- a/src/client/util/CaptureManager.tsx
+++ b/src/client/util/CaptureManager.tsx
@@ -13,7 +13,7 @@ import './CaptureManager.scss';
export class CaptureManager extends React.Component<object> {
// eslint-disable-next-line no-use-before-define
public static Instance: CaptureManager;
- static _settingsStyle = addStyleSheet();
+ static _settingsStyle = addStyleSheet().sheet;
@observable _document: Opt<Doc> = undefined;
@observable isOpen: boolean = false; // whether the CaptureManager is to be displayed or not.
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 21e1d3e12..28b19d55e 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -3,7 +3,6 @@ import { reaction, runInAction } from "mobx";
import * as rp from 'request-promise';
import { ClientUtils, OmitKeys } from "../../ClientUtils";
import { Doc, DocListCast, DocListCastAsync, FieldType, Opt } from "../../fields/Doc";
-import { DocData } from "../../fields/DocSymbols";
import { InkEraserTool, InkInkTool, InkProperty, InkTool } from "../../fields/InkField";
import { List } from "../../fields/List";
import { PrefetchProxy } from "../../fields/Proxy";
@@ -16,7 +15,7 @@ import { SetCachedGroups, SharingPermissions } from "../../fields/util";
import { Gestures } from "../../pen-gestures/GestureTypes";
import { DocServer } from "../DocServer";
import { DocUtils, FollowLinkScript } from '../documents/DocUtils';
-import { CollectionViewType, DocumentType } from "../documents/DocumentTypes";
+import { CollectionViewType, DocumentType, standardViewTypes } from "../documents/DocumentTypes";
import { Docs, DocumentOptions, FInfo, FInfoFieldType } from "../documents/Documents";
import { DashboardView } from "../views/DashboardView";
import { OverlayView } from "../views/OverlayView";
@@ -53,11 +52,12 @@ export interface Button {
numBtnMax?: number;
switchToggle?: boolean;
width?: number;
- linearBtnWidth?: number;
+ linearView_btnWidth?: number;
toolType?: string; // type of pen tool
expertMode?: boolean;// available only in expert mode
btnList?: List<string>;
ignoreClick?: boolean;
+ showUntilToggle?: boolean; // whether the popup should stay open when the background is clicked.
buttonText?: string;
backgroundColor?: string;
waitForDoubleClickToClick?: boolean;
@@ -147,11 +147,13 @@ export class CurrentUserUtils {
{ title: "Postit", backgroundColor: "yellow", icon: "sticky-note", _layout_showTitle: "title", layout_borderRounding: "5px"},
{ title: "Idea", backgroundColor: "pink", icon: "lightbulb" , _layout_showTitle: "title"},
{ title: "Topic", backgroundColor: "lightblue", icon: "book-open" , _layout_showTitle: "title"}];
+
+ const metanote = DocCast(doc.emptyMetaNote);
const reqdNoteList = [...reqdTempOpts.map(opts => {
const reqdOpts = {...opts, isSystem:true, width:200, layout_autoHeight: true, layout_fitWidth: true};
const noteTemp = tempNotes ? DocListCast(tempNotes.data).find(fdoc => fdoc.title === opts.title): undefined;
return DocUtils.AssignOpts(noteTemp, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts));
- }), ... DocListCast(tempNotes?.data).filter(note => !reqdTempOpts.find(reqd => reqd.title === note.title))];
+ }), ...(metanote ? [metanote]:[]), ... DocListCast(tempNotes?.data).filter(note => !reqdTempOpts.find(reqd => reqd.title === note.title))];
const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, isSystem: true };
return DocUtils.AssignOpts(tempNotes, reqdOpts, reqdNoteList) ?? (doc[field] = Docs.Create.TreeDocument(reqdNoteList, reqdOpts));
@@ -203,13 +205,13 @@ export class CurrentUserUtils {
const templateIconsDoc = DocUtils.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([], reqdOpts));
const labelBox = (opts: DocumentOptions, fieldKey:string) => Docs.Create.LabelDocument({
- layout: LabelBox.LayoutString(fieldKey), letterSpacing: "unset", _label_minFontSize: 14, _label_maxFontSize: 14, layout_borderRounding: "5px", _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts
+ layout: LabelBox.LayoutString(fieldKey), letterSpacing: "unset", _label_minFontSize: 14, _label_maxFontSize: 14, layout_borderRounding: "5px", _width: 150, _height: 70, _xMargin: 10, _yMargin: 10, ...opts
});
const imageBox = (opts: DocumentOptions, fieldKey:string) => Docs.Create.ImageDocument( "http://www.cs.brown.edu/~bcz/noImage.png", { layout:ImageBox.LayoutString(fieldKey), "icon_nativeWidth": 360 / 4, "icon_nativeHeight": 270 / 4, iconTemplate:DocumentType.IMG, _width: 360 / 4, _height: 270 / 4, _layout_showTitle: "title", ...opts });
const fontBox = (opts:DocumentOptions, fieldKey:string) => Docs.Create.FontIconDocument({ layout:FontIconBox.LayoutString(fieldKey), _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, ...opts });
const makeIconTemplate = (name: DocumentType | string | undefined, templateField: string, opts:DocumentOptions) => {
- const title = "icon" + (name ? "_" + name : "");
+ const title = "icon" + (name ? name[0].toUpperCase()+name.slice(1) : "");
const curIcon = DocCast(templateIconsDoc[title]);
const creator = (() => { switch (opts.iconTemplate) {
case DocumentType.IMG : return imageBox;
@@ -247,7 +249,6 @@ export class CurrentUserUtils {
title: string, toolTip: string, icon: string, ignoreClick?: boolean, dragFactory?: Doc,
backgroundColor?: string, openFactoryAsDelegate?:boolean, openFactoryLocation?:string, clickFactory?: Doc, scripts?: { onClick?: string, onDragStart?: string}, funcs?: {onDragStart?:string, hidden?: string},
}[] {
- const standardOps = (key:string) => ({ title : "Untitled "+ key, _layout_fitWidth: false, isSystem: true, "dragFactory_count": 0, cloneFieldFilter: new List<string>(["isSystem"]) });
const json = {
doc: {
type: "doc",
@@ -272,17 +273,17 @@ export class CurrentUserUtils {
// " <FormattedTextBox {...props} fieldKey={'header'} dontSelectOnLoad={'true'} ignoreAutoHeight={'true'} pointerEvents='{this._header_pointerEvents||`none`}' fontSize='{this._header_fontSize}px' height='{this._header_height}px' background='{this._header_color}' />" +
// " <FormattedTextBox {...props} fieldKey={'text'} position='absolute' top='{this._header_height}px' height='calc(100% - {this._header_height}px)'/>" +
// "</div>";
- const headerBtnHgt = 10;
- const headerTemplate = (opts:DocumentOptions) =>
- MakeTemplate(Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { ...opts, title: "Header Template",
+ const metadataBtnHght = 10;
+ const metaNoteTemplate = (opts:DocumentOptions) =>
+ MakeTemplate(Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { ...opts, title: "MetaNote",
layout:`<HTMLdiv transformOrigin='top left' width='100%' height='100%'>
- <FormattedTextBox {...props} dontScale='true' fieldKey={'text'} height='calc(100% - ${headerBtnHgt}px - {this._header_height||0}px)' />
- <FormattedTextBox {...props} dontScale='true' fieldKey={'header'} dontSelectOnLoad='true' ignoreAutoHeight='true' fontSize='{this._header_fontSize||9}px' height='{(this._header_height||0)}px' backgroundColor='{this._header_color || "lightGray"}' />
- <HTMLdiv fontSize='${headerBtnHgt - 1}px' height='${headerBtnHgt}px' backgroundColor='yellow'
- onClick={‘(this._header_height=(this._header_height===0?50:0)) + (this._layout_autoHeightMargins=this._header_height ? this._header_height+${headerBtnHgt}:0)’} > Metadata
+ <FormattedTextBox {...props} dontScale='true' fieldKey={'text'} height='calc(100% - ${metadataBtnHght}px - {this._header_height||0}px)' />
+ <FormattedTextBox {...props} noSidebar='true' dontScale='true' fieldKey={'header'} dontSelectOnLoad='true' ignoreAutoHeight='true' fontSize='{this._header_fontSize||9}px' height='{(this._header_height||0)}px' backgroundColor='{this._header_color || "lightGray"}' />
+ <HTMLdiv fontSize='${metadataBtnHght - 1}px' height='${metadataBtnHght}px' backgroundColor='yellow'
+ onClick={‘(this._header_height=(this._header_height===0?50:0)) + (this._layout_autoHeightMargins=this._header_height ? this._header_height+${metadataBtnHght}:0)’} > Metadata
</HTMLdiv>
</HTMLdiv>`
- }, "header"));
+ }, "metaNote"));
const slideView = (opts:DocumentOptions) =>
MakeTemplate(Docs.Create.MultirowDocument(
[
@@ -323,9 +324,9 @@ export class CurrentUserUtils {
type: 'scatter'
}`);
const slide = Docs.Create.TextDocument("", opts);
- slide[DocData].text = rtfield;
- slide[DocData].layout_textPainted = `<CollectionView {...props} fieldKey={'text'}/>`;
- slide[DocData]._type_collection = CollectionViewType.Freeform;
+ slide.$text = rtfield;
+ slide.$layout_textPainted = `<CollectionView {...props} fieldKey={'text'}/>`;
+ slide.$type_collection = CollectionViewType.Freeform;
slide.onPaint = ScriptField.MakeScript(`toggleDetail(documentView, "textPainted")`, {documentView:"any"});
return slide;
}
@@ -374,9 +375,9 @@ pie title Minerals in my tap water
"Potassium" : 50
"Magnesium" : 10.01`);
const slide = Docs.Create.TextDocument("", opts);
- slide[DocData].text = rtfield;
- slide[DocData].layout_textPainted = `<CollectionView {...props} fieldKey={'text'}/>`;
- slide[DocData]._type_collection = CollectionViewType.Freeform;
+ slide.$text = rtfield;
+ slide.$layout_textPainted = `<CollectionView {...props} fieldKey={'text'}/>`;
+ slide.$_type_collection = CollectionViewType.Freeform;
slide.onPaint = ScriptField.MakeScript(`toggleDetail(documentView, "textPainted")`, {documentView:"any"});
return slide;
}
@@ -401,13 +402,15 @@ pie title Minerals in my tap water
{key: "Map", creator: opts => Docs.Create.MapDocument([], opts), opts: { _width: 800, _height: 600, _layout_fitWidth: true, }},
{key: "Screengrab", creator: Docs.Create.ScreenshotDocument, opts: { _width: 400, _height: 200 }},
{key: "WebCam", creator: opts => Docs.Create.WebCamDocument("", opts), opts: { _width: 400, _height: 200, recording:true, isSystem: true, cloneFieldFilter: new List<string>(["isSystem"]) }},
- {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, title_custom: true, waitForDoubleClickToClick: 'never'}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}},
+ {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xMargin: 10, _yMargin: 10, title_custom: true, waitForDoubleClickToClick: 'never'}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}},
{key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }},
{key: "DataViz", creator: opts => Docs.Create.DataVizDocument("", opts), opts: { _width: 300, _height: 300, }},
// AARAV ADD //
- {key: "DailyJournal",creator:opts => Docs.Create.DailyJournalDocument("", opts),opts:{ _width: 300, _height: 300}},
+ {key: "DailyJournal",creator:opts => Docs.Create.DailyJournalDocument("", opts),opts: { _width: 300, _height: 300, }},
+ {key: "Scrapbook",creator:opts => Docs.Create.ScrapbookDocument([], opts),opts:{ _width: 300, _height: 300}},
+ //{key: "Scrapbook",creator:opts => Docs.Create.ScrapbookDocument([], opts),opts:{ _width: 300, _height: 300}},
{key: "Chat", creator: Docs.Create.ChatDocument, opts: { _width: 500, _height: 500, _layout_fitWidth: true, }},
- {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 120, _header_pointerEvents: "all", _header_height: 50, _header_fontSize: 9,_layout_autoHeightMargins: 50, _layout_autoHeight: true, treeView_HideUnrendered: true}},
+ {key: "MetaNote", creator: metaNoteTemplate, opts: { _width: 300, _height: 120, _header_pointerEvents: "all", _header_height: 50, _header_fontSize: 9,_layout_autoHeightMargins: 50, _layout_autoHeight: true, treeView_HideUnrendered: true}},
{key: "ViewSlide", creator: slideView, opts: { _width: 400, _height: 300, _xMargin: 3, _yMargin: 3,}},
{key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, _layout_dontCenter:'xy', dropAction: dropActionType.embed, treeView_HideTitle: true, _layout_fitWidth:true, layout_boxShadow: "0 0" }},
{key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }},
@@ -420,40 +423,46 @@ pie title Minerals in my tap water
{key: "Plotly", creator: plotlyView, opts: { _width: 300, _height: 300, }},
];
+ const standardOps = (key:string) => ({ title : "Untitled "+ key, _layout_fitWidth: false, isSystem: true, "dragFactory_count": 0, cloneFieldFilter: new List<string>(["isSystem"]) });
emptyThings.forEach(
thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs));
-
+ const metanote = DocCast(Doc.UserDoc().emptyMetaNote);
+ if (metanote) {
+ metanote.title = "MetaNote"; // hack: metanotes are used a template, so 'untitled metaNote' is an awkward name
+ }
+
return [
- { toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, clickFactory: DocCast(doc.emptyNote)},
- { toolTip: "Tap or drag to create a flashcard", title: "Flashcard", icon: "id-card", dragFactory: doc.emptyFlashcard as Doc, clickFactory: DocCast(doc.emptyFlashcard)},
- { toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, clickFactory: DocCast(doc.emptyEquation)},
- { toolTip: "Tap or drag to create a mermaid node", title: "Mermaids", icon: "rocket", dragFactory: doc.emptyMermaids as Doc, clickFactory: DocCast(doc.emptyMermaids)},
- { toolTip: "Tap or drag to create a plotly node", title: "Plotly", icon: "rocket", dragFactory: doc.emptyPlotly as Doc, clickFactory: DocCast(doc.emptyMermaids)},
- { toolTip: "Tap or drag to create a note board", title: "Notes", icon: "book", dragFactory: doc.emptyNoteboard as Doc, clickFactory: DocCast(doc.emptyNoteboard)},
- { toolTip: "Tap or drag to create an image", title: "Image", icon: "image", dragFactory: doc.emptyImage as Doc, clickFactory: DocCast(doc.emptyImage)},
- { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab)},
- { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, clickFactory: DocCast(doc.emptyWebpage)},
- { toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, clickFactory: DocCast(doc.emptyComparison)},
- { toolTip: "Tap or drag to create a diagram", title: "Diagram", icon: "tree", dragFactory: doc.emptyDiagram as Doc, clickFactory: DocCast(doc.emptyDiagram)},
- { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, clickFactory: DocCast(doc.emptyAudio), openFactoryLocation: OpenWhere.overlay},
- { toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, clickFactory: DocCast(doc.emptyMap)},
- { toolTip: "Tap or drag to create a chat assistant", title: "Assistant Chat", icon: "book",dragFactory: doc.emptyChat as Doc, clickFactory: DocCast(doc.emptyChat)},
- { toolTip: "Tap or drag to create a screen grabber", title: "Grab", icon: "photo-video", dragFactory: doc.emptyScreengrab as Doc, clickFactory: DocCast(doc.emptyScreengrab), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}},
- { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc, clickFactory: DocCast(doc.emptyWebCam), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}},
- { toolTip: "Tap or drag to create a button", title: "Button", icon: "circle", dragFactory: doc.emptyButton as Doc, clickFactory: DocCast(doc.emptyButton)},
- { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, clickFactory: DocCast(doc.emptyScript), funcs: { hidden: "IsNoviceMode()"}},
- { toolTip: "Tap or drag to create a data viz node", title: "DataViz", icon: "chart-bar", dragFactory: doc.emptyDataViz as Doc, clickFactory: DocCast(doc.emptyDataViz)},
- { toolTip: "Tap or drag to create a journal entry", title: "Journal", icon: "book", dragFactory: doc.emptyDailyJournal as Doc,clickFactory:DocCast(doc.emptyDataJournal), },
- { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "person-chalkboard", dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay,funcs: { hidden: "IsNoviceMode()"}},
- { toolTip: "Tap or drag to create a view slide", title: "View Slide", icon: "address-card", dragFactory: doc.emptyViewSlide as Doc, clickFactory: DocCast(doc.emptyViewSlide), openFactoryLocation: OpenWhere.overlay,funcs: { hidden: "IsNoviceMode()"}},
- { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize", dragFactory: doc.emptyHeader as Doc, clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true, funcs: { hidden: "IsNoviceMode()"} },
- { toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '<ScriptingRepl />' as unknown as Doc, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script
+ { toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, clickFactory: DocCast(doc.emptyNote)},
+ { toolTip: "Tap or drag to create a flashcard", title: "Flashcard", icon: "id-card", dragFactory: doc.emptyFlashcard as Doc, clickFactory: DocCast(doc.emptyFlashcard)},
+ { toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, clickFactory: DocCast(doc.emptyEquation)},
+ { toolTip: "Tap or drag to create a mermaid node", title: "Mermaids", icon: "rocket", dragFactory: doc.emptyMermaids as Doc, clickFactory: DocCast(doc.emptyMermaids)},
+ { toolTip: "Tap or drag to create a plotly node", title: "Plotly", icon: "rocket", dragFactory: doc.emptyPlotly as Doc, clickFactory: DocCast(doc.emptyMermaids)},
+ { toolTip: "Tap or drag to create a note board", title: "Notes", icon: "book", dragFactory: doc.emptyNoteboard as Doc, clickFactory: DocCast(doc.emptyNoteboard)},
+ { toolTip: "Tap or drag to create an image", title: "Image", icon: "image", dragFactory: doc.emptyImage as Doc, clickFactory: DocCast(doc.emptyImage)},
+ { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab)},
+ { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, clickFactory: DocCast(doc.emptyWebpage)},
+ { toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, clickFactory: DocCast(doc.emptyComparison)},
+ { toolTip: "Tap or drag to create a diagram", title: "Diagram", icon: "tree", dragFactory: doc.emptyDiagram as Doc, clickFactory: DocCast(doc.emptyDiagram)},
+ { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, clickFactory: DocCast(doc.emptyAudio), openFactoryLocation: OpenWhere.overlay},
+ { toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, clickFactory: DocCast(doc.emptyMap)},
+ { toolTip: "Tap or drag to create a chat assistant", title: "Chat Assist", icon: "book", dragFactory: doc.emptyChat as Doc, clickFactory: DocCast(doc.emptyChat)},
+ { toolTip: "Tap or drag to create a screen grabber", title: "Grab", icon: "photo-video", dragFactory: doc.emptyScreengrab as Doc, clickFactory: DocCast(doc.emptyScreengrab), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}},
+ { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc, clickFactory: DocCast(doc.emptyWebCam), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}},
+ { toolTip: "Tap or drag to create a button", title: "Button", icon: "circle", dragFactory: doc.emptyButton as Doc, clickFactory: DocCast(doc.emptyButton)},
+ { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, clickFactory: DocCast(doc.emptyScript), funcs: { hidden: "IsNoviceMode()"}},
+ { toolTip: "Tap or drag to create a data viz node", title: "DataViz", icon: "chart-bar", dragFactory: doc.emptyDataViz as Doc, clickFactory: DocCast(doc.emptyDataViz)},
+ { toolTip: "Tap or drag to create a scrapbook template", title: "Scrapbook", icon: "palette", dragFactory: doc.emptyScrapbook as Doc,clickFactory:DocCast(doc.emptyScrapbook), },
+ { toolTip: "Tap or drag to create a journal entry", title: "Journal", icon: "book", dragFactory:doc.emptyDailyJournal as Doc,clickFactory: DocCast(doc.emptyDataJournal), },
+ { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon:"person-chalkboard",dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}},
+ { toolTip: "Tap or drag to create a view slide", title: "View Slide", icon: "address-card", dragFactory: doc.emptyViewSlide as Doc, clickFactory: DocCast(doc.emptyViewSlide), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}},
+ { toolTip: "Tap or drag to create a data note", title: "MetaNote", icon: "window-maximize", dragFactory: doc.emptyMetaNote as Doc, clickFactory: DocCast(doc.emptyMetaNote), openFactoryAsDelegate: true, funcs: { hidden: "IsNoviceMode()"} },
+ { toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '<ScriptingRepl />' as unknown as Doc, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script
].map(tuple => (
{ openFactoryLocation: OpenWhere.addRight,
scripts: { onClick: 'openDoc(copyDragFactory(this.clickFactory,this.openFactoryAsDelegate), this.openFactoryLocation)',
onDragStart: '{ return copyDragFactory(this.dragFactory,this.openFactoryAsDelegate); }'},
funcs: tuple.funcs,
- ...tuple, }))
+ ...tuple, }));
}
/// Initalizes the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools
@@ -481,22 +490,24 @@ pie title Minerals in my tap water
const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(this.target?.data).filter(doc => !docList(this.target.viewed).includes(doc)).length.toString())";
const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails";
return [
- { title: "Dashboards", toolTip: "Dashboards", target: this.setupDashboards(doc, "myDashboards"), ignoreClick: true, icon: "desktop", funcs: {hidden: "IsNoviceMode()"} },
- { title: "Search", toolTip: "Search ⌘F", target: this.setupSearcher(doc, "mySearcher"), ignoreClick: true, icon: "search", },
- { title: "Files", toolTip: "Files", target: this.setupFilesystem(doc, "myFilesystem"), ignoreClick: true, icon: "folder-open", },
- { title: "Tools", toolTip: "Tools", target: this.setupToolsBtnPanel(doc, "myTools"), ignoreClick: true, icon: "wrench", },
- { title: "Imports", toolTip: "Imports ⌘I", target: this.setupImportSidebar(doc, "myImports"), ignoreClick:false, icon: "upload", },
- { title: "Closed", toolTip: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), ignoreClick: true, icon: "archive", hidden: true }, // this doc is hidden from the Sidebar, but it's still being used in MyFilesystem which ignores the hidden field
- { title: "Shared", toolTip: "Shared Docs", target: Doc.MySharedDocs, ignoreClick: true, icon: "users", funcs: {badgeValue: badgeValue}},
- { title: "Trails", toolTip: "Trails ⌘R", target: Doc.UserDoc(), ignoreClick: true, icon: "pres-trail", funcs: {target: getActiveDashTrails}},
- { title: "Image Grouper", toolTip: "Image Grouper", target: this.setupImageGrouper(doc, "myImageGrouper"), ignoreClick: true, icon: "folder-open", hidden: false },
- { title: "Faces", toolTip: "Unique Faces", target: this.setupFaceCollection(doc, "myFaceCollection"), ignoreClick: true, icon: "face-smile", hidden: false },
- { title: "User Doc", toolTip: "User Doc", target: this.setupUserDocView(doc, "myUserDocView"), ignoreClick: true, icon: "address-card",funcs: {hidden: "IsNoviceMode()"} },
+ { title: "Dashboards", toolTip: "Dashboards", target: this.setupDashboards(doc, "myDashboards"), icon: "desktop", funcs: {hidden: "IsNoviceMode()"} },
+ { title: "Search", toolTip: "Search ⌘F", target: this.setupSearcher(doc, "mySearcher"), icon: "search", },
+ { title: "Files", toolTip: "Files", target: this.setupFilesystem(doc, "myFilesystem"), icon: "folder-open", },
+ { title: "Tools", toolTip: "Tools", target: this.setupToolsBtnPanel(doc, "myTools"), icon: "wrench", },
+ { title: "Imports", toolTip: "Imports ⌘I", target: this.setupImportSidebar(doc, "myImports"), icon: "upload", },
+ { title: "Closed", toolTip: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), icon: "archive", hidden: true }, // this doc is hidden from the Sidebar, but it's still being used in MyFilesystem which ignores the hidden field
+ { title: "Shared", toolTip: "Shared Docs", target: Doc.MySharedDocs??Doc.UserDoc(), icon: "users", funcs: {badgeValue: badgeValue}},
+ { title: "Trails", toolTip: "Trails ⌘R", target: Doc.UserDoc(), icon: "pres-trail", funcs: {target: getActiveDashTrails}},
+ { title: "Image Grouper", toolTip: "Image Grouper", target: this.setupImageGrouper(doc, "myImageGrouper"), icon: "folder-open", hidden: false },
+ { title: "Faces", toolTip: "Unique Faces", target: this.setupFaceCollection(doc, "myFaceCollection"), icon: "face-smile", hidden: false },
+ { title: "User Doc", toolTip: "User Doc", target: this.setupUserDocView(doc, "myUserDocView"), icon: "address-card",funcs: {hidden: "IsNoviceMode()"} },
].map(tuple => ({...tuple, scripts:{onClick: 'selectMainMenu(this)'}}));
}
/// the empty panel that is filled with whichever left menu button's panel has been selected
static setupLeftSidebarPanel(doc: Doc, field="myLeftSidebarPanel") {
+ const panel = DocCast(doc[field]);
+ if (panel) panel.proto = undefined;
DocUtils.AssignDocField(doc, field, (opts) => Doc.assign(new Doc(), opts as {[key:string]: FieldType}), {title:"leftSidebarPanel", isSystem:true, undoIgnoreFields: new List<string>(['proto'])});
}
@@ -546,7 +557,6 @@ pie title Minerals in my tap water
const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc, allTools?.length ? allTools[0]:undefined);
const userTools = allTools && allTools?.length > 1 ? allTools[1]:undefined;
const userBtns = CurrentUserUtils.setupUserDocumentCreatorButtons(doc, userTools);
- // doc.myUserBtns = new PrefetchProxy(userBtns);
const reqdToolOps:DocumentOptions = {
title: "My Tools", isSystem: true, ignoreClick: true, layout_boxShadow: "0 0",
layout_explainer: "This is a palette of documents that can be created.", _layout_dontCenter: "y",
@@ -602,7 +612,7 @@ pie title Minerals in my tap water
const myFilesystem = DocCast(doc[field]);
const newFolderOpts: DocumentOptions = {
- _forceActive: true, _dragOnlyWithinContainer: true, _embedContainer: Doc.MyFilesystem, _width: 30, _height: 30, undoIgnoreFields:new List<string>(['treeView_SortCriterion']),
+ _forceActive: true, _dragOnlyWithinContainer: true, embedContainer: Doc.MyFilesystem, _width: 30, _height: 30, undoIgnoreFields:new List<string>(['treeView_SortCriterion']),
title: "New folder", color: Colors.BLACK, btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", isSystem: true
};
const newFolderScript = { onClick: CollectionTreeView.AddTreeFunc};
@@ -653,7 +663,7 @@ pie title Minerals in my tap water
}
static linearButtonList = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.LinearDocument(docs, {
- ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, layout_boxShadow: "0 0", _forceActive: true,
+ ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, layout_boxShadow: "0 0", _forceActive: true, linearView: true,
dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
_lockedPosition: true, isSystem: true, flexDirection: "row"
})
@@ -687,7 +697,7 @@ pie title Minerals in my tap water
const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, defaultDoubleClick: 'ignore', undoIgnoreFields: new List<string>(['opacity']), _dragOnlyWithinContainer: true, ...desc.opts}, desc.scripts));
const dockBtnsReqdOpts:DocumentOptions = {
title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDragAction: dropActionType.move,
- childDontRegisterViews: true, linearView_IsOpen: true, linearView_Expandable: true, ignoreClick: true
+ childDontRegisterViews: true, linearView_isOpen: true, linearView_expandable: true, ignoreClick: true
};
reaction(() => UndoManager.redoStack.slice(), () => { Doc.GetProto(btns.find(btn => btn.title === "Redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4; }, { fireImmediately: true });
reaction(() => UndoManager.undoStack.slice(), () => { Doc.GetProto(btns.find(btn => btn.title === "Undo")!).opacity = UndoManager.CanUndo() ? 1 : 0.4; }, { fireImmediately: true });
@@ -737,12 +747,12 @@ pie title Minerals in my tap water
}
static viewTools(): Button[] {
return [
- { title: "Tags", icon: "id-card", toolTip: "Toggle Tags display", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"toggle-tags",funcs: { }, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} },
- { title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"snaplines", funcs: { hidden: `!SelectedDocType("${CollectionViewType.Freeform}", this.expertMode)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
- { title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"grid", funcs: { hidden: `!SelectedDocType("${CollectionViewType.Freeform}", this.expertMode)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
- { title: "Fit All", icon: "object-group", toolTip:"Fit Docs to View (double tap to persist)",
- btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"viewAll", funcs: { hidden: `!SelectedDocType("${CollectionViewType.Freeform}", this.expertMode)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}', onDoubleClick: '{ return showFreeform(this.toolType, _readOnly_, true);}'}}, // Only when floating document is selected in freeform
- { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"clusters", funcs: { hidden: `!SelectedDocType("${CollectionViewType.Freeform}", this.expertMode)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+ { title: "Tags", icon: "id-card", toolTip: "Toggle Tags display", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"toggle-tags",funcs: { }, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} },
+ { title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"snaplines", funcs: { hidden: `!SelectedDocType("${CollectionViewType.Freeform}", this.expertMode)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+ { title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"grid", funcs: { hidden: `!SelectedDocType("${CollectionViewType.Freeform}", this.expertMode)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
+ { title: "Fit All", icon: "object-group", toolTip:"Fit Docs to View (double tap to persist)",
+ btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"viewAll", funcs: { hidden: `!SelectedDocType("${CollectionViewType.Freeform}", this.expertMode)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}', onDoubleClick: '{ return showFreeform(this.toolType, _readOnly_, true);}'}}, // Only when floating document is selected in freeform
+ { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"clusters", funcs: { hidden: `!SelectedDocType("${CollectionViewType.Freeform}", this.expertMode)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform
]
}
static textTools():Button[] {
@@ -760,14 +770,14 @@ pie title Minerals in my tap water
{ title: "Vcenter", toolTip: "Vertical center", btnType: ButtonType.ToggleButton, icon: "pallet", toolType:"vcent", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
{ title: "Align", toolTip: "Alignment", btnType: ButtonType.MultiToggleButton, toolType:"alignment",ignoreClick: true,
subMenu: [
- { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
- { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
- { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
+ { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
+ { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
+ { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
]},
- { title: "Fit Box", toolTip: "Fit text to box", btnType: ButtonType.ToggleButton, icon: "object-group",toolType:"fitBox", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
- { title: "Elide", toolTip: "Elide selection", btnType: ButtonType.ToggleButton, icon: "eye", toolType:"elide", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
- { title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
- { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", toolType:"noAutoLink", expertMode:true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}},
+ { title: "Fit Box", toolTip: "Fit text to box", btnType: ButtonType.ToggleButton, icon: "object-group",toolType:"fitBox", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
+ { title: "Elide", toolTip: "Elide selection", btnType: ButtonType.ToggleButton, icon: "eye", toolType:"elide", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
+ { title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} },
+ { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", toolType:"noAutoLink",expertMode: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}},
// { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", scripts: {onClick:: 'toggleStrikethrough()'}},
// { title: "Superscript", tooltip: "Superscript", btnType: ButtonType.ToggleButton, icon: "superscript", scripts: {onClick:: 'toggleSuperscript()'}},
// { title: "Subscript", tooltip: "Subscript", btnType: ButtonType.ToggleButton, icon: "subscript", scripts: {onClick:: 'toggleSubscript()'}},
@@ -779,24 +789,24 @@ pie title Minerals in my tap water
{ title: "Circle", toolTip: "Circle (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "circle", toolType: Gestures.Circle, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} },
{ title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square", toolType: Gestures.Rectangle, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} },
{ title: "Line", toolTip: "Line (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "minus", toolType: Gestures.Line, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} },
- { title: "Ink", toolTip: "Ink", btnType: ButtonType.MultiToggleButton, toolType: InkTool.Ink, scripts: {onClick:'{ return setActiveTool(this.toolType, true, _readOnly_);}' },
+ { title: "Ink", toolTip: "Ink", btnType: ButtonType.MultiToggleButton, toolType: InkTool.Ink, showUntilToggle: true, scripts: {onClick:'{ return setActiveTool(this.toolType, true, _readOnly_);}' },
subMenu: [
{ title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", toolType: InkInkTool.Pen, ignoreClick: true, scripts: {onClick:'{ return setActiveTool(this.toolType, true, _readOnly_);}' }},
{ title: "Highlight",toolTip: "Highlight (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", toolType: InkInkTool.Highlight, ignoreClick: true, scripts: {onClick:'{ return setActiveTool(this.toolType, true, _readOnly_);}' }},
{ title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", toolType: InkInkTool.Write, ignoreClick: true, scripts: {onClick:'{ return setActiveTool(this.toolType, true, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }},
]},
- { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberSliderButton, toolType: InkProperty.StrokeWidth,ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"!activeInkTool()"}, numBtnMin: 1, linearBtnWidth:40},
+ { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberSliderButton, toolType: InkProperty.StrokeWidth,ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"!activeInkTool()"}, numBtnMin: 1, linearView_btnWidth:40},
{ title: "Color", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", toolType: InkProperty.StrokeColor,ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"!activeInkTool()"}},
- { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.MultiToggleButton, toolType: InkTool.Eraser, scripts: {onClick:'{ return setActiveTool(this.toolType, false, _readOnly_);}' },
+ { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.MultiToggleButton, toolType: InkTool.Eraser, showUntilToggle: true, scripts: {onClick:'{ return setActiveTool(this.toolType, false, _readOnly_);}' },
subMenu: [
{ title: "Stroke", toolTip: "Eraser complete strokes",btnType: ButtonType.ToggleButton, icon: "eraser", toolType:InkEraserTool.Stroke, ignoreClick: true, scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'}},
{ title: "Segment", toolTip: "Erase between intersections",btnType:ButtonType.ToggleButton,icon:"xmark", toolType:InkEraserTool.Segment, ignoreClick: true, scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'}},
{ title: "Area", toolTip: "Erase like a pencil", btnType: ButtonType.ToggleButton, icon: "circle-xmark",toolType:InkEraserTool.Radius, ignoreClick: true, scripts: {onClick: '{ return setActiveTool(this.toolType, false, _readOnly_);}'}},
]},
- { title: " Size", toolTip: "Size of area pencil eraser", btnType: ButtonType.NumberSliderButton, toolType: InkProperty.EraserWidth,ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"NotRadiusEraser()"}, numBtnMin: 1, linearBtnWidth:40},
+ { title: " Size", toolTip: "Size of area pencil eraser", btnType: ButtonType.NumberSliderButton, toolType: InkProperty.EraserWidth,ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"NotRadiusEraser()"}, numBtnMin: 1, linearView_btnWidth:40},
{ title: "Mask", toolTip: "Make Stroke a Stencil Mask", btnType: ButtonType.ToggleButton, icon: "user-circle", toolType: InkProperty.Mask, scripts: {onClick:'{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"IsNoviceMode()" } },
{ title: "Labels", toolTip: "Show Labels Inside Shapes", btnType: ButtonType.ToggleButton, icon: "text-width", toolType: InkProperty.Labels, scripts: {onClick:'{ return setInkProperty(this.toolType, value, _readOnly_);}'}},
- { title: "Smart Draw", toolTip: "Draw with AI", btnType: ButtonType.ToggleButton, icon: "user-pen", toolType: InkTool.SmartDraw, scripts: {onClick:'{ return setActiveTool(this.toolType, false, _readOnly_);}'}, funcs: {hidden: "IsNoviceMode()"}},
+ { title: "Smart Draw", toolTip: "Draw with AI", btnType: ButtonType.ToggleButton, icon: "user-pen", toolType: InkTool.SmartDraw, scripts: {onClick:'{ return setActiveTool(this.toolType, false, _readOnly_);}'}, funcs: {hidden: "IsNoviceMode()"}},
];
}
@@ -825,36 +835,34 @@ pie title Minerals in my tap water
{ title: "Rotate",toolTip: "Rotate 90", btnType: ButtonType.ClickButton, icon: "redo-alt", scripts: { onClick: 'imageRotate90();' }},
];
}
- static contextMenuTools(doc:Doc):Button[] {
+ static contextMenuTools():Button[] {
return [
- { btnList: new List<string>([CollectionViewType.Freeform, CollectionViewType.Card, CollectionViewType.Carousel,CollectionViewType.Carousel3D,
- CollectionViewType.Masonry, CollectionViewType.Multicolumn, CollectionViewType.Multirow, CollectionViewType.Linear,
- CollectionViewType.Map, CollectionViewType.NoteTaking, CollectionViewType.Pivot, CollectionViewType.Schema, CollectionViewType.Stacking,
- CollectionViewType.Calendar, CollectionViewType.Grid, CollectionViewType.Tree, CollectionViewType.Time, ]),
- title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: '{ return setView(value, shiftKey, _readOnly_); }'}},
+ { title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, expertMode: false, btnList: new List<string>(standardViewTypes), ignoreClick: true, width: 100, scripts: { script: '{ return setView(value, shiftKey, _readOnly_); }'}},
{ title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, expertMode: false, width: 30, scripts: { onClick: 'pinWithView(altKey)'}, funcs: {hidden: "IsNoneSelected()"}},
{ title: "Header", icon: "heading", toolTip: "Doc Titlebar Color", btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'} },
{ title: "Template",icon: "scroll", toolTip: "Default Note Template",btnType: ButtonType.ToggleButton, expertMode: false, toolType:DocumentType.RTF, scripts: { onClick: '{ return setDefaultTemplate(_readOnly_); }'} },
+ { title: "Img Temp",icon: "portrait", toolTip: "Default Image Template",btnType:ButtonType.ToggleButton, expertMode: false, toolType:DocumentType.IMG, scripts: { onClick: '{ return setDefaultImageTemplate(_readOnly_); }'} },
{ title: "Fill", icon: "fill-drip", toolTip: "Fill/Background Color",btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, width: 30, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'} }, // Only when a document is selected
- { title: "Border", icon: "pen", toolTip: "Border Color", btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, width: 30, scripts: { script: 'return setBorderColor(value, _readOnly_)'} }, // Only when a document is selected
- { title: "B.Width", toolTip: "Border width", btnType: ButtonType.NumberSliderButton, ignoreClick: true, scripts: {script: '{ return setBorderWidth(value, _readOnly_);}'}, numBtnMin: 0, linearBtnWidth:40},
+ { title: "Border", icon: "border-style", toolTip: "Border Color", btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, width: 30, scripts: { script: 'return setBorderColor(value, _readOnly_)'} }, // Only when a document is selected
+ { title: "B.Width", toolTip: "Border width", btnType: ButtonType.NumberSliderButton, ignoreClick: true, scripts: {script: '{ return setBorderWidth(value, _readOnly_);}'}, numBtnMin: 0, linearView_btnWidth:40},
{ title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode, true)'}, scripts: { onClick: '{ return toggleOverlay(_readOnly_); }'}}, // Only when floating document is selected in freeform
{ title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}},
{ title: "Num", icon:"", toolTip: "Frame # (click to toggle edit mode)",btnType: ButtonType.TextButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}},
{ title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
{ title: "Chat", icon: "lightbulb", toolTip: "Toggle Chat Assistant",btnType: ButtonType.ToggleButton, expertMode: false, toolType:"toggle-chat", funcs: {}, width: 30, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} },
- { title: "Filter", icon: "=", toolTip: "Filter cards by tags", subMenu: CurrentUserUtils.filterTools(), ignoreClick:true, toolType:DocumentType.COL, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, btnType: ButtonType.MultiToggleButton, width: 30, backgroundColor: doc.userVariantColor as string},
- { title: "Sort", icon: "Sort", toolTip: "Sort Documents", subMenu: CurrentUserUtils.sortTools(), expertMode: false, toolType:DocumentType.COL, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
- { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
- { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: {hidden: `IsExploreMode()`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
- { title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode, true)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
- { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:DocumentType.COL, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
- { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
-
- { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected
- { title: "Video", icon: "Video", toolTip: "Video functions", subMenu: CurrentUserUtils.videoTools(), expertMode: false, toolType:DocumentType.VID, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when video is selected
- { title: "Image", icon: "Image", toolTip: "Image functions", subMenu: CurrentUserUtils.imageTools(), expertMode: false, toolType:DocumentType.IMG, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when image is selected
- { title: "Schema", icon: "Schema", toolTip: "Schema functions", subMenu: CurrentUserUtils.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`}, linearBtnWidth:58 }, // Only when Schema is selected
+ { title: "Filter", icon: "=", toolTip: "Filter cards by tags", btnType: ButtonType.MultiToggleButton,
+ subMenu: this.filterTools(), expertMode: false, toolType:DocumentType.COL, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'},ignoreClick:true, width: 30},
+ { title: "Sort", icon: "Sort", toolTip: "Sort Documents", subMenu: this.sortTools(), expertMode: false, toolType:DocumentType.COL, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_isOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
+ { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: this.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_isOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
+ { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: this.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: {hidden: `IsExploreMode()`, linearView_isOpen: `SelectedDocType(this.toolType, this.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
+ { title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: this.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode, true)`, linearView_isOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
+ { title: "View", icon: "View", toolTip: "View tools", subMenu: this.viewTools(), expertMode: false, toolType:DocumentType.COL, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_isOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
+ { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: this.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_isOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
+
+ { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: this.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_isOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected
+ { title: "Video", icon: "Video", toolTip: "Video functions", subMenu: this.videoTools(), expertMode: false, toolType:DocumentType.VID, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_isOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when video is selected
+ { title: "Image", icon: "Image", toolTip: "Image functions", subMenu: this.imageTools(), expertMode: false, toolType:DocumentType.IMG, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_isOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when image is selected
+ { title: "Schema", icon: "Schema", toolTip: "Schema functions", subMenu: this.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_isOpen: `SelectedDocType(this.toolType, this.expertMode)`}, linearView_btnWidth:58 }, // Only when Schema is selected
];
}
@@ -865,10 +873,10 @@ pie title Minerals in my tap water
...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit,
color: Colors.WHITE,
_nativeWidth: params.width ?? 30, _width: params.width ?? 30,
- _height: 30, _nativeHeight: 30, linearBtnWidth: params.linearBtnWidth,
+ _height: 30, _nativeHeight: 30, linearView_btnWidth: params.linearView_btnWidth,
toolType: params.toolType, expertMode: params.expertMode,
_dragOnlyWithinContainer: true, _lockedPosition: true,
- _embedContainer: btnContainer
+ embedContainer: btnContainer
};
const reqdFuncs:{[key:string]:string} = {
...params.funcs,
@@ -884,9 +892,9 @@ pie title Minerals in my tap water
return this.setupContextMenuButton(params, menuBtnDoc, menuDoc);
}
// linear view
- const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, undoIgnoreFields: new List<string>(['width', "linearView_IsOpen"]),
+ const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, undoIgnoreFields: new List<string>(['width', "linearView_isOpen"]),
childDontRegisterViews: true, flexGap: 0, _height: 30, _width: 30, ignoreClick: !params.scripts?.onClick,
- linearView_SubMenu: true, linearView_Expandable: true, embedContainer: menuDoc};
+ linearView_expandable: true, embedContainer: menuDoc};
const items = (menuBtn?:Doc) => !menuBtn ? [] : subMenu.map(sub => this.setupContextMenuBtn(sub, menuBtn) );
const creator = params.btnType === ButtonType.MultiToggleButton ? this.multiToggleList : this.linearButtonList;
@@ -898,9 +906,9 @@ pie title Minerals in my tap water
/// Initializes all the default buttons for the top bar context menu
static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") {
- const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", undoIgnoreFields:new List<string>(['width', "linearView_IsOpen"]), flexGap: 0, childDragAction: dropActionType.embed, childDontRegisterViews: true, linearView_IsOpen: true, ignoreClick: true, linearView_Expandable: false, _height: 35 };
+ const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", undoIgnoreFields:new List<string>(['width', "linearView_isOpen"]), flexGap: 0, childDragAction: dropActionType.embed, childDontRegisterViews: true, linearView_isOpen: true, ignoreClick: true, linearView_expandable: false, _height: 35 };
const ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined);
- const ctxtMenuBtns = CurrentUserUtils.contextMenuTools(doc).map(params => this.setupContextMenuBtn(params, ctxtMenuBtnsDoc) );
+ const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => this.setupContextMenuBtn(params, ctxtMenuBtnsDoc) );
return DocUtils.AssignOpts(ctxtMenuBtnsDoc, reqdCtxtOpts, ctxtMenuBtns);
}
/// Initializes all the default buttons for the top bar context menu
@@ -925,7 +933,7 @@ pie title Minerals in my tap water
const btns = btnDescs.map(desc => dockBtn({_width: desc.opts.width??30, _height: 30, defaultDoubleClick: 'ignore', undoIgnoreFields: new List<string>(['opacity']), _dragOnlyWithinContainer: true, ...desc.opts}, desc.scripts, desc.funcs));
const dockBtnsReqdOpts:DocumentOptions = {
title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDragAction: dropActionType.move,
- childDontRegisterViews: true, linearView_IsOpen: true, linearView_Expandable: false, ignoreClick: true
+ childDontRegisterViews: true, linearView_isOpen: true, linearView_expandable: false, ignoreClick: true
};
return DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), dockBtnsReqdOpts, btns);
}
@@ -973,7 +981,10 @@ pie title Minerals in my tap water
};
DocUtils.AssignDocField(doc, "mySharedDocs", opts => Docs.Create.TreeDocument([], opts, sharingDocumentId + "layout", sharingDocumentId), sharedDocOpts, undefined, sharedScripts);
- if (!Doc.GetProto(DocCast(doc.mySharedDocs)).data_dashboards) Doc.GetProto(DocCast(doc.mySharedDocs)).data_dashboards = new List<Doc>();
+ const sharedDocs = DocCast(doc.mySharedDocs);
+ if (sharedDocs) {
+ if (!Doc.GetProto(sharedDocs).data_dashboards) Doc.GetProto(sharedDocs).data_dashboards = new List<Doc>();
+ }
}
/// Import option on the left side button panel
@@ -998,9 +1009,9 @@ pie title Minerals in my tap water
static updateUserDocument(docIn: Doc, sharingDocumentId: string, linkDatabaseId: string) {
const doc = docIn;
DocUtils.AssignDocField(doc, "globalGroupDatabase", () => Docs.Prototypes.MainGroupDocument(), {});
- reaction(() => DateCast(DocCast(doc.globalGroupDatabase).data_modificationDate),
+ reaction(() => DateCast(DocCast(doc.globalGroupDatabase)?.data_modificationDate),
async () => {
- const groups = await DocListCastAsync(DocCast(doc.globalGroupDatabase).data);
+ const groups = await DocListCastAsync(DocCast(doc.globalGroupDatabase)?.data);
const mygroups = groups?.filter(group => JSON.parse(StrCast(group.members)).includes(ClientUtils.CurrentUserEmail())) || [];
SetCachedGroups(["Guest", ...(mygroups?.map(g => StrCast(g.title))??[])]);
}, { fireImmediately: true });
@@ -1056,11 +1067,13 @@ pie title Minerals in my tap water
SelectionManager.DeselectAll(); // this forces SelectionManager implementation to copy over to DocumentView's API. This also triggers the LinkManager to be created
- Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards);
- Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs);
- Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyRecentlyClosed);
+ if (Doc.MyFilesystem) {
+ Doc.MyDashboards && Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards);
+ Doc.MyDashboards && Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards);
+ Doc.MyRecentlyClosed && Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyRecentlyClosed);
+ }
- Doc.GetProto(DocCast(Doc.UserDoc().emptyWebpage)).data = new WebField("https://www.wikipedia.org");
+ DocCast(Doc.UserDoc().emptyWebpage) && (Doc.GetProto(DocCast(Doc.UserDoc().emptyWebpage)!).data = new WebField("https://wikipedia.org"));
DocServer.CacheNeedsUpdate() && setTimeout(UPDATE_SERVER_CACHE, 2500);
setInterval(UPDATE_SERVER_CACHE, 120000);
@@ -1140,7 +1153,7 @@ pie title Minerals in my tap water
const file = input.files?.[0];
if (file?.type === 'application/zip' || file?.type === 'application/x-zip-compressed') {
const doc = await Doc.importDocument(file);
- const list = Cast(Doc.MyImports.data, listSpec(Doc), null);
+ const list = Cast(Doc.MyImports?.data, listSpec(Doc), null);
doc instanceof Doc && list?.splice(0, 0, doc);
} else if (input.files && input.files.length !== 0) {
const disposer = OverlayView.ShowSpinner();
@@ -1148,7 +1161,7 @@ pie title Minerals in my tap water
if (results.length !== input.files?.length) {
alert("Error uploading files - possibly due to unsupported file types");
}
- const list = Cast(Doc.MyImports.data, listSpec(Doc), null);
+ const list = Cast(Doc.MyImports?.data, listSpec(Doc), null);
list?.splice(0, 0, ...results);
disposer();
} else {
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 897366757..dcef4a4fe 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -2,7 +2,6 @@
import * as interpreter from 'words-to-numbers';
import { ClientUtils } from '../../ClientUtils';
import { Doc, Opt } from '../../fields/Doc';
-import { DocData } from '../../fields/DocSymbols';
import { List } from '../../fields/List';
import { RichTextField } from '../../fields/RichTextField';
import { listSpec } from '../../fields/Schema';
@@ -339,13 +338,12 @@ export namespace DictationManager {
{
action: (target: DocumentView) => {
const newBox = Docs.Create.TextDocument('', { _width: 400, _height: 200, title: 'My Outline', _layout_autoHeight: true });
- const proto = newBox[DocData];
const prompt = 'Press alt + r to start dictating here...';
const head = 3;
const anchor = head + prompt.length;
const proseMirrorState = `{"doc":{"type":"doc","content":[{"type":"ordered_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"${prompt}"}]}]}]}]},"selection":{"type":"text","anchor":${anchor},"head":${head}}}`;
- proto.data = new RichTextField(proseMirrorState, prompt);
- proto.backgroundColor = '#eeffff';
+ newBox.$data = new RichTextField(proseMirrorState, prompt);
+ newBox.$backgroundColor = '#eeffff';
target.props.addDocTab(newBox, OpenWhere.addRight);
},
},
@@ -358,23 +356,16 @@ export namespace DictationManager {
action: (target: DocumentView, matches: RegExpExecArray) => {
const count = interpretNumber(matches[1]);
const what = matches[2];
- const dataDoc = Doc.GetProto(target.Document);
- const fieldKey = 'data';
- if (isNaN(count)) {
- return;
- }
- for (let i = 0; i < count; i++) {
- let created: Doc | undefined;
- switch (what) {
- case 'image':
- created = Docs.Create.ImageDocument('https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg');
- break;
- case 'nested collection':
- created = Docs.Create.FreeformDocument([], {});
- break;
- default:
+ if (!isNaN(count)) {
+ for (let i = 0; i < count; i++) {
+ const created = (() => {
+ switch (what) {
+ case 'image': return Docs.Create.ImageDocument('https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg');
+ case 'nested collection':return Docs.Create.FreeformDocument([], {});
+ } // prettier-ignore
+ })();
+ created && Doc.AddDocToList(target.dataDoc, Doc.LayoutDataKey(target.Document), created);
}
- created && Doc.AddDocToList(dataDoc, fieldKey, created);
}
},
restrictTo: [DocumentType.COL],
@@ -390,13 +381,15 @@ export namespace DictationManager {
},
];
}
- export function recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) {
+ export function recordAudioAnnotation(doc: Doc, fieldIn: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) {
+ const field = '$' + fieldIn + '_audioAnnotations';
let gumStream: MediaStream | undefined;
let recorder: MediaRecorder | undefined;
navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {
- let audioTextAnnos = Cast(dataDoc[field + '_audioAnnotations_text'], listSpec('string'), null);
+ let audioTextAnnos = Cast(doc[field + '_text'], listSpec('string'), null);
if (audioTextAnnos) audioTextAnnos.push('');
- else audioTextAnnos = dataDoc[field + '_audioAnnotations_text'] = new List<string>(['']);
+ else audioTextAnnos = doc[field + '_text'] = new List<string>(['']);
+ doc._layout_showTags = true;
DictationManager.Controls.listen({
interimHandler: value => { audioTextAnnos[audioTextAnnos.length - 1] = value; }, // prettier-ignore
continuous: { indefinite: false },
@@ -417,16 +410,16 @@ export namespace DictationManager {
const [{ result }] = await Networking.UploadFilesToServer({ file: file as Blob & { name: string; lastModified: number; webkitRelativePath: string } });
if (!(result instanceof Error)) {
const audioField = new AudioField(result.accessPaths.agnostic.client);
- const audioAnnos = Cast(dataDoc[field + '_audioAnnotations'], listSpec(AudioField), null);
+ const audioAnnos = Cast(doc[field], listSpec(AudioField), null);
if (audioAnnos) audioAnnos.push(audioField);
- else dataDoc[field + '_audioAnnotations'] = new List([audioField]);
+ else doc[field] = new List([audioField]);
}
};
recorder.start();
const stopFunc = () => {
recorder?.stop();
DictationManager.Controls.stop(/* false */);
- dataDoc.audioAnnoState = AudioAnnoState.stopped;
+ doc._audioAnnoState = AudioAnnoState.stopped;
gumStream?.getAudioTracks()[0].stop();
};
if (onRecording) onRecording(stopFunc);
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index e33449782..fc8f22cf3 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -2,7 +2,6 @@ import { Howl } from 'howler';
import { action, computed, makeObservable, observable, ObservableSet, observe } from 'mobx';
import { Doc, Opt } from '../../fields/Doc';
import { Animation, DocData } from '../../fields/DocSymbols';
-import { Id } from '../../fields/FieldSymbols';
import { listSpec } from '../../fields/Schema';
import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types';
import { AudioField } from '../../fields/URLField';
@@ -108,16 +107,16 @@ export class DocumentManager {
});
// gets all views
- public getDocumentViewsById(id: string) {
+ public getAllDocumentViews(doc: Doc) {
const toReturn: DocumentView[] = [];
DocumentManager.Instance.DocumentViews.forEach(view => {
- if (view.Document[Id] === id) {
+ if (view.Document === doc) {
toReturn.push(view);
}
});
if (toReturn.length === 0) {
DocumentManager.Instance.DocumentViews.forEach(view => {
- if (view.Document[DocData]?.[Id] === id) {
+ if (view.Document[DocData] === doc) {
toReturn.push(view);
}
});
@@ -125,10 +124,6 @@ export class DocumentManager {
return toReturn;
}
- public getAllDocumentViews(doc: Doc) {
- return this.getDocumentViewsById(doc[Id]);
- }
-
public getDocumentView(target: Doc | undefined, preferredCollection?: DocumentView): DocumentView | undefined {
const docViewArray = DocumentManager.Instance.DocumentViews;
const passes = !target ? [] : preferredCollection ? [preferredCollection, undefined] : [undefined];
@@ -178,17 +173,17 @@ export class DocumentManager {
while (
containerDocContext.length &&
DocCast(containerDocContext[0]?.embedContainer) &&
- DocCast(containerDocContext[0].embedContainer)?._type_collection !== CollectionViewType.Docking &&
+ DocCast(containerDocContext[0].embedContainer)!._type_collection !== CollectionViewType.Docking &&
(includeExistingViews || !DocumentManager.Instance.getDocumentView(containerDocContext[0]))
) {
- containerDocContext = [Cast(containerDocContext[0].embedContainer, Doc, null), ...containerDocContext];
+ containerDocContext = [DocCast(containerDocContext[0].embedContainer)!, ...containerDocContext];
}
return containerDocContext;
}
static _howl: Howl;
static playAudioAnno(doc: Doc) {
- const anno = Cast(doc[Doc.LayoutFieldKey(doc) + '_audioAnnotations'], listSpec(AudioField), null)?.lastElement();
+ const anno = Cast(doc[Doc.LayoutDataKey(doc) + '_audioAnnotations'], listSpec(AudioField), null)?.lastElement();
if (anno) {
this._howl?.stop();
if (anno instanceof AudioField) {
@@ -253,7 +248,7 @@ export class DocumentManager {
finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done.
) => {
const options = optionsIn;
- Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, targetDoc);
+ Doc.MyRecentlyClosed && Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, targetDoc);
const docContextPath = DocumentManager.GetContextPath(targetDoc, true);
if (docContextPath.some(doc => doc.hidden)) options.toggleTarget = false;
let activatedTab = false;
@@ -277,7 +272,7 @@ export class DocumentManager {
}));
if (options.openLocation?.includes(OpenWhere.lightbox)) {
// even if we found the document view, if the target is a lightbox, we try to open it in the lightbox to preserve lightbox semantics (eg, there's only one active doc in the lightbox)
- const target = DocCast(targetDoc.annotationOn, targetDoc);
+ const target = DocCast(targetDoc.annotationOn, targetDoc)!;
const compView = this.getDocumentView(DocCast(target.embedContainer))?.ComponentView;
if ((compView?.addDocTab ?? compView?._props.addDocTab)?.(target, options.openLocation)) {
await new Promise<void>(waitres => {
@@ -354,7 +349,7 @@ export class DocumentManager {
// bcz: should this delay be an options parameter?
setTimeout(() => {
Doc.linkFollowHighlight(viewSpec ? [docView.Document, viewSpec] : docView.Document, undefined, options.effect);
- const zoomableText = StrCast(targetDoc.text_html, StrCast(targetDoc.ai_firefly_prompt));
+ const zoomableText = StrCast(targetDoc.text_html, StrCast(targetDoc.ai_prompt));
if (options.zoomTextSelections && Doc.IsUnhighlightTimerSet() && contextView && zoomableText) {
// if the docView is a text anchor, the contextView is the PDF/Web/Text doc
contextView.setTextHtmlOverlay(zoomableText, options.effect);
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 2a7859f09..a66e6998b 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -234,29 +234,27 @@ export namespace DragManager {
dropDoc instanceof Doc && CreateLinkToActiveAudio(() => dropDoc);
return dropDoc;
};
- const finishDrag = async (e: DragCompleteEvent) => {
+ const finishDrag = (e: DragCompleteEvent) => {
const { docDragData } = e;
setTimeout(() => dragData.dragEnding?.());
onDropCompleted?.(e); // glr: optional additional function to be called - in this case with presentation trails
if (docDragData && !docDragData.droppedDocuments.length) {
docDragData.dropAction = dragData.userDropAction || dragData.dropAction;
- docDragData.droppedDocuments = (
- await Promise.all(
- dragData.draggedDocuments.map(async d =>
- !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart)
- ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result as Doc)
- : docDragData.dropAction === dropActionType.embed
- ? Doc.BestEmbedding(d)
- : docDragData.dropAction === dropActionType.add
- ? d
- : docDragData.dropAction === dropActionType.proto
- ? d[DocData]
- : docDragData.dropAction === dropActionType.copy
- ? (await Doc.MakeClone(d)).clone
- : d
- )
+ docDragData.droppedDocuments = dragData.draggedDocuments
+ .map(d =>
+ !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart)
+ ? addAudioTag(ScriptCast(d.onDragStart)!.script.run({ this: d }).result as Doc)
+ : docDragData.dropAction === dropActionType.embed
+ ? Doc.BestEmbedding(d)
+ : docDragData.dropAction === dropActionType.add
+ ? d
+ : docDragData.dropAction === dropActionType.proto
+ ? d[DocData]
+ : docDragData.dropAction === dropActionType.copy
+ ? Doc.MakeClone(d).clone
+ : d
)
- ).filter(d => d);
+ .filter(d => d);
![dropActionType.same, dropActionType.proto].includes(StrCast(docDragData.dropAction) as dropActionType) &&
docDragData.droppedDocuments
// .filter(drop => !drop.dragOnlyWithinContainer || ['embed', 'copy'].includes(docDragData.dropAction as any))
@@ -280,11 +278,12 @@ export namespace DragManager {
export function StartButtonDrag(eles: HTMLElement[], script: string, title: string, vars: { [name: string]: FieldType }, params: string[], initialize: (button: Doc) => void, downX: number, downY: number, options?: DragOptions) {
const finishDrag = (e: DragCompleteEvent) => {
const bd = Docs.Create.ButtonDocument({ toolTip: title, z: 1, _width: 150, _height: 50, title, onClick: ScriptField.MakeScript(script) });
+ const bdData = bd[DocData];
params.forEach(p => {
- Object.keys(vars).indexOf(p) !== -1 && (bd[DocData][p] = new PrefetchProxy(vars[p] as Doc));
+ Object.keys(vars).indexOf(p) !== -1 && (bdData[p] = new PrefetchProxy(vars[p] as Doc));
}); // copy all "captured" arguments into document parameterfields
initialize?.(bd);
- bd[DocData]['onClick-paramFieldKeys'] = new List<string>(params);
+ bd.$onClick_paramFieldKeys = new List<string>(params);
e.docDragData && (e.docDragData.droppedDocuments = [bd]);
return e;
};
@@ -363,7 +362,7 @@ export namespace DragManager {
};
}
- async function dispatchDrag(target: Element, e: PointerEvent, complete: DragCompleteEvent, pos: { x: number; y: number }, finishDrag?: (e: DragCompleteEvent) => void, options?: DragOptions, endDrag?: () => void) {
+ function dispatchDrag(target: Element, e: PointerEvent, complete: DragCompleteEvent, pos: { x: number; y: number }, finishDrag?: (e: DragCompleteEvent) => void, options?: DragOptions, endDrag?: () => void) {
const dropArgs = {
cancelable: true, // allows preventDefault() to be called to cancel the drop
bubbles: true,
@@ -379,7 +378,7 @@ export namespace DragManager {
};
target.dispatchEvent(new CustomEvent<DropEvent>('dashPreDrop', dropArgs));
UndoManager.StartTempBatch(); // run drag/drop in temp batch in case drop is not allowed (so we can undo any intermediate changes)
- await finishDrag?.(complete);
+ finishDrag?.(complete);
UndoManager.EndTempBatch(target.dispatchEvent(new CustomEvent<DropEvent>('dashOnDrop', dropArgs))); // event return val is true unless the event preventDefault() is called
options?.dragComplete?.(complete);
endDrag?.();
@@ -565,11 +564,11 @@ export namespace DragManager {
const targClassName = e.target instanceof HTMLElement && typeof e.target.className === 'string' ? e.target.className : '';
if (['lm_tab', 'lm_title_wrap', 'lm_tabs', 'lm_header'].includes(targClassName) && docDragData.draggedDocuments.length === 1) {
if (!startWindowDragTimer) {
- startWindowDragTimer = setTimeout(async () => {
+ startWindowDragTimer = setTimeout(() => {
startWindowDragTimer = undefined;
docDragData.dropAction = docDragData.userDropAction || dropActionType.same;
AbortDrag();
- await finishDrag?.(new DragCompleteEvent(true, docDragData));
+ finishDrag?.(new DragCompleteEvent(true, docDragData));
DragManager.StartWindowDrag?.(e, docDragData.droppedDocuments, aborted => {
if (!aborted && (docDragData?.dropAction === dropActionType.move || docDragData?.dropAction === dropActionType.same)) {
docDragData.removeDocument?.(docDragData?.draggedDocuments[0]);
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index b5d29be4c..1d4779d8a 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -1,9 +1,9 @@
import { Doc, DocListCast, StrListCast } from '../../fields/Doc';
-import { DocData } from '../../fields/DocSymbols';
+import { DocData, DocLayout } from '../../fields/DocSymbols';
import { ObjectField } from '../../fields/ObjectField';
import { RichTextField } from '../../fields/RichTextField';
import { ComputedField, ScriptField } from '../../fields/ScriptField';
-import { StrCast } from '../../fields/Types';
+import { DocCast, StrCast } from '../../fields/Types';
import { ImageField } from '../../fields/URLField';
import { Docs, DocumentOptions } from '../documents/Documents';
import { DocumentType } from '../documents/DocumentTypes';
@@ -23,7 +23,7 @@ import { ScriptingGlobals } from './ScriptingGlobals';
*/
function makeTemplate(doc: Doc, first: boolean = true): boolean {
const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc;
- if (layoutDoc.layout instanceof Doc) {
+ if (DocCast(layoutDoc.layout)) {
return true; // its already a template
}
const layout = StrCast(layoutDoc.layout).match(/fieldKey={'[^']*'}/)?.[0];
@@ -41,7 +41,7 @@ function makeTemplate(doc: Doc, first: boolean = true): boolean {
if (first && !docs.length) {
// bcz: feels hacky : if the root level document has items, it's not a field template
isTemplate = Doc.MakeMetadataFieldTemplate(doc, layoutDoc[DocData], true) || isTemplate;
- } else if (docData instanceof RichTextField || docData instanceof ImageField) {
+ } else if (docData instanceof RichTextField || docData instanceof ImageField || (docData === undefined && doc.type === DocumentType.IMG)) {
if (!StrCast(layoutDoc.title).startsWith('-')) {
isTemplate = Doc.MakeMetadataFieldTemplate(layoutDoc, layoutDoc[DocData], true);
}
@@ -68,7 +68,7 @@ export function MakeTemplate(doc: Doc) {
* Makes a draggable button or image that will create a template doc Instance
*/
export function makeUserTemplateButtonOrImage(doc: Doc, image?: string) {
- const layoutDoc = doc; // doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc;
+ const layoutDoc = doc;
if (layoutDoc.type !== DocumentType.FONTICON) {
!layoutDoc.isTemplateDoc && makeTemplate(layoutDoc);
}
@@ -86,6 +86,8 @@ export function makeUserTemplateButtonOrImage(doc: Doc, image?: string) {
dbox.dragFactory = layoutDoc;
dbox.dropPropertiesToRemove = doc.dropPropertiesToRemove instanceof ObjectField ? ObjectField.MakeCopy(doc.dropPropertiesToRemove) : undefined;
dbox.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory)');
+ const userTemplatesDoc = DocCast(Doc.UserDoc().template_user);
+ userTemplatesDoc && Doc.AddDocToList(userTemplatesDoc, 'data', layoutDoc);
return dbox;
}
@@ -93,7 +95,7 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
data?.draggedDocuments.forEach((doc, i) => {
let dbox = doc;
// bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant
- if (doc.type === DocumentType.FONTICON || StrCast(Doc.Layout(doc).layout).includes(FontIconBox.name)) {
+ if (doc.type === DocumentType.FONTICON || StrCast(doc[DocLayout].layout).includes(FontIconBox.name)) {
if (data.dropPropertiesToRemove || dbox.dropPropertiesToRemove) {
// dbox = Doc.MakeEmbedding(doc); // don't need to do anything if dropping an icon doc onto an icon bar since there should be no layout data for an icon
dbox = Doc.MakeEmbedding(dbox);
diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx
index 1ec85c9d9..79d009720 100644
--- a/src/client/util/GroupManager.tsx
+++ b/src/client/util/GroupManager.tsx
@@ -19,6 +19,7 @@ import './GroupManager.scss';
import { GroupMemberView } from './GroupMemberView';
import { SharingManager, User } from './SharingManager';
import { SnappingManager } from './SnappingManager';
+import { SettingsManager } from './SettingsManager';
/**
* Interface for options for the react-select component
@@ -290,11 +291,12 @@ export class GroupManager extends ObservableReactComponent<object> {
this.createGroupModalOpen = false;
TaskCompletionBox.taskCompleted = false;
})}
- color={StrCast(Doc.UserDoc().userColor)}
+ color={SettingsManager.userColor}
+ background={SettingsManager.userBackgroundColor}
/>
</div>
</div>
- <div className="group-input" style={{ border: StrCast(Doc.UserDoc().userColor) }}>
+ <div className="group-input" style={{ border: SettingsManager.userColor }}>
<input
ref={this.inputRef}
onKeyDown={this.handleKeyDown}
@@ -306,7 +308,7 @@ export class GroupManager extends ObservableReactComponent<object> {
})}
/>
</div>
- <div style={{ border: StrCast(Doc.UserDoc().userColor) }}>
+ <div style={{ border: SettingsManager.userColor }}>
<Select
className="select-users"
isMulti
@@ -332,15 +334,15 @@ export class GroupManager extends ObservableReactComponent<object> {
}),
valueContainer: () => ({
display: 'inline-flex',
- fontStyle: StrCast(Doc.UserDoc().userColor),
- color: StrCast(Doc.UserDoc().userColor),
+ fontStyle: SettingsManager.userColor,
+ color: SettingsManager.userColor,
width: '100%',
}),
}}
/>
</div>
<div className="create-button">
- <Button text="Create" type={Type.TERT} color={StrCast(Doc.UserDoc().userColor)} onClick={this.createGroup} />
+ <Button text="Create" type={Type.TERT} color={SettingsManager.userColor} background={SettingsManager.userBackgroundColor} onClick={this.createGroup} />
</div>
</div>
);
diff --git a/src/client/util/History.ts b/src/client/util/History.ts
index 9728e3177..0df0ec337 100644
--- a/src/client/util/History.ts
+++ b/src/client/util/History.ts
@@ -94,7 +94,7 @@ export namespace HistoryUtil {
}
if (Array.isArray(value)) {
} else if (parser === true || parser === 'json') {
- value = JSON.parse(value);
+ value = value === 'undefined' ? undefined : JSON.parse(value);
} else if (parser === 'none') {
} else {
value = parser(value);
diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts
index 43807397f..eae3460b3 100644
--- a/src/client/util/Import & Export/ImageUtils.ts
+++ b/src/client/util/Import & Export/ImageUtils.ts
@@ -1,6 +1,5 @@
import { ClientUtils } from '../../../ClientUtils';
import { Doc } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { Cast, NumCast, StrCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
@@ -16,13 +15,12 @@ export namespace ImageUtils {
export const AssignImgInfo = (document: Doc, data?: Upload.InspectionResults) => {
if (data) {
data.nativeWidth && (document._height = (NumCast(document._width) * data.nativeHeight) / data.nativeWidth);
- const proto = document[DocData];
- const field = Doc.LayoutFieldKey(document);
- proto[`${field}_nativeWidth`] = data.nativeWidth;
- proto[`${field}_nativeHeight`] = data.nativeHeight;
- proto[`${field}_path`] = data.source;
- proto[`${field}_exif`] = JSON.stringify(data.exifData.data);
- proto[`${field}_contentSize`] = data.contentSize ? data.contentSize : undefined;
+ const field = '$' + Doc.LayoutDataKey(document);
+ document[`${field}_nativeWidth`] = data.nativeWidth;
+ document[`${field}_nativeHeight`] = data.nativeHeight;
+ document[`${field}_path`] = data.source;
+ document[`${field}_exif`] = JSON.stringify(data.exifData.data);
+ document[`${field}_contentSize`] = data.contentSize ? data.contentSize : undefined;
}
return document;
};
diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts
index 0e67dcfaa..6081c3fae 100644
--- a/src/client/util/LinkFollower.ts
+++ b/src/client/util/LinkFollower.ts
@@ -43,13 +43,13 @@ export class LinkFollower {
};
public static traverseLink(link: Opt<Doc>, sourceDoc: Doc, finished?: () => void, traverseBacklink?: boolean) {
- const getView = (doc: Doc) => DocumentView.getFirstDocumentView(DocCast(doc.layout_unrendered ? doc.annotationOn : doc));
- const isAnchor = (source: Doc, anchor: Doc) => Doc.AreProtosEqual(anchor, source) || Doc.AreProtosEqual(anchor.annotationOn as Doc, source);
+ const getView = (doc: Doc) => DocumentView.getFirstDocumentView(DocCast(doc.layout_unrendered ? doc.annotationOn : doc)!);
+ const isAnchor = (source?: Doc, anchor?: Doc) => Doc.AreProtosEqual(anchor, source) || Doc.AreProtosEqual(DocCast(anchor?.annotationOn), source);
const linkDocs = link ? [link] : Doc.Links(sourceDoc);
- const fwdLinks = linkDocs.filter(l => isAnchor(sourceDoc, l.link_anchor_1 as Doc)); // link docs where 'sourceDoc' is link_anchor_1
- const backLinks = linkDocs.filter(l => isAnchor(sourceDoc, l.link_anchor_2 as Doc)); // link docs where 'sourceDoc' is link_anchor_2
- const fwdLinkWithoutTargetView = fwdLinks.find(l => !getView(DocCast(l.link_anchor_2)));
- const backLinkWithoutTargetView = backLinks.find(l => !getView(DocCast(l.link_anchor_1)));
+ const fwdLinks = linkDocs.filter(l => isAnchor(sourceDoc, DocCast(l.link_anchor_1))); // link docs where 'sourceDoc' is link_anchor_1
+ const backLinks = linkDocs.filter(l => isAnchor(sourceDoc, DocCast(l.link_anchor_2))); // link docs where 'sourceDoc' is link_anchor_2
+ const fwdLinkWithoutTargetView = fwdLinks.find(l => !DocCast(l.link_anchor_2) || !getView(DocCast(l.link_anchor_2)!));
+ const backLinkWithoutTargetView = backLinks.find(l => !DocCast(l.link_anchor_1) || !getView(DocCast(l.link_anchor_1)!));
const linkWithoutTargetDoc = traverseBacklink === undefined ? (fwdLinkWithoutTargetView ?? backLinkWithoutTargetView) : traverseBacklink ? backLinkWithoutTargetView : fwdLinkWithoutTargetView;
const linkDocList = linkWithoutTargetDoc && !sourceDoc.followAllLinks ? [linkWithoutTargetDoc] : traverseBacklink === undefined ? fwdLinks.concat(backLinks) : traverseBacklink ? backLinks : fwdLinks;
const followLinks = sourceDoc.followLinkToggle || sourceDoc.followAllLinks ? linkDocList : linkDocList.slice(0, 1);
@@ -60,17 +60,17 @@ export class LinkFollower {
return false;
}
followLinks.forEach(async linkDoc => {
- const target = (
+ const target = DocCast(
sourceDoc === linkDoc.link_anchor_1
? linkDoc.link_anchor_2
: sourceDoc === linkDoc.link_anchor_2
? linkDoc.link_anchor_1
- : Doc.AreProtosEqual(sourceDoc, linkDoc.link_anchor_1 as Doc) || Doc.AreProtosEqual((linkDoc.link_anchor_1 as Doc).annotationOn as Doc, sourceDoc)
+ : Doc.AreProtosEqual(sourceDoc, DocCast(linkDoc.link_anchor_1)) || Doc.AreProtosEqual(DocCast(DocCast(linkDoc.link_anchor_1)?.annotationOn), sourceDoc)
? linkDoc.link_anchor_2
: linkDoc.link_anchor_1
- ) as Doc;
- const srcAnchor: Doc = Doc.getOppositeAnchor(linkDoc, target) ?? sourceDoc;
+ );
if (target) {
+ const srcAnchor = Doc.getOppositeAnchor(linkDoc, target) ?? sourceDoc;
const doFollow = (canToggle?: boolean) => {
const toggleTarget = canToggle && BoolCast(sourceDoc.followLinkToggle);
const options: FocusViewOptions = {
@@ -102,14 +102,16 @@ export class LinkFollower {
if (srcAnchor.followLinkLocation === OpenWhere.inParent) {
const sourceDocParent = DocCast(sourceDoc.embedContainer);
if (target.embedContainer instanceof Doc && target.embedContainer !== sourceDocParent) {
- Doc.RemoveDocFromList(target.embedContainer, Doc.LayoutFieldKey(target.embedContainer), target);
+ Doc.RemoveDocFromList(target.embedContainer, Doc.LayoutDataKey(target.embedContainer), target);
movedTarget = true;
}
- if (!DocListCast(sourceDocParent[Doc.LayoutFieldKey(sourceDocParent)]).includes(target)) {
- Doc.AddDocToList(sourceDocParent, Doc.LayoutFieldKey(sourceDocParent), target);
- movedTarget = true;
+ if (sourceDocParent) {
+ if (!DocListCast(sourceDocParent[Doc.LayoutDataKey(sourceDocParent)]).includes(target)) {
+ Doc.AddDocToList(sourceDocParent, Doc.LayoutDataKey(sourceDocParent), target);
+ movedTarget = true;
+ }
+ Doc.SetContainer(target, sourceDocParent);
}
- Doc.SetContainer(target, sourceDocParent);
}
const moveTo = [NumCast(sourceDoc.x) + NumCast(sourceDoc.followLinkXoffset), NumCast(sourceDoc.y) + NumCast(sourceDoc.followLinkYoffset)];
if (srcAnchor.followLinkXoffset !== undefined && moveTo[0] !== target.x) {
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index d04d41968..6461605a6 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -136,7 +136,7 @@ export class LinkManager {
true
);
FieldLoader.ServerLoadStatus.message = 'links';
- this.addLinkDB(Doc.LinkDBDoc());
+ Doc.LinkDBDoc() && this.addLinkDB(Doc.LinkDBDoc()!);
}
public createlink_relationshipLists = () => {
@@ -148,16 +148,21 @@ export class LinkManager {
public addLink(linkDoc: Doc, checkExists = false) {
Doc.AddDocToList(Doc.UserDoc(), 'links', linkDoc);
- if (!checkExists || !DocListCast(Doc.LinkDBDoc().data).includes(linkDoc)) {
- Doc.AddDocToList(Doc.LinkDBDoc(), 'data', linkDoc);
- // eslint-disable-next-line no-use-before-define
- setTimeout(UPDATE_SERVER_CACHE, 100);
+ if (Doc.LinkDBDoc()) {
+ if (!checkExists || !DocListCast(Doc.LinkDBDoc()!.data).includes(linkDoc)) {
+ Doc.AddDocToList(Doc.LinkDBDoc()!, 'data', linkDoc);
+ // eslint-disable-next-line no-use-before-define
+ setTimeout(UPDATE_SERVER_CACHE, 100);
+ }
}
}
public deleteLink(linkDoc: Doc) {
- const ret = Doc.RemoveDocFromList(Doc.LinkDBDoc(), 'data', linkDoc);
- linkDoc[DocData].link_anchor_1 = linkDoc[DocData].link_anchor_2 = undefined;
- return ret;
+ if (Doc.LinkDBDoc()) {
+ const ret = Doc.RemoveDocFromList(Doc.LinkDBDoc()!, 'data', linkDoc);
+ linkDoc.$link_anchor_1 = linkDoc.$link_anchor_2 = undefined;
+ return ret;
+ }
+ return false;
}
public deleteAllLinksOnAnchor(anchor: Doc) {
LinkManager.Instance.relatedLinker(anchor).forEach(LinkManager.Instance.deleteLink);
@@ -178,8 +183,8 @@ export class LinkManager {
}
const dirLinks = Array.from(anchor[DocData][DirectLinks]).filter(l => Doc.GetProto(anchor) === anchor[DocData] || ['1', '2'].includes(LinkManager.anchorIndex(l, anchor) as '0' | '1' | '2'));
- const anchorRoot = DocCast(anchor.rootDocument, anchor); // template Doc fields store annotations on the topmost root of a template (not on themselves since the template layout items are only for layout)
- const annos = DocListCast(anchorRoot[Doc.LayoutFieldKey(anchor) + '_annotations']);
+ const anchorRoot = DocCast(anchor.rootDocument, anchor)!; // template Doc fields store annotations on the topmost root of a template (not on themselves since the template layout items are only for layout)
+ const annos = DocListCast(anchorRoot[Doc.LayoutDataKey(anchor) + '_annotations']);
return Array.from(
annos.reduce((set, anno) => {
if (!processed.includes(anno)) {
@@ -212,7 +217,8 @@ export class LinkManager {
}
// finds the opposite anchor of a given anchor in a link
- public static getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc | undefined {
+ public static getOppositeAnchor(linkDoc: Doc | undefined, anchor: Doc | undefined): Doc | undefined {
+ if (!linkDoc || !anchor) return undefined;
const id = LinkManager.anchorIndex(linkDoc, anchor);
const a1 = DocCast(linkDoc.link_anchor_1);
const a2 = DocCast(linkDoc.link_anchor_2);
@@ -242,11 +248,13 @@ export function UPDATE_SERVER_CACHE() {
.filter(doc => doc instanceof Doc)
.map(doc => doc as Doc);
const references = new Set<Doc>(prototypes);
+ DocCast(Doc.UserDoc().myLinkDatabase) && references.add(DocCast(Doc.UserDoc().myLinkDatabase)!); // prevent crawling through link database here -- see below
Doc.FindReferences(Doc.UserDoc(), references, undefined);
- DocListCast(DocCast(Doc.UserDoc().myLinkDatabase).data).forEach(link => {
- if (!references.has(DocCast(link.link_anchor_1)) && !references.has(DocCast(link.link_anchor_2))) {
- Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myLinkDatabase), 'data', link);
- Doc.AddDocToList(Doc.MyRecentlyClosed, undefined, link);
+
+ DocListCast(DocCast(Doc.UserDoc().myLinkDatabase)?.data).forEach(link => {
+ if (DocCast(link.link_anchor_1) && !references.has(DocCast(link.link_anchor_1)!) && DocCast(link.link_anchor_2) && !references.has(DocCast(link.link_anchor_2)!)) {
+ DocCast(Doc.UserDoc().myLinkDatabase) && Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myLinkDatabase)!, 'data', link);
+ Doc.MyRecentlyClosed && Doc.AddDocToList(Doc.MyRecentlyClosed, undefined, link);
}
});
LinkManager.Instance.userLinkDBs.forEach(linkDb => Doc.FindReferences(linkDb, references, undefined));
@@ -257,10 +265,10 @@ export function UPDATE_SERVER_CACHE() {
cacheDocumentIds = newCacheUpdate;
// print out cached docs
- //Doc.MyDockedBtns.linearView_IsOpen && console.log('Set cached docs = ');
+ Doc.MyDockedBtns?.linearView_isOpen && console.log('Set cached docs = ');
const isFiltered = filtered.filter(doc => !Doc.IsSystem(doc));
const strings = isFiltered.map(doc => StrCast(doc.title) + ' ' + (Doc.IsDataProto(doc) ? '(data)' : '(embedding)'));
- //Doc.MyDockedBtns.linearView_IsOpen && strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str));
+ Doc.MyDockedBtns?.linearView_isOpen && strings.sort().forEach((str, i) => console.log(i.toString() + ' ' + str));
rp.post(ClientUtils.prepend('/setCacheDocumentIds'), {
body: {
diff --git a/src/client/util/ReplayMovements.ts b/src/client/util/ReplayMovements.ts
index 62a09a8bc..4f0423342 100644
--- a/src/client/util/ReplayMovements.ts
+++ b/src/client/util/ReplayMovements.ts
@@ -108,9 +108,11 @@ export class ReplayMovements {
movements.forEach((movement, i) => {
if (typeof movement.doc === 'string') {
- movements[i].doc = IdToDoc(movement.doc);
- if (!movements[i].doc) {
+ const doc = IdToDoc(movement.doc);
+ if (!doc) {
console.log('ERROR: tracked doc not found');
+ } else {
+ movements[i].doc = doc;
}
}
});
diff --git a/src/client/util/ScriptManager.ts b/src/client/util/ScriptManager.ts
index 9158f6c0b..8c7f88bf6 100644
--- a/src/client/util/ScriptManager.ts
+++ b/src/client/util/ScriptManager.ts
@@ -1,7 +1,6 @@
-import { Doc, DocListCast } from '../../fields/Doc';
+import { Doc, DocListCast, StrListCast } from '../../fields/Doc';
import { List } from '../../fields/List';
-import { listSpec } from '../../fields/Schema';
-import { Cast, StrCast } from '../../fields/Types';
+import { StrCast } from '../../fields/Types';
import { Docs } from '../documents/Documents';
import { ScriptingGlobals } from './ScriptingGlobals';
@@ -10,7 +9,6 @@ export class ScriptManager {
// eslint-disable-next-line no-use-before-define
private static _instance: ScriptManager;
public static get Instance(): ScriptManager {
- // eslint-disable-next-line no-return-assign
return this._instance || (this._instance = new this());
}
private constructor() {
@@ -58,7 +56,7 @@ export class ScriptManager {
public static addScriptToGlobals(scriptDoc: Doc): void {
ScriptingGlobals.removeGlobal(StrCast(scriptDoc.name));
- const params = Cast(scriptDoc['data-params'], listSpec('string'), []);
+ const params = StrListCast(scriptDoc['data-params']);
const paramNames = params.reduce((o: string, p: string) => {
let out = o;
if (params.indexOf(p) === params.length - 1) {
@@ -69,7 +67,6 @@ export class ScriptManager {
return out;
}, '' as string);
- // eslint-disable-next-line no-new-func
const f = new Function(paramNames, StrCast(scriptDoc.script));
Object.defineProperty(f, 'name', { value: StrCast(scriptDoc.name), writable: false });
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index b0886a67c..2fa6e3059 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -51,6 +51,7 @@ function Run(script: string | undefined, customParams: string[], diagnostics: ts
const errors = diagnostics.filter(diag => diag.category === ts.DiagnosticCategory.Error).filter(diag => //
diag.code !== 2304 &&
diag.code !== 2339 &&
+ diag.code !== 2314 &&
(diag.code !== 2552 ||!Object.keys(scriptingGlobals).includes(diagnostics[0].messageText.toString().match(/Cannot find name '([A-Za-z0-9$-_]+)'/)?.[1]??"-------"))
); // prettier-ignore
if ((options.typecheck !== false && errors.length) || !script) {
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 733eae5f4..fc3bb99ab 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -9,11 +9,11 @@ export namespace SearchUtil {
export type HighlightingResult = { [id: string]: { [key: string]: string[] } };
export function SearchCollection(collectionDoc: Opt<Doc>, queryIn: string, matchKeyNames: boolean, onlyKeys?: string[]) {
- const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
+ const blockedTypes = [DocumentType.PRESSLIDE, DocumentType.CONFIG, DocumentType.KVP, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
const blockedKeys = matchKeyNames
? []
: Object.entries(DocOptions)
- .filter(([, info]: [string, FInfo]) => !info?.searchable())
+ .filter(([, info]: [string, FieldType | FInfo | undefined]) => (info instanceof FInfo ? !info.searchable() : true))
.map(([key]) => key);
const exact = queryIn.startsWith('=');
@@ -21,9 +21,8 @@ export namespace SearchUtil {
const results = new ObservableMap<Doc, string[]>();
if (collectionDoc) {
- const docs = DocListCast(collectionDoc[Doc.LayoutFieldKey(collectionDoc)]);
- // eslint-disable-next-line @typescript-eslint/ban-types
- const docIDs: String[] = [];
+ const docs = DocListCast(collectionDoc[Doc.LayoutDataKey(collectionDoc)]);
+ const docIDs: string[] = [];
SearchUtil.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => {
const dtype = StrCast(doc.type) as DocumentType;
if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth >= 0) {
@@ -77,7 +76,7 @@ export namespace SearchUtil {
// eslint-disable-next-line no-loop-func
docs.filter(d => d && !visited.includes(d)).forEach(d => {
visited.push(d);
- const fieldKey = Doc.LayoutFieldKey(d);
+ const fieldKey = Doc.LayoutDataKey(d);
const annos = !Field.toString(Doc.LayoutField(d) as FieldType).includes('CollectionView');
const data = d[annos ? fieldKey + '_annotations' : fieldKey];
data && newarray.push(...DocListCast(data));
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index 6ea242fc3..9e79fd870 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -30,7 +30,7 @@ export enum ColorScheme {
export class SettingsManager extends React.Component<object> {
// eslint-disable-next-line no-use-before-define
public static Instance: SettingsManager;
- static _settingsStyle = addStyleSheet();
+ static _settingsStyle = addStyleSheet().sheet;
@observable private _passwordResultText = '';
@observable private _playgroundMode = false;
@@ -135,9 +135,9 @@ export class SettingsManager extends React.Component<object> {
reaction(
() => [SettingsManager.userBackgroundColor, SettingsManager.userColor, SettingsManager.userVariantColor],
([back, user, variant]) => {
- SnappingManager.userBackgroundColor = back;
- SnappingManager.userVariantColor = variant;
- SnappingManager.userColor = user;
+ SnappingManager.SetUserBackgroundColor(back);
+ SnappingManager.SetUserVariantColor(variant);
+ SnappingManager.SetUserColor(user);
},
{ fireImmediately: true }
);
@@ -177,6 +177,7 @@ export class SettingsManager extends React.Component<object> {
}))}
dropdownType={DropdownType.SELECT}
color={SettingsManager.userColor}
+ background={SettingsManager.userBackgroundColor}
fillWidth
/>
<Toggle formLabel="Match System" toggleType={ToggleType.SWITCH} color={SettingsManager.userColor} toggleStatus={BoolCast(Doc.UserDoc().userThemeSystem)} onClick={this.userThemeSystemToggle} />
@@ -300,6 +301,7 @@ export class SettingsManager extends React.Component<object> {
<NumberDropdown
number={NumCast(Doc.UserDoc().headerHeight, 30)}
color={SettingsManager.userColor}
+ background={SettingsManager.userBackgroundColor}
numberDropdownType="slider"
min={6}
max={60}
@@ -342,6 +344,7 @@ export class SettingsManager extends React.Component<object> {
<Group formLabel="Default Font">
<NumberDropdown
color={SettingsManager.userColor}
+ background={SettingsManager.userBackgroundColor}
numberDropdownType="slider"
min={0}
max={50}
@@ -355,10 +358,10 @@ export class SettingsManager extends React.Component<object> {
/>
<ColorPicker
color={SettingsManager.userColor}
+ background={SettingsManager.userBackgroundColor}
type={Type.PRIM}
defaultPickerType="Classic"
selectedColor={StrCast(Doc.UserDoc().textBackgroundColor, Colors.LIGHT_GRAY)}
- background={SnappingManager.userBackgroundColor}
icon={<FontAwesomeIcon icon="palette" size="lg" />}
tooltip="default text background color"
label="background"
@@ -390,6 +393,7 @@ export class SettingsManager extends React.Component<object> {
this.changeFontFamily(val as string);
}}
color={SettingsManager.userColor}
+ background={SettingsManager.userBackgroundColor}
fillWidth
/>
</Group>
@@ -402,12 +406,12 @@ export class SettingsManager extends React.Component<object> {
@computed get passwordContent() {
return (
<div className="password-content">
- <EditableText placeholder="Current password" type={Type.SEC} color={SettingsManager.userColor} val="" setVal={val => this.changeVal(val as string, 'curr')} fillWidth password />
- <EditableText placeholder="New password" type={Type.SEC} color={SettingsManager.userColor} val="" setVal={val => this.changeVal(val as string, 'new')} fillWidth password />
- <EditableText placeholder="Confirm new password" type={Type.SEC} color={SettingsManager.userColor} val="" setVal={val => this.changeVal(val as string, 'conf')} fillWidth password />
+ <EditableText placeholder="Current password" type={Type.SEC} color={SettingsManager.userColor} background={SettingsManager.userBackgroundColor} val="" setVal={val => this.changeVal(val as string, 'curr')} fillWidth password />
+ <EditableText placeholder="New password" type={Type.SEC} color={SettingsManager.userColor} background={SettingsManager.userBackgroundColor} val="" setVal={val => this.changeVal(val as string, 'new')} fillWidth password />
+ <EditableText placeholder="Confirm new password" type={Type.SEC} color={SettingsManager.userColor} background={SettingsManager.userBackgroundColor} val="" setVal={val => this.changeVal(val as string, 'conf')} fillWidth password />
{!this._passwordResultText ? null : <div className={`${this._passwordResultText.startsWith('Error') ? 'error' : 'success'}-text`}>{this._passwordResultText}</div>}
- <Button type={Type.SEC} text="Forgot Password" color={SettingsManager.userColor} />
- <Button type={Type.TERT} text="Submit" onClick={this.changePassword} color={SettingsManager.userColor} />
+ <Button type={Type.SEC} text="Forgot Password" color={SettingsManager.userColor} background={SettingsManager.userBackgroundColor} />
+ <Button type={Type.TERT} text="Submit" onClick={this.changePassword} color={SettingsManager.userColor} background={SettingsManager.userBackgroundColor} />
</div>
);
}
@@ -415,7 +419,7 @@ export class SettingsManager extends React.Component<object> {
@computed get accountOthersContent() {
return (
<div className="account-others-content">
- <Button type={Type.TERT} text="Connect to Google" iconPlacement="left" icon={<BsGoogle />} onClick={() => this.googleAuthorize()} />
+ <Button type={Type.TERT} text="Connect to Google" color={SnappingManager.userColor} background={SnappingManager.userBackgroundColor} iconPlacement="left" icon={<BsGoogle />} onClick={() => this.googleAuthorize()} />
</div>
);
}
@@ -465,6 +469,7 @@ export class SettingsManager extends React.Component<object> {
type={Type.TERT}
placement="bottom-start"
color={SettingsManager.userColor}
+ background={SettingsManager.userBackgroundColor}
fillWidth
/>
<Toggle formLabel="Playground Mode" toggleType={ToggleType.SWITCH} toggleStatus={this._playgroundMode} onClick={this.playgroundModeToggle} color={SettingsManager.userColor} />
@@ -494,13 +499,14 @@ export class SettingsManager extends React.Component<object> {
type={Type.TERT}
placement="bottom-start"
color={SettingsManager.userColor}
+ background={SettingsManager.userBackgroundColor}
/>
</div>
</div>
<div className="tab-column">
<div className="tab-column-title">Permissions</div>
<div className="tab-column-content">
- <Button text="Manage Groups" type={Type.TERT} onClick={() => GroupManager.Instance?.open()} color={SettingsManager.userColor} />
+ <Button text="Manage Groups" type={Type.TERT} color={SnappingManager.userColor} background={SnappingManager.userBackgroundColor} onClick={() => GroupManager.Instance?.open()} />
<Toggle
toggleType={ToggleType.SWITCH}
formLabel="Default access private"
@@ -572,7 +578,7 @@ export class SettingsManager extends React.Component<object> {
<div className="settings-username" style={{ color: SettingsManager.userBackgroundColor }}>
{ClientUtils.CurrentUserEmail()}
</div>
- <Button text={Doc.GuestDashboard ? 'Exit' : 'Log Out'} type={Type.TERT} color={SettingsManager.userVariantColor} onClick={() => window.location.assign(ClientUtils.prepend('/logout'))} />
+ <Button text={Doc.GuestDashboard ? 'Exit' : 'Log Out'} type={Type.TERT} color={SettingsManager.userVariantColor} background={SettingsManager.userColor} onClick={() => window.location.assign(ClientUtils.prepend('/logout'))} />
</div>
</div>
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 3a248400b..db8c6c5cb 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -286,7 +286,7 @@ export class SharingManager extends React.Component<object> {
{this.focusOn(docs.length < 2 ? StrCast(targetDoc?.title, 'this document') : '-multiple-')}
</p>
<div className="share-copy-link">
- <Button type={Type.TERT} color={SnappingManager.userColor} icon={<FontAwesomeIcon icon="copy" size="sm" />} iconPlacement="left" text="Copy Guest URL" onClick={this.copyURL} />
+ <Button type={Type.TERT} color={SnappingManager.userColor} background={SnappingManager.userBackgroundColor} icon={<FontAwesomeIcon icon="copy" size="sm" />} iconPlacement="left" text="Copy Guest URL" onClick={this.copyURL} />
</div>
<div className="close-button">
<Button icon={<FontAwesomeIcon icon="times" size="lg" />} onClick={this.close} color={SnappingManager.userColor} />
@@ -331,7 +331,7 @@ export class SharingManager extends React.Component<object> {
</select>
</div>
<div className="share-button">
- <Button text="SHARE" type={Type.TERT} color={SnappingManager.userColor} onClick={this.share} />
+ <Button text="SHARE" type={Type.TERT} color={SnappingManager.userColor} background={SnappingManager.userBackgroundColor} onClick={this.share} />
</div>
</div>
<div className="sort-checkboxes">
@@ -633,7 +633,7 @@ export class SharingManager extends React.Component<object> {
private focusOn = (contents: string) => {
const title = this.targetDoc ? StrCast(this.targetDoc.title) : '';
- const docs = DocumentView.Selected().length > 1 ? DocumentView.Selected().map(docView => docView.props.Document) : [this.targetDoc];
+ const docs = DocumentView.Selected().length > 1 ? DocumentView.Selected().map(docView => docView.Document) : [this.targetDoc];
return (
<span
className="focus-span"
diff --git a/src/client/util/SnappingManager.ts b/src/client/util/SnappingManager.ts
index 3bbc297b8..54c91087f 100644
--- a/src/client/util/SnappingManager.ts
+++ b/src/client/util/SnappingManager.ts
@@ -1,4 +1,4 @@
-import { observable, action, runInAction, makeObservable } from 'mobx';
+import { observable, action, makeObservable } from 'mobx';
import { Gestures } from '../../pen-gestures/GestureTypes';
export enum freeformScrollMode {
@@ -34,6 +34,9 @@ export class SnappingManager {
@observable _keepGestureMode: boolean = false; // for whether primitive selection enters a one-shot or persistent mode
@observable _inkShape: Gestures | undefined = undefined;
@observable _chatVisible: boolean = false;
+ @observable _userBackgroundColor: string | undefined = undefined;
+ @observable _userVariantColor: string | undefined = undefined;
+ @observable _userColor: string | undefined = undefined;
private constructor() {
SnappingManager._manager = this;
@@ -48,6 +51,9 @@ export class SnappingManager {
this.Instance._vertSnapLines.push(...vertLines);
};
+ public static get userBackgroundColor() { return this.Instance._userBackgroundColor; } // prettier-ignore
+ public static get userVariantColor() { return this.Instance._userVariantColor; } // prettier-ignore
+ public static get userColor() { return this.Instance._userColor; } // prettier-ignore
public static get HorizSnapLines() { return this.Instance._horizSnapLines; } // prettier-ignore
public static get VertSnapLines() { return this.Instance._vertSnapLines; } // prettier-ignore
public static get LongPress() { return this.Instance._longPress; } // prettier-ignore
@@ -71,29 +77,29 @@ export class SnappingManager {
public static get InkShape() { return this.Instance._inkShape; } // prettier-ignore
public static get ChatVisible() { return this.Instance._chatVisible; } // prettier-ignore
- public static SetLongPress = (press: boolean) => runInAction(() => {this.Instance._longPress = press}); // prettier-ignore
- public static SetShiftKey = (down: boolean) => runInAction(() => {this.Instance._shiftKey = down}); // prettier-ignore
- public static SetCtrlKey = (down: boolean) => runInAction(() => {this.Instance._ctrlKey = down}); // prettier-ignore
- public static SetMetaKey = (down: boolean) => runInAction(() => {this.Instance._metaKey = down}); // prettier-ignore
- public static SetHideUI = (vis: boolean) => runInAction(() => {this.Instance._hideUI = vis}); // prettier-ignore
- public static SetShowPresPaths = (paths:boolean) => runInAction(() => {this.Instance._showPresPaths = paths}); // prettier-ignore
- public static SetIsLinkFollowing= (follow:boolean)=> runInAction(() => {this.Instance._isLinkFollowing = follow}); // prettier-ignore
- public static SetIsDragging = (drag: boolean) => runInAction(() => {this.Instance._isDragging = drag}); // prettier-ignore
- public static SetIsResizing = (docid?:string) => runInAction(() => {this.Instance._isResizing = docid}); // prettier-ignore
- public static SetCanEmbed = (embed:boolean) => runInAction(() => {this.Instance._canEmbed = embed}); // prettier-ignore
- public static SetExploreMode = (state:boolean) => runInAction(() => {this.Instance._exploreMode = state}); // prettier-ignore
- public static TriggerUserPanned = () => runInAction(() => {this.Instance._userPanned = !this.Instance._userPanned}); // prettier-ignore
- public static SetServerVersion = (version:string) =>runInAction(() => {this.Instance._serverVersion = version}); // prettier-ignore
- public static SetLastPressedBtn = (id:string) =>runInAction(() => {this.Instance._lastBtnId = id}); // prettier-ignore
- public static SetPropertiesWidth= (wid:number) =>runInAction(() => {this.Instance._propertyWid = wid}); // prettier-ignore
- public static SetPrintToConsole = (state:boolean) =>runInAction(() => {this.Instance._printToConsole = state}); // prettier-ignore
- public static SetHideDecorations= (state:boolean) =>runInAction(() => {this.Instance._hideDecorations = state}); // prettier-ignore
- public static SetKeepGestureMode= (state:boolean) =>runInAction(() => {this.Instance._keepGestureMode = state}); // prettier-ignore
- public static SetInkShape = (shape?:Gestures)=>runInAction(() => {this.Instance._inkShape = shape}); // prettier-ignore
- public static SetChatVisible = (vis:boolean) =>runInAction(() => {this.Instance._chatVisible = vis}); // prettier-ignore
+ public static SetUserBackgroundColor = action((color: string) => (this.Instance._userBackgroundColor = color)); // prettier-ignore
+ public static SetUserVariantColor = action((color: string) => (this.Instance._userVariantColor = color)); // prettier-ignore
+ public static SetUserColor = action((color: string) => (this.Instance._userColor = color)); // prettier-ignore
+ public static SetLongPress = action((press: boolean)=> (this.Instance._longPress = press)); // prettier-ignore
+ public static SetShiftKey = action((down: boolean) => (this.Instance._shiftKey = down)); // prettier-ignore
+ public static SetCtrlKey = action((down: boolean) => (this.Instance._ctrlKey = down)); // prettier-ignore
+ public static SetMetaKey = action((down: boolean) => (this.Instance._metaKey = down)); // prettier-ignore
+ public static SetHideUI = action((vis: boolean) => (this.Instance._hideUI = vis)); // prettier-ignore
+ public static SetShowPresPaths = action((paths:boolean) => (this.Instance._showPresPaths = paths)); // prettier-ignore
+ public static SetIsLinkFollowing = action((follow:boolean)=> (this.Instance._isLinkFollowing = follow)); // prettier-ignore
+ public static SetIsDragging = action((drag: boolean) => (this.Instance._isDragging = drag)); // prettier-ignore
+ public static SetIsResizing = action((docid?:string) => (this.Instance._isResizing = docid)); // prettier-ignore
+ public static SetCanEmbed = action((embed:boolean) => (this.Instance._canEmbed = embed)); // prettier-ignore
+ public static SetExploreMode = action((state:boolean) => (this.Instance._exploreMode = state)); // prettier-ignore
+ public static TriggerUserPanned = action(() => (this.Instance._userPanned = !this.Instance._userPanned)); // prettier-ignore
+ public static SetServerVersion = action((version:string)=> (this.Instance._serverVersion = version)); // prettier-ignore
+ public static SetLastPressedBtn = action((id:string) => (this.Instance._lastBtnId = id)); // prettier-ignore
+ public static SetPropertiesWidth = action((wid:number) => (this.Instance._propertyWid = wid)); // prettier-ignore
+ public static SetPrintToConsole = action((state:boolean) => (this.Instance._printToConsole = state)); // prettier-ignore
+ public static SetHideDecorations = action((state:boolean) => (this.Instance._hideDecorations = state)); // prettier-ignore
+ public static SetKeepGestureMode = action((state:boolean) => (this.Instance._keepGestureMode = state)); // prettier-ignore
+ public static SetInkShape = action((shape?:Gestures)=>(this.Instance._inkShape = shape)); // prettier-ignore
+ public static SetChatVisible = action((vis:boolean) => (this.Instance._chatVisible = vis)); // prettier-ignore
- public static userColor: string | undefined;
- public static userVariantColor: string | undefined;
- public static userBackgroundColor: string | undefined;
public static SettingsStyle: CSSStyleSheet | null;
}
diff --git a/src/client/util/reportManager/ReportManagerComponents.tsx b/src/client/util/reportManager/ReportManagerComponents.tsx
index 92f877859..80653779e 100644
--- a/src/client/util/reportManager/ReportManagerComponents.tsx
+++ b/src/client/util/reportManager/ReportManagerComponents.tsx
@@ -1,5 +1,3 @@
-/* eslint-disable react/require-default-props */
-/* eslint-disable prefer-destructuring */
/* eslint-disable no-use-before-define */
import * as React from 'react';
import ReactMarkdown from 'react-markdown';
@@ -299,7 +297,7 @@ export function IssueView({ issue }: IssueViewProps) {
</div>
</div>
)}
- <ReactMarkdown className="issue-content" remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]}>
+ <ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]}>
{issueBody}
</ReactMarkdown>
</div>
diff --git a/src/client/util/request-image-size.ts b/src/client/util/request-image-size.ts
index 32ab23618..798390c7d 100644
--- a/src/client/util/request-image-size.ts
+++ b/src/client/util/request-image-size.ts
@@ -33,27 +33,25 @@ export function requestImageSize(url: string): Promise<ISizeCalculationResult> {
res.on('data', chunk => {
buffer = Buffer.concat([buffer, chunk]);
- });
-
- res.on('error', reject);
-
- res.on('end', () => {
- try {
- size = imageSize(buffer);
- if (size) {
- resolve(size);
- req.abort();
+ })
+ .on('error', reject)
+ .on('end', () => {
+ try {
+ size = imageSize(buffer);
+ if (size) {
+ resolve(size);
+ req.abort();
+ }
+ } catch (err) {
+ /* empty */
+ console.log('Error: ', err);
+ }
+ if (!size) {
+ reject(new Error('Image has no size'));
+ return;
}
- } catch (err) {
- /* empty */
- console.log('Error: ', err);
- }
- if (!size) {
- reject(new Error('Image has no size'));
- return;
- }
- resolve(size);
- });
+ resolve(size);
+ });
});
req.on('error', reject);