aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormadelinegr <monika_hedman@brown.edu>2019-06-12 12:26:53 -0400
committermadelinegr <monika_hedman@brown.edu>2019-06-12 12:26:53 -0400
commit475663393d8fb65d3682826db883bb143aae4017 (patch)
treea622104fcb3b3986b89553fd9b1c5baf2c980d4e /src
parentfbcbbb2dc3dcb59f3389de0e4cc11283a7e4d87a (diff)
filter open close working
Diffstat (limited to 'src')
-rw-r--r--src/client/views/search/IconBar.tsx46
-rw-r--r--src/client/views/search/SearchBox.tsx203
-rw-r--r--src/client/views/search/SearchItem.tsx11
3 files changed, 185 insertions, 75 deletions
diff --git a/src/client/views/search/IconBar.tsx b/src/client/views/search/IconBar.tsx
index 3f77d64eb..f3741a5de 100644
--- a/src/client/views/search/IconBar.tsx
+++ b/src/client/views/search/IconBar.tsx
@@ -160,95 +160,95 @@ export class IconBar extends React.Component<IconBarProps> {
render() {
return (
<div>
- <div className="icon-title">Filter by type of node</div>
- <div className="icon-bar">
- <div className="type-outer">
- <div className={"type-icon none"}
+ <div className="filter icon-title">Filter by type of node</div>
+ <div className="filter icon-bar">
+ <div className="filter type-outer">
+ <div className={"type-icon filter none"}
ref={this.noneRef}
data-selected={"false"}
onClick={() => { this.onClick(DocTypes.NONE); }}>
- <FontAwesomeIcon className="fontawesome-icon" style={{ order: -2 }} icon={faBan} />
+ <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: -2 }} icon={faBan} />
</div>
<div className="filter-description">Clear</div>
</div>
<div className="type-outer">
- <div className={"type-icon " + (this.isRefSelected(this.pdfRef) ? "selected" : "not-selected")}
+ <div className={"type-icon filter " + (this.isRefSelected(this.pdfRef) ? "selected" : "not-selected")}
ref={this.pdfRef}
data-selected={this.getInitialStatus(DocTypes.PDF)}
onClick={() => { this.onClick(DocTypes.PDF); }}>
- <FontAwesomeIcon className="fontawesome-icon" style={{ order: 0 }} icon={faFilePdf} />
+ <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 0 }} icon={faFilePdf} />
</div>
<div className="filter-description">PDF</div>
</div>
<div className="type-outer">
- <div className={"type-icon " + (this.isRefSelected(this.histRef) ? "selected" : "not-selected")}
+ <div className={"type-icon filter " + (this.isRefSelected(this.histRef) ? "selected" : "not-selected")}
ref={this.histRef}
data-selected={this.getInitialStatus(DocTypes.HIST)}
onClick={() => { this.onClick(DocTypes.HIST); }}>
- <FontAwesomeIcon className="fontawesome-icon" style={{ order: 1 }} icon={faChartBar} />
+ <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 1 }} icon={faChartBar} />
</div>
<div className="filter-description">Histogram</div>
</div>
<div className="type-outer">
- <div className={"type-icon " + (this.isRefSelected(this.colRef) ? "selected" : "not-selected")}
+ <div className={"type-icon filter " + (this.isRefSelected(this.colRef) ? "selected" : "not-selected")}
ref={this.colRef}
data-selected={this.getInitialStatus(DocTypes.COL)}
onClick={() => { this.onClick(DocTypes.COL); }}>
- <FontAwesomeIcon className="fontawesome-icon" style={{ order: 2 }} icon={faObjectGroup} />
+ <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 2 }} icon={faObjectGroup} />
</div>
<div className="filter-description">Collection</div>
</div>
<div className="type-outer">
- <div className={"type-icon " + (this.isRefSelected(this.imgRef) ? "selected" : "not-selected")}
+ <div className={"type-icon filter " + (this.isRefSelected(this.imgRef) ? "selected" : "not-selected")}
ref={this.imgRef}
data-selected={this.getInitialStatus(DocTypes.IMG)}
onClick={() => { this.onClick(DocTypes.IMG); }}>
- <FontAwesomeIcon className="fontawesome-icon" style={{ order: 3 }} icon={faImage} />
+ <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 3 }} icon={faImage} />
</div>
<div className="filter-description">Image</div>
</div>
<div className="type-outer">
- <div className={"type-icon " + (this.isRefSelected(this.vidRef) ? "selected" : "not-selected")}
+ <div className={"type-icon filter " + (this.isRefSelected(this.vidRef) ? "selected" : "not-selected")}
ref={this.vidRef}
data-selected={this.getInitialStatus(DocTypes.VID)}
onClick={() => { this.onClick(DocTypes.VID); }}>
- <FontAwesomeIcon className="fontawesome-icon" style={{ order: 4 }} icon={faFilm} />
+ <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 4 }} icon={faFilm} />
</div>
<div className="filter-description">Video</div>
</div>
<div className="type-outer">
- <div className={"type-icon " + (this.isRefSelected(this.webRef) ? "selected" : "not-selected")}
+ <div className={"type-icon filter " + (this.isRefSelected(this.webRef) ? "selected" : "not-selected")}
ref={this.webRef}
data-selected={this.getInitialStatus(DocTypes.WEB)}
onClick={() => { this.onClick(DocTypes.WEB); }}>
- <FontAwesomeIcon className="fontawesome-icon" style={{ order: 5 }} icon={faGlobeAsia} />
+ <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 5 }} icon={faGlobeAsia} />
</div>
<div className="filter-description">Web</div>
</div>
<div className="type-outer">
- <div className={"type-icon " + (this.isRefSelected(this.linkRef) ? "selected" : "not-selected")}
+ <div className={"type-icon filter " + (this.isRefSelected(this.linkRef) ? "selected" : "not-selected")}
ref={this.linkRef}
data-selected={this.getInitialStatus(DocTypes.LINK)}
onClick={() => { this.onClick(DocTypes.LINK); }}>
- <FontAwesomeIcon className="fontawesome-icon" style={{ order: 6 }} icon={faLink} />
+ <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 6 }} icon={faLink} />
</div>
<div className="filter-description">Link</div>
</div>
<div className="type-outer">
- <div className={"type-icon " + (this.isRefSelected(this.audioRef) ? "selected" : "not-selected")}
+ <div className={"type-icon filter " + (this.isRefSelected(this.audioRef) ? "selected" : "not-selected")}
ref={this.audioRef}
data-selected={this.getInitialStatus(DocTypes.AUDIO)}
onClick={() => { this.onClick(DocTypes.AUDIO); }}>
- <FontAwesomeIcon className="fontawesome-icon" style={{ order: 7 }} icon={faMusic} />
+ <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 7 }} icon={faMusic} />
</div>
<div className="filter-description">Audio</div>
</div>
<div className="type-outer">
- <div className={"type-icon " + (this.isRefSelected(this.textRef) ? "selected" : "not-selected")}
+ <div className={"type-icon filter " + (this.isRefSelected(this.textRef) ? "selected" : "not-selected")}
ref={this.textRef}
data-selected={this.getInitialStatus(DocTypes.TEXT)}
onClick={() => { this.onClick(DocTypes.TEXT); }}>
- <FontAwesomeIcon className="fontawesome-icon" style={{ order: 8 }} icon={faStickyNote} />
+ <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 8 }} icon={faStickyNote} />
</div>
<div className="filter-description">Text</div>
</div>
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 0303707c7..0b9b84030 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -27,6 +27,9 @@ import { type } from 'os';
@observer
export class SearchBox extends React.Component {
+
+ static Instance: SearchBox;
+
@observable _searchString: string = "";
//if true, any keywords can be used. if false, all keywords are required.
@observable _wordStatus: boolean = true;
@@ -35,6 +38,21 @@ export class SearchBox extends React.Component {
@observable private _resultsOpen: boolean = false;
@observable private _results: Doc[] = [];
@observable filterBoxStatus: boolean = false;
+ @observable filterMenuRef: React.RefObject<HTMLDivElement> = React.createRef();
+ @observable filterButtonRef: React.RefObject<HTMLButtonElement> = React.createRef();
+
+ constructor(props: Readonly<{}>) {
+ super(props);
+ SearchBox.Instance = this;
+ }
+
+ componentDidMount = () => {
+ document.addEventListener("pointerdown", (e) => {
+ if (e.timeStamp !== this._pointerTime) {
+ this.closeSearch();
+ }
+ });
+ }
@action.bound
onChange(e: React.ChangeEvent<HTMLInputElement>) {
@@ -45,7 +63,7 @@ export class SearchBox extends React.Component {
submitSearch = async () => {
let query = this._searchString;
- if(!this._wordStatus){
+ if (!this._wordStatus) {
let oldWords = query.split(" ");
let newWords: string[] = [];
console.log(oldWords);
@@ -87,16 +105,16 @@ export class SearchBox extends React.Component {
return this.filterDocs(docs);
}
- @action filterDocs(docs: Doc[]){
+ @action filterDocs(docs: Doc[]) {
console.log(this._icons)
- if(this._icons.length === 0){
+ if (this._icons.length === 0) {
console.log("length is 0")
return docs;
}
let finalDocs: Doc[] = [];
docs.forEach(doc => {
let layoutresult = Cast(doc.type, "string", "");
- if(this._icons.includes(layoutresult)){
+ if (this._icons.includes(layoutresult)) {
finalDocs.push(doc)
}
});
@@ -120,51 +138,107 @@ export class SearchBox extends React.Component {
}
}
- @action
- handleSearchClick = (e: Event): void => {
- let element = document.getElementsByClassName((e.target as any).className)[0];
- let name: string = (e.target as any).className;
- //handles case with filter button
- if (String(name).indexOf("filter") !== -1 || String(name).indexOf("SVG") !== -1) {
- this._resultsOpen = false;
- this._results = [];
- this._open = true;
- }
- else if (element && element.parentElement) {
- //if the filter element is found, show the form and hide the results
- if (this.findAncestor(element, "filter-form")) {
- this._resultsOpen = false;
- this._results = [];
- this._open = true;
- }
- //if in main search div, keep results open and close filter
- else if (this.findAncestor(element, "main-searchDiv")) {
- this._resultsOpen = true;
- this._open = false;
- }
- }
- //not in either, close both
- else {
- this._resultsOpen = false;
- this._results = [];
- this._open = false;
- }
+ // isClickInFilter(curElement: Element) {
+ // console.log(curElement)
+ // let name: string = curElement.className;
+ // if (name.indexOf("filter") !== -1) {
+ // return true;
+ // }
+ // else {
+ // return this.findAncestor2(name);
- }
+ // // if(curElement.parentElement){
+ // // let parentName = curElement.parentElement.className;
+ // // if(parentName.indexOf("filter") !== -1){
+ // // return true;
+ // // }
+ // // }
+ // }
+ // return false;
+ // }
- //finds ancestor div that matches class name passed in, if not found false returned
- findAncestor(curElement: any, cls: string) {
- while ((curElement = curElement.parentElement) && !curElement.classList.contains(cls));
- return curElement;
- }
+ // findAncestor2(elementName: string){
- componentWillMount() {
- document.addEventListener('mousedown', this.handleSearchClick, false);
- }
+ // if(elementName === ""){
+ // return false;
+ // }
- componentWillUnmount() {
- document.removeEventListener('mousedown', this.handleSearchClick, false);
- }
+ // if(String(elementName).indexOf("filter") !== -1){
+ // return true;
+ // }
+
+ // if(String(elementName).indexOf("SVG")!==-1){
+ // console.log("is svg")
+ // return true;
+ // }
+
+ // let curElement: Element = document.getElementsByClassName(elementName)[0];
+ // let name: string;
+ // while(curElement.parentElement){
+ // name = curElement.className;
+ // if(name.indexOf("filter") !== -1){
+ // return true;
+ // }
+ // curElement = curElement.parentElement;
+ // }
+ // return false;
+ // }
+
+ // @action
+ // handleSearchClick = (e: MouseEvent): void => {
+
+ // // console.log(e)
+
+ // let name: string = (e.target as any).className;
+
+
+
+ // // console.log((e.target as any).className)
+ // let element = document.getElementsByClassName((e.target as any).className)[0];
+ // // console.log(this.findAncestor2(name));
+ // //handles case with filter button
+ // if (String(name).indexOf("filter") !== -1 || String(name).indexOf("SVG") !== -1) {
+ // this._resultsOpen = false;
+ // this._results = [];
+ // this._open = true;
+ // // console.log("name is svg")
+ // }
+ // else if (element && element.parentElement) {
+ // //if the filter element is found, show the form and hide the results
+ // if (this.findAncestor(element, "filter-form")) {
+ // this._resultsOpen = false;
+ // this._results = [];
+ // this._open = true;
+ // // console.log("parent is filter form")
+ // }
+ // //if in main search div, keep results open and close filter
+ // else if (this.findAncestor(element, "main-searchDiv")) {
+ // this._resultsOpen = true;
+ // this._open = false;
+ // }
+ // }
+ // //not in either, close both
+ // else {
+ // this._resultsOpen = false;
+ // this._results = [];
+ // this._open = false;
+ // }
+
+ // }
+
+ // //finds ancestor div that matches class name passed in, if not found false returned
+ // findAncestor(curElement: any, cls: string) {
+ // while ((curElement = curElement.parentElement) && !curElement.classList.contains(cls));
+ // return curElement;
+ // }
+
+ // componentWillMount() {
+ // document.addEventListener('mousedown', this.handleSearchClick, false);
+ // }
+
+ // componentWillUnmount() {
+ // document.removeEventListener('mousedown', this.handleSearchClick, false);
+ // }
enter = (e: React.KeyboardEvent) => {
if (e.key === "Enter") {
@@ -172,6 +246,19 @@ export class SearchBox extends React.Component {
}
}
+ @action.bound
+ closeSearch = () => {
+ this._open = false;
+ this._resultsOpen = false;
+ }
+
+ @action
+ openFilter = () => {
+ this._open = true;
+ this._resultsOpen = false;
+ this._results = [];
+ }
+
collectionRef = React.createRef<HTMLSpanElement>();
startDragCollection = async () => {
const results = await this.getResults(this._searchString);
@@ -235,6 +322,22 @@ export class SearchBox extends React.Component {
return this._icons;
}
+ private _pointerTime: number = -1;
+
+ stopProp = (e: React.PointerEvent) => {
+ e.stopPropagation();
+ console.log('stopping prop')
+ this._pointerTime = e.timeStamp;
+ }
+
+ @action.bound
+ openSearch(e: React.PointerEvent) {
+ e.stopPropagation();
+ this._open = false;
+ this._resultsOpen = true;
+ this._pointerTime = e.timeStamp;
+ }
+
// Useful queries:
// Delegates of a document: {!join from=id to=proto_i}id:{protoId}
// Documents in a collection: {!join from=data_l to=id}id:{collectionProtoId}
@@ -247,9 +350,9 @@ export class SearchBox extends React.Component {
<FontAwesomeIcon icon="object-group" className="searchBox-barChild" size="lg" />
</span>
<input value={this._searchString} onChange={this.onChange} type="text" placeholder="Search..."
- className="searchBox-barChild searchBox-input" onKeyPress={this.enter}
+ className="searchBox-barChild searchBox-input" onPointerDown={this.openSearch} onKeyPress={this.enter}
style={{ width: this._resultsOpen ? "500px" : "100px" }} />
- <button className="searchBox-barChild searchBox-filter">Filter</button>
+ <button className="searchBox-barChild searchBox-filter" onClick={this.openFilter} onPointerDown={this.stopProp} ref={this.filterButtonRef}>Filter</button>
</div>
{this._resultsOpen ? (
<div className="searchBox-results">
@@ -259,14 +362,14 @@ export class SearchBox extends React.Component {
</div>
{/* these all need class names in order to find ancestor - please do not delete */}
{this._open ? (
- <div className="filter-form" id="filter" style={this._open ? { display: "flex" } : { display: "none" }}>
+ <div className="filter-form" onPointerDown={this.stopProp} ref={this.filterMenuRef} id="filter" style={this._open ? { display: "flex" } : { display: "none" }}>
<div className="filter-form filter-div" id="header">Filter Search Results</div>
<div className="filter-form " id="option">
<div className="required-words filter-div">
<ToggleBar originalStatus={this._wordStatus} optionOne={"Include Any Keywords"} optionTwo={"Include All Keywords"} changeStatus={this.handleWordQueryChange} />
</div>
<div className="type-of-node filter-div">
- <IconBar updateIcon={this.updateIcon} getIcons={this.getIcons}/>
+ <IconBar updateIcon={this.updateIcon} getIcons={this.getIcons} />
</div>
<div className="filter-collection filter-div">
temp for filtering by collection
@@ -275,7 +378,7 @@ export class SearchBox extends React.Component {
temp for filtering where in doc the keywords are found
</div>
</div>
- <button className = "reset-filter">Reset Filters</button>
+ <button className="reset-filter">Reset Filters</button>
</div>
) : undefined}
</div>
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index d470090f8..65f4dfd31 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -15,6 +15,7 @@ import { observer } from "mobx-react";
import "./SearchItem.scss";
import { CollectionViewType } from "../collections/CollectionBaseView";
import { DocTypes } from "../../documents/Documents";
+import { SearchBox } from "./SearchBox";
export interface SearchItemProps {
doc: Doc;
@@ -133,10 +134,16 @@ export class SearchItem extends React.Component<SearchItemProps> {
return num.toString() + " links";
}
+ pointerDown = (e: React.PointerEvent) => {
+ SearchBox.Instance.openSearch(e);
+ }
+
render() {
return (
- <div className="search-overview">
- <div className="search-item" ref={this.collectionRef} id="result" onClick={this.onClick} onPointerDown={SetupDrag(this.collectionRef, this.startDocDrag)} >
+ <div className="search-overview" onPointerDown = {this.pointerDown}>
+ <div className="search-item" ref={this.collectionRef} id="result" onClick={this.onClick} onPointerDown={ () => {
+ this.pointerDown;
+ SetupDrag(this.collectionRef, this.startDocDrag);}} >
<div className="main-search-info">
<div className="search-title" id="result" >{this.props.doc.title}</div>
<div className="search-info">