UNPKG

zotero-web-library

Version:

Web library from zotero.org

430 lines (400 loc) 11.2 kB
'use strict'; var log = require('libzotero/lib/Log').Logger('zotero-web-library:SiteSearch'); var net = require('libzotero/lib/Net'); var React = require('react'); var LoadingSpinner = require('./LoadingSpinner.js'); var supportSearchRedirect = function supportSearchRedirect(query) { var q = encodeURIComponent(query + ' site:www.zotero.org/support'); var url = 'https://duckduckgo.com/?q=' + q; window.location = url; }; var forumSearchRedirect = function forumSearchRedirect(query) { var q = encodeURIComponent(query + ' site:forums.zotero.org'); var url = 'https://duckduckgo.com/?q=' + q; /*var url = "https://www.google.com/#q=" + q;*/ window.location = url; }; var UserSearchResult = React.createClass({ displayName: 'UserSearchResult', render: function render() { var user = this.props.user; var profile = user.meta.profile; var profileHref = '/' + user.slug; var imageSrc = 'https://s3.amazonaws.com/zotero.org/images/settings/profile/default_squarethumb.png'; if (user.hasImage == true) { imageSrc = 'https://s3.amazonaws.com/zotero.org/images/settings/profile/' + user.userID + '_squarethumb.png'; } var profileImage = React.createElement( 'a', { href: profileHref }, React.createElement('img', { className: 'small-profile-image media-object', src: imageSrc, alt: user.displayName, title: user.displayName }) ); var profileNodes = ['title', 'affiliation', 'location', 'disciplines'].map(function (field) { if (!profile[field]) { return null; } return React.createElement( 'li', { key: field }, profile[field] ); }); return React.createElement( 'li', { className: 'user-result' }, React.createElement( 'div', { className: 'nugget-user media' }, React.createElement( 'div', { className: 'media-left' }, profileImage ), React.createElement( 'div', { className: 'media-body' }, React.createElement( 'div', { className: 'nugget-name' }, React.createElement( 'a', { href: profileHref }, user.displayName ) ), React.createElement( 'ul', { className: 'nugget-profile list-unstyled' }, profileNodes ) ) ) ); } }); var GroupSearchResult = React.createClass({ displayName: 'GroupSearchResult', render: function render() { var group = this.props.group; var data = group.apiObj.data; var groupHref = group.apiObj.links.alternate; var groupLibraryHref = groupHref + '/items'; var groupImage = null; if (group.wwwData.hasImage) { //let imageSrc = `https://s3.amazonaws.com/zotero.org/images/settings/group/default_squarethumb.png`; var imageSrc = 'https://s3.amazonaws.com/zotero.org/images/settings/group/' + data.groupID + '_squarethumb.png'; groupImage = React.createElement( 'a', { href: groupHref }, React.createElement('img', { className: 'small-profile-image media-object', src: imageSrc, alt: data.name, title: data.name }) ); } var libraryLink = null; if (data.type == 'PublicOpen' || data.type == 'PublicClosed') { libraryLink = React.createElement( 'a', { href: groupLibraryHref }, 'Library' ); } return React.createElement( 'li', { className: 'group-result' }, React.createElement( 'div', { className: 'nugget-group media' }, React.createElement( 'div', { className: 'media-left' }, groupImage ), React.createElement( 'div', { className: 'media-body' }, React.createElement( 'div', { className: 'nugget-name' }, React.createElement( 'a', { href: groupHref }, data.name ) ), React.createElement( 'dl', { 'class': 'nugget-profile' }, React.createElement( 'div', { className: 'nugget-description' }, React.createElement( 'dt', null, 'Description' ), React.createElement( 'dd', null, data.description ) ), React.createElement( 'div', { className: 'nugget-type' }, React.createElement( 'dt', null, 'Type' ), React.createElement( 'dd', null, data.type ) ) ), libraryLink ) ) ); } }); var SiteSearch = React.createClass({ displayName: 'SiteSearch', componentWillMount: function componentWillMount() { Zotero.config.nonparsedBaseUrl = '/search'; }, componentDidMount: function componentDidMount() { if (this.state.query != '') { this.search(); } }, getDefaultProps: function getDefaultProps() { return {}; }, getInitialState: function getInitialState() { var query = Zotero.state.getUrlVar('q'); var type = Zotero.state.getUrlVar('type'); if (type == '' || typeof type == 'undefined') { type = 'support'; } if (typeof query == 'undefined') { log.debug('query is undefined'); query = ''; } return { query: query, type: type, supportType: 'documentation', loading: false, page: 1, results: null, resultCount: null }; }, queryChanged: function queryChanged(evt) { var newq = evt.target.value; this.setState({ query: newq, page: 1 }); }, search: function search(evt) { var _this = this; if (evt) { evt.preventDefault(); } var query = this.state.query; var type = this.state.type; //redirect to duckduckgo if site search if (type == 'support' && this.state.query !== '') { if (this.state.supportType == 'documentation') { supportSearchRedirect(this.state.query); } else if (this.state.supportType == 'forums') { forumSearchRedirect(this.state.query); } } Zotero.state.setQueryVar('q', query); Zotero.state.pushState(); //build local search url var searchPath = '/search/' + type + '?query=' + encodeURIComponent(query); if (this.state.page > 1) { searchPath += '&page=' + this.state.page; } var newState = { loading: true }; if (this.state.page == 1) { newState.results = null; newState.resultCount = null; } this.setState(newState); net.ajax({ type: 'GET', url: searchPath }).then(function (request) { var results = JSON.parse(request.response); var newResultArray = results.results; if (_this.state.page > 1) { newResultArray = _this.state.results.concat(newResultArray); } _this.setState({ resultCount: results.resultCount, results: newResultArray, loading: false }); }); }, loadMore: function loadMore() { var newPage = this.state.page + 1; this.setState({ page: newPage }, this.search); }, setType: function setType(evt) { evt.preventDefault(); var type = evt.currentTarget.getAttribute('data-searchtype'); this.setState({ type: type, results: null, resultCount: null, loading: false }); Zotero.state.setUrlVar('type', type); Zotero.state.pushState(); }, changeSupportType: function changeSupportType(evt) { this.setState({ supportType: evt.target.value }); }, render: function render() { var resultNodes = null; if (this.state.results != null) { switch (this.state.type) { case 'users': resultNodes = this.state.results.map(function (result) { return React.createElement(UserSearchResult, { key: result.userID, user: result }); }); break; case 'groups': resultNodes = this.state.results.map(function (result) { return React.createElement(GroupSearchResult, { key: result.apiObj.id, group: result }); }); break; case 'default': log.warn('unknown search type: ' + this.state.type); } } var usersLiClassname = this.state.type == 'users' ? 'active' : ''; var groupsLiClassname = this.state.type == 'groups' ? 'active' : ''; var supportLiClassname = this.state.type == 'support' ? 'active' : ''; var tabPanel = null; switch (this.state.type) { case 'users': tabPanel = React.createElement( 'form', { onSubmit: this.search }, React.createElement('input', { type: 'text', className: 'textinput form-control', value: this.state.query, onChange: this.queryChanged }) ); break; case 'groups': tabPanel = React.createElement( 'form', { onSubmit: this.search }, React.createElement('input', { type: 'text', className: 'textinput form-control', value: this.state.query, onChange: this.queryChanged }) ); break; case 'support': tabPanel = React.createElement( 'form', { onSubmit: this.search }, React.createElement('input', { type: 'text', className: 'textinput form-control', value: this.state.query, onChange: this.queryChanged }), React.createElement( 'div', { className: 'radio' }, React.createElement( 'label', null, React.createElement('input', { type: 'radio', checked: this.state.supportType == 'documentation', name: 'supportType', value: 'documentation', onChange: this.changeSupportType }), 'Documentation' ) ), React.createElement( 'div', { className: 'radio' }, React.createElement( 'label', null, React.createElement('input', { type: 'radio', checked: this.state.supportType == 'forums', name: 'supportType', value: 'forums', onChange: this.changeSupportType }), 'Forums' ) ) ); break; default: log.warn('unexpected search type: ' + this.state.type); } var moreButton = null; if (this.state.results != null) { if (this.state.resultCount > this.state.results.length) { moreButton = React.createElement( 'button', { className: 'btn btn-default', onClick: this.loadMore }, 'More' ); } } return React.createElement( 'div', { className: 'sitesearch' }, React.createElement( 'h1', null, 'Search' ), React.createElement( 'ul', { className: 'nav nav-pills' }, React.createElement( 'li', { className: usersLiClassname }, React.createElement( 'a', { href: '#', 'data-searchtype': 'users', onClick: this.setType }, React.createElement( 'span', null, 'People' ) ) ), React.createElement( 'li', { className: groupsLiClassname }, React.createElement( 'a', { href: '#', 'data-searchtype': 'groups', onClick: this.setType }, React.createElement( 'span', null, 'Groups' ) ) ), React.createElement( 'li', { className: supportLiClassname }, React.createElement( 'a', { href: '#', 'data-searchtype': 'support', onClick: this.setType }, React.createElement( 'span', null, 'Support' ) ) ) ), React.createElement( 'div', { className: 'tab-content' }, tabPanel ), React.createElement( 'div', { id: 'results' }, React.createElement('h2', { id: 'search-result-count' }), React.createElement(LoadingSpinner, { loading: this.state.loading }), React.createElement( 'ul', { id: 'search-results', className: 'list-unstyled' }, resultNodes ), moreButton ) ); } }); module.exports = SiteSearch;