aboutsummaryrefslogtreecommitdiff
path: root/src/client/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util')
-rw-r--r--src/client/util/CurrentUserUtils.ts99
-rw-r--r--src/client/util/DocumentManager.ts24
-rw-r--r--src/client/util/DragManager.ts44
-rw-r--r--src/client/util/InteractionUtils.tsx53
-rw-r--r--src/client/util/ReportManager.tsx33
-rw-r--r--src/client/util/Scripting.ts8
-rw-r--r--src/client/util/SelectionManager.ts2
-rw-r--r--src/client/util/SettingsManager.tsx2
-rw-r--r--src/client/util/SharingManager.scss3
-rw-r--r--src/client/util/SharingManager.tsx2
-rw-r--r--src/client/util/request-image-size.js26
11 files changed, 154 insertions, 142 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 99a8c895f..cd2ea4c87 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1,12 +1,14 @@
+import { forOwn } from "lodash";
import { reaction } from "mobx";
import * as rp from 'request-promise';
import { Doc, DocListCast, DocListCastAsync, Opt } from "../../fields/Doc";
import { Id } from "../../fields/FieldSymbols";
+import { InkTool } from "../../fields/InkField";
import { List } from "../../fields/List";
import { PrefetchProxy } from "../../fields/Proxy";
import { RichTextField } from "../../fields/RichTextField";
import { listSpec } from "../../fields/Schema";
-import { ScriptField } from "../../fields/ScriptField";
+import { ComputedField, ScriptField } from "../../fields/ScriptField";
import { Cast, DateCast, DocCast, PromiseValue, StrCast } from "../../fields/Types";
import { nullAudio } from "../../fields/URLField";
import { SetCachedGroups, SharingPermissions } from "../../fields/util";
@@ -143,7 +145,7 @@ export class CurrentUserUtils {
{ noteType: "Idea", backgroundColor: "pink", icon: "lightbulb" },
{ noteType: "Topic", backgroundColor: "lightblue", icon: "book-open" }];
const reqdNoteList = reqdTempOpts.map(opts => {
- const reqdOpts = {...opts, title: "text", width:200, system: true};
+ const reqdOpts = {...opts, title: "text", width:200, autoHeight: true, fitWidth: true, system: true};
const noteType = tempNotes ? DocListCast(tempNotes.data).find(doc => doc.noteType === opts.noteType): undefined;
return DocUtils.AssignOpts(noteType, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts), true, opts.noteType??"Note");
});
@@ -154,7 +156,7 @@ export class CurrentUserUtils {
/// Initializes collection of templates for notes and click functions
static setupDocTemplates(doc: Doc, field="myTemplates") {
- DocUtils.AssignDocField(doc, "presElement", opts => Docs.Create.PresElementBoxDocument(opts), { title: "pres element template", type: DocumentType.PRESELEMENT, _fitWidth: true, _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data"});
+ DocUtils.AssignDocField(doc, "presElement", opts => Docs.Create.PresElementBoxDocument(), { });
const templates = [
CurrentUserUtils.setupNoteTemplates(doc),
CurrentUserUtils.setupClickEditorTemplates(doc)
@@ -196,6 +198,7 @@ export class CurrentUserUtils {
makeIconTemplate(DocumentType.RTF, "text", { iconTemplate:DocumentType.LABEL, _showTitle: "creationDate"}),
makeIconTemplate(DocumentType.IMG, "data", { iconTemplate:DocumentType.IMG, _height: undefined}),
makeIconTemplate(DocumentType.COL, "icon", { iconTemplate:DocumentType.IMG}),
+ makeIconTemplate(DocumentType.COL, "icon", { iconTemplate:DocumentType.IMG}),
makeIconTemplate(DocumentType.VID, "icon", { iconTemplate:DocumentType.IMG}),
makeIconTemplate(DocumentType.BUTTON,"data", { iconTemplate:DocumentType.FONTICON}),
//nasty hack .. templates are looked up exclusively by type -- but we want a template for a document with a certain field (transcription) .. so this hack and the companion hack in createCustomView does this for now
@@ -205,7 +208,7 @@ export class CurrentUserUtils {
DocUtils.AssignOpts(DocCast(doc[field]), {}, iconTemplates);
}
- /// initalizes the set of "empty<DocType>" versions of each document type with default fields. e.g.,. emptyNote, emptyPresentation
+ /// initalizes the set of "empty<DocType>" versions of each document type with default fields. e.g.,. emptyNote, emptyTrail
static creatorBtnDescriptors(doc: Doc): {
title: string, toolTip: string, icon: string, ignoreClick?: boolean, dragFactory?: Doc,
backgroundColor?: string, clickFactory?: Doc, scripts?: { onClick?: string, onDragStart?: string}, funcs?: {onDragStart?:string, hidden?: string},
@@ -267,7 +270,7 @@ export class CurrentUserUtils {
{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 }},
{key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true,}},
- {key: "Presentation",creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 500, _viewType: CollectionViewType.Stacking, targetDropAction: "alias" as any, treeViewHideTitle: true, _chromeHidden: true, boxShadow: "0 0" }},
+ {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _viewType: CollectionViewType.Stacking, targetDropAction: "alias" as any, treeViewHideTitle: true, _chromeHidden: true, boxShadow: "0 0" }},
{key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _backgroundGridShow: true, }},
{key: "Slide", creator: opts => Docs.Create.TreeDocument([], opts), opts: { _width: 300, _height: 200, _viewType: CollectionViewType.Tree,
treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true,
@@ -321,16 +324,17 @@ export class CurrentUserUtils {
/// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents
static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}}[] {
- const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())";
+ const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())";
+ const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails";
return [
- { title: "Dashboards", target: this.setupDashboards(doc, "myDashboards"), icon: "desktop", },
+ { title: "Dashboards", target: this.setupDashboards(doc, "myDashboards"), icon: "desktop", funcs: {hidden: "IsNoviceMode()"} },
{ title: "Search", target: this.setupSearcher(doc, "mySearcher"), icon: "search", },
{ title: "Files", target: this.setupFilesystem(doc, "myFilesystem"), icon: "folder-open", },
{ title: "Tools", target: this.setupToolsBtnPanel(doc, "myTools"), icon: "wrench", funcs: {hidden: "IsNoviceMode()"} },
{ title: "Imports", target: this.setupImportSidebar(doc, "myImports"), icon: "upload", },
{ title: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), icon: "archive", },
{ title: "Shared Docs", target: Doc.MySharedDocs, icon: "users", funcs: {badgeValue:badgeValue}},
- { title: "Trails", target: this.setupTrails(doc, "myTrails"), icon: "pres-trail", },
+ { title: "Trails", target: Doc.UserDoc(), icon: "pres-trail", funcs: {target: getActiveDashTrails}},
{ title: "User Doc View", target: this.setupUserDocView(doc, "myUserDocView"), icon: "address-card",funcs: {hidden: "IsNoviceMode()"} },
].map(tuple => ({...tuple, scripts:{onClick: 'selectMainMenu(self)'}}));
}
@@ -458,28 +462,33 @@ export class CurrentUserUtils {
static setupDashboards(doc: Doc, field:string) {
var myDashboards = DocCast(doc[field]);
+ const toggleDarkTheme = `this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`;
const newDashboard = `createNewDashboard()`;
+
const reqdBtnOpts:DocumentOptions = { _forceActive: true, _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true,
title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", system: true };
const reqdBtnScript = {onClick: newDashboard,}
const newDashboardButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myDashboards?.buttonMenuDoc), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript);
+ const contextMenuScripts = [/*newDashboard*/] as string[];
+ const contextMenuLabels = [/*"Create New Dashboard"*/] as string[];
+ const contextMenuIcons = [/*"plus"*/] as string[];
+ const childContextMenuScripts = [toggleDarkTheme, `toggleComicMode()`, `snapshotDashboard()`, `shareDashboard(self)`, 'removeDashboard(self)', 'resetDashboard(self)']; // entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuFilters
+ const childContextMenuFilters = ['!IsNoviceMode()', '!IsNoviceMode()', '!IsNoviceMode()', undefined as any, undefined as any, undefined as any];// entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuScripts
+ const childContextMenuLabels = ["Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard", "Reset Dashboard"];// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters
+ const childContextMenuIcons = ["chalkboard", "tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters
const reqdOpts:DocumentOptions = {
title: "My Dashboards", childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, boxShadow: "0 0", childDontRegisterViews: true,
targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true, treeViewTruncateTitleWidth: 150, ignoreClick: true,
buttonMenu: true, buttonMenuDoc: newDashboardButton, childDropAction: "alias",
_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true,
- contextMenuLabels: new List<string>(["Create New Dashboard"]),
- contextMenuIcons: new List<string>(["plus"]),
- childContextMenuLabels: new List<string>(["Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard"]),// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters
- childContextMenuIcons: new List<string>(["chalkboard", "tv", "camera", "users", "times"]), // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters
+ contextMenuLabels:new List<string>(contextMenuLabels),
+ contextMenuIcons:new List<string>(contextMenuIcons),
+ childContextMenuLabels:new List<string>(childContextMenuLabels),
+ childContextMenuIcons:new List<string>(childContextMenuIcons),
explainer: "This is your collection of dashboards. A dashboard represents the tab configuration of your workspace. To manage documents as folders, go to the Files."
};
myDashboards = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), reqdOpts);
- const toggleDarkTheme = `this.colorScheme = this.colorScheme ? undefined : "${ColorScheme.Dark}"`;
- const contextMenuScripts = [newDashboard];
- const childContextMenuScripts = [toggleDarkTheme, `toggleComicMode()`, `snapshotDashboard()`, `shareDashboard(self)`, 'removeDashboard(self)']; // entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuFilters
- const childContextMenuFilters = ['!IsNoviceMode()', '!IsNoviceMode()', '!IsNoviceMode()', undefined as any, undefined as any];// entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuScripts
if (Cast(myDashboards.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) {
myDashboards.contextMenuScripts = new List<ScriptField>(contextMenuScripts.map(script => ScriptField.MakeFunction(script)!));
}
@@ -492,31 +501,6 @@ export class CurrentUserUtils {
return myDashboards;
}
- /// initializes the left sidebar Trails pane
- static setupTrails(doc: Doc, field:string) {
- var myTrails = DocCast(doc[field]);
- const reqdBtnOpts:DocumentOptions = { _forceActive: true, _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true,
- title: "New trail", toolTip: "Create new trail", btnType: ButtonType.ClickButton, buttonText: "New trail", icon: "plus", system: true };
- const reqdBtnScript = {onClick: `createNewPresentation()`};
- const newTrailButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myTrails?.buttonMenuDoc), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript);
-
- const reqdOpts:DocumentOptions = {
- title: "My Trails", _showTitle: "title", _height: 100,
- treeViewHideTitle: true, _fitWidth: true, _gridGap: 5, _forceActive: true, childDropAction: "alias",
- treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newTrailButton,
- contextMenuIcons: new List<string>(["plus"]),
- contextMenuLabels: new List<string>(["Create New Trail"]),
- _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true,
- explainer: "All of the trails that you have created will appear here."
- };
- myTrails = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), reqdOpts);
- const contextMenuScripts = [reqdBtnScript.onClick];
- if (Cast(myTrails.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) {
- myTrails.contextMenuScripts = new List<ScriptField>(contextMenuScripts.map(script => ScriptField.MakeFunction(script)!));
- }
- return myTrails;
- }
-
/// initializes the left sidebar File system pane
static setupFilesystem(doc: Doc, field:string) {
var myFilesystem = DocCast(doc[field]);
@@ -597,14 +581,17 @@ export class CurrentUserUtils {
/// initializes the required buttons in the expanding button menu at the bottom of the Dash window
static setupDockedButtons(doc: Doc, field="myDockedBtns") {
const dockedBtns = DocCast(doc[field]);
- const dockBtn = (opts: DocumentOptions, scripts: {[key:string]:string}) =>
+ const dockBtn = (opts: DocumentOptions, scripts: {[key:string]:string}, funcs?: {[key:string]:string}) =>
DocUtils.AssignScripts(DocUtils.AssignOpts(DocListCast(dockedBtns?.data)?.find(doc => doc.title === opts.title), opts) ??
- CurrentUserUtils.createToolButton(opts), scripts);
+ CurrentUserUtils.createToolButton(opts), scripts, funcs);
const btnDescs = [// setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet
{ scripts: { onClick: "undo()"}, opts: { title: "undo", icon: "undo-alt", toolTip: "Click to undo" }},
- { scripts: { onClick: "redo()"}, opts: { title: "redo", icon: "redo-alt", toolTip: "Click to redo" }}
- ];
+ { scripts: { onClick: "redo()"}, opts: { title: "redo", icon: "redo-alt", toolTip: "Click to redo" }},
+ // { scripts: { onClick: 'prevKeyFrame(_readOnly_)'}, opts: { title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, width: 20}},
+ // { scripts: { onClick:""}, opts: { title: "Num", icon: "", toolTip: "Frame Number", btnType: ButtonType.TextButton, width: 20}, funcs: { buttonText: 'selectedDocs()?.lastElement()?.currentFrame.toString()'}},
+ // { scripts: { onClick: 'nextKeyFrame(_readOnly_)'}, opts:{title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, width: 20,} },
+ ];
const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, dontUndo: true, _stayInCollection: true, ...desc.opts}, desc.scripts));
const dockBtnsReqdOpts = {
title: "docked buttons", _height: 40, flexGap: 0, linearViewFloating: true,
@@ -619,8 +606,8 @@ export class CurrentUserUtils {
return [
{ title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, ignoreClick: true, scripts: {script: 'setFont(value, _readOnly_)'},
btnList: new List<string>(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]) },
- { title: "Size", toolTip: "Font size", width: 75, btnType: ButtonType.NumberButton, ignoreClick: true, scripts: {script: '{ return setFontSize(value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 0, numBtnType: NumButtonType.DropdownOptions },
- { title: "Color", toolTip: "Font color", btnType: ButtonType.ColorButton, icon: "font", ignoreClick: true, scripts: {script: '{ return setFontColor(value, _readOnly_); }'}},
+ { title: "Size", toolTip: "Font size", width: 75, btnType: ButtonType.NumberButton, ignoreClick: true, scripts: {script: '{ return setFontSize(value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 0, numBtnType: NumButtonType.DropdownOptions },
+ { title: "Color", toolTip: "Font color", btnType: ButtonType.ColorButton, icon: "font", ignoreClick: true, scripts: {script: '{ return setFontColor(value, _readOnly_);}'}},
{ title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", scripts: {onClick: '{ return toggleBold(_readOnly_); }'} },
{ title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", scripts: {onClick: '{ return toggleItalic(_readOnly_);}'} },
{ title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", scripts: {onClick: '{ return toggleUnderline(_readOnly_);}'} },
@@ -677,15 +664,15 @@ export class CurrentUserUtils {
title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: 'setView(value, _readOnly_)'}},
{ title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "tab")'}, width: 20, scripts: { onClick: 'pinWithView(_readOnly_)'}},
{ title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()'}, width: 20, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}},
- { title: "Num", icon: "", toolTip: "Frame Number", btnType: ButtonType.TextButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()', buttonText: 'selectedDocs()?.lastElement()?.currentFrame.toString()'}, width: 20, scripts: {}},
+ { title: "Num", icon: "", toolTip: "Frame Number", btnType: ButtonType.TextButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: {}},
{ title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()'}, width: 20, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
{ title: "Fill", icon: "fill-drip", toolTip: "Background Fill Color",btnType: ButtonType.ColorButton, funcs: {hidden: '!SelectionManager_selectedDocType()'}, ignoreClick: true, width: 20, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'}}, // Only when a document is selected
{ title: "Header", icon: "heading", toolTip: "Header Color", btnType: ButtonType.ColorButton, funcs: {hidden: '!SelectionManager_selectedDocType()'}, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'}},
{ title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform", true)'}, scripts: { onClick: 'toggleOverlay(_readOnly_)'}}, // Only when floating document is selected in freeform
- { title: "Text", icon: "text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), funcs: {hidden: 'false', linearViewIsExpanded: `SelectionManager_selectedDocType("${DocumentType.RTF}")`} }, // Always available
- { title: "Ink", icon: "ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), funcs: {hidden: 'false', inearViewIsExpanded: `SelectionManager_selectedDocType("${DocumentType.INK}")`} }, // Always available
- { title: "Web", icon: "web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), funcs: {hidden: `!SelectionManager_selectedDocType("${DocumentType.WEB}")`, linearViewIsExpanded: `SelectionManager_selectedDocType("${DocumentType.WEB}")`, } }, // Only when Web is selected
- { title: "Schema", icon: "schema", toolTip: "Schema functions", subMenu: CurrentUserUtils.schemaTools(), funcs: {hidden: `!SelectionManager_selectedDocType(undefined, "${CollectionViewType.Schema}")`, linearViewIsExpanded: `SelectionManager_selectedDocType(undefined, "${CollectionViewType.Schema}")`} } // Only when Schema is selected
+ { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), funcs: {hidden: 'false', linearViewIsExpanded: `SelectionManager_selectedDocType("${DocumentType.RTF}")`} }, // Always available
+ { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), funcs: {hidden: 'false', linearViewIsExpanded: `SelectionManager_selectedDocType("${DocumentType.INK}")`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
+ { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), funcs: {hidden: `!SelectionManager_selectedDocType("${DocumentType.WEB}")`, linearViewIsExpanded: `SelectionManager_selectedDocType("${DocumentType.WEB}")`, } }, // Only when Web is selected
+ { title: "Schema", icon: "Schema", toolTip: "Schema functions", subMenu: CurrentUserUtils.schemaTools(), funcs: {hidden: `!SelectionManager_selectedDocType(undefined, "${CollectionViewType.Schema}")`, linearViewIsExpanded: `SelectionManager_selectedDocType(undefined, "${CollectionViewType.Schema}")`} } // Only when Schema is selected
];
}
@@ -717,13 +704,13 @@ export class CurrentUserUtils {
return this.setupContextMenuButton(params, menuBtnDoc);
} else {
const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit,
- childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: true,
+ childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: params.scripts?.onClick ? false : true,
linearViewSubMenu: true, linearViewExpandable: true, };
const items = params.subMenu?.map(sub =>
this.setupContextMenuButton(sub, DocListCast(menuBtnDoc?.data).find(doc => doc.title === sub.title))
);
return DocUtils.AssignScripts(
- DocUtils.AssignDocField(ctxtMenuBtnsDoc, StrCast(params.title), (opts) => this.linearButtonList(opts, items??[]), reqdSubMenuOpts, items), undefined, params.funcs);
+ DocUtils.AssignDocField(ctxtMenuBtnsDoc, StrCast(params.title), (opts) => this.linearButtonList(opts, items??[]), reqdSubMenuOpts, items), params.scripts, params.funcs);
}
});
return DocUtils.AssignOpts(ctxtMenuBtnsDoc, reqdCtxtOpts, ctxtMenuBtns);
@@ -768,7 +755,7 @@ export class CurrentUserUtils {
childContextMenuLabels: new List<string>(["Add to Dashboards",]),
childContextMenuIcons: new List<string>(["user-plus",]),
"acl-Public": SharingPermissions.Augment, "_acl-Public": SharingPermissions.Augment,
- childDropAction: "alias", system: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 50, _gridGap: 15,
+ childDropAction: "alias", system: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 0, _gridGap: 15,
// NOTE: treeViewHideTitle & _showTitle is for a TreeView's editable title, _showTitle is for DocumentViews title bar
_showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true,
explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'"
@@ -952,6 +939,8 @@ ScriptingGlobals.add(function MySharedDocs() { return Doc.MySharedDocs; }, "docu
ScriptingGlobals.add(function IsNoviceMode() { return Doc.noviceMode; }, "is Dash in novice mode");
ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering");
ScriptingGlobals.add(function createNewPresentation() { return MainView.Instance.createNewPresentation(); }, "creates a new presentation when called");
+ScriptingGlobals.add(function openPresentation(pres:Doc) { return MainView.Instance.openPresentation(pres); }, "creates a new presentation when called");
ScriptingGlobals.add(function createNewFolder() { return MainView.Instance.createNewFolder(); }, "creates a new folder in myFiles when called");
ScriptingGlobals.add(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); }, "returns all the links to the document or its annotations", "(doc: any)");
ScriptingGlobals.add(function importDocument() { return CurrentUserUtils.importDocument(); }, "imports files from device directly into the import sidebar");
+ScriptingGlobals.add(function setInkToolDefaults() { Doc.ActiveTool = InkTool.None; }); \ No newline at end of file
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 52b643c04..50190061a 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -154,7 +154,7 @@ export class DocumentManager {
CollectionDockingView.AddSplit(doc, 'right');
finished?.();
};
- public jumpToDocument = async (
+ public jumpToDocument = (
targetDoc: Doc, // document to display
willZoom: boolean, // whether to zoom doc to take up most of screen
createViewFunc = DocumentManager.addView, // how to create a view of the doc if it doesn't exist
@@ -165,13 +165,13 @@ export class DocumentManager {
finished?: () => void,
originalTarget?: Doc,
noSelect?: boolean,
- presZoom?: number
- ): Promise<void> => {
+ presZoomScale?: number
+ ): void => {
originalTarget = originalTarget ?? targetDoc;
const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView;
const docView = getFirstDocView(targetDoc, originatingDoc);
const annotatedDoc = Cast(targetDoc.annotationOn, Doc, null);
- const resolvedTarget = targetDoc.type === DocumentType.MARKER ? annotatedDoc ?? targetDoc : targetDoc; // if target is a marker, then focus toggling should apply to the document it's on since the marker itself doesn't have a hidden field
+ const resolvedTarget = targetDoc.type === DocumentType.MARKER ? annotatedDoc ?? docView?.rootDoc ?? targetDoc : docView?.rootDoc ?? targetDoc; // if target is a marker, then focus toggling should apply to the document it's on since the marker itself doesn't have a hidden field
var wasHidden = resolvedTarget.hidden;
if (wasHidden) {
runInAction(() => {
@@ -207,7 +207,7 @@ export class DocumentManager {
finished?.();
};
const annoContainerView = (!wasHidden || resolvedTarget !== annotatedDoc) && annotatedDoc && getFirstDocView(annotatedDoc);
- const contextDocs = docContext.length ? await DocListCastAsync(docContext[0].data) : undefined;
+ const contextDocs = docContext.length ? DocListCast(docContext[0].data) : undefined;
const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext.lastElement() : undefined;
const targetDocContext = contextDoc || annotatedDoc;
const targetDocContextView = (targetDocContext && getFirstDocView(targetDocContext)) || (wasHidden && annoContainerView); // if we have an annotation container and the target was hidden, then try again because we just un-hid the document above
@@ -218,7 +218,7 @@ export class DocumentManager {
annoContainerView.focus(targetDoc, {
originalTarget,
willZoom,
- scale: presZoom,
+ scale: presZoomScale,
afterFocus: (didFocus: boolean) =>
new Promise<ViewAdjustment>(res => {
focusAndFinish(true);
@@ -228,7 +228,7 @@ export class DocumentManager {
);
return;
} else if (!docView && targetDoc.type !== DocumentType.MARKER) {
- annoContainerView.focus(targetDoc); // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below
+ annoContainerView.focus(targetDoc, {}); // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below
}
}
if (focusView) {
@@ -237,7 +237,7 @@ export class DocumentManager {
focusView.focus(originalTarget ?? targetDoc, {
originalTarget,
willZoom,
- scale: presZoom,
+ scale: presZoomScale,
afterFocus: (didFocus: boolean) =>
new Promise<ViewAdjustment>(res => {
focusAndFinish(forceDidFocus || didFocus);
@@ -265,7 +265,9 @@ export class DocumentManager {
afterFocus: async () => {
targetDocContext._viewTransition = undefined;
if (targetDocContext.layoutKey === 'layout_icon') {
- targetDocContextView.iconify(() => this.jumpToDocument(resolvedTarget ?? targetDoc, willZoom, createViewFunc, docContext, linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoom));
+ targetDocContextView.iconify(() =>
+ this.jumpToDocument(resolvedTarget ?? targetDoc, willZoom, createViewFunc, docContext, linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoomScale)
+ );
}
return ViewAdjustment.doNothing;
},
@@ -309,7 +311,7 @@ export class DocumentManager {
const docContextView = this.getFirstDocumentView(docContext[0]);
if (docContextView) {
return docContextView.iconify(() =>
- this.jumpToDocument(targetDoc, willZoom, createViewFunc, docContext.slice(1, docContext.length), linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoom)
+ this.jumpToDocument(targetDoc, willZoom, createViewFunc, docContext.slice(1, docContext.length), linkDoc, closeContextIfNotFound, originatingDoc, finished, originalTarget, noSelect, presZoomScale)
);
}
}
@@ -335,7 +337,7 @@ export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) {
const showDoc = context || doc;
const bestAlias = showDoc === Doc.GetProto(showDoc) ? DocListCast(showDoc.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail) : showDoc;
- CollectionDockingView.AddSplit(bestAlias ? bestAlias : Doc.MakeAlias(showDoc), 'right') && context && setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc));
+ CollectionDockingView.AddSplit(bestAlias ? bestAlias : Doc.MakeAlias(showDoc), 'right') && context && setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc, {}));
}
}
ScriptingGlobals.add(DocFocusOrOpen);
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 6386c87a0..664933de0 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -344,8 +344,7 @@ export namespace DragManager {
}
Object.assign(dragDiv.style, { width: '', height: '', overflow: '' });
dragDiv.hidden = false;
- const scaleXs: number[] = [],
- scaleYs: number[] = [],
+ const scalings: number[] = [],
xs: number[] = [],
ys: number[] = [];
@@ -355,8 +354,18 @@ export namespace DragManager {
top: Number.MAX_SAFE_INTEGER,
bottom: Number.MIN_SAFE_INTEGER,
};
+ let rot = 0;
const docsToDrag = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof AnchorAnnoDragData ? [dragData.dragDocument] : [];
const dragElements = eles.map(ele => {
+ let useDim = false;
+ if (ele?.parentElement?.parentElement?.parentElement?.className === 'collectionFreeFormDocumentView-container') {
+ ele = ele.parentElement.parentElement.parentElement;
+ const rotStr = ele.style.transform.replace(/.*rotate\(([-0-9.]*)deg\).*/, '$1');
+ if (rotStr) rot = Number(rotStr);
+ } else {
+ useDim = true;
+ }
+ if (rot < 0) rot += 360;
if (!ele.parentNode) dragDiv.appendChild(ele);
const dragElement = ele.parentNode === dragDiv ? ele : (ele.cloneNode(true) as HTMLElement);
const children = Array.from(dragElement.children);
@@ -376,17 +385,28 @@ export namespace DragManager {
}
}
const rect = ele.getBoundingClientRect();
- const scaleX = rect.width / (ele.offsetWidth || rect.width);
- const scaleY = scaleX; //ele.offsetHeight ? rect.height / (ele.offsetHeight || rect.height) : scaleX;
+ const w = ele.offsetWidth || rect.width;
+ const h = ele.offsetHeight || rect.height;
+ const rotR = -(rot / 180) * Math.PI;
+ const tl = [0, 0];
+ const tr = [Math.cos(rotR) * w, Math.sin(-rotR) * w];
+ const bl = [Math.sin(rotR) * h, Math.cos(-rotR) * h];
+ const br = [Math.cos(rotR) * w + Math.sin(rotR) * h, Math.cos(-rotR) * h - Math.sin(rotR) * w];
+ const minx = Math.min(tl[0], tr[0], br[0], bl[0]);
+ const maxx = Math.max(tl[0], tr[0], br[0], bl[0]);
+ const miny = Math.min(tl[1], tr[1], br[1], bl[1]);
+ const maxy = Math.max(tl[1], tr[1], br[1], bl[1]);
+ const scaling = rect.width / (Math.abs(maxx - minx) || 1);
elesCont.left = Math.min(rect.left, elesCont.left);
elesCont.top = Math.min(rect.top, elesCont.top);
elesCont.right = Math.max(rect.right, elesCont.right);
elesCont.bottom = Math.max(rect.bottom, elesCont.bottom);
- xs.push(rect.left + (options?.offsetX || 0));
- ys.push(rect.top + (options?.offsetY || 0));
- scaleXs.push(scaleX);
- scaleYs.push(scaleY);
+ xs.push(((0 - minx) / (maxx - minx)) * rect.width + rect.left);
+ ys.push(((0 - miny) / (maxy - miny)) * rect.height + rect.top);
+ scalings.push(scaling);
+ const width = useDim ? getComputedStyle(ele).width : '';
+ const height = useDim ? getComputedStyle(ele).height : '';
Object.assign(dragElement.style, {
opacity: '0.7',
position: 'absolute',
@@ -399,9 +419,9 @@ export namespace DragManager {
borderRadius: getComputedStyle(ele).borderRadius,
zIndex: globalCssVariables.contextMenuZindex,
transformOrigin: '0 0',
- width: `${rect.width / scaleX}px`,
- height: `${rect.height / scaleY}px`,
- transform: `translate(${xs[0]}px, ${ys[0]}px) scale(${scaleX}, ${scaleY})`,
+ width,
+ height,
+ transform: `translate(${xs[0]}px, ${ys[0]}px) rotate(${rot}deg) scale(${scaling})`,
});
dragLabel.style.transform = `translate(${xs[0]}px, ${ys[0] - 20}px)`;
@@ -542,7 +562,7 @@ export namespace DragManager {
const moveVec = { x: x - lastPt.x, y: y - lastPt.y };
lastPt = { x, y };
- dragElements.map((dragElement, i) => (dragElement.style.transform = `translate(${(xs[i] += moveVec.x)}px, ${(ys[i] += moveVec.y)}px) scale(${scaleXs[i]}, ${scaleYs[i]})`));
+ dragElements.map((dragElement, i) => (dragElement.style.transform = `translate(${(xs[i] += moveVec.x)}px, ${(ys[i] += moveVec.y)}px) rotate(${rot}deg) scale(${scalings[i]})`));
dragLabel.style.transform = `translate(${xs[0]}px, ${ys[0] - 20}px)`;
};
const upHandler = (e: PointerEvent) => {
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 4af51b9a0..85700da37 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -230,58 +230,33 @@ export namespace InteractionUtils {
points.push({ X: right, Y: bottom });
points.push({ X: left, Y: bottom });
points.push({ X: left, Y: top });
+ break;
case 'triangle':
- // points.push({ X: left, Y: bottom });
- // points.push({ X: right, Y: bottom });
- // points.push({ X: (right + left) / 2, Y: top });
- // points.push({ X: left, Y: bottom });
-
- points.push({ X: left, Y: bottom });
points.push({ X: left, Y: bottom });
-
- points.push({ X: right, Y: bottom });
- points.push({ X: right, Y: bottom });
points.push({ X: right, Y: bottom });
- points.push({ X: right, Y: bottom });
-
- points.push({ X: (right + left) / 2, Y: top });
- points.push({ X: (right + left) / 2, Y: top });
points.push({ X: (right + left) / 2, Y: top });
- points.push({ X: (right + left) / 2, Y: top });
-
- points.push({ X: left, Y: bottom });
points.push({ X: left, Y: bottom });
+ break;
case 'circle':
const centerX = (Math.max(left, right) + Math.min(left, right)) / 2;
const centerY = (Math.max(top, bottom) + Math.min(top, bottom)) / 2;
const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom));
- if (centerX - Math.min(left, right) < centerY - Math.min(top, bottom)) {
- for (var y = Math.min(top, bottom); y < Math.max(top, bottom); y++) {
- const x = Math.sqrt(Math.pow(radius, 2) - Math.pow(y - centerY, 2)) + centerX;
- points.push({ X: x, Y: y });
- }
- for (var y = Math.max(top, bottom); y > Math.min(top, bottom); y--) {
- const x = Math.sqrt(Math.pow(radius, 2) - Math.pow(y - centerY, 2)) + centerX;
- const newX = centerX - (x - centerX);
- points.push({ X: newX, Y: y });
- }
- points.push({ X: Math.sqrt(Math.pow(radius, 2) - Math.pow(Math.min(top, bottom) - centerY, 2)) + centerX, Y: Math.min(top, bottom) });
- } else {
- for (var x = Math.min(left, right); x < Math.max(left, right); x++) {
- const y = Math.sqrt(Math.pow(radius, 2) - Math.pow(x - centerX, 2)) + centerY;
- points.push({ X: x, Y: y });
- }
- for (var x = Math.max(left, right); x > Math.min(left, right); x--) {
- const y = Math.sqrt(Math.pow(radius, 2) - Math.pow(x - centerX, 2)) + centerY;
- const newY = centerY - (y - centerY);
- points.push({ X: x, Y: newY });
- }
- points.push({ X: Math.min(left, right), Y: Math.sqrt(Math.pow(radius, 2) - Math.pow(Math.min(left, right) - centerX, 2)) + centerY });
+ for (var x = Math.min(left, right); x < Math.max(left, right); x++) {
+ const y = Math.sqrt(Math.pow(radius, 2) - Math.pow(x - centerX, 2)) + centerY;
+ points.push({ X: x, Y: y });
}
+ for (var x = Math.max(left, right); x > Math.min(left, right); x--) {
+ const y = Math.sqrt(Math.pow(radius, 2) - Math.pow(x - centerX, 2)) + centerY;
+ const newY = centerY - (y - centerY);
+ points.push({ X: x, Y: newY });
+ }
+ points.push({ X: Math.min(left, right), Y: Math.sqrt(Math.pow(radius, 2) - Math.pow(Math.min(left, right) - centerX, 2)) + centerY });
+ break;
+
case 'line':
points.push({ X: left, Y: top });
points.push({ X: right, Y: bottom });
- return points;
+ break;
}
return points;
}
diff --git a/src/client/util/ReportManager.tsx b/src/client/util/ReportManager.tsx
index 55c5ca87f..51742d455 100644
--- a/src/client/util/ReportManager.tsx
+++ b/src/client/util/ReportManager.tsx
@@ -57,7 +57,7 @@ export class ReportManager extends React.Component<{}> {
ReportManager.Instance = this;
this.octokit = new Octokit({
- auth: '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'
+ auth: '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'
});
}
@@ -104,6 +104,20 @@ export class ReportManager extends React.Component<{}> {
}
}
+ // turns an upload link into a servable link
+ // ex:
+ // C: /Users/dash/Documents/GitHub/Dash-Web/src/server/public/files/images/upload_8008dbc4b6424fbff14da7345bb32eb2.png
+ // -> http://localhost:1050/files/images/upload_8008dbc4b6424fbff14da7345bb32eb2_l.png
+ private fileLinktoServerLink = (fileLink: string) => {
+ const serverUrl = 'https://browndash.com/';
+
+ const regex = 'public'
+ const publicIndex = fileLink.indexOf(regex) + regex.length;
+
+ const finalUrl = `${serverUrl}${fileLink.substring(publicIndex + 1).replace('.', '_l.')}`;
+ return finalUrl;
+ }
+
public async reportIssue() {
if (this.bugTitle === '' || this.bugDescription === ''
|| this.bugType === '' || this.bugPriority === '') {
@@ -111,14 +125,15 @@ export class ReportManager extends React.Component<{}> {
return;
}
-
if (this.toGithub) {
+ const formattedLinks = (this.fileLinks ?? []).map(this.fileLinktoServerLink)
+
const req = await this.octokit.request('POST /repos/{owner}/{repo}/issues', {
owner: 'brown-dash',
repo: 'Dash-Web',
title: this.formatTitle(this.bugTitle, Doc.CurrentUserEmail),
- body: `${this.bugDescription} \n\nfiles:\n${(this.fileLinks ?? []).join('\n')}`,
+ body: `${this.bugDescription} \n\nfiles:\n${formattedLinks.join('\n')}`,
labels: [
'from-dash-app',
this.bugType,
@@ -140,7 +155,7 @@ export class ReportManager extends React.Component<{}> {
// if we're down here, then we're good to go. reset the fields.
this.setBugTitle('');
this.setBugDescription('');
- this.toGithub = false;
+ // this.toGithub = false;
this.setFileLinks([]);
this.setBugType('');
this.setBugPriority('');
@@ -176,10 +191,10 @@ export class ReportManager extends React.Component<{}> {
(<div className="settings-content">
<h3 style={{ 'textDecoration': 'underline'}}>Report an Issue</h3>
<label>Please leave a title for the bug.</label><br />
- <input type="text" placeholder='title' onChange={(e) => this.bugTitle = e.target.value} required/>
+ <input type="text" placeholder='title' onChange={(e) => this.setBugTitle(e.target.value)} required/>
<br />
<label>Please leave a description for the bug and how it can be recreated.</label>
- <textarea placeholder='description' onChange={(e) => this.bugDescription = e.target.value} required/>
+ <textarea placeholder='description' onChange={(e) => this.setBugDescription(e.target.value)} required/>
<br />
{/* {<label>Send to github issues? </label>
<input type="checkbox" onChange={(e) => this.toGithub = e.target.checked} />
@@ -187,14 +202,14 @@ export class ReportManager extends React.Component<{}> {
<label>Please label the issue</label>
<div className='flex-select'>
- <select name="bugType">
+ <select name="bugType" onChange={e => this.bugType = e.target.value}>
<option value="" disabled selected>Type</option>
<option value="bug">Bug</option>
<option value="cosmetic">Poor Design or Cosmetic</option>
<option value="documentation">Poor Documentation</option>
</select>
- <select name="bigPriority">
+ <select name="bigPriority" onChange={e => this.bugPriority = e.target.value}>
<option value="" disabled selected>Priority</option>
<option value="priority-low">Low</option>
<option value="priority-medium">Medium</option>
@@ -205,7 +220,7 @@ export class ReportManager extends React.Component<{}> {
<div>
<label>Upload media that shows the bug (optional)</label>
- <input type="file" name="file" multiple accept='audio/*, video/*' onChange={e => this.uploadFiles(e.target)}/>
+ <input type="file" name="file" multiple accept='audio/*, video/*, image/*' onChange={e => this.uploadFiles(e.target)}/>
</div>
<br />
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index ea2bf6551..6dcdcb71b 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -7,6 +7,8 @@
import * as typescriptlib from '!!raw-loader!./type_decls.d';
import * as ts from 'typescript';
import { Doc, Field } from '../../fields/Doc';
+import { ObjectField } from '../../fields/ObjectField';
+import { ScriptField } from '../../fields/ScriptField';
import { scriptingGlobals, ScriptingGlobals } from './ScriptingGlobals';
export { ts };
@@ -177,6 +179,10 @@ function forEachNode(node: ts.Node, onEnter: Traverser, onExit?: Traverser, inde
}
export function CompileScript(script: string, options: ScriptOptions = {}): CompileResult {
+ const captured = options.capturedVariables ?? {};
+ const signature = Object.keys(captured).reduce((p, v) => p + `${v}=${captured[v] instanceof ObjectField ? 'XXX' : captured[v].toString()}`, '');
+ const found = ScriptField.GetScriptFieldCache(script + ':' + signature);
+ if (found) return found as CompiledScript;
const { requiredType = '', addReturn = false, params = {}, capturedVariables = {}, typecheck = true } = options;
if (options.params && !options.params.this) options.params.this = Doc.name;
if (options.params && !options.params.self) options.params.self = Doc.name;
@@ -241,6 +247,8 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp
if (options.globals) {
ScriptingGlobals.resetScriptingGlobals();
}
+ !signature.includes('XXX') && ScriptField._scriptFieldCache.set(script + ':' + signature, result as CompiledScript);
+ //console.log('COMPILED: ' + script + ':' + signature);
return result;
}
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 7a555d5f8..a3d6f5227 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -91,7 +91,7 @@ export namespace SelectionManager {
}
export function Views(): Array<DocumentView> {
- return Array.from(manager.SelectedViews.keys()).filter(dv => manager.SelectedViews.get(dv)?._viewType !== CollectionViewType.Docking);
+ return Array.from(manager.SelectedViews.keys()); //.filter(dv => manager.SelectedViews.get(dv)?._viewType !== CollectionViewType.Docking);
}
export function SelectedSchemaDoc(): Doc | undefined {
return manager.SelectedSchemaDocument;
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index cf143c5e8..a185c8936 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<{}> {
public static Instance: SettingsManager;
static _settingsStyle = addStyleSheet();
- @observable private isOpen = false;
+ @observable public isOpen = false;
@observable private passwordResultText = '';
@observable private playgroundMode = false;
diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss
index 2de636f21..932e94664 100644
--- a/src/client/util/SharingManager.scss
+++ b/src/client/util/SharingManager.scss
@@ -107,7 +107,7 @@
.user-sort {
text-align: left;
margin-left: 10;
- width: 100px;
+ width: 100%;
cursor: pointer;
}
@@ -122,6 +122,7 @@
background: #e8e8e8;
padding-left: 10px;
padding-right: 10px;
+ width: 100%;
overflow-y: scroll;
overflow-x: hidden;
text-align: left;
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 895bd3374..4b0310e76 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -374,7 +374,7 @@ export class SharingManager extends React.Component<{}> {
if (!uniform) dropdownValues.unshift('-multiple-');
if (override) dropdownValues.unshift('None');
return dropdownValues
- .filter(permission => !Doc.noviceMode || ![SharingPermissions.View, SharingPermissions.SelfEdit].includes(permission as any))
+ .filter(permission => !Doc.noviceMode || ![SharingPermissions.SelfEdit].includes(permission as any))
.map(permission => (
<option key={permission} value={permission}>
{permission}
diff --git a/src/client/util/request-image-size.js b/src/client/util/request-image-size.js
index beb030635..502e0fbac 100644
--- a/src/client/util/request-image-size.js
+++ b/src/client/util/request-image-size.js
@@ -15,15 +15,18 @@ const HttpError = require('standard-http-error');
module.exports = function requestImageSize(options) {
let opts = {
- encoding: null
+ encoding: null,
};
if (options && typeof options === 'object') {
opts = Object.assign(options, opts);
} else if (options && typeof options === 'string') {
- opts = Object.assign({
- uri: options
- }, opts);
+ opts = Object.assign(
+ {
+ uri: options,
+ },
+ opts
+ );
} else {
return Promise.reject(new Error('You should provide an URI string or a "request" options object.'));
}
@@ -38,9 +41,8 @@ module.exports = function requestImageSize(options) {
return reject(new HttpError(res.statusCode, res.statusMessage));
}
- let buffer = new Buffer.from([]);
+ let buffer = Buffer.from([]);
let size;
- let imageSizeError;
res.on('data', chunk => {
buffer = Buffer.concat([buffer, chunk]);
@@ -48,8 +50,8 @@ module.exports = function requestImageSize(options) {
try {
size = imageSize(buffer);
} catch (err) {
- imageSizeError = err;
- return;
+ reject(err);
+ return req.abort();
}
if (size) {
@@ -58,11 +60,11 @@ module.exports = function requestImageSize(options) {
}
});
- res.on('error', err => reject(err));
+ res.on('error', reject);
res.on('end', () => {
if (!size) {
- return reject(imageSizeError);
+ return reject(new Error('Image has no size'));
}
size.downloaded = buffer.length;
@@ -70,6 +72,6 @@ module.exports = function requestImageSize(options) {
});
});
- req.on('error', err => reject(err));
+ req.on('error', reject);
});
-}; \ No newline at end of file
+};