aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/DocumentView.tsx
diff options
context:
space:
mode:
authoralyssaf16 <alyssa_feinberg@brown.edu>2024-03-12 16:14:58 -0400
committeralyssaf16 <alyssa_feinberg@brown.edu>2024-03-12 16:14:58 -0400
commit2d9763a63a661420ae0ffa8b4436b29ed717b90b (patch)
tree4c3623c87a6e4e184d06579569fb239cfbad3dc1 /src/client/views/nodes/DocumentView.tsx
parentecfb0d119e08a101cd8d18e8a90d31995f71eeec (diff)
parent641220e9cd9626af182118f84f8f775d7638cc67 (diff)
Merge branch 'master' into alyssa-starter
Diffstat (limited to 'src/client/views/nodes/DocumentView.tsx')
-rw-r--r--src/client/views/nodes/DocumentView.tsx113
1 files changed, 57 insertions, 56 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 7e86125e5..7e7a9d7f9 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,11 +1,10 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { Dropdown, DropdownType, Type } from 'browndash-components';
import { Howl } from 'howler';
import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal';
-import { Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils';
+import { DivWidth, Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils';
import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc';
import { AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
@@ -48,6 +47,7 @@ import { KeyValueBox } from './KeyValueBox';
import { LinkAnchorBox } from './LinkAnchorBox';
import { FormattedTextBox } from './formattedText/FormattedTextBox';
import { PresEffect, PresEffectDirection } from './trails';
+import { FieldsDropdown } from '../FieldsDropdown';
interface Window {
MediaRecorder: MediaRecorder;
}
@@ -413,7 +413,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
if (!Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, Date.now())) {
this.cleanupPointerEvents();
this._longPressSelector && clearTimeout(this._longPressSelector);
- this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && 'embed') || ((this.Document.dragAction || this._props.dragAction || undefined) as dropActionType));
+ this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && dropActionType.embed) || ((this.Document.dragAction || this._props.dragAction || undefined) as dropActionType));
}
};
@@ -457,11 +457,11 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
deleteClicked = undoable(() => this._props.removeDocument?.(this.Document), 'delete doc');
setToggleDetail = undoable(
- (defaultLayout: string, scriptFieldKey: 'onClick') =>
+ (scriptFieldKey: 'onClick') =>
(this.Document[scriptFieldKey] = ScriptField.MakeScript(
`toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey)
.replace('layout_', '')
- .replace(/^layout$/, 'detail')}", "${defaultLayout}")`,
+ .replace(/^layout$/, 'detail')}")`,
{ documentView: 'any' }
)),
'set toggle detail'
@@ -518,7 +518,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
};
onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => {
- if (e && this.layoutDoc._layout_hideContextMenu && Doc.noviceMode) {
+ if (e && this.layoutDoc.layout_hideContextMenu && Doc.noviceMode) {
e.preventDefault();
e.stopPropagation();
//!this._props.isSelected(true) && SelectionManager.SelectView(this.DocumentView(), false);
@@ -705,7 +705,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
panelHeight = () => this._props.PanelHeight() - this.headerMargin;
screenToLocalContent = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin);
onClickFunc = this.disableClickScriptFunc ? undefined : () => this.onClickHandler;
- setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = height);
+ setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), height));
setContentView = action((view: ViewBoxInterface) => (this._componentView = view));
isContentActive = (): boolean | undefined => this._isContentActive;
childFilters = () => [...this._props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)];
@@ -787,28 +787,25 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
}
captionStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption');
- fieldsDropdown = (reqdFields: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => {
- const filteredFields = Object.entries(DocOptions).reduce((set, [field, opts]) => (opts.filterable ? set.add(field) : set), new Set(reqdFields));
+ fieldsDropdown = (placeholder: string) => {
return (
- <div style={{ width: dropdownWidth }}>
- <div
- ref={action((r: any) => r && (this._titleDropDownInnerWidth = Number(getComputedStyle(r).width.replace('px', ''))))}
- onPointerDown={action(e => (this._changingTitleField = true))}
- style={{ width: 'max-content', transformOrigin: 'left', transform: `scale(${this.titleHeight / 30 /* height of Dropdown */})` }}>
- <Dropdown
- activeChanged={action(isOpen => !isOpen && (this._changingTitleField = false))}
- selectedVal={placeholder}
- setSelectedVal={onChange}
- color={SettingsManager.userColor}
- background={SettingsManager.userVariantColor}
- type={Type.TERT}
- closeOnSelect={true}
- dropdownType={DropdownType.SELECT}
- items={Array.from(filteredFields).map(facet => ({ val: facet, text: facet }))}
- width={100}
- fillWidth
- />
- </div>
+ <div
+ ref={action((r: any) => r && (this._titleDropDownInnerWidth = DivWidth(r)))}
+ onPointerDown={action(e => (this._changingTitleField = true))}
+ style={{ width: 'max-content', background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor, transformOrigin: 'left', transform: `scale(${this.titleHeight / 30 /* height of Dropdown */})` }}>
+ <FieldsDropdown
+ Document={this.Document}
+ placeholder={placeholder}
+ selectFunc={action((field: string | number) => {
+ if (this.layoutDoc.layout_showTitle) {
+ this.layoutDoc._layout_showTitle = field;
+ } else if (!this._props.layout_showTitle) {
+ Doc.UserDoc().layout_showTitle = field;
+ }
+ this._changingTitleField = false;
+ })}
+ menuClose={action(() => (this._changingTitleField = false))}
+ />
</div>
);
};
@@ -842,22 +839,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
background,
pointerEvents: (!this.disableClickScriptFunc && this.onClickHandler) || this.Document.ignoreClick ? 'none' : this.isContentActive() || this._props.isDocumentActive?.() ? 'all' : undefined,
}}>
- {!dropdownWidth
- ? null
- : this.fieldsDropdown(
- [StrCast(this.layoutDoc.layout_showTitle)],
- dropdownWidth,
- StrCast(this.layoutDoc.layout_showTitle).split(':')[0],
- action((field: string | number) => {
- if (this.layoutDoc.layout_showTitle) {
- this.layoutDoc._layout_showTitle = field;
- } else if (!this._props.layout_showTitle) {
- Doc.UserDoc().layout_showTitle = field;
- }
- this._changingTitleField = false;
- }),
- action(() => (this._changingTitleField = false))
- )}
+ {!dropdownWidth ? null : <div style={{ width: dropdownWidth }}>{this.fieldsDropdown(showTitle)}</div>}
<div
style={{
width: `calc(100% - ${dropdownWidth}px)`,
@@ -867,10 +849,12 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
}}>
<EditableView
ref={this._titleRef}
- contents={showTitle
- .split(';')
- .map(field => targetDoc[field.trim()]?.toString())
- .join(' \\ ')}
+ contents={
+ showTitle
+ .split(';')
+ .map(field => Field.toString(targetDoc[field.trim()] as Field))
+ .join(' \\ ') || '-unset-'
+ }
display="block"
oneLine={true}
fontSize={(this.titleHeight / 15) * 10}
@@ -1220,7 +1204,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
};
public noOnClick = () => this._docViewInternal?.noOnClick();
public toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => this._docViewInternal?.toggleFollowLink(zoom, setTargetToggle);
- public setToggleDetail = (defaultLayout = '', scriptFieldKey = 'onClick') => this._docViewInternal?.setToggleDetail(defaultLayout, scriptFieldKey);
+ public setToggleDetail = (scriptFieldKey = 'onClick') => this._docViewInternal?.setToggleDetail(scriptFieldKey);
public onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY);
public cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents();
public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource);
@@ -1298,7 +1282,22 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
custom && DocUtils.makeCustomViewClicked(this.Document, Docs.Create.StackingDocument, layout, undefined);
}, 'set custom view');
+ /**
+ * This switches between the current view of a Doc and a specified alternate layout view.
+ * The current view of the Doc is stored in the layout_default field so that it can be restored.
+ * If the current view of the Doc is already the specified alternate layout view, this will switch
+ * back to the original layout (stored in layout_default)
+ * @param detailLayoutKeySuffix the name of the alternate layout field key (NOTE: 'layout_' will be prepended to this string to get the actual field nam)
+ */
+ public toggleDetail = (detailLayoutKeySuffix: string) => {
+ const curLayout = StrCast(this.Document.layout_fieldKey).replace('layout_', '').replace('layout', '');
+ if (!this.Document.layout_default && curLayout !== detailLayoutKeySuffix) this.Document.layout_default = curLayout;
+ const defaultLayout = StrCast(this.Document.layout_default);
+ if (this.Document.layout_fieldKey === 'layout_' + detailLayoutKeySuffix) this.switchViews(defaultLayout ? true : false, defaultLayout, undefined, true);
+ else this.switchViews(true, detailLayoutKeySuffix, undefined, true);
+ };
public switchViews = (custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => {
+ const batch = UndoManager.StartBatch('switchView:' + view);
runInAction(() => this._docViewInternal && (this._docViewInternal._animateScalingTo = 0.1)); // shrink doc
setTimeout(
action(() => {
@@ -1311,6 +1310,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
setTimeout(
action(() => {
this._docViewInternal && (this._docViewInternal._animateScalingTo = 0);
+ batch.end();
finished?.();
}),
Math.max(0, (this._docViewInternal?.animateScaleTime() ?? 0) - 10)
@@ -1470,9 +1470,8 @@ ScriptingGlobals.add(function deiconifyViewToLightbox(documentView: DocumentView
LightboxView.Instance.AddDocTab(documentView.Document, OpenWhere.lightbox, 'layout'); //, 0);
});
-ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuffix: string, defaultLayout = '') {
- if (dv.Document.layout_fieldKey === 'layout_' + detailLayoutKeySuffix) dv.switchViews(defaultLayout ? true : false, defaultLayout, undefined, true);
- else dv.switchViews(true, detailLayoutKeySuffix, undefined, true);
+ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuffix: string) {
+ dv.toggleDetail(detailLayoutKeySuffix);
});
ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc, linkSource: Doc) {
@@ -1503,8 +1502,8 @@ ScriptingGlobals.add(function updateTagsCollection(collection: Doc) {
let created = false;
const matchedDocs = matchedTags
.filter(tagDoc => !Doc.AreProtosEqual(collection, tagDoc))
- .map(tagDoc => {
- let embedding = collectionDocs.find(doc => Doc.AreProtosEqual(tagDoc, doc));
+ .reduce((aset, tagDoc) => {
+ let embedding = Array.from(aset).find(doc => Doc.AreProtosEqual(tagDoc, doc)) ?? collectionDocs.find(doc => Doc.AreProtosEqual(tagDoc, doc));
if (!embedding) {
embedding = Doc.MakeEmbedding(tagDoc);
embedding.x = wid;
@@ -1513,8 +1512,10 @@ ScriptingGlobals.add(function updateTagsCollection(collection: Doc) {
wid += NumCast(tagDoc._width);
created = true;
}
- return embedding;
- });
+ Doc.SetContainer(embedding, collection);
+ aset.add(embedding);
+ return aset;
+ }, new Set<Doc>());
created && (collection[DocData].data = new List<Doc>(matchedDocs));
return true;