aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/PropertiesButtons.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/PropertiesButtons.tsx')
-rw-r--r--src/client/views/PropertiesButtons.tsx386
1 files changed, 258 insertions, 128 deletions
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 9c6d9a108..8c4c1d00b 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -1,221 +1,345 @@
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@material-ui/core';
-import { action, computed, observable } from "mobx";
-import { observer } from "mobx-react";
-import { Doc, Opt } from "../../fields/Doc";
-import { Id } from "../../fields/FieldSymbols";
+import { action, computed, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import { Doc, Opt } from '../../fields/Doc';
+import { Id } from '../../fields/FieldSymbols';
import { InkField } from '../../fields/InkField';
import { RichTextField } from '../../fields/RichTextField';
-import { BoolCast, StrCast } from "../../fields/Types";
-import { ImageField } from "../../fields/URLField";
+import { BoolCast, StrCast } from '../../fields/Types';
+import { ImageField } from '../../fields/URLField';
import { DocUtils } from '../documents/Documents';
-import { DocumentType } from '../documents/DocumentTypes';
+import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
import { SelectionManager } from '../util/SelectionManager';
import { undoBatch } from '../util/UndoManager';
-import { CollectionViewType } from './collections/CollectionView';
-import { Colors } from "./global/globalEnums";
+import { Colors } from './global/globalEnums';
import { InkingStroke } from './InkingStroke';
import { DocumentView } from './nodes/DocumentView';
-import { VideoBox } from "./nodes/VideoBox";
-import { pasteImageBitmap } from "./nodes/WebBoxRenderer";
+import { VideoBox } from './nodes/VideoBox';
+import { pasteImageBitmap } from './nodes/WebBoxRenderer';
import './PropertiesButtons.scss';
-import React = require("react");
-const higflyout = require("@hig/flyout");
+import React = require('react');
+const higflyout = require('@hig/flyout');
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
enum UtilityButtonState {
Default,
OpenRight,
- OpenExternally
+ OpenExternally,
}
@observer
export class PropertiesButtons extends React.Component<{}, {}> {
@observable public static Instance: PropertiesButtons;
- @computed get selectedDoc() { return SelectionManager.SelectedSchemaDoc() || SelectionManager.Views().lastElement()?.rootDoc; }
- @computed get selectedTabView() { return !SelectionManager.SelectedSchemaDoc() && SelectionManager.Views().lastElement()?.topMost; }
+ @computed get selectedDoc() {
+ return SelectionManager.SelectedSchemaDoc() || SelectionManager.Views().lastElement()?.rootDoc;
+ }
+ @computed get selectedTabView() {
+ return !SelectionManager.SelectedSchemaDoc() && SelectionManager.Views().lastElement()?.topMost;
+ }
propertyToggleBtn = (label: string, property: string, tooltip: (on?: any) => string, icon: (on: boolean) => string, onClick?: (dv: Opt<DocumentView>, doc: Doc, property: string) => void, useUserDoc?: boolean) => {
const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedDoc;
- const onPropToggle = (dv: Opt<DocumentView>, doc: Doc, prop: string) => (dv?.layoutDoc || doc)[prop] = (dv?.layoutDoc || doc)[prop] ? false : true;
- return !targetDoc ? (null) :
+ const onPropToggle = (dv: Opt<DocumentView>, doc: Doc, prop: string) => ((dv?.layoutDoc || doc)[prop] = (dv?.layoutDoc || doc)[prop] ? false : true);
+ return !targetDoc ? null : (
<Tooltip title={<div className={`dash-tooltip`}>{tooltip(targetDoc?.[property])} </div>} placement="top">
<div>
- <div className={`propertiesButtons-linkButton-empty toggle-${StrCast(targetDoc[property]).includes(":hover") ? "hover" : targetDoc[property] ? "on" : "off"}`}
+ <div
+ className={`propertiesButtons-linkButton-empty toggle-${StrCast(targetDoc[property]).includes(':hover') ? 'hover' : targetDoc[property] ? 'on' : 'off'}`}
onPointerDown={e => e.stopPropagation()}
onClick={undoBatch(() => {
if (SelectionManager.Views().length > 1) {
SelectionManager.Views().forEach(dv => (onClick ?? onPropToggle)(dv, dv.rootDoc, property));
} else if (targetDoc) (onClick ?? onPropToggle)(undefined, targetDoc, property);
- })} >
+ })}>
<FontAwesomeIcon className="documentdecorations-icon" size="lg" icon={icon(BoolCast(targetDoc?.[property])) as any} />
</div>
<div className="propertiesButtons-title">{label}</div>
</div>
- </Tooltip>;
- }
+ </Tooltip>
+ );
+ };
@computed get lockButton() {
- return this.propertyToggleBtn("No\xA0Drag", "_lockedPosition", on => `${on ? "Unlock" : "Lock"} position to prevent dragging`, on => "thumbtack");
+ return this.propertyToggleBtn(
+ 'No\xA0Drag',
+ '_lockedPosition',
+ on => `${on ? 'Unlock' : 'Lock'} position to prevent dragging`,
+ on => 'thumbtack'
+ );
}
@computed get dictationButton() {
- return this.propertyToggleBtn("Dictate", "_showAudio", on => `${on ? "Hide" : "Show"} dictation/recording controls`, on => "microphone");
+ return this.propertyToggleBtn(
+ 'Dictate',
+ '_showAudio',
+ on => `${on ? 'Hide' : 'Show'} dictation/recording controls`,
+ on => 'microphone'
+ );
}
@computed get maskButton() {
- return this.propertyToggleBtn("Mask", "isInkMask", on => on ? "Make plain ink" : "Make highlight mask", on => "paint-brush", (dv, doc) => InkingStroke.toggleMask(dv?.layoutDoc || doc));
+ return this.propertyToggleBtn(
+ 'Mask',
+ 'isInkMask',
+ on => (on ? 'Make plain ink' : 'Make highlight mask'),
+ on => 'paint-brush',
+ (dv, doc) => InkingStroke.toggleMask(dv?.layoutDoc || doc)
+ );
}
@computed get clustersButton() {
- return this.propertyToggleBtn("Clusters", "_useClusters", on => `${on ? "Hide" : "Show"} clusters`, on => "braille");
+ return this.propertyToggleBtn(
+ 'Clusters',
+ '_useClusters',
+ on => `${on ? 'Hide' : 'Show'} clusters`,
+ on => 'braille'
+ );
}
@computed get panButton() {
- return this.propertyToggleBtn("Lock\xA0View", "_lockedTransform", on => `${on ? "Unlock" : "Lock"} panning of view`, on => "lock");
+ return this.propertyToggleBtn(
+ 'Lock\xA0View',
+ '_lockedTransform',
+ on => `${on ? 'Unlock' : 'Lock'} panning of view`,
+ on => 'lock'
+ );
}
@computed get fitContentButton() {
- return this.propertyToggleBtn("View All", "_fitContentsToBox", on => `${on ? "Don't" : "Do"} fit content to container visible area`, on => "eye");
+ return this.propertyToggleBtn(
+ 'View All',
+ '_fitContentsToBox',
+ on => `${on ? "Don't" : 'Do'} fit content to container visible area`,
+ on => 'eye'
+ );
}
@computed get fitWidthButton() {
- return this.propertyToggleBtn("Fit\xA0Width", "_fitWidth", on => `${on ? "Don't" : "Do"} fit content to width of container`, on => "arrows-alt-h");
+ return this.propertyToggleBtn(
+ 'Fit\xA0Width',
+ '_fitWidth',
+ on => `${on ? "Don't" : 'Do'} fit content to width of container`,
+ on => 'arrows-alt-h'
+ );
}
@computed get captionButton() {
- return this.propertyToggleBtn("Caption", "_showCaption", on => `${on ? "Hide" : "Show"} caption footer`, on => "closed-captioning", (dv, doc) => (dv?.rootDoc || doc)._showCaption = (dv?.rootDoc || doc)._showCaption === undefined ? "caption" : undefined);
+ return this.propertyToggleBtn(
+ 'Caption',
+ '_showCaption',
+ on => `${on ? 'Hide' : 'Show'} caption footer`,
+ on => 'closed-captioning',
+ (dv, doc) => ((dv?.rootDoc || doc)._showCaption = (dv?.rootDoc || doc)._showCaption === undefined ? 'caption' : undefined)
+ );
}
@computed get chromeButton() {
- return this.propertyToggleBtn("Controls", "_chromeHidden", on => `${on ? "Show" : "Hide"} editing UI`, on => "edit", (dv, doc) => (dv?.rootDoc || doc)._chromeHidden = !(dv?.rootDoc || doc)._chromeHidden);
+ return this.propertyToggleBtn(
+ 'Controls',
+ '_chromeHidden',
+ on => `${on ? 'Show' : 'Hide'} editing UI`,
+ on => 'edit',
+ (dv, doc) => ((dv?.rootDoc || doc)._chromeHidden = !(dv?.rootDoc || doc)._chromeHidden)
+ );
}
@computed get titleButton() {
- return this.propertyToggleBtn("Title", "_showTitle", on => "Switch between title styles", on => "text-width", (dv, doc) => (dv?.rootDoc || doc)._showTitle = !(dv?.rootDoc || doc)._showTitle ? "title" : (dv?.rootDoc || doc)._showTitle === "title" ? "title:hover" : undefined);
+ return this.propertyToggleBtn(
+ 'Title',
+ '_showTitle',
+ on => 'Switch between title styles',
+ on => 'text-width',
+ (dv, doc) => ((dv?.rootDoc || doc)._showTitle = !(dv?.rootDoc || doc)._showTitle ? 'title' : (dv?.rootDoc || doc)._showTitle === 'title' ? 'title:hover' : undefined)
+ );
}
@computed get autoHeightButton() {
- return this.propertyToggleBtn("Auto\xA0Size", "_autoHeight", on => `Automatical vertical sizing to show all content`, on => "arrows-alt-v");
+ return this.propertyToggleBtn(
+ 'Auto\xA0Size',
+ '_autoHeight',
+ on => `Automatical vertical sizing to show all content`,
+ on => 'arrows-alt-v'
+ );
}
@computed get gridButton() {
- return this.propertyToggleBtn("Grid", "_backgroundGridShow", on => `Display background grid in collection`, on => "border-all");
+ return this.propertyToggleBtn(
+ 'Grid',
+ '_backgroundGridShow',
+ on => `Display background grid in collection`,
+ on => 'border-all'
+ );
}
@computed get groupButton() {
- return this.propertyToggleBtn("Group", "isGroup", on => `Display collection as a Group`, on => "object-group", (dv, doc) => { doc.isGroup = !doc.isGroup; doc.forceActive = doc.isGroup; });
+ return this.propertyToggleBtn(
+ 'Group',
+ 'isGroup',
+ on => `Display collection as a Group`,
+ on => 'object-group',
+ (dv, doc) => {
+ doc.isGroup = !doc.isGroup;
+ doc.forceActive = doc.isGroup;
+ }
+ );
}
@computed get freezeThumb() {
- return this.propertyToggleBtn("Freeze\Thumb", "_thumb-frozen", on => `${on ? "Freeze" : "Unfreeze"} thumbnail`, on => "arrows-alt-h", (dv, doc) => {
- if (doc["thumb-frozen"]) doc["thumb-frozen"] = undefined;
- else {
- document.body.focus(); // so that we can access the clipboard without an error
- setTimeout(() =>
- pasteImageBitmap((data_url: any, error: any) => {
- error && console.log(error);
- data_url && VideoBox.convertDataUri(data_url, doc[Id] + "-thumb-frozen", true).then(
- returnedfilename => doc["thumb-frozen"] = new ImageField(returnedfilename));
- }));
+ return this.propertyToggleBtn(
+ 'FreezeThumb',
+ '_thumb-frozen',
+ on => `${on ? 'Freeze' : 'Unfreeze'} thumbnail`,
+ on => 'arrows-alt-h',
+ (dv, doc) => {
+ if (doc['thumb-frozen']) doc['thumb-frozen'] = undefined;
+ else {
+ document.body.focus(); // so that we can access the clipboard without an error
+ setTimeout(() =>
+ pasteImageBitmap((data_url: any, error: any) => {
+ error && console.log(error);
+ data_url && VideoBox.convertDataUri(data_url, doc[Id] + '-thumb-frozen', true).then(returnedfilename => (doc['thumb-frozen'] = new ImageField(returnedfilename)));
+ })
+ );
+ }
}
- });
+ );
}
@computed get snapButton() {
- return this.propertyToggleBtn("Snap\xA0Lines", "showSnapLines", on => `Display snapping lines when objects are dragged`, on => "border-all", undefined, true);
+ return this.propertyToggleBtn(
+ 'Snap\xA0Lines',
+ 'showSnapLines',
+ on => `Display snapping lines when objects are dragged`,
+ on => 'border-all',
+ undefined,
+ true
+ );
}
@computed
get onClickButton() {
- return !this.selectedDoc ? (null) : <Tooltip title={<div className="dash-tooltip">Choose onClick behavior</div>} placement="top">
- <div>
- <div className="propertiesButtons-linkFlyout">
- <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.onClickFlyout}>
- <div className={"propertiesButtons-linkButton-empty"} onPointerDown={e => e.stopPropagation()} >
- <FontAwesomeIcon className="documentdecorations-icon" icon="mouse-pointer" size="lg" />
- </div>
- </Flyout>
+ return !this.selectedDoc ? null : (
+ <Tooltip title={<div className="dash-tooltip">Choose onClick behavior</div>} placement="top">
+ <div>
+ <div className="propertiesButtons-linkFlyout">
+ <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.onClickFlyout}>
+ <div className={'propertiesButtons-linkButton-empty'} onPointerDown={e => e.stopPropagation()}>
+ <FontAwesomeIcon className="documentdecorations-icon" icon="mouse-pointer" size="lg" />
+ </div>
+ </Flyout>
+ </div>
+ <div className="propertiesButtons-title"> onclick </div>
</div>
- <div className="propertiesButtons-title"> onclick </div>
- </div>
- </Tooltip>;
+ </Tooltip>
+ );
}
@computed
get perspectiveButton() {
- return !this.selectedDoc ? (null) : <Tooltip title={<div className="dash-tooltip">Choose view perspective</div>} placement="top">
- <div>
- <div className="propertiesButtons-linkFlyout">
- <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.onPerspectiveFlyout}>
- <div className={"propertiesButtons-linkButton-empty"} onPointerDown={e => e.stopPropagation()} >
- <FontAwesomeIcon className="documentdecorations-icon" icon="mouse-pointer" size="lg" />
- </div>
- </Flyout>
+ return !this.selectedDoc ? null : (
+ <Tooltip title={<div className="dash-tooltip">Choose view perspective</div>} placement="top">
+ <div>
+ <div className="propertiesButtons-linkFlyout">
+ <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.onPerspectiveFlyout}>
+ <div className={'propertiesButtons-linkButton-empty'} onPointerDown={e => e.stopPropagation()}>
+ <FontAwesomeIcon className="documentdecorations-icon" icon="mouse-pointer" size="lg" />
+ </div>
+ </Flyout>
+ </div>
+ <div className="propertiesButtons-title"> Perspective </div>
</div>
- <div className="propertiesButtons-title"> Perspective </div>
- </div>
- </Tooltip>;
+ </Tooltip>
+ );
}
@undoBatch
handlePerspectiveChange = (e: any) => {
this.selectedDoc && (this.selectedDoc._viewType = e.target.value);
- SelectionManager.Views().filter(dv => dv.docView).map(dv => dv.docView!).forEach(docView => docView.layoutDoc._viewType = e.target.value);
- }
+ SelectionManager.Views()
+ .filter(dv => dv.docView)
+ .map(dv => dv.docView!)
+ .forEach(docView => (docView.layoutDoc._viewType = e.target.value));
+ };
@undoBatch
@action
handleOptionChange = (onClick: string) => {
this.selectedDoc && (this.selectedDoc.onClickBehavior = onClick);
- SelectionManager.Views().filter(dv => dv.docView).map(dv => dv.docView!).forEach(docView => {
- docView.noOnClick();
- switch (onClick) {
- case "enterPortal": docView.makeIntoPortal(); break;
- case "toggleDetail": docView.setToggleDetail(); break;
- case "linkInPlace": docView.toggleFollowLink("inPlace", true, false); break;
- case "linkOnRight": docView.toggleFollowLink("add:right", false, false); break;
- }
- });
- }
+ SelectionManager.Views()
+ .filter(dv => dv.docView)
+ .map(dv => dv.docView!)
+ .forEach(docView => {
+ docView.noOnClick();
+ switch (onClick) {
+ case 'enterPortal':
+ docView.makeIntoPortal();
+ break;
+ case 'toggleDetail':
+ docView.setToggleDetail();
+ break;
+ case 'linkInPlace':
+ docView.toggleFollowLink('inPlace', true, false);
+ break;
+ case 'linkOnRight':
+ docView.toggleFollowLink('add:right', false, false);
+ break;
+ }
+ });
+ };
@undoBatch
editOnClickScript = () => {
- if (SelectionManager.Views().length) SelectionManager.Views().forEach(dv => DocUtils.makeCustomViewClicked(dv.rootDoc, undefined, "onClick"));
- else this.selectedDoc && DocUtils.makeCustomViewClicked(this.selectedDoc, undefined, "onClick");
- }
+ if (SelectionManager.Views().length) SelectionManager.Views().forEach(dv => DocUtils.makeCustomViewClicked(dv.rootDoc, undefined, 'onClick'));
+ else this.selectedDoc && DocUtils.makeCustomViewClicked(this.selectedDoc, undefined, 'onClick');
+ };
@computed
get onClickFlyout() {
const buttonList = [
- ["nothing", "Select Document"],
- ["enterPortal", "Enter Portal"],
- ["toggleDetail", "Toggle Detail"],
- ["linkInPlace", "Follow Link"],
- ["linkOnRight", "Open Link on Right"]
+ ['nothing', 'Select Document'],
+ ['enterPortal', 'Enter Portal'],
+ ['toggleDetail', 'Toggle Detail'],
+ ['linkInPlace', 'Follow Link'],
+ ['linkOnRight', 'Open Link on Right'],
];
const currentSelection = this.selectedDoc.onClickBehavior;
// Get items to place into the list
- const list = buttonList.map((value) => {
+ const list = buttonList.map(value => {
const click = () => {
this.handleOptionChange(value[0]);
};
- return <div className="list-item" key={`${value}`}
- style={{
- backgroundColor: value[0] === currentSelection ? Colors.LIGHT_BLUE : undefined
- }}
- onClick={click}>
- {value[1]}
- </div>;
+ return (
+ <div
+ className="list-item"
+ key={`${value}`}
+ style={{
+ backgroundColor: value[0] === currentSelection ? Colors.LIGHT_BLUE : undefined,
+ }}
+ onClick={click}>
+ {value[1]}
+ </div>
+ );
});
- return <div>
+ return (
<div>
- <div className="propertiesButton-dropdownList">
- {list}
+ <div>
+ <div className="propertiesButton-dropdownList">{list}</div>
</div>
+ {Doc.noviceMode ? null : (
+ <div onPointerDown={this.editOnClickScript} className="onClickFlyout-editScript">
+ {' '}
+ Edit onClick Script
+ </div>
+ )}
</div>
- {Doc.noviceMode ? (null) : <div onPointerDown={this.editOnClickScript} className="onClickFlyout-editScript"> Edit onClick Script</div>}
- </div>;
+ );
}
@computed
get onPerspectiveFlyout() {
const excludedViewTypes = [CollectionViewType.Invalid, CollectionViewType.Docking, CollectionViewType.Pile, CollectionViewType.StackedTimeline, CollectionViewType.Linear];
- const makeLabel = (value: string, label: string) => <div className="radio" key={label}>
- <label>
- <input type="radio" value={value} checked={(this.selectedDoc?._viewType ?? "invalid") === value} onChange={this.handlePerspectiveChange} />
- {label}
- </label>
- </div>;
- return <form>
- {Object.values(CollectionViewType).filter(type => !excludedViewTypes.includes(type)).map(type => makeLabel(type, type))}
- </form>;
+ const makeLabel = (value: string, label: string) => (
+ <div className="radio" key={label}>
+ <label>
+ <input type="radio" value={value} checked={(this.selectedDoc?._viewType ?? 'invalid') === value} onChange={this.handlePerspectiveChange} />
+ {label}
+ </label>
+ </div>
+ );
+ return (
+ <form>
+ {Object.values(CollectionViewType)
+ .filter(type => !excludedViewTypes.includes(type))
+ .map(type => makeLabel(type, type))}
+ </form>
+ );
}
render() {
@@ -228,27 +352,33 @@ export class PropertiesButtons extends React.Component<{}, {}> {
const isFreeForm = this.selectedDoc?._viewType === CollectionViewType.Freeform;
const isTree = this.selectedDoc?._viewType === CollectionViewType.Tree;
const isTabView = this.selectedTabView;
- const toggle = (ele: JSX.Element | null, style?: React.CSSProperties) => <div className="propertiesButtons-button" style={style}> {ele} </div>;
+ const toggle = (ele: JSX.Element | null, style?: React.CSSProperties) => (
+ <div className="propertiesButtons-button" style={style}>
+ {' '}
+ {ele}{' '}
+ </div>
+ );
const isNovice = Doc.noviceMode;
- return !this.selectedDoc ? (null) :
+ return !this.selectedDoc ? null : (
<div className="propertiesButtons">
{toggle(this.titleButton)}
{toggle(this.captionButton)}
{toggle(this.lockButton)}
- {toggle(this.dictationButton, { display: isNovice ? "none" : "" })}
+ {toggle(this.dictationButton, { display: isNovice ? 'none' : '' })}
{toggle(this.onClickButton)}
{toggle(this.fitWidthButton)}
{toggle(this.freezeThumb)}
- {toggle(this.fitContentButton, { display: !isFreeForm && !isMap ? "none" : "" })}
- {toggle(this.autoHeightButton, { display: !isText && !isStacking && !isTree ? "none" : "" })}
- {toggle(this.maskButton, { display: !isInk ? "none" : "" })}
- {toggle(this.chromeButton, { display: !isCollection || isNovice ? "none" : "" })}
- {toggle(this.gridButton, { display: !isCollection ? "none" : "" })}
- {toggle(this.groupButton, { display: isTabView || !isCollection ? "none" : "" })}
- {toggle(this.snapButton, { display: !isCollection ? "none" : "" })}
- {toggle(this.clustersButton, { display: !isFreeForm ? "none" : "" })}
- {toggle(this.panButton, { display: !isFreeForm ? "none" : "" })}
- {toggle(this.perspectiveButton, { display: !isCollection || isNovice ? "none" : "" })}
- </div>;
- }
-} \ No newline at end of file
+ {toggle(this.fitContentButton, { display: !isFreeForm && !isMap ? 'none' : '' })}
+ {toggle(this.autoHeightButton, { display: !isText && !isStacking && !isTree ? 'none' : '' })}
+ {toggle(this.maskButton, { display: !isInk ? 'none' : '' })}
+ {toggle(this.chromeButton, { display: !isCollection || isNovice ? 'none' : '' })}
+ {toggle(this.gridButton, { display: !isCollection ? 'none' : '' })}
+ {toggle(this.groupButton, { display: isTabView || !isCollection ? 'none' : '' })}
+ {toggle(this.snapButton, { display: !isCollection ? 'none' : '' })}
+ {toggle(this.clustersButton, { display: !isFreeForm ? 'none' : '' })}
+ {toggle(this.panButton, { display: !isFreeForm ? 'none' : '' })}
+ {toggle(this.perspectiveButton, { display: !isCollection || isNovice ? 'none' : '' })}
+ </div>
+ );
+ }
+}