diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/documents/DocUtils.ts | 8 | ||||
-rw-r--r-- | src/client/documents/Documents.ts | 23 | ||||
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 4 | ||||
-rw-r--r-- | src/client/views/EditableView.tsx | 22 | ||||
-rw-r--r-- | src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx | 3 | ||||
-rw-r--r-- | src/client/views/collections/collectionSchema/SchemaCellField.tsx | 6 | ||||
-rw-r--r-- | src/client/views/collections/collectionSchema/SchemaTableCell.tsx | 3 | ||||
-rw-r--r-- | src/client/views/nodes/KeyValueBox.tsx | 17 | ||||
-rw-r--r-- | src/client/views/nodes/KeyValuePair.tsx | 27 | ||||
-rw-r--r-- | src/fields/Doc.ts | 8 |
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) { |