aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx63
-rw-r--r--src/client/views/nodes/DataVizBox/components/Chart.scss1
-rw-r--r--src/client/views/nodes/DocumentView.tsx6
-rw-r--r--src/client/views/nodes/FontIconBox/FontIconBox.tsx8
-rw-r--r--src/client/views/nodes/formattedText/DashFieldView.tsx13
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx34
-rw-r--r--src/client/views/nodes/formattedText/nodes_rts.ts3
7 files changed, 81 insertions, 47 deletions
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 8365f4770..e453bcee0 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Colors, Toggle, ToggleType, Type } from 'browndash-components';
-import { ObservableMap, action, computed, makeObservable, observable, runInAction } from 'mobx';
+import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { emptyFunction, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents } from '../../../../Utils';
@@ -40,9 +40,9 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() im
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
private _marqueeref = React.createRef<MarqueeAnnotator>();
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
+ private _disposers: { [name: string]: IReactionDisposer } = {};
anchorMenuClick?: () => undefined | ((anchor: Doc) => void);
crop: ((region: Doc | undefined, addCrop?: boolean) => Doc | undefined) | undefined;
- @observable _schemaDataVizChildren: any = undefined;
@observable _marqueeing: number[] | undefined = undefined;
@observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
@@ -256,12 +256,39 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() im
componentDidMount() {
this._props.setContentViewBox?.(this);
if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData();
+ this._disposers.datavis = reaction(
+ () => {
+ const getFrom = DocCast(this.layoutDoc.dataViz_asSchema);
+ const keys = Cast(getFrom?.schema_columnKeys, listSpec('string'))?.filter(key => key != 'text');
+ if (!keys) return;
+ const children = DocListCast(getFrom[Doc.LayoutFieldKey(getFrom)]);
+ var current: { [key: string]: string }[] = [];
+ children
+ .filter(child => child)
+ .forEach(child => {
+ const row: { [key: string]: string } = {};
+ keys.forEach(key => {
+ var cell = child[key];
+ if (cell && (cell as string)) cell = cell.toString().replace(/\,/g, '');
+ row[key] = StrCast(cell);
+ });
+ current.push(row);
+ });
+ return current;
+ },
+ current => {
+ current && DataVizBox.dataset.set(CsvCast(this.Document[this.fieldKey]).url.href, current);
+ },
+ { fireImmediately: true }
+ );
}
fetchData = () => {
- DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, []); // assign temporary dataset as a lock to prevent duplicate server requests
- fetch('/csvData?uri=' + this.dataUrl?.url.href) //
- .then(res => res.json().then(action(res => !res.errno && DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, res))));
+ if (!this.Document.dataViz_asSchema) {
+ DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, []); // assign temporary dataset as a lock to prevent duplicate server requests
+ fetch('/csvData?uri=' + this.dataUrl?.url.href) //
+ .then(res => res.json().then(action(res => !res.errno && DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, res))));
+ }
};
// toggles for user to decide which chart type to view the data in
@@ -327,33 +354,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() im
GPTPopup.Instance.addDoc = this.sidebarAddDocument;
};
- @action
- updateSchemaViz = () => {
- const getFrom = DocCast(this.layoutDoc.dataViz_asSchema);
- const keys = Cast(getFrom.schema_columnKeys, listSpec('string'))?.filter(key => key != 'text');
- if (!keys) return;
- const children = DocListCast(getFrom[Doc.LayoutFieldKey(getFrom)]);
- var current: { [key: string]: string }[] = [];
- for (let i = 0; i < children.length; i++) {
- var row: { [key: string]: string } = {};
- if (children[i]) {
- for (let j = 0; j < keys.length; j++) {
- var cell = children[i][keys[j]];
- if (cell && (cell as string)) cell = cell.toString().replace(/\,/g, '');
- row[keys[j]] = StrCast(cell);
- }
- }
- current.push(row);
- }
- DataVizBox.dataset.set(CsvCast(this.Document[this.fieldKey]).url.href, current);
- };
-
render() {
- if (this.layoutDoc && this.layoutDoc.dataViz_asSchema) {
- this._schemaDataVizChildren = DocListCast(DocCast(this.layoutDoc.dataViz_asSchema)[Doc.LayoutFieldKey(DocCast(this.layoutDoc.dataViz_asSchema))]).length;
- this.updateSchemaViz();
- }
-
const scale = this._props.NativeDimScaling?.() || 1;
return !this.records.length ? (
// displays how to get data into the DataVizBox if its empty
diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss
index 2f7dd0487..116a45623 100644
--- a/src/client/views/nodes/DataVizBox/components/Chart.scss
+++ b/src/client/views/nodes/DataVizBox/components/Chart.scss
@@ -93,7 +93,6 @@
display: flex;
flex-direction: column;
cursor: default;
- margin-top: 30px;
height: calc(100% - 40px); // bcz: hack 40px is the size of the button rows
.tableBox-container {
overflow: scroll;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a82580ddb..2e1ba2a7e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -592,13 +592,9 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
!Doc.noviceMode && onClicks.push({ description: 'Toggle Detail', event: this.setToggleDetail, icon: 'concierge-bell' });
if (!this.Document.annotationOn) {
- const options = cm.findByDescription('Options...');
- const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : [];
- !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'compass' });
-
onClicks.push({ description: this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(false, false), icon: 'link' });
!Doc.noviceMode && onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' });
- !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
+ cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' });
} else if (LinkManager.Links(this.Document).length) {
onClicks.push({ description: 'Restore On Click default', event: () => this.noOnClick(), icon: 'link' });
onClicks.push({ description: 'Follow Link on Click', event: () => this.followLinkOnClick(), icon: 'link' });
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index cf07d98be..8290e102c 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -73,7 +73,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
};
specificContextMenu = (): void => {
- if (!Doc.noviceMode) {
+ if (!Doc.noviceMode && Cast(this.layoutDoc.dragFactory, Doc, null)) {
const cm = ContextMenu.Instance;
cm.addItem({ description: 'Show Template', event: this.showTemplate, icon: 'tag' });
cm.addItem({ description: 'Use as Render Template', event: this.dragAsTemplate, icon: 'tag' });
@@ -366,7 +366,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
);
}
- render() {
+ renderButton = () => {
const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color);
const tooltip = StrCast(this.Document.toolTip);
const scriptFunc = () => ScriptCast(this.Document.onClick)?.script.run({ this: this.Document, self: this.Document, _readOnly_: false });
@@ -389,5 +389,9 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
background={SettingsManager.userBackgroundColor} size={Size.LARGE} tooltipPlacement='right' onPointerDown={scriptFunc} />;
}
return this.defaultButton;
+ };
+
+ render() {
+ return <div onContextMenu={this.specificContextMenu}>{this.renderButton()}</div>;
}
}
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index dc9914637..18286267a 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -1,10 +1,10 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
-import { action, computed, IReactionDisposer, makeObservable, observable } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
-import { Doc } from '../../../../fields/Doc';
+import { Doc, Field } from '../../../../fields/Doc';
import { List } from '../../../../fields/List';
import { listSpec } from '../../../../fields/Schema';
import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
@@ -114,6 +114,13 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
}
}
+ componentDidMount() {
+ this._reactionDisposer = reaction(
+ () => (this._dashDoc ? Field.toKeyValueString(this._dashDoc, this._props.fieldKey) : undefined),
+ keyvalue => keyvalue && this._props.tbox.tryUpdateDoc(true)
+ );
+ }
+
componentWillUnmount() {
this._reactionDisposer?.();
}
@@ -184,7 +191,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
}}>
{this._props.hideKey ? null : (
<span className="dashFieldView-labelSpan" title="click to see related tags" onPointerDown={this.onPointerDownLabelSpan}>
- {this._fieldKey}
+ {(this._textBoxDoc === this._dashDoc ? '' : this._dashDoc?.title + ':') + this._fieldKey}
</span>
)}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 731ab1d53..6f9c2893e 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -67,6 +67,7 @@ import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu';
import { RichTextRules } from './RichTextRules';
import { schema } from './schema_rts';
import { SummaryView } from './SummaryView';
+import { CollectionView } from '../../collections/CollectionView';
// import * as applyDevTools from 'prosemirror-dev-tools';
@observer
export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
@@ -325,13 +326,26 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
} catch (e) {}
};
+ leafText = (node: Node) => {
+ if (node.type === this._editorView?.state.schema.nodes.dashField) {
+ const refDoc = !node.attrs.docId ? this.Document : (DocServer.GetCachedRefField(node.attrs.docId as string) as Doc);
+ return Field.toJavascriptString(refDoc[node.attrs.fieldKey as string] as Field);
+ }
+ return '';
+ };
dispatchTransaction = (tx: Transaction) => {
if (this._editorView && (this._editorView as any).docView) {
const state = this._editorView.state.apply(tx);
this._editorView.updateState(state);
+ this.tryUpdateDoc(false);
+ }
+ };
+ tryUpdateDoc = (force: boolean) => {
+ if (this._editorView && (this._editorView as any).docView) {
+ const state = this._editorView.state;
const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc.proto), this.fieldKey) ? DocCast(this.layoutDoc.proto) : this.dataDoc;
- const newText = state.doc.textBetween(0, state.doc.content.size, ' \n');
+ const newText = state.doc.textBetween(0, state.doc.content.size, ' \n', this.leafText);
const newJson = JSON.stringify(state.toJSON());
const prevData = Cast(this.layoutDoc[this.fieldKey], RichTextField, null); // the actual text in the text box
const templateData = this.Document !== this.layoutDoc ? prevData : undefined; // the default text stored in a layout template
@@ -350,13 +364,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
dataDoc.tags = accumTags.length ? new List<string>(Array.from(new Set<string>(accumTags))) : undefined;
let unchanged = true;
- if (this._applyingChange !== this.fieldKey && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
+ if (this._applyingChange !== this.fieldKey && (force || removeSelection(newJson) !== removeSelection(prevData?.Data))) {
this._applyingChange = this.fieldKey;
const textChange = newText !== prevData?.Text;
textChange && (dataDoc[this.fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())));
if ((!prevData && !protoData) || newText || (!newText && !templateData)) {
// if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
- if ((this._finishingLink || this._props.isContentActive() || this._inDrop) && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
+ if (force || ((this._finishingLink || this._props.isContentActive() || this._inDrop) && removeSelection(newJson) !== removeSelection(prevData?.Data))) {
const numstring = NumCast(dataDoc[this.fieldKey], null);
dataDoc[this.fieldKey] = numstring !== undefined ? Number(newText) : new RichTextField(newJson, newText);
dataDoc[this.fieldKey + '_noTemplate'] = true; // mark the data field as being split from the template if it has been edited
@@ -480,7 +494,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
var alink: Doc | undefined;
this.findInNode(editorView, editorView.state.doc, autoLinkTerm).forEach(sel => {
const splitter = editorView.state.schema.marks.splitter.create({ id: Utils.GenerateGuid() });
- if (!sel.$anchor.pos || editorView.state.doc.textBetween(sel.$anchor.pos - 1, sel.$to.pos).trim() === autoLinkTerm) {
+ if (!sel.$anchor.pos || [autoLinkTerm, StrCast(target.title)].includes(editorView.state.doc.textBetween(sel.$anchor.pos - 1, sel.$to.pos).trim())) {
tr = tr.addMark(sel.from, sel.to, splitter);
tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => {
if (node.firstChild === null && !node.marks.find((m: Mark) => m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
@@ -919,6 +933,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
event: () => (this.layoutDoc._createDocOnCR = !this.layoutDoc._createDocOnCR),
icon: !this.Document._createDocOnCR ? 'grip-lines' : 'bars',
});
+ optionItems.push({
+ description: 'Make Paint Function',
+ event: () => {
+ this.dataDoc.layout_painted = CollectionView.LayoutString('painted');
+ this.layoutDoc.layout_fieldKey = 'layout_painted';
+ this.layoutDoc.type_collection = CollectionViewType.Freeform;
+ this.DocumentView?.().setToggleDetail();
+ this.dataDoc.paintFunc = ComputedField.MakeFunction(`toJavascriptString(this['${this.fieldKey}']?.Text)`);
+ },
+ icon: !this.Document._layout_enableAltContentUI ? 'eye-slash' : 'eye',
+ });
!Doc.noviceMode &&
optionItems.push({
description: `${this.Document._layout_autoHeight ? 'Lock' : 'Auto'} Height`,
@@ -1682,7 +1707,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
FormattedTextBox.LiveTextUndo = undefined;
const state = this._editorView!.state;
- const curText = state.doc.textBetween(0, state.doc.content.size, ' \n');
if (StrCast(this.Document.title).startsWith('@') && !this.dataDoc.title_custom) {
UndoManager.RunInBatch(() => {
this.dataDoc.title_custom = true;
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index d023020e1..31f001b11 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -2,6 +2,8 @@ import * as React from 'react';
import { DOMOutputSpec, Node, NodeSpec } from 'prosemirror-model';
import { listItem, orderedList } from 'prosemirror-schema-list';
import { ParagraphNodeSpec, toParagraphDOM, getParagraphNodeAttrs } from './ParagraphNodeSpec';
+import { DocServer } from '../../../DocServer';
+import { Doc, Field } from '../../../../fields/Doc';
const blockquoteDOM: DOMOutputSpec = ['blockquote', 0],
hrDOM: DOMOutputSpec = ['hr'],
@@ -264,6 +266,7 @@ export const nodes: { [index: string]: NodeSpec } = {
hideKey: { default: false },
editable: { default: true },
},
+ leafText: node => Field.toString((DocServer.GetCachedRefField(node.attrs.docId as string) as Doc)?.[node.attrs.fieldKey as string] as Field),
group: 'inline',
draggable: false,
toDOM(node) {