diff --git a/src/views/search/controller.js b/src/views/search/controller.js index 423aa0b..35bdb0c 100644 --- a/src/views/search/controller.js +++ b/src/views/search/controller.js @@ -18,7 +18,153 @@ export class SearchController extends ViewController { 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 => { diff --git a/src/views/search/index.js b/src/views/search/index.js index ba55e2a..c668fe8 100644 --- a/src/views/search/index.js +++ b/src/views/search/index.js @@ -7,8 +7,8 @@ import { SearchController } from './controller'; // The controller for this vie export const searchView = (state, emit) => { const controller = new SearchController(state); - if (!controller.state.done) { - controller.search(state.query.search).then(() => { + if (!controller.state.done && controller.hasQuery) { + controller.searchOpenLibrary(state.query.for).then(() => { emit('render'); }); }