/* eslint-disable node/no-unpublished-import */ import { jml, body, nbsp } from 'jamilih' import $ from 'query-result' import { manipulation } from 'qr-manipulation' manipulation($, jml) const baseAPIURL = 'https://openclipart.org/search/json/' const jsVoid = 'javascript: void(0);' /** * Shows results after query submission. * @param {string} url * @returns {Promise} */ async function processResults (url) { /** * @param {string} query * @returns {external:JamilihArray} */ function queryLink (query) { return ['a', { href: jsVoid, dataset: { value: query }, $on: { click (e) { e.preventDefault() const { value } = this.dataset $('#query')[0].$set(value) $('#openclipart')[0].$submit() } } }, [query]] } const r = await fetch(url) const json = await r.json() if (!json || json.msg !== 'success') { // Todo: This could use a generic alert library instead alert('There was a problem downloading the results') return } const { payload, info: { results: numResults, pages, current_page: currentPage } } = json // $('#page')[0].value = currentPage; // $('#page')[0].max = pages; // Unused properties: // - `svg_filesize` always 0? // - `dimensions: { // png_thumb: {width, height}, // png_full_lossy: {width, height} // }` object of relevance? // - No need for `tags` with `tags_array` // - `svg`'s: `png_thumb`, `png_full_lossy`, `png_2400px` const semiColonSep = '; ' + nbsp $('#results').jml('div', [ ['span', [ 'Number of results: ', numResults ]], semiColonSep, ['span', [ 'page ', currentPage, ' out of ', pages ]], ...payload.map(({ title, description, id, uploader, created, svg: { url: svgURL }, detail_link: detailLink, tags_array: tagsArray, downloaded_by: downloadedBy, total_favorites: totalFavorites }) => { const imgHW = '100px' const colonSep = ': ' + nbsp return ['div', [ ['button', { style: 'margin-right: 8px; border: 2px solid black;', dataset: { id, value: svgURL }, $on: { async click (e) { e.preventDefault() const { value: svgurl } = this.dataset const post = (message) => { // Todo: Make origin customizable as set by opening window // Todo: If dropping IE9, avoid stringifying window.parent.postMessage(JSON.stringify({ namespace: 'imagelib', ...message }), '*') } // Send metadata (also indicates file is about to be sent) post({ name: title, id: svgurl }) const result = await fetch(svgurl) const svg = await result.text() post({ href: svgurl, data: svg }) } } }, [ // If we wanted interactive versions despite security risk: // ['object', {data: svgURL, type: 'image/svg+xml'}] ['img', { src: svgURL, style: `width: ${imgHW}; height: ${imgHW};` }] ]], ['b', [title]], ' ', ['i', [description]], ' ', ['span', [ '(ID: ', ['a', { href: jsVoid, dataset: { value: id }, $on: { click (e) { e.preventDefault() const { value } = this.dataset $('#byids')[0].$set(value) $('#openclipart')[0].$submit() } } }, [id]], ')' ]], ' ', ['i', [ ['a', { href: detailLink, target: '_blank' }, ['Details']] ]], ['br'], ['span', [ ['u', ['Uploaded by']], colonSep, queryLink(uploader), semiColonSep ]], ['span', [ ['u', ['Download count']], colonSep, downloadedBy, semiColonSep ]], ['span', [ ['u', ['Times used as favorite']], colonSep, totalFavorites, semiColonSep ]], ['span', [ ['u', ['Created date']], colonSep, created ]], ['br'], ['u', ['Tags']], colonSep, ...tagsArray.map((tag) => { return ['span', [ ' ', queryLink(tag) ]] }) ]] }), ['br'], ['br'], (currentPage === 1 || pages <= 2 ? '' : ['span', [ ['a', { href: jsVoid, $on: { click (e) { e.preventDefault() $('#page')[0].value = 1 $('#openclipart')[0].$submit() } } }, ['First']], ' ' ]] ), (currentPage === 1 ? '' : ['span', [ ['a', { href: jsVoid, $on: { click (e) { e.preventDefault() $('#page')[0].value = currentPage - 1 $('#openclipart')[0].$submit() } } }, ['Prev']], ' ' ]] ), (currentPage === pages ? '' : ['span', [ ['a', { href: jsVoid, $on: { click (e) { e.preventDefault() $('#page')[0].value = currentPage + 1 $('#openclipart')[0].$submit() } } }, ['Next']], ' ' ]] ), (currentPage === pages || pages <= 2 ? '' : ['span', [ ['a', { href: jsVoid, $on: { click (e) { e.preventDefault() $('#page')[0].value = pages $('#openclipart')[0].$submit() } } }, ['Last']], ' ' ]] ) ]) } jml('div', [ ['style', [ `.control { padding-top: 10px; }` ]], ['form', { id: 'openclipart', $custom: { async $submit () { const url = new URL(baseAPIURL); [ 'query', 'sort', 'amount', 'page', 'byids' ].forEach((prop) => { const { value } = $('#' + prop)[0] if (value) { url.searchParams.set(prop, value) } }) await processResults(url) } }, $on: { submit (e) { e.preventDefault() this.$submit() } } }, [ // Todo: i18nize ['fieldset', [ ['legend', ['Search terms']], ['div', { class: 'control' }, [ ['label', [ 'Query (Title, description, uploader, or tag): ', ['input', { id: 'query', name: 'query', placeholder: 'cat', $custom: { $set (value) { $('#byids')[0].value = '' this.value = value } }, $on: { change () { $('#byids')[0].value = '' } } }] ]] ]], ['br'], ' OR ', ['br'], ['div', { class: 'control' }, [ ['label', [ 'IDs (single or comma-separated): ', ['input', { id: 'byids', name: 'ids', placeholder: '271380, 265741', $custom: { $set (value) { $('#query')[0].value = '' this.value = value } }, $on: { change () { $('#query')[0].value = '' } } }] ]] ]] ]], ['fieldset', [ ['legend', ['Configuring results']], ['div', { class: 'control' }, [ ['label', [ 'Sort by: ', ['select', { id: 'sort' }, [ // Todo: i18nize first values ['Date', 'date'], ['Downloads', 'downloads'], ['Favorited', 'favorites'] ].map(([text, value = text]) => { return ['option', { value }, [text]] })] ]] ]], ['div', { class: 'control' }, [ ['label', [ 'Results per page: ', ['input', { id: 'amount', name: 'amount', value: 10, type: 'number', min: 1, max: 200, step: 1, pattern: '\\d+' }] ]] ]], ['div', { class: 'control' }, [ ['label', [ 'Page number: ', ['input', { // max: 1, // We'll change this based on available results id: 'page', name: 'page', value: 1, style: 'width: 40px;', type: 'number', min: 1, step: 1, pattern: '\\d+' }] ]] ]] ]], ['div', { class: 'control' }, [ ['input', { type: 'submit' }] ]] ]], ['div', { id: 'results' }] ], body)