206 lines
7.3 KiB
JavaScript
206 lines
7.3 KiB
JavaScript
|
import { ViewController } from '../controller';
|
||
|
|
||
|
export class SearchController extends ViewController {
|
||
|
constructor(state) {
|
||
|
// Super passes state, view name, and default state to ViewController,
|
||
|
// which stores state in this.appState and the view controller's state to this.state
|
||
|
super(state, 'search', {
|
||
|
done: false,
|
||
|
results: [],
|
||
|
});
|
||
|
|
||
|
// If using controller methods in an input's onchange or onclick instance,
|
||
|
// either bind the class's 'this' instance to the method first...
|
||
|
// or use `onclick=${() => controller.submit()}` to maintain the 'this' of the class instead.
|
||
|
}
|
||
|
|
||
|
get results() {
|
||
|
return [...this.state.results];
|
||
|
}
|
||
|
|
||
|
get hasQuery() {
|
||
|
return this.appState.query.hasOwnProperty('for') && this.appState.query.for.trim() !== '';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Query a MediaWiki api.php instance with the given options
|
||
|
*/
|
||
|
mediaWikiQuery(endpoint, options) {
|
||
|
/**
|
||
|
* Create a uniquely-named callback that will process the JSONP results
|
||
|
*/
|
||
|
var createCallback = function (k) {
|
||
|
var i = 1;
|
||
|
var callbackName;
|
||
|
do {
|
||
|
callbackName = 'searchCallback' + i;
|
||
|
i = i + 1;
|
||
|
} while (window[callbackName])
|
||
|
window[callbackName] = k;
|
||
|
return callbackName;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Flatten an object into a URL query string.
|
||
|
* For example: { foo: 'bar', baz: 42 } becomes 'foo=bar&baz=42'
|
||
|
*/
|
||
|
var queryStr = function (options) {
|
||
|
var query = [];
|
||
|
for (var i in options) {
|
||
|
if (options.hasOwnProperty(i)) {
|
||
|
query.push(encodeURIComponent(i) + '=' + encodeURIComponent(options[i]));
|
||
|
}
|
||
|
}
|
||
|
return query.join('&');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Build a function that can be applied to a callback. The callback processes
|
||
|
* the JSON results of the API call.
|
||
|
*/
|
||
|
return function (k) {
|
||
|
options.format = 'json';
|
||
|
options.callback = createCallback(k);
|
||
|
var script = document.createElement('script');
|
||
|
script.id = 'searchResults';
|
||
|
script.src = endpoint + '?' + queryStr(options);
|
||
|
var head = document.getElementsByTagName('head')[0];
|
||
|
head.appendChild(script);
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
search(term) {
|
||
|
const query = this.mediaWikiQuery('https://en.wikibooks.org/w/api.php', {
|
||
|
action: 'query',
|
||
|
list: 'search',
|
||
|
// list: 'categorymembers',
|
||
|
// cmtitle: 'Category:Subject:Books by subject/all books',
|
||
|
srsearch: term,
|
||
|
srprop: '',
|
||
|
// pageids: 20308,
|
||
|
// prop: 'categories|pageprops',
|
||
|
});
|
||
|
query(response => {
|
||
|
console.log(response);
|
||
|
const searchScript = document.getElementById('searchResults');
|
||
|
searchScript.parentNode.removeChild(searchScript);
|
||
|
for (let property in window) {
|
||
|
if (property.includes('searchCallback')) {
|
||
|
delete window[property];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const bookResults = [];
|
||
|
const pageids = response.query.search.map(item => item.pageid);
|
||
|
const propsQuery = this.mediaWikiQuery('https://en.wikibooks.org/w/api.php', {
|
||
|
action: 'query',
|
||
|
pageids: pageids.join('|'),
|
||
|
prop: 'categories|pageprops',
|
||
|
});
|
||
|
propsQuery(propsResponse => {
|
||
|
console.log(propsResponse);
|
||
|
for (let pageid in propsResponse.query.pages) {
|
||
|
if (propsResponse.query.pages[pageid].hasOwnProperty('categories')) {
|
||
|
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
// this.state.results = results;
|
||
|
this.state.done = true;
|
||
|
});
|
||
|
|
||
|
// return fetch(`https://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=${term}&format=json&callback=searchCallback`, {
|
||
|
// method: 'GET',
|
||
|
// mode: 'no-cors',
|
||
|
// headers: new Headers(
|
||
|
// {
|
||
|
// "Accept": "text/plain"
|
||
|
// }
|
||
|
// ),
|
||
|
// // body: JSON.stringify({
|
||
|
// // action: 'opensearch',
|
||
|
// // search: term,
|
||
|
// // format: 'json',
|
||
|
// // }),
|
||
|
// })
|
||
|
// .then(res => res.text())
|
||
|
// .then(response => {
|
||
|
// console.log(response);
|
||
|
// // if (response.hasOwnProperty('docs')) {
|
||
|
// // // Format the response into usable objects
|
||
|
// // const docs = response.docs.map(doc => {
|
||
|
// // return {
|
||
|
// // title: doc.title_suggest.trim(),
|
||
|
// // authors: doc.hasOwnProperty('author_name') ? doc.author_name.map(name => name.trim()) : [],
|
||
|
// // cover: doc.hasOwnProperty('cover_i') ? `//covers.openlibrary.org/b/id/${doc.cover_i}-S.jpg` : false,
|
||
|
// // };
|
||
|
// // });
|
||
|
|
||
|
// // // Filter out duplicate items with the same title and author
|
||
|
// // const results = docs.filter((doc, index, allDocs) => {
|
||
|
// // return typeof allDocs.find((filterResult, filterIndex) => {
|
||
|
// // return index !== filterIndex && filterResult.title === doc.title
|
||
|
// // && JSON.stringify(filterResult.authors) === JSON.stringify(doc.authors);
|
||
|
// // }) === 'undefined';
|
||
|
// // }).map(result => {
|
||
|
// // // Find any duplicates in case they have different cover data
|
||
|
// // const duplicates = docs.filter(doc => {
|
||
|
// // return doc.title.toLowerCase() === result.title.toLowerCase() && JSON.stringify(doc.authors) === JSON.stringify(result.authors);
|
||
|
// // });
|
||
|
// // result.covers = [];
|
||
|
// // duplicates.forEach(duplicate => {
|
||
|
// // if (duplicate.cover !== false) {
|
||
|
// // result.covers.push(duplicate.cover);
|
||
|
// // }
|
||
|
// // });
|
||
|
// // return result;
|
||
|
// // });
|
||
|
|
||
|
// // this.state.results = results;
|
||
|
// this.state.done = true;
|
||
|
// // }
|
||
|
// });
|
||
|
}
|
||
|
|
||
|
searchOpenLibrary(term) {
|
||
|
this.state.done = false;
|
||
|
return fetch('http://openlibrary.org/search.json?q=' + encodeURIComponent(term))
|
||
|
.then(res => res.json())
|
||
|
.then(response => {
|
||
|
if (response.hasOwnProperty('docs')) {
|
||
|
// Format the response into usable objects
|
||
|
const docs = response.docs.map(doc => {
|
||
|
return {
|
||
|
title: doc.title_suggest.trim(),
|
||
|
authors: doc.hasOwnProperty('author_name') ? doc.author_name.map(name => name.trim()) : [],
|
||
|
cover: doc.hasOwnProperty('cover_i') ? `//covers.openlibrary.org/b/id/${doc.cover_i}-S.jpg` : false,
|
||
|
};
|
||
|
});
|
||
|
|
||
|
// Filter out duplicate items with the same title and author
|
||
|
const results = docs.filter((doc, index, allDocs) => {
|
||
|
return typeof allDocs.find((filterResult, filterIndex) => {
|
||
|
return index !== filterIndex && filterResult.title === doc.title
|
||
|
&& JSON.stringify(filterResult.authors) === JSON.stringify(doc.authors);
|
||
|
}) === 'undefined';
|
||
|
}).map(result => {
|
||
|
// Find any duplicates in case they have different cover data
|
||
|
const duplicates = docs.filter(doc => {
|
||
|
return doc.title.toLowerCase() === result.title.toLowerCase() && JSON.stringify(doc.authors) === JSON.stringify(result.authors);
|
||
|
});
|
||
|
result.covers = [];
|
||
|
duplicates.forEach(duplicate => {
|
||
|
if (duplicate.cover !== false) {
|
||
|
result.covers.push(duplicate.cover);
|
||
|
}
|
||
|
});
|
||
|
return result;
|
||
|
});
|
||
|
|
||
|
this.state.results = results;
|
||
|
this.state.done = true;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|