From: Dan Brown Date: Mon, 9 May 2022 17:08:36 +0000 (+0100) Subject: Added google search results chrome extension example X-Git-Url: http://source.bookstackapp.com/api-scripts/commitdiff_plain/b06661c944b516e6b4626897e581debe8ef2c3bd Added google search results chrome extension example --- diff --git a/chrome-extension-google-search-results/background.js b/chrome-extension-google-search-results/background.js new file mode 100644 index 0000000..92925af --- /dev/null +++ b/chrome-extension-google-search-results/background.js @@ -0,0 +1,61 @@ +// Listen to messages from our content-script +chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { + + + // If we're receiving a message with a query, search BookStack + // and return the BookStack results in the response. + if (request.query) { + searchBookStack(request.query).then(results => { + if (results) { + sendResponse({results}); + } + }); + } + + // Return true enables 'sendResponse' to work async + return true; +}); + + +// Search our BookStack instance using the given query +async function searchBookStack(query) { + + // Load BookStack API details from our options + const options = await loadOptions(); + for (const option of Object.values(options)) { + if (!option) { + console.log('Missing a required option'); + return; + } + } + + // Query BookStack, making an authorized API search request + const url = `${options.baseUrl}/api/search?query=${encodeURIComponent(query)}`; + const resp = await fetch(url, { + method: 'GET', + headers: { + Authorization: `Token ${options.tokenId}:${options.tokenSecret}`, + } + }); + + // Parse the JSON response and return the results + const data = await resp.json(); + return data.data || null; +} + + +/** + * Load our options from chrome's storage. + * @returns Promise + */ +function loadOptions() { + return new Promise((res, rej) => { + chrome.storage.sync.get({ + tokenId: '', + tokenSecret: '', + baseUrl: '', + }, options => { + res(options); + }) + }); +} \ No newline at end of file diff --git a/chrome-extension-google-search-results/content-script.js b/chrome-extension-google-search-results/content-script.js new file mode 100644 index 0000000..ab5c690 --- /dev/null +++ b/chrome-extension-google-search-results/content-script.js @@ -0,0 +1,39 @@ +const url = new URL(window.location.href); +const query = url.searchParams.get("q"); +const resultContainer = document.getElementById('search'); + +// If we have a query in the URL, and a '#search' section, we are +// likely on a search results page so we kick-off the display of +// results by messaging the back-end to make the request to BookStack. +if (query && resultContainer) { + + chrome.runtime.sendMessage({query}, function(response) { + // If re receive results back from our background script API call, + // show them on the current page. + if (response.results) { + showResults(response.results); + } + }); + +} + +/** + * Display the given API search result objects as a list of links on + * the current page, within the '#search' section. + * @param {Object[]} results + */ +function showResults(results) { + const resultHTML = results.map(result => { + return ` + +

${result.type.toUpperCase()}: ${result.preview_html.name}

+

${result.preview_html.content}

+
+ `; + }).join('\n'); + + const header = `

BookStack Results

`; + const container = document.createElement('div'); + container.innerHTML = header + resultHTML + '
'; + resultContainer.prepend(container); +} \ No newline at end of file diff --git a/chrome-extension-google-search-results/manifest.json b/chrome-extension-google-search-results/manifest.json new file mode 100644 index 0000000..3d849e9 --- /dev/null +++ b/chrome-extension-google-search-results/manifest.json @@ -0,0 +1,21 @@ +{ + "name": "BookStack Google Search", + "description": "A simple demo extension to show BookStack results in google", + "version": "1.0", + "manifest_version": 3, + "permissions": ["storage"], + "host_permissions": ["http://*/", "https://*/"], + "options_page": "options.html", + "background": { + "service_worker": "background.js" + }, + "externally_connectable": { + "matches": ["https://*.google.com/*"] + }, + "content_scripts": [ + { + "matches": ["https://*.google.com/*"], + "js": ["content-script.js"] + } + ] + } \ No newline at end of file diff --git a/chrome-extension-google-search-results/options.html b/chrome-extension-google-search-results/options.html new file mode 100644 index 0000000..9ca2d04 --- /dev/null +++ b/chrome-extension-google-search-results/options.html @@ -0,0 +1,55 @@ + + + + + + + Options + + + + + + + +
+ +
+ + +

(No trailing slashes, Do not include '/api/' in URL, Must start with https:// or http://)

+
+ +
+ + +
+ +
+ + +
+ + + +

+ +
+ + + + + + \ No newline at end of file diff --git a/chrome-extension-google-search-results/options.js b/chrome-extension-google-search-results/options.js new file mode 100644 index 0000000..01a3829 --- /dev/null +++ b/chrome-extension-google-search-results/options.js @@ -0,0 +1,30 @@ +const inputs = [...document.querySelectorAll('input[type="text"]')]; +const form = document.querySelector('form'); +const message = document.getElementById('message'); + +// Store settings on submit +form.addEventListener('submit', event => { + + event.preventDefault(); + + const settings = {}; + for (const input of inputs) { + settings[input.name] = input.value; + } + + chrome.storage.sync.set(settings, () => { + message.textContent = 'Settings updated!'; + }); + +}); + +// Restore settings on load +chrome.storage.sync.get({ + tokenId: '', + tokenSecret: '', + baseUrl: '', +}, settings => { + for (const input of inputs) { + input.value = settings[input.name]; + } +}); \ No newline at end of file diff --git a/chrome-extension-google-search-results/readme.md b/chrome-extension-google-search-results/readme.md new file mode 100644 index 0000000..1e094d2 --- /dev/null +++ b/chrome-extension-google-search-results/readme.md @@ -0,0 +1,29 @@ +# BookStack in Google Search Results Chrome Extension + +This is a very rough and simplistic example of a Google chrome extension that will inject BookStack +search results into the page when making google.com searches. + +**This is only meant as an example or foundation**, it is not a fully featured/finished/tested extension. +The styles are quite bad and it may be prone to breaking. I am not looking to improve or expand this extension +so PRs, unless minor issue fixes, will not be accepted. + +If you look to build this out into a proper chrome-store extension, please don't use the "BookStack" name +or logo alone and make it clear your extension is unofficial. + +## Requirements + +You will need a Chrome (or Chromium based browser) instance where you can enable developer mode in extensions. +You will also need BookStack API credentials (TOKEN_ID & TOKEN_SECRET) at the ready. + +## Usage + +This extension is not on the app store but you can side-load it with relative ease. +Within chrome: + +- Go to "Manage Extensions" +- Toggle "Developer mode" on. +- Click the "Load unpacked" option. +- Select this folder. + +You will need to configure the extension options and fill in your BookStack instance API details. +You can get to this by right-clicking the extension in the top of the browser and clicking "Options", or via "Manage Extension" > Click "Details" on the extension > "Extension Options". \ No newline at end of file