aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-01-25 12:59:50 -0500
committerbobzel <zzzman@gmail.com>2023-01-25 12:59:50 -0500
commit1763ff090ea734ca275c3c28edc6c303c935b801 (patch)
tree88630593b7bcdf109fa04f427fe565ce234667d8 /src
parent555d67a31adbe7e6d42f7f7805ba1348e6d505f6 (diff)
added a linkFollow o[ption to choose between opening target, or highest level collection containing target. fixed adding marker annotations to pdf/web/etc. fixed following link to wikipedia pages to not create a new document each time. made searchBox's search function static so that it can be called programmatically. Fixed LinkDocPreview to not flicker when doing a nopreview link follow. changed PlayTrail to restore state of all freeform collections containing source anchor.
Diffstat (limited to 'src')
-rw-r--r--src/client/util/DocumentManager.ts9
-rw-r--r--src/client/util/LinkFollower.ts23
-rw-r--r--src/client/views/MainView.tsx6
-rw-r--r--src/client/views/PropertiesView.tsx12
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx9
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx72
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx16
-rw-r--r--src/client/views/pdf/AnchorMenu.tsx4
-rw-r--r--src/client/views/search/SearchBox.tsx27
-rw-r--r--src/fields/Types.ts90
10 files changed, 152 insertions, 116 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index aa09fb005..7c867d710 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -194,11 +194,16 @@ export class DocumentManager {
return toReturn;
}
- static GetContextPath(doc: Opt<Doc>) {
+ static GetContextPath(doc: Opt<Doc>, includeExistingViews?: boolean) {
if (!doc) return [];
const srcContext = Cast(doc.context, Doc, null) ?? Cast(Cast(doc.annotationOn, Doc, null)?.context, Doc, null);
var containerDocContext = srcContext ? [srcContext] : [];
- while (containerDocContext.length && containerDocContext[0]?.context && DocCast(containerDocContext[0].context)?.viewType !== CollectionViewType.Docking && !DocumentManager.Instance.getDocumentView(containerDocContext[0])) {
+ while (
+ containerDocContext.length &&
+ containerDocContext[0]?.context &&
+ DocCast(containerDocContext[0].context)?.viewType !== CollectionViewType.Docking &&
+ (includeExistingViews || !DocumentManager.Instance.getDocumentView(containerDocContext[0]))
+ ) {
containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext];
}
return containerDocContext;
diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts
index 5bdfca54a..57618b53c 100644
--- a/src/client/util/LinkFollower.ts
+++ b/src/client/util/LinkFollower.ts
@@ -100,7 +100,7 @@ export class LinkFollower {
: linkDoc.anchor1
) as Doc;
if (target) {
- const doFollow = async (canToggle?: boolean) => {
+ const doFollow = (canToggle?: boolean) => {
const options: DocFocusOptions = {
playAudio: BoolCast(sourceDoc.followLinkAudio),
toggleTarget: canToggle && BoolCast(sourceDoc.followLinkToggle),
@@ -114,27 +114,14 @@ export class LinkFollower {
zoomTextSelections: BoolCast(sourceDoc.followLinkZoomText),
};
if (target.type === DocumentType.PRES) {
- const containerAnnoDoc = Cast(sourceDoc, Doc, null);
- const containerDoc = containerAnnoDoc || sourceDoc;
- var containerDocContext = containerDoc?.context ? [Cast(await containerDoc?.context, Doc, null)] : ([] as Doc[]);
- while (containerDocContext.length && containerDocContext[0]?.context && DocCast(containerDocContext[0].context)?.viewType !== CollectionViewType.Docking) {
- containerDocContext = [Cast(await containerDocContext[0].context, Doc, null), ...containerDocContext];
- }
- if (!DocumentManager.Instance.getDocumentView(containerDocContext[0])) {
- CollectionDockingView.AddSplit(containerDocContext[0], OpenWhereMod.right);
- }
+ const containerDocContext = DocumentManager.GetContextPath(sourceDoc, true); // gather all views that affect layout of sourceDoc so we can revert them after playing the rail
SelectionManager.DeselectAll();
- DocumentManager.Instance.AddViewRenderedCb(target, dv => containerDocContext.length && (dv.ComponentView as PresBox).PlayTrail(containerDocContext[0]));
+ DocumentManager.Instance.AddViewRenderedCb(target, dv => containerDocContext.length && (dv.ComponentView as PresBox).PlayTrail(containerDocContext));
PresBox.OpenPresMinimized(target, [0, 0]);
finished?.();
} else {
- const containerAnnoDoc = Cast(target.annotationOn, Doc, null);
- const containerDoc = containerAnnoDoc || target;
- var containerDocContext = containerDoc?.context ? [Cast(await containerDoc?.context, Doc, null)] : ([] as Doc[]);
- while (containerDocContext.length && containerDocContext[0]?.context && !DocumentManager.Instance.getDocumentView(containerDocContext[0]) && DocCast(containerDocContext[0].context)?.viewType !== CollectionViewType.Docking) {
- containerDocContext = [Cast(await containerDocContext[0].context, Doc, null), ...containerDocContext];
- }
- const targetContexts = LightboxView.LightboxDoc ? [containerAnnoDoc || containerDocContext[0]].filter(a => a) : containerDocContext;
+ const containerDocContext = DocumentManager.GetContextPath(target);
+ const targetContexts = !sourceDoc.followLinkToOuterContext && containerDocContext.length ? [containerDocContext.lastElement()] : containerDocContext;
DocumentManager.Instance.jumpToDocument(target, options, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, OpenWhere.inPlace), finished), targetContexts, allFinished);
}
};
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 839db5795..895ed9bda 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -948,6 +948,10 @@ export class MainView extends React.Component {
);
}
+ @computed get linkDocPreview() {
+ return LinkDocPreview.LinkInfo ? <LinkDocPreview {...LinkDocPreview.LinkInfo} /> : null;
+ }
+
render() {
return (
<div
@@ -975,7 +979,7 @@ export class MainView extends React.Component {
{this._hideUI ? null : <TopBar />}
{LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null}
{DocumentLinksButton.LinkEditorDocView ? <LinkMenu clearLinkEditor={action(() => (DocumentLinksButton.LinkEditorDocView = undefined))} docView={DocumentLinksButton.LinkEditorDocView} /> : null}
- {LinkDocPreview.LinkInfo ? <LinkDocPreview {...LinkDocPreview.LinkInfo} /> : null}
+ {this.linkDocPreview}
{((page: string) => {
// prettier-ignore
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index af50478b0..411f51d84 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1,6 +1,6 @@
import React = require('react');
import { IconLookup } from '@fortawesome/fontawesome-svg-core';
-import { faAnchor, faArrowRight } from '@fortawesome/free-solid-svg-icons';
+import { faAnchor, faArrowRight, faWindowMaximize } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Checkbox, Tooltip } from '@material-ui/core';
import { intersection } from 'lodash';
@@ -1690,6 +1690,16 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</button>
</div>
<div className="propertiesView-input inline">
+ <p>Toggle Follow to Outer Context</p>
+ <button
+ style={{ background: !this.sourceAnchor?.followLinkToOuterContext ? '' : '#4476f7', borderRadius: 3 }}
+ onPointerDown={e => this.toggleAnchorProp(e, 'followLinkToOuterContext', this.sourceAnchor)}
+ onClick={e => e.stopPropagation()}
+ className="propertiesButton">
+ <FontAwesomeIcon className="fa-icon" icon={faWindowMaximize as IconLookup} size="lg" />
+ </button>
+ </div>
+ <div className="propertiesView-input inline">
<p>Toggle Target (Show/Hide)</p>
<button
style={{ background: !this.sourceAnchor?.followLinkToggle ? '' : '#4476f7', borderRadius: 3 }}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index ffc004df6..1ead80bd0 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -156,10 +156,13 @@ export class CollectionDockingView extends CollectionSubView() {
}
const tab = Array.from(instance.tabMap.keys()).find(tab => tab.contentItem.config.props.panelName === panelName);
if (tab) {
- tab.header.parent.addChild(newConfig, undefined);
const j = tab.header.parent.contentItems.indexOf(tab.contentItem);
- !addToSplit && j !== -1 && tab.header.parent.contentItems[j].remove();
- return instance.layoutChanged();
+ if (newConfig.props.documentId !== tab.header.parent.contentItems[j].config.props.documentId) {
+ tab.header.parent.addChild(newConfig, undefined);
+ !addToSplit && j !== -1 && tab.header.parent.contentItems[j].remove();
+ return instance.layoutChanged();
+ }
+ return false;
}
return CollectionDockingView.AddSplit(document, panelName, stack, panelName);
}
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 7eb42994b..1eab06381 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -4,7 +4,7 @@ import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import wiki from 'wikijs';
import { Doc, DocCastAsync, DocListCast, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
-import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types';
import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils';
import { DocServer } from '../../DocServer';
import { Docs, DocUtils } from '../../documents/Documents';
@@ -17,6 +17,8 @@ import { Transform } from '../../util/Transform';
import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView';
import './LinkDocPreview.scss';
import React = require('react');
+import { SearchUtil } from '../../util/SearchUtil';
+import { SearchBox } from '../search/SearchBox';
interface LinkDocPreviewProps {
linkDoc?: Doc;
@@ -36,6 +38,8 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
LinkDocPreview.LinkInfo !== info && (LinkDocPreview.LinkInfo = info);
}
+ static _instance: Opt<LinkDocPreview>;
+
_infoRef = React.createRef<HTMLDivElement>();
_linkDocRef = React.createRef<HTMLDivElement>();
@observable public static LinkInfo: Opt<LinkDocPreviewProps>;
@@ -46,6 +50,11 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
@observable _toolTipText = '';
@observable _hrefInd = 0;
+ constructor(props: any) {
+ super(props);
+ LinkDocPreview._instance = this;
+ }
+
@action init() {
var linkTarget = this.props.linkDoc;
this._linkSrc = this.props.linkSrc;
@@ -62,6 +71,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
this._markerTargetDoc = this._targetDoc = linkTarget;
}
this._toolTipText = '';
+ this.updateHref();
}
componentDidUpdate(props: any) {
if (props.linkSrc !== this.props.linkSrc || props.linkDoc !== this.props.linkDoc || props.hrefs !== this.props.hrefs) this.init();
@@ -71,6 +81,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
document.addEventListener('pointerdown', this.onPointerDown, true);
}
+ @action
componentWillUnmount() {
LinkDocPreview.SetLinkInfo(undefined);
document.removeEventListener('pointerdown', this.onPointerDown, true);
@@ -80,7 +91,8 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
!this._linkDocRef.current?.contains(e.target as any) && LinkDocPreview.Clear(); // close preview when not clicking anywhere other than the info bar of the preview
};
- @computed get href() {
+ @action
+ updateHref() {
if (this.props.hrefs?.length) {
const href = this.props.hrefs[this._hrefInd];
if (href.indexOf(Doc.localServerPath()) !== 0) {
@@ -90,33 +102,33 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
.page(href.replace('https://en.wikipedia.org/wiki/', ''))
.then(page => page.summary().then(action(summary => (this._toolTipText = summary.substring(0, 500)))));
} else {
- setTimeout(action(() => (this._toolTipText = 'url => ' + href)));
+ this._toolTipText = 'url => ' + href;
}
} else {
// hyperlink to a document .. decode doc id and retrieve from the server. this will trigger vals() being invalidated
- const anchorDoc = href.replace(Doc.localServerPath(), '').split('?')[0];
- anchorDoc &&
- DocServer.GetRefField(anchorDoc).then(
- action(anchor => {
- if (anchor instanceof Doc && DocListCast(anchor.links).length) {
- this._linkDoc = this._linkDoc ?? DocListCast(anchor.links)[0];
- const automaticLink = this._linkDoc.linkRelationship === LinkManager.AutoKeywords;
- if (automaticLink) {
- // automatic links specify the target in the link info, not the source
- const linkTarget = anchor;
- this._linkSrc = LinkManager.getOppositeAnchor(this._linkDoc, linkTarget);
- this._markerTargetDoc = this._targetDoc = linkTarget;
- } else {
- this._linkSrc = anchor;
- const linkTarget = LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc);
- this._markerTargetDoc = linkTarget;
- this._targetDoc = /*linkTarget?.type === DocumentType.MARKER &&*/ linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget;
- }
- this._toolTipText = '';
- if (LinkDocPreview.LinkInfo?.noPreview || this._linkSrc?.followLinkToggle || this._markerTargetDoc?.type === DocumentType.PRES) this.followLink();
+ const anchorDocId = href.replace(Doc.localServerPath(), '').split('?')[0];
+ const anchorDoc = anchorDocId ? PromiseValue(DocCast(DocServer.GetCachedRefField(anchorDocId) ?? DocServer.GetRefField(anchorDocId))) : undefined;
+ anchorDoc?.then?.(
+ action(anchor => {
+ if (anchor instanceof Doc && DocListCast(anchor.links).length) {
+ this._linkDoc = this._linkDoc ?? DocListCast(anchor.links)[0];
+ const automaticLink = this._linkDoc.linkRelationship === LinkManager.AutoKeywords;
+ if (automaticLink) {
+ // automatic links specify the target in the link info, not the source
+ const linkTarget = anchor;
+ this._linkSrc = LinkManager.getOppositeAnchor(this._linkDoc, linkTarget);
+ this._markerTargetDoc = this._targetDoc = linkTarget;
+ } else {
+ this._linkSrc = anchor;
+ const linkTarget = LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc);
+ this._markerTargetDoc = linkTarget;
+ this._targetDoc = /*linkTarget?.type === DocumentType.MARKER &&*/ linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget;
}
- })
- );
+ this._toolTipText = 'link to ' + this._targetDoc?.title;
+ if (LinkDocPreview.LinkInfo?.noPreview || this._linkSrc?.followLinkToggle || this._markerTargetDoc?.type === DocumentType.PRES) this.followLink();
+ }
+ })
+ );
}
return href;
}
@@ -158,11 +170,14 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
};
followLink = () => {
+ LinkDocPreview.Clear();
if (this._linkDoc && this._linkSrc) {
- LinkDocPreview.Clear();
LinkFollower.FollowLink(this._linkDoc, this._linkSrc, this.props.docProps, false);
} else if (this.props.hrefs?.length) {
- this.props.docProps?.addDocTab(Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, useCors: true }), OpenWhere.addRight);
+ const webDoc =
+ Array.from(SearchBox.staticSearchCollection(Doc.MyFilesystem, this.props.hrefs[0]).keys()).lastElement() ??
+ Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, useCors: true });
+ this.props.docProps?.addDocTab(webDoc, OpenWhere.lightbox);
}
};
@@ -208,7 +223,6 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
}
@computed get docPreview() {
- const href = this.href; // needs to be here to trigger lookup of web pages and docs on server
return (!this._linkDoc || !this._targetDoc || !this._linkSrc) && !this._toolTipText ? null : (
<div className="linkDocPreview-inner">
{!this.props.showHeader ? null : this.previewHeader}
@@ -285,7 +299,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
className="linkDocPreview"
ref={this._linkDocRef}
onPointerDown={this.followLinkPointerDown}
- style={{ left: this.props.location[0], top: this.props.location[1], width: this.width() + borders, height: this.height() + borders + (this.props.showHeader ? 37 : 0) }}>
+ style={{ display: !this._toolTipText ? 'none' : undefined, left: this.props.location[0], top: this.props.location[1], width: this.width() + borders, height: this.height() + borders + (this.props.showHeader ? 37 : 0) }}>
{this.docPreview}
</div>
);
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 4a60c99ec..ff05dcdcb 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -624,14 +624,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
_exitTrail: Opt<() => void>;
- PlayTrail = (doc: Doc) => {
- const savedState = { c: doc, x: NumCast(doc.panX), y: NumCast(doc.panY), s: NumCast(doc.viewScale) };
+ PlayTrail = (docs: Doc[]) => {
+ const savedStates = docs.map(doc => (doc._viewType !== CollectionViewType.Freeform ? undefined : { c: doc, x: NumCast(doc.panX), y: NumCast(doc.panY), s: NumCast(doc.viewScale) }));
this.startPresentation(0);
this._exitTrail = () => {
- const { x, y, s, c } = savedState;
- c._panX = x;
- c._panY = y;
- c._viewScale = s;
+ savedStates
+ .filter(savedState => savedState)
+ .map(savedState => {
+ const { x, y, s, c } = savedState!;
+ c._panX = x;
+ c._panY = y;
+ c._viewScale = s;
+ });
LightboxView.SetLightboxDoc(undefined);
Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, this.rootDoc);
return PresStatus.Edit;
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 9af686d83..c53cc608c 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -50,7 +50,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
public OnAudio: (e: PointerEvent) => void = unimplementedFunction;
public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
- public Highlight: (color: string, isTargetToggler: boolean) => Opt<Doc> = (color: string, isTargetToggler: boolean) => undefined;
+ public Highlight: (color: string, isTargetToggler: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>, addAsAnnotation?: boolean) => Opt<Doc> = (color: string, isTargetToggler: boolean) => undefined;
public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => undefined;
public Delete: () => void = unimplementedFunction;
public PinToPres: () => void = unimplementedFunction;
@@ -120,7 +120,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@action
highlightClicked = (e: React.MouseEvent) => {
- if (!this.Highlight(this.highlightColor, false) && this.Pinned) {
+ if (!this.Highlight(this.highlightColor, false, undefined, true) && this.Pinned) {
this.Highlighting = !this.Highlighting;
}
AnchorMenu.Instance.fadeOut(true);
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 7e2a5a237..4c4275ce7 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -2,7 +2,7 @@ import { Tooltip } from '@material-ui/core';
import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { DirectLinksSym, Doc, DocListCast, DocListCastAsync, Field } from '../../../fields/Doc';
+import { DirectLinksSym, Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { DocCast, StrCast } from '../../../fields/Types';
import { StopEvent } from '../../../Utils';
@@ -205,6 +205,13 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
*/
@action
searchCollection(query: string) {
+ this._selectedResult = undefined;
+ this._results = SearchBox.staticSearchCollection(CollectionDockingView.Instance?.rootDoc, query);
+
+ this.computePageRanks();
+ }
+ @action
+ static staticSearchCollection(rootDoc: Opt<Doc>, query: string) {
const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.KVP, DocumentType.FILTER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
const blockedKeys = [
'x',
@@ -240,18 +247,15 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
'panY',
'viewScale',
];
- const collection = CollectionDockingView.Instance;
query = query.toLowerCase();
- this._results.clear();
- this._selectedResult = undefined;
-
- if (collection !== undefined) {
- const docs = DocListCast(collection.rootDoc[Doc.LayoutFieldKey(collection.rootDoc)]);
+ const results = new Map<Doc, string[]>();
+ if (rootDoc) {
+ const docs = DocListCast(rootDoc[Doc.LayoutFieldKey(rootDoc)]);
const docIDs: String[] = [];
SearchBox.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => {
- const dtype = StrCast(doc.type, 'string') as DocumentType;
- if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth > 0) {
+ const dtype = StrCast(doc.type) as DocumentType;
+ if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth >= 0) {
const hlights = new Set<string>();
SearchBox.documentKeys(doc).forEach(
key =>
@@ -262,14 +266,13 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
blockedKeys.forEach(key => hlights.delete(key));
if (Array.from(hlights.keys()).length > 0) {
- this._results.set(doc, Array.from(hlights.keys()));
+ results.set(doc, Array.from(hlights.keys()));
}
}
docIDs.push(doc[Id]);
});
}
-
- this.computePageRanks();
+ return results;
}
/**
diff --git a/src/fields/Types.ts b/src/fields/Types.ts
index bf40a0d7b..3ef7cb1de 100644
--- a/src/fields/Types.ts
+++ b/src/fields/Types.ts
@@ -1,48 +1,50 @@
-import { Field, Opt, FieldResult, Doc } from "./Doc";
-import { List } from "./List";
-import { RefField } from "./RefField";
-import { DateField } from "./DateField";
-import { ScriptField } from "./ScriptField";
-import { URLField, WebField, ImageField } from "./URLField";
-import { TextField } from "@material-ui/core";
-import { RichTextField } from "./RichTextField";
-
-export type ToType<T extends InterfaceValue> =
- T extends "string" ? string :
- T extends "number" ? number :
- T extends "boolean" ? boolean :
- T extends ListSpec<infer U> ? List<U> :
- // T extends { new(...args: any[]): infer R } ? (R | Promise<R>) : never;
- T extends DefaultFieldConstructor<infer _U> ? never :
- T extends { new(...args: any[]): List<Field> } ? never :
- T extends { new(...args: any[]): infer R } ? R :
- T extends (doc?: Doc) => infer R ? R : never;
-
-export type ToConstructor<T extends Field> =
- T extends string ? "string" :
- T extends number ? "number" :
- T extends boolean ? "boolean" :
- T extends List<infer U> ? ListSpec<U> :
- new (...args: any[]) => T;
+import { Field, Opt, FieldResult, Doc } from './Doc';
+import { List } from './List';
+import { RefField } from './RefField';
+import { DateField } from './DateField';
+import { ScriptField } from './ScriptField';
+import { URLField, WebField, ImageField } from './URLField';
+import { TextField } from '@material-ui/core';
+import { RichTextField } from './RichTextField';
+
+export type ToType<T extends InterfaceValue> = T extends 'string'
+ ? string
+ : T extends 'number'
+ ? number
+ : T extends 'boolean'
+ ? boolean
+ : T extends ListSpec<infer U>
+ ? List<U>
+ : // T extends { new(...args: any[]): infer R } ? (R | Promise<R>) : never;
+ T extends DefaultFieldConstructor<infer _U>
+ ? never
+ : T extends { new (...args: any[]): List<Field> }
+ ? never
+ : T extends { new (...args: any[]): infer R }
+ ? R
+ : T extends (doc?: Doc) => infer R
+ ? R
+ : never;
+
+export type ToConstructor<T extends Field> = T extends string ? 'string' : T extends number ? 'number' : T extends boolean ? 'boolean' : T extends List<infer U> ? ListSpec<U> : new (...args: any[]) => T;
export type ToInterface<T extends Interface> = {
- [P in Exclude<keyof T, "proto">]: T[P] extends DefaultFieldConstructor<infer F> ? Exclude<FieldResult<F>, undefined> : FieldResult<ToType<T[P]>>;
+ [P in Exclude<keyof T, 'proto'>]: T[P] extends DefaultFieldConstructor<infer F> ? Exclude<FieldResult<F>, undefined> : FieldResult<ToType<T[P]>>;
};
// type ListSpec<T extends Field[]> = { List: ToContructor<Head<T>> | ListSpec<Tail<T>> };
export type ListSpec<T extends Field> = { List: ToConstructor<T> };
export type DefaultFieldConstructor<T extends Field> = {
- type: ToConstructor<T>,
- defaultVal: T
+ type: ToConstructor<T>;
+ defaultVal: T;
};
// type ListType<U extends Field[]> = { 0: List<ListType<Tail<U>>>, 1: ToType<Head<U>> }[HasTail<U> extends true ? 0 : 1];
export type Head<T extends any[]> = T extends [any, ...any[]] ? T[0] : never;
-export type Tail<T extends any[]> =
- ((...t: T) => any) extends ((_: any, ...tail: infer TT) => any) ? TT : [];
-export type HasTail<T extends any[]> = T extends ([] | [any]) ? false : true;
+export type Tail<T extends any[]> = ((...t: T) => any) extends (_: any, ...tail: infer TT) => any ? TT : [];
+export type HasTail<T extends any[]> = T extends [] | [any] ? false : true;
export type InterfaceValue = ToConstructor<Field> | ListSpec<Field> | DefaultFieldConstructor<Field> | ((doc?: Doc) => any);
//TODO Allow you to optionally specify default values for schemas, which should then make that field not be partial
@@ -58,14 +60,14 @@ export function Cast<T extends CastCtor>(field: FieldResult, ctor: T): FieldResu
export function Cast<T extends CastCtor>(field: FieldResult, ctor: T, defaultVal: WithoutList<WithoutRefField<ToType<T>>> | null): WithoutList<ToType<T>>;
export function Cast<T extends CastCtor>(field: FieldResult, ctor: T, defaultVal?: ToType<T> | null): FieldResult<ToType<T>> | undefined {
if (field instanceof Promise) {
- return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) as any : defaultVal === null ? undefined : defaultVal;
+ return defaultVal === undefined ? (field.then(f => Cast(f, ctor) as any) as any) : defaultVal === null ? undefined : defaultVal;
}
if (field !== undefined && !(field instanceof Promise)) {
- if (typeof ctor === "string") {
+ if (typeof ctor === 'string') {
if (typeof field === ctor) {
return field as ToType<T>;
}
- } else if (typeof ctor === "object") {
+ } else if (typeof ctor === 'object') {
if (field instanceof List) {
return field as any;
}
@@ -81,15 +83,15 @@ export function DocCast(field: FieldResult, defaultVal?: Doc) {
}
export function NumCast(field: FieldResult, defaultVal: number | null = 0) {
- return Cast(field, "number", defaultVal);
+ return Cast(field, 'number', defaultVal);
}
-export function StrCast(field: FieldResult, defaultVal: string | null = "") {
- return Cast(field, "string", defaultVal);
+export function StrCast(field: FieldResult, defaultVal: string | null = '') {
+ return Cast(field, 'string', defaultVal);
}
export function BoolCast(field: FieldResult, defaultVal: boolean | null = false) {
- return Cast(field, "boolean", defaultVal);
+ return Cast(field, 'boolean', defaultVal);
}
export function DateCast(field: FieldResult) {
return Cast(field, DateField, null);
@@ -113,7 +115,7 @@ type WithoutList<T extends Field> = T extends List<infer R> ? (R extends RefFiel
export function FieldValue<T extends Field, U extends WithoutList<T>>(field: FieldResult<T>, defaultValue: U): WithoutList<T>;
export function FieldValue<T extends Field>(field: FieldResult<T>): Opt<T>;
export function FieldValue<T extends Field>(field: FieldResult<T>, defaultValue?: T): Opt<T> {
- return (field instanceof Promise || field === undefined) ? defaultValue : field;
+ return field instanceof Promise || field === undefined ? defaultValue : field;
}
export interface PromiseLike<T> {
@@ -121,5 +123,9 @@ export interface PromiseLike<T> {
}
export function PromiseValue<T extends Field>(field: FieldResult<T>): PromiseLike<Opt<T>> {
if (field instanceof Promise) return field as Promise<Opt<T>>;
- return { then(cb: ((field: Opt<T>) => void)) { return cb(field); } };
-} \ No newline at end of file
+ return {
+ then(cb: (field: Opt<T>) => void) {
+ return cb(field);
+ },
+ };
+}