aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorusodhi <61431818+usodhi@users.noreply.github.com>2021-02-22 21:26:10 -0500
committerusodhi <61431818+usodhi@users.noreply.github.com>2021-02-22 21:26:10 -0500
commit3f954b00b8624861386b23bdb75291bd6a260de8 (patch)
tree7bb4674cb48dc02dde800b5ed7edc5658ba53ab4
parent0381050cab3cbcf6f1c3552fa86cace3a1654a07 (diff)
parentf22163e9e4118df3faf06afc28045b84615fba0d (diff)
merging
-rw-r--r--src/client/documents/Documents.ts2
-rw-r--r--src/client/util/CurrentUserUtils.ts2
-rw-r--r--src/client/views/DocumentDecorations.tsx4
-rw-r--r--src/client/views/LightboxView.tsx2
-rw-r--r--src/client/views/PropertiesButtons.tsx2
-rw-r--r--src/client/views/collections/CollectionSubView.tsx4
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx2
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx2
-rw-r--r--src/client/views/collections/TreeView.tsx233
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx2
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx2
-rw-r--r--src/client/views/nodes/DocumentView.tsx4
12 files changed, 133 insertions, 128 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 1a51f7a4b..518370e7b 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -956,7 +956,7 @@ export namespace DocUtils {
const filteredDocs = docFilters.length ? childDocs.filter(d => {
if (d.z) return true;
// if the document needs a cookie but no filter provides the cookie, then the document does not pass the filter
- if (d["cookies"] && (!filterFacets["cookies"] || !Object.keys(filterFacets["cookies"]).some(key => d["cookies"] === key))) {
+ if (d.cookies && (!filterFacets.cookies || !Object.keys(filterFacets.cookies).some(key => d.cookies === key))) {
return false;
}
for (const facetKey of Object.keys(filterFacets).filter(fkey => fkey !== "cookies")) {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index ae22320f3..dd27f2dab 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -548,6 +548,7 @@ export class CurrentUserUtils {
iconShape: "square",
_stayInCollection: true,
_hideContextMenu: true,
+ system: true,
dontUndo: true,
title,
target,
@@ -580,6 +581,7 @@ export class CurrentUserUtils {
btn.color = "white";
btn._backgroundColor = "";
btn.dontUndo = true;
+ btn.system = true;
if (btn.title === "Catalog" || btn.title === "My Files") { // migration from Catalog to My Files
btn.target = Doc.UserDoc().myFilesystem;
btn.title = "My Files";
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index c8a5b338a..7f1023a4a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -580,9 +580,9 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
</Tooltip>;
const titleArea = this._edtingTitle ?
- <input ref={this._keyinput} className="documentDecorations-title" type="text" name="dynbox" autoComplete="on" value={this._accumulatedTitle}
+ <input ref={this._keyinput} className="documentDecorations-title" style={{ width: `calc(100% - ${seldoc?.props.hideResizeHandles ? 0 : 20}px` }} type="text" name="dynbox" autoComplete="on" value={this._accumulatedTitle}
onBlur={e => this.titleBlur(true)} onChange={action(e => this._accumulatedTitle = e.target.value)} onKeyPress={this.titleEntered} /> :
- <div className="documentDecorations-title" style={{ width: `calc(100% - ${seldoc.props.hideResizeHandles ? 0 : 20}px` }} key="title" onPointerDown={this.onTitleDown} >
+ <div className="documentDecorations-title" style={{ width: `calc(100% - ${seldoc?.props.hideResizeHandles ? 0 : 20}px` }} key="title" onPointerDown={this.onTitleDown} >
<span className="documentDecorations-titleSpan">{`${this.selectionTitle}`}</span>
</div>;
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 5e810d335..e967a5b07 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -148,7 +148,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
LightboxView.SetLightboxDoc(undefined);
return;
}
- const { doc, target } = LightboxView._history?.lastElement()!;
+ const { doc, target } = LightboxView._history?.lastElement();
const docView = target && DocumentManager.Instance.getLightboxDocumentView(target);
if (docView && target) {
LightboxView._doc = doc;
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 53a017592..8ad5f3f2b 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -222,7 +222,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
}
@undoBatch
- setDictation = () => SelectionManager.Views().forEach(dv => dv.rootDoc._showAudio = !dv.rootDoc._showAudio);
+ setDictation = () => SelectionManager.Views().forEach(dv => dv.rootDoc._showAudio = !dv.rootDoc._showAudio)
@computed
get dictationButton() {
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 2ba45df2c..a9438f8f7 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -256,8 +256,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
const addDocument = (doc: Doc | Doc[]) => {
const docs = doc instanceof Doc ? [doc] : doc;
docs.forEach(doc => Doc.AddDocToList(Cast(Doc.UserDoc().myFileOrphans, Doc, null), "data", doc));
- this.addDocument(doc);
- }
+ return this.addDocument(doc);
+ };
if (html) {
if (FormattedTextBox.IsFragment(html)) {
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 8067e1d07..cd91cbf63 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -130,7 +130,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
@action
contentsDown = (e: React.MouseEvent) => {
- let prevFilterIndex = NumCast(this.layoutDoc._prevFilterIndex);
+ const prevFilterIndex = NumCast(this.layoutDoc._prevFilterIndex);
if (prevFilterIndex > 0) {
this.goTo(prevFilterIndex - 1);
} else {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index d67fa75e9..b0c3064dc 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -209,7 +209,7 @@ export class
moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.styleProvider, this.props.ScreenToLocalTransform,
this.outerXf, this.active, this.panelWidth, this.props.renderDepth, () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields),
BoolCast(this.doc.treeViewPreventOpen), [], this.props.onCheckedClick,
- this.onChildClick, this.props.treeViewSkipFields, true, this.whenActiveChanged, this.props.dontRegisterView || Cast(this.props.Document.dontRegisterChildViews, "boolean", null));
+ this.onChildClick, this.props.treeViewSkipFields, true, this.whenActiveChanged, this.props.dontRegisterView || Cast(this.props.Document.dontRegisterChildViews, "boolean", null), this);
}
@computed get titleBar() {
const hideTitle = this.props.treeViewHideTitle || this.doc.treeViewHideTitle;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index d091e477a..184d5814a 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1,5 +1,5 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable } from "mobx";
+import { action, computed, observable, runInAction, trace, reaction, IReactionDisposer } from "mobx";
import { observer } from "mobx-react";
import { DataSym, Doc, DocListCast, DocListCastOrNull, Field, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
@@ -32,7 +32,6 @@ import { CollectionTreeView } from './CollectionTreeView';
import { CollectionView, CollectionViewType } from './CollectionView';
import "./TreeView.scss";
import React = require("react");
-import { ContextMenu } from '../ContextMenu';
export interface TreeViewProps {
document: Doc;
@@ -48,8 +47,8 @@ export interface TreeViewProps {
panelWidth: () => number;
panelHeight: () => number;
addDocument: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean;
- indentDocument?: () => void;
- outdentDocument?: () => void;
+ indentDocument?: (editTitle: boolean) => void;
+ outdentDocument?: (editTitle: boolean) => void;
ScreenToLocalTransform: () => Transform;
dontRegisterView?: boolean;
styleProvider?: StyleProviderFunc | undefined;
@@ -65,6 +64,7 @@ export interface TreeViewProps {
skipFields?: string[];
firstLevel: boolean;
whenActiveChanged: (isActive: boolean) => void;
+ parentTreeView: TreeView | CollectionTreeView | undefined;
}
const treeBulletWidth = function () { return Number(TREE_BULLET_WIDTH.replace("px", "")); };
@@ -79,28 +79,31 @@ const treeBulletWidth = function () { return Number(TREE_BULLET_WIDTH.replace("p
* treeViewExpandedView : name of field whose contents are being displayed as the document's subtree
*/
export class TreeView extends React.Component<TreeViewProps> {
+ static _editTitleOnLoad: Opt<{ id: string, parent: TreeView | CollectionTreeView | undefined }>;
+ static _openTitleScript: Opt<ScriptField | undefined>;
+ static _openLevelScript: Opt<ScriptField | undefined>;
private _editTitleScript: (() => ScriptField) | undefined;
private _openScript: (() => ScriptField) | undefined;
private _header?: React.RefObject<HTMLDivElement> = React.createRef();
private _treedropDisposer?: DragManager.DragDropDisposer;
private _tref = React.createRef<HTMLDivElement>();
- private _docRef = React.createRef<DocumentView>();
- private _uniqueId = Utils.GenerateGuid();
+ private _docRef: Opt<DocumentView>;
private _editMaxWidth: number | string = 0;
+ private _selDisposer: Opt<IReactionDisposer>;
-
- @observable _dref: DocumentView | undefined | null;
- @computed get doc() { TraceMobx(); return this.props.document; }
- get noviceMode() { return BoolCast(Doc.UserDoc().noviceMode, false); }
- get displayName() { return "TreeView(" + this.props.document.title + ")"; } // this makes mobx trace() statements more descriptive
- get treeViewLockExpandedView() { return this.doc.treeViewLockExpandedView; }
- get defaultExpandedView() { return StrCast(this.doc.treeViewDefaultExpandedView, this.fileSysMode ? "data" : this.noviceMode || this.outlineMode ? "layout" : "fields"); }
- get treeViewDefaultExpandedView() { return this.treeViewLockExpandedView ? this.defaultExpandedView : (this.childDocs && !this.fileSysMode ? this.fieldKey : this.defaultExpandedView); }
- @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.doc.treeViewOpen = this._overrideTreeViewOpen = c;
}
+ @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state
+ @observable _editTitle: boolean = false;
+ @observable _dref: DocumentView | undefined | null;
+ get displayName() { return "TreeView(" + this.props.document.title + ")"; } // this makes mobx trace() statements more descriptive
+ get treeViewLockExpandedView() { return this.doc.treeViewLockExpandedView; }
+ get defaultExpandedView() { return StrCast(this.doc.treeViewDefaultExpandedView, this.fileSysMode ? "data" : Doc.UserDoc().noviceMode || this.outlineMode ? "layout" : "fields"); }
+ get treeViewDefaultExpandedView() { return this.treeViewLockExpandedView ? this.defaultExpandedView : (this.childDocs && !this.fileSysMode ? this.fieldKey : this.defaultExpandedView); }
+
+ @computed get doc() { TraceMobx(); return this.props.document; }
@computed get outlineMode() { return this.props.treeView.doc.treeViewType === "outline"; }
@computed get fileSysMode() { return this.props.treeView.doc.treeViewType === "fileSystem"; }
@computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && !this.doc.treeViewPreventOpen && BoolCast(this.doc.treeViewOpen)) || this._overrideTreeViewOpen; }
@@ -109,6 +112,11 @@ export class TreeView extends React.Component<TreeViewProps> {
@computed get dataDoc() { return this.doc[DataSym]; }
@computed get layoutDoc() { return Doc.Layout(this.doc); }
@computed get fieldKey() { TraceMobx(); const splits = StrCast(Doc.LayoutField(this.doc)).split("fieldKey={\'"); return splits.length > 1 ? splits[1].split("\'")[0] : "data"; }
+ @computed get childDocs() { TraceMobx(); return this.childDocList(this.fieldKey); }
+ @computed get childLinks() { return this.childDocList("links"); }
+ @computed get childAnnos() { return this.childDocList(this.fieldKey + "-annotations"); }
+ @computed get selected() { return SelectionManager.Views().length && SelectionManager.Views()[0].props.Document === this.props.document; }
+
childDocList(field: string) {
if (this.fileSysMode && !this.doc.isFolder) return [] as Doc[];
const layout = Doc.LayoutField(this.doc) instanceof Doc ? Doc.LayoutField(this.doc) as Doc : undefined;
@@ -116,14 +124,6 @@ export class TreeView extends React.Component<TreeViewProps> {
(layout ? DocListCastOrNull(layout[field]) : undefined) || // else if there's a layout doc, display it's fields
DocListCastOrNull(this.doc[field])); // otherwise use the document's data field
}
- @computed get childDocs() { TraceMobx(); return this.childDocList(this.fieldKey); }
- @computed get childLinks() { return this.childDocList("links"); }
- @computed get childAnnos() { return this.childDocList(this.fieldKey + "-annotations"); }
- @computed get isCollectionDoc() {
- return !StrCast(this.props.document.type).includes(DocumentType.COL) || !DocListCast(this.props.document[this.fieldKey]).length ? false : true;
- }
-
- @undoBatch openRight = () => this.props.addDocTab(this.doc, "add:right");
@undoBatch move = (doc: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => {
return this.doc !== target && this.props.removeDoc?.(doc) === true && addDoc(doc);
}
@@ -134,17 +134,36 @@ export class TreeView extends React.Component<TreeViewProps> {
res && ind > 0 && DocumentManager.Instance.getDocumentView(this.dataDoc[key][ind - 1], this.props.treeView.props.CollectionView)?.select(false);
return res;
}
- @undoBatch @action removeDoc = (doc: Doc | Doc[]) => this.remove(doc, Doc.LayoutFieldKey(this.doc));
- selected = () => SelectionManager.Views().length && SelectionManager.Views()[0].props.Document === this.props.document;
+ @action setEditTitle = (docView?: DocumentView) => {
+ this._selDisposer?.();
+ if (!docView) {
+ this._editTitle = false;
+ }
+ else if (docView.isSelected()) {
+ this._editTitle = true;
+ this._selDisposer = reaction(() => docView.isSelected(), sel => !sel && this.setEditTitle(undefined));
+ } else {
+ docView.select(false);
+ }
+ }
+ @action
+ openLevel = (docView: DocumentView) => {
+ if (this.props.document.isFolder || Doc.IsSystem(this.props.document)) {
+ this.treeViewOpen = !this.treeViewOpen;
+ } else {
+ this.props.addDocTab(this.props.document, "add:right");
+ }
+ docView?.select(false);
+ }
constructor(props: any) {
super(props);
- const titleScript = ScriptField.MakeScript(`{scriptContext.selected() && setInPlace(self, 'editTitle', '${this._uniqueId}'); documentView.select();} `, { scriptContext: "any", documentView: "any" });
- const openScript = ScriptField.MakeScript(`self.isFolder? (scriptContext.treeViewOpen = !scriptContext.treeViewOpen) : openOnRight(self) && documentView.select()`, { scriptContext: "any", documentView: "any" });
- const treeOpenScript = ScriptField.MakeScript(`scriptContext.treeViewOpen = !scriptContext.treeViewOpen`, { scriptContext: "any" });
- this._editTitleScript = !Doc.IsSystem(this.props.document) || props.document.isFolder ? titleScript && (() => titleScript) : treeOpenScript && (() => treeOpenScript);
- this._openScript = !Doc.IsSystem(this.props.document) || props.document.isFolder ? openScript && (() => openScript) : undefined;
- if (Doc.GetT(this.props.document, "editTitle", "string", true) === "*") Doc.SetInPlace(this.props.document, "editTitle", this._uniqueId, false);
+ if (!TreeView._openLevelScript) {
+ TreeView._openTitleScript = ScriptField.MakeScript("scriptContext.setEditTitle(documentView)", { scriptContext: "any", documentView: "any" });
+ TreeView._openLevelScript = ScriptField.MakeScript(`scriptContext.openLevel(documentView)`, { scriptContext: "any", documentView: "any" });
+ }
+ this._openScript = Doc.IsSystem(this.props.document) ? undefined : () => TreeView._openLevelScript!;
+ this._editTitleScript = Doc.IsSystem(this.props.document) ? () => TreeView._openLevelScript! : () => TreeView._openTitleScript!;
}
protected createTreeDropTarget = (ele: HTMLDivElement) => {
@@ -153,6 +172,7 @@ export class TreeView extends React.Component<TreeViewProps> {
}
componentWillUnmount() {
+ this._selDisposer?.();
document.removeEventListener("pointermove", this.onDragMove, true);
document.removeEventListener("pointermove", this.onDragUp, true);
}
@@ -166,8 +186,8 @@ export class TreeView extends React.Component<TreeViewProps> {
if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
this._header!.current!.className = "treeView-header";
document.removeEventListener("pointermove", this.onDragMove, true);
- document.addEventListener("pointermove", this.onDragMove, true);
document.removeEventListener("pointerup", this.onDragUp, true);
+ document.addEventListener("pointermove", this.onDragMove, true);
document.addEventListener("pointerup", this.onDragUp, true);
}
}
@@ -201,63 +221,26 @@ export class TreeView extends React.Component<TreeViewProps> {
});
Doc.GetProto(bullet).title = ComputedField.MakeFunction('self.text?.Text');
Doc.GetProto(bullet).data = new List<Doc>([]);
- Doc.SetInPlace(bullet, "editTitle", "*", false);
FormattedTextBox.SelectOnLoad = bullet[Id];
return bullet;
}
makeTextCollection = () => {
- Doc.SetInPlace(this.doc, "editTitle", undefined, false);
const bullet = TreeView.makeTextBullet();
const added = this.props.addDocument(bullet);
+ TreeView._editTitleOnLoad = { id: bullet[Id], parent: this };
bullet.context = this.props.treeView.Document;
return added;
}
makeFolder = () => {
- Doc.SetInPlace(this.doc, "editTitle", undefined, false);
- const folder = Docs.Create.TreeDocument([], { title: "-folder-", _stayInCollection: true, isFolder: true, system: true });
+ const folder = Docs.Create.TreeDocument([], { title: "-folder-", _stayInCollection: true, isFolder: true });
const added = this.props.addDocument(folder);
folder.context = this.props.treeView.Document;
+ TreeView._editTitleOnLoad = { id: folder[Id], parent: this.props.parentTreeView };
return added;
}
- editableView = (key: string, style?: string) => (<EditableView
- oneLine={true}
- display={"inline-block"}
- editing={true}
- contents={StrCast(this.doc[key])}
- height={12}
- sizeToContent={true}
- fontStyle={style}
- fontSize={12}
- GetValue={() => StrCast(this.doc[key])}
- OnFillDown={(value) => {
- if (this.fileSysMode) {
- this.makeFolder();
- }
- }}
- SetValue={undoBatch((value: string, shiftKey: boolean, enterKey: boolean) => {
- Doc.SetInPlace(this.doc, key, value, false);
- if (this.outlineMode && enterKey) {
- this.makeTextCollection();
- } else if (this.fileSysMode && enterKey) {
- // add folder
- } else {
- Doc.SetInPlace(this.doc, "editTitle", undefined, false);
- }
- })}
- onClick={() => {
- SelectionManager.DeselectAll();
- return false;
- }}
- OnEmpty={undoBatch(() => this.outlineMode && this.props.removeDoc?.(this.doc))}
- OnTab={undoBatch((shift?: boolean) => {
- shift ? this.props.outdentDocument?.() : this.props.indentDocument?.();
- setTimeout(() => Doc.SetInPlace(this.doc, "editTitle", `${this.props.treeView._uniqueId}`, false), 0);
- })}
- />)
-
preTreeDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
const dragData = de.complete.docDragData;
dragData && (dragData.dropAction = this.props.treeView.props.Document === dragData.treeViewDoc ? "same" : dragData.dropAction);
@@ -351,7 +334,7 @@ export class TreeView extends React.Component<TreeViewProps> {
this.props.treeView, doc, undefined, key, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.titleStyleProvider, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active,
this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
- [...this.props.renderedIds, doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView);
+ [...this.props.renderedIds, doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView, this);
} else {
contentElement = <EditableView key="editableView"
contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
@@ -419,19 +402,21 @@ export class TreeView extends React.Component<TreeViewProps> {
const docs = expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs;
const sortKey = `${this.fieldKey}-sortCriteria`;
return <ul key={expandKey + "more"} className={this.doc.treeViewHideTitle ? "no-indent" : ""} onClick={(e) => {
- !this.outlineMode && (this.doc[sortKey] =
- (this.doc[sortKey] === "ascending" ? "descending" :
- (this.doc[sortKey] === "descending" ? "zorder" :
- (this.doc[sortKey] === "zorder" ? undefined :
- "ascending"))));
- e.stopPropagation();
+ if (this.props.active()) {
+ !this.outlineMode && (this.doc[sortKey] =
+ (this.doc[sortKey] === "ascending" ? "descending" :
+ (this.doc[sortKey] === "descending" ? "zorder" :
+ (this.doc[sortKey] === "zorder" ? undefined :
+ "ascending"))));
+ e.stopPropagation();
+ }
}}>
{!docs ? (null) :
TreeView.GetChildElements(docs, this.props.treeView, this.layoutDoc,
this.dataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.props.pinToPres, this.titleStyleProvider, this.props.ScreenToLocalTransform,
this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
- [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView)}
+ [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView, this)}
</ul >;
} else if (this.treeViewExpandedView === "fields") {
return <ul key={this.doc[Id] + this.doc.title}>
@@ -488,7 +473,6 @@ export class TreeView extends React.Component<TreeViewProps> {
}
</div>;
}
- @computed get showTitleEditorControl() { return ["*", this._uniqueId, this.props.treeView._uniqueId].includes(Doc.GetT(this.doc, "editTitle", "string", true) || ""); }
@computed get headerElements() {
return (Doc.IsSystem(this.doc) && Doc.UserDoc().noviceMode) || this.props.treeViewHideHeaderFields() ? (null) :
<>
@@ -512,7 +496,7 @@ export class TreeView extends React.Component<TreeViewProps> {
</>;
}
- showContextMenu = (e: React.MouseEvent) => simulateMouseClick(this._docRef.current?.ContentDiv, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
+ showContextMenu = (e: React.MouseEvent) => simulateMouseClick(this._docRef?.ContentDiv, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
contextMenuItems = () => this.doc.isFolder ? [{ script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: "any" })!, label: "New Folder" }] : Doc.IsSystem(this.doc) ? [] : [{ script: ScriptField.MakeFunction(`openOnRight(self)`)!, label: "Open" }, { script: ScriptField.MakeFunction(`DocFocus(self)`)!, label: "Focus" }];
truncateTitleWidth = () => NumCast(this.props.treeView.props.Document.treeViewTruncateTitleWidth, this.props.panelWidth());
onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick));
@@ -530,7 +514,7 @@ export class TreeView extends React.Component<TreeViewProps> {
switch (property.split(":")[0]) {
case StyleProp.Opacity: return this.outlineMode ? undefined : 1;
- case StyleProp.BackgroundColor: return this.selected() ? "#7089bb" : StrCast(doc._backgroundColor, StrCast(doc.backgroundColor));
+ case StyleProp.BackgroundColor: return this.selected ? "#7089bb" : StrCast(doc._backgroundColor, StrCast(doc.backgroundColor));
case StyleProp.DocContents: return testDocProps(props) && !props?.treeViewDoc ? (null) :
<div className="treeView-label" style={{ // just render a title for a tree view label (identified by treeViewDoc being set in 'props')
maxWidth: props?.PanelWidth() || undefined,
@@ -551,7 +535,7 @@ export class TreeView extends React.Component<TreeViewProps> {
e.preventDefault();
switch (e.key) {
case "Tab": setTimeout(() => RichTextMenu.Instance.TextView?.EditorView?.focus(), 150);
- return UndoManager.RunInBatch(() => e.shiftKey ? this.props.outdentDocument?.() : this.props.indentDocument?.(), "tab");
+ return UndoManager.RunInBatch(() => e.shiftKey ? this.props.outdentDocument?.(true) : this.props.indentDocument?.(true), "tab");
case "Backspace": return !(this.doc.text as RichTextField)?.Text && this.props.removeDoc?.(this.doc);
case "Enter": return UndoManager.RunInBatch(this.makeTextCollection, "bullet");
}
@@ -564,9 +548,35 @@ export class TreeView extends React.Component<TreeViewProps> {
@computed
get renderTitle() {
TraceMobx();
- const view = this.showTitleEditorControl ? this.editableView("title") :
- <DocumentView key="title"
- ref={this._docRef}
+ const view = this._editTitle ? <EditableView key="_editTitle"
+ oneLine={true}
+ display={"inline-block"}
+ editing={true}
+ contents={StrCast(this.doc.title)}
+ height={12}
+ sizeToContent={true}
+ fontSize={12}
+ GetValue={() => StrCast(this.doc.title)}
+ OnTab={undoBatch((shift?: boolean) => {
+ if (!shift) this.props.indentDocument?.(true);
+ else this.props.outdentDocument?.(true);
+ })}
+ OnEmpty={undoBatch(() => this.outlineMode && this.props.removeDoc?.(this.doc))}
+ OnFillDown={val => this.fileSysMode && this.makeFolder()}
+ SetValue={undoBatch((value: string, shiftKey: boolean, enterKey: boolean) => {
+ Doc.SetInPlace(this.doc, "title", value, false);
+ this.outlineMode && enterKey && this.makeTextCollection();
+ })}
+ />
+ : <DocumentView key="title"
+ ref={action((r: any) => {
+ this._docRef = r ? r : undefined;
+ if (this._docRef && TreeView._editTitleOnLoad?.id === this.props.document[Id] && TreeView._editTitleOnLoad.parent == this.props.parentTreeView) {
+ this._docRef.select(false);
+ this.setEditTitle(this._docRef);
+ TreeView._editTitleOnLoad = undefined;
+ }
+ })}
Document={this.doc}
DataDoc={undefined}
scriptContext={this}
@@ -602,8 +612,9 @@ export class TreeView extends React.Component<TreeViewProps> {
ContainingCollectionView={undefined}
ContainingCollectionDoc={this.props.treeView.props.Document}
/>;
+
return <>
- <div className={`docContainer${Doc.IsSystem(this.props.document) ? "-system" : ""}`} ref={this._tref} title="click to edit title. Double Click or Drag to Open"
+ <div className={`docContainer${Doc.IsSystem(this.props.document) || this.props.document.isFolder ? "-system" : ""}`} ref={this._tref} title="click to edit title. Double Click or Drag to Open"
style={{
fontWeight: Doc.IsSearchMatch(this.doc) !== undefined ? "bold" : undefined,
textDecoration: Doc.GetT(this.doc, "title", "string", true) ? "underline" : undefined,
@@ -700,12 +711,12 @@ export class TreeView extends React.Component<TreeViewProps> {
render() {
TraceMobx();
if (this.props.renderedIds.indexOf(this.doc[Id]) !== -1) return "<" + this.doc.title + ">";
- if (this.showTitleEditorControl) { // find containing CollectionTreeView and set our maximum width so the containing tree view won't have to scroll
+ if (this._editTitle) { // find containing CollectionTreeView and set our maximum width so the containing tree view won't have to scroll
let par: any = this._header?.current;
while (par && par.className !== "collectionTreeView-dropTarget") par = par.parentNode;
if (par) {
const par_rect = (par as HTMLElement).getBoundingClientRect();
- const my_recct = this._docRef.current?.ContentDiv?.getBoundingClientRect();
+ const my_recct = this._docRef?.ContentDiv?.getBoundingClientRect();
this._editMaxWidth = Math.max(100, par_rect.right - (my_recct?.left || 0));
}
}
@@ -780,59 +791,50 @@ export class TreeView extends React.Component<TreeViewProps> {
skipFields: string[] | undefined,
firstLevel: boolean,
whenActiveChanged: (isActive: boolean) => void,
- dontRegisterView: boolean | undefined) {
+ dontRegisterView: boolean | undefined,
+ parentTreeView: CollectionTreeView | TreeView | undefined
+ ) {
const viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField);
if (viewSpecScript) {
childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result);
}
const docs = TreeView.sortDocs(childDocs, StrCast(containingCollection?.[key + "-sortCriteria"]));
-
const rowWidth = () => panelWidth() - treeBulletWidth();
+ const treeViewRefs = new Map<Doc, TreeView | undefined>();
return docs.filter(child => child instanceof Doc).map((child, i) => {
const pair = Doc.GetLayoutDataDocPair(containingCollection, dataDoc, child);
if (!pair.layout || pair.data instanceof Promise) {
return (null);
}
- const indent = i === 0 ? undefined : () => {
- if (remove && StrCast(docs[i - 1].layout).indexOf('fieldKey') !== -1) {
- const fieldKeysub = StrCast(docs[i - 1].layout).split('fieldKey')[1];
- const fieldKey = fieldKeysub.split("\'")[1];
- if (fieldKey && Cast(docs[i - 1][fieldKey], listSpec(Doc)) !== undefined) {
- remove(child);
- FormattedTextBox.SelectOnLoad = child[Id];
- Doc.AddDocToList(docs[i - 1], fieldKey, child);
- docs[i - 1].treeViewOpen = true;
- child.context = treeView.Document;
- }
- }
- };
- const outdent = !parentCollectionDoc ? undefined : () => {
- if (parentCollectionDoc._viewType === CollectionViewType.Tree && remove && StrCast(parentCollectionDoc.layout).indexOf('fieldKey') !== -1) {
- const fieldKeysub = StrCast(parentCollectionDoc.layout).split('fieldKey')[1];
- const fieldKey = fieldKeysub.split("\'")[1];
+ const dentDoc = (editTitle: boolean, newParent: Doc, addAfter: Doc | undefined, parent: TreeView | CollectionTreeView | undefined) => {
+ const fieldKey = Doc.LayoutFieldKey(newParent);
+ if (remove && fieldKey && Cast(newParent[fieldKey], listSpec(Doc)) !== undefined) {
remove(child);
FormattedTextBox.SelectOnLoad = child[Id];
- Doc.AddDocToList(parentCollectionDoc, fieldKey, child, parentPrevSibling, false);
- parentCollectionDoc.treeViewOpen = true;
+ TreeView._editTitleOnLoad = editTitle ? { id: child[Id], parent } : undefined;
+ Doc.AddDocToList(newParent, fieldKey, child, addAfter, false);
+ newParent.treeViewOpen = true;
child.context = treeView.Document;
}
- };
+ }
+ const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1]));
+ const outdent = parentCollectionDoc?._viewType !== CollectionViewType.Tree ? undefined : ((editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, parentPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined));
const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false);
const childLayout = Doc.Layout(pair.layout);
const rowHeight = () => {
const aspect = Doc.NativeAspect(childLayout);
return aspect ? Math.min(childLayout[WidthSym](), rowWidth()) / aspect : childLayout[HeightSym]();
};
- return <TreeView key={child[Id]}
+ return <TreeView key={child[Id]} ref={r => treeViewRefs.set(child, r ? r : undefined)}
document={pair.layout}
dataDoc={pair.data}
containingCollection={containingCollection}
prevSibling={docs[i]}
treeView={treeView}
indentDocument={indent}
- outdentDocument={!parentCollectionDoc ? undefined : outdent}
+ outdentDocument={outdent}
onCheckedClick={onCheckedClick}
onChildClick={onChildClick}
renderDepth={renderDepth}
@@ -855,7 +857,8 @@ export class TreeView extends React.Component<TreeViewProps> {
renderedIds={renderedIds}
skipFields={skipFields}
firstLevel={firstLevel}
- whenActiveChanged={whenActiveChanged} />;
+ whenActiveChanged={whenActiveChanged}
+ parentTreeView={parentTreeView} />;
});
}
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index f5a60effe..36d14056b 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -134,7 +134,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
e.stopPropagation();
} else if (e.key === "f" && e.ctrlKey) {
e.preventDefault();
- const root = Docs.Create.FreeformDocument([], { title: "folder", _stayInCollection: true, system: true, isFolder: true });
+ const root = Docs.Create.TreeDocument([], { title: "folder", _stayInCollection: true, isFolder: true });
const folder = Docs.Create.TreeDocument([root], { title: "root", isFolder: true, treeViewType: "fileSystem", treeViewTruncateTitleWidth: 150 });
Doc.GetProto(folder).isFolder = true;
folder.x = x;
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 8a90d5d62..18cabc309 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -94,7 +94,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
const rootAlias = Doc.MakeAlias(rootDoc);
rootAlias.x = rootAlias.y = 0;
return rootAlias;
- }
+ };
let wid = rootDoc[WidthSym]();
const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([rootAlias()], { title: this.props.View.Document.title + "-pivot", _width: 500, _height: 500, }, docid);
const docs = await DocListCastAsync(Doc.GetProto(target).data);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 161469e24..f99eb1b3b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -448,7 +448,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
shiftKey: e.shiftKey
}, console.log);
UndoManager.RunInBatch(() => func().result?.select === true ? this.props.select(false) : "", "on double click");
- } else if (!Doc.IsSystem(this.props.Document)) {
+ } else if (!Doc.IsSystem(this.rootDoc)) {
if (this.props.Document.type !== DocumentType.LABEL) {
UndoManager.RunInBatch(() => this.props.addDocTab((this.rootDoc._fullScreenView as Doc) || this.rootDoc, "lightbox"), "double tap");
SelectionManager.DeselectAll();
@@ -731,7 +731,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
}
- if (this.props.removeDocument && !this.props.Document._stayInCollection && CurrentUserUtils.ActiveDashboard !== this.props.Document) { // need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions)
+ if (this.props.removeDocument && !Doc.IsSystem(this.rootDoc) && CurrentUserUtils.ActiveDashboard !== this.props.Document) { // need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions)
moreItems.push({ description: "Close", event: this.deleteClicked, icon: "times" });
}