diff options
author | bobzel <zzzman@gmail.com> | 2024-05-14 23:15:24 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2024-05-14 23:15:24 -0400 |
commit | 3534aaf88a3c30a474b3b5a5b7f04adfe6f15fac (patch) | |
tree | 47fb7a8671b209bd4d76e0f755a5b035c6936607 /src/client/views/PropertiesView.tsx | |
parent | 87bca251d87b5a95da06b2212400ce9427152193 (diff) | |
parent | 5cb7ad90e120123ca572e8ef5b1aa6ca41581134 (diff) |
Merge branch 'restoringEslint' into sarah-ai-visualization
Diffstat (limited to 'src/client/views/PropertiesView.tsx')
-rw-r--r-- | src/client/views/PropertiesView.tsx | 1160 |
1 files changed, 627 insertions, 533 deletions
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index ae29382c1..e4ca3daeb 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1,3 +1,6 @@ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +/* eslint-disable prettier/prettier */ import { IconLookup } from '@fortawesome/fontawesome-svg-core'; import { faAnchor, faArrowRight, faWindowMaximize } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -8,9 +11,10 @@ import { IReactionDisposer, action, computed, makeObservable, observable, reacti import { observer } from 'mobx-react'; import * as React from 'react'; import { ColorResult, SketchPicker } from 'react-color'; -import * as Icons from 'react-icons/bs'; //{BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs" -import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from '../../Utils'; -import { Doc, Field, FieldResult, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast } from '../../fields/Doc'; +import * as Icons from 'react-icons/bs'; // {BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs" +import { ClientUtils, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../ClientUtils'; +import { emptyFunction } from '../../Utils'; +import { Doc, Field, FieldResult, FieldType, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast } from '../../fields/Doc'; import { AclAdmin, DocAcl, DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { InkField } from '../../fields/InkField'; @@ -19,10 +23,8 @@ import { ComputedField } from '../../fields/ScriptField'; import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { GetEffectiveAcl, SharingPermissions, normalizeEmail } from '../../fields/util'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; -import { DocumentManager } from '../util/DocumentManager'; import { GroupManager } from '../util/GroupManager'; import { LinkManager } from '../util/LinkManager'; -import { SelectionManager } from '../util/SelectionManager'; import { SettingsManager } from '../util/SettingsManager'; import { SharingManager } from '../util/SharingManager'; import { Transform } from '../util/Transform'; @@ -36,11 +38,12 @@ import { PropertiesDocBacklinksSelector } from './PropertiesDocBacklinksSelector import { PropertiesDocContextSelector } from './PropertiesDocContextSelector'; import { PropertiesSection } from './PropertiesSection'; import './PropertiesView.scss'; -import { DefaultStyleProvider } from './StyleProvider'; -import { DocumentView, OpenWhere } from './nodes/DocumentView'; +import { DefaultStyleProvider, SetFilterOpener as SetPropertiesFilterOpener } from './StyleProvider'; +import { DocumentView } from './nodes/DocumentView'; import { StyleProviderFuncType } from './nodes/FieldView'; -import { KeyValueBox } from './nodes/KeyValueBox'; +import { OpenWhere } from './nodes/OpenWhere'; import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails'; + const _global = (window /* browser */ || global) /* node */ as any; interface PropertiesViewProps { @@ -54,11 +57,18 @@ interface PropertiesViewProps { export class PropertiesView extends ObservableReactComponent<PropertiesViewProps> { private _widthUndo?: UndoManager.Batch; + // eslint-disable-next-line no-use-before-define public static Instance: PropertiesView | undefined; constructor(props: any) { super(props); makeObservable(this); PropertiesView.Instance = this; + SetPropertiesFilterOpener( + action(() => { + this.CloseAll(); + this.openFilters = true; + }) + ); } @computed get MAX_EMBED_HEIGHT() { @@ -66,7 +76,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps } @computed get selectedDoc() { - return SelectionManager.SelectedSchemaDoc || this.selectedDocumentView?.Document || Doc.ActiveDashboard; + return DocumentView.SelectedSchemaDoc() || this.selectedDocumentView?.Document || Doc.ActiveDashboard; } @computed get selectedLink() { @@ -74,12 +84,10 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps } @computed get selectedLayoutDoc() { - return SelectionManager.SelectedSchemaDoc || this.selectedDocumentView?.layoutDoc || Doc.ActiveDashboard; + return DocumentView.SelectedSchemaDoc() || this.selectedDocumentView?.layoutDoc || Doc.ActiveDashboard; } @computed get selectedDocumentView() { - if (SelectionManager.Views.length) return SelectionManager.Views[0]; - if (PresBox.Instance?.selectedArray.size) return DocumentManager.Instance.getDocumentView(PresBox.Instance.Document); - return undefined; + return DocumentView.Selected().lastElement(); } @computed get isPres(): boolean { return this.selectedDoc?.type === DocumentType.PRES; @@ -101,14 +109,13 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps @observable openTransform: boolean = true; @observable openFilters: boolean = false; - //Pres Trails booleans: + // Pres Trails booleans: @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; private _disposers: { [name: string]: IReactionDisposer } = {}; @@ -176,42 +183,47 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps const rows: JSX.Element[] = []; if (this.dataDoc && this.selectedDoc) { 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)); + const docs: Doc[] = + DocumentView.Selected().length < 2 // + ? [this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc] + : DocumentView.Selected().map(dv => (this.layoutFields ? dv.layoutDoc : dv.dataDoc)); docs.forEach(doc => Object.keys(doc) .filter(filter) .forEach(key => doc[key] !== ComputedField.undefined && key && ids.add(key)) ); - // prettier-ignore - Array.from(ids).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> - - {contentElement} - </div> - ); - }); + Array.from(ids) + .sort() + .forEach(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 FieldType); + const contentElement = ( + <EditableView + key="editableView" + contents={displayContents} + height={13} + fontSize={10} + GetValue={() => editableContents} + SetValue={(value: string) => { + value !== '-multiple-' && docs.map(doc => Doc.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> + + {contentElement} + </div> + ); + }); rows.push( <div className="propertiesView-field" key="newKeyValue" style={{ marginTop: '3px', backgroundColor: SettingsManager.userBackgroundColor, textAlign: 'center' }}> - <EditableView key="editableView" oneLine contents={'add key:value or #tags'} height={13} fontSize={10} GetValue={() => ''} SetValue={this.setKeyValue} /> + <EditableView key="editableView" oneLine contents="add key:value or #tags" height={13} fontSize={10} GetValue={returnEmptyString} SetValue={this.setKeyValue} /> </div> ); } @@ -224,23 +236,29 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps @computed get noviceFields() { 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); + 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 = + DocumentView.Selected().length < 2 && this.selectedDoc + ? [this.layoutFields + ? Doc.Layout(this.selectedDoc) // + : this.dataDoc!] + : DocumentView.Selected().map(dv => (this.layoutFields ? dv.layoutDoc : dv.dataDoc)); // prettier-ignore docs.forEach(doc => { if (value.indexOf(':') !== -1) { const newVal = value[0].toUpperCase() + value.substring(1, value.length); const splits = newVal.split(':'); - KeyValueBox.SetField(doc, splits[0], splits[1], true); + Doc.SetField(doc, splits[0], splits[1], true); const tags = StrCast(doc.tags, ':'); if (tags.includes(`${splits[0]}:`) && splits[1] === 'undefined') { - KeyValueBox.SetField(doc, 'tags', `"${tags.replace(splits[0] + ':', '')}"`, true); + Doc.SetField(doc, 'tags', `"${tags.replace(splits[0] + ':', '')}"`, true); } return true; - } else if (value[0] === '#') { + } + if (value[0] === '#') { const tags = StrListCast(doc.tags); if (!tags.includes(value)) { tags.push(value); @@ -248,6 +266,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps } return true; } + return undefined; }); return false; }; @@ -255,44 +274,43 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps @observable transform: Transform = Transform.Identity(); getTransform = () => this.transform; propertiesDocViewRef = (ref: HTMLDivElement) => { - const observer = new _global.ResizeObserver( - action((entries: any) => { + const resizeObserver = new _global.ResizeObserver( + action(() => { const cliRect = ref.getBoundingClientRect(); this.transform = new Transform(-cliRect.x, -cliRect.y, 1); }) ); - ref && observer.observe(ref); + ref && resizeObserver.observe(ref); }; @computed get contexts() { - return !this.selectedDoc ? null : <PropertiesDocContextSelector DocView={this.selectedDocumentView} hideTitle={true} addDocTab={this._props.addDocTab} />; + return !this.selectedDoc ? null : <PropertiesDocContextSelector DocView={this.selectedDocumentView} hideTitle addDocTab={this._props.addDocTab} />; } @computed get contextCount() { if (this.selectedDocumentView) { const target = this.selectedDocumentView.Document; return Doc.GetEmbeddings(target).length - 1; - } else { - return 0; } + return 0; } @computed get links() { const selAnchor = this.selectedDocumentView?.anchorViewDoc ?? LinkManager.Instance.currentLinkAnchor ?? this.selectedDoc; - return !selAnchor ? null : <PropertiesDocBacklinksSelector Document={selAnchor} hideTitle={true} addDocTab={this._props.addDocTab} />; + return !selAnchor ? null : <PropertiesDocBacklinksSelector Document={selAnchor} hideTitle addDocTab={this._props.addDocTab} />; } @computed get linkCount() { const selAnchor = this.selectedDocumentView?.anchorViewDoc ?? LinkManager.Instance.currentLinkAnchor ?? this.selectedDoc; - var counter = 0; + let counter = 0; - LinkManager.Links(selAnchor).forEach((l, i) => counter++); + Doc.Links(selAnchor).forEach(() => counter++); return counter; } @computed get layoutPreview() { - if (SelectionManager.Views.length > 1) { + if (DocumentView.Selected().length > 1) { return '-- multiple selected --'; } if (this.selectedDoc) { @@ -308,7 +326,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps fitContentsToBox={returnTrue} styleProvider={DefaultStyleProvider} containerViewPath={returnEmptyDoclist} - dontCenter={'y'} + dontCenter="y" isDocumentActive={returnFalse} isContentActive={emptyFunction} NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined} @@ -326,13 +344,12 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps whenChildContentsActiveChanged={emptyFunction} addDocTab={returnFalse} pinToPres={emptyFunction} - dontRegisterView={true} + dontRegisterView /> </div> ); - } else { - return null; } + return null; } /** @@ -340,7 +357,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps */ @undoBatch changePermissions = (e: any, user: string) => { - const docs = SelectionManager.Views.length < 2 ? [this.selectedDoc] : SelectionManager.Views.map(dv => (this.layoutDocAcls ? dv.layoutDoc : dv.dataDoc)); + const docs = DocumentView.Selected().length < 2 ? [this.selectedDoc] : DocumentView.Selected().map(dv => (this.layoutDocAcls ? dv.layoutDoc : dv.dataDoc)); SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, docs, this.layoutDocAcls); }; @@ -352,9 +369,9 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps if (permission === '-multiple-') dropdownValues.unshift(permission); return ( <select className="propertiesView-permissions-select" value={permission} onChange={e => this.changePermissions(e, user)}> - {dropdownValues.map(permission => ( - <option className="propertiesView-permisssions-select" key={permission} value={permission}> - {concat(ReverseHierarchyMap.get(permission)?.image, ' ', permission)} + {dropdownValues.map(permissionVal => ( + <option className="propertiesView-permisssions-select" key={permissionVal} value={permissionVal}> + {concat(ReverseHierarchyMap.get(permissionVal)?.image, ' ', permissionVal)} </option> ))} </select> @@ -381,7 +398,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps return ( <div className="expansion-button"> <IconButton - icon={<FontAwesomeIcon icon={'ellipsis-h'} />} + icon={<FontAwesomeIcon icon="ellipsis-h" />} size={Size.XSMALL} color={SettingsManager.userColor} onClick={action(() => { @@ -397,10 +414,8 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps /** * @returns a row of the permissions panel */ - sharingItem(name: string, admin: boolean, permission: string, showExpansionIcon?: boolean) { - if (name == Doc.CurrentUserEmail) { - name = 'Me'; - } + sharingItem(nameIn: string, admin: boolean, permission: string, showExpansionIcon?: boolean) { + const name = nameIn === ClientUtils.CurrentUserEmail() ? 'Me' : nameIn; return ( <div className="propertiesView-sharingTable-item" @@ -415,7 +430,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps {/* {name !== "Me" ? this.notifyIcon : null} */} <div className="propertiesView-sharingTable-item-permission"> {this.colorACLDropDown(name, admin, permission, false)} - {(permission === 'Owner' && name == 'Me') || showExpansionIcon ? this.expansionIcon : null} + {(permission === 'Owner' && name === 'Me') || showExpansionIcon ? this.expansionIcon : null} </div> </div> ); @@ -425,10 +440,10 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps * @returns a colored dropdown bar reflective of the permission */ colorACLDropDown(name: string, admin: boolean, permission: string, showGuestOptions: boolean) { - var shareImage = ReverseHierarchyMap.get(permission)?.image; + const shareImage = ReverseHierarchyMap.get(permission)?.image; return ( <div> - <div className={'propertiesView-shareDropDown'}> + <div className="propertiesView-shareDropDown"> <div className={`propertiesView-shareDropDown${permission}`}> <div>{admin && permission !== 'Owner' ? this.getPermissionsSelect(name, permission, showGuestOptions) : concat(shareImage, ' ', permission)}</div> </div> @@ -440,9 +455,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps /** * Sorting algorithm to sort users. */ - sortUsers = (u1: String, u2: String) => { - return u1 > u2 ? -1 : u1 === u2 ? 0 : 1; - }; + sortUsers = (u1: String, u2: String) => (u1 > u2 ? -1 : u1 === u2 ? 0 : 1); /** * Sorting algorithm to sort groups. @@ -458,45 +471,45 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps */ @computed get sharingTable() { // all selected docs - const docs = SelectionManager.Views.length < 2 && this.selectedDoc ? [this.selectedDoc] : SelectionManager.Views.map(docView => docView.Document); + const docs = DocumentView.Selected().length < 2 && this.selectedDoc ? [this.selectedDoc] : DocumentView.SelectedDocs(); const target = docs[0]; - const showAdmin = GetEffectiveAcl(target) == AclAdmin; + const showAdmin = GetEffectiveAcl(target) === AclAdmin; const individualTableEntries = []; const usersAdded: string[] = []; // all shared users being added - organized by denormalized email const seldoc = this.layoutDocAcls ? this.selectedLayoutDoc : this.selectedDoc?.[DocData]; // adds each user to usersAdded SharingManager.Instance.users.forEach(eachUser => { - var userOnDoc = true; + let userOnDoc = true; if (seldoc) { - if (Doc.GetT(seldoc, 'acl-' + normalizeEmail(eachUser.user.email), 'string', true) === '' || Doc.GetT(seldoc, 'acl-' + normalizeEmail(eachUser.user.email), 'string', true) === undefined) { + if (Doc.GetT(seldoc, 'acl_' + normalizeEmail(eachUser.user.email), 'string', true) === '' || Doc.GetT(seldoc, 'acl_' + normalizeEmail(eachUser.user.email), 'string', true) === undefined) { userOnDoc = false; } } - if (userOnDoc && !usersAdded.includes(eachUser.user.email) && eachUser.user.email !== 'guest' && eachUser.user.email != target.author) { + if (userOnDoc && !usersAdded.includes(eachUser.user.email) && eachUser.user.email !== 'guest' && eachUser.user.email !== target.author) { usersAdded.push(eachUser.user.email); } }); // sorts and then adds each user to the table usersAdded.sort(this.sortUsers); - usersAdded.map(userEmail => { - const userKey = `acl-${normalizeEmail(userEmail)}`; - var aclField = Doc.GetT(this.layoutDocAcls ? target : Doc.GetProto(target), userKey, 'string', true); - var permission = StrCast(aclField); + usersAdded.forEach(userEmail => { + const userKey = `acl_${normalizeEmail(userEmail)}`; + const aclField = Doc.GetT(this.layoutDocAcls ? target : Doc.GetProto(target), userKey, 'string', true); + const permission = StrCast(aclField); individualTableEntries.unshift(this.sharingItem(userEmail, showAdmin, permission!, false)); // adds each user }); // adds current user - var userEmail = Doc.CurrentUserEmail; - if (userEmail == 'guest') userEmail = 'Guest'; - const userKey = `acl-${normalizeEmail(userEmail)}`; - if (!usersAdded.includes(userEmail) && userEmail !== 'Guest' && userEmail != target.author) { - var permission; + let userEmail = ClientUtils.CurrentUserEmail(); + if (userEmail === 'guest') userEmail = 'Guest'; + const userKey = `acl_${normalizeEmail(userEmail)}`; + if (!usersAdded.includes(userEmail) && userEmail !== 'Guest' && userEmail !== target.author) { + let permission; if (this.layoutDocAcls) { if (target[DocAcl][userKey]) permission = HierarchyMapping.get(target[DocAcl][userKey])?.name; - else if (target['embedContainer']) permission = StrCast(Doc.GetProto(DocCast(target['embedContainer']))[userKey]); + else if (target.embedContainer) permission = StrCast(Doc.GetProto(DocCast(target.embedContainer))[userKey]); else permission = StrCast(Doc.GetProto(target)?.[userKey]); } else permission = StrCast(target[userKey]); individualTableEntries.unshift(this.sharingItem(userEmail, showAdmin, permission!, false)); // adds each user @@ -509,15 +522,15 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps const groupTableEntries: JSX.Element[] = []; const groupList = GroupManager.Instance?.allGroups || []; groupList.sort(this.sortGroups); - groupList.map(group => { - if (group.title != 'Guest' && this.selectedDoc) { - const groupKey = 'acl-' + normalizeEmail(StrCast(group.title)); - if (this.selectedDoc[groupKey] != '' && this.selectedDoc[groupKey] != undefined) { - var permission; + groupList.forEach(group => { + if (group.title !== 'Guest' && this.selectedDoc) { + const groupKey = 'acl_' + normalizeEmail(StrCast(group.title)); + if (this.selectedDoc[groupKey] !== '' && this.selectedDoc[groupKey] !== undefined) { + let permission; if (this.layoutDocAcls) { if (target[DocAcl][groupKey]) { permission = HierarchyMapping.get(target[DocAcl][groupKey])?.name; - } else if (target['embedContainer']) permission = StrCast(Doc.GetProto(DocCast(target['embedContainer']))[groupKey]); + } else if (target.embedContainer) permission = StrCast(Doc.GetProto(DocCast(target.embedContainer))[groupKey]); else permission = StrCast(Doc.GetProto(target)?.[groupKey]); } else permission = StrCast(target[groupKey]); groupTableEntries.unshift(this.sharingItem(StrCast(group.title), showAdmin, permission!, false)); @@ -526,27 +539,27 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps }); // guest permission - const guestPermission = StrCast((this.layoutDocAcls ? target : Doc.GetProto(target))['acl-Guest']); + const guestPermission = StrCast((this.layoutDocAcls ? target : Doc.GetProto(target)).acl_Guest); return ( <div> <div> - <br></br> Individuals with Access to this Document + <br /> Individuals with Access to this Document </div> <div className="propertiesView-sharingTable" style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}> - {<div> {individualTableEntries}</div>} + <div> {individualTableEntries}</div> </div> {groupTableEntries.length > 0 ? ( <div> <div> - <br></br> Groups with Access to this Document + <br /> Groups with Access to this Document </div> <div className="propertiesView-sharingTable" style={{ background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}> - {<div> {groupTableEntries}</div>} + <div> {groupTableEntries}</div> </div> </div> ) : null} - <br></br> Guest + <br /> Guest <div>{this.colorACLDropDown('Guest', showAdmin, guestPermission!, true)}</div> </div> ); @@ -558,7 +571,9 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps } @action - toggleCheckbox = () => (this.layoutFields = !this.layoutFields); + toggleCheckbox = () => { + this.layoutFields = !this.layoutFields; + }; @computed get color() { return SettingsManager.userColor; @@ -574,25 +589,21 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps @computed get editableTitle() { const titles = new Set<string>(); - SelectionManager.Views.forEach(dv => titles.add(StrCast(dv.Document.title))); + DocumentView.Selected().forEach(dv => titles.add(StrCast(dv.Document.title))); const title = Array.from(titles.keys()).length > 1 ? '--multiple selected--' : StrCast(this.selectedDoc?.title); return ( <div> - <EditableText val={title} setVal={this.setTitle} color={this.color} type={Type.SEC} formLabel={'Title'} fillWidth /> + <EditableText val={title} setVal={this.setTitle} color={this.color} type={Type.SEC} formLabel="Title" fillWidth /> {LinkManager.Instance.currentLinkAnchor ? ( <p className="propertiesView-titleExtender"> - <> - <b>Anchor:</b> - {LinkManager.Instance.currentLinkAnchor.title} - </> + <b>Anchor:</b> + {StrCast(LinkManager.Instance.currentLinkAnchor.title)} </p> ) : null} {this.selectedLink?.title ? ( <p className="propertiesView-titleExtender"> - <> - <b>Link:</b> - {this.selectedLink.title} - </> + <b>Link:</b> + {StrCast(this.selectedLink.title)} </p> ) : null} </div> @@ -600,9 +611,9 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps } @computed get currentType() { - const documentType = StrCast(this.selectedDoc?.type); - var currentType: string = documentType; - var capitalizedDocType = Utils.cleanDocumentType(currentType as DocumentType); + const docType = StrCast(this.selectedDoc?.type) as DocumentType; + const colType = StrCast(this.selectedDoc?.type_collection) as CollectionViewType; + const capitalizedDocType = ClientUtils.cleanDocumentType(docType, colType); return ( <div> @@ -618,7 +629,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps } @computed get currentComponent() { - var iconName = StrCast(this.selectedDoc?.systemIcon); + const iconName = StrCast(this.selectedDoc?.systemIcon); if (iconName) { const Icon = Icons[iconName as keyof typeof Icons]; @@ -629,11 +640,11 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps @undoBatch setTitle = (value: string | number) => { - if (SelectionManager.Views.length > 1) { - SelectionManager.Views.map(dv => Doc.SetInPlace(dv.Document, 'title', value, true)); + if (DocumentView.Selected().length > 1) { + DocumentView.Selected().map(dv => Doc.SetInPlace(dv.Document, 'title', value, true)); } else if (this.dataDoc) { if (this.selectedDoc) Doc.SetInPlace(this.selectedDoc, 'title', value, true); - else KeyValueBox.SetField(this.dataDoc, 'title', value as string, true); + else Doc.SetField(this.dataDoc, 'title', value as string, true); } }; @@ -650,13 +661,11 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps const ys = ink.map(p => p.Y); const left = Math.min(...xs); const top = Math.min(...ys); - const right = Math.max(...xs); - const bottom = Math.max(...ys); _centerPoints.push({ X: left, Y: top }); } } - var index = 0; + let index = 0; if (doc.type === DocumentType.INK && doc.x && doc.y && layout._width && layout._height && doc.data) { layout.rotation = NumCast(layout.rotation) + angle; const inks = Cast(doc.stroke, InkField)?.inkData; @@ -687,11 +696,13 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps get controlPointsButton() { return ( <div className="inking-button"> - <Tooltip title={<div className="dash-tooltip">{'Edit points'}</div>}> + <Tooltip title={<div className="dash-tooltip">Edit points</div>}> <div className="inking-button-points" style={{ backgroundColor: InkStrokeProperties.Instance._controlButton ? 'black' : '' }} - onPointerDown={action(() => (InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton))}> + onPointerDown={action(() => { + InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton; + })}> <FontAwesomeIcon icon="bezier-curve" size="lg" /> </div> </Tooltip> @@ -699,152 +710,129 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps ); } - inputBox = (key: string, value: any, setter: (val: string) => {}, title: string) => { - return ( - <div - className="inputBox" - style={{ - marginRight: title === 'X:' ? '19px' : '', - marginLeft: title === '∠:' ? '39px' : '', - }}> - <div className="inputBox-title"> {title} </div> - <input - className="inputBox-input" - type="text" - value={value} - style={{ color: SettingsManager.userColor, backgroundColor: SettingsManager.userBackgroundColor }} - onChange={e => setter(e.target.value)} - onKeyDown={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" size="sm" /> - </div> - <div className="inputbox-Button-down" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons('down', key)))}> - <FontAwesomeIcon icon="caret-down" size="sm" /> - </div> + inputBox = (key: string, value: any, setter: (val: string) => {}, title: string) => ( + <div + className="inputBox" + style={{ + marginRight: title === 'X:' ? '19px' : '', + marginLeft: title === '∠:' ? '39px' : '', + }}> + <div className="inputBox-title"> {title} </div> + <input className="inputBox-input" type="text" value={value} style={{ color: SettingsManager.userColor, backgroundColor: SettingsManager.userBackgroundColor }} onChange={e => setter(e.target.value)} onKeyDown={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" size="sm" /> + </div> + <div className="inputbox-Button-down" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons('down', key)))}> + <FontAwesomeIcon icon="caret-down" size="sm" /> </div> </div> - ); - }; + </div> + ); - inputBoxDuo = (key: string, value: any, setter: (val: string) => {}, title1: string, key2: string, value2: any, setter2: (val: string) => {}, title2: string) => { - return ( - <div className="inputBox-duo"> - {this.inputBox(key, value, setter, title1)} - {title2 === '' ? null : this.inputBox(key2, value2, setter2, title2)} - </div> - ); - }; + inputBoxDuo = (key: string, value: any, setter: (val: string) => {}, title1: string, key2: string, value2: any, setter2: (val: string) => {}, title2: string) => ( + <div className="inputBox-duo"> + {this.inputBox(key, value, setter, title1)} + {title2 === '' ? null : this.inputBox(key2, value2, setter2, title2)} + </div> + ); @action upDownButtons = (dirs: string, field: string) => { const selDoc = this.selectedDoc; if (!selDoc) return; - //prettier-ignore + // prettier-ignore switch (field) { 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?.[DocData].stroke_width) + (dirs === 'up' ? 0.1 : -0.1); break; - case 'wid': - 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(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 }); + case 'wid': { + 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 (let j = 0; j < ink.length; j++) { + // (new x — oldx) + (oldxpoint * newWidt)/oldWidth + 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 }); + } + selDoc.data = new InkField(newPoints); } - selDoc.data = new InkField(newPoints); } } break; - case 'hgt': - 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(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 }); + case 'hgt': { + 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 (let j = 0; j < ink.length; j++) { + // (new x — oldx) + (oldxpoint * newWidt)/oldWidth + 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 }); + } + selDoc.data = new InkField(newPoints); } - selDoc.data = new InkField(newPoints); } } break; + default: { /* empty */ } } }; getField(key: string) { - return Field.toString(this.selectedDoc?.[DocData][key] as Field); + return Field.toString(this.selectedDoc?.[DocData][key] as FieldType); } - @computed get shapeXps() { - return NumCast(this.selectedDoc?.x); - } - @computed get shapeYps() { - return NumCast(this.selectedDoc?.y); - } - @computed get shapeHgt() { - return NumCast(this.selectedDoc?._height); - } - @computed get shapeWid() { - return NumCast(this.selectedDoc?._width); - } - @computed get strokeThk() { - return NumCast(this.selectedDoc?.[DocData].stroke_width); - } - set shapeXps(value) { - this.selectedDoc && (this.selectedDoc.x = Math.round(value * 100) / 100); - } - set shapeYps(value) { - this.selectedDoc && (this.selectedDoc.y = Math.round(value * 100) / 100); - } - set shapeWid(value) { - this.selectedDoc && (this.selectedDoc._width = Math.round(value * 100) / 100); - } - set shapeHgt(value) { - this.selectedDoc && (this.selectedDoc._height = Math.round(value * 100) / 100); - } - set strokeThk(value) { - this.selectedDoc && (this.selectedDoc[DocData].stroke_width = Math.round(value * 100) / 100); - } + @computed get shapeXps() { return NumCast(this.selectedDoc?.x); } // prettier-ignore + set shapeXps(value) { this.selectedDoc && (this.selectedDoc.x = Math.round(value * 100) / 100); } // prettier-ignore + @computed get shapeYps() { return NumCast(this.selectedDoc?.y); } // prettier-ignore + set shapeYps(value) { this.selectedDoc && (this.selectedDoc.y = Math.round(value * 100) / 100); } // prettier-ignore + @computed get shapeWid() { return NumCast(this.selectedDoc?._width); } // prettier-ignore + set shapeWid(value) { this.selectedDoc && (this.selectedDoc._width = Math.round(value * 100) / 100); } // prettier-ignore + @computed get shapeHgt() { return NumCast(this.selectedDoc?._height); } // prettier-ignore + set shapeHgt(value) { this.selectedDoc && (this.selectedDoc._height = Math.round(value * 100) / 100); } // prettier-ignore + @computed get strokeThk(){ return NumCast(this.selectedDoc?.[DocData].stroke_width); } // prettier-ignore + set strokeThk(value) { this.selectedDoc && (this.selectedDoc[DocData].stroke_width = Math.round(value * 100) / 100); } // prettier-ignore @computed get hgtInput() { return this.inputBoxDuo( 'hgt', this.shapeHgt, - undoable((val: string) => !isNaN(Number(val)) && (this.shapeHgt = +val), 'set height'), + undoable((val: string) => { + !Number(val) && (this.shapeHgt = +val); + }, 'set height'), 'H:', 'wid', this.shapeWid, - undoable((val: string) => !isNaN(Number(val)) && (this.shapeWid = +val), 'set width'), + undoable((val: string) => { + !isNaN(Number(val)) && (this.shapeWid = +val); + }, 'set width'), 'W:' ); } @computed get XpsInput() { + // prettier-ignore return this.inputBoxDuo( 'Xps', this.shapeXps, - undoable((val: string) => val !== '0' && !isNaN(Number(val)) && (this.shapeXps = +val), 'set x coord'), + undoable((val: string) => { val !== '0' && !isNaN(Number(val)) && (this.shapeXps = +val); }, 'set x coord'), 'X:', 'Yps', this.shapeYps, - undoable((val: string) => val !== '0' && !isNaN(Number(val)) && (this.shapeYps = +val), 'set y coord'), + undoable((val: string) => { val !== '0' && !isNaN(Number(val)) && (this.shapeYps = +val); }, 'set y coord'), 'Y:' ); } @@ -854,22 +842,14 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps private _lastDash: any = '2'; - @computed get colorFil() { - return StrCast(this.selectedDoc?.[DocData].fillColor); - } - @computed get colorStk() { - return StrCast(this.selectedDoc?.[DocData].color); - } - set colorFil(value) { - this.selectedDoc && (this.selectedDoc[DocData].fillColor = value ? value : undefined); - } - set colorStk(value) { - this.selectedDoc && (this.selectedDoc[DocData].color = value ? value : undefined); - } + @computed get colorFil() { return StrCast(this.selectedDoc?.[DocData].fillColor); } // prettier-ignore + set colorFil(value) { this.selectedDoc && (this.selectedDoc[DocData].fillColor = value || undefined); } // prettier-ignore + @computed get colorStk() { return StrCast(this.selectedDoc?.[DocData].color); } // prettier-ignore + set colorStk(value) { this.selectedDoc && (this.selectedDoc[DocData].color = value || undefined); } // prettier-ignore colorButton(value: string, type: string, setter: () => void) { return ( - <div className="color-button" key="color" onPointerDown={action(e => setter())}> + <div className="color-button" key="color" onPointerDown={action(() => setter())}> <div className="color-button-preview" style={{ @@ -888,7 +868,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps return ( <SketchPicker onChange={undoable( - action((color: ColorResult) => setter(color.hex)), + action((col: ColorResult) => setter(col.hex)), 'set stroke color property' )} presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']} @@ -911,10 +891,10 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps } @computed get fillPicker() { - return this.colorPicker(this.colorFil, (color: string) => (this.colorFil = color)); + return this.colorPicker(this.colorFil, (color: string) => { this.colorFil = color; }); // prettier-ignore } @computed get linePicker() { - return this.colorPicker(this.colorStk, (color: string) => (this.colorStk = color)); + return this.colorPicker(this.colorStk, (color: string) => { this.colorStk = color; }); // prettier-ignore } @computed get strokeAndFill() { @@ -936,60 +916,41 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps ); } - @computed get dashdStk() { - return this.selectedDoc?.stroke_dash || ''; - } - @computed get widthStk() { - return this.getField('stroke_width') || '1'; - } - @computed get markScal() { - return Number(this.getField('stroke_markerScale') || '1'); - } - @computed get markHead() { - return this.getField('stroke_startMarker') || ''; - } - @computed get markTail() { - return this.getField('stroke_endMarker') || ''; - } + @computed get dashdStk() { return this.selectedDoc?.stroke_dash || ''; } // prettier-ignore set dashdStk(value) { value && (this._lastDash = value); this.selectedDoc && (this.selectedDoc[DocData].stroke_dash = value ? this._lastDash : undefined); } - set markScal(value) { - this.selectedDoc && (this.selectedDoc[DocData].stroke_markerScale = Number(value)); - } + @computed get widthStk() { return this.getField('stroke_width') || '1'; } // prettier-ignore set widthStk(value) { this.selectedDoc && (this.selectedDoc[DocData].stroke_width = Number(value)); } + @computed get markScal() { return Number(this.getField('stroke_markerScale') || '1'); } // prettier-ignore + set markScal(value) { + this.selectedDoc && (this.selectedDoc[DocData].stroke_markerScale = Number(value)); + } + @computed get markHead() { return this.getField('stroke_startMarker') || ''; } // prettier-ignore set markHead(value) { this.selectedDoc && (this.selectedDoc[DocData].stroke_startMarker = value); } + @computed get markTail() { return this.getField('stroke_endMarker') || ''; } // prettier-ignore set markTail(value) { this.selectedDoc && (this.selectedDoc[DocData].stroke_endMarker = value); } - @computed get stkInput() { - return this.regInput('stk', this.widthStk, (val: string) => (this.widthStk = val)); - } - @computed get markScaleInput() { - return this.regInput('scale', this.markScal.toString(), (val: string) => (this.markScal = Number(val))); - } - - regInput = (key: string, value: any, setter: (val: string) => {}) => { - return ( - <div className="inputBox"> - <input className="inputBox-input" type="text" value={value} style={{ color: SettingsManager.userColor, backgroundColor: SettingsManager.userBackgroundColor }} onChange={e => setter(e.target.value)} /> - <div className="inputBox-button"> - <div className="inputBox-button-up" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons('up', key)))}> - <FontAwesomeIcon icon="caret-up" size="sm" /> - </div> - <div className="inputbox-Button-down" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons('down', key)))}> - <FontAwesomeIcon icon="caret-down" size="sm" /> - </div> + regInput = (key: string, value: any, setter: (val: string) => {}) => ( + <div className="inputBox"> + <input className="inputBox-input" type="text" value={value} style={{ color: SettingsManager.userColor, backgroundColor: SettingsManager.userBackgroundColor }} onChange={e => setter(e.target.value)} /> + <div className="inputBox-button"> + <div className="inputBox-button-up" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons('up', key)))}> + <FontAwesomeIcon icon="caret-up" size="sm" /> + </div> + <div className="inputbox-Button-down" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons('down', key)))}> + <FontAwesomeIcon icon="caret-down" size="sm" /> </div> </div> - ); - }; + </div> + ); @action CloseAll = () => { @@ -1005,18 +966,55 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps @computed get widthAndDash() { return ( + // prettier-ignore <div className="widthAndDash"> - <div className="width">{this.getNumber('Thickness', '', 0, Math.max(50, this.strokeThk), this.strokeThk, (val: number) => !isNaN(val) && (this.strokeThk = val), 50, 1)}</div> - <div className="width">{this.getNumber('Arrow Scale', '', 0, Math.max(10, this.markScal), this.markScal, (val: number) => !isNaN(val) && (this.markScal = val), 10, 1)}</div> + <div className="width"> + {this.getNumber( + 'Thickness', + '', + 0, + Math.max(50, this.strokeThk), + this.strokeThk, + (val: number) => { !isNaN(val) && (this.strokeThk = val); }, + 50, + 1 + )} + </div> + <div className="width"> + {this.getNumber( + 'Arrow Scale', + '', + 0, + Math.max(10, this.markScal), + this.markScal, + (val: number) => { !isNaN(val) && (this.markScal = val); }, + 10, + 1 + )} + </div> <div className="arrows"> <div className="arrows-head"> <div className="arrows-head-title">Arrow Head: </div> - <input key="markHead" className="arrows-head-input" type="checkbox" checked={this.markHead !== ''} onChange={undoBatch(action(() => (this.markHead = this.markHead ? '' : 'arrow')))} /> + <input + key="markHead" + className="arrows-head-input" + type="checkbox" + checked={this.markHead !== ''} + onChange={undoBatch(action(() => { this.markHead = this.markHead ? '' : 'arrow'; }))} + /> </div> <div className="arrows-tail"> <div className="arrows-tail-title">Arrow End: </div> - <input key="markTail" className="arrows-tail-input" type="checkbox" checked={this.markTail !== ''} onChange={undoBatch(action(() => (this.markTail = this.markTail ? '' : 'arrow')))} /> + <input + key="markTail" + className="arrows-tail-input" + type="checkbox" + checked={this.markTail !== ''} + onChange={undoBatch( + action(() => { this.markTail = this.markTail ? '' : 'arrow'; }) + )} + /> </div> </div> <div className="dashed"> @@ -1045,50 +1043,53 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps setFinalNumber = () => { this._sliderBatch?.end(); }; - getNumber = (label: string, unit: string, min: number, max: number, number: number, setNumber: any, autorange?: number, autorangeMinVal?: number) => { - return ( - <div key={label + this.selectedDoc?.title}> - <NumberInput formLabel={label} formLabelPlacement={'left'} type={Type.SEC} unit={unit} fillWidth color={this.color} number={number} setNumber={setNumber} min={min} max={max} /> - <Slider - key={label} - onPointerDown={e => (this._sliderBatch = UndoManager.StartBatch('slider ' + label))} - multithumb={false} - color={this.color} - size={Size.XSMALL} - min={min} - max={max} - autorangeMinVal={autorangeMinVal} - autorange={autorange} - number={number} - unit={unit} - decimals={1} - setFinalNumber={this.setFinalNumber} - setNumber={setNumber} - fillWidth - /> - </div> - ); - }; + getNumber = (label: string, unit: string, min: number, max: number, number: number, setNumber: any, autorange?: number, autorangeMinVal?: number) => ( + <div key={label + (this.selectedDoc?.title ?? '')}> + <NumberInput formLabel={label} formLabelPlacement="left" type={Type.SEC} unit={unit} fillWidth color={this.color} number={number} setNumber={setNumber} min={min} max={max} /> + <Slider + key={label} + onPointerDown={() => { + this._sliderBatch = UndoManager.StartBatch('slider ' + label); + }} + multithumb={false} + color={this.color} + size={Size.XSMALL} + min={min} + max={max} + autorangeMinVal={autorangeMinVal} + autorange={autorange} + number={number} + unit={unit} + decimals={1} + setFinalNumber={this.setFinalNumber} + setNumber={setNumber} + fillWidth + /> + </div> + ); + setVal = (func: (doc: Doc, val: number) => void) => (val: number) => this.selectedDoc && !isNaN(val) && func(this.selectedDoc, val); @computed get transformEditor() { return ( + // prettier-ignore <div className="transform-editor"> - {!this.isStack ? null : this.getNumber('Gap', ' px', 0, 200, NumCast(this.selectedDoc!.gridGap), (val: number) => !isNaN(val) && (this.selectedDoc!.gridGap = val))} - {!this.isStack ? null : this.getNumber('xMargin', ' px', 0, 500, NumCast(this.selectedDoc!.xMargin), (val: number) => !isNaN(val) && (this.selectedDoc!.xMargin = val))} - {!this.isStack ? null : this.getNumber('yMargin', ' px', 0, 500, NumCast(this.selectedDoc!.yMargin), (val: number) => !isNaN(val) && (this.selectedDoc!.yMargin = val))} - {!this.isGroup ? null : this.getNumber('Padding', ' px', 0, 500, NumCast(this.selectedDoc!.xPadding), (val: number) => !isNaN(val) && (this.selectedDoc!.xPadding = this.selectedDoc!.yPadding = val))} + {!this.isStack ? null : this.getNumber('Gap', ' px', 0, 200, NumCast(this.selectedDoc!.gridGap), this.setVal((doc: Doc, val: number) => { doc.gridGap = val; })) } + {!this.isStack ? null : this.getNumber('xMargin', ' px', 0, 500, NumCast(this.selectedDoc!.xMargin), this.setVal((doc: Doc, val: number) => { doc.xMargin = val; })) } + {!this.isStack ? null : this.getNumber('yMargin', ' px', 0, 500, NumCast(this.selectedDoc!.yMargin), this.setVal((doc: Doc, val: number) => { doc.yMargin = val; })) } + {!this.isGroup ? null : this.getNumber('Padding', ' px', 0, 500, NumCast(this.selectedDoc!.xPadding), this.setVal((doc: Doc, val: number) => { doc.xPadding = doc.yPadding = val; })) } {this.isInk ? this.controlPointsButton : null} - {this.getNumber('Width', ' px', 0, Math.max(1000, this.shapeWid), this.shapeWid, (val: number) => !isNaN(val) && (this.shapeWid = val), 1000, 1)} - {this.getNumber('Height', ' px', 0, Math.max(1000, this.shapeHgt), this.shapeHgt, (val: number) => !isNaN(val) && (this.shapeHgt = val), 1000, 1)} - {this.getNumber('X', ' px', this.shapeXps - 500, this.shapeXps + 500, this.shapeXps, (val: number) => !isNaN(val) && (this.shapeXps = val), 1000)} - {this.getNumber('Y', ' px', this.shapeYps - 500, this.shapeYps + 500, this.shapeYps, (val: number) => !isNaN(val) && (this.shapeYps = val), 1000)} + {this.getNumber('Width', ' px', 0, Math.max(1000, this.shapeWid), this.shapeWid, this.setVal((doc: Doc, val:number) => {this.shapeWid = val}), 1000, 1)} + {this.getNumber('Height', ' px', 0, Math.max(1000, this.shapeHgt), this.shapeHgt, this.setVal((doc: Doc, val:number) => {this.shapeHgt = val}), 1000, 1)} + {this.getNumber('X', ' px', this.shapeXps - 500, this.shapeXps + 500, this.shapeXps, this.setVal((doc: Doc, val:number) => {this.shapeXps = val}), 1000)} + {this.getNumber('Y', ' px', this.shapeYps - 500, this.shapeYps + 500, this.shapeYps, this.setVal((doc: Doc, val:number) => {this.shapeYps = val}), 1000)} </div> ); } @computed get optionsSubMenu() { return ( - <PropertiesSection title="Options" inSection={this.inOptions} isOpen={this.openOptions} setInSection={bool => (this.inOptions = bool)} setIsOpen={bool => (this.openOptions = bool)} onDoubleClick={this.CloseAll}> + // prettier-ignore + <PropertiesSection title="Options" isOpen={this.openOptions} setIsOpen={bool => { this.openOptions = bool; }} onDoubleClick={this.CloseAll}> <PropertiesButtons /> </PropertiesSection> ); @@ -1096,12 +1097,23 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps @computed get sharingSubMenu() { return ( - <PropertiesSection title="Sharing and Permissions" isOpen={this.openSharing} setIsOpen={bool => (this.openSharing = bool)} onDoubleClick={() => this.CloseAll()}> + // prettier-ignore + <PropertiesSection + title="Sharing and Permissions" + isOpen={this.openSharing} + setIsOpen={bool => { this.openSharing = bool; }} + onDoubleClick={this.CloseAll}> <> {/* <div className="propertiesView-buttonContainer"> */} <div className="propertiesView-acls-checkbox"> Layout Permissions - <Checkbox color="primary" onChange={action(() => (this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} /> + <Checkbox + color="primary" + onChange={action(() => { + this.layoutDocAcls = !this.layoutDocAcls; + })} + checked={this.layoutDocAcls} + /> </div> {/* <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}> <button onPointerDown={() => SharingManager.Instance.distributeOverCollection(this.selectedDoc!)}> @@ -1141,7 +1153,8 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps @computed get filtersSubMenu() { return ( - <PropertiesSection title="Filters" isOpen={this.openFilters} setIsOpen={bool => (this.openFilters = bool)} onDoubleClick={() => this.CloseAll()}> + // prettier-ignore + <PropertiesSection title="Filters" isOpen={this.openFilters} setIsOpen={bool => { this.openFilters = bool; }} onDoubleClick={this.CloseAll}> <div className="propertiesView-content filters" style={{ position: 'relative', height: 'auto' }}> <FilterPanel Document={this.selectedDoc ?? Doc.ActiveDashboard!} /> </div> @@ -1151,11 +1164,12 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps @computed get inkSubMenu() { return ( + // prettier-ignore <> - <PropertiesSection title="Appearance" isOpen={this.openAppearance} setIsOpen={bool => (this.openAppearance = bool)} onDoubleClick={() => this.CloseAll()}> + <PropertiesSection title="Appearance" isOpen={this.openAppearance} setIsOpen={bool => { this.openAppearance = bool; }} onDoubleClick={this.CloseAll}> {this.selectedLayoutDoc?.layout_isSvg ? this.appearanceEditor : null} </PropertiesSection> - <PropertiesSection title="Transform" isOpen={this.openTransform} setIsOpen={bool => (this.openTransform = bool)} onDoubleClick={() => this.CloseAll()}> + <PropertiesSection title="Transform" isOpen={this.openTransform} setIsOpen={bool => { this.openTransform = bool; }} onDoubleClick={this.CloseAll}> {this.transformEditor} </PropertiesSection> </> @@ -1164,7 +1178,13 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps @computed get fieldsSubMenu() { return ( - <PropertiesSection title="Fields & Tags" isOpen={this.openFields} setIsOpen={bool => (this.openFields = bool)} onDoubleClick={() => this.CloseAll()}> + <PropertiesSection + title="Fields & Tags" + isOpen={this.openFields} + setIsOpen={bool => { + this.openFields = bool; + }} + onDoubleClick={this.CloseAll}> <div className="propertiesView-content fields">{Doc.noviceMode ? this.noviceFields : this.expandedField}</div> </PropertiesSection> ); @@ -1172,7 +1192,13 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps @computed get contextsSubMenu() { return ( - <PropertiesSection title="Other Contexts" isOpen={this.openContexts} setIsOpen={bool => (this.openContexts = bool)} onDoubleClick={() => this.CloseAll()}> + <PropertiesSection + title="Other Contexts" + isOpen={this.openContexts} + setIsOpen={bool => { + this.openContexts = bool; + }} + onDoubleClick={this.CloseAll}> {this.contextCount > 0 ? this.contexts : 'There are no other contexts.'} </PropertiesSection> ); @@ -1180,7 +1206,13 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps @computed get linksSubMenu() { return ( - <PropertiesSection title="Linked To" isOpen={this.openLinks} setIsOpen={bool => (this.openLinks = bool)} onDoubleClick={this.CloseAll}> + <PropertiesSection + title="Linked To" + isOpen={this.openLinks} + setIsOpen={bool => { + this.openLinks = bool; + }} + onDoubleClick={this.CloseAll}> {this.linkCount > 0 ? this.links : 'There are no current links.'} </PropertiesSection> ); @@ -1188,14 +1220,20 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps @computed get layoutSubMenu() { return ( - <PropertiesSection title="Layout" isOpen={this.openLayout} setIsOpen={bool => (this.openLayout = bool)} onDoubleClick={this.CloseAll}> + <PropertiesSection + title="Layout" + isOpen={this.openLayout} + setIsOpen={bool => { + this.openLayout = bool; + }} + onDoubleClick={this.CloseAll}> {this.layoutPreview} </PropertiesSection> ); } @computed get description() { - return Field.toString(this.selectedLink?.link_description as any as Field); + return Field.toString(this.selectedLink?.link_description as any as FieldType); } @computed get relationship() { return StrCast(this.selectedLink?.link_relationship); @@ -1250,12 +1288,12 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps // if the relationship is already in the list AND the new rel is different from the prev rel, update the rel sizes } else if (linkRelationshipList && value !== prevRelationship) { const index = linkRelationshipList.indexOf(value); - //increment size of new relationship size + // increment size of new relationship size if (index !== -1 && index < linkRelationshipSizes.length) { const pvalue = linkRelationshipSizes[index]; linkRelationshipSizes[index] = pvalue === undefined || !Number.isFinite(pvalue) ? 1 : pvalue + 1; } - //decrement the size of the previous relationship if it already exists (i.e. not default 'link' relationship upon link creation) + // decrement the size of the previous relationship if it already exists (i.e. not default 'link' relationship upon link creation) if (linkRelationshipList.includes(prevRelationship)) { const pindex = linkRelationshipList.indexOf(prevRelationship); if (pindex !== -1 && pindex < linkRelationshipSizes.length) { @@ -1265,21 +1303,25 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps } } this.relationshipButtonColor = 'rgb(62, 133, 55)'; - setTimeout( - action(() => (this.relationshipButtonColor = '')), - 750 - ); + setTimeout(action(() => { this.relationshipButtonColor = ''; }), 750); // prettier-ignore return true; } + return undefined; }); - changeFollowBehavior = undoable((loc: Opt<string>) => this.sourceAnchor && (this.sourceAnchor.followLinkLocation = loc), 'change follow behavior'); + changeFollowBehavior = undoable((loc: Opt<string>) => { + this.sourceAnchor && (this.sourceAnchor.followLinkLocation = loc); + }, 'change follow behavior'); @undoBatch - changeAnimationBehavior = action((behavior: string) => this.sourceAnchor && (this.sourceAnchor.followLinkAnimEffect = behavior)); + changeAnimationBehavior = action((behavior: string) => { + this.sourceAnchor && (this.sourceAnchor.followLinkAnimEffect = behavior); + }); @undoBatch - changeEffectDirection = action((effect: PresEffectDirection) => this.sourceAnchor && (this.sourceAnchor.followLinkAnimDirection = effect)); + 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; @@ -1300,7 +1342,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps document.getElementById('link_description_input')?.blur(); }; - onDescriptionKey = (e: React.KeyboardEvent<HTMLTextAreaElement>) => { + onDescriptionKey = () => { // if (e.key === 'Enter') { // this.setDescripValue(this.description); // document.getElementById('link_description_input')?.blur(); @@ -1320,20 +1362,26 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps }; toggleLinkProp = (e: React.PointerEvent, prop: string) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedLink && (this.selectedLink[prop] = !this.selectedLink[prop])))); + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + undoBatch(action(() => { this.selectedLink && (this.selectedLink[prop] = !this.selectedLink[prop]); })) // prettier-ignore + ); }; @computed get destinationAnchor() { const ldoc = this.selectedLink; const lanch = this.selectedDocumentView?.anchorViewDoc ?? LinkManager.Instance.currentLinkAnchor; - if (ldoc && lanch) return LinkManager.getOppositeAnchor(ldoc, lanch) ?? lanch; + if (ldoc && lanch) return Doc.getOppositeAnchor(ldoc, lanch) ?? lanch; return ldoc ? DocCast(ldoc.link_anchor_2) : ldoc; } @computed get sourceAnchor() { const selAnchor = this.selectedDocumentView?.anchorViewDoc ?? LinkManager.Instance.currentLinkAnchor; - return selAnchor ?? (this.selectedLink && this.destinationAnchor ? LinkManager.getOppositeAnchor(this.selectedLink, this.destinationAnchor) : this.selectedLink); + return selAnchor ?? (this.selectedLink && this.destinationAnchor ? Doc.getOppositeAnchor(this.selectedLink, this.destinationAnchor) : this.selectedLink); } toggleAnchorProp = (e: React.PointerEvent, prop: string, anchor?: Doc, value: any = true, ovalue: any = false, cb: (val: any) => any = val => val) => { @@ -1343,12 +1391,10 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps e, returnFalse, emptyFunction, - undoBatch( - action(() => { - anchor[prop] = anchor[prop] === value ? ovalue : value; - this.selectedDoc && cb(anchor[prop]); - }) - ) + undoBatch(action(() => { + anchor[prop] = anchor[prop] === value ? ovalue : value; + this.selectedDoc && cb(anchor[prop]); + })) // prettier-ignore ); }; @@ -1357,7 +1403,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps return ( <input style={{ color: SettingsManager.userColor, backgroundColor: SettingsManager.userBackgroundColor }} - autoComplete={'off'} + autoComplete="off" id="link_relationship_input" value={StrCast(this.selectedLink?.link_relationship)} onKeyDown={this.onRelationshipKey} @@ -1398,7 +1444,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps const zoom = Number((NumCast(this.sourceAnchor?.followLinkZoomScale, 1) * 100).toPrecision(3)); const targZoom = this.sourceAnchor?.followLinkZoom; const indent = 30; - const hasSelectedAnchor = this.selectedLink !== this.selectedDoc && LinkManager.Links(this.sourceAnchor).includes(this.selectedLink!); + const hasSelectedAnchor = this.selectedLink !== this.selectedDoc && Doc.Links(this.sourceAnchor).includes(this.selectedLink!); return ( <> @@ -1425,7 +1471,8 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps <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.lightbox}>Opening in lightbox</option> + <option value={OpenWhere.lightboxAlways}>Opening in lightbox always</option> + <option value={OpenWhere.lightbox}>Opening in lightbox if not visible</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> @@ -1459,11 +1506,14 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps '10', NumCast(this.sourceAnchor?.followLinkTransitionTime) / 1000, true, - (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS)), + (val: string) => + PresBox.SetTransitionTime(val, (timeInMS: number) => { + this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS); + }), indent )}{' '} <div - className={'slider-headers'} + className="slider-headers" style={{ display: 'grid', justifyContent: 'space-between', @@ -1478,111 +1528,147 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps </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> + { + // eslint-disable-next-line jsx-a11y/control-has-associated-label + <button + type="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>Play Target Video</p> - <button - style={{ background: !this.sourceAnchor?.followLinkVideo ? '' : '#4476f7', borderRadius: 3 }} - onPointerDown={e => this.toggleAnchorProp(e, 'followLinkVideo', this.sourceAnchor)} - onClick={e => e.stopPropagation()} - className="propertiesButton"> - <FontAwesomeIcon className="fa-icon" icon={faAnchor as IconLookup} size="lg" /> - </button> + { + // eslint-disable-next-line jsx-a11y/control-has-associated-label + <button + type="button" + style={{ background: !this.sourceAnchor?.followLinkVideo ? '' : '#4476f7', borderRadius: 3 }} + onPointerDown={e => this.toggleAnchorProp(e, 'followLinkVideo', 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> + { + // eslint-disable-next-line jsx-a11y/control-has-associated-label + <button + type="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> + { + // eslint-disable-next-line jsx-a11y/control-has-associated-label + <button + type="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> + { + // eslint-disable-next-line jsx-a11y/control-has-associated-label + <button + type="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> + { + // eslint-disable-next-line jsx-a11y/control-has-associated-label + <button + type="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> + { + // eslint-disable-next-line jsx-a11y/control-has-associated-label + <button + type="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> + { + // eslint-disable-next-line jsx-a11y/control-has-associated-label + <button + type="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%', color: SettingsManager.userColor, backgroundColor: SettingsManager.userBackgroundColor }} readOnly={true} type="number" value={zoom} /> + <input className="presBox-input" style={{ width: '100%', color: SettingsManager.userColor, backgroundColor: SettingsManager.userBackgroundColor }} readOnly 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'} /> + <FontAwesomeIcon icon="caret-up" /> </div> <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), -0.1))}> - <FontAwesomeIcon icon={'caret-down'} /> + <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> + { + // eslint-disable-next-line jsx-a11y/control-has-associated-label + <button + type="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'} + className="slider-headers" style={{ display: !targZoom ? 'none' : 'grid', justifyContent: 'space-between', @@ -1594,7 +1680,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps }}> <div className="slider-text">0%</div> <div className="slider-text">100%</div> - </div>{' '} + </div> </div> )} </> @@ -1622,128 +1708,136 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps </div> </div> ); - } else { - if (this.selectedDoc && !this.isPres) { - return ( - <div - className="propertiesView" - style={{ - background: SettingsManager.userBackgroundColor, - color: SettingsManager.userColor, - width: this._props.width, - minWidth: this._props.width, - }}> - <div className="propertiesView-propAndInfoGrouping"> - <div className="propertiesView-sectionTitle" style={{ width: this._props.width }}> - Properties - <div className="propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties')}> - <IconButton icon={<FontAwesomeIcon icon="info-circle" />} color={SettingsManager.userColor} /> - </div> + } + if (this.selectedDoc && !this.isPres) { + return ( + <div + className="propertiesView" + style={{ + background: SettingsManager.userBackgroundColor, + color: SettingsManager.userColor, + width: this._props.width, + minWidth: this._props.width, + }}> + <div className="propertiesView-propAndInfoGrouping"> + <div className="propertiesView-sectionTitle" style={{ width: this._props.width }}> + Properties + <div className="propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/properties')}> + <IconButton icon={<FontAwesomeIcon icon="info-circle" />} color={SettingsManager.userColor} /> </div> </div> + </div> - <div className="propertiesView-name">{this.editableTitle}</div> - <div className="propertiesView-type"> {this.currentType} </div> - {this.fieldsSubMenu} - {this.optionsSubMenu} - {this.linksSubMenu} - {!this.selectedLink || !this.openLinks ? null : this.linkProperties} - {this.inkSubMenu} - {this.contextsSubMenu} - {isNovice ? null : this.sharingSubMenu} - {this.filtersSubMenu} - {isNovice ? null : this.layoutSubMenu} + <div className="propertiesView-name">{this.editableTitle}</div> + <div className="propertiesView-type"> {this.currentType} </div> + {this.fieldsSubMenu} + {this.optionsSubMenu} + {this.linksSubMenu} + {!this.selectedLink || !this.openLinks ? null : this.linkProperties} + {this.inkSubMenu} + {this.contextsSubMenu} + {isNovice ? null : this.sharingSubMenu} + {this.filtersSubMenu} + {isNovice ? null : this.layoutSubMenu} + </div> + ); + } + if (this.isPres && PresBox.Instance) { + const selectedItem: boolean = PresBox.Instance.selectedArray.size > 0; + const type = [DocumentType.AUDIO, DocumentType.VID].find(dt => dt === DocCast(PresBox.Instance.activeItem?.annotationOn)?.type) + ? DocCast(PresBox.Instance.activeItem?.annotationOn)?.type + : PresBox.targetRenderedDoc(PresBox.Instance.activeItem)?.type; + return ( + <div className="propertiesView" style={{ width: this._props.width }}> + <div className="propertiesView-sectionTitle" style={{ width: this._props.width }}> + Presentation </div> - ); - } - 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-sectionTitle" style={{ width: this._props.width }}> - Presentation + <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> - <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> - </div> - {!selectedItem ? null : ( - <div className="propertiesView-presentationTrails"> - <div - className="propertiesView-presentationTrails-title" - onPointerDown={action(() => (this.openPresTransitions = !this.openPresTransitions))} - style={{ - color: SettingsManager.userColor, - backgroundColor: this.openPresTransitions ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor, - }}> - <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> Transitions - <div className="propertiesView-presentationTrails-title-icon"> - <FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg" /> - </div> + </div> + {!selectedItem ? null : ( + <div className="propertiesView-presentationTrails"> + <div + className="propertiesView-presentationTrails-title" + onPointerDown={action(() => { + this.openPresTransitions = !this.openPresTransitions; + })} + style={{ + color: SettingsManager.userColor, + backgroundColor: this.openPresTransitions ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor, + }}> + <FontAwesomeIcon style={{ alignSelf: 'center' }} icon="rocket" /> Transitions + <div className="propertiesView-presentationTrails-title-icon"> + <FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg" /> </div> - {this.openPresTransitions ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.transitionDropdown}</div> : null} </div> - )} - {!selectedItem ? null : ( - <div className="propertiesView-presentationTrails"> - <div - className="propertiesView-presentationTrails-title" - onPointerDown={action(() => (this.openPresVisibilityAndDuration = !this.openPresVisibilityAndDuration))} - style={{ - color: SettingsManager.userColor, - backgroundColor: this.openPresVisibilityAndDuration ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor, - }}> - <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> Visibility - <div className="propertiesView-presentationTrails-title-icon"> - <FontAwesomeIcon icon={this.openPresVisibilityAndDuration ? 'caret-down' : 'caret-right'} size="lg" /> - </div> + {this.openPresTransitions ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.transitionDropdown}</div> : null} + </div> + )} + {!selectedItem ? null : ( + <div className="propertiesView-presentationTrails"> + <div + className="propertiesView-presentationTrails-title" + onPointerDown={action(() => { + this.openPresVisibilityAndDuration = !this.openPresVisibilityAndDuration; + })} + style={{ + color: SettingsManager.userColor, + backgroundColor: this.openPresVisibilityAndDuration ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor, + }}> + <FontAwesomeIcon style={{ alignSelf: 'center' }} icon="rocket" /> Visibility + <div className="propertiesView-presentationTrails-title-icon"> + <FontAwesomeIcon icon={this.openPresVisibilityAndDuration ? 'caret-down' : 'caret-right'} size="lg" /> </div> - {this.openPresVisibilityAndDuration ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.visibilityDurationDropdown}</div> : null} </div> - )} - {!selectedItem ? null : ( - <div className="propertiesView-presentationTrails"> - <div - className="propertiesView-presentationTrails-title" - onPointerDown={action(() => (this.openPresProgressivize = !this.openPresProgressivize))} - style={{ - color: SettingsManager.userColor, - backgroundColor: this.openPresProgressivize ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor, - }}> - <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> Progressivize - <div className="propertiesView-presentationTrails-title-icon"> - <FontAwesomeIcon icon={this.openPresProgressivize ? 'caret-down' : 'caret-right'} size="lg" /> - </div> + {this.openPresVisibilityAndDuration ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.visibilityDurationDropdown}</div> : null} + </div> + )} + {!selectedItem ? null : ( + <div className="propertiesView-presentationTrails"> + <div + className="propertiesView-presentationTrails-title" + onPointerDown={action(() => { + this.openPresProgressivize = !this.openPresProgressivize; + })} + style={{ + color: SettingsManager.userColor, + backgroundColor: this.openPresProgressivize ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor, + }}> + <FontAwesomeIcon style={{ alignSelf: 'center' }} icon="rocket" /> Progressivize + <div className="propertiesView-presentationTrails-title-icon"> + <FontAwesomeIcon icon={this.openPresProgressivize ? 'caret-down' : 'caret-right'} size="lg" /> </div> - {this.openPresProgressivize ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.progressivizeDropdown}</div> : null} </div> - )} - {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? null : ( - <div className="propertiesView-presentationTrails"> - <div - className="propertiesView-presentationTrails-title" - onPointerDown={action(() => (this.openSlideOptions = !this.openSlideOptions))} - style={{ - color: SettingsManager.userColor, - backgroundColor: this.openSlideOptions ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor, - }}> - <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={type === DocumentType.AUDIO ? 'file-audio' : 'file-video'} /> {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'} - <div className="propertiesView-presentationTrails-title-icon"> - <FontAwesomeIcon icon={this.openSlideOptions ? 'caret-down' : 'caret-right'} size="lg" /> - </div> + {this.openPresProgressivize ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.progressivizeDropdown}</div> : null} + </div> + )} + {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? null : ( + <div className="propertiesView-presentationTrails"> + <div + className="propertiesView-presentationTrails-title" + onPointerDown={action(() => { + this.openSlideOptions = !this.openSlideOptions; + })} + style={{ + color: SettingsManager.userColor, + backgroundColor: this.openSlideOptions ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor, + }}> + <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={type === DocumentType.AUDIO ? 'file-audio' : 'file-video'} /> {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'} + <div className="propertiesView-presentationTrails-title-icon"> + <FontAwesomeIcon icon={this.openSlideOptions ? 'caret-down' : 'caret-right'} size="lg" /> </div> - {this.openSlideOptions ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.mediaOptionsDropdown}</div> : null} </div> - )} - </div> - ); - } + {this.openSlideOptions ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.mediaOptionsDropdown}</div> : null} + </div> + )} + </div> + ); } + return null; } } |