aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/PropertiesButtons.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-05-22 11:25:32 -0400
committerbobzel <zzzman@gmail.com>2023-05-22 11:25:32 -0400
commitbed3309e1fda6597b2a8fea10ad82cd3a0402051 (patch)
treefe599bbdc5fca2c221e1e0f7a60995b7cd39f870 /src/client/views/PropertiesButtons.tsx
parent887a4f7e0fc25fde87b20a5de2e7b0aee561cc78 (diff)
parent3d26d5b2654841a9b92f3d66b28d1dc8e36cca6a (diff)
merged physics with master
Diffstat (limited to 'src/client/views/PropertiesButtons.tsx')
-rw-r--r--src/client/views/PropertiesButtons.tsx163
1 files changed, 86 insertions, 77 deletions
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 66c3ed439..76828a576 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -6,16 +6,18 @@ import { Doc, DocListCast, Opt } from '../../fields/Doc';
import { Id } from '../../fields/FieldSymbols';
import { InkField } from '../../fields/InkField';
import { RichTextField } from '../../fields/RichTextField';
-import { BoolCast, StrCast } from '../../fields/Types';
+import { BoolCast, ScriptCast, StrCast } from '../../fields/Types';
import { ImageField } from '../../fields/URLField';
+import { Utils } from '../../Utils';
import { DocUtils } from '../documents/Documents';
import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
+import { IsFollowLinkScript } from '../util/LinkFollower';
+import { LinkManager } from '../util/LinkManager';
import { SelectionManager } from '../util/SelectionManager';
-import { undoBatch } from '../util/UndoManager';
+import { undoable, undoBatch } from '../util/UndoManager';
import { Colors } from './global/globalEnums';
import { InkingStroke } from './InkingStroke';
import { DocumentView, OpenWhere } from './nodes/DocumentView';
-import { VideoBox } from './nodes/VideoBox';
import { pasteImageBitmap } from './nodes/WebBoxRenderer';
import './PropertiesButtons.scss';
import React = require('react');
@@ -48,11 +50,11 @@ export class PropertiesButtons extends React.Component<{}, {}> {
<div
className={`propertiesButtons-linkButton-empty toggle-${StrCast(targetDoc[property]).includes(':hover') ? 'hover' : targetDoc[property] ? 'on' : 'off'}`}
onPointerDown={e => e.stopPropagation()}
- onClick={undoBatch(() => {
+ onClick={undoable(() => {
if (SelectionManager.Views().length > 1) {
SelectionManager.Views().forEach(dv => (onClick ?? onPropToggle)(dv, dv.rootDoc, property));
} else if (targetDoc) (onClick ?? onPropToggle)(undefined, targetDoc, property);
- })}>
+ }, property)}>
<FontAwesomeIcon className="documentdecorations-icon" size="lg" icon={icon(BoolCast(targetDoc?.[property])) as any} />
</div>
<div className="propertiesButtons-title">{label}</div>
@@ -71,16 +73,24 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@computed get maskButton() {
return this.propertyToggleBtn(
'Mask',
- 'isInkMask',
+ 'stroke_isInkMask',
on => (on ? 'Make plain ink' : 'Make highlight mask'),
on => 'paint-brush',
(dv, doc) => InkingStroke.toggleMask(dv?.layoutDoc || doc)
);
}
+ @computed get hideImageButton() {
+ return this.propertyToggleBtn(
+ 'Background',
+ '_hideImage',
+ on => (on ? 'Show Image' : 'Show Background'),
+ on => 'portrait'
+ );
+ }
@computed get clustersButton() {
return this.propertyToggleBtn(
'Clusters',
- '_useClusters',
+ '_freeform_useClusters',
on => `${on ? 'Hide' : 'Show'} clusters`,
on => 'braille'
);
@@ -104,52 +114,41 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@computed get fitContentButton() {
return this.propertyToggleBtn(
'View All',
- '_fitContentsToBox',
+ '_freeform_fitContentsToBox',
on => `${on ? "Don't" : 'Do'} fit content to container visible area`,
- on => 'eye'
+ on => 'object-group'
);
}
- // this implments a container pattern by marking the targetDoc (collection) as an inPlace container,
- // and then making the contained collection be a "menu" such that when any of its contents are clicked,
- // they will open their targets in the outer container. To get back to the "menu", you click on the main container.
- @computed get inPlaceContainerButton() {
+ // 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(
- 'In Place',
- 'isInPlaceContainer',
- on => `${on ? 'Make' : 'Remove'} in place container flag`,
+ 'Lightbox',
+ 'isLightbox',
+ on => `${on ? 'Set' : 'Remove'} lightbox flag`,
on => 'window-restore',
onClick => {
SelectionManager.Views().forEach(dv => {
const containerDoc = dv.rootDoc;
- containerDoc.followAllLinks =
- containerDoc.noShadow =
- containerDoc.noHighlighting =
- containerDoc._isLinkButton =
- containerDoc._fitContentsToBox =
- containerDoc._forceActive =
- containerDoc._isInPlaceContainer =
- !containerDoc._isInPlaceContainer;
- containerDoc.followLinkLocation = containerDoc._isInPlaceContainer ? OpenWhere.inPlace : undefined;
- containerDoc._xPadding = containerDoc._yPadding = containerDoc._isInPlaceContainer ? 10 : undefined;
- const menuDoc = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]).lastElement();
- if (menuDoc) {
- menuDoc.hideDecorations = menuDoc._forceActive = menuDoc._fitContentsToBox = menuDoc._isLinkButton = menuDoc._noShadow = menuDoc.noHighlighting = containerDoc._isInPlaceContainer;
- if (!dv.allLinks.find(link => link.anchor1 === menuDoc || link.anchor2 === menuDoc)) {
- DocUtils.MakeLink({ doc: dv.rootDoc }, { doc: menuDoc }, 'back link to container');
- }
- DocListCast(menuDoc[Doc.LayoutFieldKey(menuDoc)]).forEach(menuItem => {
- menuItem.followLinkAudio = menuItem.followAllLinks = menuItem._isLinkButton = true;
- menuItem._followLinkLocation = OpenWhere.inPlace;
- });
- }
+ //containerDoc.followAllLinks =
+ // containerDoc.noShadow =
+ // containerDoc.disableDocBrushing =
+ // containerDoc._forceActive =
+ //containerDoc._freeform_fitContentsToBox =
+ containerDoc._isLightbox = !containerDoc._isLightbox;
+ //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined;
+ const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]);
+ //dv.rootDoc.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' });
+ containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.layout_linkDisplay = false)));
});
}
);
}
- @computed get fitWidthButton() {
+ @computed get layout_fitWidthButton() {
return this.propertyToggleBtn(
'Fit\xA0Width',
- '_fitWidth',
+ '_layout_fitWidth',
on => `${on ? "Don't" : 'Do'} fit content to width of container`,
on => 'arrows-alt-h'
);
@@ -157,10 +156,10 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@computed get captionButton() {
return this.propertyToggleBtn(
'Caption',
- '_showCaption',
+ '_layout_showCaption',
on => `${on ? 'Hide' : 'Show'} caption footer`,
on => 'closed-captioning',
- (dv, doc) => ((dv?.rootDoc || doc)._showCaption = (dv?.rootDoc || doc)._showCaption === undefined ? 'caption' : undefined)
+ (dv, doc) => ((dv?.rootDoc || doc)._layout_showCaption = (dv?.rootDoc || doc)._layout_showCaption === undefined ? 'caption' : undefined)
);
}
@computed get chromeButton() {
@@ -175,16 +174,20 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@computed get titleButton() {
return this.propertyToggleBtn(
'Title',
- '_showTitle',
+ '_layout_showTitle',
on => 'Switch between title styles',
on => 'text-width',
- (dv, doc) => ((dv?.rootDoc || doc)._showTitle = !(dv?.rootDoc || doc)._showTitle ? 'title' : (dv?.rootDoc || doc)._showTitle === 'title' ? 'title:hover' : undefined)
+ (dv, doc) => {
+ const tdoc = dv?.rootDoc || doc;
+ const newtitle = !tdoc._layout_showTitle ? 'title' : tdoc._layout_showTitle === 'title' ? 'title:hover' : '';
+ tdoc._layout_showTitle = newtitle;
+ }
);
}
- @computed get autoHeightButton() {
+ @computed get layout_autoHeightButton() {
return this.propertyToggleBtn(
'Auto\xA0Size',
- '_autoHeight',
+ '_layout_autoHeight',
on => `Automatical vertical sizing to show all content`,
on => 'arrows-alt-v'
);
@@ -192,7 +195,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@computed get gridButton() {
return this.propertyToggleBtn(
'Grid',
- '_backgroundGridShow',
+ '_freeform_backgroundGrid',
on => `Display background grid in collection`,
on => 'border-all'
);
@@ -214,7 +217,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
'FreezeThumb',
'_thumb-frozen',
on => `${on ? 'Freeze' : 'Unfreeze'} thumbnail`,
- on => 'arrows-alt-h',
+ on => 'snowflake',
(dv, doc) => {
if (doc['thumb-frozen']) doc['thumb-frozen'] = undefined;
else {
@@ -222,7 +225,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
setTimeout(() =>
pasteImageBitmap((data_url: any, error: any) => {
error && console.log(error);
- data_url && VideoBox.convertDataUri(data_url, doc[Id] + '-thumb-frozen', true).then(returnedfilename => (doc['thumb-frozen'] = new ImageField(returnedfilename)));
+ data_url && Utils.convertDataUri(data_url, doc[Id] + '-thumb-frozen', true).then(returnedfilename => (doc['thumb-frozen'] = new ImageField(returnedfilename)));
})
);
}
@@ -232,9 +235,9 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@computed get snapButton() {
return this.propertyToggleBtn(
'Snap\xA0Lines',
- 'showSnapLines',
+ 'freeform_snapLines',
on => `Display snapping lines when objects are dragged`,
- on => 'border-all',
+ on => 'th',
undefined,
true
);
@@ -277,21 +280,21 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@undoBatch
handlePerspectiveChange = (e: any) => {
- this.selectedDoc && (this.selectedDoc._viewType = e.target.value);
+ this.selectedDoc && (this.selectedDoc._type_collection = e.target.value);
SelectionManager.Views()
.filter(dv => dv.docView)
.map(dv => dv.docView!)
- .forEach(docView => (docView.layoutDoc._viewType = e.target.value));
+ .forEach(docView => (docView.layoutDoc._type_collection = e.target.value));
};
@undoBatch
@action
handleOptionChange = (onClick: string) => {
- this.selectedDoc && (this.selectedDoc.onClickBehavior = onClick);
SelectionManager.Views()
.filter(dv => dv.docView)
.map(dv => dv.docView!)
.forEach(docView => {
+ const linkButton = IsFollowLinkScript(docView.props.Document.onClick);
docView.noOnClick();
switch (onClick) {
case 'enterPortal':
@@ -301,10 +304,12 @@ export class PropertiesButtons extends React.Component<{}, {}> {
docView.setToggleDetail();
break;
case 'linkInPlace':
- docView.toggleFollowLink('inPlace', false, false);
+ docView.toggleFollowLink(false, false);
+ docView.props.Document.followLinkLocation = linkButton ? OpenWhere.lightbox : undefined;
break;
case 'linkOnRight':
- docView.toggleFollowLink('add:right', false, false);
+ docView.toggleFollowLink(false, false);
+ docView.props.Document.followLinkLocation = linkButton ? OpenWhere.addRight : undefined;
break;
}
});
@@ -322,24 +327,26 @@ export class PropertiesButtons extends React.Component<{}, {}> {
['nothing', 'Select Document'],
['enterPortal', 'Enter Portal'],
['toggleDetail', 'Toggle Detail'],
- ['linkInPlace', 'Open in Place'],
+ ['linkInPlace', 'Open Link in Lightbox'],
['linkOnRight', 'Open Link on Right'],
];
- const currentSelection = this.selectedDoc.onClickBehavior;
- // Get items to place into the list
-
const list = buttonList.map(value => {
- const click = () => {
- this.handleOptionChange(value[0]);
- };
+ 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);
+
+ let active = false;
+ // prettier-ignore
+ switch (value[0]) {
+ case 'linkInPlace': active = linkButton && followLoc === OpenWhere.lightbox && !linkedToLightboxView(); break;
+ case 'linkOnRight': active = linkButton && followLoc === OpenWhere.addRight; break;
+ 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;
+ }
return (
- <div
- className="list-item"
- key={`${value}`}
- style={{
- backgroundColor: value[0] === currentSelection ? Colors.LIGHT_BLUE : undefined,
- }}
- onClick={click}>
+ <div className="list-item" key={`${value}`} style={{ backgroundColor: active ? Colors.LIGHT_BLUE : undefined }} onClick={click}>
{value[1]}
</div>
);
@@ -365,7 +372,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
const makeLabel = (value: string, label: string) => (
<div className="radio" key={label}>
<label>
- <input type="radio" value={value} checked={(this.selectedDoc?._viewType ?? 'invalid') === value} onChange={this.handlePerspectiveChange} />
+ <input type="radio" value={value} checked={(this.selectedDoc?._type_collection ?? 'invalid') === value} onChange={this.handlePerspectiveChange} />
{label}
</label>
</div>
@@ -383,12 +390,13 @@ export class PropertiesButtons extends React.Component<{}, {}> {
const layoutField = this.selectedDoc?.[Doc.LayoutFieldKey(this.selectedDoc)];
const isText = layoutField instanceof RichTextField;
const isInk = layoutField instanceof InkField;
+ const isImage = layoutField instanceof ImageField;
const isMap = this.selectedDoc?.type === DocumentType.MAP;
const isCollection = this.selectedDoc?.type === DocumentType.COL;
//TODO: will likely need to create separate note-taking view type here
- const isStacking = this.selectedDoc?._viewType === CollectionViewType.Stacking || this.selectedDoc?._viewType === CollectionViewType.NoteTaking;
- const isFreeForm = this.selectedDoc?._viewType === CollectionViewType.Freeform;
- const isTree = this.selectedDoc?._viewType === CollectionViewType.Tree;
+ const isStacking = this.selectedDoc?._type_collection === CollectionViewType.Stacking || this.selectedDoc?._type_collection === CollectionViewType.NoteTaking;
+ 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}>
@@ -403,13 +411,14 @@ export class PropertiesButtons extends React.Component<{}, {}> {
{toggle(this.captionButton)}
{toggle(this.lockButton)}
{toggle(this.onClickButton)}
- {toggle(this.fitWidthButton)}
+ {toggle(this.layout_fitWidthButton)}
{toggle(this.freezeThumb)}
- {toggle(this.forceActiveButton, { display: !isFreeForm && !isMap ? 'none' : '' })}
+ {toggle(this.forceActiveButton)}
{toggle(this.fitContentButton, { display: !isFreeForm && !isMap ? 'none' : '' })}
- {toggle(this.inPlaceContainerButton, { display: !isFreeForm && !isMap ? 'none' : '' })}
- {toggle(this.autoHeightButton, { display: !isText && !isStacking && !isTree ? 'none' : '' })}
+ {toggle(this.isLightboxButton, { display: !isFreeForm && !isMap ? 'none' : '' })}
+ {toggle(this.layout_autoHeightButton, { display: !isText && !isStacking && !isTree ? 'none' : '' })}
{toggle(this.maskButton, { display: !isInk ? 'none' : '' })}
+ {toggle(this.hideImageButton, { display: !isImage ? 'none' : '' })}
{toggle(this.chromeButton, { display: !isCollection || isNovice ? 'none' : '' })}
{toggle(this.gridButton, { display: !isCollection ? 'none' : '' })}
{toggle(this.groupButton, { display: isTabView || !isCollection ? 'none' : '' })}