zotero-web-library
Version:
Web library from zotero.org
430 lines (400 loc) • 11.2 kB
JavaScript
'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;