API search now works
This commit is contained in:
parent
976f535aec
commit
68a1e27881
7 changed files with 296 additions and 42 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
246
public/scripts/plugins/jets.js
Normal file
246
public/scripts/plugins/jets.js
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
/* global define */
|
||||||
|
|
||||||
|
/*! Jets.js - v0.14.1 - 2018-06-22
|
||||||
|
* http://NeXTs.github.com/Jets.js/
|
||||||
|
* Copyright (c) 2015 Denis Lukov; Refactored 2018 Paul Anthony Webb; Licensed MIT */
|
||||||
|
|
||||||
|
(function (root, definition) {
|
||||||
|
if (typeof module !== "undefined") module.exports = definition();
|
||||||
|
else if (typeof define === "function" && typeof define.amd === "object") define(definition);
|
||||||
|
else root["Jets"] = definition();
|
||||||
|
}(this, function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function Jets(opts) {
|
||||||
|
if (!(this instanceof Jets)) return new Jets(opts);
|
||||||
|
|
||||||
|
const defaults = {
|
||||||
|
diacriticsMap: {},
|
||||||
|
hideBy: "display: none",
|
||||||
|
searchSelector: "*AND"
|
||||||
|
};
|
||||||
|
|
||||||
|
const self = this;
|
||||||
|
self.options = {};
|
||||||
|
|
||||||
|
[
|
||||||
|
"addImportant",
|
||||||
|
"callSearchManually",
|
||||||
|
"columns",
|
||||||
|
"diacriticsMap",
|
||||||
|
"didSearch",
|
||||||
|
"hideBy",
|
||||||
|
"invert",
|
||||||
|
"manualContentHandling",
|
||||||
|
"searchInSpecificColumn",
|
||||||
|
"searchSelector"
|
||||||
|
].forEach(name => self.options[name] = opts[name] || defaults[name]);
|
||||||
|
|
||||||
|
if (this.options.searchSelector.length > 1) {
|
||||||
|
const searchSelector = self.options["searchSelector"].trim();
|
||||||
|
|
||||||
|
self.options.searchSelector = searchSelector.substr(0, 1);
|
||||||
|
self.options.searchSelectorMode = searchSelector.substr(1).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.content_tag = document.querySelectorAll(opts.contentTag);
|
||||||
|
if (!self.content_tag) throw new Error("Error! Could not find contentTag element");
|
||||||
|
self.content_param = opts.contentTag;
|
||||||
|
self.search_tag = document.querySelector(opts.searchTag);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!self.search_tag &&
|
||||||
|
!self.options.callSearchManually
|
||||||
|
) throw new Error("Error! Provide one of search methods: searchTag or callSearchManually and call .search(\"phrase\") manually");
|
||||||
|
|
||||||
|
let last_search_query = self.search_tag && self.search_tag.value || "";
|
||||||
|
|
||||||
|
self.search = (search_query, optional_column) => {
|
||||||
|
const new_search_query =
|
||||||
|
self.options.callSearchManually &&
|
||||||
|
typeof search_query !== "undefined"
|
||||||
|
? search_query
|
||||||
|
: self.search_tag
|
||||||
|
? self.search_tag.value
|
||||||
|
: "";
|
||||||
|
|
||||||
|
if (last_search_query === (last_search_query = new_search_query)) return;
|
||||||
|
(0, self._applyCSS(last_search_query, optional_column));
|
||||||
|
self.options.didSearch && self.options.didSearch(last_search_query);
|
||||||
|
};
|
||||||
|
|
||||||
|
self._onSearch = function (event) {
|
||||||
|
if (event.type === "keydown") return setTimeout(self.search, 0);
|
||||||
|
self.search();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.destroy = function () {
|
||||||
|
if (!self.options.callSearchManually) self._processEventListeners("remove");
|
||||||
|
self._destroy();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!self.options.callSearchManually) self._processEventListeners("add");
|
||||||
|
|
||||||
|
self._addStyleTag();
|
||||||
|
self._setJets();
|
||||||
|
self._applyCSS(last_search_query);
|
||||||
|
}
|
||||||
|
|
||||||
|
Jets.prototype = {
|
||||||
|
constructor: Jets,
|
||||||
|
_processEventListeners: function (action) {
|
||||||
|
[
|
||||||
|
"change",
|
||||||
|
"input",
|
||||||
|
"keydown"
|
||||||
|
].forEach(function (event_type) {
|
||||||
|
this.search_tag[action + "EventListener"](event_type, this._onSearch);
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
_applyCSS: function (search_query, optional_column) {
|
||||||
|
const options = this.options;
|
||||||
|
|
||||||
|
const search_phrase = this.replaceDiacritics(
|
||||||
|
search_query
|
||||||
|
.trim()
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/\s\s+/g, " ")
|
||||||
|
).replace(/\\/g, "\\\\");
|
||||||
|
|
||||||
|
const words = options.searchSelectorMode
|
||||||
|
? search_phrase.split(" ").filter((item, pos, arr) => arr.indexOf(item) === pos)
|
||||||
|
: [search_phrase];
|
||||||
|
|
||||||
|
const is_strict_selector = options.searchSelectorMode === "AND";
|
||||||
|
const selectors = new Array(words.length);
|
||||||
|
|
||||||
|
for (let i = 0, ii = words.length; i < ii; i++) {
|
||||||
|
selectors[i] =
|
||||||
|
(is_strict_selector ? this.content_param + ">" : "") +
|
||||||
|
(options.invert ? "" : ":not(") +
|
||||||
|
"[data-jets" + (typeof optional_column !== "undefined" ? "-col-" + optional_column : "") + options.searchSelector + `="${words[i]}"]` +
|
||||||
|
(options.invert ? "" : ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
const hide_rules =
|
||||||
|
options.hideBy
|
||||||
|
.split(";")
|
||||||
|
.filter(Boolean)
|
||||||
|
.map(rule => rule + (options.addImportant ? "!important" : ""));
|
||||||
|
|
||||||
|
const css_rule = (is_strict_selector ? "" : this.content_param + ">") + selectors.join(is_strict_selector ? "," : "") + "{" + hide_rules.join(";") + "}";
|
||||||
|
|
||||||
|
this.styleTag.innerHTML = search_phrase.length ? css_rule : "";
|
||||||
|
},
|
||||||
|
|
||||||
|
_addStyleTag: function () {
|
||||||
|
this.styleTag = document.createElement("style");
|
||||||
|
document.head.appendChild(this.styleTag);
|
||||||
|
},
|
||||||
|
|
||||||
|
_getText: function (tag) {
|
||||||
|
return tag && (tag.textContent || tag.innerText) || "";
|
||||||
|
},
|
||||||
|
|
||||||
|
_sanitize: function (text) {
|
||||||
|
return this.replaceDiacritics(text).trim().replace(/\s+/g, " ").toLowerCase();
|
||||||
|
},
|
||||||
|
|
||||||
|
_getContentTags: function (query) {
|
||||||
|
return Array.prototype.slice.call(this.content_tag).reduce((all, elem) => {
|
||||||
|
return all.concat(Array.prototype.slice.call(elem.querySelectorAll(query || ":scope > *")));
|
||||||
|
}, []);
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleSpecificColumns: function (tag, set) {
|
||||||
|
const self = this;
|
||||||
|
if (!self.options.searchInSpecificColumn) return;
|
||||||
|
|
||||||
|
Array.prototype.slice.call(tag.children).map((children, i) => {
|
||||||
|
if (
|
||||||
|
self.options.columns &&
|
||||||
|
self.options.columns.length &&
|
||||||
|
self.options.columns.indexOf(i) === -1
|
||||||
|
) return;
|
||||||
|
|
||||||
|
tag[(set || "remove") + "Attribute"]("data-jets-col-" + i, set && self._sanitize(self._getText(children)));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_setJets: function (query, force) {
|
||||||
|
const self = this;
|
||||||
|
const tags = self._getContentTags(force ? "" : query);
|
||||||
|
let text;
|
||||||
|
|
||||||
|
for (const tag of tags) {
|
||||||
|
if (tag.hasAttribute("data-jets") && !force) continue;
|
||||||
|
|
||||||
|
text = this.options.manualContentHandling
|
||||||
|
? this.options.manualContentHandling(tag)
|
||||||
|
: self.options.columns &&
|
||||||
|
self.options.columns.length
|
||||||
|
? self.options.columns.map(column => self._getText(tag.children[column])).join(" ")
|
||||||
|
: self._getText(tag);
|
||||||
|
|
||||||
|
tag.setAttribute("data-jets", self._sanitize(text));
|
||||||
|
self._handleSpecificColumns(tag, "set");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
replaceDiacritics: function (text) {
|
||||||
|
const diacritics = this.options.diacriticsMap;
|
||||||
|
|
||||||
|
for (const letter in diacritics) if (diacritics.hasOwnProperty(letter)) {
|
||||||
|
for (let i = 0, ii = diacritics[letter].length; i < ii; i++) {
|
||||||
|
text = text.replace(new RegExp(diacritics[letter][i], "g"), letter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
},
|
||||||
|
|
||||||
|
update: function (force) {
|
||||||
|
this._setJets(":scope > :not([data-jets])", force);
|
||||||
|
},
|
||||||
|
|
||||||
|
_destroy: function () {
|
||||||
|
this.styleTag.parentNode && document.head.removeChild(this.styleTag);
|
||||||
|
const tags = this._getContentTags();
|
||||||
|
|
||||||
|
for (const tag of tags) {
|
||||||
|
tag.removeAttribute("data-jets");
|
||||||
|
this._handleSpecificColumns(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// :scope polyfill
|
||||||
|
// https://stackoverflow.com/a/17989803/1221082
|
||||||
|
;(function (doc, proto) {
|
||||||
|
try {
|
||||||
|
doc.querySelector(":scope body");
|
||||||
|
} catch (err) {
|
||||||
|
["querySelector", "querySelectorAll"].forEach(method => {
|
||||||
|
const nativ = proto[method];
|
||||||
|
|
||||||
|
proto[method] = function (selectors) {
|
||||||
|
if (/(^|,)\s*:scope/.test(selectors)) {
|
||||||
|
const id = this.getAttribute("id");
|
||||||
|
this.id = "ID_" + Date.now();
|
||||||
|
selectors = selectors.replace(/((^|,)\s*):scope/g, "$1#" + this.getAttribute("id"));
|
||||||
|
|
||||||
|
const result = doc[method](selectors);
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nativ.call(this, selectors);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(window.document, Element.prototype);
|
||||||
|
|
||||||
|
return Jets;
|
||||||
|
}));
|
|
@ -28,9 +28,9 @@
|
||||||
|
|
||||||
.api__toc__search__field {
|
.api__toc__search__field {
|
||||||
border-bottom: 1px solid rgba($gray, 0.3);
|
border-bottom: 1px solid rgba($gray, 0.3);
|
||||||
font-size: 1rem;
|
font-size: 0.8rem;
|
||||||
line-height: 2rem;
|
line-height: 2rem;
|
||||||
padding: 0.25rem calc(2rem + 4px) 0.25rem 0.5rem;
|
padding: 0.25rem calc(2rem + 4px) 0.25rem 0.75rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
color: $white;
|
color: $white;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
line-height: 1.3;
|
line-height: 1.15;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transition: opacity 0.2s;
|
transition: opacity 0.2s;
|
||||||
|
@ -59,39 +59,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.api__toc__search__results,
|
|
||||||
.api__toc__items {
|
.api__toc__items {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
line-height: 1.33;
|
line-height: 1.33;
|
||||||
}
|
|
||||||
|
|
||||||
.api__toc__search__results {
|
|
||||||
list-style-type: none;
|
|
||||||
|
|
||||||
&:not(.active) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background-color: rgba($gray, 0.3);
|
|
||||||
border-bottom: 1px solid rgba($gray, 0.3);
|
|
||||||
padding-top: 0.25rem;
|
|
||||||
padding-bottom: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
display: block;
|
|
||||||
padding: 0.25rem 0.5rem 0.25rem 0.75rem;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgba($gray, 0.3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.api__toc__items {
|
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding-top: 0.25rem;
|
padding-top: 0.25rem;
|
||||||
padding-bottom: 0.25rem;
|
padding-bottom: 0.25rem;
|
||||||
|
@ -127,7 +97,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
// border-bottom: 1px solid rgba($gray, 0.3);
|
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
letter-spacing: 0.1rem;
|
letter-spacing: 0.1rem;
|
||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
|
@ -140,10 +109,6 @@
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol, ul {
|
|
||||||
// padding-left: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
table {
|
||||||
border: 1px solid rgba($white, 0.1);
|
border: 1px solid rgba($white, 0.1);
|
||||||
border-radius: 0.3rem;
|
border-radius: 0.3rem;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
const dedent = require("dedent");
|
const dedent = require("dedent");
|
||||||
const fetch = require("make-fetch-happen").defaults({ cacheManager: "./cache" });
|
const fetch = require("make-fetch-happen").defaults({ cacheManager: "./cache" });
|
||||||
|
const fs = require("graceful-fs");
|
||||||
const html = require("choo-async/html");
|
const html = require("choo-async/html");
|
||||||
const raw = require("nanohtml/raw");
|
const raw = require("nanohtml/raw");
|
||||||
|
|
||||||
|
@ -16,6 +17,8 @@ const apiFileLink = process.env.NODE_ENV === "development" ?
|
||||||
"https://cdn.rawgit.com/lbryio/lbry/5b3103e4/docs/api.json"
|
"https://cdn.rawgit.com/lbryio/lbry/5b3103e4/docs/api.json"
|
||||||
;
|
;
|
||||||
|
|
||||||
|
const apiScripts = "<script>" + fs.readFileSync("./views/partials/api-scripts.js", "utf-8") + "</script>";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// E X P O R T
|
// E X P O R T
|
||||||
|
@ -34,6 +37,8 @@ module.exports = exports = () => async () => parseApiFile().then(response => htm
|
||||||
|
|
||||||
<section class="api__content" id="toc-content">${raw(createApiContent(response).join(""))}</section>
|
<section class="api__content" id="toc-content">${raw(createApiContent(response).join(""))}</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
${raw(apiScripts)}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,9 +51,9 @@ function createApiContent(apiDetails) {
|
||||||
for (const apiDetail of apiDetails) {
|
for (const apiDetail of apiDetails) {
|
||||||
const apiDetailsReturns = JSON.parse(JSON.stringify(apiDetail.returns));
|
const apiDetailsReturns = JSON.parse(JSON.stringify(apiDetail.returns));
|
||||||
|
|
||||||
/* if (apiDetail.name !== "settings_set") */ apiContent.push(`
|
apiContent.push(`
|
||||||
<div class="api__content__body">
|
<div class="api__content__body">
|
||||||
<h2 id="#${apiDetail.name}">${apiDetail.name}</h2>
|
<h2 id="${apiDetail.name}">${apiDetail.name}</h2>
|
||||||
<p>${apiDetail.description}</p>
|
<p>${apiDetail.description}</p>
|
||||||
|
|
||||||
<h3>Returns</h3>
|
<h3>Returns</h3>
|
||||||
|
|
37
views/partials/api-scripts.js
Normal file
37
views/partials/api-scripts.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/* global $, Jets */ "use strict";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let jets = new Jets({
|
||||||
|
searchTag: "#input-search",
|
||||||
|
contentTag: "#toc"
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$("#input-search")[0].value = ""; // reset on page load
|
||||||
|
|
||||||
|
$("#input-search").on("keyup", () => {
|
||||||
|
if ($("#input-search").val()) $(".api__toc__search__clear").addClass("active");
|
||||||
|
else $(".api__toc__search__clear").removeClass("active");
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".api__toc__search__clear").on("click", () => {
|
||||||
|
$("#input-search")[0].value = "";
|
||||||
|
$(".api__toc__search__clear").removeClass("active");
|
||||||
|
jets.destroy();
|
||||||
|
reinitJets();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// H E L P E R
|
||||||
|
|
||||||
|
function reinitJets() {
|
||||||
|
jets = new Jets({
|
||||||
|
searchTag: "#input-search",
|
||||||
|
contentTag: "#toc"
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#input-search").focus();
|
||||||
|
}
|
|
@ -55,6 +55,7 @@ module.exports = exports = () => async (state) => {
|
||||||
html`<link rel="stylesheet" href="/assets/css/style.css"/>`,
|
html`<link rel="stylesheet" href="/assets/css/style.css"/>`,
|
||||||
|
|
||||||
html`<script src="/assets/scripts/vendor/zepto.js"></script>`,
|
html`<script src="/assets/scripts/vendor/zepto.js"></script>`,
|
||||||
|
pageTitle === "API" ? html`<script src="/assets/scripts/plugins/jets.js"></script>` : "",
|
||||||
html`<script>const ws = new WebSocket(location.origin.replace(/^http/, "ws"));</script>`,
|
html`<script>const ws = new WebSocket(location.origin.replace(/^http/, "ws"));</script>`,
|
||||||
html`<script src="/assets/scripts/sockets.js"></script>`
|
html`<script src="/assets/scripts/sockets.js"></script>`
|
||||||
]}`;
|
]}`;
|
||||||
|
|
Loading…
Reference in a new issue