aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/DocumentView.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/DocumentView.tsx')
-rw-r--r--src/client/views/nodes/DocumentView.tsx131
1 files changed, 99 insertions, 32 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c2355e4f7..4a43ffe3e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -17,7 +17,7 @@ import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils';
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
import { DocServer } from '../../DocServer';
-import { Docs, DocUtils } from '../../documents/Documents';
+import { DocOptions, Docs, DocUtils, FInfo } from '../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
import { Networking } from '../../Network';
import { DictationManager } from '../../util/DictationManager';
@@ -54,6 +54,8 @@ import { PinProps, PresBox } from './trails/PresBox';
import React = require('react');
import { KeyValueBox } from './KeyValueBox';
import { LinkBox } from './LinkBox';
+import { FilterPanel } from '../FilterPanel';
+import { Dropdown, DropdownType, Type } from 'browndash-components';
const { Howl } = require('howler');
interface Window {
@@ -143,7 +145,7 @@ export interface DocComponentView {
annotationKey?: string;
getTitle?: () => string;
getCenter?: (xf: Transform) => { X: number; Y: number };
- screenBounds?: () => { left: number; top: number; right: number; bottom: number; center?:{X:number, Y:number} };
+ screenBounds?: () => { left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } };
ptToScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number };
ptFromScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number };
snapPt?: (pt: { X: number; Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number; Y: number }; distance: number };
@@ -622,7 +624,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (this.props.Document === Doc.ActiveDashboard) {
e.stopPropagation();
e.preventDefault();
- alert((e.target as any)?.closest?.('*.lm_content') ? "You can't perform this move most likely because you don't have permission to modify the destination." : 'Linking to document tabs not yet supported. Drop link on document content.');
+ alert(
+ (e.target as any)?.closest?.('*.lm_content')
+ ? "You can't perform this move most likely because you didn't drag the document's title bar to enable embedding in a different document."
+ : 'Linking to document tabs not yet supported. Drop link on document content.'
+ );
return true;
}
const linkdrag = de.complete.annoDragData ?? de.complete.linkDragData;
@@ -1068,6 +1074,41 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
};
captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => this.props?.styleProvider?.(doc, props, property + ':caption');
+ @observable _changingTitleField = false;
+ @observable _dropDownInnerWidth = 0;
+ fieldsDropdown = (inputOptions: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => {
+ const filteredOptions = new Set(inputOptions);
+ const scaling = this.titleHeight / 30; /* height of Dropdown */
+ Object.entries(DocOptions)
+ .filter(opts => opts[1].filterable)
+ .forEach((pair: [string, FInfo]) => filteredOptions.add(pair[0]));
+ filteredOptions.add(StrCast(this.layoutDoc.layout_showTitle));
+ const options = Array.from(filteredOptions)
+ .filter(f => f)
+ .map(facet => ({ val: facet, text: facet }));
+ return (
+ <div style={{ width: dropdownWidth }}>
+ <div
+ ref={action((r: any) => r && (this._dropDownInnerWidth = Number(getComputedStyle(r).width.replace('px', ''))))}
+ onPointerDown={action(e => (this._changingTitleField = true))}
+ style={{ width: 'max-content', transformOrigin: 'left', transform: `scale(${scaling})` }}>
+ <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={options}
+ width={100}
+ fillWidth
+ />
+ </div>
+ </div>
+ );
+ };
@computed get innards() {
TraceMobx();
const showTitle = this.layout_showTitle?.split(':')[0];
@@ -1095,8 +1136,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
</div>
);
const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.rootDoc;
- const background = StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.userBackgroundColor));
+ const background = StrCast(
+ this.layoutDoc.layout_headingColor,
+ StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(this.layoutDoc.layout_headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.userBackgroundColor)))
+ );
+ const dropdownWidth = this._titleRef.current?._editing || this._changingTitleField ? Math.max(10, (this._dropDownInnerWidth * this.titleHeight) / 30) : 0;
const sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', '');
+ // displays a 'title' at the top of a document. The title contents default to the 'title' field, but can be changed to one or more fields by
+ // setting layout_showTitle using the format: field1[;field2[...][:hover]]
+ // from the UI, this is done by clicking the title field and prefixin the format with '#'. eg., #field1[;field2;...][:hover]
const titleView = !showTitle ? null : (
<div
className={`documentView-titleWrapper${showTitleHover ? '-hover' : ''}`}
@@ -1104,39 +1152,58 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
style={{
position: this.headerMargin ? 'relative' : 'absolute',
height: this.titleHeight,
- width: !this.headerMargin ? `calc(${sidebarWidthPercent || 100}% - 18px)` : (sidebarWidthPercent || 100) + '%', // leave room for annotation button
+ width: 100 - sidebarWidthPercent + '%',
color: background === 'transparent' ? SettingsManager.userColor : lightOrDark(background),
background,
pointerEvents: (!this.disableClickScriptFunc && this.onClickHandler) || this.Document.ignoreClick ? 'none' : this.isContentActive() || this.props.isDocumentActive?.() ? 'all' : undefined,
}}>
- <EditableView
- ref={this._titleRef}
- contents={showTitle
- .split(';')
- .map(field => field.trim())
- .map(field => targetDoc[field]?.toString())
- .join('\\')}
- display={'block'}
- fontSize={10}
- GetValue={() => {
- return showTitle.split(';').length === 1 ? showTitle + '=' + Field.toString(targetDoc[showTitle.split(';')[0]] as any as Field) : '#' + showTitle;
- }}
- SetValue={undoBatch((input: string) => {
- if (input?.startsWith('#')) {
- if (this.rootDoc.layout_showTitle) {
- this.rootDoc._layout_showTitle = input?.substring(1) ? input.substring(1) : undefined;
- } else if (!this.props.layout_showTitle) {
- Doc.UserDoc().layout_showTitle = input?.substring(1) ? input.substring(1) : 'author_date';
+ {!dropdownWidth
+ ? null
+ : this.fieldsDropdown(
+ [],
+ dropdownWidth,
+ StrCast(this.layoutDoc.layout_showTitle).split(':')[0],
+ action((field: string | number) => {
+ if (this.rootDoc.layout_showTitle) {
+ this.rootDoc._layout_showTitle = field;
+ } else if (!this.props.layout_showTitle) {
+ Doc.UserDoc().layout_showTitle = field;
+ }
+ this._changingTitleField = false;
+ }),
+ action(() => (this._changingTitleField = false))
+ )}
+ <div
+ style={{
+ width: `calc(100% - ${dropdownWidth}px)`,
+ minWidth: '100px',
+ color: this._titleRef.current?._editing || this._changingTitleField ? 'black' : undefined,
+ background: this._titleRef.current?._editing || this._changingTitleField ? 'yellow' : undefined,
+ }}>
+ <EditableView
+ ref={this._titleRef}
+ contents={showTitle
+ .split(';')
+ .map(field => targetDoc[field.trim()]?.toString())
+ .join(' \\ ')}
+ display="block"
+ oneLine={true}
+ fontSize={(this.titleHeight / 15) * 10}
+ GetValue={() => (showTitle.split(';').length !== 1 ? '#' + showTitle : Field.toKeyValueString(this.rootDoc, showTitle.split(';')[0]))}
+ SetValue={undoBatch((input: string) => {
+ if (input?.startsWith('#')) {
+ if (this.rootDoc.layout_showTitle) {
+ this.rootDoc._layout_showTitle = input?.substring(1);
+ } else if (!this.props.layout_showTitle) {
+ Doc.UserDoc().layout_showTitle = input?.substring(1) ?? 'author_date';
+ }
+ } else if (showTitle && !showTitle.includes('Date') && showTitle !== 'author') {
+ KeyValueBox.SetField(targetDoc, showTitle, input);
}
- } else {
- var value = input.replace(new RegExp(showTitle + '='), '') as string | number;
- if (showTitle !== 'title' && Number(value).toString() === value) value = Number(value);
- if (showTitle.includes('Date') || showTitle === 'author') return true;
- Doc.SetInPlace(targetDoc, showTitle, value, true);
- }
- return true;
- })}
- />
+ return true;
+ })}
+ />
+ </div>
</div>
);
return this.props.hideTitle || (!showTitle && !this.layout_showCaption) ? (