aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/DocServer.ts64
-rw-r--r--src/client/util/Scripting.ts2
-rw-r--r--src/client/views/DocumentButtonBar.tsx32
-rw-r--r--src/client/views/DocumentDecorations.tsx2
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx8
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx10
-rw-r--r--src/client/views/collections/CollectionTreeView.scss1
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx18
-rw-r--r--src/client/views/collections/ParentDocumentSelector.tsx4
9 files changed, 83 insertions, 58 deletions
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 0c9d5f75c..bf9fd232c 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -7,6 +7,7 @@ import { RefField } from '../new_fields/RefField';
import { Id, HandleUpdate } from '../new_fields/FieldSymbols';
import GestureOverlay from './views/GestureOverlay';
import MobileInkOverlay from '../mobile/MobileInkOverlay';
+import { runInAction } from 'mobx';
/**
* This class encapsulates the transfer and cross-client synchronization of
@@ -109,6 +110,7 @@ export namespace DocServer {
GUID = identifier;
_socket = OpenSocket(`${protocol}//${hostname}:${port}`);
+ _GetCachedRefField = _GetCachedRefFieldImpl;
_GetRefField = _GetRefFieldImpl;
_GetRefFields = _GetRefFieldsImpl;
_CreateField = _CreateFieldImpl;
@@ -243,12 +245,22 @@ export namespace DocServer {
return Promise.resolve(cached);
}
};
+ const _GetCachedRefFieldImpl = (id: string): Opt<RefField> => {
+ const cached = _cache[id];
+ if (cached !== undefined && !(cached instanceof Promise)) {
+ return cached;
+ }
+ }
let _GetRefField: (id: string) => Promise<Opt<RefField>> = errorFunc;
+ let _GetCachedRefField: (id: string) => Opt<RefField> = errorFunc;
export function GetRefField(id: string): Promise<Opt<RefField>> {
return _GetRefField(id);
}
+ export function GetCachedRefField(id: string): Opt<RefField> {
+ return _GetCachedRefField(id);
+ }
export async function getYoutubeChannels() {
const apiKey = await Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, { type: YoutubeQueryTypes.Channels });
@@ -308,32 +320,34 @@ export namespace DocServer {
const deserializeFields = getSerializedFields.then(async fields => {
const fieldMap: { [id: string]: RefField } = {};
const proms: Promise<void>[] = [];
- for (const field of fields) {
- if (field !== undefined && field !== null) {
- // deserialize
- const prom = SerializationHelper.Deserialize(field).then(deserialized => {
- fieldMap[field.id] = deserialized;
-
- //overwrite or delete any promises (that we inserted as flags
- // to indicate that the field was in the process of being fetched). Now everything
- // should be an actual value within or entirely absent from the cache.
- if (deserialized !== undefined) {
- _cache[field.id] = deserialized;
- } else {
- delete _cache[field.id];
- }
- return deserialized;
- });
- // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache)
- // we set the value at the field's id to a promise that will resolve to the field.
- // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method).
- // The mapping in the .then call ensures that when other callers await these promises, they'll
- // get the resolved field
- _cache[field.id] = prom;
- // adds to a list of promises that will be awaited asynchronously
- proms.push(prom);
+ runInAction(() => {
+ for (const field of fields) {
+ if (field !== undefined && field !== null) {
+ // deserialize
+ const prom = SerializationHelper.Deserialize(field).then(deserialized => {
+ fieldMap[field.id] = deserialized;
+
+ //overwrite or delete any promises (that we inserted as flags
+ // to indicate that the field was in the process of being fetched). Now everything
+ // should be an actual value within or entirely absent from the cache.
+ if (deserialized !== undefined) {
+ _cache[field.id] = deserialized;
+ } else {
+ delete _cache[field.id];
+ }
+ return deserialized;
+ });
+ // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache)
+ // we set the value at the field's id to a promise that will resolve to the field.
+ // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method).
+ // The mapping in the .then call ensures that when other callers await these promises, they'll
+ // get the resolved field
+ _cache[field.id] = prom;
+ // adds to a list of promises that will be awaited asynchronously
+ proms.push(prom);
+ }
}
- }
+ });
await Promise.all(proms);
return fieldMap;
});
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index 12628273b..8b7b9c9c7 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -136,7 +136,7 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an
if (batch) {
batch.end();
}
- onError && onError(error);
+ onError?.(error);
return { success: false, error, result: errorVal };
}
};
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index cf57094b2..d58eb5875 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -50,11 +50,9 @@ enum UtilityButtonState {
}
@observer
-export class DocumentButtonBar extends React.Component<{ views: (DocumentView | undefined)[], stack?: any }, {}> {
+export class DocumentButtonBar extends React.Component<{ views: () => (DocumentView | undefined)[], stack?: any }, {}> {
private _linkButton = React.createRef<HTMLDivElement>();
private _dragRef = React.createRef<HTMLDivElement>();
- private _downX = 0;
- private _downY = 0;
private _pullAnimating = false;
private _pushAnimating = false;
private _pullColorAnimating = false;
@@ -71,7 +69,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
public static hasPushedHack = false;
public static hasPulledHack = false;
- constructor(props: { views: (DocumentView | undefined)[] }) {
+ constructor(props: { views: () => (DocumentView | undefined)[] }) {
super(props);
runInAction(() => DocumentButtonBar.Instance = this);
}
@@ -113,7 +111,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
this._pullColorAnimating = false;
});
- get view0() { return this.props.views?.[0]; }
+ get view0() { return this.props.views()?.[0]; }
@action
onLinkButtonMoved = (e: PointerEvent) => {
@@ -265,7 +263,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
const view0 = this.view0;
return !view0 ? (null) : <div title="Show metadata panel" className="documentButtonBar-linkFlyout">
<Flyout anchorPoint={anchorPoints.LEFT_TOP}
- content={<MetadataEntryMenu docs={() => this.props.views.filter(dv => dv).map(dv => dv!.props.Document)} suggestWithFunction /> /* tfs: @bcz This might need to be the data document? */}>
+ content={<MetadataEntryMenu docs={() => this.props.views().filter(dv => dv).map(dv => dv!.props.Document)} suggestWithFunction /> /* tfs: @bcz This might need to be the data document? */}>
<div className={"documentButtonBar-linkButton-" + "empty"} onPointerDown={e => e.stopPropagation()} >
{<FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="sm" />}
</div>
@@ -289,7 +287,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
}
onAliasButtonMoved = () => {
if (this._dragRef.current) {
- const dragDocView = this.props.views[0]!;
+ const dragDocView = this.view0!;
const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]);
const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
dragData.embedDoc = true;
@@ -308,16 +306,18 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
get templateButton() {
const view0 = this.view0;
const templates: Map<Template, boolean> = new Map();
+ const views = this.props.views();
Array.from(Object.values(Templates.TemplateList)).map(template =>
- templates.set(template, this.props.views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean)));
- return !view0 ? (null) : <div title="Tap: Customize layout. Drag: Create alias" className="documentButtonBar-linkFlyout" ref={this._dragRef}>
- <Flyout anchorPoint={anchorPoints.LEFT_TOP} onOpen={action(() => this._aliasDown = true)} onClose={action(() => this._aliasDown = false)}
- content={!this._aliasDown ? (null) : <TemplateMenu docViews={this.props.views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}>
- <div className={"documentButtonBar-linkButton-empty"} ref={this._dragRef} onPointerDown={this.onAliasButtonDown} >
- {<FontAwesomeIcon className="documentdecorations-icon" icon="edit" size="sm" />}
- </div>
- </Flyout>
- </div>;
+ templates.set(template, views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean)));
+ return !view0 ? (null) :
+ <div title="Tap: Customize layout. Drag: Create alias" className="documentButtonBar-linkFlyout" ref={this._dragRef}>
+ <Flyout anchorPoint={anchorPoints.LEFT_TOP} onOpen={action(() => this._aliasDown = true)} onClose={action(() => this._aliasDown = false)}
+ content={!this._aliasDown ? (null) : <TemplateMenu docViews={views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}>
+ <div className={"documentButtonBar-linkButton-empty"} ref={this._dragRef} onPointerDown={this.onAliasButtonDown} >
+ {<FontAwesomeIcon className="documentdecorations-icon" icon="edit" size="sm" />}
+ </div>
+ </Flyout>
+ </div>;
}
render() {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index b89806656..9b6105811 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -499,7 +499,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
</div >
<div className="link-button-container" style={{ left: bounds.x - this._resizeBorderWidth / 2, top: bounds.b + this._resizeBorderWidth / 2 }}>
- <DocumentButtonBar views={SelectionManager.SelectedDocuments()} />
+ <DocumentButtonBar views={SelectionManager.SelectedDocuments} />
</div>
</div >
);
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 6cd5d1b1b..6f5989052 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -517,14 +517,14 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
DragManager.StartDocumentDrag([gearSpan], dragData, e.clientX, e.clientY);
}
};
- let rendered = false;
+
tab.buttonDisposer = reaction(() => ((view: Opt<DocumentView>) => view ? [view] : [])(DocumentManager.Instance.getDocumentView(doc)),
(views) => {
- !rendered && ReactDOM.render(<span title="Drag as document" className="collectionDockingView-dragAsDocument" onPointerDown={onDown} >
- <DockingViewButtonSelector views={views} Stack={stack} />
+ ReactDOM.render(<span title="Drag as document" className="collectionDockingView-dragAsDocument" onPointerDown={onDown} >
+ <DockingViewButtonSelector views={() => views} Stack={stack} />
</span>,
gearSpan);
- rendered = true;
+ tab.buttonDisposer?.();
});
tab.reactComponents = [gearSpan];
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4cc2e1a5f..c199988c0 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -57,6 +57,14 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
}
@computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; }
+ constructor(props: any) {
+ super(props);
+
+ if (this.sectionHeaders === undefined) {
+ this.props.Document.sectionHeaders = new List<SchemaHeaderField>();
+ }
+ }
+
children(docs: Doc[], columns?: number) {
TraceMobx();
this._docXfs.length = 0;
@@ -85,7 +93,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
setTimeout(() => this.props.Document.sectionHeaders = new List<SchemaHeaderField>(), 0);
return new Map<SchemaHeaderField, Doc[]>();
}
- const sectionHeaders: SchemaHeaderField[] = Array.from(this.sectionHeaders);
+ const sectionHeaders = Array.from(this.sectionHeaders);
const fields = new Map<SchemaHeaderField, Doc[]>(sectionHeaders.map(sh => [sh, []] as [SchemaHeaderField, []]));
let changed = false;
this.filteredChildren.map(d => {
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index a00bb6bfb..2aac81146 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -81,7 +81,6 @@
position: relative;
text-overflow: ellipsis;
white-space: pre-wrap;
- overflow: hidden;
min-width: 10px;
// width:100%;//width: max-content;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 297c11e35..4fb54cc07 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -34,6 +34,7 @@ import "./CollectionTreeView.scss";
import { CollectionViewType } from './CollectionView';
import React = require("react");
import { makeTemplate } from '../../util/DropConverter';
+import { TraceMobx } from '../../../new_fields/util';
export interface TreeViewProps {
@@ -100,7 +101,7 @@ class TreeView extends React.Component<TreeViewProps> {
get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.props.document.defaultExpandedView, "fields"); }
@observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state
set treeViewOpen(c: boolean) { if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = this._overrideTreeViewOpen = c; }
- @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && BoolCast(this.props.document.treeViewOpen)) || this._overrideTreeViewOpen; }
+ @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && !this.props.document.treeViewPreventOpen && BoolCast(this.props.document.treeViewOpen)) || this._overrideTreeViewOpen; }
@computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.defaultExpandedView); }
@computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containingCollection.maxEmbedHeight, 200); }
@computed get dataDoc() { return this.templateDataDoc ? this.templateDataDoc : this.props.document; }
@@ -326,6 +327,7 @@ class TreeView extends React.Component<TreeViewProps> {
rtfHeight = () => this.rtfWidth() < Doc.Layout(this.props.document)?.[WidthSym]() ? Math.min(Doc.Layout(this.props.document)?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
@computed get renderContent() {
+ TraceMobx();
const expandKey = this.treeViewExpandedView === this.fieldKey ? this.fieldKey : this.treeViewExpandedView === "links" ? "links" : undefined;
if (expandKey !== undefined) {
const remDoc = (doc: Doc) => this.remove(doc, expandKey);
@@ -419,13 +421,15 @@ class TreeView extends React.Component<TreeViewProps> {
return [{ script: focusScript!, label: "Focus" }];
}
_docRef = React.createRef<DocumentView>();
+ _editTitleScript: ScriptField | undefined;
/**
* Renders the EditableView title element for placement into the tree.
*/
@computed
get renderTitle() {
+ TraceMobx();
const onItemDown = SetupDrag(this._tref, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId[Id], true);
- const editTitle = ScriptField.MakeFunction("setInPlace(this, 'editTitle', true)");
+ //!this._editTitleScript && (this._editTitleScript = ScriptField.MakeFunction("setInPlace(this, 'editTitle', true)"));
const headerElements = (
<>
@@ -449,7 +453,6 @@ class TreeView extends React.Component<TreeViewProps> {
return <>
<div className="docContainer" ref={this._tref} title="click to edit title" id={`docContainer-${this.props.parentKey}`} onPointerDown={onItemDown}
style={{
- background: Doc.IsHighlighted(this.props.document) ? "orange" : Doc.IsBrushed(this.props.document) ? "#06121212" : "0",
fontWeight: this.props.document.searchMatch ? "bold" : undefined,
textDecoration: Doc.GetT(this.props.document, "title", "string", true) ? "underline" : undefined,
outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined,
@@ -461,12 +464,12 @@ class TreeView extends React.Component<TreeViewProps> {
ref={this._docRef}
Document={this.props.document}
DataDoc={undefined}
- LibraryPath={this.props.libraryPath || []}
+ LibraryPath={this.props.libraryPath || emptyPath}
addDocument={undefined}
addDocTab={this.props.addDocTab}
rootSelected={returnTrue}
pinToPres={emptyFunction}
- onClick={this.props.onChildClick || editTitle}
+ onClick={this.props.onChildClick || this._editTitleScript}
dropAction={this.props.dropAction}
moveDocument={this.move}
removeDocument={this.removeDoc}
@@ -478,7 +481,7 @@ class TreeView extends React.Component<TreeViewProps> {
NativeWidth={returnZero}
contextMenuItems={this.contextMenuItems}
renderDepth={1}
- focus={emptyFunction}
+ focus={returnTrue}
parentActive={returnTrue}
whenActiveChanged={emptyFunction}
bringToFront={emptyFunction}
@@ -493,8 +496,9 @@ class TreeView extends React.Component<TreeViewProps> {
}
render() {
+ TraceMobx();
const sorting = this.props.document[`${this.fieldKey}-sortAscending`];
- setTimeout(() => runInAction(() => untracked(() => this._overrideTreeViewOpen = this.treeViewOpen)), 0);
+ //setTimeout(() => runInAction(() => untracked(() => this._overrideTreeViewOpen = this.treeViewOpen)), 0);
return <div className="treeViewItem-container" ref={this.createTreeDropTarget}>
<li className="collection-child">
<div className="treeViewItem-header" ref={this._header} onClick={e => {
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 10c6ead1a..6e4f801c0 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -94,7 +94,7 @@ export class ParentDocSelector extends React.Component<SelectorProps> {
}
@observer
-export class DockingViewButtonSelector extends React.Component<{ views: DocumentView[], Stack: any }> {
+export class DockingViewButtonSelector extends React.Component<{ views: () => DocumentView[], Stack: any }> {
customStylesheet(styles: any) {
return {
...styles,
@@ -120,7 +120,7 @@ export class DockingViewButtonSelector extends React.Component<{ views: Document
if (getComputedStyle(this._ref.current!).width !== "100%") {
e.stopPropagation(); e.preventDefault();
}
- this.props.views[0]?.select(false);
+ this.props.views()[0]?.select(false);
}} className="buttonSelector">
<Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.flyout} stylesheet={this.customStylesheet}>
<FontAwesomeIcon icon={"cog"} size={"sm"} />