+
Recommendations
+ {NewLightboxView.LightboxDoc && (
+
+ The recommendations are produced based on the text in the document{' '}
+
+ {StrCast(NewLightboxView.LightboxDoc.title)}
+
+ . The following keywords are used to fetch the recommendations.
- :
-
- {keywordsLoc && keywordsLoc.map((word, ind) => {
- return
- {word}
-
} onClick={() => {
- let kw = keywordsLoc
- kw.splice(ind)
- NewLightboxView.SetKeywords(kw)
- }}/>
+ )}
+ Keywords
+ {loadingKeywords ? (
+
- })}
-
- }
- {!showMore ?
-
{setShowMore(true)}}>
- More
+ ) : (
+
+ {keywordsLoc &&
+ keywordsLoc.map((word, ind) => {
+ return (
+
+ {word}
+ }
+ onClick={() => {
+ let kw = keywordsLoc;
+ kw.splice(ind);
+ NewLightboxView.SetKeywords(kw);
+ }}
+ />
+
+ );
+ })}
+
+ )}
+ {!showMore ? (
+
{
+ setShowMore(true);
+ }}>
+ More
+
+ ) : (
+
+
{
+ setShowMore(false);
+ }}>
+ Less
+
+
Type
+
Sources
+
+ )}
- :
-
-
{setShowMore(false)}}>
- Less
-
-
Type
-
Sources
+
+ {recs &&
+ recs.map((rec: IRecommendation) => {
+ return ;
+ })}
- }
-
-
- {recs && recs.map((rec: IRecommendation) => {
- return
- })}
-
-}
\ No newline at end of file
+ );
+};
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 58820a498..a04030a5f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,6 +1,6 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { Howl } from 'howler';
-import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction, trace } from 'mobx';
+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';
@@ -50,7 +50,6 @@ import { KeyValueBox } from './KeyValueBox';
import { LinkAnchorBox } from './LinkAnchorBox';
import { FormattedTextBox } from './formattedText/FormattedTextBox';
import { PresEffect, PresEffectDirection } from './trails';
-import { InkingStroke } from '../InkingStroke';
interface Window {
MediaRecorder: MediaRecorder;
}
diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx
index c43f89be1..a557cff4f 100644
--- a/src/client/views/nodes/EquationBox.tsx
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -1,6 +1,7 @@
import { action, makeObservable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
+import { DivHeight, DivWidth } from '../../../Utils';
import { Id } from '../../../fields/FieldSymbols';
import { NumCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
@@ -11,7 +12,6 @@ import { LightboxView } from '../LightboxView';
import './EquationBox.scss';
import { FieldView, FieldViewProps } from './FieldView';
import EquationEditor from './formattedText/EquationEditor';
-import { DivHeight, DivWidth } from '../../../Utils';
@observer
export class EquationBox extends ViewBoxBaseComponent
() {
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 7ad250714..36bd037ca 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -15,9 +15,9 @@ import { EditableView } from '../EditableView';
import { LightboxView } from '../LightboxView';
import { StyleProp } from '../StyleProvider';
import { ComparisonBox } from './ComparisonBox';
+import { DocumentView } from './DocumentView';
import { FieldView, FieldViewProps } from './FieldView';
import './LinkBox.scss';
-import { DocumentView } from './DocumentView';
@observer
export class LinkBox extends ViewBoxBaseComponent() {
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index f4d5eef05..434415b96 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { htmlToText } from 'html-to-text';
-import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction, trace } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import * as WebRequest from 'web-request';
@@ -34,7 +34,7 @@ import { GPTPopup } from '../pdf/GPTPopup/GPTPopup';
import { SidebarAnnos } from '../SidebarAnnos';
import { StyleProp } from '../StyleProvider';
import { DocumentView, OpenWhere } from './DocumentView';
-import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView';
+import { FieldView, FieldViewProps, FocusViewOptions } from './FieldView';
import { LinkInfo } from './LinkDocPreview';
import { PinProps, PresBox } from './trails';
import './WebBox.scss';
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index ae6da8fb0..cd9fec839 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -18,6 +18,7 @@ import { DocServer } from '../../../DocServer';
import { Docs } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
import { DocumentManager } from '../../../util/DocumentManager';
+import { dropActionType } from '../../../util/DragManager';
import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
import { SelectionManager } from '../../../util/SelectionManager';
import { SerializationHelper } from '../../../util/SerializationHelper';
@@ -32,11 +33,10 @@ import { ViewBoxBaseComponent } from '../../DocComponent';
import { Colors } from '../../global/globalEnums';
import { LightboxView } from '../../LightboxView';
import { DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView';
-import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
+import { FieldView, FieldViewProps, FocusViewOptions } from '../FieldView';
import { ScriptingBox } from '../ScriptingBox';
import './PresBox.scss';
import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums';
-import { dropActionType } from '../../../util/DragManager';
export interface pinDataTypes {
scrollable?: boolean;
dataviz?: number[];
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index addad2bbc..eab33114e 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -3,6 +3,7 @@ import { Button, IconButton, isDark, Size, Type } from 'browndash-components';
import { action, computed, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
+import { Flip } from 'react-awesome-reveal';
import { FaBug } from 'react-icons/fa';
import { Doc, DocListCast } from '../../../fields/Doc';
import { AclAdmin, DashVersion } from '../../../fields/DocSymbols';
@@ -11,6 +12,7 @@ import { GetEffectiveAcl } from '../../../fields/util';
import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils';
import { CurrentUserUtils } from '../../util/CurrentUserUtils';
import { DocumentManager } from '../../util/DocumentManager';
+import { dropActionType } from '../../util/DragManager';
import { PingManager } from '../../util/PingManager';
import { ReportManager } from '../../util/reportManager/ReportManager';
import { ServerStats } from '../../util/ServerStats';
@@ -23,11 +25,9 @@ import { CollectionLinearView } from '../collections/collectionLinear';
import { DashboardView } from '../DashboardView';
import { Colors } from '../global/globalEnums';
import { DocumentViewInternal, returnEmptyDocViewList } from '../nodes/DocumentView';
+import { ObservableReactComponent } from '../ObservableReactComponent';
import { DefaultStyleProvider } from '../StyleProvider';
import './TopBar.scss';
-import { dropActionType } from '../../util/DragManager';
-import { Flip } from 'react-awesome-reveal';
-import { ObservableReactComponent } from '../ObservableReactComponent';
/**
* ABOUT: This is the topbar in Dash, which included the current Dashboard as well as access to information on the user
--
cgit v1.2.3-70-g09d2
From 47ae05389d7ce564efde19b7a639b38842759cc1 Mon Sep 17 00:00:00 2001
From: bobzel
Date: Sun, 31 Mar 2024 00:09:33 -0400
Subject: fixed dropdown in title bar location. moved rotate button up to not
interfere with button bar. don't blur title when editing it. fix drawgging
rotate center on templates. support setting alternate colors for text docs
-- pretty hacky. fixed tabbing through dashFieldViews.
---
src/client/views/DocumentDecorations.scss | 2 +-
src/client/views/DocumentDecorations.tsx | 21 +++++++++++++++------
src/client/views/StyleProvider.tsx | 5 ++++-
.../collectionFreeForm/CollectionFreeFormView.tsx | 2 +-
src/client/views/global/globalScripts.ts | 4 +++-
src/client/views/nodes/DocumentView.scss | 6 ++++++
src/client/views/nodes/DocumentView.tsx | 6 +++++-
.../views/nodes/formattedText/DashFieldView.tsx | 17 ++++++++++-------
.../views/nodes/formattedText/FormattedTextBox.tsx | 7 +++++--
9 files changed, 50 insertions(+), 20 deletions(-)
(limited to 'src/client/views/collections/collectionFreeForm')
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index ac0ef054c..239c0a977 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -14,7 +14,7 @@ $resizeHandler: 8px;
height: 30;
width: 30;
right: -40;
- bottom: -40;
+ bottom: -20;
//top: calc(50% - 15px);
position: absolute;
pointer-events: all;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 6698cd5bc..951e0912c 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -73,11 +73,18 @@ export class DocumentDecorations extends ObservableReactComponent {
+ let inputting = false;
+ if (this._titleControlString.startsWith('$')) {
+ const titleFieldKey = this._titleControlString.substring(1);
+ if (SelectionManager.Views[0]?.Document[titleFieldKey] !== this._accumulatedTitle) {
+ inputting = true;
+ }
+ }
const center = {x: (this.Bounds.x+this.Bounds.r)/2, y: (this.Bounds.y+this.Bounds.b)/2};
const {x,y} = Utils.rotPt(e.clientX - center.x,
e.clientY - center.y,
NumCast(SelectionManager.Views.lastElement()?.screenToViewTransform().Rotate));
- (this._showNothing = !DocumentButtonBar.Instance?._tooltipOpen && !(this.Bounds.x !== Number.MAX_VALUE && //
+ (this._showNothing = !inputting && !DocumentButtonBar.Instance?._tooltipOpen && !(this.Bounds.x !== Number.MAX_VALUE && //
(this.Bounds.x > center.x+x || this.Bounds.r < center.x+x ||
this.Bounds.y > center.y+y || this.Bounds.b < center.y+y )));
})); // prettier-ignore
@@ -336,8 +343,8 @@ export class DocumentDecorations extends ObservableReactComponent // return false to keep getting events
this.setRotateCenter(seldocview, [this.rotCenter[0] + delta[0], this.rotCenter[1] + delta[1]]) as any as boolean,
action(e => (this._isRotating = false)), // upEvent
- action(e => (seldocview.Document.rotation_centerX = seldocview.Document.rotation_centerY = 0))
+ action(e => (seldocview.Document._rotation_centerX = seldocview.Document._rotation_centerY = 0)),
+ true
); // prettier-ignore
+ e.stopPropagation();
};
@action
@@ -617,7 +626,7 @@ export class DocumentDecorations extends ObservableReactComponent {
this._editingTitle = false;
- !hideTitle && this.titleBlur();
+ this.titleBlur();
})}
onChange={action(e => !hideTitle && (this._accumulatedTitle = e.target.value))}
onKeyDown={hideTitle ? emptyFunction : this.titleEntered}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 749198fe6..dcec2fe3d 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -200,7 +200,10 @@ export function DefaultStyleProvider(doc: Opt, props: Opt = StrCast(doc?.[fieldKey + 'backgroundColor'], StrCast(doc?.backgroundColor, isCaption ? 'rgba(0,0,0,0.4)' : ''));
+ const dataKey = doc ? Doc.LayoutFieldKey(doc) : "";
+ const usePath = StrCast(doc?.[dataKey + "_usePath"]);
+ const alternate = usePath.includes(":hover") ? ( doc?.isHovering ? '_' + usePath.replace(":hover","") : "") : usePath ? "_" +usePath:usePath;
+ let docColor: Opt = StrCast(doc?.[fieldKey+alternate], StrCast(doc?.['backgroundColor' +alternate], isCaption ? 'rgba(0,0,0,0.4)' : ''));
if (doc?.[StrCast(doc?.layout_fieldKey)] instanceof Doc) docColor = StrCast(doc._backgroundColor,docColor)
// prettier-ignore
switch (layoutDoc?.type) {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d435173f3..791124f50 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1288,7 +1288,7 @@ export class CollectionFreeFormView extends CollectionSubView div {
+ transform-origin: top left !important;
+ }
+}
+
.contentFittingDocumentView {
position: relative;
display: flex;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a04030a5f..fc2da18d9 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -843,7 +843,11 @@ export class DocumentViewInternal extends DocComponent
- {!dropdownWidth ? null : {this.fieldsDropdown(showTitle)}
}
+ {!dropdownWidth ? null : (
+
+ {this.fieldsDropdown(showTitle)}
+
+ )}
this._nodeSelected;
@@ -38,6 +39,7 @@ export class DashFieldView {
const self = this;
this.node = node;
this.tbox = tbox;
+ this.getpos = getPos;
this.dom = document.createElement('div');
this.dom.style.width = node.attrs.width;
this.dom.style.height = node.attrs.height;
@@ -54,13 +56,13 @@ export class DashFieldView {
const editor = tbox.EditorView;
if (editor) {
const state = editor.state;
- for (var i = state.selection.to; i < state.doc.content.size; i++) {
+ for (var i = self.getpos() + 1; i < state.doc.content.size; i++) {
if (state.doc.nodeAt(i)?.type.name === state.schema.nodes.dashField.name) {
editor.dispatch(state.tr.setSelection(new NodeSelection(state.doc.resolve(i))));
return;
}
}
- tBox.setFocus(state.selection.to);
+ // tBox.setFocus(state.selection.to);
}
}
};
@@ -137,7 +139,7 @@ export class DashFieldViewInternal extends ObservableReactComponent (this._dashDoc = this._props.dataDoc ? doc[DocData] : doc);
+ const setDoc = action((doc: Doc) => (this._dashDoc = this._props.dataDoc ? doc[DocData] : doc));
if (this._props.docId) {
DocServer.GetRefField(this._props.docId).then(dashDoc => dashDoc instanceof Doc && setDoc(dashDoc));
@@ -255,7 +257,7 @@ export class DashFieldViewInternal extends ObservableReactComponent | undefined) => {
- event && this._dashDoc && (this._dashDoc[this._fieldKey] = event.target.value);
+ event && this._dashDoc && (this._dashDoc[this._fieldKey] = event.target.value === '-unset-' ? undefined : event.target.value);
};
@computed get values() {
@@ -281,13 +283,14 @@ export class DashFieldViewInternal extends ObservableReactComponent
)}
{this._props.fieldKey.startsWith('#') || this._hideValue ? null : this.fieldValueContent}
- {/* {!this.values.length ? null : (
-
);
}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 66df1eaf2..3700b08d6 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -2064,8 +2064,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (this._isHovering = true))}
- onPointerLeave={action(() => (this._isHovering = false))}
+ onPointerEnter={action(() => {
+ this._isHovering = true;
+ this.layoutDoc[`_${this._props.fieldKey}_usePath`] && (this.Document.isHovering = true);
+ })}
+ onPointerLeave={action(() => (this.Document.isHovering = this._isHovering = false))}
ref={r => {
this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
this._oldWheel = r;
--
cgit v1.2.3-70-g09d2
From 108e27f0d08a8d6d3b3fcd456d6cca999c077e8b Mon Sep 17 00:00:00 2001
From: bobzel
Date: Sun, 31 Mar 2024 23:09:53 -0400
Subject: fixed scrolling to targets in text views. fixed referencing fields
on another doc from text box. fixed '@name' technique for publishing
documents to also remove documents and work anywhere a title is set.
---
src/client/documents/Documents.ts | 5 ++++
src/client/util/Scripting.ts | 2 +-
src/client/views/DocumentButtonBar.tsx | 2 +-
src/client/views/DocumentDecorations.tsx | 6 ----
.../views/collections/CollectionDockingView.tsx | 25 ++++++++++++++--
.../collections/collectionFreeForm/MarqueeView.tsx | 2 +-
.../views/nodes/formattedText/DashFieldView.tsx | 8 ++---
.../views/nodes/formattedText/FormattedTextBox.tsx | 34 ++++++++++------------
.../views/nodes/formattedText/RichTextRules.ts | 13 +++------
src/client/views/nodes/formattedText/nodes_rts.ts | 1 -
src/fields/Doc.ts | 13 +++++++--
src/fields/util.ts | 16 +++++++++-
12 files changed, 78 insertions(+), 49 deletions(-)
(limited to 'src/client/views/collections/collectionFreeForm')
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 6a0d45543..eb15c332f 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1516,6 +1516,9 @@ export namespace DocUtils {
return linkDoc;
});
+ const a = source.layout_unrendered ? 'link_anchor_1.annotationOn' : 'link_anchor_1';
+ const b = target.layout_unrendered ? 'link_anchor_2.annotationOn' : 'link_anchor_2';
+
return makeLink(
Docs.Create.LinkDocument(
source,
@@ -1529,6 +1532,8 @@ export namespace DocUtils {
link_displayLine: linkSettings.link_displayLine,
link_relationship: linkSettings.link_relationship,
link_description: linkSettings.link_description,
+ x: ComputedField.MakeFunction(`(this.${a}.x+this.${b}.x)/2`) as any,
+ y: ComputedField.MakeFunction(`(this.${a}.y+this.${b}.y)/2`) as any,
link_autoMoveAnchors: true,
_lockedPosition: true,
_layout_showCaption: '', // removed since they conflict with showing a link with a LinkBox (ie, line, not comparison box)
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index 31222aa50..422e708bc 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -250,7 +250,7 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp
const outputText = host.readFile('file.js');
const diagnostics = ts.getPreEmitDiagnostics(program).concat(testResult.diagnostics);
-
+ if (script.startsWith('@')) options.typecheck = true; // need the compilation to fail so that the script will return itself as a string (instead of nothing)
const result = Run(outputText, paramNames, diagnostics, script, options);
if (options.globals) {
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index d65e0b406..15ce4c15f 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -416,7 +416,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
)}
{DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== doc ? {this.endLinkButton}
: null}
- {Doc.noviceMode ? null : {this.templateButton}
}
+ {this.templateButton}
{!SelectionManager.Views?.some(v => v.allLinks.length) ? null : {this.followLinkButton}
}
{this.pinButton}
{this.recordButton}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 951e0912c..9e469ed1f 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -131,12 +131,6 @@ export class DocumentDecorations extends ObservableReactComponent {
if (titleFieldKey === 'title') {
d.dataDoc.title_custom = !this._accumulatedTitle.startsWith('-');
- if (StrCast(d.Document.title).startsWith('@') && !this._accumulatedTitle.startsWith('@')) {
- Doc.RemFromMyPublished(d.Document);
- }
- if (!StrCast(d.Document.title).startsWith('@') && this._accumulatedTitle.startsWith('@')) {
- Doc.AddToMyPublished(d.Document);
- }
}
KeyValueBox.SetField(d.Document, titleFieldKey, this._accumulatedTitle);
}),
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 25bfdb588..b2897a9b7 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -3,14 +3,14 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
import * as GoldenLayout from '../../../client/goldenLayout';
-import { Doc, DocListCast, Opt } from '../../../fields/Doc';
+import { Doc, DocListCast, Field, Opt } from '../../../fields/Doc';
import { AclAdmin, AclEdit, DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
-import { ImageCast, NumCast, StrCast } from '../../../fields/Types';
+import { FieldValue, ImageCast, NumCast, StrCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
-import { GetEffectiveAcl, inheritParentAcls } from '../../../fields/util';
+import { GetEffectiveAcl, inheritParentAcls, SetPropSetterCb } from '../../../fields/util';
import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, DivHeight, DivWidth, emptyFunction, incrementTitleCopy } from '../../../Utils';
import { DocServer } from '../../DocServer';
import { Docs } from '../../documents/Documents';
@@ -32,6 +32,7 @@ import './CollectionDockingView.scss';
import { CollectionFreeFormView } from './collectionFreeForm';
import { CollectionSubView } from './CollectionSubView';
import { TabDocView } from './TabDocView';
+import { ComputedField } from '../../../fields/ScriptField';
const _global = (window /* browser */ || global) /* node */ as any;
@observer
@@ -313,8 +314,26 @@ export class CollectionDockingView extends CollectionSubView() {
}
};
+ /**
+ * This publishes Docs having titles starting with '@' to Doc.myPublishedDocs
+ * Once published, any text that uses the 'title' in its body will automatically
+ * be linked to this published document.
+ * @param target
+ * @param title
+ */
+ titleChanged = (target: any, value: any) => {
+ const title = Field.toString(value);
+ if (title.startsWith('@') && !title.substring(1).match(/[\(\)\[\]@]/) && title.length > 1) {
+ const embedding = DocListCast(target.proto_embeddings).lastElement();
+ embedding && Doc.AddToMyPublished(embedding);
+ } else if (!title.startsWith('@')) {
+ DocListCast(target.proto_embeddings).forEach(doc => Doc.RemFromMyPublished(doc));
+ }
+ };
+
componentDidMount: () => void = async () => {
this._unmounting = false;
+ SetPropSetterCb('title', this.titleChanged); // this overrides any previously assigned callback for the property
if (this._containerRef.current) {
this._lightboxReactionDisposer = reaction(
() => LightboxView.LightboxDoc,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 6b3a56b0b..6eca91e9d 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -499,7 +499,7 @@ export class MarqueeView extends ObservableReactComponent
);
@@ -119,7 +118,6 @@ interface IDashFieldViewInternal {
height: number;
editable: boolean;
nodeSelected: () => boolean;
- dataDoc: boolean;
node: any;
getPos: any;
unclickable: () => boolean;
@@ -139,7 +137,7 @@ export class DashFieldViewInternal extends ObservableReactComponent (this._dashDoc = this._props.dataDoc ? doc[DocData] : doc));
+ const setDoc = action((doc: Doc) => (this._dashDoc = doc));
if (this._props.docId) {
DocServer.GetRefField(this._props.docId).then(dashDoc => dashDoc instanceof Doc && setDoc(dashDoc));
@@ -168,7 +166,7 @@ export class DashFieldViewInternal extends ObservableReactComponent !this._props.tbox.ProseRef?.contains(document.activeElement) && this._props.tbox._props.onBlur?.());
}
});
- selectedCell = (): [Doc, number] => [this._dashDoc!, 0];
+ selectedCell = (): [Doc, number] | undefined => (this._dashDoc ? [this._dashDoc, 0] : undefined);
columnWidth = () => Math.min(this._props.tbox._props.PanelWidth(), Math.max(50, this._props.tbox._props.PanelWidth() - 100)); // try to leave room for the fieldKey
// set the display of the field's value (checkbox for booleans, span of text for strings)
@@ -284,7 +282,7 @@ export class DashFieldViewInternal extends ObservableReactComponent
+
{this.values.map(val => (
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 2deecb6ad..80e56efe0 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -478,7 +478,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent FieldValue(this.dataDoc.title));
if (!(cfield instanceof ComputedField)) {
this.dataDoc.title = (prefix + str.substring(0, Math.min(40, str.length)) + (str.length > 40 ? '...' : '')).trim();
- if (str.startsWith('@') && str.length > 1) {
- Doc.AddToMyPublished(this.Document);
- }
}
}
};
@@ -510,7 +507,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent) => {
const editorView = this._editorView;
if (editorView && (editorView as any).docView && !Doc.AreProtosEqual(target, this.Document)) {
- const autoLinkTerm = StrCast(target.title).replace(/^@/, '');
+ const autoLinkTerm = Field.toString(target.title as Field).replace(/^@/, '');
var alink: Doc | undefined;
this.findInNode(editorView, editorView.state.doc, autoLinkTerm).forEach(sel => {
if (
@@ -1312,15 +1309,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent NumCast(this.layoutDoc._layout_scrollTop),
pos => {
- if (!this._ignoreScroll && this._scrollRef.current && !this._props.dontSelectOnLoad) {
+ if (!this._ignoreScroll && this.ProseRef && !this._props.dontSelectOnLoad) {
const viewTrans = quickScroll ?? StrCast(this.Document._viewTransition);
const durationMiliStr = viewTrans.match(/([0-9]*)ms/);
const durationSecStr = viewTrans.match(/([0-9.]*)s/);
const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0;
if (duration) {
- this._scrollStopper = smoothScroll(duration, this._scrollRef.current, Math.abs(pos || 0), 'ease', this._scrollStopper);
+ this._scrollStopper = smoothScroll(duration, this.ProseRef, Math.abs(pos || 0), 'ease', this._scrollStopper);
} else {
- this._scrollRef.current.scrollTo({ top: pos });
+ this.ProseRef.scrollTo({ top: pos });
}
}
},
@@ -1418,7 +1415,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent {
const docPos = editorView.coordsAtPos(editorView.state.selection.to);
const viewRect = self._ref.current!.getBoundingClientRect();
- const scrollRef = self._scrollRef.current;
+ const scrollRef = self.ProseRef;
const topOff = docPos.top < viewRect.top ? docPos.top - viewRect.top : undefined;
const botOff = docPos.bottom > viewRect.bottom ? docPos.bottom - viewRect.bottom : undefined;
if (((topOff && Math.abs(Math.trunc(topOff)) > 0) || (botOff && Math.abs(Math.trunc(botOff)) > 0)) && scrollRef) {
@@ -1750,20 +1747,21 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent document publishing to Doc.myPublishedDocs
+ const match = RTFCast(this.Document[this.fieldKey]).Text.match(/^(@[a-zA-Z][a-zA-Z_0-9 -]*[a-zA-Z_0-9-]+)/);
+ if (match) {
+ this.dataDoc.title_custom = true;
+ this.dataDoc.title = match[1]; // this triggers the collectionDockingView to publish this Doc
+ this.EditorView?.dispatch(this.EditorView?.state.tr.deleteRange(0, match[1].length + 1));
+ }
+
this.endUndoTypingBatch();
FormattedTextBox.LiveTextUndo?.end();
FormattedTextBox.LiveTextUndo = undefined;
const state = this._editorView!.state;
- if (StrCast(this.Document.title).startsWith('@') && !this.dataDoc.title_custom) {
- UndoManager.RunInBatch(() => {
- this.dataDoc.title_custom = true;
- this.dataDoc.layout_showTitle = 'title';
- const tr = this._editorView!.state.tr;
- this._editorView?.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(0), tr.doc.resolve(StrCast(this.Document.title).length + 2))).deleteSelection());
- }, 'titler');
- }
// if the text box blurs and none of its contents are focused(), then pass the blur along
setTimeout(() => !this.ProseRef?.contains(document.activeElement) && this._props.onBlur?.());
};
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 5e53a019e..e8cf9e992 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -295,8 +295,8 @@ export class RichTextRules {
// create a hyperlink to a titled document
// @()
- new InputRule(new RegExp(/(^|\s)@\(([a-zA-Z_@\.\? \-0-9]+)\)/), (state, match, start, end) => {
- const docTitle = match[2];
+ new InputRule(new RegExp(/@\(([a-zA-Z_@\.\? \-0-9]+)\)/), (state, match, start, end) => {
+ const docTitle = match[1];
const prefixLength = '@('.length;
if (docTitle) {
const linkToDoc = (target: Doc) => {
@@ -342,12 +342,7 @@ export class RichTextRules {
const assign = match[4] === ':' ? (match[4] = '') : match[4];
const value = match[5];
const dataDoc = value === undefined ? !fieldKey.startsWith('_') : !assign?.startsWith('=');
- const getTitledDoc = (docTitle: string) => {
- if (!DocServer.FindDocByTitle(docTitle)) {
- Doc.AddToMyPublished(Docs.Create.TextDocument('', { title: docTitle, _width: 400, _layout_autoHeight: true }));
- }
- return DocServer.FindDocByTitle(docTitle);
- };
+ const getTitledDoc = (docTitle: string) => DocServer.FindDocByTitle(docTitle);
// if the value has commas assume its an array (unless it's part of a chat gpt call indicated by '((' )
if (value?.includes(',') && !value.startsWith('((')) {
const values = value.split(',');
@@ -359,7 +354,7 @@ export class RichTextRules {
if (fieldKey === this.TextBox.fieldKey) return this.TextBox.EditorView!.state.tr;
}
const target = docTitle ? getTitledDoc(docTitle) : undefined;
- const fieldView = state.schema.nodes.dashField.create({ fieldKey, docId: target?.[Id], hideKey: false, hideValue: false, dataDoc });
+ const fieldView = state.schema.nodes.dashField.create({ fieldKey, docId: target?.[Id], hideKey: false, hideValue: false });
return state.tr.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end))).replaceSelectionWith(fieldView, true);
},
{ inCode: true }
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index e335044ea..cab3a6ef5 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -266,7 +266,6 @@ export const nodes: { [index: string]: NodeSpec } = {
hideKey: { default: false },
hideValue: { default: false },
editable: { default: true },
- dataDoc: { default: false },
},
leafText: node => Field.toString((DocServer.GetCachedRefField(node.attrs.docId as string) as Doc)?.[node.attrs.fieldKey as string] as Field),
group: 'inline',
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 200896e25..9973232bf 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -86,7 +86,8 @@ export namespace Field {
// this is a bit hacky, but we treat '^@' references to a published document
// as a kind of macro to include the content of those documents
Doc.MyPublishedDocs.forEach(doc => {
- const regex = new RegExp(`^\\^${doc.title}\\s`, 'm');
+ const regexMultilineFlag = 'm';
+ const regex = new RegExp(`^\\^${StrCast(doc.title).replace(/[\(\)]*/g, '')}\\s`, regexMultilineFlag); // need to remove characters that can cause the regular expression to be invalid
const sections = (Cast(doc.text, RichTextField, null)?.Text ?? '').split('--DOCDATA--');
if (script.match(regex)) {
script = script.replace(regex, sections[0]) + (sections.length > 1 ? sections[1] : '');
@@ -218,8 +219,14 @@ export class Doc extends RefField {
public static IsInMyOverlay(doc: Doc) { return Doc.MyOverlayDocs.includes(doc); } // prettier-ignore
public static AddToMyOverlay(doc: Doc) { Doc.ActiveDashboard?.myOverlayDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myOverlayDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore
public static RemFromMyOverlay(doc: Doc) { Doc.ActiveDashboard?.myOverlayDocs ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myOverlayDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore
- public static AddToMyPublished(doc: Doc) { Doc.ActiveDashboard?.myPublishedDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myPublishedDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore
- public static RemFromMyPublished(doc: Doc){ Doc.ActiveDashboard?.myPublishedDocs ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myPublishedDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore
+ public static AddToMyPublished(doc: Doc) {
+ doc[DocData].title_custom = true;
+ doc[DocData].layout_showTitle = 'title';
+ Doc.ActiveDashboard?.myPublishedDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myPublishedDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore
+ public static RemFromMyPublished(doc: Doc){
+ doc[DocData].title_custom = false;
+ doc[DocData].layout_showTitle = undefined;
+ Doc.ActiveDashboard?.myPublishedDocs ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myPublishedDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore
public static IsComicStyle(doc?: Doc) { return doc && Doc.ActiveDashboard && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === 'comic' ; } // prettier-ignore
constructor(id?: FieldId, forceSave?: boolean) {
diff --git a/src/fields/util.ts b/src/fields/util.ts
index c2ec3f13a..ad592391e 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -1,4 +1,4 @@
-import { $mobx, action, observable, runInAction, trace } from 'mobx';
+import { $mobx, action, observable, runInAction, trace, values } from 'mobx';
import { computedFn } from 'mobx-utils';
import { returnZero } from '../Utils';
import { DocServer } from '../client/DocServer';
@@ -16,6 +16,7 @@ import { RichTextField } from './RichTextField';
import { SchemaHeaderField } from './SchemaHeaderField';
import { ComputedField } from './ScriptField';
import { DocCast, ScriptCast, StrCast } from './Types';
+import { BaseException } from 'pdfjs-dist/types/src/shared/util';
function _readOnlySetter(): never {
throw new Error("Documents can't be modified in read-only mode");
@@ -56,6 +57,8 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
delete curValue[FieldChanged];
}
+ if (typeof prop === 'string' && _propSetterCB.has(prop)) _propSetterCB.get(prop)!(target[SelfProxy], value);
+
const effectiveAcl = GetEffectiveAcl(target);
const writeMode = DocServer.getFieldWriteMode(prop as string);
@@ -282,6 +285,17 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
dataDocChanged && updateCachedAcls(dataDoc);
}
+export var _propSetterCB = new Map void) | undefined>();
+/**
+ * sets a callback function to be called whenever a value is assigned to the specified field key.
+ * For example, this is used to "publish" documents with titles that start with '@'
+ * @param prop
+ * @param setter
+ */
+export function SetPropSetterCb(prop: string, setter: ((target: any, value: any) => void) | undefined) {
+ _propSetterCB.set(prop, setter);
+}
+
//
// target should be either a Doc or ListImpl. receiver should be a Proxy Or List.
//
--
cgit v1.2.3-70-g09d2
From 059218b567ce57d3afa771bd764cde6f5f55b459 Mon Sep 17 00:00:00 2001
From: bobzel
Date: Sun, 14 Apr 2024 17:22:10 -0400
Subject: clean up of freeform centeringShift and nativeScaling
---
.../CollectionFreeFormBackgroundGrid.tsx | 10 +++---
.../collectionFreeForm/CollectionFreeFormView.tsx | 37 +++++++++++-----------
2 files changed, 23 insertions(+), 24 deletions(-)
(limited to 'src/client/views/collections/collectionFreeForm')
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx
index 08dfb32ad..0acc99360 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx
@@ -14,8 +14,8 @@ export interface CollectionFreeFormViewBackgroundGridProps {
nativeDimScaling: () => number;
zoomScaling: () => number;
layoutDoc: Doc;
- cachedCenteringShiftX: number;
- cachedCenteringShiftY: number;
+ centeringShiftX: number;
+ centeringShiftY: number;
}
@observer
export class CollectionFreeFormBackgroundGrid extends React.Component {
@@ -32,7 +32,7 @@ export class CollectionFreeFormBackgroundGrid extends React.Component {
const ctx = el?.getContext('2d');
if (ctx) {
- const Cx = this.props.cachedCenteringShiftX % renderGridSpace;
- const Cy = this.props.cachedCenteringShiftY % renderGridSpace;
+ const Cx = this.props.centeringShiftX % renderGridSpace;
+ const Cy = this.props.centeringShiftY % renderGridSpace;
ctx.lineWidth = Math.min(1, Math.max(0.5, this.props.zoomScaling()));
ctx.setLineDash(gridSpace > 50 ? [3, 3] : [1, 5]);
ctx.clearRect(0, 0, w, h);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 791124f50..3fab00968 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -169,17 +169,19 @@ export class CollectionFreeFormView extends CollectionSubView this.freeformData()?.bounds.cx ?? NumCast(this.Document[this.panXFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.freeform_panX, 1));
panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.freeform_panY, 1));
zoomScaling = () => this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], 1); //, NumCast(DocCast(this.Document.resolvedDataDoc)?.[this.scaleFieldKey], 1));
- PanZoomCenterXf = () =>
- this._props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`;
+ PanZoomCenterXf = () => (this._props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.centeringShiftX}px, ${this.centeringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`);
ScreenToContentsXf = () => this.screenToFreeformContentsXf.copy();
getActiveDocuments = () => this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout);
isAnyChildContentActive = () => this._props.isAnyChildContentActive();
@@ -1114,9 +1115,7 @@ export class CollectionFreeFormView extends CollectionSubView
);
@@ -1812,7 +1811,7 @@ export class CollectionFreeFormView extends CollectionSubView