diff options
Diffstat (limited to 'src/client/views/PropertiesButtons.tsx')
-rw-r--r-- | src/client/views/PropertiesButtons.tsx | 212 |
1 files changed, 96 insertions, 116 deletions
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 517a80d63..edf6df2b9 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -1,3 +1,6 @@ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +/* eslint-disable react/no-unused-class-component-methods */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Dropdown, DropdownType, IListItemProps, Toggle, ToggleType, Type } from 'browndash-components'; import { action, computed, observable } from 'mobx'; @@ -12,98 +15,47 @@ import { MdClosedCaption, MdClosedCaptionDisabled, MdGridOff, MdGridOn, MdSubtit import { RxWidth } from 'react-icons/rx'; import { TbEditCircle, TbEditCircleOff, TbHandOff, TbHandStop, TbHighlight, TbHighlightOff } from 'react-icons/tb'; import { TfiBarChart } from 'react-icons/tfi'; -import { Doc, DocListCast, Opt } from '../../fields/Doc'; +import { Doc, Opt } from '../../fields/Doc'; import { DocData } from '../../fields/DocSymbols'; import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, ScriptCast } from '../../fields/Types'; import { ImageField } from '../../fields/URLField'; +import { DocUtils, IsFollowLinkScript } from '../documents/DocUtils'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; -import { DocUtils } from '../documents/Documents'; -import { IsFollowLinkScript } from '../util/LinkFollower'; -import { LinkManager } from '../util/LinkManager'; -import { SelectionManager } from '../util/SelectionManager'; import { SettingsManager } from '../util/SettingsManager'; import { undoBatch, undoable } from '../util/UndoManager'; import { InkingStroke } from './InkingStroke'; import './PropertiesButtons.scss'; import { Colors } from './global/globalEnums'; -import { DocumentView, OpenWhere } from './nodes/DocumentView'; +import { DocumentView } from './nodes/DocumentView'; +import { OpenWhere } from './nodes/OpenWhere'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; @observer export class PropertiesButtons extends React.Component<{}, {}> { + // eslint-disable-next-line no-use-before-define @observable public static Instance: PropertiesButtons; @computed get selectedDoc() { - return SelectionManager.SelectedSchemaDoc || SelectionManager.Views.lastElement()?.Document; + return DocumentView.SelectedSchemaDoc() || DocumentView.Selected().lastElement()?.Document; } @computed get selectedLayoutDoc() { - return SelectionManager.SelectedSchemaDoc || SelectionManager.Views.lastElement()?.layoutDoc; + return DocumentView.SelectedSchemaDoc() || DocumentView.Selected().lastElement()?.layoutDoc; } @computed get selectedTabView() { - return !SelectionManager.SelectedSchemaDoc && SelectionManager.Views.lastElement()?.topMost; - } - - propertyToggleBtn = (label: (on?: any) => string, property: string, tooltip: (on?: any) => string, icon: (on?: any) => any, onClick?: (dv: Opt<DocumentView>, doc: Doc, property: string) => void, useUserDoc?: boolean) => { - const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedLayoutDoc; - const onPropToggle = (dv: Opt<DocumentView>, doc: Doc, prop: string) => ((dv?.layoutDoc || doc)[prop] = (dv?.layoutDoc || doc)[prop] ? false : true); - return !targetDoc ? null : ( - <Toggle - toggleStatus={BoolCast(targetDoc[property])} - tooltip={tooltip(BoolCast(targetDoc[property]))} - text={label(targetDoc?.[property])} - color={SettingsManager.userColor} - icon={icon(targetDoc?.[property] as any)} - iconPlacement="left" - align="flex-start" - fillWidth={true} - toggleType={ToggleType.BUTTON} - onClick={undoable(() => { - if (SelectionManager.Views.length > 1) { - SelectionManager.Views.forEach(dv => (onClick ?? onPropToggle)(dv, dv.Document, property)); - } else if (targetDoc) (onClick ?? onPropToggle)(undefined, targetDoc, property); - }, property)} - /> - ); - }; - - // this implments a container pattern by marking the targetDoc (collection) as a lightbox - // that always fits its contents to its container and that hides all other documents when - // a link is followed that targets a 'lightbox' destination - @computed get isLightboxButton() { - return this.propertyToggleBtn( - on => 'Lightbox', - 'isLightbox', - on => `${on ? 'Set' : 'Remove'} lightbox flag`, - on => 'window-restore', - onClick => { - SelectionManager.Views.forEach(dv => { - const containerDoc = dv.Document; - //containerDoc.followAllLinks = - // containerDoc.noShadow = - // containerDoc.layout_disableBrushing = - // containerDoc._forceActive = - //containerDoc._freeform_fitContentsToBox = - containerDoc._isLightbox = !containerDoc._isLightbox; - //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined; - const containerContents = DocListCast(dv.dataDoc[Doc.LayoutFieldKey(containerDoc)]); - //dv.Docuemnt.onClick = ScriptField.MakeScript('{this.data = undefined; documentView.select(false)}', { documentView: 'any' }); - containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.link_displayLine = false))); - }); - } - ); + return !DocumentView.SelectedSchemaDoc() && DocumentView.Selected().lastElement()?.topMost; } @computed get titleButton() { return this.propertyToggleBtn( - on => (!on ? 'SHOW TITLE' : this.selectedDoc?.['_layout_showTitle'] === 'title:hover' ? 'HIDE TITLE' : 'HOVER TITLE'), + on => (!on ? 'SHOW TITLE' : this.selectedDoc?._layout_showTitle === 'title:hover' ? 'HIDE TITLE' : 'HOVER TITLE'), '_layout_showTitle', - on => 'Switch between title styles', + () => 'Switch between title styles', on => (on ? <MdSubtitlesOff /> : <MdSubtitles />), // {currentIcon}, //(on ? <MdSubtitles/> :) , //,'text-width', on ? <MdSubtitles/> : <MdSubtitlesOff/>, (dv, doc) => { const tdoc = dv?.Document || doc; const newtitle = !tdoc._layout_showTitle ? 'title' : tdoc._layout_showTitle === 'title' ? 'title:hover' : ''; - tdoc._layout_showTitle = newtitle ? newtitle : undefined; + tdoc._layout_showTitle = newtitle || undefined; } ); } @@ -119,7 +71,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { } @computed get maskButton() { - //highlight text while going down and reading through + // highlight text while going down and reading through return this.propertyToggleBtn( on => (on ? 'PLAIN INK' : 'HIGHLIGHTER MASK'), 'stroke_isInkMask', @@ -132,10 +84,10 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get hideImageButton() { // put in developer -- can trace on top of object and drawing is still there return this.propertyToggleBtn( - on => (on ? 'SHOW BACKGROUND IMAGE' : 'HIDE BACKGROUND IMAGE'), //'Background', + on => (on ? 'SHOW BACKGROUND IMAGE' : 'HIDE BACKGROUND IMAGE'), // 'Background', '_hideImage', on => (on ? 'Show Image' : 'Show Background'), - on => (on ? <BiShow /> : <BiHide />) //'portrait' + on => (on ? <BiShow /> : <BiHide />) // 'portrait' ); } @@ -144,35 +96,35 @@ export class PropertiesButtons extends React.Component<{}, {}> { on => (on ? 'DISABLE CLUSTERS' : 'HIGHLIGHT CLUSTERS'), '_freeform_useClusters', on => `${on ? 'Hide' : 'Show'} clusters`, - on => <FaBraille /> + () => <FaBraille /> ); } @computed get panButton() { return this.propertyToggleBtn( - on => (on ? 'ENABLE PANNING' : 'DISABLE PANNING'), //'Lock\xA0View', + on => (on ? 'ENABLE PANNING' : 'DISABLE PANNING'), // 'Lock\xA0View', '_lockedTransform', on => `${on ? 'Unlock' : 'Lock'} panning of view`, - on => (on ? <TbHandStop /> : <TbHandOff />) //'lock' + on => (on ? <TbHandStop /> : <TbHandOff />) // 'lock' ); } @computed get forceActiveButton() { - //select text + // select text return this.propertyToggleBtn( on => (on ? 'SELECT TO INTERACT' : 'ALWAYS INTERACTIVE'), '_forceActive', on => `${on ? 'Document must be selected to interact with its contents' : 'Contents always active (respond to click/drag events)'} `, - on => <MdTouchApp /> // 'eye' + () => <MdTouchApp /> // 'eye' ); } @computed get verticalAlignButton() { - //select text + // select text return this.propertyToggleBtn( on => (on ? 'ALIGN TOP' : 'ALIGN CENTER'), '_layout_centered', on => `${on ? 'Text is aligned with top of document' : 'Text is aligned with center of document'} `, - on => <MdTouchApp /> // 'eye' + () => <MdTouchApp /> // 'eye' ); } @@ -181,9 +133,9 @@ export class PropertiesButtons extends React.Component<{}, {}> { on => (on ? 'DISABLE FLASHCARD' : 'ENABLE FLASHCARD'), 'layout_textPainted', on => `${on ? 'Flashcard enabled' : 'Flashcard disabled'} `, - on => <MdTouchApp />, + () => <MdTouchApp />, (dv, doc) => { - const on = doc.onPaint ? true : false; + const on = !!doc.onPaint; doc[DocData].onPaint = on ? undefined : ScriptField.MakeScript(`toggleDetail(documentView, "textPainted")`, { documentView: 'any' }); doc[DocData].layout_textPainted = on ? undefined : `<ComparisonBox {...props} fieldKey={'${dv?.LayoutFieldKey ?? 'text'}'}/>`; } @@ -192,10 +144,10 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get fitContentButton() { return this.propertyToggleBtn( - on => (on ? 'PREVIOUS VIEW' : 'VIEW ALL'), //'View All', + on => (on ? 'PREVIOUS VIEW' : 'VIEW ALL'), // 'View All', '_freeform_fitContentsToBox', on => `${on ? "Don't" : 'Do'} fit content to container visible area`, - on => (on ? <CiGrid31 /> : <BsGrid3X3GapFill />) //'object-group' + on => (on ? <CiGrid31 /> : <BsGrid3X3GapFill />) // 'object-group' ); } @@ -209,7 +161,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { // on => `${on ? 'Set' : 'Remove'} lightbox flag`, // on => 'window-restore', // onClick => { - // SelectionManager.Views.forEach(dv => { + // DocumentView.Selected().forEach(dv => { // const containerDoc = dv.Document; // //containerDoc.followAllLinks = // // containerDoc.noShadow = @@ -228,7 +180,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get layout_fitWidthButton() { return this.propertyToggleBtn( - on => (on ? 'SCALED VIEW' : 'READING VIEW'), //'Fit\xA0Width', + on => (on ? 'SCALED VIEW' : 'READING VIEW'), // 'Fit\xA0Width', '_layout_fitWidth', on => on @@ -240,12 +192,14 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get captionButton() { return this.propertyToggleBtn( - //DEVELOPER - on => (on ? 'HIDE CAPTION' : 'SHOW CAPTION'), //'Caption', + // DEVELOPER + on => (on ? 'HIDE CAPTION' : 'SHOW CAPTION'), // 'Caption', '_layout_showCaption', on => `${on ? 'Hide' : 'Show'} caption footer`, - on => (on ? <MdClosedCaptionDisabled /> : <MdClosedCaption />), //'closed-captioning', - (dv, doc) => ((dv?.Document || doc)._layout_showCaption = (dv?.Document || doc)._layout_showCaption === undefined ? 'caption' : undefined) + on => (on ? <MdClosedCaptionDisabled /> : <MdClosedCaption />), // 'closed-captioning', + (dv, doc) => { + (dv?.Document || doc)._layout_showCaption = (dv?.Document || doc)._layout_showCaption === undefined ? 'caption' : undefined; + } ); } @@ -256,7 +210,9 @@ export class PropertiesButtons extends React.Component<{}, {}> { '_chromeHidden', on => `${on ? 'Show' : 'Hide'} editing UI`, on => (on ? <TbEditCircle /> : <TbEditCircleOff />), // 'edit', - (dv, doc) => ((dv?.Document || doc)._chromeHidden = !(dv?.Document || doc)._chromeHidden) + (dv, doc) => { + (dv?.Document || doc)._chromeHidden = !(dv?.Document || doc)._chromeHidden; + } ); } @@ -265,8 +221,8 @@ export class PropertiesButtons extends React.Component<{}, {}> { return this.propertyToggleBtn( on => (on ? 'AUTO\xA0SIZE' : 'FIXED SIZE'), '_layout_autoHeight', - on => `Automatical vertical sizing to show all content`, - on => <FontAwesomeIcon icon="arrows-alt-v" size="lg" /> + () => `Automatical vertical sizing to show all content`, + () => <FontAwesomeIcon icon="arrows-alt-v" size="lg" /> ); } @@ -274,8 +230,8 @@ export class PropertiesButtons extends React.Component<{}, {}> { return this.propertyToggleBtn( on => (on ? 'HIDE GRID' : 'DISPLAY GRID'), '_freeform_backgroundGrid', - on => `Display background grid in collection`, - on => (on ? <MdGridOff /> : <MdGridOn />) //'border-all' + () => `Display background grid in collection`, + on => (on ? <MdGridOff /> : <MdGridOn />) // 'border-all' ); } @@ -317,8 +273,8 @@ export class PropertiesButtons extends React.Component<{}, {}> { return this.propertyToggleBtn( on => (on ? 'HIDE SNAP LINES' : 'SHOW SNAP LINES'), 'freeform_snapLines', - on => `Display snapping lines when objects are dragged`, - on => <TfiBarChart />, //'th', + () => `Display snapping lines when objects are dragged`, + () => <TfiBarChart />, // 'th', undefined ); } @@ -361,18 +317,20 @@ export class PropertiesButtons extends React.Component<{}, {}> { @undoBatch handlePerspectiveChange = (e: any) => { this.selectedDoc && (this.selectedDoc._type_collection = e.target.value); - SelectionManager.Views.forEach(docView => (docView.layoutDoc._type_collection = e.target.value)); + DocumentView.Selected().forEach(docView => { + docView.layoutDoc._type_collection = e.target.value; + }); }; @computed get onClickVal() { const linkButton = IsFollowLinkScript(this.selectedDoc.onClick); const followLoc = this.selectedDoc._followLinkLocation; - const linkedToLightboxView = () => LinkManager.Links(this.selectedDoc).some(link => LinkManager.getOppositeAnchor(link, this.selectedDoc)?._isLightbox); + const linkedToLightboxView = () => Doc.Links(this.selectedDoc).some(link => Doc.getOppositeAnchor(link, this.selectedDoc)?._isLightbox); if (followLoc === OpenWhere.lightbox && !linkedToLightboxView()) return 'linkInPlace'; - else if (linkButton && followLoc === OpenWhere.addRight) return 'linkOnRight'; - else if (linkButton && this.selectedDoc._followLinkLocation === OpenWhere.lightbox && linkedToLightboxView()) return 'enterPortal'; - else if (ScriptCast(this.selectedDoc.onClick)?.script.originalScript.includes('toggleDetail')) return 'toggleDetail'; - else return 'nothing'; + if (linkButton && followLoc === OpenWhere.addRight) return 'linkOnRight'; + if (linkButton && this.selectedDoc._followLinkLocation === OpenWhere.lightbox && linkedToLightboxView()) return 'enterPortal'; + if (ScriptCast(this.selectedDoc.onClick)?.script.originalScript.includes('toggleDetail')) return 'toggleDetail'; + return 'nothing'; } @computed @@ -385,20 +343,18 @@ export class PropertiesButtons extends React.Component<{}, {}> { ['linkOnRight', 'Open Link on Right'], ]; - const items: IListItemProps[] = buttonList.map(value => { - return { - text: value[1], - val: value[1], - }; - }); + const items: IListItemProps[] = buttonList.map(value => ({ + text: value[1], + val: value[1], + })); return !this.selectedDoc ? null : ( <Dropdown - tooltip={'Choose onClick behavior'} + tooltip="Choose onClick behavior" items={items} - closeOnSelect={true} + closeOnSelect selectedVal={this.onClickVal} setSelectedVal={val => this.handleOptionChange(val as string)} - title={'Choose onClick behaviour'} + title="Choose onClick behaviour" color={SettingsManager.userColor} dropdownType={DropdownType.SELECT} type={Type.SEC} @@ -422,7 +378,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { @undoBatch @action handleOptionChange = (onClick: string) => { - SelectionManager.Views.forEach(docView => { + DocumentView.Selected().forEach(docView => { const linkButton = IsFollowLinkScript(docView.Document.onClick); docView.noOnClick(); switch (onClick) { @@ -440,16 +396,11 @@ export class PropertiesButtons extends React.Component<{}, {}> { docView.toggleFollowLink(false, false); docView.Document.followLinkLocation = linkButton ? OpenWhere.addRight : undefined; break; + default: } }); }; - @undoBatch - editOnClickScript = () => { - if (SelectionManager.Views.length) SelectionManager.Views.forEach(dv => DocUtils.makeCustomViewClicked(dv.Document, undefined, 'onClick')); - else this.selectedDoc && DocUtils.makeCustomViewClicked(this.selectedDoc, undefined, 'onClick'); - }; - @computed get onClickFlyout() { const buttonList = [ @@ -463,7 +414,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { const click = () => this.handleOptionChange(value[0]); const linkButton = IsFollowLinkScript(this.selectedDoc.onClick); const followLoc = this.selectedDoc._followLinkLocation; - const linkedToLightboxView = () => LinkManager.Links(this.selectedDoc).some(link => LinkManager.getOppositeAnchor(link, this.selectedDoc)?._isLightbox); + const linkedToLightboxView = () => Doc.Links(this.selectedDoc).some(link => Doc.getOppositeAnchor(link, this.selectedDoc)?._isLightbox); let active = false; // prettier-ignore @@ -473,6 +424,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { case 'enterPortal': active = linkButton && this.selectedDoc._followLinkLocation === OpenWhere.lightbox && linkedToLightboxView(); break; case 'toggleDetail':active = ScriptCast(this.selectedDoc.onClick)?.script.originalScript.includes('toggleDetail'); break; case 'nothing': active = !linkButton && this.selectedDoc.onClick === undefined;break; + default: } return ( <div className="list-item" key={`${value}`} style={{ backgroundColor: active ? Colors.LIGHT_BLUE : undefined }} onClick={click}> @@ -494,10 +446,40 @@ export class PropertiesButtons extends React.Component<{}, {}> { </div> ); } + @undoBatch + editOnClickScript = () => { + if (DocumentView.Selected().length) DocumentView.Selected().forEach(dv => DocUtils.makeCustomViewClicked(dv.Document, undefined, 'onClick')); + else this.selectedDoc && DocUtils.makeCustomViewClicked(this.selectedDoc, undefined, 'onClick'); + }; + + propertyToggleBtn = (label: (on?: any) => string, property: string, tooltip: (on?: any) => string, icon: (on?: any) => any, onClick?: (dv: Opt<DocumentView>, doc: Doc, property: string) => void, useUserDoc?: boolean) => { + const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedLayoutDoc; + const onPropToggle = (dv: Opt<DocumentView>, doc: Doc, prop: string) => { + (dv?.layoutDoc || doc)[prop] = !(dv?.layoutDoc || doc)[prop]; + }; + return !targetDoc ? null : ( + <Toggle + toggleStatus={BoolCast(targetDoc[property])} + tooltip={tooltip(BoolCast(targetDoc[property]))} + text={label(targetDoc?.[property])} + color={SettingsManager.userColor} + icon={icon(targetDoc?.[property] as any)} + iconPlacement="left" + align="flex-start" + fillWidth + toggleType={ToggleType.BUTTON} + onClick={undoable(() => { + if (DocumentView.Selected().length > 1) { + DocumentView.Selected().forEach(dv => (onClick ?? onPropToggle)(dv, dv.Document, property)); + } else if (targetDoc) (onClick ?? onPropToggle)(undefined, targetDoc, property); + }, property)} + /> + ); + }; render() { const layoutField = this.selectedDoc?.[Doc.LayoutFieldKey(this.selectedDoc)]; - const isText = SelectionManager.Views.lastElement()?.ComponentView instanceof FormattedTextBox; + const isText = DocumentView.Selected().lastElement()?.ComponentView instanceof FormattedTextBox; const isInk = this.selectedDoc?.layout_isSvg; const isImage = layoutField instanceof ImageField; const isMap = this.selectedDoc?.type === DocumentType.MAP; @@ -505,11 +487,9 @@ export class PropertiesButtons extends React.Component<{}, {}> { const isStacking = [CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.NoteTaking].includes(this.selectedDoc?._type_collection as any); const isFreeForm = this.selectedDoc?._type_collection === CollectionViewType.Freeform; const isTree = this.selectedDoc?._type_collection === CollectionViewType.Tree; - const isTabView = this.selectedTabView; const toggle = (ele: JSX.Element | null, style?: React.CSSProperties) => ( <div className="propertiesButtons-button" style={style}> - {' '} - {ele}{' '} + {ele} </div> ); const isNovice = Doc.noviceMode; |