diff options
| author | madelinegr <monika_hedman@brown.edu> | 2019-06-10 15:45:12 -0400 |
|---|---|---|
| committer | madelinegr <monika_hedman@brown.edu> | 2019-06-10 15:45:12 -0400 |
| commit | 3655e529eef051e3d68f6e9c242d320be9b32906 (patch) | |
| tree | 623c79d092fd17f05126a86c26aa9a98374f0fd3 /src/client/views/SearchBox.tsx | |
| parent | 89b560153d6cb987602a13397c019845143ee70d (diff) | |
end of day 6/10 eek
Diffstat (limited to 'src/client/views/SearchBox.tsx')
| -rw-r--r-- | src/client/views/SearchBox.tsx | 449 |
1 files changed, 0 insertions, 449 deletions
diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx deleted file mode 100644 index 812876d14..000000000 --- a/src/client/views/SearchBox.tsx +++ /dev/null @@ -1,449 +0,0 @@ -import * as React from 'react'; -import { observer } from 'mobx-react'; -import { observable, action, runInAction } from 'mobx'; -import "./SearchBox.scss"; -import { faSearch, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faMusic, faLink, faChartBar, faGlobeAsia, faBan } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { library } from '@fortawesome/fontawesome-svg-core'; -import * as rp from 'request-promise'; -import { SearchItem } from './SearchItem'; -import { DocServer } from '../DocServer'; -import { Doc } from '../../new_fields/Doc'; -import { Id } from '../../new_fields/FieldSymbols'; -import { SetupDrag } from '../util/DragManager'; -import { Docs, DocTypes } from '../documents/Documents'; -import { RouteStore } from '../../server/RouteStore'; -import { NumCast } from '../../new_fields/Types'; -import { SearchUtil } from '../util/SearchUtil'; -import * as anime from 'animejs'; -import { updateFunction } from '../../new_fields/util'; -import * as _ from "lodash"; -// import "./globalCssVariables.scss"; -import { findDOMNode } from 'react-dom'; - -// import * as anime from '../../../node_modules/@types'; -// const anime = require('lib/anime.js'); -// import anime from 'animejs/lib/anime.es'; -// import anime = require ('lib/anime.min.js'); -// import Anime from 'react-anime'; - -library.add(faSearch); -library.add(faObjectGroup); -library.add(faImage); -library.add(faStickyNote); -library.add(faFilePdf); -library.add(faFilm); -library.add(faMusic); -library.add(faLink); -library.add(faChartBar); -library.add(faGlobeAsia); -library.add(faBan); - -export interface IconBarProps { - updateIcon(newIcons: string[]): void; - getIcons(): string[]; -} - -@observer -export class IconBar extends React.Component<IconBarProps> { - - @observable newIcons: string[] = []; - - //changes colors of buttons on click - not sure if this is the best method (it probably isn't) - //but i spent a ton of time on it and this is the only thing i could get to work - componentDidMount = () => { - - let buttons = document.querySelectorAll<HTMLDivElement>(".type-icon").forEach(node => - node.addEventListener('click', function () { - if (this.style.backgroundColor === "rgb(194, 194, 197)") { - this.style.backgroundColor = "#121721"; - } - else { - this.style.backgroundColor = "#c2c2c5" - } - }) - ); - - } - - onClick = (value: string) => { - let oldIcons = this.props.getIcons() - if (value === DocTypes.NONE) { - this.newIcons = [value]; - //if its none, change the color of all the other circles - document.querySelectorAll<HTMLDivElement>(".type-icon").forEach(node => { - if (node.id === "none") { - node.style.backgroundColor = "#c2c2c5"; - } - else { - node.style.backgroundColor = "#121721"; - } - } - ); - } - else { - //turns "none" button off - let noneDoc = document.getElementById(DocTypes.NONE) - if(noneDoc){ - noneDoc.style.backgroundColor = "#121721"; - } - if (oldIcons.includes(value)) { - this.newIcons = _.remove(oldIcons, value); - if (this.newIcons.length === 0) { - this.newIcons = [DocTypes.NONE]; - } - } - else { - this.newIcons = oldIcons; - if (this.newIcons.length === 1 && this.newIcons[0] === DocTypes.NONE) { - this.newIcons = [value] - } - else { this.newIcons.push(value); } - } - } - this.props.updateIcon(this.newIcons) - - } - - render() { - - return ( - <div> - <div className="icon-bar"> - <div className="type-icon" id="none" - onClick={() => { this.onClick(DocTypes.NONE) }}> - <FontAwesomeIcon className="fontawesome-icon" style={{ order: -2 }} icon={faBan} /> - </div> - <div className="type-icon" - onClick={() => { this.onClick(DocTypes.PDF) }}> - <FontAwesomeIcon className="fontawesome-icon" style={{ order: 0 }} icon={faFilePdf} /> - </div> - <div className="type-icon" - onClick={() => { this.onClick(DocTypes.HIST) }}> - <FontAwesomeIcon className="fontawesome-icon" style={{ order: 1 }} icon={faChartBar} /> - </div> - <div className="type-icon" - onClick={() => { this.onClick(DocTypes.COL) }}> - <FontAwesomeIcon className="fontawesome-icon" style={{ order: 2 }} icon={faObjectGroup} /> - </div> - <div className="type-icon" - onClick={() => { this.onClick(DocTypes.IMG) }}> - <FontAwesomeIcon className="fontawesome-icon" style={{ order: 3 }} icon={faImage} /> - </div> - <div className="type-icon" - onClick={() => { this.onClick(DocTypes.VID) }}> - <FontAwesomeIcon className="fontawesome-icon" style={{ order: 4 }} icon={faFilm} /> - </div> - <div className="type-icon" - onClick={() => { this.onClick(DocTypes.WEB) }}> - <FontAwesomeIcon className="fontawesome-icon" style={{ order: 5 }} icon={faGlobeAsia} /> - </div> - <div className="type-icon" - onClick={() => { this.onClick(DocTypes.LINK) }}> - <FontAwesomeIcon className="fontawesome-icon" style={{ order: 6 }} icon={faLink} /> - </div> - <div className="type-icon" - onClick={() => { this.onClick(DocTypes.AUDIO) }}> - <FontAwesomeIcon className="fontawesome-icon" style={{ order: 7 }} icon={faMusic} /> - </div> - <div className="type-icon" - onClick={() => { this.onClick(DocTypes.TEXT) }}> - <FontAwesomeIcon className="fontawesome-icon" style={{ order: 8 }} icon={faStickyNote} /> - </div> - </div> - </div> - ) - } -} - -export interface ToggleBarProps { - //false = right, true = left - // status: boolean; - changeStatus(value: boolean): void; - optionOne: string; - optionTwo: string; -} - -//TODO: justify content will align to specific side. Maybe do status passed in and out? -@observer -export class ToggleBar extends React.Component<ToggleBarProps>{ - - @observable _status: boolean = false; - @observable timeline: anime.AnimeTimelineInstance; - @observable _toggleButton: React.RefObject<HTMLDivElement>; - - constructor(props: ToggleBarProps) { - super(props); - this._toggleButton = React.createRef(); - this.timeline = anime.timeline({ - autoplay: false, - direction: "reverse" - }); - } - - componentDidMount = () => { - - let bar = document.getElementById("toggle-bar"); - let tog = document.getElementById("toggle-button"); - let barwidth = 0; - let togwidth = 0; - if (bar && tog) { - barwidth = bar.clientWidth; - togwidth = tog.clientWidth; - } - let totalWidth = (barwidth - togwidth - 10); - - this.timeline.add({ - targets: this._toggleButton.current, - loop: false, - translateX: totalWidth, - easing: "easeInOutQuad", - duration: 500 - }); - } - - @action.bound - onclick() { - this._status = !this._status; - this.props.changeStatus(this._status); - this.timeline.play(); - this.timeline.reverse(); - } - - render() { - return ( - <div> - <div className="toggle-title"> - <div className="toggle-option">{this.props.optionOne}</div> - <div className="toggle-option">{this.props.optionTwo}</div> - </div> - <div className="toggle-bar" id="toggle-bar"> - <div className="toggle-button" id="toggle-button" ref={this._toggleButton} onClick={this.onclick} /> - </div> - </div> - ); - }; -} - - -@observer -export class SearchBox extends React.Component { - @observable _searchString: string = ""; - @observable _wordStatus: boolean = true; - @observable _icons: string[] = ["none"]; - @observable private _open: boolean = false; - @observable private _resultsOpen: boolean = false; - @observable private _results: Doc[] = []; - - @action.bound - onChange(e: React.ChangeEvent<HTMLInputElement>) { - this._searchString = e.target.value; - } - - @action - submitSearch = async () => { - let query = this._searchString; - //gets json result into a list of documents that can be used - const results = await this.getResults(query); - - runInAction(() => { - this._resultsOpen = true; - this._results = results; - }); - - } - - @action - getResults = async (query: string) => { - let response = await rp.get(DocServer.prepend('/search'), { - qs: { - query - } - }); - let res: string[] = JSON.parse(response); - const fields = await DocServer.GetRefFields(res); - const docs: Doc[] = []; - for (const id of res) { - const field = fields[id]; - if (field instanceof Doc) { - docs.push(field); - } - } - return docs; - } - - public static async convertDataUri(imageUri: string, returnedFilename: string) { - try { - let posting = DocServer.prepend(RouteStore.dataUriToImage); - const returnedUri = await rp.post(posting, { - body: { - uri: imageUri, - name: returnedFilename - }, - json: true, - }); - return returnedUri; - - } catch (e) { - console.log(e); - } - } - - @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._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._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._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") { - this.submitSearch(); - } - } - - collectionRef = React.createRef<HTMLSpanElement>(); - startDragCollection = async () => { - const results = await this.getResults(this._searchString); - const docs = results.map(doc => { - const isProto = Doc.GetT(doc, "isPrototype", "boolean", true); - if (isProto) { - return Doc.MakeDelegate(doc); - } else { - return Doc.MakeAlias(doc); - } - }); - let x = 0; - let y = 0; - for (const doc of docs) { - doc.x = x; - doc.y = y; - const size = 200; - const aspect = NumCast(doc.nativeHeight) / NumCast(doc.nativeWidth, 1); - if (aspect > 1) { - doc.height = size; - doc.width = size / aspect; - } else if (aspect > 0) { - doc.width = size; - doc.height = size * aspect; - } else { - doc.width = size; - doc.height = size; - } - doc.zoomBasis = 1; - x += 250; - if (x > 1000) { - x = 0; - y += 300; - } - } - return Docs.FreeformDocument(docs, { width: 400, height: 400, panX: 175, panY: 175, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` }); - } - - @action - getViews = async (doc: Doc) => { - const results = await SearchUtil.GetViewsOfDocument(doc); - let toReturn: Doc[] = []; - await runInAction(() => { - toReturn = results; - }); - return toReturn; - } - - handleWordQueryChange = (value: boolean) => { - this._wordStatus = value; - } - - @action.bound - updateIcon(newArray: string[]) { - this._icons = newArray; - } - - @action.bound - getIcons(): string[] { - return this._icons; - } - - // 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} - render() { - return ( - <div> - <div className="searchBox-container"> - <div className="searchBox-bar"> - <span onPointerDown={SetupDrag(this.collectionRef, this.startDragCollection)} ref={this.collectionRef}> - <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} - style={{ width: this._resultsOpen ? "500px" : "100px" }} /> - <button className="searchBox-barChild searchBox-filter">Filter</button> - </div> - {this._resultsOpen ? ( - <div className="searchBox-results"> - {this._results.map(result => <SearchItem doc={result} key={result[Id]} />)} - </div> - ) : undefined} - </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" id="header">Filter Search Results</div> - <div className="filter-form" id="option"> - <div className="required-words"> - <ToggleBar optionOne={"Include Any Keywords"} optionTwo={"Include All Keywords"} changeStatus={this.handleWordQueryChange} /> - </div> - <div className="type-of-node"> - temp for filtering by a type of node - <IconBar updateIcon={this.updateIcon} getIcons={this.getIcons} /> - </div> - <div className="filter-collection"> - temp for filtering by collection - </div> - <div className="where-in-doc"> - temp for filtering where in doc the keywords are found - </div> - </div> - </div> - ) : undefined} - </div> - ); - } -}
\ No newline at end of file |
