aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2021-09-16 21:04:57 -0400
committerbobzel <zzzman@gmail.com>2021-09-16 21:04:57 -0400
commit64119b5d8766725025b8b2bfda72f2401bba0f00 (patch)
treec35230d13e954e7541d5e433f190454dd700c5cd /src
parent68b20c7cf3b3472a7c7adbdcffa2318ad3549d8d (diff)
added search() component method. changed search menu to call search on documents that match search string. added seach bar for web pages.
Diffstat (limited to 'src')
-rw-r--r--src/client/views/GlobalKeyHandler.ts16
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx4
-rw-r--r--src/client/views/nodes/DocumentView.tsx1
-rw-r--r--src/client/views/nodes/PDFBox.tsx18
-rw-r--r--src/client/views/nodes/WebBox.scss86
-rw-r--r--src/client/views/nodes/WebBox.tsx65
-rw-r--r--src/client/views/pdf/PDFViewer.tsx13
-rw-r--r--src/client/views/search/SearchBox.tsx15
8 files changed, 172 insertions, 46 deletions
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index f66c9c788..de6f4ae8b 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -10,10 +10,11 @@ import { Cast, PromiseValue } from "../../fields/Types";
import { GoogleAuthenticationManager } from "../apis/GoogleAuthenticationManager";
import { DocServer } from "../DocServer";
import { DocumentType } from "../documents/DocumentTypes";
-import { DictationManager } from "../util/DictationManager";
+import { CurrentUserUtils } from "../util/CurrentUserUtils";
import { DragManager } from "../util/DragManager";
import { GroupManager } from "../util/GroupManager";
import { SelectionManager } from "../util/SelectionManager";
+import { SettingsManager } from "../util/SettingsManager";
import { SharingManager } from "../util/SharingManager";
import { SnappingManager } from "../util/SnappingManager";
import { undoBatch, UndoManager } from "../util/UndoManager";
@@ -27,8 +28,6 @@ import { LightboxView } from "./LightboxView";
import { MainView } from "./MainView";
import { DocumentLinksButton } from "./nodes/DocumentLinksButton";
import { AnchorMenu } from "./pdf/AnchorMenu";
-import { CurrentUserUtils } from "../util/CurrentUserUtils";
-import { SettingsManager } from "../util/SettingsManager";
const modifiers = ["control", "meta", "shift", "alt"];
type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise<KeyControlInfo>;
@@ -222,10 +221,13 @@ export class KeyManager {
PromiseValue(Cast(Doc.UserDoc()["tabs-button-tools"], Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv }));
break;
case "f":
- const searchBtn = Doc.UserDoc().searchBtn as Doc;
-
- if (searchBtn) {
- MainView.Instance.selectMenu(searchBtn);
+ if (SelectionManager.Views().length === 1 && SelectionManager.Views()[0].ComponentView?.search) {
+ SelectionManager.Views()[0].ComponentView?.search?.("", false, false);
+ } else {
+ const searchBtn = Doc.UserDoc().searchBtn as Doc;
+ if (searchBtn) {
+ MainView.Instance.selectMenu(searchBtn);
+ }
}
break;
case "o":
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index be0b078ec..94cf1c5a6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -902,7 +902,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
HistoryUtil.pushState(state);
}
}
- SelectionManager.DeselectAll();
+ if (SelectionManager.Views().length !== 1 || SelectionManager.Views()[0].Document !== doc) {
+ SelectionManager.DeselectAll();
+ }
if (this.props.Document.scrollHeight || this.props.Document.scrollTop !== undefined) {
this.props.focus(doc, options);
} else {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e8a78d75c..187905960 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -96,6 +96,7 @@ export interface DocComponentView {
annotationKey?: string;
getTitle?: () => string;
getScrollHeight?: () => number;
+ search?: (str:string, bwd?:boolean, clear?:boolean) => boolean;
}
export interface DocumentViewSharedProps {
renderDepth: number;
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index ce851b830..274d166f1 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -96,7 +96,17 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
!this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw));
}
- public search = (string: string, fwd: boolean) => this._pdfViewer?.search(string, fwd);
+ public search = action((searchString: string, bwd?: boolean, clear: boolean = false) => {
+ if (!this._searching && !clear) {
+ this._searching = true;
+ setTimeout(() => {
+ this._searchRef.current?.focus();
+ this._searchRef.current?.select();
+ this._searchRef.current?.setRangeText(searchString);
+ });
+ }
+ return this._pdfViewer?.search(searchString, bwd, clear) || false;
+ });
public prevAnnotation = () => this._pdfViewer?.prevAnnotation();
public nextAnnotation = () => this._pdfViewer?.nextAnnotation();
public backPage = () => { this.Document._curPage = (this.Document._curPage || 1) - 1; return true; };
@@ -184,8 +194,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
<div className="pdfBox-overlayCont" onPointerDown={(e) => e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}>
<button className="pdfBox-overlayButton" title={searchTitle} />
<input className="pdfBox-searchBar" placeholder="Search" ref={this._searchRef} onChange={this.searchStringChanged}
- onKeyDown={e => e.keyCode === KeyCodes.ENTER && this.search(this._searchString, !e.shiftKey)} />
- <button className="pdfBox-search" title="Search" onClick={e => this.search(this._searchString, !e.shiftKey)}>
+ onKeyDown={e => e.keyCode === KeyCodes.ENTER && this.search(this._searchString, e.shiftKey)} />
+ <button className="pdfBox-search" title="Search" onClick={e => this.search(this._searchString, e.shiftKey)}>
<FontAwesomeIcon icon="search" size="sm" />
</button>
<button className="pdfBox-prevIcon" title="Previous Annotation" onClick={this.prevAnnotation} >
@@ -196,7 +206,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
</button>
</div>
<button className="pdfBox-overlayButton" title={searchTitle}
- onClick={action(() => { this._searching = !this._searching; this.search("mxytzlaf", true); })} >
+ onClick={action(() => { this._searching = !this._searching; this.search("", true, true); })} >
<div className="pdfBox-overlayButton-arrow" onPointerDown={(e) => e.stopPropagation()} />
<div className="pdfBox-overlayButton-iconCont" onPointerDown={(e) => e.stopPropagation()}>
<FontAwesomeIcon icon={this._searching ? "times" : "search"} size="lg" />
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index 417a17d96..79289abaa 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -6,6 +6,92 @@
position: relative;
display: flex;
+ .webBox-ui {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ z-index: 1;
+ pointer-events: none;
+ top: 0;
+ left: 0;
+ overflow: hidden;
+
+ .webBox-overlayButton {
+ border-bottom-left-radius: 50%;
+ display: flex;
+ justify-content: space-evenly;
+ align-items: center;
+ height: 20px;
+ background: none;
+ padding: 0;
+ position: absolute;
+ pointer-events: all;
+ color: white;
+ bottom: 0;
+ right: 0;
+
+ .webBox-overlayButton-arrow {
+ width: 0;
+ height: 0;
+ border-top: 10px solid transparent;
+ border-bottom: 10px solid transparent;
+ border-right: 15px solid #121721;
+ transition: all 0.5s;
+ }
+
+ .webBox-overlayButton-iconCont {
+ background: #121721;
+ height: 20px;
+ width: 25px;
+ display: flex;
+ position: relative;
+ align-items: center;
+ justify-content: center;
+ border-radius: 3px;
+ pointer-events: all;
+ }
+ }
+
+ .webBox-nextIcon,
+ .webBox-prevIcon {
+ background: #121721;
+ color: white;
+ height: 20px;
+ width: 25px;
+ display: flex;
+ position: relative;
+ align-items: center;
+ justify-content: center;
+ border-radius: 3px;
+ pointer-events: all;
+ padding: 0px;
+ }
+
+ .webBox-overlayButton:hover {
+ background: none;
+ }
+
+
+ .webBox-overlayCont {
+ position: absolute;
+ width: calc(100% - 40px);
+ height: 20px;
+ background: #121721;
+ bottom: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ overflow: hidden;
+ transition: left .5s;
+ pointer-events: all;
+
+ .webBox-searchBar {
+ width: 70%;
+ font-size: 14px;
+ }
+ }
+ }
+
.webBox-overlayButton-sidebar {
background: #121721;
height: 25px;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 0c9c36418..cb9256595 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -16,6 +16,7 @@ import { TraceMobx } from "../../../fields/util";
import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils";
import { Docs } from "../../documents/Documents";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
+import { KeyCodes } from "../../util/KeyCodes";
import { Scripting } from "../../util/Scripting";
import { SnappingManager } from "../../util/SnappingManager";
import { undoBatch } from "../../util/UndoManager";
@@ -52,6 +53,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
private _keyInput = React.createRef<HTMLInputElement>();
private _initialScroll: Opt<number>;
private _sidebarRef = React.createRef<SidebarAnnos>();
+ private _searchRef = React.createRef<HTMLInputElement>();
+ private _searchString = "";
+ @observable private _searching: boolean = false;
+ @observable _showSidebar = false;
@observable private _scrollTimer: any;
@observable private _overlayAnnoInfo: Opt<Doc>;
@observable private _marqueeing: number[] | undefined;
@@ -73,6 +78,24 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || this.Document[HeightSym]() / this.Document[WidthSym]() * 850);
}
+ @action
+ search = (searchString: string, bwd?: boolean, clear: boolean = false) => {
+ if (!this._searching && !clear) {
+ this._searching = true;
+ setTimeout(() => {
+ this._searchRef.current?.focus();
+ this._searchRef.current?.select();
+ this._searchRef.current?.setRangeText(searchString);
+ });
+ }
+ if (clear) {
+ this._iframe?.contentWindow?.getSelection()?.empty();
+ }
+ if (searchString) {
+ (this._iframe?.contentWindow as any)?.find(searchString, false, bwd, true);
+ }
+ return true;
+ }
async componentDidMount() {
this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
@@ -524,9 +547,29 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
</div>;
}
- @observable _showSidebar = false;
@computed get SidebarShown() { return this._showSidebar || this.layoutDoc._showSidebar ? true : false; }
+ @computed get searchUI() {
+ return <div className="webBox-ui"
+ onPointerDown={e => e.stopPropagation()} style={{ display: this.props.isContentActive() ? "flex" : "none" }}>
+ <div className="webBox-overlayCont" onPointerDown={(e) => e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}>
+ <button className="webBox-overlayButton" title={"search"} />
+ <input className="webBox-searchBar" placeholder="Search" ref={this._searchRef} onChange={this.searchStringChanged}
+ onKeyDown={e => e.keyCode === KeyCodes.ENTER && this.search(this._searchString, e.shiftKey)} />
+ <button className="webBox-search" title="Search" onClick={e => this.search(this._searchString, e.shiftKey)}>
+ <FontAwesomeIcon icon="search" size="sm" />
+ </button>
+ </div>
+ <button className="webBox-overlayButton" title={"search"}
+ onClick={action(() => { this._searching = !this._searching; this.search("", false, true); })} >
+ <div className="webBox-overlayButton-arrow" onPointerDown={(e) => e.stopPropagation()} />
+ <div className="webBox-overlayButton-iconCont" onPointerDown={(e) => e.stopPropagation()}>
+ <FontAwesomeIcon icon={this._searching ? "times" : "search"} size="lg" />
+ </div>
+ </button>
+ </div>;
+ }
+ searchStringChanged = (e: React.ChangeEvent<HTMLInputElement>) => this._searchString = e.currentTarget.value;
showInfo = action((anno: Opt<Doc>) => this._overlayAnnoInfo = anno);
setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => this._setPreviewCursor = func;
panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1) - this.sidebarWidth(); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
@@ -623,25 +666,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
onPointerDown={this.sidebarBtnDown} >
<FontAwesomeIcon style={{ color: Colors.WHITE }} icon={"comment-alt"} size="sm" />
</div>
- {/* <div className="webBox-search" key="search" title="Search"
- style={{
- top: 10,
- left: 10,
- width: 200,
- height: 50,
- display: "block",
- position: "absolute"
- }}
- >
- <input onKeyPress={e => {
- if (e.key === "Enter") {
- (this._iframe?.contentWindow as any)?.find(e.target.value);
- }
- }} onChange={e => {
- this._iframe?.contentWindow?.getSelection()?.empty();
- (this._iframe?.contentWindow as any)?.find(e.target.value)
- }}></input>
- </div> */}
+ {!this.props.isContentActive() ? (null) : this.searchUI}
</div>);
}
}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index d953c6b6c..7aa18e46f 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -125,12 +125,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
}
});
- this._disposers.searchMatch = reaction(() => Doc.IsSearchMatch(this.props.rootDoc),
- m => {
- if (m) (this._lastSearch = true) && this.search(Doc.SearchQuery(), m.searchMatch > 0);
- else !(this._lastSearch = false) && setTimeout(() => !this._lastSearch && this.search("", false, true), 200);
- }, { fireImmediately: true });
-
this._disposers.selected = reaction(() => this.props.isSelected(),
selected => {
// if (!selected) {
@@ -337,10 +331,10 @@ export class PDFViewer extends React.Component<IViewerProps> {
}
@action
- search = (searchString: string, fwd: boolean, clear: boolean = false) => {
+ search = (searchString: string, bwd?: boolean, clear: boolean = false) => {
const findOpts = {
caseSensitive: false,
- findPrevious: !fwd,
+ findPrevious: bwd,
highlightAll: true,
phraseSearch: true,
query: searchString
@@ -348,7 +342,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
if (clear) {
this._pdfViewer?.findController.executeCommand('reset', { query: "" });
} else if (!searchString) {
- fwd ? this.nextAnnotation() : this.prevAnnotation();
+ bwd ? this.prevAnnotation() : this.nextAnnotation();
} else if (this._pdfViewer?.pageViewsReady) {
this._pdfViewer.findController.executeCommand('findagain', findOpts);
}
@@ -357,6 +351,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
this._mainCont.current.addEventListener("pagesloaded", executeFind);
this._mainCont.current.addEventListener("pagerendered", executeFind);
}
+ return true;
}
@action
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 9c353e9d0..3612bd7c4 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -104,9 +104,9 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc
* This method is called when the user clicks on a search result. The _selectedResult is
* updated accordingly and the doc is highlighted with the selectElement method.
*/
- onResultClick = action((doc: Doc) => {
- this.selectElement(doc);
+ onResultClick = action(async (doc: Doc) => {
this._selectedResult = doc;
+ this.selectElement(doc, () => DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, false));
});
makeLink = action((linkTo: Doc) => {
@@ -269,8 +269,8 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc
* This method selects a doc by either jumping to it (centering/zooming in on it)
* or opening it in a new tab.
*/
- selectElement = async (doc: Doc) => {
- await DocumentManager.Instance.jumpToDocument(doc, true);
+ selectElement = async (doc: Doc, finishFunc: () => void) => {
+ await DocumentManager.Instance.jumpToDocument(doc, true, undefined, undefined, undefined, undefined, undefined, finishFunc);
}
/**
@@ -307,7 +307,12 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc
validResults++;
return (
<Tooltip key={result[0][Id]} placement={"right"} title={<><div className="dash-tooltip">{title}</div></>}>
- <div onClick={isLinkSearch ? () => this.makeLink(result[0]) : () => this.onResultClick(result[0])} className={className}>
+ <div onClick={isLinkSearch ?
+ () => this.makeLink(result[0]) :
+ e => {
+ this.onResultClick(result[0]);
+ e.stopPropagation();
+ }} className={className}>
<div className="searchBox-result-title">
{title}
</div>