aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
authorLionel Han <47760119+IGoByJoe@users.noreply.github.com>2020-08-14 12:55:05 -0700
committerLionel Han <47760119+IGoByJoe@users.noreply.github.com>2020-08-14 12:55:05 -0700
commit4fd8f1533be68bdcd3a6b8a832a38655adde4d71 (patch)
treecd2110b252c6a73932dfae36ba3d535d5e40fff0 /src/client/views/collections
parenta9161a668c96750d8bb50647c043a979058ef451 (diff)
parent36f7b54914b4d5fce98de3a6d83f1b186ebb17d1 (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into new_audio
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx2
-rw-r--r--src/client/views/collections/CollectionDockingView.scss76
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx89
-rw-r--r--src/client/views/collections/CollectionLinearView.tsx2
-rw-r--r--src/client/views/collections/CollectionMenu.scss1
-rw-r--r--src/client/views/collections/CollectionMenu.tsx25
-rw-r--r--src/client/views/collections/CollectionSchemaCells.tsx260
-rw-r--r--src/client/views/collections/CollectionSchemaHeaders.tsx250
-rw-r--r--src/client/views/collections/CollectionSchemaView.scss93
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx52
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx7
-rw-r--r--src/client/views/collections/CollectionSubView.tsx51
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx25
-rw-r--r--src/client/views/collections/CollectionView.tsx120
-rw-r--r--src/client/views/collections/ParentDocumentSelector.tsx14
-rw-r--r--src/client/views/collections/SchemaTable.tsx74
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx165
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx64
-rw-r--r--src/client/views/collections/collectionFreeForm/PropertiesView.tsx16
19 files changed, 812 insertions, 574 deletions
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 27aea4b99..8a27f8102 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -64,7 +64,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
</div>
<div className="collectionCarouselView-caption" key="caption"
style={{
- background: StrCast(this.layoutDoc._captionBackgroundColor, this.props.backgroundColor?.(this.props.Document)),
+ background: StrCast(this.layoutDoc._captionBackgroundColor, this.props.backgroundColor?.(this.props.Document, this.props.renderDepth)),
color: StrCast(this.layoutDoc._captionColor, StrCast(this.layoutDoc.color)),
borderRadius: StrCast(this.layoutDoc._captionBorderRounding),
}}>
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index 4204ef5bb..6ebd5103b 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -20,82 +20,6 @@
}
}
-.miniPres:hover {
- opacity: 1;
-}
-
-.miniPres {
- position: absolute;
- overflow: hidden;
- right: 10;
- top: 10;
- opacity: 0.1;
- transition: all 0.4s;
- /* border: solid 1px; */
- color: white;
- /* box-shadow: black 0.4vw 0.4vw 0.8vw; */
-
- .miniPresOverlay {
- display: grid;
- grid-template-columns: auto auto auto auto auto auto auto auto;
- grid-template-rows: 100%;
- height: 100%;
- justify-items: center;
- align-items: center;
-
- .miniPres-button-text {
- display: flex;
- height: 20;
- font-weight: 400;
- min-width: 100%;
- border-radius: 5px;
- align-items: center;
- justify-content: center;
- transition: all 0.3s;
- }
-
- .miniPres-button-frame {
- justify-self: center;
- align-self: center;
- align-items: center;
- display: grid;
- grid-template-columns: auto auto auto;
- justify-content: space-around;
- font-size: 11;
- margin-left: 7;
- width: 30;
- height: 85%;
- background-color: rgba(91, 157, 221, 0.4);
- border-radius: 5px;
- }
-
- .miniPres-divider {
- width: 0.5px;
- height: 80%;
- border-right: solid 2px #5a5a5a;
- }
-
- .miniPres-button {
- display: flex;
- height: 20;
- min-width: 20;
- border-radius: 100%;
- align-items: center;
- justify-content: center;
- transition: all 0.3s;
- }
-
- .miniPres-button:hover {
- background-color: #5a5a5a;
- }
-
- .miniPres-button-text:hover {
- background-color: #5a5a5a;
- }
- }
-}
-
-
.lm_title {
margin-top: 3px;
border-radius: 5px;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 3691e844f..43da0d3cf 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -191,31 +191,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
return retVal;
}
- @undoBatch
- @action
- public static ReplaceTab(document: Doc, stack: any): Opt<Doc> {
- if (!CollectionDockingView.Instance) return undefined;
- const instance = CollectionDockingView.Instance;
- const replaceTab = (doc: Doc, child: any): Opt<Doc> => {
- for (const contentItem of child.contentItems) {
- const { config, isStack, isRow, isColumn } = contentItem;
- if (isRow || isColumn || isStack) {
- const val = replaceTab(doc, contentItem);
- if (val) return val;
- } else if (config.component === "DocumentFrameRenderer" &&
- config.props.documentId === doc[Id]) {
- const alias = Doc.MakeAlias(doc);
- config.props.documentId = alias[Id];
- config.title = alias.title;
- instance.stateChanged();
- return alias;
- }
- }
- return undefined;
- };
- return replaceTab(document, instance._goldenLayout.root);
- }
-
//
// Creates a vertical split on the right side of the docking view, and then adds the Document to the right of that split
//
@@ -358,6 +333,32 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
return true;
}
+ @undoBatch
+ @action
+ public ReplaceTab = (stack: any, document: Doc, libraryPath?: Doc[]) => {
+ Doc.GetProto(document).lastOpened = new DateField;
+ const docContentConfig = CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath);
+ if (stack === undefined) {
+ let stack: any = this._goldenLayout.root;
+ while (!stack.isStack) {
+ if (stack.contentItems.length) {
+ stack = stack.contentItems[0];
+ } else {
+ stack.addChild({ type: 'stack', content: [docContentConfig] });
+ stack = undefined;
+ break;
+ }
+ }
+ if (stack) {
+ stack.addChild(docContentConfig);
+ }
+ } else {
+ stack.addChild(docContentConfig, undefined);
+ }
+ this.layoutChanged();
+ return true;
+ }
+
setupGoldenLayout() {
const config = StrCast(this.props.Document.dockingConfig);
if (config) {
@@ -727,9 +728,11 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
pinDoc.presZoomButton = true;
pinDoc.context = curPres;
Doc.AddDocToList(curPres, "data", pinDoc);
+ if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
if (!DocumentManager.Instance.getDocumentView(curPres)) {
CollectionDockingView.AddRightSplit(curPres);
}
+ DocumentManager.Instance.jumpToDocument(doc, false, undefined, Cast(doc.context, Doc, null));
}
}
}
@@ -758,7 +761,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged);
this.props.glContainer.on("tab", this.onActiveContentItemChanged);
this.onActiveContentItemChanged();
- this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: StrCast(this._document?._backgroundColor, "white") }),
+ this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: StrCast(this._document?._backgroundColor, this._document && CollectionDockingView.Instance?.props.backgroundColor?.(this._document, 0) || "white") }),
(data) => {
const selected = data.views.some(v => Doc.AreProtosEqual(v.props.Document, this._document));
this._tab && (this._tab.style.backgroundColor = selected ? data.color : "");
@@ -821,7 +824,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
if (this._mainCont && this._mainCont.children) {
const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont.children[0].firstChild as HTMLElement);
const scale = Utils.GetScreenTransform(this._mainCont).scale;
- return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / this.contentScaling() / scale);
+ return CollectionDockingView.Instance?.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / this.contentScaling() / scale);
}
return Transform.Identity();
}
@@ -837,12 +840,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
} else if (location === "close") {
return CollectionDockingView.CloseRightSplit(doc);
} else if (location === "replace") {
- const alias = CollectionDockingView.ReplaceTab(doc, this._stack);
- if (alias) {
- runInAction(() => this._document = alias);
- return true;
- }
- return false;
+ CollectionDockingView.UseRightSplit(doc);
+ return true;
} else {// if (location === "inPlace") {
return CollectionDockingView.Instance.AddTab(this._stack, doc, libraryPath);
}
@@ -873,30 +872,11 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
const currentFrame = Cast(presTargetDoc.currentFrame, "number", null);
return currentFrame;
}
- renderMiniPres() {
- return (
- <div className="miniPres"
- style={{ width: 250, height: 30, background: '#323232' }}
- >
- {<div className="miniPresOverlay">
- <div className="miniPres-button" onClick={PresBox.Instance.back}><FontAwesomeIcon icon={"arrow-left"} /></div>
- <div className="miniPres-button" onClick={() => PresBox.Instance.startAutoPres(PresBox.Instance.itemIndex)}><FontAwesomeIcon icon={PresBox.Instance.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div>
- <div className="miniPres-button" onClick={PresBox.Instance.next}><FontAwesomeIcon icon={"arrow-right"} /></div>
- <div className="miniPres-divider"></div>
- <div className="miniPres-button-text">
- Slide {PresBox.Instance.itemIndex + 1} / {PresBox.Instance.childDocs.length}
- {PresBox.Instance.playButtonFrames}
- </div>
- <div className="miniPres-divider"></div>
- <div className="miniPres-button-text" onClick={PresBox.Instance.updateMinimize}>EXIT</div>
- </div>}
- </div>
- );
- }
+
renderMiniMap() {
return <div className="miniMap" style={{
width: this.returnMiniSize(), height: this.returnMiniSize(), background: StrCast(this._document!._backgroundColor,
- StrCast(this._document!.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document!))),
+ StrCast(this._document!.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document!, 0))),
}}>
<CollectionFreeFormView
Document={this._document!}
@@ -975,7 +955,6 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined} />
{document._viewType === CollectionViewType.Freeform && !this._document?.hideMinimap ? this.renderMiniMap() : (null)}
- {document._viewType === CollectionViewType.Freeform && this._document?.miniPres ? this.renderMiniPres() : (null)}
</>;
}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 3cf46dbed..e1b07077e 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -119,7 +119,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
// transform: this.props.Document.linearViewIsExpanded ? "" : "rotate(45deg)"
}}
onPointerDown={e => e.stopPropagation()} >
- <p>+</p>
+ <p>{BoolCast(this.props.Document.linearViewIsExpanded) ? "–" : "+"}</p>
</label>;
return <div className="collectionLinearView-outer">
diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss
index b41cbe92d..8658212b7 100644
--- a/src/client/views/collections/CollectionMenu.scss
+++ b/src/client/views/collections/CollectionMenu.scss
@@ -315,6 +315,7 @@
display: inline-flex;
position: relative;
align-items: center;
+ margin-left: 10px;
.antimodeMenu-button {
text-align: center;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 53d2a136e..5119ff6c9 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -85,7 +85,8 @@ export default class CollectionMenu extends AntimodeMenu {
const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Properties Panel" : "Open Properties Panel";
const prop = <Tooltip title={<div className="dash-tooltip">{propTitle}</div>} key="properties" placement="bottom">
- <button className="antimodeMenu-button" key="properties" onPointerDown={this.toggleProperties}>
+ <button className="antimodeMenu-button" key="properties" style={{ backgroundColor: "#424242" }}
+ onPointerDown={this.toggleProperties}>
<FontAwesomeIcon icon={propIcon} size="lg" />
</button>
</Tooltip>;
@@ -580,9 +581,9 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
onPointerDown={action(() => { this.changeColor(color, "color"); this._colorBtn = false; this.editProperties(color, "color"); })}
style={{ backgroundColor: this._colorBtn ? "121212" : "", zIndex: 1001 }}>
{/* <FontAwesomeIcon icon="pen-nib" size="lg" /> */}
- <div className="color-previewII" style={{ backgroundColor: color }} />
- {color === "" ? <p style={{ fontSize: 45, color: "red", marginTop: -16, marginLeft: -5, position: "fixed" }}>☒</p> : ""}
-
+ <div className="color-previewII" style={{ backgroundColor: color }}>
+ {color === "" ? <p style={{ fontSize: 45, color: "red", marginTop: -16, marginLeft: -5, position: "fixed" }}>☒</p> : ""}
+ </div>
</button>)}
</div>;
}
@@ -622,7 +623,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
</div>
</Tooltip> : null}
{!this.isText && !this.props.isDoc ? <Tooltip key="num" title={<div className="dash-tooltip">Toggle View All</div>} placement="bottom">
- <div className="numKeyframe" style={{ backgroundColor: this.document.editing ? "#759c75" : "#c56565" }}
+ <div className="numKeyframe" style={{ color: this.document.editing ? "white" : "black", backgroundColor: this.document.editing ? "#5B9FDD" : "#AEDDF8" }}
onClick={action(() => this.document.editing = !this.document.editing)} >
{NumCast(this.document.currentFrame)}
</div>
@@ -669,7 +670,7 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu
@computed get pivotField() { return StrCast(this.document._pivotField); }
getKeySuggestions = async (value: string): Promise<string[]> => {
- value = value.toLowerCase();
+ const val = value.toLowerCase();
const docs = DocListCast(this.document[this.props.fieldKey]);
if (Doc.UserDoc().noviceMode) {
@@ -677,7 +678,7 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu
const keys = Object.keys(docs).filter(key => key.indexOf("title") >= 0 || key.indexOf("author") >= 0 ||
key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 ||
(key[0].toUpperCase() === key[0] && key.substring(0, 3) !== "ACL" && key !== "UseCors" && key[0] !== "_"));
- return keys.filter(key => key.toLowerCase().indexOf(value.toLowerCase()) > -1);
+ return keys.filter(key => key.toLowerCase().indexOf(val) > -1);
} else {
const keys = new Set<string>();
docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
@@ -685,16 +686,16 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu
key.indexOf("author") >= 0 || key.indexOf("creationDate") >= 0 ||
key.indexOf("lastModified") >= 0 || (key[0].toUpperCase() === key[0] &&
key.substring(0, 3) !== "ACL" && key !== "UseCors" && key[0] !== "_"));
- return noviceKeys.filter(key => key.toLowerCase().indexOf(value.toLowerCase()) > -1);
+ return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1);
}
}
if (docs instanceof Doc) {
- return Object.keys(docs).filter(key => key.toLowerCase().startsWith(value));
+ return Object.keys(docs).filter(key => key.toLowerCase().indexOf(val) > -1);
} else {
const keys = new Set<string>();
docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
- return Array.from(keys).filter(key => key.toLowerCase().startsWith(value));
+ return Array.from(keys).filter(key => key.toLowerCase().indexOf(val) > -1);
}
}
@@ -735,8 +736,10 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu
@action resetValue = () => { this._currentKey = this.pivotField; };
render() {
+ const doctype = this.props.docView.Document.type;
+ const isPres: boolean = (doctype === DocumentType.PRES);
return (
- <div className="collectionStackingViewChrome-cont">
+ isPres ? (null) : <div className="collectionStackingViewChrome-cont">
<div className="collectionStackingViewChrome-pivotField-cont">
<div className="collectionStackingViewChrome-pivotField-label">
GROUP BY:
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 8a1dd8472..20ce6b76d 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -1,5 +1,5 @@
import React = require("react");
-import { action, observable, trace, computed } from "mobx";
+import { action, observable, trace, computed, runInAction } from "mobx";
import { observer } from "mobx-react";
import { CellInfo } from "react-table";
import "react-table/react-table.css";
@@ -33,6 +33,8 @@ import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import { DateField } from "../../../fields/DateField";
import { RichTextField } from "../../../fields/RichTextField";
+import { DocumentManager } from "../../util/DocumentManager";
+import { SearchUtil } from "../../util/SearchUtil";
const path = require('path');
library.add(faExpand);
@@ -67,10 +69,29 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
protected _document = this.props.rowProps.original;
protected _dropDisposer?: DragManager.DragDropDisposer;
- componentDidMount() {
+ async componentWillMount() {
+
+ }
+
+ async componentDidMount() {
document.addEventListener("keydown", this.onKeyDown);
+ console.log("mounted");
+ console.log(this.type);
+ if (this.type === "context") {
+ console.log("mounted2");
+ const doc = Doc.GetProto(this.props.rowProps.original);
+ const aliasdoc = await SearchUtil.GetAliasesOfDocument(doc);
+ if (aliasdoc.length > 0) {
+ const targetContext = Cast(aliasdoc[0].context, Doc) as Doc;
+ console.log(StrCast(targetContext.title));
+ runInAction(() => this.contents = StrCast(targetContext.title));
+ }
+ }
+
}
+ @observable contents: string = "";
+
componentWillUnmount() {
document.removeEventListener("keydown", this.onKeyDown);
}
@@ -159,6 +180,31 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
// e.stopPropagation();
// }
+ returnHighlights(bing: (() => string), positions?: number[]) {
+ const results = [];
+ const contents = bing();
+
+ if (positions !== undefined) {
+ StrCast(this.props.Document._searchString);
+ const length = StrCast(this.props.Document._searchString).length;
+ const color = contents ? "black" : "grey";
+
+ results.push(<span key="-1" style={{ color }}>{contents?.slice(0, positions[0])}</span>);
+ positions.forEach((num, cur) => {
+ results.push(<span key={"start" + cur} style={{ backgroundColor: "#FFFF00", color }}>{contents?.slice(num, num + length)}</span>);
+ let end = 0;
+ cur === positions.length - 1 ? end = contents.length : end = positions[cur + 1];
+ results.push(<span key={"end" + cur} style={{ color }}>{contents?.slice(num + length, end)}</span>);
+ }
+ );
+ return results;
+ }
+ else {
+ return <span style={{ color: contents ? "black" : "grey" }}>{contents ? contents?.valueOf() : "undefined"}</span>;
+ }
+ }
+ type: string = "";
+
renderCellWithType(type: string | undefined) {
const dragRef: React.RefObject<HTMLDivElement> = React.createRef();
@@ -200,12 +246,23 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
const doc = FieldValue(Cast(field, Doc));
const fieldIsDoc = (type === "document" && typeof field === "object") || (typeof field === "object" && doc);
- const onItemDown = (e: React.PointerEvent) => {
- //fieldIsDoc &&
- SetupDrag(this._focusRef,
- () => this._document[props.fieldKey] instanceof Doc ? this._document[props.fieldKey] : this._document,
- this._document[props.fieldKey] instanceof Doc ? (doc: Doc | Doc[], target: Doc | undefined, addDoc: (newDoc: Doc | Doc[]) => any) => addDoc(doc) : this.props.moveDocument,
- this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e);
+ const onItemDown = async (e: React.PointerEvent) => {
+ if (this.props.Document._searchDoc !== undefined) {
+ const doc = Doc.GetProto(this.props.rowProps.original);
+ const aliasdoc = await SearchUtil.GetAliasesOfDocument(doc);
+ let targetContext = undefined;
+ if (aliasdoc.length > 0) {
+ targetContext = Cast(aliasdoc[0].context, Doc) as Doc;
+ }
+ DocumentManager.Instance.jumpToDocument(this.props.rowProps.original, false, undefined, targetContext);
+ }
+ else {
+ fieldIsDoc &&
+ SetupDrag(this._focusRef,
+ () => this._document[props.fieldKey] instanceof Doc ? this._document[props.fieldKey] : this._document,
+ this._document[props.fieldKey] instanceof Doc ? (doc: Doc | Doc[], target: Doc | undefined, addDoc: (newDoc: Doc | Doc[]) => any) => addDoc(doc) : this.props.moveDocument,
+ this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e);
+ }
};
const onPointerEnter = (e: React.PointerEvent): void => {
if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === "document" || type === undefined)) {
@@ -250,20 +307,10 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
// </div>
// );
const positions = [];
+ let cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
+ this.type = props.fieldKey;
if (StrCast(this.props.Document._searchString).toLowerCase() !== "") {
- const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
- let term = "";
- if (cfield !== undefined) {
- if (cfield.Text !== undefined) {
- term = cfield.Text;
- }
- else if (StrCast(cfield)) {
- term = StrCast(cfield);
- }
- else {
- term = String(NumCast(cfield));
- }
- }
+ let term = Field.toString(cfield as Field);
term = term.toLowerCase();
const search = StrCast(this.props.Document._searchString).toLowerCase();
let start = term.indexOf(search);
@@ -281,89 +328,123 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
positions.pop();
}
}
+ let search = false;
+ if (this.props.Document._searchDoc !== undefined) {
+ search = true;
+ }
+
return (
<div className="collectionSchemaView-cellContainer" style={{ cursor: fieldIsDoc ? "grab" : "auto" }}
ref={dragRef} onPointerDown={this.onPointerDown} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}>
<div className={className} ref={this._focusRef} onPointerDown={onItemDown} tabIndex={-1}>
- <div className="collectionSchemaView-cellContents" ref={type === undefined || type === "document" ? this.dropRef : null} key={props.Document[Id]}>
- <EditableView
- positions={positions.length > 0 ? positions : undefined}
- search={StrCast(this.props.Document._searchString) ? StrCast(this.props.Document._searchString) : undefined}
- editing={this._isEditing}
- isEditingCallback={this.isEditingCallback}
- display={"inline"}
- contents={contents ? contents : type === "number" ? "0" : "undefined"}
- highlight={positions.length > 0 ? true : undefined}
- //contents={StrCast(contents)}
- height={"auto"}
- maxHeight={Number(MAX_ROW_HEIGHT)}
- placeholder={"enter value"}
- bing={() => {
- const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
- if (cfield !== undefined) {
- console.log(typeof (cfield));
- // if (typeof(cfield)===RichTextField)
- const a = cfield as RichTextField;
- if (a.Text !== undefined) {
- return (a.Text);
- }
- else if (StrCast(cfield)) {
- return StrCast(cfield);
- }
- else {
- return String(NumCast(cfield));
- }
- }
- }}
- GetValue={() => {
- if (type === "number" && (contents === 0 || contents === "0")) {
- return "0";
- } else {
+ <div className="collectionSchemaView-cellContents"
+ ref={type === undefined || type === "document" ? this.dropRef : null} key={props.Document[Id]}>
+ {!search ?
+ <EditableView
+ positions={positions.length > 0 ? positions : undefined}
+ search={StrCast(this.props.Document._searchString) ? StrCast(this.props.Document._searchString) : undefined}
+ editing={this._isEditing}
+ isEditingCallback={this.isEditingCallback}
+ display={"inline"}
+ contents={contents ? contents : type === "number" ? "0" : "undefined"}
+ highlight={positions.length > 0 ? true : undefined}
+ //contents={StrCast(contents)}
+ height={"auto"}
+ maxHeight={Number(MAX_ROW_HEIGHT)}
+ placeholder={"undefined"}
+ bing={() => {
const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
- if (type === "number") {
- return StrCast(cfield);
+ if (cfield !== undefined) {
+ // if (typeof(cfield)===RichTextField)
+ const a = cfield as RichTextField;
+ const b = cfield as DateField;
+ console.log(b);
+ if (a.Text !== undefined) {
+ return (a.Text);
+ }
+ else if (b.toString() !== undefined) {
+ return b.toString();
+ }
+ else if (StrCast(cfield)) {
+ return StrCast(cfield);
+ }
+ else {
+ return String(NumCast(cfield));
+ }
}
- const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined;
- const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1];
- const val = cscript !== undefined ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) :
- Field.IsField(cfield) ? Field.toScriptString(cfield) : "";
- return val;
+ }}
+ GetValue={() => {
+ if (type === "number" && (contents === 0 || contents === "0")) {
+ return "0";
+ } else {
+ const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
+ if (type === "number") {
+ return StrCast(cfield);
+ }
+ const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined;
+ const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1];
+ const val = cscript !== undefined ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) :
+ Field.IsField(cfield) ? Field.toScriptString(cfield) : "";
+ return val;
- }
+ }
- }}
- SetValue={action((value: string) => {
- let retVal = false;
+ }}
+ SetValue={action((value: string) => {
+ let retVal = false;
+
+ if (value.startsWith(":=")) {
+ retVal = this.props.setComputed(value.substring(2), props.Document, this.props.rowProps.column.id!, this.props.row, this.props.col);
+ } else {
+ const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
+ if (script.compiled) {
+ retVal = this.applyToDoc(props.Document, this.props.row, this.props.col, script.run);
+ }
- if (value.startsWith(":=")) {
- retVal = this.props.setComputed(value.substring(2), props.Document, this.props.rowProps.column.id!, this.props.row, this.props.col);
- } else {
+ }
+ if (retVal) {
+ this._isEditing = false; // need to set this here. otherwise, the assignment of the field will invalidate & cause render() to be called with the wrong value for 'editing'
+ this.props.setIsEditing(false);
+ }
+ return retVal;
+
+ //return true;
+ })}
+ OnFillDown={async (value: string) => {
const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
if (script.compiled) {
- retVal = this.applyToDoc(props.Document, this.props.row, this.props.col, script.run);
+ DocListCast(this.props.Document[this.props.fieldKey]).
+ forEach((doc, i) => value.startsWith(":=") ?
+ this.props.setComputed(value.substring(2), doc, this.props.rowProps.column.id!, i, this.props.col) :
+ this.applyToDoc(doc, i, this.props.col, script.run));
}
-
+ }}
+ />
+ :
+ this.returnHighlights(() => {
+ console.log(props.fieldKey);
+ const dateCheck: Date | undefined = this.props.rowProps.original[this.props.rowProps.column.id as string] instanceof DateField ? DateCast(this.props.rowProps.original[this.props.rowProps.column.id as string]).date : undefined;
+ if (dateCheck !== undefined) {
+ cfield = dateCheck.toLocaleString();
}
- if (retVal) {
- this._isEditing = false; // need to set this here. otherwise, the assignment of the field will invalidate & cause render() to be called with the wrong value for 'editing'
- this.props.setIsEditing(false);
+ if (props.fieldKey === "context") {
+ cfield = this.contents;
+ console.log("this should work");
}
- return retVal;
+ if (props.fieldKey === "*lastModified") {
+ if (FieldValue(props.Document["data-lastModified"]) !== undefined) {
+ const d = ComputedField.WithoutComputed(() => FieldValue(props.Document["data-lastModified"])) as DateField;
+ cfield = d.date.toLocaleString();
+ }
- //return true;
- })}
- OnFillDown={async (value: string) => {
- const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
- if (script.compiled) {
- DocListCast(this.props.Document[this.props.fieldKey]).
- forEach((doc, i) => value.startsWith(":=") ?
- this.props.setComputed(value.substring(2), doc, this.props.rowProps.column.id!, i, this.props.col) :
- this.applyToDoc(doc, i, this.props.col, script.run));
+ else if (FieldValue(props.Document["text-lastModified"]) !== undefined) {
+ const d = ComputedField.WithoutComputed(() => FieldValue(props.Document["text-lastModified"])) as DateField;
+ cfield = d.date.toLocaleString();
+ }
}
- }}
- />
-
-
+ return Field.toString(cfield as Field);
+ }, positions)
+ }
</div >
{/* {fieldIsDoc ? docExpander : null} */}
</div>
@@ -903,7 +984,6 @@ export class CollectionSchemaButtons extends CollectionSchemaCell {
}}><button onClick={() => {
doc.searchMatch = false;
setTimeout(() => doc.searchMatch = true, 0);
- doc.searchIndex = NumCast(doc.searchIndex);
}} style={{ padding: 2, left: 77 }}>
<FontAwesomeIcon icon="arrow-up" size="sm" />
</button>
@@ -911,7 +991,6 @@ export class CollectionSchemaButtons extends CollectionSchemaCell {
{
doc.searchMatchAlt = false;
setTimeout(() => doc.searchMatchAlt = true, 0);
- doc.searchIndex = NumCast(doc.searchIndex);
}
}} style={{ padding: 2 }}>
<FontAwesomeIcon icon="arrow-down" size="sm" />
@@ -929,7 +1008,6 @@ export class CollectionSchemaButtons extends CollectionSchemaCell {
onClick={() => {
doc.searchMatch = false;
setTimeout(() => doc.searchMatch = true, 0);
- doc.searchIndex = NumCast(doc.searchIndex);
}}>
<FontAwesomeIcon icon="arrow-down" size="sm" />
</button></div >;
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
index e65adcf76..5c0e6581b 100644
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/CollectionSchemaHeaders.tsx
@@ -1,22 +1,24 @@
import React = require("react");
-import { action, observable } from "mobx";
-import { observer } from "mobx-react";
-import "./CollectionSchemaView.scss";
-import { faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faSortAmountDown, faSortAmountUp, faTimes, faImage, faListUl, faCalendar } from '@fortawesome/free-solid-svg-icons';
-import { library, IconProp } from "@fortawesome/fontawesome-svg-core";
+import { IconProp, library } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { ColumnType } from "./CollectionSchemaView";
-import { faFile } from "@fortawesome/free-regular-svg-icons";
-import { SchemaHeaderField, PastelSchemaPalette } from "../../../fields/SchemaHeaderField";
+import { action, computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import { Doc, DocListCast, Opt } from "../../../fields/Doc";
+import { listSpec } from "../../../fields/Schema";
+import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
+import { ScriptField } from "../../../fields/ScriptField";
+import { Cast, StrCast } from "../../../fields/Types";
import { undoBatch } from "../../util/UndoManager";
-import { Doc } from "../../../fields/Doc";
-import { StrCast } from "../../../fields/Types";
+import { SearchBox } from "../search/SearchBox";
+import { ColumnType } from "./CollectionSchemaView";
+import "./CollectionSchemaView.scss";
+import { CollectionView } from "./CollectionView";
+import * as fa from '@fortawesome/free-solid-svg-icons';
+
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
-library.add(faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faFile as any, faSortAmountDown, faSortAmountUp, faTimes, faImage, faListUl, faCalendar);
-
export interface HeaderProps {
keyValue: SchemaHeaderField;
possibleKeys: string[];
@@ -35,7 +37,7 @@ export interface HeaderProps {
export class CollectionSchemaHeader extends React.Component<HeaderProps> {
render() {
const icon: IconProp = this.props.keyType === ColumnType.Number ? "hashtag" : this.props.keyType === ColumnType.String ? "font" :
- this.props.keyType === ColumnType.Boolean ? "check-square" : this.props.keyType === ColumnType.Doc ? "file" :
+ this.props.keyType === ColumnType.Boolean ? "check-square" : this.props.keyType === ColumnType.Doc ? "sort-amount-down" :
this.props.keyType === ColumnType.Image ? "image" : this.props.keyType === ColumnType.List ? "list-ul" : this.props.keyType === ColumnType.Date ? "calendar" :
"align-justify";
return (
@@ -238,18 +240,6 @@ export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps>
renderContent = () => {
return (
<div className="collectionSchema-header-menuOptions">
- <div className="collectionSchema-headerMenu-group">
- <label>Key:</label>
- <KeysDropdown
- keyValue={this.props.columnField.heading}
- possibleKeys={this.props.possibleKeys}
- existingKeys={this.props.existingKeys}
- canAddNew={true}
- addNew={this.props.addNew}
- onSelect={this.props.onSelect}
- setIsEditing={this.props.setIsEditing}
- />
- </div>
{this.props.onlyShowOptions ? <></> :
<>
{this.renderTypes()}
@@ -286,6 +276,15 @@ export interface KeysDropdownProps {
setIsEditing: (isEditing: boolean) => void;
width?: string;
docs?: Doc[];
+ Document: Doc;
+ dataDoc: Doc | undefined;
+ fieldKey: string;
+ ContainingCollectionDoc: Doc | undefined;
+ ContainingCollectionView: Opt<CollectionView>;
+ active?: (outsideReaction?: boolean) => boolean;
+ openHeader: (column: any, screenx: number, screeny: number) => void;
+ col: SchemaHeaderField;
+ icon: IconProp;
}
@observer
export class KeysDropdown extends React.Component<KeysDropdownProps> {
@@ -301,34 +300,38 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
@action
onSelect = (key: string): void => {
- if (key.slice(0, this._key.length) === this._key && this._key !== key) {
- const filter = key.slice(this._key.length - key.length);
- this.props.onSelect(this._key, this._key, this.props.addNew, filter);
- }
- else {
- this.props.onSelect(this._key, key, this.props.addNew);
- this.setKey(key);
- this._isOpen = false;
- this.props.setIsEditing(false);
- }
- }
-
- @action
- onSelect2 = (key: string): void => {
- this._searchTerm = this._searchTerm.slice(0, this._key.length) + key;
+ this.props.onSelect(this._key, key, this.props.addNew);
+ this.setKey(key);
this._isOpen = false;
-
+ this.props.setIsEditing(false);
}
@undoBatch
onKeyDown = (e: React.KeyboardEvent): void => {
if (e.key === "Enter") {
- const keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
- if (keyOptions.length) {
- this.onSelect(keyOptions[0]);
- } else if (this._searchTerm !== "" && this.props.canAddNew) {
- this.setSearchTerm(this._searchTerm || this._key);
- this.onSelect(this._searchTerm);
+ if (this._searchTerm.includes(":")) {
+ const colpos = this._searchTerm.indexOf(":");
+ const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length);
+ if (temp === "") {
+ Doc.setDocFilter(this.props.Document, this._key, temp, undefined);
+ }
+ else {
+ Doc.setDocFilter(this.props.Document, this._key, temp, "match");
+ this.props.col.setColor("green");
+ }
+ }
+ else {
+ let keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
+ const blockedkeys = ["_scrollTop", "customTitle", "limitHeight", "proto", "x", "y", "_width", "_height", "_autoHeight", "_fontSize", "_fontFamily", "context", "zIndex", "_timeStampOnEnter", "lines", "highlighting", "searchMatch", "creationDate", "isPrototype", "text-annotations", "aliases", "text-lastModified", "text-noTemplate", "layoutKey", "baseProto", "_xMargin", "_yMargin", "layout", "layout_keyValue", "links"];
+ keyOptions = keyOptions.filter(n => !blockedkeys.includes(n));
+ if (keyOptions.length) {
+ this.onSelect(keyOptions[0]);
+ console.log("case1");
+ } else if (this._searchTerm !== "" && this.props.canAddNew) {
+ this.setSearchTerm(this._searchTerm || this._key);
+ console.log("case2");
+ this.onSelect(this._searchTerm);
+ }
}
}
}
@@ -360,87 +363,172 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
onPointerOut = (e: React.PointerEvent): void => {
this._canClose = true;
}
-
+ @action
renderOptions = (): JSX.Element[] | JSX.Element => {
- if (!this._isOpen) return <></>;
-
+ if (!this._isOpen) {
+ this.defaultMenuHeight = 0;
+ return <></>;
+ }
const searchTerm = this._searchTerm.trim() === "New field" ? "" : this._searchTerm;
- const keyOptions = searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
+ let keyOptions = searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
const exactFound = keyOptions.findIndex(key => key.toUpperCase() === this._searchTerm.toUpperCase()) > -1 ||
this.props.existingKeys.findIndex(key => key.toUpperCase() === this._searchTerm.toUpperCase()) > -1;
+ const blockedkeys = ["proto", "x", "y", "_width", "_height", "_autoHeight", "_fontSize", "_fontFamily", "context", "zIndex", "_timeStampOnEnter", "lines", "highlighting", "searchMatch", "creationDate", "isPrototype", "text-annotations", "aliases", "text-lastModified", "text-noTemplate", "layoutKey", "baseProto", "_xMargin", "_yMargin", "layout", "layout_keyValue", "links"];
+ keyOptions = keyOptions.filter(n => !blockedkeys.includes(n));
+
const options = keyOptions.map(key => {
return <div key={key} className="key-option" style={{
border: "1px solid lightgray",
- width: this.props.width, maxWidth: this.props.width, overflowX: "hidden"
+ width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white",
}}
onPointerDown={e => e.stopPropagation()} onClick={() => { this.onSelect(key); this.setSearchTerm(""); }}>{key}</div>;
});
// if search term does not already exist as a group type, give option to create new group type
+
if (this._key !== this._searchTerm.slice(0, this._key.length)) {
+ console.log("little further");
if (!exactFound && this._searchTerm !== "" && this.props.canAddNew) {
options.push(<div key={""} className="key-option" style={{
- border: "1px solid lightgray",
- width: this.props.width, maxWidth: this.props.width, overflowX: "hidden"
+ border: "1px solid lightgray", width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white",
}}
onClick={() => { this.onSelect(this._searchTerm); this.setSearchTerm(""); }}>
Create "{this._searchTerm}" key</div>);
}
}
+ if (options.length === 0) {
+ this.defaultMenuHeight = 0;
+ }
+ else {
+ if (this.props.docs) {
+ const panesize = this.props.docs.length * 30;
+ options.length * 20 + 8 - 10 > panesize ? this.defaultMenuHeight = panesize : this.defaultMenuHeight = options.length * 20 + 8;
+ }
+ else {
+ options.length > 5 ? this.defaultMenuHeight = 108 : this.defaultMenuHeight = options.length * 20 + 8;
+ }
+ }
return options;
}
+ docSafe: Doc[] = [];
+
+ @action
renderFilterOptions = (): JSX.Element[] | JSX.Element => {
- if (!this._isOpen) return <></>;
+ if (!this._isOpen) {
+ this.defaultMenuHeight = 0;
+ return <></>;
+ }
+
const keyOptions: string[] = [];
- const temp = this._searchTerm.slice(this._key.length);
- this.props.docs?.forEach((doc) => {
+ const colpos = this._searchTerm.indexOf(":");
+ const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length);
+ if (this.docSafe.length === 0) {
+ this.docSafe = DocListCast(this.props.dataDoc![this.props.fieldKey]);
+ }
+ const docs = this.docSafe;
+ docs.forEach((doc) => {
const key = StrCast(doc[this._key]);
if (keyOptions.includes(key) === false && key.includes(temp)) {
keyOptions.push(key);
}
});
+ const filters = Cast(this.props.Document._docFilters, listSpec("string"));
+ for (let i = 0; i < (filters?.length ?? 0) - 1; i += 3) {
+ if (filters![i] === this.props.col.heading && keyOptions.includes(filters![i + 1]) === false) {
+ keyOptions.push(filters![i + 1]);
+ }
+ }
+
+ if (filters === undefined || filters.length === 0 || filters.includes(this._key) === false) {
+ this.props.col.setColor("rgb(241, 239, 235)");
+ }
const options = keyOptions.map(key => {
+ //Doc.setDocFilter(this.props.Document!, this._key, key, undefined);
+ let bool = false;
+ console.log(filters);
+ if (filters !== undefined) {
+ bool = filters.includes(key) && filters[filters.indexOf(key) + 1] === "check";
+ console.log(filters.includes(key));
+ }
return <div key={key} className="key-option" style={{
- border: "1px solid lightgray",
- width: this.props.width, maxWidth: this.props.width, overflowX: "hidden"
+ border: "1px solid lightgray", paddingLeft: 5, textAlign: "left",
+ width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white", backgroundColor: "white",
}}
- onPointerDown={e => e.stopPropagation()} onClick={() => { this.onSelect2(key); }}>{key}</div>;
+ >
+ <input type="checkbox" onChange={(e) => {
+ e.target.checked === true ? Doc.setDocFilter(this.props.Document, this._key, key, "check") : Doc.setDocFilter(this.props.Document, this._key, key, undefined);
+ e.target.checked === true ? this.props.col.setColor("green") : "";
+ e.target.checked === true && SearchBox.Instance.filter === true ? Doc.setDocFilter(docs[0], this._key, key, "check") : Doc.setDocFilter(docs[0], this._key, key, undefined);
+ }}
+ checked={bool} ></input>
+ <span style={{ paddingLeft: 4 }}>
+ {key}
+ </span>
+
+ </div>;
});
+ if (options.length === 0) {
+ this.defaultMenuHeight = 0;
+ }
+ else {
+ if (this.props.docs) {
+ const panesize = this.props.docs.length * 30;
+ options.length * 20 + 8 - 10 > panesize ? this.defaultMenuHeight = panesize : this.defaultMenuHeight = options.length * 20 + 8;
+ }
+ else {
+ options.length > 5 ? this.defaultMenuHeight = 108 : this.defaultMenuHeight = options.length * 20 + 8;
+ }
+ }
return options;
}
+ @observable defaultMenuHeight = 0;
+
+
+ get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; }
+
+ @computed get scriptField() {
+ console.log("we kinda made it");
+ const scriptText = "setDocFilter(containingTreeView, heading, this.title, checked)";
+ const script = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name });
+ return script ? () => script : undefined;
+ }
+ filterBackground = () => "rgba(105, 105, 105, 0.432)";
+
+ @observable filterOpen: boolean | undefined = undefined;
render() {
return (
- <div className="keys-dropdown" style={{ zIndex: 10, width: this.props.width, maxWidth: this.props.width }}>
- {this._key === this._searchTerm.slice(0, this._key.length) ?
- <div style={{ position: "absolute", marginLeft: "4px", marginTop: "3", color: "grey", pointerEvents: "none", lineHeight: 1.15 }}>
- {this._key}
+ <div style={{ display: "flex" }}>
+ <FontAwesomeIcon onClick={e => { this.props.openHeader(this.props.col, e.clientX, e.clientY); }} icon={this.props.icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} />
+
+ {/* <FontAwesomeIcon icon={fa.faSearchMinus} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} onClick={e => {
+ runInAction(() => { this._isOpen === undefined ? this._isOpen = true : this._isOpen = !this._isOpen })
+ }} /> */}
+
+ <div className="keys-dropdown" style={{ zIndex: 10, width: this.props.width, maxWidth: this.props.width }}>
+ <input className="keys-search" style={{ width: "100%" }}
+ ref={this._inputRef} type="text" value={this._searchTerm} placeholder="Column key" onKeyDown={this.onKeyDown}
+ onChange={e => this.onChange(e.target.value)}
+ onClick={(e) => {
+ //this._inputRef.current!.select();
+ e.stopPropagation();
+ }} onFocus={this.onFocus} onBlur={this.onBlur}></input>
+ <div className="keys-options-wrapper" style={{
+ width: this.props.width, maxWidth: this.props.width, height: "auto",
+ }}
+ onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerOut}>
+ {this._searchTerm.includes(":") ? this.renderFilterOptions() : this.renderOptions()}
</div>
- : undefined}
- <input className="keys-search" style={{ width: "100%" }}
- ref={this._inputRef} type="text" value={this._searchTerm} placeholder="Column key" onKeyDown={this.onKeyDown}
- onChange={e => this.onChange(e.target.value)}
- onClick={(e) => {
- //this._inputRef.current!.select();
- e.stopPropagation();
- }} onFocus={this.onFocus} onBlur={this.onBlur}></input>
- <div className="keys-options-wrapper" style={{
- backgroundColor: "white",
- width: this.props.width, maxWidth: this.props.width,
- }}
- onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerOut}>
- {this._key === this._searchTerm.slice(0, this._key.length) ?
- this.renderFilterOptions() : this.renderOptions()}
- </div>
- </div >
+ </div >
+ </div>
);
}
}
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index ba0a259c5..5c2931a8b 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -43,6 +43,49 @@
// }
}
+.collectionSchemaView-searchContainer {
+ border-width: $COLLECTION_BORDER_WIDTH;
+ border-color: $intermediate-color;
+ border-style: solid;
+ border-radius: $border-radius;
+ box-sizing: border-box;
+ position: relative;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ margin-top: 0;
+ transition: top 0.5s;
+ display: flex;
+ justify-content: space-between;
+ flex-wrap: nowrap;
+ touch-action: none;
+
+ div {
+ touch-action: none;
+ }
+
+
+ .collectionSchemaView-tableContainer {
+ width: 100%;
+ height: 100%;
+ }
+
+ .collectionSchemaView-dividerDragger {
+ position: relative;
+ height: 100%;
+ width: 20px;
+ z-index: 20;
+ right: 0;
+ top: 0;
+ background: gray;
+ cursor: col-resize;
+ }
+
+ // .documentView-node:first-child {
+ // background: $light-color;
+ // }
+}
+
.ReactTable {
width: 100%;
background: white;
@@ -165,7 +208,7 @@
.collectionSchema-header-menu {
- height: 100%;
+ height: auto;
z-index: 100;
position: absolute;
background:white;
@@ -280,11 +323,9 @@ button.add-column {
background-color: white;
.key-option {
- //background-color: $light-color;
background-color: white;
border: 1px solid lightgray;
padding: 2px 3px;
-
&:not(:first-child) {
border-top: 0;
}
@@ -315,12 +356,53 @@ button.add-column {
}
}
+.altcollectionTimeView-treeView {
+ display: flex;
+ flex-direction: column;
+ width: 175px;
+ height: auto;
+ position: fixed;
+ border-left: solid 1px;
+ z-index: 1;
+
+ .collectionTimeView-addfacet {
+ display: inline-block;
+ width: 200px;
+ height: 30px;
+ background: darkGray;
+ text-align: left;
+
+ .collectionTimeView-button {
+ align-items: center;
+ display: flex;
+ width: 100%;
+ height: 100%;
+
+ .collectionTimeView-span {
+ margin: auto;
+ }
+ }
+
+ >div,
+ >div>div {
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ .altcollectionTimeView-tree {
+ display: inline-block;
+ width: 100%;
+ height: calc(100% - 30px);
+ }
+}
+
.collectionSchema-row {
height: 100%;
background-color: white;
&.row-focused .rt-td {
- background-color: rgb(255, 246, 246); //$light-color-secondary;
+ background-color: #bfffc0; //$light-color-secondary;
}
&.row-wrapped {
@@ -383,6 +465,9 @@ button.add-column {
.collectionSchemaView-cellWrapper {
height: 100%;
padding: 4px;
+ text-align:left;
+ padding-left:19px;
+
position: relative;
&:focus {
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index a003de0d3..f1de3cee7 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -11,7 +11,7 @@ import { Doc } from "../../../fields/Doc";
import { List } from "../../../fields/List";
import { listSpec } from "../../../fields/Schema";
import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
-import { Cast, NumCast } from "../../../fields/Types";
+import { Cast, NumCast, BoolCast } from "../../../fields/Types";
import { TraceMobx } from "../../../fields/util";
import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents } from "../../../Utils";
import { SnappingManager } from "../../util/SnappingManager";
@@ -71,8 +71,18 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
@observable _pointerY = 0;
@observable _openTypes: boolean = false;
@computed get menuCoordinates() {
- const x = Math.max(0, Math.min(document.body.clientWidth - this._menuWidth, this._pointerX));
- const y = Math.max(0, Math.min(document.body.clientHeight - this._menuHeight, this._pointerY));
+ let searchx = 0;
+ let searchy = 0;
+ if (this.props.Document._searchDoc !== undefined) {
+ const el = document.getElementsByClassName("collectionSchemaView-searchContainer")[0];
+ if (el !== undefined) {
+ const rect = el.getBoundingClientRect();
+ searchx = rect.x;
+ searchy = rect.y;
+ }
+ }
+ const x = Math.max(0, Math.min(document.body.clientWidth - this._menuWidth, this._pointerX)) - searchx;
+ const y = Math.max(0, Math.min(document.body.clientHeight - this._menuHeight, this._pointerY)) - searchy;
return this.props.ScreenToLocalTransform().transformPoint(x, y);
}
@@ -110,7 +120,9 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
document.removeEventListener("pointerdown", this.detectClick);
}
- @action setHeaderIsEditing = (isEditing: boolean) => this._headerIsEditing = isEditing;
+ @action setHeaderIsEditing = (isEditing: boolean) => {
+ this._headerIsEditing = isEditing;
+ }
detectClick = (e: PointerEvent): void => {
if (this._node && this._node.contains(e.target as Node)) {
@@ -356,17 +368,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
@action
closeHeader = () => { this._headerOpen = false; }
- renderKeysDropDown = (col: any) => {
- return <KeysDropdown
- keyValue={col.heading}
- possibleKeys={this.possibleKeys}
- existingKeys={this.columns.map(c => c.heading)}
- canAddNew={true}
- addNew={false}
- onSelect={this.changeColumns}
- setIsEditing={this.setHeaderIsEditing}
- />;
- }
+
@undoBatch
@action
@@ -405,10 +407,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
@computed get renderMenuContent() {
TraceMobx();
return <div className="collectionSchema-header-menuOptions">
- <div className="collectionSchema-headerMenu-group">
- <label>Key:</label>
- {this.renderKeysDropDown(this._col)}
- </div>
{this.renderTypes(this._col)}
{this.renderSorting(this._col)}
{this.renderColors(this._col)}
@@ -424,7 +422,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
super.CreateDropTarget(ele);
}
- isFocused = (doc: Doc): boolean => this.props.isSelected() && doc === this._focusedTable;
+ isFocused = (doc: Doc, outsideReaction: boolean): boolean => this.props.isSelected(outsideReaction) && doc === this._focusedTable;
@action setFocused = (doc: Doc) => this._focusedTable = doc;
@@ -611,14 +609,18 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
onKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
}
render() {
+ let name = "collectionSchemaView-container";
+ if (this.props.Document._searchDoc !== undefined) {
+ name = "collectionSchemaView-searchContainer";
+ }
TraceMobx();
const menuContent = this.renderMenuContent;
const menu = <div className="collectionSchema-header-menu" ref={this.setNode}
onWheel={e => this.onZoomMenu(e)}
onPointerDown={e => this.onHeaderClick(e)}
style={{
- position: "fixed", background: "white",
- transform: `translate(${this.menuCoordinates[0] / this.scale}px, ${this.menuCoordinates[1] / this.scale}px)`
+ position: "fixed", background: "white", border: "black 1px solid",
+ transform: `translate(${(this.menuCoordinates[0] / this.scale)}px, ${(this.menuCoordinates[1] / this.scale)}px)`
}}>
<Measure offset onResize={action((r: any) => {
const dim = this.props.ScreenToLocalTransform().inverse().transformDirection(r.offset.width, r.offset.height);
@@ -627,11 +629,11 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
{({ measureRef }) => <div ref={measureRef}> {menuContent} </div>}
</Measure>
</div>;
- return <div className="collectionSchemaView-container"
+ return <div className={name}
style={{
- overflow: this.props.overflow === true ? "auto" : undefined,
+ overflow: this.props.overflow === true ? "scroll" : undefined,
pointerEvents: !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined,
- width: this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
+ width: name === "collectionSchemaView-searchContainer" ? "auto" : this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
}} >
<div className="collectionSchemaView-tableContainer"
style={{ backgroundColor: "white", width: `calc(100% - ${this.previewWidth()}px)` }}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index b27af66ba..fe3d57bdb 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -4,7 +4,7 @@ import { CursorProperty } from "csstype";
import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import Switch from 'rc-switch';
-import { DataSym, Doc, HeightSym, WidthSym, DocListCastAsync } from "../../../fields/Doc";
+import { DataSym, Doc, HeightSym, WidthSym } from "../../../fields/Doc";
import { collectionSchema, documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
import { List } from "../../../fields/List";
@@ -28,7 +28,6 @@ import { CollectionViewType } from "./CollectionView";
import { SnappingManager } from "../../util/SnappingManager";
import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
import { DocUtils } from "../../documents/Documents";
-import { MainViewNotifs } from "../MainViewNotifs";
const _global = (window /* browser */ || global /* node */) as any;
type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>;
@@ -299,10 +298,6 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
const srcInd = docs.indexOf(doc);
docs.splice(srcInd, 1);
docs.splice((targInd > srcInd ? targInd - 1 : targInd) + plusOne, 0, doc);
- DocListCastAsync(docs).then(resolvedDocs => {
- const pos = resolvedDocs?.findIndex(shareDoc => shareDoc.icon === "users") || 0; // hopefully find out if the sharing doc has been moved
- if (MainViewNotifs.NotifsCol && pos !== -1) MainViewNotifs.NotifsCol.position = pos;
- });
} else if (i < (newDocs.length / 2)) { //glr: for some reason dragged documents are duplicated
if (targInd === -1) targInd = docs.length;
else targInd = docs.indexOf(newDocs[0]) + 1;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index d1aeb1b65..3f2ad47a5 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -112,10 +112,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
[...this.props.docFilters(), ...Cast(this.props.Document._docFilters, listSpec("string"), [])];
}
@computed get childDocs() {
- let rawdocs: (Doc | Promise<Doc>)[] = DocListCast(this.props.Document._searchDocs);
-
- if (rawdocs.length !== 0) {
- } else if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list;
+ let rawdocs: (Doc | Promise<Doc>)[] = [];
+ if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list;
rawdocs = [this.dataField];
} else if (Cast(this.dataField, listSpec(Doc), null)) { // otherwise, if the collection data is a list, then use it.
rawdocs = Cast(this.dataField, listSpec(Doc), null);
@@ -128,30 +126,25 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
const docs = rawdocs.filter(d => !(d instanceof Promise)).map(d => d as Doc);
const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
- let childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
+ const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
+
+ let searchDocs = DocListCast(this.props.Document._searchDocs);
- const searchDocs = DocListCast(this.props.Document._searchDocs);
- // if (searchDocs !== undefined && searchDocs.length > 0) {
- // let newdocs: Doc[] = [];
- // childDocs.forEach((el) => {
- // searchDocs.includes(el) ? newdocs.push(el) : undefined;
- // });
- // childDocs = newdocs;
- // }
let docsforFilter: Doc[] = childDocs;
+
if (searchDocs !== undefined && searchDocs.length > 0) {
docsforFilter = [];
- // let newdocs: Doc[] = [];
- // let newarray: Doc[] = [];
- //while (childDocs.length > 0) {
- //newarray = [];
+ const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
+ console.log(searchDocs);
+ searchDocs = DocUtils.FilterDocs(searchDocs, this.docFilters(), docRangeFilters, viewSpecScript);
+ console.log(this.docFilters());
+ console.log(searchDocs);
childDocs.forEach((d) => {
if (d.data !== undefined) {
- console.log(d);
let newdocs = DocListCast(d.data);
if (newdocs.length > 0) {
- let vibecheck: boolean | undefined = undefined;
+ let displaycheck: boolean | undefined = undefined;
let newarray: Doc[] = [];
while (newdocs.length > 0) {
newarray = [];
@@ -163,12 +156,12 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
});
}
if (searchDocs.includes(t)) {
- vibecheck = true;
+ displaycheck = true;
}
});
newdocs = newarray;
}
- if (vibecheck === true) {
+ if (displaycheck === true) {
docsforFilter.push(d);
}
}
@@ -177,14 +170,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
docsforFilter.push(d);
}
});
- //childDocs = newarray;
- //}
+ return docsforFilter;
}
- childDocs = docsforFilter;
-
const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
-
- return this.props.Document.dontRegisterView ? docs : DocUtils.FilterDocs(docs, this.docFilters(), docRangeFilters, viewSpecScript);
+ return this.props.Document.dontRegisterView ? childDocs : DocUtils.FilterDocs(childDocs, this.docFilters(), docRangeFilters, viewSpecScript);
}
@action
@@ -251,6 +240,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.props.Document);
added = docDragData.moveDocument(movedDocs, this.props.Document, canAdd ? this.addDocument : returnFalse);
} else added = res;
+ !added && alert("You don't have permission to perform this move");
+ e.stopPropagation();
} else {
ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData });
added = this.addDocument(docDragData.droppedDocuments);
@@ -343,7 +334,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
let srcWeb: Doc | undefined;
if (SelectionManager.SelectedDocuments().length) {
srcWeb = SelectionManager.SelectedDocuments()[0].props.Document;
- srcUrl = (srcWeb.data as WebField).url.href?.match(/http[s]?:\/\/[^/]*/)?.[0];
+ srcUrl = (srcWeb.data as WebField).url?.href?.match(/http[s]?:\/\/[^/]*/)?.[0];
}
const reg = new RegExp(Utils.prepend(""), "g");
const modHtml = srcUrl ? html.replace(reg, srcUrl) : html;
@@ -351,7 +342,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
Doc.GetProto(htmlDoc)["data-text"] = Doc.GetProto(htmlDoc).text = text;
this.props.addDocument(htmlDoc);
if (srcWeb) {
- const focusNode = (SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")[0].contentDocument?.getSelection()?.focusNode as any);
+ const focusNode = (SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")?.[0].contentDocument?.getSelection()?.focusNode as any);
if (focusNode) {
const rect = "getBoundingClientRect" in focusNode ? focusNode.getBoundingClientRect() : focusNode?.parentElement.getBoundingClientRect();
const x = (rect?.x || 0);
@@ -481,7 +472,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
completed?.();
} else {
if (text && !text.includes("https://")) {
- this.addDocument(Docs.Create.TextDocument(text, { ...options, _width: 400, _height: 315 }));
+ UndoManager.RunInBatch(() => this.addDocument(Docs.Create.TextDocument(text, { ...options, title: text.substring(0, 20), _width: 400, _height: 315 })), "drop");
}
}
disposer();
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 3c7471d7c..d096e7d66 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -53,7 +53,7 @@ export interface TreeViewProps {
indentDocument?: () => void;
outdentDocument?: () => void;
ScreenToLocalTransform: () => Transform;
- backgroundColor?: (doc: Doc) => string | undefined;
+ backgroundColor?: (doc: Doc, renderDepth: number) => string | undefined;
outerXf: () => { translateX: number, translateY: number };
treeViewDoc: Doc;
parentKey: string;
@@ -88,7 +88,7 @@ class TreeView extends React.Component<TreeViewProps> {
get doc() { return this.props.document; }
get noviceMode() { return BoolCast(Doc.UserDoc().noviceMode, false); }
get displayName() { return "TreeView(" + this.doc.title + ")"; } // this makes mobx trace() statements more descriptive
- get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.doc.defaultExpandedView, this.noviceMode ? "layout" : "fields"); }
+ get defaultExpandedView() { return this.childDocs.length ? this.fieldKey : StrCast(this.doc.defaultExpandedView, this.noviceMode ? "layout" : "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;
@@ -108,6 +108,7 @@ class TreeView extends React.Component<TreeViewProps> {
}
@computed get childDocs() { return this.childDocList(this.fieldKey); }
@computed get childLinks() { return this.childDocList("links"); }
+ @computed get childAnnos() { return this.childDocList(this.fieldKey + "-annotations"); }
@computed get boundsOfCollectionDocument() {
return StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1 || !DocListCast(this.props.document[this.fieldKey]).length ? undefined :
Doc.ComputeContentBounds(DocListCast(this.props.document[this.fieldKey]));
@@ -127,7 +128,7 @@ class TreeView extends React.Component<TreeViewProps> {
constructor(props: any) {
super(props);
- const script = ScriptField.MakeScript(`{setInPlace(self, 'editTitle', '${this._uniqueId}'); selectDoc(self);} `);
+ const script = ScriptField.MakeScript(`{setInPlace(self, 'editTitle', '${this._uniqueId}'); documentView.select();} `, { documentView: "any" });
this._editTitleScript = script && (() => script);
if (Doc.GetT(this.doc, "editTitle", "string", true) === "*") Doc.SetInPlace(this.doc, "editTitle", this._uniqueId, false);
}
@@ -313,11 +314,11 @@ class TreeView extends React.Component<TreeViewProps> {
@computed get renderContent() {
TraceMobx();
const expandKey = this.treeViewExpandedView;
- if (["links", this.fieldKey].includes(expandKey)) {
+ if (["links", "annotations", this.fieldKey].includes(expandKey)) {
const remDoc = (doc: Doc | Doc[]) => this.remove(doc, expandKey);
const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) =>
(doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true), true);
- const docs = expandKey === "links" ? this.childLinks : this.childDocs;
+ const docs = expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs;
const sortKey = `${this.fieldKey}-sortAscending`;
return <ul key={expandKey + "more"} onClick={(e) => {
this.doc[sortKey] = (this.doc[sortKey] ? false : (this.doc[sortKey] === false ? undefined : true));
@@ -397,7 +398,7 @@ class TreeView extends React.Component<TreeViewProps> {
title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
onClick={this.bulletClick}
style={{ color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"), opacity: checked === "unchecked" ? undefined : 0.4 }}>
- {<FontAwesomeIcon icon={checked === "check" ? "check" : (checked === "x" ? "times" : checked === "unchecked" ? "square" : !this.treeViewOpen ? (this.childDocs ? "caret-square-right" : "caret-right") : (this.childDocs ? "caret-square-down" : "caret-down"))} />}
+ {<FontAwesomeIcon icon={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"))} />}
</div>;
}
@@ -424,7 +425,8 @@ class TreeView extends React.Component<TreeViewProps> {
this.doc.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? (Doc.UserDoc().noviceMode ? "layout" : "fields") :
this.treeViewExpandedView === "fields" && this.layoutDoc ? "layout" :
this.treeViewExpandedView === "layout" && DocListCast(this.doc.links).length ? "links" :
- this.childDocs ? this.fieldKey : (Doc.UserDoc().noviceMode ? "layout" : "fields");
+ (this.treeViewExpandedView === "links" || this.treeViewExpandedView === "layout") && DocListCast(this.doc[this.fieldKey + "-annotations"]).length ? "annotations" :
+ this.childDocs.length ? this.fieldKey : (Doc.UserDoc().noviceMode ? "layout" : "fields");
}
this.treeViewOpen = true;
})}>
@@ -453,6 +455,7 @@ class TreeView extends React.Component<TreeViewProps> {
NativeHeight={returnZero}
NativeWidth={returnZero}
contextMenuItems={this.contextMenuItems}
+ opacity={returnOne}
renderDepth={1}
focus={returnTrue}
parentActive={returnTrue}
@@ -475,7 +478,7 @@ class TreeView extends React.Component<TreeViewProps> {
</div >
{headerElements}
<div className="treeViewItem-openRight" onClick={this.openRight}>
- <FontAwesomeIcon title="open in pane on right" icon="external-link-alt" size="sm" />
+ <FontAwesomeIcon title="open in a new pane" icon="external-link-alt" size="sm" />
</div>
</>;
}
@@ -494,7 +497,7 @@ class TreeView extends React.Component<TreeViewProps> {
}
}
} else this._editMaxWidth = "";
- return <div className="treeViewItem-container" ref={this.createTreeDropTarget} onPointerDown={e => this.props.active() && SelectionManager.DeselectAll()}>
+ return <div className="treeViewItem-container" ref={this.createTreeDropTarget} onPointerDown={e => this.props.active(true) && SelectionManager.DeselectAll()}>
<li className="collection-child">
<div className={`treeViewItem-header` + (this._editMaxWidth ? "-editing" : "")} ref={this._header} style={{ maxWidth: this._editMaxWidth }} onClick={e => {
if (this.props.active(true)) {
@@ -533,7 +536,7 @@ class TreeView extends React.Component<TreeViewProps> {
dropAction: dropActionType,
addDocTab: (doc: Doc, where: string) => boolean,
pinToPres: (document: Doc) => void,
- backgroundColor: undefined | ((document: Doc) => string | undefined),
+ backgroundColor: undefined | ((document: Doc, renderDepth: number) => string | undefined),
screenToLocalXf: () => Transform,
outerXf: () => { translateX: number, translateY: number },
active: (outsideReaction?: boolean) => boolean,
@@ -813,7 +816,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
<div className="collectionTreeView-container" onContextMenu={this.onContextMenu}>
<div className="collectionTreeView-dropTarget" id="body"
style={{
- background: this.props.backgroundColor?.(this.doc),
+ background: this.props.backgroundColor?.(this.doc, this.props.renderDepth),
paddingLeft: `${NumCast(this.doc._xPadding, 10)}px`,
paddingRight: `${NumCast(this.doc._xPadding, 10)}px`,
paddingTop: `${NumCast(this.doc._yPadding, 20)}px`,
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 0feec3fbd..6dd21ef7f 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -46,6 +46,7 @@ import { CollectionTimeView } from './CollectionTimeView';
import { CollectionTreeView } from "./CollectionTreeView";
import './CollectionView.scss';
import { ContextMenuProps } from '../ContextMenuItem';
+import { table } from 'console';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -141,7 +142,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
const targetDataDoc = this.props.Document[DataSym];
const docList = DocListCast(targetDataDoc[this.props.fieldKey]);
const added = docs.filter(d => !docList.includes(d));
- const effectiveAcl = GetEffectiveAcl(this.props.Document);
+ const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
if (added.length) {
if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) {
@@ -182,6 +183,8 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
// targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
(targetDataDoc[this.props.fieldKey] as List<Doc>).push(...added);
targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+ const lastModified = "lastModified";
+ targetDataDoc[lastModified] = new DateField(new Date(Date.now()));
}
}
}
@@ -190,16 +193,19 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
@action.bound
removeDocument = (doc: any): boolean => {
- const collectionEffectiveAcl = GetEffectiveAcl(this.props.Document);
- const docEffectiveAcl = GetEffectiveAcl(doc);
- // you can remove the document if you either have Admin/Edit access to the collection or to the specific document
- if (collectionEffectiveAcl === AclEdit || collectionEffectiveAcl === AclAdmin || docEffectiveAcl === AclAdmin || docEffectiveAcl === AclEdit) {
+ const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
+ if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) {
const docs = doc instanceof Doc ? [doc] : doc as Doc[];
const targetDataDoc = this.props.Document[DataSym];
const value = DocListCast(targetDataDoc[this.props.fieldKey]);
const toRemove = value.filter(v => docs.includes(v));
if (toRemove.length !== 0) {
- toRemove.forEach(doc => Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey, doc));
+ const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc;
+ toRemove.forEach(doc => {
+ Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey, doc);
+ recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true);
+ doc.deleted = true;
+ });
return true;
}
}
@@ -216,7 +222,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
return true;
}
const first = doc instanceof Doc ? doc : doc[0];
- if (!first?.stayInCollection && addDocument !== returnFalse) {
+ if (!first?._stayInCollection && addDocument !== returnFalse) {
if (UndoManager.RunInTempBatch(() => this.removeDocument(doc))) {
const added = addDocument(doc);
if (!added) UndoManager.UndoTempBatch();
@@ -510,56 +516,56 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
</label>)}
</div>
);
- return !this._facetWidth || this.props.dontRegisterView ? (null) :
- <div className="collectionTimeView-treeView" style={{ width: `${this.facetWidth()}px`, overflow: this.facetWidth() < 15 ? "hidden" : undefined }}>
- <div className="collectionTimeView-addFacet" style={{ width: `${this.facetWidth()}px` }} onPointerDown={e => e.stopPropagation()}>
- <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
- <div className="collectionTimeView-button">
- <FontAwesomeIcon icon={faEdit} size={"lg"} />
- <span className="collectionTimeView-span">Facet Filters</span>
- </div>
- </Flyout>
- </div>
- <div className="collectionTimeView-tree" key="tree">
- <CollectionTreeView
- PanelPosition={""}
- Document={facetCollection}
- DataDoc={facetCollection}
- fieldKey={`${this.props.fieldKey}-filter`}
- CollectionView={this}
- docFilters={returnEmptyFilter}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}
- ContainingCollectionView={this.props.ContainingCollectionView}
- PanelWidth={this.facetWidth}
- PanelHeight={this.props.PanelHeight}
- NativeHeight={returnZero}
- NativeWidth={returnZero}
- LibraryPath={emptyPath}
- rootSelected={this.props.rootSelected}
- renderDepth={1}
- dropAction={this.props.dropAction}
- ScreenToLocalTransform={this.props.ScreenToLocalTransform}
- addDocTab={returnFalse}
- pinToPres={returnFalse}
- isSelected={returnFalse}
- select={returnFalse}
- bringToFront={emptyFunction}
- active={this.props.active}
- whenActiveChanged={returnFalse}
- treeViewHideTitle={true}
- ContentScaling={returnOne}
- focus={returnFalse}
- treeViewHideHeaderFields={true}
- onCheckedClick={this.scriptField}
- ignoreFields={this.ignoreFields}
- annotationsKey={""}
- dontRegisterView={true}
- backgroundColor={this.filterBackground}
- moveDocument={returnFalse}
- removeDocument={returnFalse}
- addDocument={returnFalse} />
- </div>
- </div>;
+
+ return !this._facetWidth || this.props.dontRegisterView ? (null) : <div className="collectionTimeView-treeView" style={{ width: `${this.facetWidth()}px`, overflow: this.facetWidth() < 15 ? "hidden" : undefined }}>
+ <div className="collectionTimeView-addFacet" style={{ width: `${this.facetWidth()}px` }} onPointerDown={e => e.stopPropagation()}>
+ <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
+ <div className="collectionTimeView-button">
+ <FontAwesomeIcon icon={faEdit} size={"lg"} />
+ <span className="collectionTimeView-span">Facet Filters</span>
+ </div>
+ </Flyout>
+ </div>
+ <div className="collectionTimeView-tree" key="tree">
+ <CollectionTreeView
+ PanelPosition={""}
+ Document={facetCollection}
+ DataDoc={facetCollection}
+ fieldKey={`${this.props.fieldKey}-filter`}
+ CollectionView={this}
+ docFilters={returnEmptyFilter}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+ ContainingCollectionView={this.props.ContainingCollectionView}
+ PanelWidth={this.facetWidth}
+ PanelHeight={this.props.PanelHeight}
+ NativeHeight={returnZero}
+ NativeWidth={returnZero}
+ LibraryPath={emptyPath}
+ rootSelected={this.props.rootSelected}
+ renderDepth={1}
+ dropAction={this.props.dropAction}
+ ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+ addDocTab={returnFalse}
+ pinToPres={returnFalse}
+ isSelected={returnFalse}
+ select={returnFalse}
+ bringToFront={emptyFunction}
+ active={this.props.active}
+ whenActiveChanged={returnFalse}
+ treeViewHideTitle={true}
+ ContentScaling={returnOne}
+ focus={returnFalse}
+ treeViewHideHeaderFields={true}
+ onCheckedClick={this.scriptField}
+ ignoreFields={this.ignoreFields}
+ annotationsKey={""}
+ dontRegisterView={true}
+ backgroundColor={this.filterBackground}
+ moveDocument={returnFalse}
+ removeDocument={returnFalse}
+ addDocument={returnFalse} />
+ </div>
+ </div>;
}
childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null);
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 4c8cac3ed..149d4927b 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -15,6 +15,7 @@ import { faCog, faChevronCircleUp } from "@fortawesome/free-solid-svg-icons";
import { library } from "@fortawesome/fontawesome-svg-core";
import { DocumentView } from "../nodes/DocumentView";
import { SelectionManager } from "../../util/SelectionManager";
+import { Tooltip } from "@material-ui/core";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -121,16 +122,17 @@ export class DockingViewButtonSelector extends React.Component<{ views: () => Do
}
render() {
- return <span title="Tap for menu, drag tab as document"
- onPointerDown={e => {
+ return <Tooltip title={<><div className="dash-tooltip">Tap for toolbar, drag to create alias in another pane</div></>} placement="bottom">
+ <span onPointerDown={e => {
if (getComputedStyle(this._ref.current!).width !== "100%") {
e.stopPropagation(); e.preventDefault();
}
this.props.views()[0]?.select(false);
}} className="buttonSelector">
- <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.flyout} stylesheet={this.customStylesheet}>
- <FontAwesomeIcon icon={"arrows-alt"} size={"sm"} />
- </Flyout>
- </span>;
+ <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.flyout} stylesheet={this.customStylesheet}>
+ <FontAwesomeIcon icon={"arrows-alt"} size={"sm"} />
+ </Flyout>
+ </span>
+ </Tooltip>;
}
}
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index a974c5496..a2c529a21 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -63,12 +63,12 @@ export interface SchemaTableProps {
addDocument: (document: Doc | Doc[]) => boolean;
moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
ScreenToLocalTransform: () => Transform;
- active: (outsideReaction: boolean) => boolean;
+ active: (outsideReaction: boolean | undefined) => boolean;
onDrop: (e: React.DragEvent<Element>, options: DocumentOptions, completed?: (() => void) | undefined) => void;
addDocTab: (document: Doc, where: string) => boolean;
pinToPres: (document: Doc) => void;
isSelected: (outsideReaction?: boolean) => boolean;
- isFocused: (document: Doc) => boolean;
+ isFocused: (document: Doc, outsideReaction: boolean) => boolean;
setFocused: (document: Doc) => void;
setPreviewDoc: (document: Doc) => void;
columns: SchemaHeaderField[];
@@ -155,7 +155,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
const possibleKeys = this.props.documentKeys.filter(key => this.props.columns.findIndex(existingKey => existingKey.heading.toUpperCase() === key.toUpperCase()) === -1);
const columns: Column<Doc>[] = [];
- const tableIsFocused = this.props.isFocused(this.props.Document);
+ const tableIsFocused = this.props.isFocused(this.props.Document, false);
const focusedRow = this._focusedCell.row;
const focusedCol = this._focusedCell.col;
const isEditable = !this.props.headerIsEditing;
@@ -177,8 +177,13 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
}
);
}
+ this.props.active;
const cols = this.props.columns.map(col => {
+ const icon: IconProp = this.getColumnType(col) === ColumnType.Number ? "hashtag" : this.getColumnType(col) === ColumnType.String ? "font" :
+ this.getColumnType(col) === ColumnType.Boolean ? "check-square" : this.getColumnType(col) === ColumnType.Doc ? "file" :
+ this.getColumnType(col) === ColumnType.Image ? "image" : this.getColumnType(col) === ColumnType.List ? "list-ul" :
+ this.getColumnType(col) === ColumnType.Date ? "calendar" : "align-justify";
const keysDropdown = <KeysDropdown
keyValue={col.heading}
@@ -189,24 +194,20 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
onSelect={this.props.changeColumns}
setIsEditing={this.props.setHeaderIsEditing}
docs={this.props.childDocs}
+ Document={this.props.Document}
+ dataDoc={this.props.dataDoc}
+ fieldKey={this.props.fieldKey}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+ ContainingCollectionView={this.props.ContainingCollectionView}
+ active={this.props.active}
+ openHeader={this.props.openHeader}
+ icon={icon}
+ col={col}
// try commenting this out
width={"100%"}
/>;
- const icon: IconProp = this.getColumnType(col) === ColumnType.Number ? "hashtag" : this.getColumnType(col) === ColumnType.String ? "font" :
- this.getColumnType(col) === ColumnType.Boolean ? "check-square" : this.getColumnType(col) === ColumnType.Doc ? "file" :
- this.getColumnType(col) === ColumnType.Image ? "image" : this.getColumnType(col) === ColumnType.List ? "list-ul" :
- this.getColumnType(col) === ColumnType.Date ? "calendar" : "align-justify";
- const headerText = this._showTitleDropdown ? keysDropdown : <div
- onClick={this.changeTitleMode}
- style={{
- background: col.color, padding: "2px",
- letterSpacing: "2px",
- textTransform: "uppercase",
- display: "flex"
- }}>
- {col.heading}</div>;
const sortIcon = col.desc === undefined ? "caret-right" : col.desc === true ? "caret-down" : "caret-up";
@@ -218,19 +219,12 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
background: col.color, padding: "2px",
display: "flex", cursor: "default", height: "100%",
}}>
- <FontAwesomeIcon icon={icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px" }} />
- {/* <div className="keys-dropdown"
- style={{ display: "inline", zIndex: 1000 }}> */}
+ {/* <FontAwesomeIcon onClick={e => this.props.openHeader(col, e.clientX, e.clientY)} icon={icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} /> */}
{keysDropdown}
- {/* </div> */}
<div onClick={e => this.changeSorting(col)}
- style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit" }}>
+ style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "hand" }}>
<FontAwesomeIcon icon={sortIcon} size="lg" />
</div>
- {/* <div onClick={e => this.props.openHeader(col, e.clientX, e.clientY)}
- style={{ float: "right", paddingRight: "6px", zIndex: 1, background: "inherit" }}>
- <FontAwesomeIcon icon={"compass"} size="sm" />
- </div> */}
</div>;
return {
@@ -318,27 +312,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
}
-
- @action
- nextHighlight = (e: React.MouseEvent, doc: Doc) => {
- e.preventDefault();
- e.stopPropagation();
- doc.searchMatch = false;
- console.log(doc.searchMatch);
- setTimeout(() => doc.searchMatch = true, 0);
- console.log(doc.searchMatch);
-
- doc.searchIndex = NumCast(doc.searchIndex);
- }
-
- @action
- nextHighlight2 = (doc: Doc) => {
-
- doc.searchMatchAlt = false;
- setTimeout(() => doc.searchMatchAlt = true, 0);
- doc.searchIndex = NumCast(doc.searchIndex);
- }
-
constructor(props: SchemaTableProps) {
super(props);
// convert old schema columns (list of strings) into new schema columns (list of schema header fields)
@@ -347,7 +320,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
const newSchemaHeaders = oldSchemaHeaders.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i);
this.props.Document._schemaHeaders = new List<SchemaHeaderField>(newSchemaHeaders);
} else if (this.props.Document._schemaHeaders === undefined) {
- this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb")]);
+ this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb"), new SchemaHeaderField("author", "#f1efeb"), new SchemaHeaderField("*lastModified", "#f1efeb"),
+ new SchemaHeaderField("text", "#f1efeb"), new SchemaHeaderField("type", "#f1efeb"), new SchemaHeaderField("context", "#f1efeb")]);
}
}
@@ -369,7 +343,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
addDoc: this.tableAddDoc,
removeDoc: this.props.deleteDocument,
rowInfo,
- rowFocused: !this.props.headerIsEditing && rowInfo.index === this._focusedCell.row && this.props.isFocused(this.props.Document),
+ rowFocused: !this.props.headerIsEditing && rowInfo.index === this._focusedCell.row && this.props.isFocused(this.props.Document, true),
textWrapRow: this.toggleTextWrapRow,
rowWrapped: this.textWrappedRows.findIndex(id => rowInfo.original[Id] === id) > -1,
dropAction: StrCast(this.props.Document.childDropAction),
@@ -383,7 +357,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
const row = rowInfo.index;
//@ts-ignore
const col = this.columns.map(c => c.heading).indexOf(column!.id);
- const isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document);
+ const isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document, true);
// TODO: editing border doesn't work :(
return {
style: {
@@ -403,7 +377,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
@action
onKeyDown = (e: KeyboardEvent): void => {
- if (!this._cellIsEditing && !this.props.headerIsEditing && this.props.isFocused(this.props.Document)) {// && this.props.isSelected(true)) {
+ if (!this._cellIsEditing && !this.props.headerIsEditing && this.props.isFocused(this.props.Document, true)) {// && this.props.isSelected(true)) {
const direction = e.key === "Tab" ? "tab" : e.which === 39 ? "right" : e.which === 37 ? "left" : e.which === 38 ? "up" : e.which === 40 ? "down" : "";
this._focusedCell = this.changeFocusedCellByDirection(direction, this._focusedCell.row, this._focusedCell.col);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 163554db9..46e30f616 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -15,7 +15,7 @@ import { ScriptField } from "../../../../fields/ScriptField";
import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
import { TraceMobx } from "../../../../fields/util";
import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
-import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, Utils } from "../../../../Utils";
+import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, Utils, setupMoveUpEvents } from "../../../../Utils";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
import { DocServer } from "../../../DocServer";
import { Docs, DocUtils } from "../../../documents/Documents";
@@ -378,7 +378,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
getClusterColor = (doc: Doc) => {
- let clusterColor = this.props.backgroundColor?.(doc);
+ let clusterColor = this.props.backgroundColor?.(doc, this.props.renderDepth + 1);
const cluster = NumCast(doc.cluster);
if (this.Document.useClusters) {
if (this._clusterSets.length <= cluster) {
@@ -1200,27 +1200,29 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.props.addDocTab(childDocs as any as Doc, "inParent");
this.props.ContainingCollectionView?.removeDocument(this.props.Document);
}));
- layoutDocsInGrid = () => {
- UndoManager.RunInBatch(() => {
- const docs = this.childLayoutPairs;
- const startX = this.Document._panX || 0;
- let x = startX;
- let y = this.Document._panY || 0;
- let i = 0;
- const width = Math.max(...docs.map(doc => NumCast(doc.layout._width)));
- const height = Math.max(...docs.map(doc => NumCast(doc.layout._height)));
- docs.forEach(pair => {
- pair.layout.x = x;
- pair.layout.y = y;
- x += width + 20;
- if (++i === 6) {
- i = 0;
- x = startX;
- y += height + 20;
- }
- });
- }, "arrange contents");
- }
+
+
+ @undoBatch
+ layoutDocsInGrid = action(() => {
+ const docs = this.childLayoutPairs;
+ const startX = this.Document._panX || 0;
+ let x = startX;
+ let y = this.Document._panY || 0;
+ let i = 0;
+ const width = Math.max(...docs.map(doc => NumCast(doc.layout._width)));
+ const height = Math.max(...docs.map(doc => NumCast(doc.layout._height)));
+ docs.forEach(pair => {
+ pair.layout.x = x;
+ pair.layout.y = y;
+ x += width + 20;
+ if (++i === 6) {
+ i = 0;
+ x = startX;
+ y += height + 20;
+ }
+ });
+ });
+
@undoBatch
@action
toggleNativeDimensions = () => {
@@ -1495,8 +1497,123 @@ interface CollectionFreeFormViewPannableContentsProps {
@observer
class CollectionFreeFormViewPannableContents extends React.Component<CollectionFreeFormViewPannableContentsProps>{
+ @observable private _drag: string = '';
+
+ //Adds event listener so knows pointer is down and moving
+ onPointerDown = (e: React.PointerEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
+ const corner = e.target as any;
+ console.log(corner.id);
+ if (corner) this._drag = corner.id;
+ const rect = document.getElementById(this._drag);
+ if (rect) {
+ console.log(this._drag);
+ setupMoveUpEvents(e.target, e, this.onPointerMove, (e) => { }, (e) => { });
+ }
+ }
+
+ //Removes all event listeners
+ onPointerUp = (e: PointerEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
+ this._drag = "";
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ }
+
+ //Adjusts the value in NodeStore
+ @action
+ onPointerMove = (e: PointerEvent) => {
+ const doc = document.getElementById('resizable');
+ const rect = doc!.getBoundingClientRect();
+ const toNumber = (original: number, delta: number): number => {
+ return original + (delta * this.props.zoomScaling());
+ };
+ if (doc) {
+ const height = doc.offsetHeight;
+ const width = doc.offsetWidth;
+ const top = doc.offsetTop;
+ const left = doc.offsetLeft;
+ switch (this._drag) {
+ case "": break;
+ case "resizer-br":
+ doc.style.width = toNumber(width, e.movementX) + 'px';
+ doc.style.height = toNumber(height, e.movementY) + 'px';
+ break;
+ case "resizer-bl":
+ doc.style.width = toNumber(width, -e.movementX) + 'px';
+ doc.style.height = toNumber(height, e.movementY) + 'px';
+ doc.style.left = toNumber(left, e.movementX) + 'px';
+ break;
+ case "resizer-tr":
+ doc.style.width = toNumber(width, -e.movementX) + 'px';
+ doc.style.height = toNumber(height, -e.movementY) + 'px';
+ doc.style.top = toNumber(top, e.movementY) + 'px';
+ case "resizer-tl":
+ doc.style.width = toNumber(width, -e.movementX) + 'px';
+ doc.style.height = toNumber(height, -e.movementY) + 'px';
+ doc.style.top = toNumber(top, e.movementY) + 'px';
+ doc.style.left = toNumber(left, e.movementX) + 'px';
+ case "resizable":
+ doc.style.top = toNumber(top, e.movementY) + 'px';
+ doc.style.left = toNumber(left, e.movementX) + 'px';
+ }
+ this.updateAll(height, width, top, left);
+ return false;
+ }
+ return true;
+ }
+
+ @action
+ updateAll = (width: number, height: number, top: number, left: number) => {
+ const activeItem = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ this.updateList(targetDoc, activeItem["viewfinder-width-indexed"], width);
+ this.updateList(targetDoc, activeItem["viewfinder-height-indexed"], height);
+ this.updateList(targetDoc, activeItem["viewfinder-top-indexed"], top);
+ this.updateList(targetDoc, activeItem["viewfinder-left-indexed"], left);
+ }
+
+ @action
+ updateList = (doc: Doc, list: any, val: number) => {
+ const x: List<number> = list;
+ if (x && x.length >= NumCast(doc.currentFrame) + 1) {
+ x[NumCast(doc.currentFrame)] = val;
+ list = x;
+ } else if (doc && x) {
+ x.length = NumCast(doc.currentFrame) + 1;
+ x[NumCast(doc.currentFrame)] = val;
+ list = x;
+ }
+ }
+
+ // scale: NumCast(targetDoc._viewScale),
+ @computed get zoomProgressivizeContainer() {
+ const activeItem = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ if (activeItem && activeItem.zoomProgressivize) {
+ const vfLeft: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-left-indexed"]);
+ const vfWidth: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-width-indexed"]);
+ const vfTop: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-top-indexed"]);
+ const vfHeight: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-height-indexed"]);
+ return (
+ <>
+ {!activeItem.editZoomProgressivize ? (null) : <div id="resizable" className="resizable" onPointerDown={this.onPointerDown} style={{ width: vfWidth, height: vfHeight, top: vfTop, left: vfLeft, position: 'absolute' }}>
+ <div className='resizers'>
+ <div id="resizer-tl" className='resizer top-left' onPointerDown={this.onPointerDown}></div>
+ <div id="resizer-tr" className='resizer top-right' onPointerDown={this.onPointerDown}></div>
+ <div id="resizer-bl" className='resizer bottom-left' onPointerDown={this.onPointerDown}></div>
+ <div id="resizer-br" className='resizer bottom-right' onPointerDown={this.onPointerDown}></div>
+ </div>
+ </div>}
+ </>
+ );
+ }
+ }
+
@computed get zoomProgressivize() {
- return PresBox.Instance && this.props.zoomProgressivize ? PresBox.Instance.zoomProgressivizeContainer : (null);
+ return PresBox.Instance && this.props.zoomProgressivize ? this.zoomProgressivizeContainer : (null);
}
@computed get progressivize() {
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 1a708d67d..c0b19fcd2 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -21,6 +21,7 @@ import { CollectionView } from "../CollectionView";
import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
import "./MarqueeView.scss";
import React = require("react");
+import { ContextMenuItem } from "../../ContextMenuItem";
interface MarqueeViewProps {
getContainerTransform: () => Transform;
@@ -70,23 +71,19 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
onKeyPress = (e: KeyboardEvent) => {
//make textbox and add it to this collection
// tslint:disable-next-line:prefer-const
- let [x, y] = this.props.getTransform().transformPoint(this._downX, this._downY);
+ const cm = ContextMenu.Instance;
+ const [x, y] = this.props.getTransform().transformPoint(this._downX, this._downY);
if (e.key === "?") {
- ContextMenu.Instance.setDefaultItem("?", (str: string) => {
- const textDoc = Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, {
- _width: 200, x, y, _nativeHeight: 962, _nativeWidth: 850, isAnnotating: false,
- title: "bing", UseCors: true
- });
- this.props.addDocTab(textDoc, "onRight");
- });
+ cm.setDefaultItem("?", (str: string) => this.props.addDocTab(
+ Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 200, x, y, _nativeHeight: 962, _nativeWidth: 850, isAnnotating: false, title: "bing", UseCors: true }), "onRight"));
- ContextMenu.Instance.displayMenu(this._downX, this._downY);
+ cm.displayMenu(this._downX, this._downY);
e.stopPropagation();
} else
if (e.key === ":") {
DocUtils.addDocumentCreatorMenuItems(this.props.addLiveTextDocument, this.props.addDocument, x, y);
- ContextMenu.Instance.displayMenu(this._downX, this._downY);
+ cm.displayMenu(this._downX, this._downY);
e.stopPropagation();
} else if (e.key === "a" && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
@@ -108,11 +105,12 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
if (br) break;
}
}
+ let ypos = y;
ns.map(line => {
const indent = line.search(/\S|$/);
- const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + indent / 3 * 10, y: y, title: line });
+ const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + indent / 3 * 10, y: ypos, title: line });
this.props.addDocument(newBox);
- y += 40 * this.props.getTransform().Scale;
+ ypos += 40 * this.props.getTransform().Scale;
});
})();
e.stopPropagation();
@@ -280,7 +278,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
} else {
this._downX = x;
this._downY = y;
- const effectiveAcl = GetEffectiveAcl(this.props.Document);
+ const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
if ([AclAdmin, AclEdit, AclAddonly].includes(effectiveAcl)) PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge);
this.clearSelection();
}
@@ -342,41 +340,33 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@undoBatch
@action
delete = () => {
- const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc;
const selected = this.marqueeSelect(false);
SelectionManager.DeselectAll();
-
- selected.map(doc => {
- const effectiveAcl = GetEffectiveAcl(doc);
- if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) { // deletes whatever you have the right to delete
- recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true);
- this.props.removeDocument(doc);
- }
- });
+ selected.forEach(doc => this.props.removeDocument(doc));
this.cleanupInteractions(false);
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
}
- getCollection = (selected: Doc[], creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, isBackground?: boolean) => {
- const bounds = this.Bounds;
- // const inkData = this.ink ? this.ink.inkData : undefined;
- const newCollection = (creator || Docs.Create.FreeformDocument)(selected, {
- x: bounds.left,
- y: bounds.top,
- _panX: 0,
- _panY: 0,
- isBackground,
- backgroundColor: this.props.isAnnotationOverlay ? "#00000015" : isBackground ? "cyan" : undefined,
- _width: bounds.width,
- _height: bounds.height,
- title: "a nested collection",
- });
+ getCollection = action((selected: Doc[], creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, isBackground?: boolean) => {
+ const newCollection = creator ? creator(selected, { title: "nested stack", }) : ((doc: Doc) => {
+ Doc.GetProto(doc).data = new List<Doc>(selected);
+ Doc.GetProto(doc).title = "nested freeform";
+ doc._panX = doc._panY = 0;
+ return doc;
+ })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
+ newCollection.system = undefined;
+ newCollection.isBackground = isBackground;
+ newCollection.backgroundColor = this.props.isAnnotationOverlay ? "#00000015" : isBackground ? "cyan" : undefined;
+ newCollection._width = this.Bounds.width;
+ newCollection._height = this.Bounds.height;
+ newCollection.x = this.Bounds.left;
+ newCollection.y = this.Bounds.top;
selected.forEach(d => d.context = newCollection);
this.hideMarquee();
return newCollection;
- }
+ });
@action
pileup = (e: KeyboardEvent | React.PointerEvent | undefined) => {
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index e0f3eca44..57e968aa7 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -316,7 +316,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
*/
getPermissionsSelect(user: string, permission: string) {
return <select className="permissions-select"
- defaultValue={permission}
+ value={permission}
onChange={e => this.changePermissions(e, user)}>
{Object.values(SharingPermissions).map(permission => {
return (
@@ -963,22 +963,22 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
}
if (this.isPres) {
const selectedItem: boolean = PresBox.Instance?._selectedArray.length > 0;
- return <div className="propertiesView">
- <div className="propertiesView-title">
+ return <div className="propertiesView" style={{ width: this.props.width }}>
+ <div className="propertiesView-title" style={{ width: this.props.width }}>
Presentation
</div>
<div className="propertiesView-name">
{this.editableTitle}
<div className="propertiesView-presSelected">
- {PresBox.Instance._selectedArray.length} selected
+ {PresBox.Instance?._selectedArray.length} selected
<div className="propertiesView-selectedList">
- {PresBox.Instance.listOfSelected}
+ {PresBox.Instance?.listOfSelected}
</div>
</div>
</div>
{!selectedItem ? (null) : <div className="propertiesView-presTrails">
<div className="propertiesView-presTrails-title"
- onPointerDown={() => runInAction(() => { this.openPresTransitions = !this.openPresTransitions; })}
+ onPointerDown={action(() => { this.openPresTransitions = !this.openPresTransitions; })}
style={{ backgroundColor: this.openPresTransitions ? "black" : "" }}>
&nbsp; <FontAwesomeIcon icon={"rocket"} /> &nbsp; Transitions
<div className="propertiesView-presTrails-title-icon">
@@ -1028,7 +1028,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{PresBox.Instance.newDocumentDropdown}
</div> : null}
</div>
- <div className="propertiesView-sharing">
+ {/* <div className="propertiesView-sharing">
<div className="propertiesView-sharing-title"
onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })}
style={{ backgroundColor: this.openSharing ? "black" : "" }}>
@@ -1040,7 +1040,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{this.openSharing ? <div className="propertiesView-sharing-content">
{this.sharingTable}
</div> : null}
- </div>
+ </div> */}
</div>;
}
}