aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/PropertiesView.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-06-23 21:44:01 -0400
committerbobzel <zzzman@gmail.com>2023-06-23 21:44:01 -0400
commit85c017527f209c9d007d67ac70958843ab45e729 (patch)
treee2649860002e0c60e98d84439a67235002ddd9a4 /src/client/views/PropertiesView.tsx
parente9d5dbeef2bf1dab9dfb863d970b70b3074e3d0a (diff)
parent1429ab79eac9aa316082f52c14c576f6b3a97111 (diff)
Merge branch 'master' into heartbeat
Diffstat (limited to 'src/client/views/PropertiesView.tsx')
-rw-r--r--src/client/views/PropertiesView.tsx1123
1 files changed, 518 insertions, 605 deletions
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 842664402..09aac053a 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1,13 +1,14 @@
import React = require('react');
import { IconLookup } from '@fortawesome/fontawesome-svg-core';
-import { faAnchor, faArrowRight } from '@fortawesome/free-solid-svg-icons';
+import { faAnchor, faArrowRight, faWindowMaximize } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Checkbox, Tooltip } from '@material-ui/core';
import { intersection } from 'lodash';
-import { action, autorun, computed, Lambda, observable } from 'mobx';
+import { action, computed, Lambda, observable } from 'mobx';
import { observer } from 'mobx-react';
import { ColorState, SketchPicker } from 'react-color';
-import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, AclSelfEdit, AclSym, AclUnset, DataSym, Doc, DocListCast, Field, HeightSym, NumListCast, Opt, StrListCast, WidthSym } from '../../fields/Doc';
+import { Doc, Field, FieldResult, HierarchyMapping, NumListCast, Opt, StrListCast } from '../../fields/Doc';
+import { AclAdmin, DocAcl, DocData, Height, Width } from '../../fields/DocSymbols';
import { Id } from '../../fields/FieldSymbols';
import { InkField } from '../../fields/InkField';
import { List } from '../../fields/List';
@@ -21,19 +22,19 @@ import { LinkManager } from '../util/LinkManager';
import { SelectionManager } from '../util/SelectionManager';
import { SharingManager } from '../util/SharingManager';
import { Transform } from '../util/Transform';
-import { undoBatch, UndoManager } from '../util/UndoManager';
+import { undoable, undoBatch, UndoManager } from '../util/UndoManager';
import { EditableView } from './EditableView';
+import { FilterPanel } from './FilterPanel';
+import { Colors } from './global/globalEnums';
import { InkStrokeProperties } from './InkStrokeProperties';
-import { DocumentView, StyleProviderFunc } from './nodes/DocumentView';
-import { FilterBox } from './nodes/FilterBox';
+import { DocumentView, OpenWhere, StyleProviderFunc } from './nodes/DocumentView';
import { KeyValueBox } from './nodes/KeyValueBox';
-import { PresBox } from './nodes/trails';
+import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails';
import { PropertiesButtons } from './PropertiesButtons';
import { PropertiesDocBacklinksSelector } from './PropertiesDocBacklinksSelector';
import { PropertiesDocContextSelector } from './PropertiesDocContextSelector';
import './PropertiesView.scss';
import { DefaultStyleProvider } from './StyleProvider';
-import { listSpec } from '../../fields/Schema';
const higflyout = require('@hig/flyout');
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -43,7 +44,7 @@ interface PropertiesViewProps {
width: number;
height: number;
styleProvider?: StyleProviderFunc;
- addDocTab: (doc: Doc, where: string) => boolean;
+ addDocTab: (doc: Doc, where: OpenWhere) => boolean;
}
@observer
@@ -69,20 +70,20 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
return this.selectedDoc?.type === DocumentType.LINK;
}
@computed get dataDoc() {
- return this.selectedDoc?.[DataSym];
+ return this.selectedDoc?.[DocData];
}
@observable layoutFields: boolean = false;
@observable openOptions: boolean = true;
@observable openSharing: boolean = true;
- @observable openFields: boolean = true;
+ @observable openFields: boolean = false;
@observable openLayout: boolean = false;
@observable openContexts: boolean = true;
@observable openLinks: boolean = true;
@observable openAppearance: boolean = true;
@observable openTransform: boolean = true;
- @observable openFilters: boolean = true; // should be false
+ @observable openFilters: boolean = false;
/**
* autorun to set up the filter doc of a collection if that collection has been selected and the filters panel is open
@@ -94,18 +95,18 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
@observable layoutDocAcls: boolean = false;
//Pres Trails booleans:
- @observable openPresTransitions: boolean = false;
+ @observable openPresTransitions: boolean = true;
@observable openPresProgressivize: boolean = false;
+ @observable openPresVisibilityAndDuration: boolean = false;
@observable openAddSlide: boolean = false;
@observable openSlideOptions: boolean = false;
@observable inOptions: boolean = false;
@observable _controlButton: boolean = false;
- @observable _lock: boolean = false;
componentDidMount() {
this.selectedDocListenerDisposer?.();
- this.selectedDocListenerDisposer = autorun(() => this.openFilters && this.selectedDoc && this.checkFilterDoc());
+ // this.selectedDocListenerDisposer = autorun(() => this.openFilters && this.selectedDoc && this.checkFilterDoc());
}
componentWillUnmount() {
@@ -116,23 +117,18 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
return this.selectedDoc?.type === DocumentType.INK;
}
- rtfWidth = () => {
- return !this.selectedDoc ? 0 : Math.min(this.selectedDoc?.[WidthSym](), this.props.width - 20);
- };
- rtfHeight = () => {
- return !this.selectedDoc ? 0 : this.rtfWidth() <= this.selectedDoc?.[WidthSym]() ? Math.min(this.selectedDoc?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
- };
+ rtfWidth = () => (!this.selectedDoc ? 0 : Math.min(this.selectedDoc?.[Width](), this.props.width - 20));
+ rtfHeight = () => (!this.selectedDoc ? 0 : this.rtfWidth() <= this.selectedDoc?.[Width]() ? Math.min(this.selectedDoc?.[Height](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT);
@action
docWidth = () => {
if (this.selectedDoc) {
const layoutDoc = this.selectedDoc;
- const aspect = Doc.NativeAspect(layoutDoc, undefined, !layoutDoc._fitWidth);
- if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.width - 20));
- return Doc.NativeWidth(layoutDoc) ? Math.min(layoutDoc[WidthSym](), this.props.width - 20) : this.props.width - 20;
- } else {
- return 0;
+ const aspect = Doc.NativeAspect(layoutDoc, undefined, !layoutDoc._layout_fitWidth);
+ if (aspect) return Math.min(layoutDoc[Width](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.width - 20));
+ return Doc.NativeWidth(layoutDoc) ? Math.min(layoutDoc[Width](), this.props.width - 20) : this.props.width - 20;
}
+ return 0;
};
@action
@@ -145,10 +141,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
this.MAX_EMBED_HEIGHT,
Doc.NativeAspect(layoutDoc, undefined, true)
? this.docWidth() / Doc.NativeAspect(layoutDoc, undefined, true)
- : layoutDoc._fitWidth
+ : layoutDoc._layout_fitWidth
? !Doc.NativeHeight(this.dataDoc)
? NumCast(this.props.height)
- : Math.min((this.docWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / Doc.NativeWidth(layoutDoc) || NumCast(this.props.height))
+ : Math.min((this.docWidth() * Doc.NativeHeight(layoutDoc)) / Doc.NativeWidth(layoutDoc) || NumCast(this.props.height))
: NumCast(layoutDoc._height) || 50
)
);
@@ -156,121 +152,60 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
return 0;
};
- @computed get expandedField() {
+ editableFields = (filter: (key: string) => boolean, reqdKeys: string[]) => {
+ const rows: JSX.Element[] = [];
if (this.dataDoc && this.selectedDoc) {
- const ids: { [key: string]: string } = {};
- const docs = SelectionManager.Views().length < 2 ? [this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc] : SelectionManager.Views().map(dv => (this.layoutFields ? dv.layoutDoc : dv.dataDoc));
- docs.forEach(doc => Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key)));
- const rows: JSX.Element[] = [];
- for (const key of Object.keys(ids).slice().sort()) {
- const docvals = new Set<any>();
- docs.forEach(doc => docvals.add(doc[key]));
- const contents = Array.from(docvals.keys()).length > 1 ? '-multiple' : docs[0][key];
- if (key[0] === '#') {
- rows.push(
- <div style={{ display: 'flex', overflowY: 'visible', marginBottom: '2px' }} key={key}>
- <span style={{ fontWeight: 'bold', whiteSpace: 'nowrap' }}>{key}</span>
- &nbsp;
- </div>
- );
- } else {
- const contentElement = (
- <EditableView
- key="editableView"
- contents={contents !== undefined ? Field.toString(contents as Field) : 'null'}
- height={13}
- fontSize={10}
- GetValue={() => (contents !== undefined ? Field.toString(contents as Field) : 'null')}
- SetValue={(value: string) => {
- docs.map(doc => KeyValueBox.SetField(doc, key, value, true));
- return true;
- }}
- />
- );
- rows.push(
- <div style={{ display: 'flex', overflowY: 'visible', marginBottom: '-1px' }} key={key}>
- <span style={{ fontWeight: 'bold', whiteSpace: 'nowrap' }}>{key + ':'}</span>
- &nbsp;
- {contentElement}
- </div>
- );
- }
- }
+ const ids = new Set<string>(reqdKeys);
+ const docs: Doc[] = SelectionManager.Views().length < 2 ? [this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc] : SelectionManager.Views().map(dv => (this.layoutFields ? dv.layoutDoc : dv.dataDoc));
+ docs.forEach(doc => Object.keys(doc).forEach(key => doc[key] !== ComputedField.undefined && ids.add(key)));
+
+ // prettier-ignore
+ Array.from(ids).filter(filter).sort().map(key => {
+ const multiple = Array.from(docs.reduce((set,doc) => set.add(doc[key]), new Set<FieldResult>()).keys()).length > 1;
+ const editableContents = multiple ? '-multiple-' : Field.toKeyValueString(docs[0], key);
+ const displayContents = multiple ? '-multiple-' : Field.toString(docs[0][key] as Field);
+ const contentElement = (
+ <EditableView
+ key="editableView"
+ contents={displayContents}
+ height={13}
+ fontSize={10}
+ GetValue={() => editableContents}
+ SetValue={(value: string) => {
+ value !== '-multiple-' && docs.map(doc => KeyValueBox.SetField(doc, key, value, true));
+ return true;
+ }}
+ />);
+ rows.push(
+ <div style={{ display: 'flex', overflowY: 'visible', marginBottom: '-1px' }} key={key}>
+ <span style={{ fontWeight: 'bold', whiteSpace: 'nowrap' }}>{key + ':'}</span>
+ &nbsp;
+ {contentElement}
+ </div>
+ );
+ });
+
rows.push(
- <div className="propertiesView-field" key={'newKeyValue'} style={{ marginTop: '3px' }}>
+ <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px' }}>
<EditableView key="editableView" oneLine contents={'add key:value or #tags'} height={13} fontSize={10} GetValue={() => ''} SetValue={this.setKeyValue} />
</div>
);
- return rows;
}
+ return rows;
+ };
+
+ @computed get expandedField() {
+ return this.editableFields(returnTrue, []);
}
@computed get noviceFields() {
- if (this.dataDoc) {
- const ids: { [key: string]: string } = {};
- const docs = SelectionManager.Views().length < 2 ? [this.dataDoc] : SelectionManager.Views().map(dv => dv.dataDoc);
- docs.forEach(doc => Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key)));
- const rows: JSX.Element[] = [];
- const noviceReqFields = ['author', 'creationDate', 'tags'];
- const noviceLayoutFields = ['_curPage'];
- const noviceKeys = [...Array.from(Object.keys(ids)).filter(key => key[0] === '#' || key.indexOf('lastModified') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('acl'))), ...noviceReqFields, ...noviceLayoutFields];
- for (const key of noviceKeys.sort()) {
- const docvals = new Set<any>();
- docs.forEach(doc => docvals.add(doc[key]));
- const contents = Array.from(docvals.keys()).length > 1 ? '-multiple' : docs[0][key];
- if (key[0] === '#') {
- rows.push(
- <div className="propertiesView-uneditable-field" key={key}>
- <span style={{ fontWeight: 'bold', whiteSpace: 'nowrap' }}>{key}</span>
- &nbsp;
- </div>
- );
- } else if (contents !== undefined) {
- const value = Field.toString(contents as Field);
- if (noviceReqFields.includes(key) || key.indexOf('lastModified') !== -1) {
- rows.push(
- <div className="propertiesView-uneditable-field" key={key}>
- <span style={{ fontWeight: 'bold', whiteSpace: 'nowrap' }}>{key + ': '}</span>
- <div style={{ whiteSpace: 'nowrap', overflowX: 'hidden' }}>{value}</div>
- </div>
- );
- } else {
- const contentElement = (
- <EditableView
- key="editableView"
- contents={value}
- height={13}
- fontSize={10}
- GetValue={() => (contents !== undefined ? Field.toString(contents as Field) : 'null')}
- SetValue={(value: string) => {
- docs.map(doc => KeyValueBox.SetField(doc, key, value, true));
- return true;
- }}
- />
- );
-
- rows.push(
- <div style={{ display: 'flex', overflowY: 'visible', marginBottom: '-1px' }} key={key}>
- <span style={{ fontWeight: 'bold', whiteSpace: 'nowrap' }}>{key + ':'}</span>
- &nbsp;
- {contentElement}
- </div>
- );
- }
- }
- }
- rows.push(
- <div className="propertiesView-field" key={'newKeyValue'} style={{ marginTop: '3px' }}>
- <EditableView key="editableView" oneLine contents={'add key:value or #tags'} height={13} fontSize={10} GetValue={() => ''} SetValue={this.setKeyValue} />
- </div>
- );
- return rows;
- }
+ const noviceReqFields = ['author', 'author_date', 'tags', '_layout_curPage'];
+ return this.editableFields(key => key.indexOf('modificationDate') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('acl')), noviceReqFields);
}
@undoBatch
setKeyValue = (value: string) => {
- const docs = SelectionManager.Views().length < 2 && this.selectedDoc ? [this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc] : SelectionManager.Views().map(dv => (this.layoutFields ? dv.layoutDoc : dv.dataDoc));
+ const docs = SelectionManager.Views().length < 2 && this.selectedDoc ? [this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc!] : SelectionManager.Views().map(dv => (this.layoutFields ? dv.layoutDoc : dv.dataDoc));
docs.forEach(doc => {
if (value.indexOf(':') !== -1) {
const newVal = value[0].toUpperCase() + value.substring(1, value.length);
@@ -282,11 +217,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
}
return true;
} else if (value[0] === '#') {
- const newVal = value + `:'${value}'`;
- doc[DataSym][value] = value;
- const tags = StrCast(doc.tags, ':');
- if (!tags.includes(`${value}:`)) {
- doc[DataSym].tags = `${tags + value + ':'}`;
+ const tags = StrListCast(doc.tags);
+ if (!tags.includes(value)) {
+ tags.push(value);
+ doc[DocData].tags = tags.length ? new List<string>(tags) : undefined;
}
return true;
}
@@ -311,7 +245,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
}
@computed get links() {
- return !this.selectedDoc ? null : <PropertiesDocBacklinksSelector Document={this.selectedDoc} hideTitle={true} addDocTab={this.props.addDocTab} />;
+ const selAnchor = this.selectedDocumentView?.anchorViewDoc ?? LinkManager.currentLinkAnchor ?? this.selectedDoc;
+ return !selAnchor ? null : <PropertiesDocBacklinksSelector Document={selAnchor} hideTitle={true} addDocTab={this.props.addDocTab} />;
}
@computed get layoutPreview() {
@@ -339,13 +274,11 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
NativeHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined}
PanelWidth={panelWidth}
PanelHeight={panelHeight}
- focus={returnFalse}
+ focus={emptyFunction}
ScreenToLocalTransform={this.getTransform}
- docFilters={returnEmptyFilter}
- docRangeFilters={returnEmptyFilter}
+ childFilters={returnEmptyFilter}
+ childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
- ContainingCollectionDoc={undefined}
- ContainingCollectionView={undefined}
addDocument={returnFalse}
moveDocument={undefined}
removeDocument={returnFalse}
@@ -354,7 +287,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
pinToPres={emptyFunction}
bringToFront={returnFalse}
dontRegisterView={true}
- dropAction={undefined}
/>
</div>
);
@@ -368,7 +300,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
*/
@undoBatch
changePermissions = (e: any, user: string) => {
- const docs = SelectionManager.Views().length < 2 ? (this.selectedDoc ? [this.selectedDoc] : []) : SelectionManager.Views().map(docView => docView.props.Document);
+ const docs = (SelectionManager.Views().length < 2 ? [this.selectedDoc] : SelectionManager.Views().map(dv => dv.props.Document)).filter(doc => doc).map(doc => (this.layoutDocAcls ? doc! : DocCast(doc)[DocData]));
SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, docs);
};
@@ -378,7 +310,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
getPermissionsSelect(user: string, permission: string) {
const dropdownValues: string[] = Object.values(SharingPermissions);
if (permission === '-multiple-') dropdownValues.unshift(permission);
- if (user === 'Override') dropdownValues.unshift('None');
+ if (user !== 'Override') dropdownValues.splice(dropdownValues.indexOf(SharingPermissions.Unset), 1);
return (
<select className="permissions-select" value={permission} onChange={e => this.changePermissions(e, user)}>
{dropdownValues
@@ -411,7 +343,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
*/
@computed get expansionIcon() {
return (
- <Tooltip title={<div className="dash-tooltip">{'Show more permissions'}</div>}>
+ <Tooltip title={<div className="dash-tooltip">Show more permissions</div>}>
<div
className="expansion-button"
onPointerDown={() => {
@@ -453,19 +385,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
* @returns the sharing and permissions panel.
*/
@computed get sharingTable() {
- const AclMap = new Map<symbol, string>([
- [AclUnset, 'None'],
- [AclPrivate, SharingPermissions.None],
- [AclReadonly, SharingPermissions.View],
- [AclAugment, SharingPermissions.Augment],
- [AclSelfEdit, SharingPermissions.SelfEdit],
- [AclEdit, SharingPermissions.Edit],
- [AclAdmin, SharingPermissions.Admin],
- ]);
-
// all selected docs
const docs =
- SelectionManager.Views().length < 2 ? [this.layoutDocAcls ? this.selectedDoc : this.selectedDoc?.[DataSym]] : SelectionManager.Views().map(docView => (this.layoutDocAcls ? docView.props.Document : docView.props.Document[DataSym]));
+ SelectionManager.Views().length < 2 && this.selectedDoc ? [this.layoutDocAcls ? this.selectedDoc : this.dataDoc!] : SelectionManager.Views().map(docView => (this.layoutDocAcls ? docView.props.Document : docView.props.Document[DocData]));
const target = docs[0];
@@ -474,7 +396,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
const showAdmin = effectiveAcls.every(acl => acl === AclAdmin);
// users in common between all docs
- const commonKeys: string[] = intersection(...docs.map(doc => (this.layoutDocAcls ? doc?.[AclSym] && Object.keys(doc[AclSym]) : doc?.[DataSym][AclSym] && Object.keys(doc[DataSym][AclSym]))));
+ const commonKeys: string[] = intersection(...docs.map(doc => doc?.[DocAcl] && Object.keys(doc[DocAcl]).filter(key => key !== 'acl-Me')));
const tableEntries = [];
@@ -482,9 +404,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
if (commonKeys.length) {
for (const key of commonKeys) {
const name = denormalizeEmail(key.substring(4));
- const uniform = docs.every(doc => (this.layoutDocAcls ? doc?.[AclSym]?.[key] === docs[0]?.[AclSym]?.[key] : doc?.[DataSym]?.[AclSym]?.[key] === docs[0]?.[DataSym]?.[AclSym]?.[key]));
+ const uniform = docs.every(doc => doc?.[DocAcl]?.[key] === docs[0]?.[DocAcl]?.[key]);
if (name !== Doc.CurrentUserEmail && name !== target.author && name !== 'Public' && name !== 'Override' /* && sidebarUsersDisplayed![name] !== false*/) {
- tableEntries.push(this.sharingItem(name, showAdmin, uniform ? AclMap.get(this.layoutDocAcls ? target[AclSym][key] : target[DataSym][AclSym][key])! : '-multiple-'));
+ tableEntries.push(this.sharingItem(name, showAdmin, uniform ? HierarchyMapping.get(target[DocAcl][key])!.name : '-multiple-'));
}
}
}
@@ -492,11 +414,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
const ownerSame = Doc.CurrentUserEmail !== target.author && docs.filter(doc => doc).every(doc => doc.author === docs[0].author);
// shifts the current user, owner, public to the top of the doc.
// tableEntries.unshift(this.sharingItem("Override", showAdmin, docs.filter(doc => doc).every(doc => doc["acl-Override"] === docs[0]["acl-Override"]) ? (AclMap.get(target[AclSym]?.["acl-Override"]) || "None") : "-multiple-"));
- tableEntries.unshift(this.sharingItem('Public', showAdmin, docs.filter(doc => doc).every(doc => doc['acl-Public'] === docs[0]['acl-Public']) ? AclMap.get(target[AclSym]?.['acl-Public']) || SharingPermissions.None : '-multiple-'));
+ if (ownerSame) tableEntries.unshift(this.sharingItem(StrCast(target.author), showAdmin, 'Owner'));
+ tableEntries.unshift(this.sharingItem('Public', showAdmin, StrCast(docs.filter(doc => doc).every(doc => doc['acl-Public'] === target['acl-Public']) ? target['acl-Public'] || SharingPermissions.None : '-multiple-')));
tableEntries.unshift(
- this.sharingItem('Me', showAdmin, docs.filter(doc => doc).every(doc => doc.author === Doc.CurrentUserEmail) ? 'Owner' : effectiveAcls.every(acl => acl === effectiveAcls[0]) ? AclMap.get(effectiveAcls[0])! : '-multiple-', !ownerSame)
+ this.sharingItem(
+ 'Me',
+ showAdmin,
+ docs.filter(doc => doc).every(doc => doc.author === Doc.CurrentUserEmail) ? 'Owner' : effectiveAcls.every(acl => acl === effectiveAcls[0]) ? HierarchyMapping.get(effectiveAcls[0])!.name : '-multiple-',
+ !ownerSame
+ )
);
- if (ownerSame) tableEntries.unshift(this.sharingItem(StrCast(target.author), showAdmin, 'Owner'));
return <div className="propertiesView-sharingTable">{tableEntries}</div>;
}
@@ -506,9 +433,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
}
@action
- toggleCheckbox = () => {
- this.layoutFields = !this.layoutFields;
- };
+ toggleCheckbox = () => (this.layoutFields = !this.layoutFields);
@computed get editableTitle() {
const titles = new Set<string>();
@@ -593,16 +518,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
<FontAwesomeIcon icon="bezier-curve" color="white" size="lg" />
</div>
</Tooltip>
- <Tooltip title={<div className="dash-tooltip">{InkStrokeProperties.Instance._lock ? 'Unlock ratio' : 'Lock ratio'}</div>}>
- <div className="inking-button-lock" onPointerDown={action(() => (InkStrokeProperties.Instance._lock = !InkStrokeProperties.Instance._lock))}>
- <FontAwesomeIcon icon={InkStrokeProperties.Instance._lock ? 'lock' : 'unlock'} color="white" size="lg" />
- </div>
- </Tooltip>
- <Tooltip title={<div className="dash-tooltip">{'Rotate 90˚'}</div>}>
- <div className="inking-button-rotate" onPointerDown={action(() => this.rotate(Math.PI / 2))}>
- <FontAwesomeIcon icon="undo" color="white" size="lg" />
- </div>
- </Tooltip>
</div>
);
}
@@ -616,17 +531,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
marginLeft: title === '∠:' ? '39px' : '',
}}>
<div className="inputBox-title"> {title} </div>
- <input
- className="inputBox-input"
- type="text"
- value={value}
- onChange={e => {
- setter(e.target.value);
- }}
- onKeyPress={e => {
- e.stopPropagation();
- }}
- />
+ <input className="inputBox-input" type="text" value={value} onChange={e => setter(e.target.value)} onKeyPress={e => e.stopPropagation()} />
<div className="inputBox-button">
<div className="inputBox-button-up" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons('up', key)))}>
<FontAwesomeIcon icon="caret-up" color="white" size="sm" />
@@ -650,60 +555,50 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
@action
upDownButtons = (dirs: string, field: string) => {
+ const selDoc = this.selectedDoc;
+ if (!selDoc) return;
+ //prettier-ignore
switch (field) {
- case 'rot':
- this.rotate(dirs === 'up' ? 0.1 : -0.1);
- break;
- case 'Xps':
- this.selectedDoc && (this.selectedDoc.x = NumCast(this.selectedDoc?.x) + (dirs === 'up' ? 10 : -10));
- break;
- case 'Yps':
- this.selectedDoc && (this.selectedDoc.y = NumCast(this.selectedDoc?.y) + (dirs === 'up' ? 10 : -10));
- break;
- case 'stk':
- this.selectedDoc && (this.selectedDoc.strokeWidth = NumCast(this.selectedDoc?.strokeWidth) + (dirs === 'up' ? 0.1 : -0.1));
- break;
+ case 'Xps': selDoc.x = NumCast(this.selectedDoc?.x) + (dirs === 'up' ? 10 : -10); break;
+ case 'Yps': selDoc.y = NumCast(this.selectedDoc?.y) + (dirs === 'up' ? 10 : -10); break;
+ case 'stk': selDoc.stroke_width = NumCast(this.selectedDoc?.stroke_width) + (dirs === 'up' ? 0.1 : -0.1); break;
case 'wid':
- const oldWidth = NumCast(this.selectedDoc?._width);
- const oldHeight = NumCast(this.selectedDoc?._height);
- const oldX = NumCast(this.selectedDoc?.x);
- const oldY = NumCast(this.selectedDoc?.y);
- this.selectedDoc && (this.selectedDoc._width = oldWidth + (dirs === 'up' ? 10 : -10));
- InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) / oldWidth) * NumCast(this.selectedDoc?._height));
- const doc = this.selectedDoc;
- if (doc?.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) {
- const ink = Cast(doc.data, InkField)?.inkData;
+ const oldWidth = NumCast(selDoc._width);
+ const oldHeight = NumCast(selDoc._height);
+ const oldX = NumCast(selDoc.x);
+ const oldY = NumCast(selDoc.y);
+ selDoc._width = oldWidth + (dirs === 'up' ? 10 : -10);
+ if (selDoc.type === DocumentType.INK && selDoc.x && selDoc.y && selDoc._height && selDoc._width) {
+ const ink = Cast(selDoc.data, InkField)?.inkData;
if (ink) {
const newPoints: { X: number; Y: number }[] = [];
for (var j = 0; j < ink.length; j++) {
// (new x — oldx) + (oldxpoint * newWidt)/oldWidth
- const newX = NumCast(doc.x) - oldX + (ink[j].X * NumCast(doc._width)) / oldWidth;
- const newY = NumCast(doc.y) - oldY + (ink[j].Y * NumCast(doc._height)) / oldHeight;
+ const newX = NumCast(selDoc.x) - oldX + (ink[j].X * NumCast(selDoc._width)) / oldWidth;
+ const newY = NumCast(selDoc.y) - oldY + (ink[j].Y * NumCast(selDoc._height)) / oldHeight;
newPoints.push({ X: newX, Y: newY });
}
- doc.data = new InkField(newPoints);
+ selDoc.data = new InkField(newPoints);
}
}
break;
case 'hgt':
- const oWidth = NumCast(this.selectedDoc?._width);
- const oHeight = NumCast(this.selectedDoc?._height);
- const oX = NumCast(this.selectedDoc?.x);
- const oY = NumCast(this.selectedDoc?.y);
- this.selectedDoc && (this.selectedDoc._height = oHeight + (dirs === 'up' ? 10 : -10));
- InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) / oHeight) * NumCast(this.selectedDoc?._width));
- const docu = this.selectedDoc;
- if (docu?.type === DocumentType.INK && docu.x && docu.y && docu._height && docu._width) {
- const ink = Cast(docu.data, InkField)?.inkData;
+ const oWidth = NumCast(selDoc._width);
+ const oHeight = NumCast(selDoc._height);
+ const oX = NumCast(selDoc.x);
+ const oY = NumCast(selDoc.y);
+ selDoc._height = oHeight + (dirs === 'up' ? 10 : -10);
+ if (selDoc.type === DocumentType.INK && selDoc.x && selDoc.y && selDoc._height && selDoc._width) {
+ const ink = Cast(selDoc.data, InkField)?.inkData;
if (ink) {
const newPoints: { X: number; Y: number }[] = [];
for (var j = 0; j < ink.length; j++) {
// (new x — oldx) + (oldxpoint * newWidt)/oldWidth
- const newX = NumCast(docu.x) - oX + (ink[j].X * NumCast(docu._width)) / oWidth;
- const newY = NumCast(docu.y) - oY + (ink[j].Y * NumCast(docu._height)) / oHeight;
+ const newX = NumCast(selDoc.x) - oX + (ink[j].X * NumCast(selDoc._width)) / oWidth;
+ const newY = NumCast(selDoc.y) - oY + (ink[j].Y * NumCast(selDoc._height)) / oHeight;
newPoints.push({ X: newX, Y: newY });
}
- docu.data = new InkField(newPoints);
+ selDoc.data = new InkField(newPoints);
}
}
break;
@@ -711,11 +606,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
};
getField(key: string) {
- //if (this.selectedDoc) {
return Field.toString(this.selectedDoc?.[key] as Field);
- // } else {
- // return undefined as Opt<string>;
- // }
}
@computed get shapeXps() {
@@ -724,9 +615,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
@computed get shapeYps() {
return this.getField('y');
}
- @computed get shapeRot() {
- return this.getField('rotation');
- }
@computed get shapeHgt() {
return this.getField('_height');
}
@@ -739,39 +627,22 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
set shapeYps(value) {
this.selectedDoc && (this.selectedDoc.y = Number(value));
}
- set shapeRot(value) {
- this.selectedDoc && (this.selectedDoc.rotation = Number(value));
- }
set shapeWid(value) {
- const oldWidth = NumCast(this.selectedDoc?._width);
this.selectedDoc && (this.selectedDoc._width = Number(value));
- InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) * NumCast(this.selectedDoc?._height)) / oldWidth);
}
set shapeHgt(value) {
- const oldHeight = NumCast(this.selectedDoc?._height);
this.selectedDoc && (this.selectedDoc._height = Number(value));
- InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) * NumCast(this.selectedDoc?._width)) / oldHeight);
}
@computed get hgtInput() {
return this.inputBoxDuo(
'hgt',
this.shapeHgt,
- (val: string) => {
- if (!isNaN(Number(val))) {
- this.shapeHgt = val;
- }
- return true;
- },
+ undoable((val: string) => !isNaN(Number(val)) && (this.shapeHgt = val), 'set height'),
'H:',
'wid',
this.shapeWid,
- (val: string) => {
- if (!isNaN(Number(val))) {
- this.shapeWid = val;
- }
- return true;
- },
+ undoable((val: string) => !isNaN(Number(val)) && (this.shapeWid = val), 'set width'),
'W:'
);
}
@@ -779,82 +650,36 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
return this.inputBoxDuo(
'Xps',
this.shapeXps,
- (val: string) => {
- if (val !== '0' && !isNaN(Number(val))) {
- this.shapeXps = val;
- }
- return true;
- },
+ undoable((val: string) => val !== '0' && !isNaN(Number(val)) && (this.shapeXps = val), 'set x coord'),
'X:',
'Yps',
this.shapeYps,
- (val: string) => {
- if (val !== '0' && !isNaN(Number(val))) {
- this.shapeYps = val;
- }
- return true;
- },
+ undoable((val: string) => val !== '0' && !isNaN(Number(val)) && (this.shapeYps = val), 'set y coord'),
'Y:'
);
}
- @computed get rotInput() {
- return this.inputBoxDuo(
- 'rot',
- this.shapeRot,
- (val: string) => {
- if (!isNaN(Number(val))) {
- this.rotate(Number(val) - Number(this.shapeRot));
- this.shapeRot = val;
- }
- return true;
- },
- '∠:',
- 'rot',
- this.shapeRot,
- (val: string) => {
- if (!isNaN(Number(val))) {
- this.rotate(Number(val) - Number(this.shapeRot));
- this.shapeRot = val;
- }
- return true;
- },
- ''
- );
- }
@observable private _fillBtn = false;
@observable private _lineBtn = false;
- private _lastFill = '#D0021B';
- private _lastLine = '#D0021B';
private _lastDash: any = '2';
@computed get colorFil() {
- const ccol = this.getField('fillColor') || '';
- ccol && (this._lastFill = ccol);
- return ccol;
+ return StrCast(this.selectedDoc?.fillColor);
}
@computed get colorStk() {
- const ccol = this.getField('color') || '';
- ccol && (this._lastLine = ccol);
- return ccol;
+ return StrCast(this.selectedDoc?.color);
}
set colorFil(value) {
- value && (this._lastFill = value);
this.selectedDoc && (this.selectedDoc.fillColor = value ? value : undefined);
}
set colorStk(value) {
- value && (this._lastLine = value);
this.selectedDoc && (this.selectedDoc.color = value ? value : undefined);
}
- colorButton(value: string, type: string, setter: () => {}) {
- // return <div className="properties-flyout" onPointerEnter={e => this.changeScrolling(false)}
- // onPointerLeave={e => this.changeScrolling(true)}>
- // <Flyout anchorPoint={anchorPoints.LEFT_TOP}
- // content={type === "fill" ? this.fillPicker : this.linePicker}>
+ colorButton(value: string, type: string, setter: () => void) {
return (
- <div className="color-button" key="color" onPointerDown={undoBatch(action(e => setter()))}>
+ <div className="color-button" key="color" onPointerDown={action(e => setter())}>
<div
className="color-button-preview"
style={{
@@ -867,31 +692,17 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{value === '' || value === 'transparent' ? <p style={{ fontSize: 25, color: 'red', marginTop: -14 }}>☒</p> : ''}
</div>
);
- // </Flyout>
- // </div>;
}
- @undoBatch
- @action
- switchStk = (color: ColorState) => {
- const val = String(color.hex);
- this.colorStk = val;
- return true;
- };
- @undoBatch
- @action
- switchFil = (color: ColorState) => {
- const val = String(color.hex);
- this.colorFil = val;
- return true;
- };
-
- colorPicker(setter: (color: string) => {}, type: string) {
+ colorPicker(color: string, setter: (color: string) => void) {
return (
<SketchPicker
- onChange={type === 'stk' ? this.switchStk : this.switchFil}
+ onChange={undoable(
+ action((color: ColorState) => setter(color.hex)),
+ 'set stroke color property'
+ )}
presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
- color={type === 'stk' ? this.colorStk : this.colorFil}
+ color={color}
/>
);
}
@@ -900,22 +711,20 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
return this.colorButton(this.colorFil, 'fill', () => {
this._fillBtn = !this._fillBtn;
this._lineBtn = false;
- return true;
});
}
@computed get lineButton() {
return this.colorButton(this.colorStk, 'line', () => {
this._lineBtn = !this._lineBtn;
this._fillBtn = false;
- return true;
});
}
@computed get fillPicker() {
- return this.colorPicker((color: string) => (this.colorFil = color), 'fil');
+ return this.colorPicker(this.colorFil, (color: string) => (this.colorFil = color));
}
@computed get linePicker() {
- return this.colorPicker((color: string) => (this.colorStk = color), 'stk');
+ return this.colorPicker(this.colorStk, (color: string) => (this.colorStk = color));
}
@computed get strokeAndFill() {
@@ -937,49 +746,36 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
);
}
- @computed get solidStk() {
- return this.selectedDoc?.color && (!this.selectedDoc?.strokeDash || this.selectedDoc?.strokeDash === '0') ? true : false;
- }
@computed get dashdStk() {
- return this.selectedDoc?.strokeDash || '';
- }
- @computed get unStrokd() {
- return this.selectedDoc?.color ? true : false;
+ return this.selectedDoc?.stroke_dash || '';
}
@computed get widthStk() {
- return this.getField('strokeWidth') || '1';
+ return this.getField('stroke_width') || '1';
}
@computed get markScal() {
- return Number(this.getField('strokeMakerScale') || '1');
+ return Number(this.getField('stroke_markerScale') || '1');
}
@computed get markHead() {
- return this.getField('strokeStartMarker') || '';
+ return this.getField('stroke_startMarker') || '';
}
@computed get markTail() {
- return this.getField('strokeEndMarker') || '';
- }
- set solidStk(value) {
- this.dashdStk = '';
- this.unStrokd = !value;
+ return this.getField('stroke_endMarker') || '';
}
set dashdStk(value) {
- value && (this._lastDash = value) && (this.unStrokd = false);
- this.selectedDoc && (this.selectedDoc.strokeDash = value ? this._lastDash : undefined);
+ value && (this._lastDash = value);
+ this.selectedDoc && (this.selectedDoc.stroke_dash = value ? this._lastDash : undefined);
}
set markScal(value) {
- this.selectedDoc && (this.selectedDoc.strokeMarkerScale = Number(value));
+ this.selectedDoc && (this.selectedDoc.stroke_markerScale = Number(value));
}
set widthStk(value) {
- this.selectedDoc && (this.selectedDoc.strokeWidth = Number(value));
- }
- set unStrokd(value) {
- this.colorStk = value ? '' : this._lastLine;
+ this.selectedDoc && (this.selectedDoc.stroke_width = Number(value));
}
set markHead(value) {
- this.selectedDoc && (this.selectedDoc.strokeStartMarker = value);
+ this.selectedDoc && (this.selectedDoc.stroke_startMarker = value);
}
set markTail(value) {
- this.selectedDoc && (this.selectedDoc.strokeEndMarker = value);
+ this.selectedDoc && (this.selectedDoc.stroke_endMarker = value);
}
@computed get stkInput() {
@@ -1087,10 +883,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
@computed get transformEditor() {
return (
<div className="transform-editor">
- {this.controlPointsButton}
+ {this.isInk ? this.controlPointsButton : null}
{this.hgtInput}
{this.XpsInput}
- {this.rotInput}
</div>
);
}
@@ -1145,62 +940,31 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
}
/**
- * Checks if a currentFilter (FilterDoc) exists on the current collection (if the Properties Panel + Filters submenu are open).
- * If it doesn't exist, it creates it.
- */
- checkFilterDoc() {
- if (!this.selectedDoc?.currentFilter) this.selectedDoc!.currentFilter = FilterBox.createFilterDoc();
- }
-
- /**
- * Creates a new currentFilter for this.filterDoc,
- */
- createNewFilterDoc = () => {
- if (this.selectedDoc) {
- const curFilterDoc = DocCast(this.selectedDoc.currentFilter);
- const currentDocFilters = this.selectedDoc._docFilters;
- const currentDocRangeFilters = this.selectedDoc._docRangeFilters;
- this.selectedDoc._docFilters = new List<string>();
- this.selectedDoc._docRangeFilters = new List<string>();
- if (DocListCast(Doc.UserDoc().savedFilters).includes(curFilterDoc)) {
- curFilterDoc._docFiltersList = currentDocFilters;
- curFilterDoc._docRangeFiltersList = currentDocRangeFilters;
- this.selectedDoc.currentFilter = FilterBox.createFilterDoc();
- } else {
- Doc.GetProto(curFilterDoc).data = undefined;
- Doc.GetProto(curFilterDoc).title = 'Unnamed Filter';
- curFilterDoc._docFiltersList = undefined;
- curFilterDoc._docRangeFiltersList = undefined;
- }
- }
- };
-
- /**
- * Updates this.filterDoc's currentFilter and saves the docFilters on the currentFilter
+ * Updates this.filterDoc's currentFilter and saves the childFilters on the currentFilter
*/
updateFilterDoc = (doc: Doc) => {
if (this.selectedDoc) {
if (doc === this.selectedDoc.currentFilter) return; // causes problems if you try to reapply the same doc
- const savedDocFilters = doc._docFiltersList;
- const currentDocFilters = this.selectedDoc._docFilters;
- this.selectedDoc._docFilters = new List<string>();
- (this.selectedDoc.currentFilter as Doc)._docFiltersList = currentDocFilters;
+ const savedDocFilters = doc._childFiltersList;
+ const currentDocFilters = this.selectedDoc._childFilters;
+ this.selectedDoc._childFilters = new List<string>();
+ (this.selectedDoc.currentFilter as Doc)._childFiltersList = currentDocFilters;
this.selectedDoc.currentFilter = doc;
- doc._docFiltersList = new List<string>();
- this.selectedDoc._docFilters = savedDocFilters;
+ doc._childFiltersList = new List<string>();
+ this.selectedDoc._childFilters = savedDocFilters;
- const savedDocRangeFilters = doc._docRangeFiltersList;
- const currentDocRangeFilters = this.selectedDoc._docRangeFilters;
- this.selectedDoc._docRangeFilters = new List<string>();
- (this.selectedDoc.currentFilter as Doc)._docRangeFiltersList = currentDocRangeFilters;
+ const savedDocRangeFilters = doc._childFiltersByRangesList;
+ const currentDocRangeFilters = this.selectedDoc._childFiltersByRanges;
+ this.selectedDoc._childFiltersByRanges = new List<string>();
+ (this.selectedDoc.currentFilter as Doc)._childFiltersByRangesList = currentDocRangeFilters;
this.selectedDoc.currentFilter = doc;
- doc._docRangeFiltersList = new List<string>();
- this.selectedDoc._docRangeFilters = savedDocRangeFilters;
+ doc._childFiltersByRangesList = new List<string>();
+ this.selectedDoc._childFiltersByRanges = savedDocRangeFilters;
}
};
@computed get filtersSubMenu() {
- return !(this.selectedDoc?.currentFilter instanceof Doc) ? null : (
+ return (
<div className="propertiesView-filters">
<div className="propertiesView-filters-title" onPointerDown={action(() => (this.openFilters = !this.openFilters))} style={{ backgroundColor: this.openFilters ? 'black' : '' }}>
Filters
@@ -1209,35 +973,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</div>
</div>
{!this.openFilters ? null : (
- <div className="propertiesView-filters-content" style={{ height: this.selectedDoc.currentFilter[HeightSym]() + 15 }}>
- <DocumentView
- Document={this.selectedDoc.currentFilter}
- DataDoc={undefined}
- addDocument={undefined}
- addDocTab={returnFalse}
- pinToPres={emptyFunction}
- rootSelected={returnTrue}
- removeDocument={returnFalse}
- ScreenToLocalTransform={this.getTransform}
- PanelWidth={() => this.props.width}
- PanelHeight={this.selectedDoc.currentFilter[HeightSym]}
- renderDepth={0}
- scriptContext={this.selectedDoc.currentFilter}
- focus={emptyFunction}
- styleProvider={DefaultStyleProvider}
- isContentActive={returnTrue}
- whenChildContentsActiveChanged={emptyFunction}
- bringToFront={emptyFunction}
- docFilters={returnEmptyFilter}
- docRangeFilters={returnEmptyFilter}
- searchFilterDocs={returnEmptyDoclist}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined}
- createNewFilterDoc={this.createNewFilterDoc}
- updateFilterDoc={this.updateFilterDoc}
- docViewPath={returnEmptyDoclist}
- dontCenter="y"
- />
+ <div className="propertiesView-filters-content" style={{ position: 'relative', height: 'auto' }}>
+ <FilterPanel rootDoc={this.selectedDoc ?? Doc.ActiveDashboard!} />
</div>
)}
</div>
@@ -1259,17 +996,15 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</div>
)}
- {this.isInk ? (
- <div className="propertiesView-transform">
- <div className="propertiesView-transform-title" onPointerDown={action(() => (this.openTransform = !this.openTransform))} style={{ backgroundColor: this.openTransform ? 'black' : '' }}>
- Transform
- <div className="propertiesView-transform-title-icon">
- <FontAwesomeIcon icon={this.openTransform ? 'caret-down' : 'caret-right'} size="lg" color="white" />
- </div>
+ <div className="propertiesView-transform">
+ <div className="propertiesView-transform-title" onPointerDown={action(() => (this.openTransform = !this.openTransform))} style={{ backgroundColor: this.openTransform ? 'black' : '' }}>
+ Transform
+ <div className="propertiesView-transform-title-icon">
+ <FontAwesomeIcon icon={this.openTransform ? 'caret-down' : 'caret-right'} size="lg" color="white" />
</div>
- {this.openTransform ? <div className="propertiesView-transform-content">{this.transformEditor}</div> : null}
</div>
- ) : null}
+ {this.openTransform ? <div className="propertiesView-transform-content">{this.transformEditor}</div> : null}
+ </div>
</>
);
}
@@ -1336,49 +1071,52 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
);
}
- @observable description = Field.toString(LinkManager.currentLink?.description as any as Field);
- @observable relationship = StrCast(LinkManager.currentLink?.linkRelationship);
+ @computed get description() {
+ return Field.toString(LinkManager.currentLink?.link_description as any as Field);
+ }
+ @computed get relationship() {
+ return StrCast(LinkManager.currentLink?.link_relationship);
+ }
@observable private relationshipButtonColor: string = '';
// @action
- // handleDescriptionChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.description = e.target.value; }
- // handleRelationshipChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.relationship = e.target.value; }
-
- @undoBatch
- handleDescriptionChange = action((value: string) => {
- if (LinkManager.currentLink && this.selectedDoc) {
- this.selectedDoc.description = value;
- this.description = value;
- return true;
- }
- });
+ // handleDescriptionChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.link_description = e.target.value; }
+ // handleRelationshipChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.link_relationship = e.target.value; }
- @undoBatch
- handleLinkRelationshipChange = action((value: string) => {
- if (LinkManager.currentLink && this.selectedDoc) {
- this.selectedDoc.linkRelationship = value;
- this.relationship = value;
- return true;
- }
- });
+ handleDescriptionChange = undoable(
+ action((value: string) => {
+ if (LinkManager.currentLink && this.selectedDoc) {
+ this.setDescripValue(value);
+ }
+ }),
+ 'change link description'
+ );
+
+ handlelinkRelationshipChange = undoable(
+ action((value: string) => {
+ if (LinkManager.currentLink && this.selectedDoc) {
+ this.setlinkRelationshipValue(value);
+ }
+ }),
+ 'change link relationship'
+ );
@undoBatch
setDescripValue = action((value: string) => {
if (LinkManager.currentLink) {
- Doc.GetProto(LinkManager.currentLink).description = value;
- return true;
+ Doc.GetProto(LinkManager.currentLink).link_description = value;
}
});
@undoBatch
- setLinkRelationshipValue = action((value: string) => {
+ setlinkRelationshipValue = action((value: string) => {
if (LinkManager.currentLink) {
- const prevRelationship = LinkManager.currentLink.linkRelationship as string;
- LinkManager.currentLink.linkRelationship = value;
- Doc.GetProto(LinkManager.currentLink).linkRelationship = value;
- const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList);
- const linkRelationshipSizes = NumListCast(Doc.UserDoc().linkRelationshipSizes);
- const linkColorList = StrListCast(Doc.UserDoc().linkColorList);
+ const prevRelationship = StrCast(LinkManager.currentLink.link_relationship);
+ LinkManager.currentLink.link_relationship = value;
+ Doc.GetProto(LinkManager.currentLink).link_relationship = value;
+ const linkRelationshipList = StrListCast(Doc.UserDoc().link_relationshipList);
+ const linkRelationshipSizes = NumListCast(Doc.UserDoc().link_relationshipSizes);
+ const linkColorList = StrListCast(Doc.UserDoc().link_ColorList);
// if the relationship does not exist in the list, add it and a corresponding unique randomly generated color
if (!linkRelationshipList?.includes(value)) {
@@ -1412,20 +1150,34 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
}
});
+ changeFollowBehavior = undoable((loc: Opt<string>) => this.sourceAnchor && (this.sourceAnchor.followLinkLocation = loc), 'change follow behavior');
+
@undoBatch
- changeFollowBehavior = action((follow: string) => {
- if (LinkManager.currentLink && this.selectedDoc) {
- this.selectedDoc.followLinkLocation = follow;
- return true;
- }
- });
+ changeAnimationBehavior = action((behavior: string) => this.sourceAnchor && (this.sourceAnchor.followLinkAnimEffect = behavior));
+
+ @undoBatch
+ changeEffectDirection = action((effect: PresEffectDirection) => this.sourceAnchor && (this.sourceAnchor.followLinkAnimDirection = effect));
+
+ animationDirection = (direction: PresEffectDirection, icon: string, gridColumn: number, gridRow: number, opts: object) => {
+ const lanch = this.sourceAnchor;
+ const color = lanch?.followLinkAnimDirection === direction || (direction === PresEffectDirection.Center && !lanch?.followLinkAnimDirection) ? Colors.MEDIUM_BLUE : '';
+ return (
+ <Tooltip title={<div className="dash-tooltip">{direction}</div>}>
+ <div
+ style={{ ...opts, border: direction === PresEffectDirection.Center ? `solid 2px ${color}` : undefined, borderRadius: '20%', cursor: 'pointer', gridColumn, gridRow, justifySelf: 'center', background: color, color: 'black' }}
+ onClick={() => this.changeEffectDirection(direction)}>
+ {icon ? <FontAwesomeIcon icon={icon as any} /> : null}
+ </div>
+ </Tooltip>
+ );
+ };
onSelectOutDesc = () => {
this.setDescripValue(this.description);
document.getElementById('link_description_input')?.blur();
};
- onDescriptionKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
+ onDescriptionKey = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === 'Enter') {
this.setDescripValue(this.description);
document.getElementById('link_description_input')?.blur();
@@ -1433,30 +1185,48 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
};
onSelectOutRelationship = () => {
- this.setLinkRelationshipValue(this.relationship);
+ this.setlinkRelationshipValue(this.relationship);
document.getElementById('link_relationship_input')?.blur();
};
onRelationshipKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
- this.setLinkRelationshipValue(this.relationship);
+ this.setlinkRelationshipValue(this.relationship);
document.getElementById('link_relationship_input')?.blur();
}
};
- toggleAnchor = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (this.selectedDoc.linkAutoMove = !this.selectedDoc.linkAutoMove))));
+ toggleLinkProp = (e: React.PointerEvent, prop: string) => {
+ setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => LinkManager.currentLink && (LinkManager.currentLink[prop] = !LinkManager.currentLink[prop]))));
};
- toggleArrow = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (this.selectedDoc.displayArrow = !this.selectedDoc.displayArrow))));
- };
+ @computed get destinationAnchor() {
+ const ldoc = LinkManager.currentLink;
+ const lanch = this.selectedDocumentView?.anchorViewDoc ?? LinkManager.currentLinkAnchor;
+ if (ldoc && lanch) return LinkManager.getOppositeAnchor(ldoc, lanch) ?? lanch;
+ return ldoc ? DocCast(ldoc.link_anchor_2) : ldoc;
+ }
- toggleZoomToTarget1 = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (DocCast(this.selectedDoc.anchor1).followLinkZoom = !DocCast(this.selectedDoc.anchor1).followLinkZoom))));
- };
- toggleZoomToTarget2 = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (DocCast(this.selectedDoc.anchor2).followLinkZoom = !DocCast(this.selectedDoc.anchor2).followLinkZoom))));
+ @computed get sourceAnchor() {
+ const selAnchor = this.selectedDocumentView?.anchorViewDoc ?? LinkManager.currentLinkAnchor;
+
+ return selAnchor ?? (LinkManager.currentLink && this.destinationAnchor ? LinkManager.getOppositeAnchor(LinkManager.currentLink, this.destinationAnchor) : LinkManager.currentLink);
+ }
+
+ toggleAnchorProp = (e: React.PointerEvent, prop: string, anchor?: Doc, value: any = true, ovalue: any = false, cb: (val: any) => any = val => val) => {
+ anchor &&
+ setupMoveUpEvents(
+ this,
+ e,
+ returnFalse,
+ emptyFunction,
+ undoBatch(
+ action(() => {
+ anchor[prop] = anchor[prop] === value ? ovalue : value;
+ this.selectedDoc && cb(anchor[prop]);
+ })
+ )
+ );
};
@computed
@@ -1465,10 +1235,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
<input
autoComplete={'off'}
id="link_relationship_input"
- value={StrCast(this.selectedDoc?.linkRelationship)}
+ value={StrCast(LinkManager.currentLink?.link_relationship)}
onKeyDown={this.onRelationshipKey}
onBlur={this.onSelectOutRelationship}
- onChange={e => this.handleLinkRelationshipChange(e.currentTarget.value)}
+ onChange={e => this.handlelinkRelationshipChange(e.currentTarget.value)}
className="text"
type="text"
/>
@@ -1478,19 +1248,28 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
@computed
get editDescription() {
return (
- <input
- autoComplete={'off'}
+ <textarea
+ autoComplete="off"
+ style={{ textAlign: 'left' }}
id="link_description_input"
- value={StrCast(this.selectedDoc?.description)}
+ value={StrCast(LinkManager.currentLink?.link_description)}
onKeyDown={this.onDescriptionKey}
onBlur={this.onSelectOutDesc}
onChange={e => this.handleDescriptionChange(e.currentTarget.value)}
className="text"
- type="text"
/>
);
}
+ // Converts seconds to ms and updates presTransition
+ setZoom = (number: String, change?: number) => {
+ let scale = Number(number) / 100;
+ if (change) scale += change;
+ if (scale < 0.01) scale = 0.01;
+ if (scale > 1) scale = 1;
+ this.sourceAnchor && (this.sourceAnchor.followLinkZoomScale = scale);
+ };
+
/**
* Handles adding and removing members from the sharing panel
*/
@@ -1504,6 +1283,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
render() {
const isNovice = Doc.noviceMode;
+ const zoom = Number((NumCast(this.sourceAnchor?.followLinkZoomScale, 1) * 100).toPrecision(3));
+ const targZoom = this.sourceAnchor?.followLinkZoom;
+ const indent = 30;
+ const hasSelectedAnchor = LinkManager.Links(this.sourceAnchor).includes(LinkManager.currentLink!);
if (!this.selectedDoc && !this.isPres) {
return (
<div className="propertiesView" style={{ width: this.props.width }}>
@@ -1513,81 +1296,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</div>
);
} else {
- if (this.selectedDoc && this.isLink) {
- return (
- <div className="propertiesView">
- <div className="propertiesView-title">Linking</div>
- <div className="propertiesView-section">
- <p className="propertiesView-label">Information</p>
- <div className="propertiesView-input first">
- <p>Link Relationship</p>
- {this.editRelationship}
- </div>
- <div className="propertiesView-input">
- <p>Description</p>
- {this.editDescription}
- </div>
- </div>
- <div className="propertiesView-section">
- <p className="propertiesView-label">Behavior</p>
- <div className="propertiesView-input inline first">
- <p>Follow</p>
- <select name="selectList" id="selectList" onChange={e => this.changeFollowBehavior(e.currentTarget.value)} value={StrCast(this.selectedDoc.followLinkLocation, 'default')}>
- <option value="default">Default</option>
- <option value="add:left">Open in new left pane</option>
- <option value="add:right">Open in new right pane</option>
- <option value="replace:left">Replace left tab</option>
- <option value="replace:right">Replace right tab</option>
- <option value="fullScreen">Open full screen</option>
- <option value="add">Open in new tab</option>
- <option value="replace">Replace current tab</option>
- {this.selectedDoc.linksToAnnotation ? <option value="openExternal">Open in external page</option> : null}
- </select>
- </div>
- <div className="propertiesView-input inline">
- <p>Auto-move anchor</p>
- <button
- style={{ background: this.selectedDoc.hidden ? 'gray' : !this.selectedDoc.linkAutoMove ? '' : '#4476f7', borderRadius: 3 }}
- onPointerDown={this.toggleAnchor}
- onClick={e => e.stopPropagation()}
- className="propertiesButton">
- <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
- </button>
- </div>
- <div className="propertiesView-input inline">
- <p>Display arrow</p>
- <button
- style={{ background: this.selectedDoc.hidden ? 'gray' : !this.selectedDoc.displayArrow ? '' : '#4476f7', borderRadius: 3 }}
- onPointerDown={this.toggleArrow}
- onClick={e => e.stopPropagation()}
- className="propertiesButton">
- <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
- </button>
- </div>
- <div className="propertiesView-input inline">
- <p>Zoom to target</p>
- <button
- style={{ background: this.selectedDoc.hidden ? 'gray' : !Cast(this.selectedDoc.anchor1, Doc, null).followLinkZoom ? '' : '#4476f7', borderRadius: 3 }}
- onPointerDown={this.toggleZoomToTarget1}
- onClick={e => e.stopPropagation()}
- className="propertiesButton">
- <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
- </button>
- </div>
- <div className="propertiesView-input inline">
- <p>Zoom to source</p>
- <button
- style={{ background: this.selectedDoc.hidden ? 'gray' : !Cast(this.selectedDoc.anchor2, Doc, null).followLinkZoom ? '' : '#4476f7', borderRadius: 3 }}
- onPointerDown={this.toggleZoomToTarget2}
- onClick={e => e.stopPropagation()}
- className="propertiesButton">
- <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
- </button>
- </div>
- </div>
- </div>
- );
- }
if (this.selectedDoc && !this.isPres) {
return (
<div
@@ -1605,6 +1313,220 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{this.contextsSubMenu}
{this.linksSubMenu}
+ {!this.selectedDoc || !LinkManager.currentLink || (!hasSelectedAnchor && this.selectedDoc !== LinkManager.currentLink) ? null : (
+ <>
+ <div className="propertiesView-section" style={{ background: 'darkgray' }}>
+ <div className="propertiesView-input first" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
+ <p>Relationship</p>
+ {this.editRelationship}
+ </div>
+ <div className="propertiesView-input" style={{ display: 'grid', gridTemplateColumns: '84px auto' }}>
+ <p>Description</p>
+ {this.editDescription}
+ </div>
+ <div className="propertiesView-input inline">
+ <p>Show link</p>
+ <button
+ style={{ background: !LinkManager.currentLink?.link_displayLine ? '' : '#4476f7', borderRadius: 3 }}
+ onPointerDown={e => this.toggleLinkProp(e, 'link_displayLine')}
+ onClick={e => e.stopPropagation()}
+ className="propertiesButton">
+ <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+ </button>
+ </div>
+ <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
+ <p>Auto-move anchors</p>
+ <button
+ style={{ background: !LinkManager.currentLink?.link_autoMoveAnchors ? '' : '#4476f7', borderRadius: 3 }}
+ onPointerDown={e => this.toggleLinkProp(e, 'link_autoMoveAnchors')}
+ onClick={e => e.stopPropagation()}
+ className="propertiesButton">
+ <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+ </button>
+ </div>
+ <div className="propertiesView-input inline" style={{ marginLeft: 10 }}>
+ <p>Display arrow</p>
+ <button
+ style={{ background: !LinkManager.currentLink?.link_displayArrow ? '' : '#4476f7', borderRadius: 3 }}
+ onPointerDown={e => this.toggleLinkProp(e, 'link_displayArrow')}
+ onClick={e => e.stopPropagation()}
+ className="propertiesButton">
+ <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+ </button>
+ </div>
+ </div>
+ {!hasSelectedAnchor ? null : (
+ <div className="propertiesView-section">
+ <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 84px)' }}>
+ <p>Follow by</p>
+ <select onChange={e => this.changeFollowBehavior(e.currentTarget.value === 'Default' ? undefined : e.currentTarget.value)} value={Cast(this.sourceAnchor?.followLinkLocation, 'string', null)}>
+ <option value={undefined}>Default</option>
+ <option value={OpenWhere.addLeft}>Opening in new left pane</option>
+ <option value={OpenWhere.addRight}>Opening in new right pane</option>
+ <option value={OpenWhere.replaceLeft}>Replacing left tab</option>
+ <option value={OpenWhere.replaceRight}>Replacing right tab</option>
+ <option value={OpenWhere.fullScreen}>Overlaying current tab</option>
+ <option value={OpenWhere.lightbox}>Opening in lightbox</option>
+ <option value={OpenWhere.add}>Opening in new tab</option>
+ <option value={OpenWhere.replace}>Replacing current tab</option>
+ <option value={OpenWhere.inParent}>Opening in same collection</option>
+ {LinkManager.currentLink?.linksToAnnotation ? <option value="openExternal">Open in external page</option> : null}
+ </select>
+ </div>
+ <div className="propertiesView-input inline first" style={{ display: 'grid', gridTemplateColumns: '84px calc(100% - 134px) 50px' }}>
+ <p>Animation</p>
+ <select style={{ width: '100%', gridColumn: 2 }} onChange={e => this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.followLinkAnimEffect, 'default')}>
+ <option value="default">Default</option>
+ {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => (
+ <option key={effect.toString()} value={effect.toString()}>
+ {effect.toString()}
+ </option>
+ ))}
+ </select>
+ <div className="effectDirection" style={{ marginLeft: '10px', display: 'grid', width: 40, height: 36, gridColumn: 3, gridTemplateRows: '12px 12px 12px' }}>
+ {this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})}
+ {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})}
+ {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})}
+ {this.animationDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})}
+ {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
+ </div>
+ </div>
+ {PresBox.inputter(
+ '0.1',
+ '0.1',
+ '10',
+ NumCast(this.sourceAnchor?.followLinkTransitionTime) / 1000,
+ true,
+ (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS)),
+ indent
+ )}{' '}
+ <div
+ className={'slider-headers'}
+ style={{
+ display: 'grid',
+ justifyContent: 'space-between',
+ width: `calc(100% - ${indent * 2}px)`,
+ marginLeft: indent,
+ marginRight: indent,
+ gridTemplateColumns: 'auto auto',
+ borderTop: 'solid',
+ }}>
+ <div className="slider-text">Fast</div>
+ <div className="slider-text">Slow</div>
+ </div>{' '}
+ <div className="propertiesView-input inline">
+ <p>Play Target Audio</p>
+ <button
+ style={{ background: !this.sourceAnchor?.followLinkAudio ? '' : '#4476f7', borderRadius: 3 }}
+ onPointerDown={e => this.toggleAnchorProp(e, 'followLinkAudio', this.sourceAnchor)}
+ onClick={e => e.stopPropagation()}
+ className="propertiesButton">
+ <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+ </button>
+ </div>
+ <div className="propertiesView-input inline">
+ <p>Zoom Text Selections</p>
+ <button
+ style={{ background: !this.sourceAnchor?.followLinkZoomText ? '' : '#4476f7', borderRadius: 3 }}
+ onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoomText', this.sourceAnchor)}
+ onClick={e => e.stopPropagation()}
+ className="propertiesButton">
+ <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+ </button>
+ </div>
+ <div className="propertiesView-input inline">
+ <p>Toggle Follow to Outer Context</p>
+ <button
+ style={{ background: !this.sourceAnchor?.followLinkToOuterContext ? '' : '#4476f7', borderRadius: 3 }}
+ onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToOuterContext', this.sourceAnchor)}
+ onClick={e => e.stopPropagation()}
+ className="propertiesButton">
+ <FontAwesomeIcon className="fa-icon" icon={faWindowMaximize as IconLookup} size="lg" />
+ </button>
+ </div>
+ <div className="propertiesView-input inline">
+ <p>Toggle Target (Show/Hide)</p>
+ <button
+ style={{ background: !this.sourceAnchor?.followLinkToggle ? '' : '#4476f7', borderRadius: 3 }}
+ onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToggle', this.sourceAnchor)}
+ onClick={e => e.stopPropagation()}
+ className="propertiesButton">
+ <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+ </button>
+ </div>
+ <div className="propertiesView-input inline">
+ <p>Ease Transitions</p>
+ <button
+ style={{ background: this.sourceAnchor?.followLinkEase === 'linear' ? '' : '#4476f7', borderRadius: 3 }}
+ onPointerDown={e => this.toggleAnchorProp(e, 'followLinkEase', this.sourceAnchor, 'ease', 'linear')}
+ onClick={e => e.stopPropagation()}
+ className="propertiesButton">
+ <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+ </button>
+ </div>
+ <div className="propertiesView-input inline">
+ <p>Capture Offset to Target</p>
+ <button
+ style={{ background: this.sourceAnchor?.followLinkXoffset === undefined ? '' : '#4476f7', borderRadius: 3 }}
+ onPointerDown={e => {
+ this.toggleAnchorProp(e, 'followLinkXoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.x) - NumCast(this.sourceAnchor?.x), undefined);
+ this.toggleAnchorProp(e, 'followLinkYoffset', this.sourceAnchor, NumCast(this.destinationAnchor?.y) - NumCast(this.sourceAnchor?.y), undefined);
+ }}
+ onClick={e => e.stopPropagation()}
+ className="propertiesButton">
+ <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+ </button>
+ </div>
+ <div className="propertiesView-input inline">
+ <p>Center Target (no zoom)</p>
+ <button
+ style={{ background: this.sourceAnchor?.followLinkZoom ? '' : '#4476f7', borderRadius: 3 }}
+ onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
+ onClick={e => e.stopPropagation()}
+ className="propertiesButton">
+ <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" />
+ </button>
+ </div>
+ <div className="propertiesView-input inline" style={{ display: 'grid', gridTemplateColumns: '78px calc(100% - 108px) 50px' }}>
+ <p>Zoom %</p>
+ <div className="ribbon-property" style={{ display: !targZoom ? 'none' : 'inline-flex' }}>
+ <input className="presBox-input" style={{ width: '100%' }} readOnly={true} type="number" value={zoom} />
+ <div className="ribbon-propertyUpDown" style={{ display: 'flex', flexDirection: 'column' }}>
+ <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), 0.1))}>
+ <FontAwesomeIcon icon={'caret-up'} />
+ </div>
+ <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), -0.1))}>
+ <FontAwesomeIcon icon={'caret-down'} />
+ </div>
+ </div>
+ </div>
+ <button
+ style={{ background: !targZoom || this.sourceAnchor?.followLinkZoomScale === 0 ? '' : '#4476f7', borderRadius: 3, gridColumn: 3 }}
+ onPointerDown={e => this.toggleAnchorProp(e, 'followLinkZoom', this.sourceAnchor)}
+ onClick={e => e.stopPropagation()}
+ className="propertiesButton">
+ <FontAwesomeIcon className="fa-icon" icon={faArrowRight as IconLookup} size="lg" />
+ </button>
+ </div>
+ {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)}
+ <div
+ className={'slider-headers'}
+ style={{
+ display: !targZoom ? 'none' : 'grid',
+ justifyContent: 'space-between',
+ width: `calc(100% - ${indent * 2}px)`,
+ marginLeft: indent,
+ marginRight: indent,
+ gridTemplateColumns: 'auto auto',
+ borderTop: 'solid',
+ }}>
+ <div className="slider-text">0%</div>
+ <div className="slider-text">100%</div>
+ </div>{' '}
+ </div>
+ )}
+ </>
+ )}
{this.inkSubMenu}
@@ -1620,9 +1542,11 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</div>
);
}
- if (this.isPres) {
- const selectedItem: boolean = PresBox.Instance?.selectedArray.size > 0;
- const type = PresBox.Instance.activeItem?.type;
+ if (this.isPres && PresBox.Instance) {
+ const selectedItem: boolean = PresBox.Instance.selectedArray.size > 0;
+ const type = [DocumentType.AUDIO, DocumentType.VID].includes(DocCast(PresBox.Instance.activeItem?.annotationOn)?.type as any as DocumentType)
+ ? (DocCast(PresBox.Instance.activeItem?.annotationOn)?.type as any as DocumentType)
+ : PresBox.targetRenderedDoc(PresBox.Instance.activeItem)?.type;
return (
<div className="propertiesView" style={{ width: this.props.width }}>
<div className="propertiesView-title" style={{ width: this.props.width }}>
@@ -1631,18 +1555,13 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
<div className="propertiesView-name" style={{ borderBottom: 0 }}>
{this.editableTitle}
<div className="propertiesView-presSelected">
- <div className="propertiesView-selectedCount">{PresBox.Instance?.selectedArray.size} selected</div>
- <div className="propertiesView-selectedList">{PresBox.Instance?.listOfSelected}</div>
+ <div className="propertiesView-selectedCount">{PresBox.Instance.selectedArray.size} selected</div>
+ <div className="propertiesView-selectedList">{PresBox.Instance.listOfSelected}</div>
</div>
</div>
{!selectedItem ? null : (
<div className="propertiesView-presTrails">
- <div
- className="propertiesView-presTrails-title"
- onPointerDown={action(() => {
- this.openPresTransitions = !this.openPresTransitions;
- })}
- style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
+ <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openPresTransitions = !this.openPresTransitions))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
&nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Transitions
<div className="propertiesView-presTrails-title-icon">
<FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg" color="white" />
@@ -1651,27 +1570,34 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{this.openPresTransitions ? <div className="propertiesView-presTrails-content">{PresBox.Instance.transitionDropdown}</div> : null}
</div>
)}
- {/* {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) : <div className="propertiesView-presTrails">
- <div className="propertiesView-presTrails-title"
- onPointerDown={action(() => this.openPresProgressivize = !this.openPresProgressivize)}
- style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
- &nbsp; <FontAwesomeIcon style={{ alignSelf: "center" }} icon={"tasks"} /> &nbsp; Progressivize
- <div className="propertiesView-presTrails-title-icon">
- <FontAwesomeIcon icon={this.openPresProgressivize ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {this.openPresProgressivize ? <div className="propertiesView-presTrails-content">
- {PresBox.Instance.progressivizeDropdown}
- </div> : null}
- </div>} */}
- {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? null : (
+ {!selectedItem ? null : (
<div className="propertiesView-presTrails">
<div
className="propertiesView-presTrails-title"
- onPointerDown={action(() => {
- this.openSlideOptions = !this.openSlideOptions;
- })}
- style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}>
+ onPointerDown={action(() => (this.openPresVisibilityAndDuration = !this.openPresVisibilityAndDuration))}
+ style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
+ &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Visibilty
+ <div className="propertiesView-presTrails-title-icon">
+ <FontAwesomeIcon icon={this.openPresVisibilityAndDuration ? 'caret-down' : 'caret-right'} size="lg" color="white" />
+ </div>
+ </div>
+ {this.openPresVisibilityAndDuration ? <div className="propertiesView-presTrails-content">{PresBox.Instance.visibiltyDurationDropdown}</div> : null}
+ </div>
+ )}
+ {!selectedItem ? null : (
+ <div className="propertiesView-presTrails">
+ <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openPresProgressivize = !this.openPresProgressivize))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
+ &nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Progressivize
+ <div className="propertiesView-presTrails-title-icon">
+ <FontAwesomeIcon icon={this.openPresProgressivize ? 'caret-down' : 'caret-right'} size="lg" color="white" />
+ </div>
+ </div>
+ {this.openPresProgressivize ? <div className="propertiesView-presTrails-content">{PresBox.Instance.progressivizeDropdown}</div> : null}
+ </div>
+ )}
+ {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? null : (
+ <div className="propertiesView-presTrails">
+ <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openSlideOptions = !this.openSlideOptions))} style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}>
&nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={type === DocumentType.AUDIO ? 'file-audio' : 'file-video'} /> &nbsp; {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'}
<div className="propertiesView-presTrails-title-icon">
<FontAwesomeIcon icon={this.openSlideOptions ? 'caret-down' : 'caret-right'} size="lg" color="white" />
@@ -1680,19 +1606,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{this.openSlideOptions ? <div className="propertiesView-presTrails-content">{PresBox.Instance.mediaOptionsDropdown}</div> : null}
</div>
)}
- {/* <div className="propertiesView-presTrails">
- <div className="propertiesView-presTrails-title"
- onPointerDown={action(() => { this.openAddSlide = !this.openAddSlide; })}
- style={{ backgroundColor: this.openAddSlide ? "black" : "" }}>
- &nbsp; <FontAwesomeIcon icon={"plus"} /> &nbsp; Add new slide
- <div className="propertiesView-presTrails-title-icon">
- <FontAwesomeIcon icon={this.openAddSlide ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {this.openAddSlide ? <div className="propertiesView-presTrails-content">
- {PresBox.Instance.newDocumentDropdown}
- </div> : null}
- </div> */}
</div>
);
}