aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/TreeView.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections/TreeView.tsx')
-rw-r--r--src/client/views/collections/TreeView.tsx259
1 files changed, 152 insertions, 107 deletions
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index cb521ea75..93d3be1fc 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1,6 +1,7 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, trace } from "mobx";
+import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
+import { TREE_BULLET_WIDTH } from '../globalCssVariables.scss';
import { DataSym, Doc, DocListCast, DocListCastOrNull, Field, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
@@ -9,7 +10,7 @@ import { listSpec } from '../../../fields/Schema';
import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
import { DocumentType } from "../../documents/DocumentTypes";
import { CurrentUserUtils } from '../../util/CurrentUserUtils';
@@ -20,11 +21,12 @@ import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { undoBatch, UndoManager } from '../../util/UndoManager';
import { EditableView } from "../EditableView";
-import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView';
-import { DocumentView } from '../nodes/DocumentView';
+import { DocumentView, DocumentViewProps, StyleProviderFunc } from '../nodes/DocumentView';
+import { FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
import { KeyValueBox } from '../nodes/KeyValueBox';
+import { StyleProp, testDocProps } from '../StyleProvider';
import { CollectionTreeView } from './CollectionTreeView';
import { CollectionView, CollectionViewType } from './CollectionView';
import "./TreeView.scss";
@@ -39,17 +41,16 @@ export interface TreeViewProps {
removeDoc: ((doc: Doc | Doc[]) => boolean) | undefined;
moveDocument: DragManager.MoveFunction;
dropAction: dropActionType;
- addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean;
+ addDocTab: (doc: Doc, where: string) => boolean;
pinToPres: (document: Doc) => void;
panelWidth: () => number;
panelHeight: () => number;
- ChromeHeight: undefined | (() => number);
addDocument: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean;
indentDocument?: () => void;
outdentDocument?: () => void;
ScreenToLocalTransform: () => Transform;
dontRegisterView?: boolean;
- backgroundColor?: (doc: Opt<Doc>, renderDepth: number, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => string | undefined;
+ styleProvider?: StyleProviderFunc | undefined;
outerXf: () => { translateX: number, translateY: number };
treeView: CollectionTreeView;
parentKey: string;
@@ -59,11 +60,13 @@ export interface TreeViewProps {
renderedIds: string[]; // list of document ids rendered used to avoid unending expansion of items in a cycle
onCheckedClick?: () => ScriptField;
onChildClick?: () => ScriptField;
- ignoreFields?: string[];
+ skipFields?: string[];
firstLevel: boolean;
whenActiveChanged: (isActive: boolean) => void;
}
+const treeBulletWidth = function () { return Number(TREE_BULLET_WIDTH.replace("px", "")); };
+
@observer
/**
* Renders a treeView of a collection of documents
@@ -83,7 +86,8 @@ export class TreeView extends React.Component<TreeViewProps> {
private _uniqueId = Utils.GenerateGuid();
private _editMaxWidth: number | string = 0;
- @observable _dref: ContentFittingDocumentView | undefined | null;
+
+ @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
@@ -284,9 +288,9 @@ export class TreeView extends React.Component<TreeViewProps> {
docWidth = () => {
const layoutDoc = this.layoutDoc;
const aspect = Doc.NativeAspect(layoutDoc);
- if (layoutDoc._fitWidth) return Math.min(this.props.panelWidth() - 20, layoutDoc[WidthSym]());
- if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.panelWidth() - 20));
- return Doc.NativeWidth(layoutDoc) ? Math.min(layoutDoc[WidthSym](), this.props.panelWidth() - 20) : Math.min(this.layoutDoc[WidthSym](), this.props.panelWidth() - 20);
+ if (layoutDoc._fitWidth) return Math.min(this.props.panelWidth() - treeBulletWidth(), layoutDoc[WidthSym]());
+ if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.panelWidth() - treeBulletWidth()));
+ return Math.min(this.props.panelWidth() - treeBulletWidth(), Doc.NativeWidth(layoutDoc) ? layoutDoc[WidthSym]() : this.layoutDoc[WidthSym]());
}
docHeight = () => {
const layoutDoc = this.layoutDoc;
@@ -311,7 +315,7 @@ export class TreeView extends React.Component<TreeViewProps> {
doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
for (const key of Object.keys(ids).slice().sort()) {
- if (this.props.ignoreFields?.includes(key) || key === "title" || key === "treeViewOpen") continue;
+ if (this.props.skipFields?.includes(key) || key === "title" || key === "treeViewOpen") continue;
const contents = doc[key];
let contentElement: (JSX.Element | null)[] | JSX.Element = [];
@@ -325,9 +329,9 @@ export class TreeView extends React.Component<TreeViewProps> {
const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true);
contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] : DocListCast(contents),
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.props.backgroundColor, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active,
- this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
- [...this.props.renderedIds, doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.ignoreFields, false, this.props.whenActiveChanged, this.props.dontRegisterView);
+ 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);
} else {
contentElement = <EditableView key="editableView"
contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
@@ -354,9 +358,9 @@ export class TreeView extends React.Component<TreeViewProps> {
return rows;
}
- rtfWidth = () => Math.min(this.layoutDoc?.[WidthSym](), this.props.panelWidth() - 20);
+ rtfWidth = () => Math.min(this.layoutDoc?.[WidthSym](), this.props.panelWidth() - treeBulletWidth());
rtfHeight = () => this.rtfWidth() <= this.layoutDoc?.[WidthSym]() ? Math.min(this.layoutDoc?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
- rtfOutlineHeight = () => Math.max(this.layoutDoc?.[HeightSym](), 20);
+ rtfOutlineHeight = () => Math.max(this.layoutDoc?.[HeightSym](), treeBulletWidth());
expandPanelHeight = () => {
if (this.layoutDoc._fitWidth) return this.docHeight();
const aspect = this.layoutDoc[WidthSym]() / this.layoutDoc[HeightSym]();
@@ -376,31 +380,46 @@ export class TreeView extends React.Component<TreeViewProps> {
if (["links", "annotations", this.fieldKey].includes(expandKey)) {
const remDoc = (doc: Doc | Doc[]) => this.remove(doc, expandKey);
const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => {
+ // if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't),
+ // then the modification would be done here
+ const ordering = StrCast(this.doc[this.fieldKey + "-sortCriteria"]);
+ if (ordering === "zorder") {
+ const docs = TreeView.sortDocs(this.childDocs || ([] as Doc[]), ordering);
+ doc.zIndex = addBefore ? (before ? NumCast(addBefore.zIndex) - 0.5 : NumCast(addBefore.zIndex) + 0.5) : 1000;
+ docs.push(doc);
+ docs.sort((a, b) => NumCast(a.zIndex) > NumCast(b.zIndex) ? 1 : -1);
+ docs.forEach((d, i) => d.zIndex = i);
+ }
const added = Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true);
added && (doc.context = this.doc.context);
return added;
};
const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true);
const docs = expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs;
- const sortKey = `${this.fieldKey}-sortAscending`;
+ 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] ? false : (this.doc[sortKey] === false ? undefined : true)));
+ !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.props.backgroundColor, this.props.ScreenToLocalTransform,
- this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
- [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.ignoreFields, false, this.props.whenActiveChanged, this.props.dontRegisterView)}
+ 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)}
</ul >;
} else if (this.treeViewExpandedView === "fields") {
- return <ul key={this.doc[Id] + this.doc.title}><div style={{ display: "inline-block" }} >
- {this.expandedField}
- </div></ul>;
- } else {
- return this.renderDocument(false);
+ return <ul key={this.doc[Id] + this.doc.title}>
+ <div style={{ display: "inline-block" }} >
+ {this.expandedField}
+ </div>
+ </ul>;
}
+ return <ul>{this.renderEmbeddedDocument(false)}</ul>;
}
get onCheckedClick() { return this.doc.type === DocumentType.COL ? undefined : this.props.onCheckedClick?.() ?? ScriptCast(this.doc.onCheckedClick); }
@@ -422,20 +441,29 @@ export class TreeView extends React.Component<TreeViewProps> {
@computed get renderBullet() {
TraceMobx();
+ const iconType = Doc.toIcon(this.doc);
const checked = this.onCheckedClick ? (this.doc.treeViewChecked ?? "unchecked") : undefined;
return <div className={`bullet${this.outlineMode ? "-outline" : ""}`} key={"bullet"}
title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
onClick={this.bulletClick}
- style={this.outlineMode ? { opacity: NumCast(this.doc.opacity, 1) } : {
+ style={this.outlineMode ? { opacity: this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.Opacity) } : {
color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"),
opacity: checked === "unchecked" ? undefined : 0.4
}}>
- {this.outlineMode && !(this.doc.text as RichTextField)?.Text ? (null) :
- <FontAwesomeIcon icon={this.outlineMode ? [this.childDocs?.length && !this.treeViewOpen ? "fas" : "far", "circle"] :
- checked === "check" ? "check" :
- (checked === "x" ? "times" : checked === "unchecked" ? "square" :
- !this.treeViewOpen ? (this.childDocs?.length ? "caret-square-right" : "caret-right") :
- (this.childDocs?.length ? "caret-square-down" : "caret-down"))} />}
+ {this.outlineMode ?
+ !(this.doc.text as RichTextField)?.Text ? (null) :
+ <FontAwesomeIcon size="sm" icon={[this.childDocs?.length && !this.treeViewOpen ? "fas" : "far", "circle"]} /> :
+ <div className="treeView-bulletIcons" >
+ <div className={`treeView-${this.onCheckedClick ? "checkIcon" : "expandIcon"}`}>
+ <FontAwesomeIcon size="sm" icon={
+ checked === "check" ? "check" :
+ (checked === "x" ? "times" : checked === "unchecked" ? "square" :
+ !this.treeViewOpen ? "caret-right" :
+ "caret-down")} />
+ </div>
+ {this.onCheckedClick ? (null) : <FontAwesomeIcon icon={iconType} />}
+ </div>
+ }
</div>;
}
@computed get showTitleEditorControl() { return ["*", this._uniqueId, this.props.treeView._uniqueId].includes(Doc.GetT(this.doc, "editTitle", "string", true) || ""); }
@@ -462,7 +490,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);
contextMenuItems = () => 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, 0);
+ truncateTitleWidth = () => NumCast(this.props.treeView.props.Document.treeViewTruncateTitleWidth, this.props.panelWidth());
onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick));
onChildDoubleClick = () => (!this.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick);
@@ -473,6 +501,26 @@ export class TreeView extends React.Component<TreeViewProps> {
e.preventDefault();
}
}
+ titleStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps | FieldViewProps>, property: string): any => {
+ if (!doc || doc !== this.doc) return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
+
+ switch (property.split(":")[0]) {
+ case StyleProp.Opacity: return this.outlineMode ? undefined : 1;
+ case StyleProp.BackgroundColor: return 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,
+ background: props?.styleProvider?.(doc, props, StyleProp.BackgroundColor),
+ }}>
+ {StrCast(doc?.title)}
+ </div>;
+ case StyleProp.Decorations: return (null);
+ }
+ }
+ embeddedStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps | FieldViewProps>, property: string): any => {
+ if (property.startsWith(StyleProp.Decorations)) return (null);
+ return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView
+ }
onKeyDown = (e: React.KeyboardEvent) => {
if (this.doc.treeViewHideHeader || this.outlineMode) {
e.stopPropagation();
@@ -497,8 +545,8 @@ export class TreeView extends React.Component<TreeViewProps> {
ref={this._docRef}
Document={this.doc}
DataDoc={undefined}
+ styleProvider={this.titleStyleProvider}
treeViewDoc={this.props.treeView.props.Document}
- LibraryPath={emptyPath}
addDocument={undefined}
addDocTab={this.props.addDocTab}
rootSelected={returnTrue}
@@ -509,11 +557,11 @@ export class TreeView extends React.Component<TreeViewProps> {
moveDocument={this.move}
removeDocument={this.props.removeDoc}
ScreenToLocalTransform={this.getTransform}
- ContentScaling={returnOne}
+ NativeHeight={returnZero}
+ NativeWidth={returnZero}
PanelWidth={this.truncateTitleWidth}
- PanelHeight={returnZero}
+ PanelHeight={() => 18}
contextMenuItems={this.contextMenuItems}
- opacity={this.outlineMode ? undefined : returnOne}
renderDepth={1}
focus={returnTrue}
parentActive={returnTrue}
@@ -524,7 +572,7 @@ export class TreeView extends React.Component<TreeViewProps> {
docRangeFilters={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
ContainingCollectionView={undefined}
- ContainingCollectionDoc={this.props.containingCollection}
+ 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"
@@ -541,15 +589,18 @@ export class TreeView extends React.Component<TreeViewProps> {
}
renderBulletHeader = (contents: JSX.Element) => {
- return <div className={`treeView-header` + (this._editMaxWidth ? "-editing" : "")} key="titleheader"
- ref={this._header}
- style={{ maxWidth: this._editMaxWidth }}
- onClick={this.ignoreEvent}
- onPointerDown={this.ignoreEvent}
- onPointerEnter={this.onPointerEnter}
- onPointerLeave={this.onPointerLeave}>
- {contents}
- </div>;
+ return <>
+ <div className={`treeView-header` + (this._editMaxWidth ? "-editing" : "")} key="titleheader"
+ ref={this._header}
+ style={{ maxWidth: this._editMaxWidth }}
+ onClick={this.ignoreEvent}
+ onPointerDown={this.ignoreEvent}
+ onPointerEnter={this.onPointerEnter}
+ onPointerLeave={this.onPointerLeave}>
+ {contents}
+ </div>
+ {this.renderBorder}
+ </>;
}
// renders the text version of a document as the header (e.g., useful for Slide views where the "")
@@ -560,26 +611,25 @@ export class TreeView extends React.Component<TreeViewProps> {
</>;
}
- renderDocument = (asText: boolean) => {
+ renderEmbeddedDocument = (asText: boolean) => {
const panelWidth = asText || StrCast(Doc.LayoutField(this.layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : this.expandPanelWidth;
const panelHeight = asText ? this.rtfOutlineHeight : StrCast(Doc.LayoutField(this.layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : this.expandPanelHeight;
- return <ContentFittingDocumentView key={this.doc[Id]} ref={action((r: ContentFittingDocumentView | null) => this._dref = r)}
+ return <DocumentView key={this.doc[Id]} ref={action((r: DocumentView | null) => this._dref = r)}
Document={this.doc}
DataDoc={undefined}
PanelWidth={panelWidth}
PanelHeight={panelHeight}
NativeWidth={!asText && this.layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined}
NativeHeight={!asText && this.layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined}
- fitToBox={!asText && this.isCollectionDoc !== undefined}
+ fitContentsToDoc={true}
+ hideTitle={asText}
LayoutTemplateString={asText ? FormattedTextBox.LayoutString("text") : undefined}
focus={asText ? this.refocus : returnFalse}
dontRegisterView={asText ? undefined : this.props.dontRegisterView}
ScreenToLocalTransform={this.docTransform}
- LibraryPath={emptyPath}
renderDepth={this.props.renderDepth + 1}
rootSelected={returnTrue}
- treeViewDoc={undefined}
- styleProvider={this.props.backgroundColor}
+ styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
docFilters={returnEmptyFilter}
docRangeFilters={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
@@ -593,21 +643,20 @@ export class TreeView extends React.Component<TreeViewProps> {
addDocTab={this.props.addDocTab}
pinToPres={this.props.pinToPres}
bringToFront={returnFalse}
- ContentScaling={returnOne}
/>;
}
@computed get renderDocumentAsHeader() {
return <>
{this.renderBullet}
- {this.renderDocument(true)}
+ {this.renderEmbeddedDocument(true)}
</>;
}
@computed get renderBorder() {
- const sorting = this.doc[`${this.fieldKey}-sortAscending`];
+ const sorting = this.doc[`${this.fieldKey}-sortCriteria`];
return <div className={`treeView-border${this.outlineMode ? "outline" : ""}`}
- style={{ borderColor: sorting === undefined ? undefined : sorting ? "crimson" : "blue" }}>
+ style={{ borderColor: sorting === undefined ? undefined : sorting === "ascending" ? "crimson" : sorting === "descending" ? "blue" : "green" }}>
{!this.treeViewOpen ? (null) : this.renderContent}
</div>;
}
@@ -627,24 +676,44 @@ export class TreeView extends React.Component<TreeViewProps> {
else this._editMaxWidth = "";
const hideTitle = this.doc.treeViewHideHeader || this.outlineMode;
- return hideTitle && !StrCast(Doc.LayoutField(this.doc)).includes("CollectionView") ?
- this.renderContent
- :
- <div className={`treeView-container${this._dref?.docView?.contentsActive() ? "-active" : ""}`}
- ref={this.createTreeDropTarget}
- onPointerDown={e => this.props.active(true) && SelectionManager.DeselectAll()}
- onKeyDown={this.onKeyDown}>
- {hideTitle ?
- <li className="collection-child">
- {this.renderBulletHeader(this.renderDocumentAsHeader)}
- {this.renderBorder}
- </li> :
- <li className="collection-child">
- {this.renderBulletHeader(this.renderTitleAsHeader)}
- {this.renderBorder}
- </li>
+ return <div className={`treeView-container${this._dref?.contentsActive() ? "-active" : ""}`}
+ ref={this.createTreeDropTarget}
+ onPointerDown={e => this.props.active(true) && SelectionManager.DeselectAll()}
+ onKeyDown={this.onKeyDown}>
+ <li className="collection-child">
+ {hideTitle && this.doc.type !== DocumentType.RTF ?
+ this.renderEmbeddedDocument(false) :
+ this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader : this.renderTitleAsHeader)}
+ </li>
+ </div>;
+ }
+
+ public static sortDocs(childDocs: Doc[], criterion: string | undefined) {
+ const docs = childDocs.slice();
+ if (criterion) {
+ const sortAlphaNum = (a: string, b: string): 0 | 1 | -1 => {
+ const reN = /[0-9]*$/;
+ const aA = a.replace(reN, ""); // get rid of trailing numbers
+ const bA = b.replace(reN, "");
+ if (aA === bA) { // if header string matches, then compare numbers numerically
+ const aN = parseInt(a.match(reN)![0], 10);
+ const bN = parseInt(b.match(reN)![0], 10);
+ return aN === bN ? 0 : aN > bN ? 1 : -1;
+ } else {
+ return aA > bA ? 1 : -1;
}
- </div>;
+ };
+ docs.sort(function (d1, d2): 0 | 1 | -1 {
+ const a = (criterion === "ascending" ? d2 : d1);
+ const b = (criterion === "ascending" ? d1 : d2);
+ const first = a[criterion === "zorder" ? "zIndex" : "title"];
+ const second = b[criterion === "zorder" ? "zIndex" : "title"];
+ if (typeof first === 'number' && typeof second === 'number') return (first - second) > 0 ? 1 : -1;
+ if (typeof first === 'string' && typeof second === 'string') return sortAlphaNum(first, second);
+ return criterion ? 1 : -1;
+ });
+ }
+ return docs;
}
public static GetChildElements(
@@ -661,19 +730,18 @@ export class TreeView extends React.Component<TreeViewProps> {
dropAction: dropActionType,
addDocTab: (doc: Doc, where: string) => boolean,
pinToPres: (document: Doc) => void,
- backgroundColor: undefined | ((document: Opt<Doc>, renderDepth: number, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => string | undefined),
+ styleProvider: undefined | StyleProviderFunc,
screenToLocalXf: () => Transform,
outerXf: () => { translateX: number, translateY: number },
active: (outsideReaction?: boolean) => boolean,
panelWidth: () => number,
- ChromeHeight: undefined | (() => number),
renderDepth: number,
treeViewHideHeaderFields: () => boolean,
treeViewPreventOpen: boolean,
renderedIds: string[],
onCheckedClick: undefined | (() => ScriptField),
onChildClick: undefined | (() => ScriptField),
- ignoreFields: string[] | undefined,
+ skipFields: string[] | undefined,
firstLevel: boolean,
whenActiveChanged: (isActive: boolean) => void,
dontRegisterView: boolean | undefined) {
@@ -682,31 +750,9 @@ export class TreeView extends React.Component<TreeViewProps> {
childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result);
}
- const docs = childDocs.slice();
- const ascending = containingCollection?.[key + "-sortAscending"];
- if (ascending !== undefined) {
- const sortAlphaNum = (a: string, b: string): 0 | 1 | -1 => {
- const reN = /[0-9]*$/;
- const aA = a.replace(reN, ""); // get rid of trailing numbers
- const bA = b.replace(reN, "");
- if (aA === bA) { // if header string matches, then compare numbers numerically
- const aN = parseInt(a.match(reN)![0], 10);
- const bN = parseInt(b.match(reN)![0], 10);
- return aN === bN ? 0 : aN > bN ? 1 : -1;
- } else {
- return aA > bA ? 1 : -1;
- }
- };
- docs.sort(function (a, b): 0 | 1 | -1 {
- const first = (ascending ? b : a).title;
- const second = (ascending ? a : b).title;
- if (typeof first === 'number' && typeof second === 'number') return (first - second) > 0 ? 1 : -1;
- if (typeof first === 'string' && typeof second === 'string') return sortAlphaNum(first, second);
- return ascending ? 1 : -1;
- });
- }
+ const docs = TreeView.sortDocs(childDocs, StrCast(containingCollection?.[key + "-sortCriteria"]));
- const rowWidth = () => panelWidth() - 20;
+ const rowWidth = () => panelWidth() - treeBulletWidth();
return docs.filter(child => child instanceof Doc).map((child, i) => {
const pair = Doc.GetLayoutDataDocPair(containingCollection, dataDoc, child);
if (!pair.layout || pair.data instanceof Promise) {
@@ -756,10 +802,9 @@ export class TreeView extends React.Component<TreeViewProps> {
renderDepth={renderDepth}
removeDoc={StrCast(containingCollection.freezeChildren).includes("remove") ? undefined : remove}
addDocument={addDocument}
- backgroundColor={backgroundColor}
+ styleProvider={styleProvider}
panelWidth={rowWidth}
panelHeight={rowHeight}
- ChromeHeight={ChromeHeight}
dontRegisterView={dontRegisterView}
moveDocument={move}
dropAction={dropAction}
@@ -772,7 +817,7 @@ export class TreeView extends React.Component<TreeViewProps> {
treeViewHideHeaderFields={treeViewHideHeaderFields}
treeViewPreventOpen={treeViewPreventOpen}
renderedIds={renderedIds}
- ignoreFields={ignoreFields}
+ skipFields={skipFields}
firstLevel={firstLevel}
whenActiveChanged={whenActiveChanged} />;
});