aboutsummaryrefslogtreecommitdiff
path: root/src/client/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util')
-rw-r--r--src/client/util/CurrentUserUtils.ts109
-rw-r--r--src/client/util/DocumentManager.ts10
-rw-r--r--src/client/util/DragManager.ts20
-rw-r--r--src/client/util/InteractionUtils.tsx79
-rw-r--r--src/client/util/ReportManager.tsx2
-rw-r--r--src/client/util/SelectionManager.ts2
-rw-r--r--src/client/util/SettingsManager.tsx24
-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
-rw-r--r--src/client/util/type_decls.d3
11 files changed, 131 insertions, 149 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 9d3f19e50..a2974177e 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1,15 +1,18 @@
+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";
+import { GestureUtils } from "../../pen-gestures/GestureUtils";
import { OmitKeys, Utils } from "../../Utils";
import { DocServer } from "../DocServer";
import { Docs, DocumentOptions, DocUtils, FInfo } from "../documents/Documents";
@@ -43,7 +46,7 @@ interface Button {
buttonText?: string;
// fields that do not correspond to DocumentOption fields
- scripts?: { script?: string; onClick?: string; }
+ scripts?: { script?: string; onClick?: string; onDoubleClick?: string }
funcs?: { [key:string]: string };
subMenu?: Button[];
}
@@ -154,7 +157,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)
@@ -206,7 +209,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},
@@ -268,7 +271,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,
@@ -322,16 +325,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)'}}));
}
@@ -459,28 +463,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,
+ targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true, treeViewTruncateTitleWidth: 350, 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)!));
}
@@ -493,31 +502,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]);
@@ -534,7 +518,7 @@ export class CurrentUserUtils {
const reqdOpts:DocumentOptions = { _showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true,
title: "My Documents", buttonMenu: true, buttonMenuDoc: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", system: true,
isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, boxShadow: "0 0", childDontRegisterViews: true,
- treeViewTruncateTitleWidth: 150, ignoreClick: true, childDropAction: "alias",
+ treeViewTruncateTitleWidth: 350, ignoreClick: true, childDropAction: "alias",
childContextMenuLabels: new List<string>(["Create new folder"]),
childContextMenuIcons: new List<string>(["plus"]),
explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard."
@@ -551,7 +535,7 @@ export class CurrentUserUtils {
static setupRecentlyClosed(doc: Doc, field:string) {
const reqdOpts:DocumentOptions = { _showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true,
title: "My Recently Closed", buttonMenu: true, childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "alias", system: true,
- treeViewTruncateTitleWidth: 150, ignoreClick: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same",
+ treeViewTruncateTitleWidth: 350, ignoreClick: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same",
contextMenuLabels: new List<string>(["Empty recently closed"]),
contextMenuIcons:new List<string>(["trash"]),
explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list."
@@ -577,7 +561,7 @@ export class CurrentUserUtils {
const reqdOpts:DocumentOptions = {
_lockedPosition: true, _gridGap: 5, _forceActive: true, title: Doc.CurrentUserEmail +"-view",
boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, system: true,
- treeViewHideTitle: true, treeViewTruncateTitleWidth: 150
+ treeViewHideTitle: true, treeViewTruncateTitleWidth: 350
};
if (!doc[field]) DocUtils.AssignOpts(doc, {treeViewOpen: true, treeViewExpandedView: "fields" });
return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, [doc]);
@@ -644,13 +628,13 @@ export class CurrentUserUtils {
static inkTools():Button[] {
return [
- { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", scripts: {onClick:'{ return setActiveTool("pen", _readOnly_);}' }},
- { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", scripts: {onClick:'{ return setActiveTool("write", _readOnly_);}'} },
- { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", scripts: {onClick:'{ return setActiveTool("eraser", _readOnly_);}' }},
+ { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", scripts: {onClick:'{ return setActiveTool("pen", false, _readOnly_);}' }},
+ { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", scripts: {onClick:'{ return setActiveTool("write", false, _readOnly_);}'} },
+ { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", scripts: {onClick:'{ return setActiveTool("eraser", false, _readOnly_);}' }},
// { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", scripts:{onClick: 'setActiveTool("highlighter")'} },
- { title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", scripts: {onClick:'{ return setActiveTool("circle", _readOnly_);}'} },
- // { title: "Square", toolTip: "Square (Ctrl+Shift+S)", btnType: ButtonType.ToggleButton, icon: "square", click: 'setActiveTool("square")' },
- { title: "Line", toolTip: "Line (Ctrl+Shift+L)", btnType: ButtonType.ToggleButton, icon: "minus", scripts: {onClick:'{ return setActiveTool("line", _readOnly_);}' }},
+ { title: "Circle", toolTip: "Circle (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "circle", scripts: {onClick:`{ return setActiveTool("${GestureUtils.Gestures.Circle}", false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool("${GestureUtils.Gestures.Circle}", true, _readOnly_);}`} },
+ { title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square", scripts: {onClick:`{ return setActiveTool("${GestureUtils.Gestures.Rectangle}", false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool("${GestureUtils.Gestures.Rectangle}", true, _readOnly_);}`} },
+ { title: "Line", toolTip: "Line (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "minus", scripts: {onClick:`{ return setActiveTool("${GestureUtils.Gestures.Line}", false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool("${GestureUtils.Gestures.Line}", true, _readOnly_);}`} },
{ title: "Mask", toolTip: "Mask", btnType: ButtonType.ToggleButton, icon: "user-circle", scripts: {onClick:'{ return setIsInkMask(_readOnly_);}'} },
{ title: "Fill", toolTip: "Fill color", btnType: ButtonType.ColorButton, icon: "fill-drip",ignoreClick: true, scripts: {script: '{ return setFillColor(value, _readOnly_);}'} },
{ title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberButton, ignoreClick: true, scripts: {script: '{ return setStrokeWidth(value, _readOnly_);}'}, numBtnType: NumButtonType.Slider, numBtnMin: 1},
@@ -679,17 +663,17 @@ export class CurrentUserUtils {
CollectionViewType.Carousel3D, CollectionViewType.Linear, CollectionViewType.Map,
CollectionViewType.Grid, CollectionViewType.NoteTaking]),
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: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "tab")'}, width: 20, scripts: { onClick: 'pinWithView(_readOnly_, altKey)'}},
{ 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
];
}
@@ -706,7 +690,7 @@ export class CurrentUserUtils {
};
const reqdFuncs:{[key:string]:any} = {
...params.funcs,
- backgroundColor: params.scripts?.onClick /// a bit hacky. if onClick is set, then we assume it returns a color value when queried with '_readOnly_'. This will be true for toggle buttons, but not generally
+ backgroundColor: params.btnType === ButtonType.ToggleButton ? params.scripts?.onClick:undefined /// a bit hacky. if onClick is set, then we assume it returns a color value when queried with '_readOnly_'. This will be true for toggle buttons, but not generally
}
return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdOpts) ?? Docs.Create.FontIconDocument(reqdOpts), params.scripts, reqdFuncs);
}
@@ -721,13 +705,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);
@@ -772,7 +756,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'"
@@ -814,6 +798,7 @@ export class CurrentUserUtils {
doc._raiseWhenDragged ?? (doc._raiseWhenDragged = true);
doc._showLabel ?? (doc._showLabel = true);
doc.textAlign ?? (doc.textAlign = "left");
+ doc.activeTool = InkTool.None;
doc.activeInkColor ?? (doc.activeInkColor = "rgb(0, 0, 0)");;
doc.activeInkWidth ?? (doc.activeInkWidth = 1);
doc.activeInkBezier ?? (doc.activeInkBezier = "0");
@@ -956,6 +941,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 2ca5d1095..b046d950f 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -171,7 +171,7 @@ export class DocumentManager {
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(() => {
@@ -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) {
@@ -244,7 +244,7 @@ export class DocumentManager {
res(ViewAdjustment.doNothing);
}),
});
- if (focusView.props.Document.layoutKey === 'layout_icon') {
+ if (focusView.props.Document.layoutKey === 'layout_icon' && focusView.rootDoc.type !== DocumentType.SCRIPTING) {
focusView.iconify(() => doFocus(true));
} else {
doFocus(false);
@@ -335,9 +335,7 @@ export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) {
} else {
const context = doc.context !== Doc.MyFilesystem && Cast(doc.context, Doc, null);
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(Doc.BestAlias(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 664933de0..36e5a65fb 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -24,7 +24,7 @@ export type dropActionType = 'alias' | 'copy' | 'move' | 'same' | 'proto' | 'non
* @param dropAction: What to do with the document when it is dropped
* @param dragStarted: Method to call when the drag is started
*/
-export function SetupDrag(_reference: React.RefObject<HTMLElement>, docFunc: () => Doc | Promise<Doc> | undefined, moveFunc?: DragManager.MoveFunction, dropAction?: dropActionType, dragStarted?: () => void) {
+export function SetupDrag(_reference: React.RefObject<HTMLElement>, docFunc: () => Doc | Promise<Doc | undefined> | undefined, moveFunc?: DragManager.MoveFunction, dropAction?: dropActionType, dragStarted?: () => void) {
const onRowMove = async (e: PointerEvent) => {
e.stopPropagation();
e.preventDefault();
@@ -206,7 +206,7 @@ export namespace DragManager {
!dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart)
? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result)
: docDragData.dropAction === 'alias'
- ? Doc.MakeAlias(d)
+ ? Doc.BestAlias(d)
: docDragData.dropAction === 'proto'
? Doc.GetProto(d)
: docDragData.dropAction === 'copy'
@@ -260,10 +260,6 @@ export namespace DragManager {
StartDrag([ele], dragData, downX, downY, options);
}
- export function StartImgDrag(ele: HTMLElement, downX: number, downY: number) {
- StartDrag([ele], {}, downX, downY);
- }
-
export function SetSnapLines(horizLines: number[], vertLines: number[]) {
SnappingManager.setSnapLines(horizLines, vertLines);
}
@@ -325,7 +321,7 @@ export namespace DragManager {
export let DocDragData: DocumentDragData | undefined;
export function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) {
if (dragData.dropAction === 'none') return;
- DocDragData = dragData instanceof DocumentDragData ? dragData : undefined;
+ DocDragData = dragData as DocumentDragData;
const batch = UndoManager.StartBatch('dragging');
eles = eles.filter(e => e);
CanEmbed = dragData.canEmbed || false;
@@ -357,15 +353,15 @@ export namespace DragManager {
let rot = 0;
const docsToDrag = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof AnchorAnnoDragData ? [dragData.dragDocument] : [];
const dragElements = eles.map(ele => {
- let useDim = false;
+ // bcz: very hacky -- if dragged element is a freeForm view with a rotation, then extract the rotation in order to apply it to the dragged element
+ let useDim = false; // if doc is rotated by freeformview, then the dragged elements width and height won't reflect the unrotated dimensions, so we need to rely on the element knowing its own width/height. \
+ // if the parent isn't a freeform view, then the element's width and height are presumed to match the acutal doc's dimensions (eg, dragging from import sidebar menu)
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);
+ rot = Number(ele.style.transform.replace(/.*rotate\(([-0-9.e]*)deg\).*/, '$1') || 0);
} 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);
@@ -387,7 +383,7 @@ export namespace DragManager {
const rect = ele.getBoundingClientRect();
const w = ele.offsetWidth || rect.width;
const h = ele.offsetHeight || rect.height;
- const rotR = -(rot / 180) * Math.PI;
+ const rotR = -((rot < 0 ? rot + 360 : 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];
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 4af51b9a0..3cdf4dbd2 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -1,4 +1,5 @@
import React = require('react');
+import { GestureUtils } from '../../pen-gestures/GestureUtils';
import { Utils } from '../../Utils';
import './InteractionUtils.scss';
@@ -186,7 +187,7 @@ export namespace InteractionUtils {
export function makePolygon(shape: string, points: { X: number; Y: number }[]) {
if (points.length > 1 && points[points.length - 1].X === points[0].X && points[points.length - 1].Y + 1 === points[0].Y) {
//pointer is up (first and last points are the same)
- if (shape === 'arrow' || shape === 'line' || shape === 'circle') {
+ if (shape === GestureUtils.Gestures.Arrow || shape === GestureUtils.Gestures.Line || shape === GestureUtils.Gestures.Circle) {
//if arrow or line, the two end points should be the starting and the ending point
var left = points[0].X;
var top = points[0].Y;
@@ -208,7 +209,7 @@ export namespace InteractionUtils {
left = points[0].X;
bottom = points[points.length - 1].Y;
top = points[0].Y;
- if (shape !== 'arrow' && shape !== 'line' && shape !== 'circle') {
+ if (shape !== GestureUtils.Gestures.Arrow && shape !== GestureUtils.Gestures.Line && shape !== GestureUtils.Gestures.Circle) {
//switch left/right and top/bottom if needed
if (left > right) {
const temp = right;
@@ -224,64 +225,39 @@ export namespace InteractionUtils {
}
points = [];
switch (shape) {
- case 'rectangle':
+ case GestureUtils.Gestures.Rectangle:
points.push({ X: left, Y: top });
points.push({ X: right, Y: top });
points.push({ X: right, Y: bottom });
points.push({ X: left, Y: bottom });
points.push({ X: left, Y: top });
- 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 });
+ break;
+ case GestureUtils.Gestures.Triangle:
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 });
- case 'circle':
+ break;
+ case GestureUtils.Gestures.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 = centerX - radius; x < centerX + radius; x++) {
+ const y = Math.sqrt(Math.pow(radius, 2) - Math.pow(x - centerX, 2)) + centerY;
+ points.push({ X: x, Y: y });
}
- case 'line':
+ for (var x = centerX + radius; x > centerX - radius; 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: centerX - radius, Y: Math.sqrt(Math.pow(radius, 2) - Math.pow(-radius, 2)) + centerY });
+ break;
+
+ case GestureUtils.Gestures.Line:
points.push({ X: left, Y: top });
points.push({ X: right, Y: bottom });
- return points;
+ break;
}
return points;
}
@@ -291,17 +267,14 @@ export namespace InteractionUtils {
* @param type - InteractionUtils.(PENTYPE | ERASERTYPE | MOUSETYPE | TOUCHTYPE)
*/
export function IsType(e: PointerEvent | React.PointerEvent, type: string): boolean {
+ // prettier-ignore
switch (type) {
// pen and eraser are both pointer type 'pen', but pen is button 0 and eraser is button 5. -syip2
- case PENTYPE:
- return e.pointerType === PENTYPE && (e.button === -1 || e.button === 0);
- case ERASERTYPE:
- return e.pointerType === PENTYPE && e.button === (e instanceof PointerEvent ? ERASER_BUTTON : ERASER_BUTTON);
- case TOUCHTYPE:
- return e.pointerType === TOUCHTYPE;
- default:
- return e.pointerType === type;
+ case PENTYPE: return e.pointerType === PENTYPE && (e.button === -1 || e.button === 0);
+ case ERASERTYPE: return e.pointerType === PENTYPE && e.button === (e instanceof PointerEvent ? ERASER_BUTTON : ERASER_BUTTON);
+ case TOUCHTYPE: return e.pointerType === TOUCHTYPE;
}
+ return e.pointerType === type;
}
/**
diff --git a/src/client/util/ReportManager.tsx b/src/client/util/ReportManager.tsx
index 180d8294f..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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'
});
}
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..5c1c836f7 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -26,11 +26,16 @@ export enum ColorScheme {
System = '-MatchSystem',
}
+export enum freeformScrollMode {
+ Pan = 'pan',
+ Zoom = 'zoom'
+}
+
@observer
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;
@@ -186,6 +191,10 @@ export class SettingsManager extends React.Component<{}> {
<input type="checkbox" onChange={e => FontIconBox.SetShowLabels(!FontIconBox.GetShowLabels())} checked={FontIconBox.GetShowLabels()} />
<div className="preferences-check">Show button labels</div>
</div>
+ <div>
+ <input type="checkbox" onChange={e => FontIconBox.SetRecognizeGesturs(!FontIconBox.GetRecognizeGestures())} checked={FontIconBox.GetRecognizeGestures()} />
+ <div className="preferences-check">Recognize ink Gesturs</div>
+ </div>
</div>
);
}
@@ -298,6 +307,12 @@ export class SettingsManager extends React.Component<{}> {
);
}
+
+
+ setFreeformScrollMode = (mode: freeformScrollMode) => {
+ Doc.UserDoc().freeformScrollMode = mode;
+ }
+
@computed get modesContent() {
return (
<div className="tab-content modes-content">
@@ -319,6 +334,13 @@ export class SettingsManager extends React.Component<{}> {
<div className="playground-text">Playground Mode</div>
</div>
</div>
+ <div className="tab-column-title">Freeform scroll mode</div>
+ <div>
+ <button onClick={() => this.setFreeformScrollMode(freeformScrollMode.Pan)}>Scroll to pan</button>
+ <div>Scrolling pans around the freeform, holding shift and scrolling zooms in and out.</div>
+ <button onClick={() => this.setFreeformScrollMode(freeformScrollMode.Zoom)}>Scroll to zoom</button>
+ <div>Scrolling zooms in and out of canvas</div>
+ </div>
</div>
<div className="tab-column">
<div className="tab-column-title">Permissions</div>
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
+};
diff --git a/src/client/util/type_decls.d b/src/client/util/type_decls.d
index 9063dc894..1a93bbe59 100644
--- a/src/client/util/type_decls.d
+++ b/src/client/util/type_decls.d
@@ -67,6 +67,9 @@ interface RegExp {
readonly sticky: boolean;
readonly unicode: boolean;
}
+interface Date {
+ now() : string;
+}
interface String {
codePointAt(pos: number): number | undefined;
includes(searchString: string, position?: number): boolean;