aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts29
-rw-r--r--src/client/util/CurrentUserUtils.ts23
-rw-r--r--src/client/util/DocumentManager.ts8
-rw-r--r--src/client/util/DragManager.ts7
-rw-r--r--src/client/util/SelectionManager.ts3
-rw-r--r--src/client/util/SettingsManager.scss1
-rw-r--r--src/client/util/SettingsManager.tsx7
-rw-r--r--src/client/views/DocumentDecorations.tsx21
-rw-r--r--src/client/views/MainView.tsx11
-rw-r--r--src/client/views/PropertiesView.tsx8
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx1
-rw-r--r--src/client/views/collections/CollectionPileView.tsx2
-rw-r--r--src/client/views/collections/CollectionSchemaHeaders.tsx8
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx9
-rw-r--r--src/client/views/collections/CollectionSubView.tsx65
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx25
-rw-r--r--src/client/views/collections/CollectionView.tsx174
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx2
-rw-r--r--src/client/views/linking/LinkMenuGroup.tsx3
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx6
-rw-r--r--src/client/views/nodes/DocumentView.tsx6
-rw-r--r--src/client/views/nodes/FilterBox.scss76
-rw-r--r--src/client/views/nodes/FilterBox.tsx114
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx15
-rw-r--r--src/client/views/nodes/WebBox.tsx4
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx5
-rw-r--r--src/client/views/pdf/PDFViewer.tsx22
-rw-r--r--src/client/views/search/SearchBox.tsx43
-rw-r--r--src/fields/documentSchemas.ts2
29 files changed, 283 insertions, 417 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index fbcecbec6..8d1f8a04e 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -108,7 +108,6 @@ export interface DocumentOptions {
layout?: string | Doc; // default layout string for a document
childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox or Buxton layout in tree view)
childLayoutString?: string; // template string for collection to use to render its children
- hideFilterView?: boolean; // whether to hide the filter popout on collections
hideLinkButton?: boolean; // whether the blue link counter button should be hidden
hideAllLinks?: boolean; // whether all individual blue anchor dots should be hidden
_columnsHideIfEmpty?: boolean; // whether stacking view column headings should be hidden
@@ -762,7 +761,7 @@ export namespace Docs {
}
export function PileDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
- return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", hideFilterView: true, forceActive: true, ...options, _viewType: CollectionViewType.Pile }, id);
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", forceActive: true, ...options, _viewType: CollectionViewType.Pile }, id);
}
export function LinearDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
@@ -835,7 +834,7 @@ export namespace Docs {
}
export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
- const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { freezeChildren: "remove|add", treeViewLockExpandedView: true, treeViewDefaultExpandedView: "data", ...options, _viewType: CollectionViewType.Docking, dockingConfig: config }, id);
+ const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { freezeChildren: "remove|add", treeViewDefaultExpandedView: "data", ...options, _viewType: CollectionViewType.Docking, dockingConfig: config }, id);
const tabs = TreeDocument(documents, { title: "On-Screen Tabs", freezeChildren: "remove|add", treeViewLockExpandedView: true, treeViewDefaultExpandedView: "data", system: true });
const all = TreeDocument([], { title: "Off-Screen Tabs", freezeChildren: "add", treeViewLockExpandedView: true, treeViewDefaultExpandedView: "data", system: true });
Doc.GetProto(inst).data = new List<Doc>([tabs, all]);
@@ -889,19 +888,21 @@ export namespace DocUtils {
if (d.z) return true;
for (const facetKey of Object.keys(filterFacets)) {
const facet = filterFacets[facetKey];
- const satisfiesFacet = Object.keys(facet).some(value => {
- if (facet[value] === "match") {
- if (facetKey.startsWith("*")) { // fields starting with a '*' are used to match families of related fields. ie, *lastModified will match text-lastModified, data-lastModified, etc
- const allKeys = Array.from(Object.keys(d));
- allKeys.push(...Object.keys(Doc.GetProto(d)));
- const keys = allKeys.filter(key => key.includes(facetKey.substring(1)));
- return keys.some(key => Field.toString(d[key] as Field).includes(value));
- }
- return d[facetKey] === undefined || Field.toString(d[facetKey] as Field).includes(value);
+ const matches = Object.keys(facet).filter(value => facet[value] === "match");
+ const checks = Object.keys(facet).filter(value => facet[value] === "check");
+ const xs = Object.keys(facet).filter(value => facet[value] === "x");
+ const failsNotEqualFacets = !xs.length ? false : xs.some(value => Doc.matchFieldValue(d, facetKey, value));
+ const satisfiesCheckFacets = !checks.length ? true : checks.some(value => Doc.matchFieldValue(d, facetKey, value));
+ const satisfiesMatchFacets = !matches.length ? true : matches.some(value => {
+ if (facetKey.startsWith("*")) { // fields starting with a '*' are used to match families of related fields. ie, *lastModified will match text-lastModified, data-lastModified, etc
+ const allKeys = Array.from(Object.keys(d));
+ allKeys.push(...Object.keys(Doc.GetProto(d)));
+ const keys = allKeys.filter(key => key.includes(facetKey.substring(1)));
+ return keys.some(key => Field.toString(d[key] as Field).includes(value));
}
- return (facet[value] === "x") !== Doc.matchFieldValue(d, facetKey, value);
+ return Field.toString(d[facetKey] as Field).includes(value);
});
- if (!satisfiesFacet) {
+ if (!satisfiesCheckFacets || !satisfiesMatchFacets || failsNotEqualFacets) {
return false;
}
}
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 164c3ab67..7a1c193c1 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -55,7 +55,7 @@ export class CurrentUserUtils {
Docs.Create.SearchDocument({ _viewType: CollectionViewType.Schema, ignoreClick: true, forceActive: true, _chromeStatus: "disabled", lockedPosition: true, title: "query", _height: 200, system: true }),
Docs.Create.FreeformDocument([], { title: "data", _height: 100, system: true })
],
- { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true, system: true }
+ { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, system: true }
);
queryTemplate.isTemplateDoc = makeTemplate(queryTemplate);
doc["template-button-query"] = CurrentUserUtils.ficon({
@@ -90,7 +90,7 @@ export class CurrentUserUtils {
Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }),
Docs.Create.TextDocument("", { title: "text", _height: 100, system: true })
],
- { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true, system: true }
+ { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, system: true }
);
slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
doc["template-button-slides"] = CurrentUserUtils.ficon({
@@ -720,7 +720,7 @@ export class CurrentUserUtils {
if (doc.myTools === undefined) {
const toolsStack = new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], {
- title: "My Tools", _width: 500, _yMargin: 20, lockedPosition: true, _chromeStatus: "disabled", hideFilterView: true, forceActive: true, system: true
+ title: "My Tools", _width: 500, _yMargin: 20, lockedPosition: true, _chromeStatus: "disabled", forceActive: true, system: true
})) as any as Doc;
doc.myTools = toolsStack;
@@ -734,7 +734,7 @@ export class CurrentUserUtils {
doc.myDashboards = new PrefetchProxy(Docs.Create.TreeDocument([], {
title: "My Dashboards", _height: 400,
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
- treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false,
+ treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false,
lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
}));
const newDashboard = ScriptField.MakeScript(`createNewDashboard(Doc.UserDoc())`);
@@ -750,7 +750,7 @@ export class CurrentUserUtils {
doc.myPresentations = new PrefetchProxy(Docs.Create.TreeDocument([], {
title: "My Presentations", _height: 100,
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
- treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false,
+ treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false,
lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
}));
const newPresentations = ScriptField.MakeScript(`createNewPresentation()`);
@@ -768,7 +768,7 @@ export class CurrentUserUtils {
doc.myRecentlyClosedDocs = new PrefetchProxy(Docs.Create.TreeDocument([], {
title: "Recently Closed", _height: 500,
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
- treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false,
+ treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false,
lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
}));
const clearAll = ScriptField.MakeScript(`self.data = new List([])`);
@@ -783,7 +783,7 @@ export class CurrentUserUtils {
doc.myFilter = new PrefetchProxy(Docs.Create.FilterDocument({
title: "FilterDoc", _height: 500,
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
- treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false,
+ treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false,
lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
}));
const clearAll = ScriptField.MakeScript(`self.data = new List([])`);
@@ -799,7 +799,7 @@ export class CurrentUserUtils {
doc.treeViewExpandedView = "fields";
doc.myUserDoc = new PrefetchProxy(Docs.Create.TreeDocument([doc], {
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, title: "My UserDoc",
- treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false,
+ treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false,
lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
})) as any as Doc;
}
@@ -867,14 +867,14 @@ export class CurrentUserUtils {
// Sharing sidebar is where shared documents are contained
static setupSharingSidebar(doc: Doc) {
if (doc.mySharedDocs === undefined) {
- doc.mySharedDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "My SharedDocs", childDropAction: "alias", system: true, _yMargin: 30, _showTitle: "title", ignoreClick: true, lockedPosition: true }));
+ doc.mySharedDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "My SharedDocs", childDropAction: "alias", system: true, _yMargin: 50, _gridGap: 15, _showTitle: "title", ignoreClick: true, lockedPosition: true }));
}
}
// Import sidebar is where shared documents are contained
static setupImportSidebar(doc: Doc) {
if (doc.myImportDocs === undefined) {
- doc.myImportDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "My ImportDocuments", forceActive: true, _showTitle: "title", childDropAction: "alias", _autoHeight: true, _yMargin: 30, lockedPosition: true, _chromeStatus: "disabled", system: true }));
+ doc.myImportDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "My ImportDocuments", forceActive: true, ignoreClick: true, _showTitle: "title", childDropAction: "alias", _autoHeight: true, _yMargin: 50, _gridGap: 15, lockedPosition: true, _chromeStatus: "disabled", system: true }));
}
if (doc.myImportPanel === undefined) {
const uploads = Cast(doc.myImportDocs, Doc, null);
@@ -1063,7 +1063,8 @@ export class CurrentUserUtils {
const importDocs = Cast(Doc.UserDoc().myImportDocs, Doc, null);
const disposer = OverlayView.ShowSpinner();
DocListCastAsync(importDocs.data).then(async list => {
- list?.push(... await DocUtils.uploadFilesToDocs(Array.from(input.files || []), {}));
+ const results = await DocUtils.uploadFilesToDocs(Array.from(input.files || []), {});
+ list?.splice(0, 0, ...results);
disposer();
});
} else {
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 2c7dcf49b..420b29559 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -215,8 +215,8 @@ export class DocumentManager {
public async FollowLink(link: Opt<Doc>, doc: Doc, createViewFunc: CreateViewFunc, zoom = false, currentContext?: Doc, finished?: () => void, traverseBacklink?: boolean) {
const linkDocs = link ? [link] : DocListCast(doc.links);
SelectionManager.DeselectAll();
- const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor1 as Doc, doc)); // link docs where 'doc' is anchor1
- const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor2 as Doc, doc)); // link docs where 'doc' is anchor2
+ const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor1 as Doc, doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, doc)); // link docs where 'doc' is anchor1
+ const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor2 as Doc, doc) || Doc.AreProtosEqual((linkDoc.anchor2 as Doc).annotationOn as Doc, doc)); // link docs where 'doc' is anchor2
const fwdLinkWithoutTargetView = firstDocs.find(d => DocumentManager.Instance.getDocumentViews(d.anchor2 as Doc).length === 0);
const backLinkWithoutTargetView = secondDocs.find(d => DocumentManager.Instance.getDocumentViews(d.anchor1 as Doc).length === 0);
const linkWithoutTargetDoc = traverseBacklink === undefined ? fwdLinkWithoutTargetView || backLinkWithoutTargetView : traverseBacklink ? backLinkWithoutTargetView : fwdLinkWithoutTargetView;
@@ -225,10 +225,10 @@ export class DocumentManager {
followLinks.forEach(async linkDoc => {
if (linkDoc) {
const target = (doc === linkDoc.anchor1 ? linkDoc.anchor2 : doc === linkDoc.anchor2 ? linkDoc.anchor1 :
- (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? linkDoc.anchor2 : linkDoc.anchor1)) as Doc;
+ (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, doc) ? linkDoc.anchor2 : linkDoc.anchor1)) as Doc;
const targetTimecode = (doc === linkDoc.anchor1 ? Cast(linkDoc.anchor2_timecode, "number") :
doc === linkDoc.anchor2 ? Cast(linkDoc.anchor1_timecode, "number") :
- (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? Cast(linkDoc.anchor2_timecode, "number") : Cast(linkDoc.anchor1_timecode, "number")));
+ (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, doc) ? Cast(linkDoc.anchor2_timecode, "number") : Cast(linkDoc.anchor1_timecode, "number")));
if (target) {
const containerDoc = (await Cast(target.annotationOn, Doc)) || target;
containerDoc._currentTimecode = targetTimecode;
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 8bf6faf03..9797f5488 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -144,7 +144,7 @@ export namespace DragManager {
linkSourceDocument: Doc;
dontClearTextBox?: boolean;
linkDocument?: Doc;
- linkDropCallback?: (data: LinkDragData) => void;
+ linkDropCallback?: (data: { linkDocument?: Doc }) => void;
}
export class ColumnDragData {
constructor(colKey: SchemaHeaderField) {
@@ -161,7 +161,7 @@ export namespace DragManager {
this.annotationDocument = annotationDoc;
this.offset = [0, 0];
}
- linkedToDoc?: boolean;
+ linkDocument?: Doc;
targetContext: Doc | undefined;
dragDocument: Doc;
annotationDocument: Doc;
@@ -169,6 +169,7 @@ export namespace DragManager {
offset: number[];
dropAction: dropActionType;
userDropAction: dropActionType;
+ linkDropCallback?: (data: { linkDocument?: Doc }) => void;
}
export function MakeDropTarget(
@@ -435,7 +436,7 @@ export namespace DragManager {
const target = document.elementFromPoint(e.x, e.y);
- if (target && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._noAutoscroll)) {
+ if (target && !Doc.UserDoc()._noAutoscroll && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._noAutoscroll)) {
const autoScrollHandler = () => {
target.dispatchEvent(
new CustomEvent<React.DragEvent>("dashDragAutoScroll", {
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 6d4f2c190..730db4f29 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -4,6 +4,7 @@ import { DocumentView } from "../views/nodes/DocumentView";
import { computedFn } from "mobx-utils";
import { List } from "../../fields/List";
import { CollectionSchemaView } from "../views/collections/CollectionSchemaView";
+import { CollectionViewType } from "../views/collections/CollectionView";
export namespace SelectionManager {
@@ -93,7 +94,7 @@ export namespace SelectionManager {
}
export function SelectedDocuments(): Array<DocumentView> {
- return Array.from(manager.SelectedDocuments.keys());
+ return Array.from(manager.SelectedDocuments.keys()).filter(dv => dv.props.Document._viewType !== CollectionViewType.Docking);
}
export function SelectedSchemaDoc(): Doc | undefined {
return manager.SelectedSchemaDocument;
diff --git a/src/client/util/SettingsManager.scss b/src/client/util/SettingsManager.scss
index b855d58bc..68e0b91b0 100644
--- a/src/client/util/SettingsManager.scss
+++ b/src/client/util/SettingsManager.scss
@@ -4,7 +4,6 @@
//background-color: whitesmoke !important;
color: grey;
width: 450px;
- height: 300px;
button {
background: #315a96;
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index a0281bc5a..0a1890ca4 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -105,6 +105,11 @@ export class SettingsManager extends React.Component<{}> {
<input type="checkbox" onChange={e => Doc.UserDoc()["documentLinksButton-hideEnd"] = !Doc.UserDoc()["documentLinksButton-hideEnd"]}
checked={BoolCast(Doc.UserDoc()["documentLinksButton-hideEnd"])} />
</div>
+ <div>
+ Autoscroll
+ <input type="checkbox" onChange={e => Doc.UserDoc()._noAutoscroll = !Doc.UserDoc()._noAutoscroll}
+ checked={!BoolCast(Doc.UserDoc()._noAutoscroll)} />
+ </div>
</div>
</div>;
}
@@ -188,6 +193,6 @@ export class SettingsManager extends React.Component<{}> {
isDisplayed={this.isOpen}
interactive={true}
closeOnExternalClick={this.close}
- dialogueBoxStyle={{ width: "600px", height: "340px" }} />;
+ dialogueBoxStyle={{ width: "600px" }} />;
}
} \ No newline at end of file
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 7781d6069..81c1676b0 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -598,16 +598,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
return collectionAcl === AclAdmin || collectionAcl === AclEdit;
});
const minimal = bounds.r - bounds.x < 100 ? true : false;
- const maximizeIcon = minimal ? (
- <Tooltip title={<div className="dash-tooltip">Show context menu</div>} placement="top">
- <div className="documentDecorations-contextMenu" onPointerDown={this.onSettingsDown}>
- <FontAwesomeIcon size="lg" icon="bars" />
- </div></Tooltip>) : canDelete ? (
- <Tooltip title={<div className="dash-tooltip">Close</div>} placement="top">
- <div className="documentDecorations-closeButton" onClick={this.onCloseClick}>
- {/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
- <FontAwesomeIcon className="documentdecorations-times" icon={"times"} size="lg" />
- </div></Tooltip>) : (null);
+ const closeIcon = canDelete ? (
+ <Tooltip title={<div className="dash-tooltip">Close</div>} placement="top">
+ <div className="documentDecorations-closeButton" onClick={this.onCloseClick}>
+ <FontAwesomeIcon className="documentdecorations-times" icon={"times"} size="lg" />
+ </div></Tooltip>) : (null);
const titleArea = this._edtingTitle ?
<input ref={this._keyinput} className="documentDecorations-title" type="text" name="dynbox" autoComplete="on" value={this._accumulatedTitle}
@@ -616,7 +611,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
{minimal ? (null) : <Tooltip title={<div className="dash-tooltip">Show context menu</div>} placement="top"><div className="documentDecorations-contextMenu" key="menu" onPointerDown={this.onSettingsDown}>
<FontAwesomeIcon size="lg" icon="bars" />
</div></Tooltip>}
- <div className="documentDecorations-title" key="title" onPointerDown={this.onTitleDown} >
+ <div className="documentDecorations-title" style={{ gridColumnEnd: minimal ? 4 : 5, gridColumnStart: minimal ? 2 : 3 }} key="title" onPointerDown={this.onTitleDown} >
<span style={{ width: "100%", display: "inline-block", cursor: "move" }}>{`${this.selectionTitle}`}</span>
</div>
</>;
@@ -651,9 +646,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
left: bounds.x - this._resizeBorderWidth / 2,
top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight,
}}>
- {maximizeIcon}
+ {closeIcon}
{titleArea}
- {SelectionManager.SelectedDocuments().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) :
+ {SelectionManager.SelectedDocuments().length !== 1 || seldoc.Document.type === DocumentType.INK || minimal ? (null) :
<Tooltip title={<div className="dash-tooltip">{`${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`}</div>} placement="top">
<div className="documentDecorations-iconifyButton" onPointerDown={this.onIconifyDown}>
<FontAwesomeIcon icon={seldoc.finalLayoutKey.includes("icon") ? "window-restore" : "window-minimize"} className="documentView-minimizedIcon" />
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index e6e80d9fb..f9b3b1da8 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -83,6 +83,7 @@ export class MainView extends React.Component {
componentDidMount() {
new InkStrokeProperties();
+ this._sidebarContent.proto = undefined;
DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's
DocServer.GetRefField("rtfProto").then(proto => (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), msg => msg && alert(msg)));
@@ -169,6 +170,14 @@ export class MainView extends React.Component {
window.addEventListener("drop", e => e.preventDefault(), false); // prevent default behavior of navigating to a new web page
window.addEventListener("dragover", e => e.preventDefault(), false);
document.addEventListener("pointerdown", this.globalPointerDown);
+ document.addEventListener("click", (e: MouseEvent) => {
+ if (!e.cancelBubble) {
+ const pathstr = (e as any)?.path.map((p: any) => p.classList?.toString()).join();
+ if (pathstr.includes("libraryFlyout")) {
+ SelectionManager.DeselectAll();
+ }
+ }
+ });
}
initAuthenticationRouters = async () => {
@@ -527,7 +536,7 @@ export class MainView extends React.Component {
TraceMobx();
return <div className="mainView-searchPanel">
<SearchBox Document={CurrentUserUtils.MySearchPanelDoc}
- DataDoc={undefined}
+ DataDoc={CurrentUserUtils.MySearchPanelDoc}
fieldKey="data"
dropAction="move"
isSelected={returnTrue}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index bb4657a2b..46f38795c 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -45,11 +45,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
@computed get selectedDoc() { return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.rootDoc; }
@computed get selectedDocumentView() {
- if (SelectionManager.SelectedDocuments().length) {
- return SelectionManager.SelectedDocuments()[0];
- } else if (PresBox.Instance && PresBox.Instance._selectedArray.length) {
- return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc);
- } else { return undefined; }
+ if (SelectionManager.SelectedDocuments().length) return SelectionManager.SelectedDocuments()[0];
+ if (PresBox.Instance && PresBox.Instance._selectedArray.length) return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc);
+ return undefined;
}
@computed get isPres(): boolean {
if (this.selectedDoc?.type === DocumentType.PRES) return true;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index a3d58f31d..c891d2035 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -140,6 +140,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
//
@undoBatch
public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) {
+ if (document._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(Doc.UserDoc(), document);
const instance = CollectionDockingView.Instance;
if (!instance) return false;
const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 2e4055256..522f93b88 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -28,10 +28,8 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
}
this._originalChrome = StrCast(this.layoutDoc._chromeStatus);
this.layoutDoc._chromeStatus = "disabled";
- this.layoutDoc.hideFilterView = true;
}
componentWillUnmount() {
- this.layoutDoc.hideFilterView = false;
this.layoutDoc._chromeStatus = this._originalChrome;
}
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
index 94f9d4f92..d2a1234ed 100644
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/CollectionSchemaHeaders.tsx
@@ -380,7 +380,7 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
@action
renderFilterOptions = (): JSX.Element[] | JSX.Element => {
- if (!this._isOpen) {
+ if (!this._isOpen || !this.props.dataDoc) {
this.defaultMenuHeight = 0;
return <></>;
}
@@ -388,7 +388,7 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
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]);
+ this.docSafe = DocListCast(this.props.dataDoc[this.props.fieldKey]);
}
const docs = this.docSafe;
docs.forEach((doc) => {
@@ -476,8 +476,8 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
removeFilters = (e: React.PointerEvent): void => {
const keyOptions: string[] = [];
- if (this.docSafe.length === 0) {
- this.docSafe = DocListCast(this.props.dataDoc![this.props.fieldKey]);
+ if (this.docSafe.length === 0 && this.props.dataDoc) {
+ this.docSafe = DocListCast(this.props.dataDoc[this.props.fieldKey]);
}
const docs = this.docSafe;
docs.forEach((doc) => {
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index e4bb8302f..fb0bce53e 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -77,6 +77,9 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
const dxf = () => this.getDocTransform(d, dref.current!);
this._docXfs.push({ dxf, width, height });
const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
+ if (height() < 5) {
+ console.log("here" + height());
+ }
const style = this.isStackingView ? { width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` };
return <div className={`collectionStackingView-${this.isStackingView ? "columnDoc" : "masonryDoc"}`} key={d[Id]} ref={dref} style={style} >
{this.getDisplayDoc(d, (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc, dxf, width)}
@@ -253,8 +256,10 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
if (!(this.layoutDoc._columnsFill)) wid = Math.min(layoutDoc[WidthSym](), wid);
return wid * aspect;
}
- return layoutDoc._fitWidth ? !nh ? this.props.PanelHeight() - 2 * this.yMargin :
- Math.min(wid * NumCast(layoutDoc.scrollHeight, nh) / (nw || 1), this.props.PanelHeight() - 2 * this.yMargin) : Math.max(20, layoutDoc[HeightSym]());
+ return layoutDoc._fitWidth ?
+ (!nh ? this.props.PanelHeight() - 2 * this.yMargin :
+ Math.min(wid * nh / (nw || 1), this.layoutDoc._autoHeight ? 100000 : this.props.PanelHeight() - 2 * this.yMargin)) :
+ Math.max(20, layoutDoc[HeightSym]());
}
columnDividerDown = (e: React.PointerEvent) => {
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 54e7f790f..8f0710f4b 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -131,42 +131,43 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
+ const docFilters = this.docFilters();
let searchDocs = this.searchFilterDocs();
+ if (this.props.Document.dontRegisterView || (!docFilters.length && !searchDocs.length)) return childDocs;
- let docsforFilter: Doc[] = childDocs;
-
- if (searchDocs.length > 0) {
- searchDocs = [...searchDocs, ...docs.filter(d => d.z)];
- docsforFilter = [];
- const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
- searchDocs = DocUtils.FilterDocs(searchDocs, this.docFilters(), docRangeFilters, viewSpecScript);
- childDocs.forEach((d) => {
- let notFiltered = searchDocs.includes(d) || d.z;
- const fieldKey = Doc.LayoutFieldKey(d);
- const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView");
- const data = d[annos ? fieldKey + "-annotations" : fieldKey];
- if (data !== undefined) {
- let subDocs = DocListCast(data);
- if (subDocs.length > 0) {
- let newarray: Doc[] = [];
- while (subDocs.length > 0 && !notFiltered) {
- newarray = [];
- subDocs.forEach((t) => {
- const fieldKey = Doc.LayoutFieldKey(t);
- const annos = !Field.toString(Doc.LayoutField(t) as Field).includes("CollectionView");
- notFiltered = notFiltered || searchDocs.includes(t);
- DocListCast(t[annos ? fieldKey + "-annotations" : fieldKey]).forEach((newdoc) => newarray.push(newdoc));
- });
- subDocs = newarray;
- }
+ const docsforFilter: Doc[] = [];
+ const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
+ childDocs.forEach((d) => {
+ if (this.props.Document.title === "lose this") {
+ console.log('here"')
+ }
+ if (d.title === "lose this") {
+ console.log('here"')
+ }
+ let notFiltered = d.z || ((!searchDocs.length || searchDocs.includes(d)) && (!docFilters.length || DocUtils.FilterDocs([d], docFilters, docRangeFilters, viewSpecScript).length > 0));
+ const fieldKey = Doc.LayoutFieldKey(d);
+ const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView");
+ const data = d[annos ? fieldKey + "-annotations" : fieldKey];
+ if (data !== undefined) {
+ let subDocs = DocListCast(data);
+ if (subDocs.length > 0) {
+ let newarray: Doc[] = [];
+ notFiltered = notFiltered || (!searchDocs.length && docFilters.length && DocUtils.FilterDocs(subDocs, docFilters, docRangeFilters, viewSpecScript).length);
+ while (subDocs.length > 0 && !notFiltered) {
+ newarray = [];
+ subDocs.forEach((t) => {
+ const fieldKey = Doc.LayoutFieldKey(t);
+ const annos = !Field.toString(Doc.LayoutField(t) as Field).includes("CollectionView");
+ notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && (!docFilters.length || DocUtils.FilterDocs([t], docFilters, docRangeFilters, viewSpecScript).length));
+ DocListCast(t[annos ? fieldKey + "-annotations" : fieldKey]).forEach((newdoc) => newarray.push(newdoc));
+ });
+ subDocs = newarray;
}
}
- notFiltered && docsforFilter.push(d);
- });
- return docsforFilter;
- }
- const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
- return this.props.Document.dontRegisterView ? childDocs : DocUtils.FilterDocs(childDocs, this.docFilters(), docRangeFilters, viewSpecScript);
+ }
+ notFiltered && docsforFilter.push(d);
+ });
+ return docsforFilter;
}
@action
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 52c3b2793..f13fee776 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -32,6 +32,7 @@ import React = require("react");
import { makeTemplate } from '../../util/DropConverter';
import { TraceMobx } from '../../../fields/util';
import { CurrentUserUtils } from '../../util/CurrentUserUtils';
+import { CollectionDockingView } from './CollectionDockingView';
export interface TreeViewProps {
document: Doc;
@@ -488,7 +489,7 @@ class TreeView extends React.Component<TreeViewProps> {
}} >
{view}
</div >
- {Doc.IsSystem(this.doc) ? (null) : headerElements}
+ {Doc.IsSystem(this.doc) && Doc.UserDoc().noviceMode ? (null) : headerElements}
</>;
}
@@ -875,28 +876,6 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
}
}
-Scripting.addGlobal(function readFacetData(layoutDoc: Doc, dataDoc: Doc, dataKey: string, facetHeader: string) {
- const allCollectionDocs = DocListCast(dataDoc[dataKey]);
- const facetValues = Array.from(allCollectionDocs.reduce((set, child) =>
- set.add(Field.toString(child[facetHeader] as Field)), new Set<string>()));
-
- let nonNumbers = 0;
- facetValues.map(val => {
- const num = Number(val);
- if (Number.isNaN(num)) {
- nonNumbers++;
- }
- });
- const facetValueDocSet = (nonNumbers / facetValues.length > .1 ? facetValues.sort() : facetValues.sort((n1: string, n2: string) => Number(n1) - Number(n2))).map(facetValue => {
- const doc = new Doc();
- doc.system = true;
- doc.title = facetValue.toString();
- doc.treeViewChecked = ComputedField.MakeFunction("determineCheckedState(layoutDoc, facetHeader, facetValue)", {}, { layoutDoc, facetHeader, facetValue });
- return doc;
- });
- return new List<Doc>(facetValueDocSet);
-});
-
Scripting.addGlobal(function determineCheckedState(layoutDoc: Doc, facetHeader: string, facetValue: string) {
const docFilters = Cast(layoutDoc._docFilters, listSpec("string"), []);
for (let i = 0; i < docFilters.length; i += 3) {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index cb053e85c..ba8e23447 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -271,7 +271,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
return this.SubViewHelper(type, renderProps);
}
-
setupViewTypes(category: string, func: (viewType: CollectionViewType) => Doc, addExtras: boolean) {
const subItems: ContextMenuProps[] = [];
@@ -367,6 +366,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
onMovePrevRequest={action(() => this._curLightboxImg = (this._curLightboxImg + images.length - 1) % images.length)}
onMoveNextRequest={action(() => this._curLightboxImg = (this._curLightboxImg + 1) % images.length)} />);
}
+
get _facetWidth() { return NumCast(this.props.Document._facetWidth); }
set _facetWidth(value) { this.props.Document._facetWidth = value; }
@@ -390,9 +390,11 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, DataDoc, doc)).filter(pair => pair.layout);
return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
}
+
get childDocList() {
return Cast(this.dataField, listSpec(Doc));
}
+
get childDocs() {
const dfield = this.dataField;
const rawdocs = (dfield instanceof Doc) ? [dfield] : Cast(dfield, listSpec(Doc), Cast(this.props.Document.rootDocument, Doc, null) ? [Cast(this.props.Document.rootDocument, Doc, null)] : []);
@@ -401,99 +403,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
return viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
}
- @computed get _allFacets() {
- TraceMobx();
- return ["author", "creationDate", "type", "text", "context"];
- const noviceReqFields = ["author", "creationDate", "type", "text", "context"];
- const noviceLayoutFields: string[] = [];//["_curPage"];
- const noviceFields = [...noviceReqFields, ...noviceLayoutFields];
-
- const facets = new Set<string>([...noviceReqFields, ...noviceLayoutFields]);
- this.childDocs.filter(child => child).forEach(child => child && Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key)));
- Doc.AreProtosEqual(this.dataDoc, this.props.Document) && this.childDocs.filter(child => child).forEach(child => Object.keys(child).forEach(key => facets.add(key)));
-
- return Array.from(facets).filter(key => key[0] === "#" || key.indexOf("lastModified") !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith("_") && !key.startsWith("ACL")) || noviceFields.includes(key)).sort();
- }
-
- /**
- * Responds to clicking the check box in the flyout menu
- */
- facetClick = (facetHeader: string) => {
- const facetCollection = this.props.Document;
- const found = DocListCast(facetCollection[this.props.fieldKey + "-filter"]).findIndex(doc => doc.title === facetHeader);
- if (found !== -1) {
- (facetCollection[this.props.fieldKey + "-filter"] as List<Doc>).splice(found, 1);
- const docFilter = Cast(this.props.Document._docFilters, listSpec("string"));
- if (docFilter) {
- let index: number;
- while ((index = docFilter.findIndex(item => item === facetHeader)) !== -1) {
- docFilter.splice(index, 3);
- }
- }
- const docRangeFilters = Cast(this.props.Document._docRangeFilters, listSpec("string"));
- if (docRangeFilters) {
- let index: number;
- while ((index = docRangeFilters.findIndex(item => item === facetHeader)) !== -1) {
- docRangeFilters.splice(index, 3);
- }
- }
- } else {
- const allCollectionDocs = DocListCast(this.dataDoc[this.props.fieldKey]);
- var rtfields = 0;
- const facetValues = Array.from(allCollectionDocs.reduce((set, child) => {
- const field = child[facetHeader] as Field;
- const fieldStr = Field.toString(field);
- if (field instanceof RichTextField || (typeof (field) === "string" && fieldStr.split(" ").length > 2)) rtfields++;
- return set.add(fieldStr);
- }, new Set<string>()));
-
- let nonNumbers = 0;
- let minVal = Number.MAX_VALUE, maxVal = -Number.MAX_VALUE;
- facetValues.map(val => {
- const num = Number(val);
- if (Number.isNaN(num)) {
- nonNumbers++;
- } else {
- minVal = Math.min(num, minVal);
- maxVal = Math.max(num, maxVal);
- }
- });
- let newFacet: Opt<Doc>;
- if (facetHeader === "text" || rtfields / allCollectionDocs.length > 0.1) {
- newFacet = Docs.Create.TextDocument("", { _width: 100, _height: 25, treeViewExpandedView: "layout", title: facetHeader, treeViewOpen: true, forceActive: true, ignoreClick: true });
- Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox
- newFacet.target = this.props.Document;
- newFacet._textBoxPadding = 4;
- const scriptText = `setDocFilter(this.target, "${facetHeader}", text, "match")`;
- newFacet.onTextChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, text: "string" });
- } else if (nonNumbers / facetValues.length < .1) {
- newFacet = Docs.Create.SliderDocument({ title: facetHeader, treeViewExpandedView: "layout", treeViewOpen: true });
- const newFacetField = Doc.LayoutFieldKey(newFacet);
- const ranged = Doc.readDocRangeFilter(this.props.Document, facetHeader);
- Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox
- const extendedMinVal = minVal - Math.min(1, Math.abs(maxVal - minVal) * .05);
- const extendedMaxVal = maxVal + Math.min(1, Math.abs(maxVal - minVal) * .05);
- newFacet[newFacetField + "-min"] = ranged === undefined ? extendedMinVal : ranged[0];
- newFacet[newFacetField + "-max"] = ranged === undefined ? extendedMaxVal : ranged[1];
- Doc.GetProto(newFacet)[newFacetField + "-minThumb"] = extendedMinVal;
- Doc.GetProto(newFacet)[newFacetField + "-maxThumb"] = extendedMaxVal;
- newFacet.target = this.props.Document;
- const scriptText = `setDocFilterRange(this.target, "${facetHeader}", range)`;
- newFacet.onThumbChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, range: "number" });
- Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet);
- } else {
- newFacet = new Doc();
- newFacet.sytem = true;
- newFacet.title = facetHeader;
- newFacet.treeViewOpen = true;
- newFacet.type = DocumentType.COL;
- const capturedVariables = { layoutDoc: this.props.Document, dataDoc: this.dataDoc };
- newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, {}, capturedVariables);
- }
- newFacet && Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet);
- }
- }
-
onPointerDown = (e: React.PointerEvent) => {
setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
this._facetWidth = this.props.PanelWidth() - Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0);
@@ -501,78 +410,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
}), returnFalse, action(() => this._facetWidth = this.facetWidth() < 15 ? Math.min(this.props.PanelWidth() - 25, 200) : 0), false);
}
- filterBackground = () => "rgba(105, 105, 105, 0.432)";
- get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; } // this makes the tree view collection ignore these filters (otherwise, the filters would filter themselves)
- @computed get scriptField() {
- 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;
- }
- @computed get filterView() {
- TraceMobx();
- const facetCollection = this.props.Document;
- const flyout = (
- <div className="collectionTimeView-flyout" style={{ width: `${this.facetWidth()}`, height: this.props.PanelHeight() - 30 }} onWheel={e => e.stopPropagation()}>
- {this._allFacets.map(facet => <label className="collectionTimeView-flyout-item" key={`${facet}`} onClick={e => this.facetClick(facet)}>
- <input type="checkbox" onChange={e => { }} checked={DocListCast(this.props.Document[this.props.fieldKey + "-filter"]).some(d => d.title === facet)} />
- <span className="checkmark" />
- {facet}
- </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={"edit"} 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}
- searchFilterDocs={returnEmptyDoclist}
- 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);
childLayoutString = this.props.childLayoutString || StrCast(this.props.Document.childLayoutString);
@@ -603,11 +440,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
Utils.CorsProxy(Cast(d.data, ImageField)!.url.href) : Cast(d.data, ImageField)!.url.href
:
""))}
- {(Doc.UserDoc()?.noviceMode || !this.props.isSelected() && !this.props.Document.forceActive) || this.props.Document.hideFilterView ? (null) :
- <div className="collectionView-filterDragger" title="library View Dragger" onPointerDown={this.onPointerDown}
- style={{ right: this.facetWidth() - 1, top: this.props.Document._viewType === CollectionViewType.Docking ? "25%" : "60%" }} />
- }
- {Doc.UserDoc()?.noviceMode || this.facetWidth() < 10 ? (null) : this.filterView}
</div>);
}
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 30a71398b..306dfe797 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1167,7 +1167,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if ((e as any).handlePan || this.props.isAnnotationOverlay) return;
(e as any).handlePan = true;
- if (this._marqueeRef?.current) {
+ if (!this.props.Document._noAutoscroll && this._marqueeRef?.current) {
const dragX = e.detail.clientX;
const dragY = e.detail.clientY;
const bounds = this._marqueeRef.current?.getBoundingClientRect();
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index 2ae87ac13..8e09052a3 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -66,7 +66,8 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
}
render() {
- const groupItems = this.props.group.map(linkDoc => {
+ const set = new Set<Doc>(this.props.group);
+ const groupItems = Array.from(set.keys()).map(linkDoc => {
const destination = LinkManager.Instance.getOppositeAnchor(linkDoc, this.props.sourceDoc) ||
LinkManager.Instance.getOppositeAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, null).annotationOn === this.props.sourceDoc ? Cast(linkDoc.anchor2, Doc, null) : Cast(linkDoc.anchor1, Doc, null));
if (destination && this.props.sourceDoc) {
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 1d346894c..ab6cae0ad 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -220,7 +220,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
@computed
get linkButton() {
TraceMobx();
- const links = this.props.links;
+ const links = new Set<Doc>(this.props.links);
const menuTitle = this.props.StartLink ? "Drag or tap to start link" : "Tap to complete link";
const buttonTitle = "Tap to view links";
@@ -265,7 +265,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
<FontAwesomeIcon className="documentdecorations-icon" icon="hand-paper" size="sm" /> : links.length} */}
{this.props.InMenu ? this.props.StartLink ? <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" /> :
- link : links.length}
+ link : Array.from(links).length}
</div>
{this.props.InMenu && !this.props.StartLink && DocumentLinksButton.StartLink !== this.props.View.props.Document ?
@@ -287,7 +287,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
}
</div >;
- return (!links.length) && !this.props.AlwaysOn ? (null) :
+ return (!Array.from(links).length) && !this.props.AlwaysOn ? (null) :
this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink) ?
<Tooltip title={<><div className="dash-tooltip">{title}</div></>}>
{linkButton}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 41e6d9603..f6360fc87 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -661,10 +661,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
if (de.complete.annoDragData) {
/// this whole section for handling PDF annotations looks weird. Need to rethink this to make it cleaner
e.stopPropagation();
- de.complete.annoDragData.linkedToDoc = true;
-
- const linkDoc = DocUtils.MakeLink({ doc: de.complete.annoDragData.annotationDocument }, { doc: this.props.Document }, "link");
- linkDoc && makeLink(linkDoc);
+ de.complete.annoDragData.linkDocument = DocUtils.MakeLink({ doc: de.complete.annoDragData.annotationDocument }, { doc: this.props.Document }, "link");
+ de.complete.annoDragData.linkDocument && makeLink(de.complete.annoDragData.linkDocument);
}
if (de.complete.linkDragData) {
e.stopPropagation();
diff --git a/src/client/views/nodes/FilterBox.scss b/src/client/views/nodes/FilterBox.scss
index c5d6e2505..b39793f01 100644
--- a/src/client/views/nodes/FilterBox.scss
+++ b/src/client/views/nodes/FilterBox.scss
@@ -1,44 +1,54 @@
- .collectionTimeView-treeView {
- display: flex;
- flex-direction: column;
- width: 200px;
- height: 100%;
- position: absolute;
- right: 0;
- top: 0;
- border-left: solid 1px;
- z-index: 1;
-
- .collectionTimeView-addfacet {
- display: inline-block;
- width: 200px;
- height: 30px;
- background: darkGray;
+.filterBox-flyout {
+ width: 400px;
+ display: block;
+ text-align: left;
+ .filterBox-flyout-facet {
+ background-color: lightgray;
text-align: left;
+ display: inline-block;
+ position: relative;
+ width: 100%;
+ }
+}
+.filterBox-treeView {
+ display: flex;
+ flex-direction: column;
+ width: 200px;
+ height: 100%;
+ position: absolute;
+ right: 0;
+ top: 0;
+ border-left: solid 1px;
+ z-index: 1;
- .collectionTimeView-button {
- align-items: center;
- display: flex;
- width: 100%;
- height: 100%;
+ .filterBox-addfacet {
+ display: inline-block;
+ width: 200px;
+ height: 30px;
+ background: darkGray;
+ text-align: left;
- .collectionTimeView-span {
- margin: auto;
- }
- }
+ .filterBox-addFacetButton {
+ display: flex;
+ margin: auto;
- >div,
- >div>div {
- width: 100%;
- height: 100%;
+ .filterBox-span {
+ margin-right: 15px;
}
}
- .collectionTimeView-tree {
- display: inline-block;
+ >div,
+ >div>div {
width: 100%;
- height: calc(100% - 30px);
+ height: 100%;
}
- } \ No newline at end of file
+ }
+
+ .filterBox-tree {
+ display: inline-block;
+ width: 100%;
+ height: calc(100% - 30px);
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index 7bffc9184..790901a29 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -1,27 +1,24 @@
import React = require("react");
-import { action, computed } from "mobx";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { computed } from "mobx";
import { observer } from "mobx-react";
-import { ColorState, SketchPicker } from 'react-color';
-import { Doc, Opt, DocListCast, Field, DataSym } from "../../../fields/Doc";
-import { Utils, returnEmptyFilter, returnEmptyDoclist, returnZero, emptyPath, returnFalse, emptyFunction, returnOne } from "../../../Utils";
+import { DataSym, Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
-import { InkTool } from "../../../fields/InkField";
-import { makeInterface, listSpec } from "../../../fields/Schema";
-import { StrCast, Cast } from "../../../fields/Types";
-import { SelectionManager } from "../../util/SelectionManager";
-import { undoBatch } from "../../util/UndoManager";
-import { ViewBoxBaseComponent } from "../DocComponent";
-import "./ColorBox.scss";
-import { FieldView, FieldViewProps } from './FieldView';
+import { List } from "../../../fields/List";
+import { RichTextField } from "../../../fields/RichTextField";
+import { listSpec, makeInterface } from "../../../fields/Schema";
+import { ComputedField, ScriptField } from "../../../fields/ScriptField";
+import { Cast } from "../../../fields/Types";
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnZero } from "../../../Utils";
+import { Docs } from "../../documents/Documents";
import { DocumentType } from "../../documents/DocumentTypes";
+import { CollectionDockingView } from "../collections/CollectionDockingView";
import { CollectionTreeView } from "../collections/CollectionTreeView";
-import { ScriptField, ComputedField } from "../../../fields/ScriptField";
-import { Docs } from "../../documents/Documents";
-import { RichTextField } from "../../../fields/RichTextField";
-import { List } from "../../../fields/List";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { ViewBoxBaseComponent } from "../DocComponent";
+import { SearchBox } from "../search/SearchBox";
+import { FieldView, FieldViewProps } from './FieldView';
import './FilterBox.scss';
-import { CollectionDockingView } from "../collections/CollectionDockingView";
+import { Scripting } from "../../util/Scripting";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -33,17 +30,24 @@ const FilterBoxDocument = makeInterface(documentSchema);
export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDocument>(FilterBoxDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(FilterBox, fieldKey); }
- @computed get _allFacets() {
- return ["author", "creationDate", "type", "text", "context"];
- // const noviceReqFields = ["author", "creationDate", "type", "text", "context"];
- // const noviceLayoutFields: string[] = [];//["_curPage"];
- // const noviceFields = [...noviceReqFields, ...noviceLayoutFields];
+ @computed get allDocs() {
+ const allDocs = new Set<Doc>();
+ if (CollectionDockingView.Instance) {
+ const activeTabs = DocListCast(CollectionDockingView.Instance.props.Document.data);
+ SearchBox.foreachRecursiveDoc(activeTabs, (doc: Doc) => allDocs.add(doc));
+ setTimeout(() => CollectionDockingView.Instance.props.Document.allDocuments = new List<Doc>(Array.from(allDocs)));
+ }
+ return allDocs;
+ }
- // const facets = new Set<string>([...noviceReqFields, ...noviceLayoutFields]);
- // this.childDocs.filter(child => child).forEach(child => child && Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key)));
- // Doc.AreProtosEqual(this.dataDoc, this.props.Document) && this.childDocs.filter(child => child).forEach(child => Object.keys(child).forEach(key => facets.add(key)));
+ @computed get _allFacets() {
+ const noviceReqFields = ["author", "tags", "text", "type"];
+ const noviceLayoutFields: string[] = [];//["_curPage"];
+ const noviceFields = [...noviceReqFields, ...noviceLayoutFields];
- // return Array.from(facets).filter(key => key[0] === "#" || key.indexOf("lastModified") !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith("_") && !key.startsWith("ACL")) || noviceFields.includes(key)).sort();
+ const keys = new Set<string>(noviceFields);
+ this.allDocs.forEach(doc => SearchBox.documentKeys(doc).filter(key => keys.add(key)));
+ return Array.from(keys.keys()).filter(key => key[0] === "#" || key.indexOf("lastModified") !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith("_") && !key.startsWith("ACL")) || noviceFields.includes(key)).sort();
}
/**
* Responds to clicking the check box in the flyout menu
@@ -95,7 +99,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
newFacet._textBoxPadding = 4;
const scriptText = `setDocFilter(this?.target, "${facetHeader}", text, "match")`;
newFacet.onTextChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, text: "string" });
- } else if (nonNumbers / facetValues.length < .1) {
+ } else if (facetHeader !== "tags" && nonNumbers / facetValues.length < .1) {
newFacet = Docs.Create.SliderDocument({ title: facetHeader, treeViewExpandedView: "layout", treeViewOpen: true });
const newFacetField = Doc.LayoutFieldKey(newFacet);
const ranged = Doc.readDocRangeFilter(targetDoc, facetHeader);
@@ -115,7 +119,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
newFacet.treeViewOpen = true;
newFacet.type = DocumentType.COL;
const capturedVariables = { layoutDoc: targetDoc, dataDoc: (targetDoc.data as any)[0][DataSym] };
- newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, {}, capturedVariables);
+ newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, "${facetHeader}")`, {}, capturedVariables);
}
newFacet && Doc.AddDocToList(this.dataDoc, this.props.fieldKey, newFacet);
}
@@ -128,28 +132,26 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
return script ? () => script : undefined;
}
- @computed get filterView() {
+ render() {
const facetCollection = this.props.Document.proto as Doc;
- const flyout = (
- <div className="collectionTimeView-flyout" style={{ width: `100%`, height: this.props.PanelHeight() - 30 }} onWheel={e => e.stopPropagation()}>
- {this._allFacets.map(facet => <label className="collectionTimeView-flyout-item" key={`${facet}`} onClick={e => this.facetClick(facet)}>
- <input type="checkbox" onChange={e => { }} checked={DocListCast(this.props.Document[this.props.fieldKey]).some(d => d.title === facet)} />
- <span className="checkmark" />
- {facet}
- </label>)}
- </div>
- );
+ const flyout = <div className="filterBox-flyout" style={{ width: `100%`, height: this.props.PanelHeight() - 30 }} onWheel={e => e.stopPropagation()}>
+ {this._allFacets.map(facet => <label className="filterBox-flyout-facet" key={`${facet}`} onClick={e => this.facetClick(facet)}>
+ <input type="checkbox" onChange={e => { }} checked={DocListCast(this.props.Document[this.props.fieldKey]).some(d => d.title === facet)} />
+ <span className="checkmark" />
+ {facet}
+ </label>)}
+ </div>;
- return this.props.dontRegisterView ? (null) : <div className="collectionTimeView-treeView" style={{ width: "100%" }}>
- <div className="collectionTimeView-addFacet" style={{ width: "100%" }} onPointerDown={e => e.stopPropagation()}>
+ return this.props.dontRegisterView ? (null) : <div className="filterBox-treeView" style={{ width: "100%" }}>
+ <div className="filterBox-addFacet" style={{ width: "100%" }} onPointerDown={e => e.stopPropagation()}>
<Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
- <div className="collectionTimeView-button">
+ <div className="filterBox-addFacetButton">
<FontAwesomeIcon icon={"edit"} size={"lg"} />
- <span className="collectionTimeView-span">Facet Filters</span>
+ <span className="filterBox-span">Choose Facets</span>
</div>
</Flyout>
</div>
- <div className="collectionTimeView-tree" key="tree">
+ <div className="filterBox-tree" key="tree">
<CollectionTreeView
PanelPosition={""}
Document={facetCollection}
@@ -191,7 +193,23 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
</div>
</div>;
}
- render() {
- return this.filterView;
- }
-} \ No newline at end of file
+}
+
+Scripting.addGlobal(function readFacetData(layoutDoc: Doc, facetHeader: string) {
+ const allCollectionDocs = DocListCast(CollectionDockingView.Instance?.props.Document.allDocuments);
+ const set = new Set<string>();
+ if (facetHeader === "tags") allCollectionDocs.forEach(child => Field.toString(child[facetHeader] as Field).split(":").forEach(key => set.add(key)));
+ else allCollectionDocs.forEach(child => set.add(Field.toString(child[facetHeader] as Field)));
+ let facetValues = Array.from(set).filter(v => v);
+
+ let nonNumbers = 0;
+ facetValues.map(val => Number.isNaN(Number(val)) && nonNumbers++);
+ const facetValueDocSet = (nonNumbers / facetValues.length > .1 ? facetValues.sort() : facetValues.sort((n1: string, n2: string) => Number(n1) - Number(n2))).map(facetValue => {
+ const doc = new Doc();
+ doc.system = true;
+ doc.title = facetValue.toString();
+ doc.treeViewChecked = ComputedField.MakeFunction("determineCheckedState(layoutDoc, facetHeader, facetValue)", {}, { layoutDoc, facetHeader, facetValue });
+ return doc;
+ });
+ return new List<Doc>(facetValueDocSet);
+}); \ No newline at end of file
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index ce8df5195..dddefc17f 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -22,6 +22,7 @@ interface Props {
}
@observer
export class LinkDocPreview extends React.Component<Props> {
+ static TargetDoc: Doc | undefined;
@observable public static LinkInfo: Opt<{ linkDoc?: Doc; addDocTab: (document: Doc, where: string) => boolean, linkSrc: Doc; href?: string; Location: number[] }>;
@observable _targetDoc: Opt<Doc>;
@observable _toolTipText = "";
@@ -42,12 +43,14 @@ export class LinkDocPreview extends React.Component<Props> {
LinkDocPreview.LinkInfo = undefined;
this._targetDoc ? DocumentManager.Instance.FollowLink(this.props.linkDoc, this._targetDoc, doc => this.props.addDocTab(doc, "add:right"), false) : null;
}
+ componentWillUnmount() { LinkDocPreview.TargetDoc = undefined; }
componentDidUpdate() { this.updatePreview(); }
componentDidMount() { this.updatePreview(); }
async updatePreview() {
const linkDoc = this.props.linkDoc;
const linkSrc = this.props.linkSrc;
+ LinkDocPreview.TargetDoc = undefined;
if (this.props.href) {
if (this.props.href.startsWith("https://en.wikipedia.org/wiki/")) {
wiki().page(this.props.href.replace("https://en.wikipedia.org/wiki/", "")).then(page => page.summary().then(action(summary => this._toolTipText = summary.substring(0, 500))));
@@ -59,7 +62,7 @@ export class LinkDocPreview extends React.Component<Props> {
const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor;
runInAction(() => {
this._toolTipText = "";
- this._targetDoc = target;
+ LinkDocPreview.TargetDoc = this._targetDoc = target;
if (anchor !== this._targetDoc && anchor && this._targetDoc) {
this._targetDoc._scrollY = NumCast(anchor?.y);
}
@@ -74,8 +77,8 @@ export class LinkDocPreview extends React.Component<Props> {
this.props.addDocTab(Docs.Create.WebDocument(this.props.href, { title: this.props.href, _width: 200, _height: 400, useCors: true }), "add:right");
}
}
- width = () => Math.min(225, NumCast(this._targetDoc?.[WidthSym](), 225));
- height = () => Math.min(225, NumCast(this._targetDoc?.[HeightSym](), 225));
+ width = () => Math.min(225, NumCast(this._targetDoc?.[WidthSym](), 225)) - 16;
+ height = () => Math.min(225, NumCast(this._targetDoc?.[HeightSym](), 225)) - 16
@computed get targetDocView() {
return !this._targetDoc ?
<div style={{
@@ -105,8 +108,8 @@ export class LinkDocPreview extends React.Component<Props> {
ContainingCollectionDoc={undefined}
ContainingCollectionView={undefined}
renderDepth={0}
- PanelWidth={() => this.width() - 16} //Math.min(350, NumCast(target._width, 350))}
- PanelHeight={() => this.height() - 16} //Math.min(250, NumCast(target._height, 250))}
+ PanelWidth={this.width} //Math.min(350, NumCast(target._width, 350))}
+ PanelHeight={this.height} //Math.min(250, NumCast(target._height, 250))}
focus={emptyFunction}
whenActiveChanged={returnFalse}
bringToFront={returnFalse}
@@ -120,7 +123,7 @@ export class LinkDocPreview extends React.Component<Props> {
return <div className="linkDocPreview"
style={{
position: "absolute", left: this.props.location[0],
- top: this.props.location[1], width: this.width(), height: this.height(),
+ top: this.props.location[1], width: this.width() + 16, height: this.height() + 16,
zIndex: 1000,
border: "8px solid white", borderRadius: "7px",
boxShadow: "3px 3px 1.5px grey",
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index f9e6227d7..c5d7c3c9f 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -499,8 +499,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
if (annotationDoc) {
DragManager.StartPdfAnnoDrag([ele], new DragManager.PdfAnnoDragData(this.props.Document, annotationDoc, targetDoc), e.pageX, e.pageY, {
dragComplete: e => {
- if (!e.aborted && e.annoDragData && !e.annoDragData.linkedToDoc) {
- DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
+ if (!e.aborted && e.annoDragData && !e.annoDragData.linkDocument) {
+ e.annoDragData.linkDocument = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
annotationDoc.isLinkButton = true;
}
}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 436538eba..311143ff7 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -460,8 +460,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
} else if (de.complete.linkDragData) {
de.complete.linkDragData.linkDropCallback = this.linkDrop;
}
+ else if (de.complete.annoDragData) {
+ de.complete.annoDragData.linkDropCallback = this.linkDrop;
+ }
}
- linkDrop = (data: DragManager.LinkDragData) => {
+ linkDrop = (data: { linkDocument?: Doc }) => {
const linkDoc = data.linkDocument!;
const anchor1Title = linkDoc.anchor1 instanceof Doc ? StrCast(linkDoc.anchor1.title) : "-untitled-";
const anchor1Id = linkDoc.anchor1 instanceof Doc ? linkDoc.anchor1[Id] : "";
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 0a52f6ad5..18be9b679 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -32,6 +32,7 @@ import { PDFMenu } from "./PDFMenu";
import "./PDFViewer.scss";
const pdfjs = require('pdfjs-dist/es5/build/pdf.js');
import React = require("react");
+import { LinkDocPreview } from "../nodes/LinkDocPreview";
const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
const pdfjsLib = require("pdfjs-dist");
@@ -98,6 +99,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
@observable private _zoomed = 1;
private _pdfViewer: any;
+ private _styleRule: any; // stylesheet rule for making hyperlinks clickable
private _retries = 0; // number of times tried to create the PDF viewer
private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void);
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
@@ -166,7 +168,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
(scrollY) => {
if (scrollY !== undefined) {
(this._showCover || this._showWaiting) && this.setupPdfJsViewer();
- this._mainCont.current && smoothScroll(1000, this._mainCont.current, (this.Document._scrollY || 0));
+ (!LinkDocPreview.TargetDoc) && this._mainCont.current && smoothScroll(1000, this._mainCont.current, (this.Document._scrollY || 0));
setTimeout(() => this.Document._scrollY = undefined, 1000);
}
},
@@ -435,11 +437,10 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
// if alt+left click, drag and annotate
this._downX = e.clientX;
this._downY = e.clientY;
- addStyleSheetRule(PDFViewer._annotationStyle, "pdfAnnotation", { "pointer-events": "none" });
+ (e.target as any).tagName === "SPAN" && (this._styleRule = addStyleSheetRule(PDFViewer._annotationStyle, "pdfAnnotation", { "pointer-events": "none" }));
if ((this.Document._viewScale || 1) !== 1) return;
if ((e.button !== 0 || e.altKey) && this.active(true)) {
this._setPreviewCursor?.(e.clientX, e.clientY, true);
- //e.stopPropagation();
}
this._marqueeing = false;
if (!e.altKey && e.button === 0 && this.active(true)) {
@@ -461,12 +462,15 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
this._marqueeHeight = this._marqueeWidth = 0;
this._marqueeing = true;
}
- document.removeEventListener("pointermove", this.onSelectMove);
document.addEventListener("pointermove", this.onSelectMove);
- document.removeEventListener("pointerup", this.onSelectEnd);
document.addEventListener("pointerup", this.onSelectEnd);
+ document.addEventListener("pointerup", this.removeStyle, true);
}
}
+ removeStyle = () => {
+ clearStyleSheetRules(PDFViewer._annotationStyle);
+ document.removeEventListener("pointerup", this.removeStyle);
+ }
@action
onSelectMove = (e: PointerEvent): void => {
@@ -605,11 +609,11 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
if (annotationDoc) {
DragManager.StartPdfAnnoDrag([ele], new DragManager.PdfAnnoDragData(this.props.Document, annotationDoc, targetDoc), e.pageX, e.pageY, {
dragComplete: e => {
- if (!e.aborted && e.annoDragData && !e.annoDragData.linkedToDoc) {
- const link = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
- annotationDoc.isLinkButton = true;
- if (link) Doc.GetProto(link).followLinkLocation = "default";
+ if (!e.aborted && e.annoDragData && !e.annoDragData.linkDocument) {
+ e.annoDragData.linkDocument = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
+ annotationDoc.isLinkButton = true; // prevents link button fro showing up --- maybe not a good thing?
}
+ e.annoDragData && e.annoDragData.linkDocument && e.annoDragData?.linkDropCallback?.({ linkDocument: e.annoDragData.linkDocument });
}
});
}
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 3907d2d5c..b37ae02c3 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -179,6 +179,21 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
return finalDocs;
}
+ static foreachRecursiveDoc(docs: Doc[], func: (doc: Doc) => void) {
+ let newarray: Doc[] = [];
+ while (docs.length > 0) {
+ newarray = [];
+ docs.forEach(d => {
+ const fieldKey = Doc.LayoutFieldKey(d);
+ const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView");
+ const data = d[annos ? fieldKey + "-annotations" : fieldKey];
+ data && newarray.push(...DocListCast(data));
+ func(d);
+ });
+ docs = newarray;
+ }
+ }
+
@action
searchCollection(query: string) {
const selectedCollection = this.currentSelectedCollection;//SelectionManager.SelectedDocuments()[0];
@@ -186,26 +201,14 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
if (selectedCollection !== undefined) {
// this._currentSelectedCollection = selectedCollection;
- let docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]);
+ const docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]);
const found: [Doc, string[], string[]][] = [];
- let newarray: Doc[] = [];
-
- while (docs.length > 0) {
- newarray = [];
- docs.forEach(d => {
- const fieldKey = Doc.LayoutFieldKey(d);
- const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView");
- const data = d[annos ? fieldKey + "-annotations" : fieldKey];
- data && newarray.push(...DocListCast(data));
- const hlights = new Set<string>();
- this.documentKeys(d).forEach(key =>
- Field.toString(d[key] as Field).toLowerCase().includes(query) && hlights.add(key));
- if (Array.from(hlights.keys()).length > 0) {
- found.push([d, Array.from(hlights.keys()), []]);
- }
- });
- docs = newarray;
- }
+ SearchBox.foreachRecursiveDoc(docs, (doc: Doc) => {
+ const hlights = new Set<string>();
+ SearchBox.documentKeys(doc).forEach(key => Field.toString(doc[key] as Field).toLowerCase().includes(query) && hlights.add(key));
+ Array.from(hlights.keys()).length > 0 && found.push([doc, Array.from(hlights.keys()), []]);
+ });
+
this._results = found;
this.docsforfilter = this._results.map(r => r[0]);
this.setSearchFilter(selectedCollection, this.filter && found.length ? this.docsforfilter : undefined);
@@ -218,7 +221,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
}
- documentKeys(doc: Doc) {
+ static documentKeys(doc: Doc) {
const keys: { [key: string]: boolean } = {};
// bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields.
// then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index 76b26a9aa..71294c59c 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -95,7 +95,7 @@ export const documentSchema = createSchema({
onPointerDown: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop)
onPointerUp: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop)
onDragStart: ScriptField, // script to run when document is dragged (without being selected). the script should return the Doc to be dropped.
- followLinkLocation: "string",// flag for where to place content when following a click interaction (e.g., onRight, inPlace, inTab, )
+ followLinkLocation: "string",// flag for where to place content when following a click interaction (e.g., add:right, inPlace, default, )
hideLinkButton: "boolean", // whether the blue link counter button should be hidden
hideAllLinks: "boolean", // whether all individual blue anchor dots should be hidden
linkDisplay: "boolean", // whether a link connection should be shown between link anchor endpoints.