aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/DocUtils.ts8
-rw-r--r--src/client/documents/Documents.ts23
-rw-r--r--src/client/util/CurrentUserUtils.ts4
-rw-r--r--src/client/views/EditableView.tsx22
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx3
-rw-r--r--src/client/views/collections/collectionSchema/SchemaCellField.tsx6
-rw-r--r--src/client/views/collections/collectionSchema/SchemaTableCell.tsx3
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx17
-rw-r--r--src/client/views/nodes/KeyValuePair.tsx27
-rw-r--r--src/fields/Doc.ts8
10 files changed, 60 insertions, 61 deletions
diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts
index 0bb6c0ce9..69bf4815e 100644
--- a/src/client/documents/DocUtils.ts
+++ b/src/client/documents/DocUtils.ts
@@ -283,10 +283,10 @@ export namespace DocUtils {
}
return val1 === val2;
};
- Object.entries(reqdOpts).forEach(pair => {
- const targetDoc = pair[0].startsWith('_') ? doc : Doc.GetProto(doc as Doc);
- if (!Object.getOwnPropertyNames(targetDoc).includes(pair[0].replace(/^_/, '')) || !compareValues(pair[1], targetDoc[pair[0]])) {
- targetDoc[pair[0]] = pair[1];
+ Object.entries(reqdOpts).forEach(([key, val]) => {
+ const targetDoc = key.startsWith('_') ? doc : Doc.GetProto(doc as Doc);
+ if (!Object.getOwnPropertyNames(targetDoc).includes(key.replace(/^_/, '')) || !compareValues(val, targetDoc[key])) {
+ targetDoc[key] = val as FieldType;
}
});
items?.forEach(item => !DocListCast(doc.data).includes(item) && Doc.AddDocToList(Doc.GetProto(doc), 'data', item));
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 668725d2b..972b1aa5c 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -5,6 +5,7 @@ import { ClientUtils, OmitKeys } from '../../ClientUtils';
import { DateField } from '../../fields/DateField';
import { CreateLinkToActiveAudio, Doc, FieldType, Opt, updateCachedAcls } from '../../fields/Doc';
import { Initializing } from '../../fields/DocSymbols';
+import { Id } from '../../fields/FieldSymbols';
import { HtmlField } from '../../fields/HtmlField';
import { InkField } from '../../fields/InkField';
import { List } from '../../fields/List';
@@ -18,7 +19,6 @@ import { PointData } from '../../pen-gestures/GestureTypes';
import { DocServer } from '../DocServer';
import { dropActionType } from '../util/DropActionTypes';
import { CollectionViewType, DocumentType } from './DocumentTypes';
-import { Id } from '../../fields/FieldSymbols';
class EmptyBox {
public static LayoutString() {
@@ -43,7 +43,6 @@ export class FInfo {
readOnly: boolean = false;
fieldType?: FInfoFieldType;
values?: FieldType[];
- onLayout?: boolean;
filterable?: boolean = true; // can be used as a Filter in FilterPanel
// format?: string; // format to display values (e.g, decimal places, $, etc)
// parse?: ScriptField; // parse a value from a string
@@ -156,12 +155,16 @@ type DROPt = DAInfo | dropActionType;
type DATEt = DateInfo | number;
type DTYPEt = DTypeInfo | string;
export class DocumentOptions {
+ [key: string]: FInfo | FieldType | undefined;
// coordinate and dimensions depending on view
x?: NUMt = new NumInfo('horizontal coordinate in freeform view', false);
y?: NUMt = new NumInfo('vertical coordinate in freeform view', false);
z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', false, false, [1, 0]);
+ zIndex?: NUMt = new NumInfo('stacking index of documents in freeform view (higher numbers are towards the top');
overlayX?: NUMt = new NumInfo('horizontal coordinate in overlay view', false);
overlayY?: NUMt = new NumInfo('vertical coordinate in overlay view', false);
+ embedContainer?: DOCt = new DocInfo('document that displays (contains) this document', false);
+
text?: RTFt = new RtfInfo('plain or rich text', true);
text_html?: STRt = new StrInfo('plain text or html', true);
_dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height", false);
@@ -215,7 +218,6 @@ export class DocumentOptions {
author?: string; // STRt = new StrInfo('creator of document'); // bcz: don't change this. Otherwise, the userDoc's field Infos will have a FieldInfo assigned to its author field which will render it unreadable
author_date?: DATEt = new DateInfo('date the document was created', true);
annotationOn?: DOCt = new DocInfo('document annotated by this document', false);
- _embedContainer?: DOCt = new DocInfo('document that displays (contains) this document', false);
rootDocument?: DOCt = new DocInfo('document that supplies the information needed for a rendering template (eg, pres slide for PresElement)');
color?: STRt = new StrInfo('foreground color data doc', false);
hidden?: BOOLt = new BoolInfo('whether the document is not rendered by its collection', false);
@@ -686,10 +688,11 @@ export namespace Docs {
layout: layout.view?.LayoutString(layout.dataField),
};
Object.entries(options)
- .filter(pair => typeof pair[1] === 'string' && pair[1].startsWith('@'))
- .forEach(pair => {
- if (!existing || ScriptCast(existing[pair[0]])?.script.originalScript !== pair[1].substring(1)) {
- (options as { [key: string]: unknown })[pair[0]] = ComputedField.MakeFunction(pair[1].substring(1));
+ .filter(([, val]) => (val as string)?.startsWith?.('@'))
+ .map(([key, val]) => [key, val as string])
+ .forEach(([key, val]) => {
+ if (!existing || ScriptCast(existing[key])?.script.originalScript !== val.substring(1)) {
+ options[key] = ComputedField.MakeFunction(val.substring(1));
}
});
return Doc.assign(existing ?? new Doc(prototypeId, true), OmitKeys(options, Object.keys(existing ?? {})).omit as { [key: string]: FieldType }, undefined, true);
@@ -722,7 +725,7 @@ export namespace Docs {
*/
function InstanceFromProto(proto: Doc, data: FieldType | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = 'data', protoId?: string, placeholderDocIn?: Doc, noView?: boolean) {
const placeholderDoc = placeholderDocIn;
- const viewKeys = ['x', 'y', 'isSystem']; // keys that should be addded to the view document even though they don't begin with an "_"
+ const viewKeys = ['x', 'y', 'isSystem', 'overlayX', 'overlayY', 'zIndex', 'embedContainer']; // keys that should be addded to the view document even though they don't begin with an "_"
const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, '^_') as { omit: { [key: string]: FieldType | undefined }; extract: { [key: string]: FieldType | undefined } };
// dataProps.acl_Override = SharingPermissions.Unset;
@@ -947,9 +950,9 @@ export namespace Docs {
return InstanceFromProto(
Prototypes.get(DocumentType.JOURNAL),
- "",
+ '',
{
- title: "",
+ title: '',
...options,
},
undefined,
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 537c703b4..44ed136f6 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -601,7 +601,7 @@ pie title Minerals in my tap water
const myFilesystem = DocCast(doc[field]);
const newFolderOpts: DocumentOptions = {
- _forceActive: true, _dragOnlyWithinContainer: true, _embedContainer: Doc.MyFilesystem, _width: 30, _height: 30, undoIgnoreFields:new List<string>(['treeView_SortCriterion']),
+ _forceActive: true, _dragOnlyWithinContainer: true, embedContainer: Doc.MyFilesystem, _width: 30, _height: 30, undoIgnoreFields:new List<string>(['treeView_SortCriterion']),
title: "New folder", color: Colors.BLACK, btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", isSystem: true
};
const newFolderScript = { onClick: CollectionTreeView.AddTreeFunc};
@@ -867,7 +867,7 @@ pie title Minerals in my tap water
_height: 30, _nativeHeight: 30, linearBtnWidth: params.linearBtnWidth,
toolType: params.toolType, expertMode: params.expertMode,
_dragOnlyWithinContainer: true, _lockedPosition: true,
- _embedContainer: btnContainer
+ embedContainer: btnContainer
};
const reqdFuncs:{[key:string]:string} = {
...params.funcs,
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index e2490cec8..d9447b7ec 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -287,8 +287,8 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
staticDisplay = () => {
let toDisplay;
- const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n');
if (this._props.inputString) {
+ const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n');
toDisplay = (
<input
className="editableView-input"
@@ -315,15 +315,17 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
};
render() {
- const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n');
- if (this._editing && gval !== undefined) {
- return this._props.sizeToContent ? (
- <div style={{ display: 'grid', minWidth: 100 }}>
- <div style={{ display: 'inline-block', position: 'relative', height: 0, width: '100%', overflow: 'hidden' }}>{this.renderEditor()}</div>
- </div>
- ) : (
- this.renderEditor()
- );
+ if (this._editing) {
+ const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n');
+ if (gval !== undefined) {
+ return this._props.sizeToContent ? (
+ <div style={{ display: 'grid', minWidth: 100 }}>
+ <div style={{ display: 'inline-block', position: 'relative', height: 0, width: '100%', overflow: 'hidden' }}>{this.renderEditor()}</div>
+ </div>
+ ) : (
+ this.renderEditor()
+ );
+ }
}
setTimeout(() => this._props.autosuggestProps?.resetValue());
return (
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 58582a142..f27398427 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -202,7 +202,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
return Transform.Identity(); // we're still waiting on promises to resolve
}
let offset = 0;
- // eslint-disable-next-line no-restricted-syntax
for (const { layout: candidate } of this.childLayoutPairs) {
if (candidate === layout) {
return this.ScreenToLocalBoxXf().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0);
@@ -316,7 +315,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
const collector: JSX.Element[] = [];
this.childLayouts.forEach((layout, i) => {
collector.push(
- // eslint-disable-next-line react/no-array-index-key
<Tooltip title={'Doc: ' + StrCast(layout.title)} key={'wrapper' + i}>
<div className="document-wrapper" style={{ flexDirection: 'column', width: this.lookupPixels(layout) }}>
{this.getDisplayDoc(layout)}
@@ -328,7 +326,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
</Tooltip>,
<ResizeBar
width={resizerWidth}
- // eslint-disable-next-line react/no-array-index-key
key={'resizer' + i}
styleProvider={this._props.styleProvider}
isContentActive={this._props.isContentActive}
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index daffdf1f5..1dff76df2 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -96,10 +96,10 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
{ fireImmediately: true }
);
this._disposers.fieldUpdate = reaction(
- () => this._props.GetValue(),
- fieldVal => {
+ () => ({ fieldVal: this._props.GetValue(), editing: 0 }), // this._editing }),
+ ({ fieldVal, editing }) => {
this._unrenderedContent = fieldVal ?? '';
- this.finalizeEdit(false, false, false);
+ !this._editing && this.finalizeEdit(false, false, false);
}
);
}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index e6fe46638..aeceedc30 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -211,8 +211,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
this._props.finishEdit?.();
return true;
}
- const hasNoLayout = Doc.IsDataProto(fieldProps.Document) ? true : undefined; // the "delegate" is a a data document so never write to it's proto
- const ret = Doc.SetField(fieldProps.Document, this._props.fieldKey.replace(/^_/, ''), value, hasNoLayout);
+ const ret = Doc.SetField(fieldProps.Document, this._props.fieldKey, value);
this._submittedValue = value;
this._props.finishEdit?.();
return ret;
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 8911fac6d..b54004697 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -9,7 +9,7 @@ import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { DocCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
import { DocumentType } from '../../documents/DocumentTypes';
-import { Docs } from '../../documents/Documents';
+import { Docs, DocumentOptions } from '../../documents/Documents';
import { SetupDrag } from '../../util/DragManager';
import { CompiledScript } from '../../util/Scripting';
import { undoable } from '../../util/UndoManager';
@@ -121,10 +121,13 @@ export class KeyValueBox extends ViewBoxBaseComponent<FieldViewProps>() {
return false;
};
- public static SetField = undoable((doc: Doc, key: string, value: string, forceOnDelegate?: boolean, setResult?: (value: FieldResult) => void) => {
+ public static SetField = undoable((doc: Doc, key: string, value: string, forceOnDelegateIn?: boolean, setResult?: (value: FieldResult) => void) => {
const script = KeyValueBox.CompileKVPScript(value);
if (!script) return false;
- return KeyValueBox.ApplyKVPScript(doc, key, script, forceOnDelegate, setResult);
+ const ldoc = key.startsWith('_') ? Doc.Layout(doc) : doc;
+ const forceOnDelegate = forceOnDelegateIn || (ldoc !== doc && !value.startsWith('='));
+ const setKey = value.startsWith('=') ? key.replace(/^_/, '') : key; // an '=' value redirects a key targeting the render template to the root document
+ return KeyValueBox.ApplyKVPScript(doc, setKey, script, forceOnDelegate, setResult);
}, 'Set Doc Field');
onPointerDown = (e: React.PointerEvent): void => {
@@ -156,12 +159,16 @@ export class KeyValueBox extends ViewBoxBaseComponent<FieldViewProps>() {
});
});
- const layoutProtos = Doc.GetAllPrototypes(this.layoutDoc);
+ const docinfos = new DocumentOptions();
+
+ const layoutProtos = this.layoutDoc !== doc ? Doc.GetAllPrototypes(this.layoutDoc) : [];
layoutProtos.forEach(proto => {
Object.keys(proto)
+ .filter(key => !(key in ids) || docinfos['_' + key]) // if '_key' is in docinfos (as opposed to just 'key'), then the template Doc's value should be displayed instead of the root document's value
.map(key => '_' + key)
.forEach(key => {
- if (!(key.replace(/^_/, '') in ids) && doc[key] !== ComputedField.undefined) {
+ if (doc[key] !== ComputedField.undefined) {
+ if (key.replace(/^_/, '') in ids) delete ids[key.replace(/^_/, '')];
ids[key] = key;
}
});
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 4c082b2ad..e3c481a75 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -61,31 +61,22 @@ export class KeyValuePair extends ObservableReactComponent<KeyValuePairProps> {
render() {
let doc = this._props.keyName.startsWith('_') ? Doc.Layout(this._props.doc) : this._props.doc;
- // let fieldKey = Object.keys(props.Document).indexOf(props.fieldKey) !== -1 ? props.fieldKey : "(" + props.fieldKey + ")";
const layoutField = doc !== this._props.doc;
const key = layoutField ? this._props.keyName.replace(/^_/, '') : this._props.keyName;
let protoCount = 0;
- while (doc) {
- if (Object.keys(doc).includes(key)) {
- break;
- }
+ while (doc && !Object.keys(doc).includes(key)) {
protoCount++;
doc = DocCast(doc.proto);
}
const parenCount = Math.max(0, protoCount - 1);
const keyStyle = layoutField ? 'red' : protoCount === 0 ? 'black' : 'blue';
-
const hover = { transition: '0.3s ease opacity', opacity: this.isPointerOver || this.isChecked ? 1 : 0 };
-
+ const docOpts = Object.entries(new DocumentOptions());
return (
<tr
- className={this._props.rowStyle}
- onPointerEnter={action(() => {
- this.isPointerOver = true;
- })}
- onPointerLeave={action(() => {
- this.isPointerOver = false;
- })}>
+ className={this._props.rowStyle} //
+ onPointerEnter={action(() => (this.isPointerOver = true))}
+ onPointerLeave={action(() => (this.isPointerOver = false))}>
<td className="keyValuePair-td-key" style={{ width: `${this._props.keyWidth}%` }}>
<div className="keyValuePair-td-key-container">
<button
@@ -93,14 +84,12 @@ export class KeyValuePair extends ObservableReactComponent<KeyValuePairProps> {
style={hover}
className="keyValuePair-td-key-delete"
onClick={undoable(() => {
- if (Object.keys(this._props.doc).indexOf(key) !== -1) {
- delete this._props.doc[key];
- } else delete DocCast(this._props.doc.proto)?.[key];
+ delete (Object.keys(doc).indexOf(key) !== -1 ? doc : DocCast(this._props.doc.proto))[key];
}, 'set key value')}>
X
</button>
<input className="keyValuePair-td-key-check" type="checkbox" style={hover} onChange={this.handleCheck} ref={this.checkbox} />
- <Tooltip title={Object.entries(new DocumentOptions()).find((pair: [string, FInfo]) => pair[0].replace(/^_/, '') === key)?.[1].description ?? ''}>
+ <Tooltip title={(docOpts.find(([k]) => k.replace(/^_/, '') === key)?.[1] as FInfo)?.description ?? ''}>
<div className="keyValuePair-keyField" style={{ marginLeft: 20 * (key.match(/_/g)?.length || 0), color: keyStyle }}>
{'('.repeat(parenCount)}
{(keyStyle === 'black' ? '' : layoutField ? '_' : '$') + key}
@@ -135,7 +124,7 @@ export class KeyValuePair extends ObservableReactComponent<KeyValuePairProps> {
pinToPres: returnZero,
}}
GetValue={() => Field.toKeyValueString(this._props.doc, this._props.keyName)}
- SetValue={(value: string) => Doc.SetField(this._props.doc, this._props.keyName, value)}
+ SetValue={value => Doc.SetField(this._props.doc, this._props.keyName, value)}
/>
</div>
</td>
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index ba088d674..32c664969 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -43,10 +43,12 @@ export namespace Field {
* @param doc doc containing key
* @param key field key to display
* @param showComputedValue whether copmuted function should display its value instead of its function
+ * @param schemaCell
* @returns string representation of the field
*/
- export function toKeyValueString(doc: Doc, key: string, showComputedValue?: boolean, schemaCell?: boolean): string {
- const isOnDelegate = !Doc.IsDataProto(doc) && Object.keys(doc).includes(key.replace(/^_/, ''));
+ export function toKeyValueString(docIn: Doc, key: string, showComputedValue?: boolean, schemaCell?: boolean): string {
+ const doc = key.startsWith('_') && Doc.Layout(docIn) !== docIn ? Doc.Layout(docIn) : docIn;
+ const isOnDelegate = !key.startsWith('_') && doc === docIn && !Doc.IsDataProto(doc) && Object.keys(doc).includes(key.replace(/^_/, ''));
const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
const valFunc = (field: FieldType): string => {
const res =
@@ -64,7 +66,7 @@ export namespace Field {
.trim()
.replace(/^new List\((.*)\)$/, '$1');
};
- return !Field.IsField(cfield) ? (key.startsWith('_') ? '=' : '') : (isOnDelegate ? '=' : '') + valFunc(cfield);
+ return !Field.IsField(cfield) ? '' : (isOnDelegate ? '=' : '') + valFunc(cfield);
}
export function toScriptString(field: FieldType, schemaCell?: boolean) {
switch (typeof field) {