Skip to content

Commit

Permalink
Merge pull request #5 from chunkybanana/main
Browse files Browse the repository at this point in the history
_now_ it should actually work
  • Loading branch information
mi2ebi authored Dec 19, 2024
2 parents 230f18d + 4cf095c commit 25e4946
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 147 deletions.
72 changes: 37 additions & 35 deletions events.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var worker = {"postMessage": function(a) {}};
var page, q = "", res = [];
window.addEventListener("scroll", function(e) {
var worker = { postMessage() { } };
var page, res = [];
window.addEventListener("scroll", function (e) {
if (window.innerHeight + window.scrollY >= document.body.scrollHeight - 100) {
page++;
load(res, page);
Expand All @@ -13,45 +13,47 @@ function checkLength() {
}
}
function clearRes() {
res = null;
[`res`, `len`, `bottom`].forEach(x => $(x).innerHTML = "");
}
function redirect() {
var v = "?";
if (q) v += "&q=" + encodeURIComponent(q);
v = v.replace(/\?&/g, "?").replace(/[?&]+$/, "");
window.history.pushState(null, null, window.location.href.split("?")[0] + v);

function navigate(q, push_state = true, is_search = false) {
clearRes();
if (!is_search) $`search`.value = q;

if (q == '') {
page = 0;
return
}

let newLink = window.location.href.split("?")[0] + (q ? "?q=" + encodeURIComponent(q) : '')
if (push_state) {
window.history.pushState('', '', newLink)
} else {
window.history.replaceState('', '', newLink)
}

$`bottom`.innerHTML = "chum lao jí pó jóaıse"
worker.postMessage({ q })
}
var timer;
$`search`.addEventListener("input", function() {

let timer;
$`search`.addEventListener("input", function () {
clearTimeout(timer);
q = $`search`.value.trim();
res = null;
clearRes();
redirect();
$`bottom`.innerHTML = "chum lao jí pó jóaıse"
timer = setTimeout(function() {
if (q.length) {
worker.postMessage({"q": q})
} else {
res = null;
clearRes();
page = 0;
}
}, 100);
timer = setTimeout(() => {
navigate(this.value.trim(), false, true);
}, 100)
});
$`clear`.addEventListener("click", function() {
$`search`.value = "";
$`clear`.addEventListener("click", function () {
$`search`.focus();
dispatchSearch();
navigate("", false);
});
$`english`.addEventListener("click", function() {
$`search`.value =
$`search`.value.split(" ")
.filter(t => !/^([!-]|not:)*(\$|scope:)/.test(t))
.concat(["$en"]).join(" ").trim();
$`english`.addEventListener("click", function () {
let newQuery =
$`search`.value.split(" ")
.filter(t => !/^([!-]|not:)*(\$|scope:)/.test(t))
.concat(["$en"]).join(" ").trim();
$`search`.focus();
dispatchSearch();
navigate(newQuery, false);
});
function dispatchSearch() {
$`search`.dispatchEvent(new Event("input", {"bubbles": true}));
}
79 changes: 39 additions & 40 deletions helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,74 +10,73 @@ function mkel(tag, props, children) {
}
return element;
}

function htmlify(json) {
const entry =
mkel("div", {"className": "entry"}, [
return mkel("div", { "className": "entry" }, [
mkel("dt", {}, [
json.warn ? mkel("span", {}, "⚠\ufe0f ") : null,
mkel("a", {
"className": "toa",
"href": "?q=" + encodeURIComponent(json.head)
onclick() { navigate(json.head) }
}, [json.head]),
" • ",
mkel("a", {
"className": "scope",
"href": "?q=" + encodeURIComponent("scope:" + json.scope)
onclick() { navigate("scope:" + json.scope) }
}, [json.scope]),
" ",
mkel("a", {"href": "?q=" + encodeURIComponent("@" + json.user)}, [json.user]),
mkel("a", { onclick() { navigate("@" + json.user) } }, [json.user]),
" ",
mkel("span", {"className": "score"}, [
mkel("span", { "className": "score" }, [
("" + json.score).replace(/^0$/, "±").replace(/^(\d)/, "+$1")
]),
" • ",
mkel("a", {"href": "?q=" + encodeURIComponent("#" + json.id)}, [json.date.slice(0, 10)]),
mkel("a", { onclick() { navigate("#" + json.id) } }, [json.date.slice(0, 10)]),
" ",
mkel("a", {"href": "https://toadua.uakci.space/#" + encodeURIComponent("#" + json.id)}, ["↗"]),
mkel("a", { "href": "https://toadua.uakci.space/#" + encodeURIComponent("#" + json.id) }, ["↗"]),
]),
mkel("dd", {}, replaceLinks(json.body)),
mkel("div", {"className": "notes indent"}, json.notes.map(note => [
mkel("span", {"className": "score"}, [
mkel("a", {"href": "?q=" + encodeURIComponent("@" + note.user)}, [note.user]),
mkel("div", { "className": "notes indent" }, json.notes.flatMap(note => [
mkel("span", { "className": "score" }, [
mkel("a", { onclick() { navigate("@" + note.user) } }, [note.user]),
": "
]),
mkel("span", {}, replaceLinks(note.content)),
" ",
mkel("span", {"className": "scope"}, [/^\d/.test(note.date) ? note.date.slice(0, 10) : new Date(note.date).toISOString().slice(0, 10)]),
mkel("span", { "className": "scope" }, [/^\d/.test(note.date) ? note.date.slice(0, 10) : new Date(note.date).toISOString().slice(0, 10)]),
mkel("br", {}, [])
]).flat(Infinity))
]))
]);
return entry;
}
/*
- replace **word** with a link to said word
- replace https://example.com with a link to said URL
- replace #ID with a link to said ID
- replace <stuff> with a link to the query stuff [???]
*/
// just me trying to figure out how this works
// i'll probably replace this with a more descriptive one once things work again


function replaceLinks(str) {
// ugh why isn't /u a default regex flag
var bits = str
.replace(/\*\*/g, "📦")
.replace(/https?:\/\/([a-z0-9./#%?=&_:()'-]+)/giu, "🌐$1🌐")
.replace(/(?<!🌐[^ ]*)#([a-z0-9_-]{9,})(?=[^a-z0-9_-]|$)/giu, "🆔$1🆔")
.replace(/<((?![/ ])[^>]+(?<! ))>(?!.+<\/\1>)/giu, "📎$1📎")
.split(/(?=[📦🆔🌐📎])/u);
for (var i = 0; i < bits.length; i++) {
if (i == 0) continue;
if ([...bits[i]][0] === [...bits[i - 1]][0] && "📦🆔🌐📎".includes([...bits[i]][0])) {
bits[i] = bits[i].replace(/^[📦🆔🌐📎]/u, "");
var hrefprefix = bits[i - 1].startsWith("📦") ? "?q=%3D" : bits[i - 1].startsWith("🆔") ? "?q=%23" : bits[i - 1].startsWith("📎") ? "?q=" : "https://";
var textprefix = bits[i - 1].startsWith("📦") || bits[i - 1].startsWith("📎") ? "" : bits[i - 1].startsWith("🆔") ? "#" : "https://";
if (i >= 2 && bits[i - 1].startsWith("🌐") && bits[i - 1].endsWith(")") && bits[i - 2].endsWith("(")) {
bits[i - 1] = bits[i - 1].replace(/\)$/, "");
bits[i] = ")" + bits[i];
}
var href = bits[i - 1].replace(/^[📦🆔🌐📎]/u, "");
if (bits[i - 1].startsWith("📦")) {
href = href.replace(/ /g, "|");
}
bits[i - 1] = mkel("a", {
"href": hrefprefix + (hrefprefix != "https://" ? encodeURIComponent : (x) => x)(href)
}, [bits[i - 1].replace(/^[📦🆔🌐📎]/u, textprefix)])
let parts = str
.replace(/\*\*/g, "📦")
.replace(/https?:\/\/([a-z0-9./#%?=&_:'-]+)/giu, "🌐$1🌐")
.replace(/(?<!🌐[^ ]*)(#[a-z0-9_-]{9,})(?=[^a-z0-9_-]|$)/giu, "🆔$1🆔")
.replace(/<((?![/ ])[^>]+(?<! ))>(?!.+<\/\1>)/giu, "📎$1📎")
.match(/([📦🆔🌐📎]).*?\1|[^📦🆔🌐📎]+/ug);

return parts.map(part => {
part = [...part];
let head = part[0], body = part.slice(1, -1).join("")
if (!"📦🆔🌐📎".includes(head)) return part.join("")
if (head === "🌐") {
return mkel("a", { href: body }, [body]);
}
}
return bits;
let search = head === '📦' ? '=' + body.replace(/ /g, '|') : body;
return mkel("a", { onclick() { navigate(search) } }, [body]);
})
}

function load(res, page) {
Expand All @@ -91,4 +90,4 @@ function load(res, page) {
}
}
$`res`.append(...nodes);
}
}
158 changes: 86 additions & 72 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,82 +1,96 @@
<!DOCTYPE html>
<html>
<head>
<title>mí soakue</title>
<link href="noto.css" rel="stylesheet" />
<link href="iosevka.css" rel="stylesheet" />
<link href="style.css" rel="stylesheet" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="nuifuaq.png" type="image/png" />
</head>
<body>
<h1>mí soakue / 󱛘󱚰󱛊󱚹󱛛󱛓󱚺󱛃󱛍󱚺󱛄󱚲󱛍󱚴󱛓󱛙</h1>
<p><a href="https://github.com/berrymot/soakue">github</a></p>
<input type="text" id="search" name="search" autocomplete="off" spellcheck="false" size="1" placeholder="chum lao jí pó tóakue" disabled />
<span id="btns">
<button type="reset" id="clear">sıajòaı</button>
<button type="button" id="english">toìqlızuno</button>
</span>
<span id="len"></span>
<div id="res"></div>
<div id="bottom"></div>
<div id="howto">
<h2>about</h2>
<p>this updates every day. it used to update every 6 hours, but github actions scheduling is not very precise.</p>
<p>the fonts here are mostly in Noto, except the font for Tangut (which is by BabelStone) and the Deranı one (Iosevka modified by Laqme+Kıa).</p>
<p>kuaq kıe jí mí Sofıa lä soa muoja já ka :3</p>
<h2>operators</h2>
<p><code>= head</code> searches just the words themselves. there are a couple fancy things you can do with this:</p>
<div class="indent"><p>

<head>
<title>mí soakue</title>
<link href="noto.css" rel="stylesheet" />
<link href="iosevka.css" rel="stylesheet" />
<link href="style.css" rel="stylesheet" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="nuifuaq.png" type="image/png" />
</head>

<body>
<h1>mí soakue / 󱛘󱚰󱛊󱚹󱛛󱛓󱚺󱛃󱛍󱚺󱛄󱚲󱛍󱚴󱛓󱛙</h1>
<p><a href="https://github.com/berrymot/soakue">github</a></p>
<input type="text" id="search" name="search" autocomplete="off" spellcheck="false" size="1"
placeholder="chum lao jí pó tóakue" disabled />
<span id="btns">
<button type="reset" id="clear">sıajòaı</button>
<button type="button" id="english">toìqlızuno</button>
</span>
<span id="len"></span>
<div id="res"></div>
<div id="bottom"></div>
<div id="howto">
<h2>about</h2>
<p>this updates every day. it used to update every 6 hours, but github actions scheduling is not very precise.
</p>
<p>the fonts here are mostly in Noto, except the font for Tangut (which is by BabelStone) and the Deranı one
(Iosevka modified by Laqme+Kıa).</p>
<p>kuaq kıe jí mí Sofıa lä soa muoja já ka :3</p>
<h2>operators</h2>
<p><code>= head</code> searches just the words themselves. there are a couple fancy things you can do with this:
</p>
<div class="indent">
<p>
<code>*</code> matches anything (or nothing, i.e. it's <code>/.*/</code>)<br />
<code>?</code> matches any single letter, <code>/[aeıoumpbfntdczsrljꝡqkg'h]|[ncs]h/i</code><br />
<code>CVFQ</code> match their <a href="https://toaq.net/refgram/phonology">refgram</a> definitions (note that <code>VV</code>&nbsp;⊋&nbsp;<code>F</code>)<br />
<code>CVFQ</code> match their <a href="https://toaq.net/refgram/phonology">refgram</a> definitions (note
that <code>VV</code>&nbsp;⊋&nbsp;<code>F</code>)<br />
<code>R</code> matches a raku</code><br />
<code>_</code> matches a space<br />
<code>()[]|</code> work like in <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions#writing_a_regular_expression_pattern">regex</a>
</p></div>
<div class="indent"><p>
<code>()[]|</code> work like in <a
href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions#writing_a_regular_expression_pattern">regex</a>
</p>
</div>
<div class="indent">
<p>
<code>i</code><code>ı</code>, <code>vw</code><code></code>, <code>x</code><code>'</code><br />
<code>.</code><code>◌̣</code><br />
<code>1234</code><code>◌̀◌́◌̈◌̂</code>
</p></div>
<p><code>~</code> is similar but will also match word-internally: <code>~◌</code> = <code>=*◌*</code></p>
<p><code>@ user</code> searches word authors</p>
<p><code># id</code> finds the word with id <i>x</i></p>
<p><code>/ arity</code> finds definitions with <i>x</i> slots</p>
<p><code>$ scope</code> shows words defined under a particular language code</p>
<p><code>! - not</code> negate a query, e.g. <code>-@official</code></p>
<p><code>^ score</code> finds definitions with at least +<i>x</i> votes. you can do <code>!^</code> for less than <i>x</i>, and <code>^=</code> for exactly <i>x</i>.</p>
<h2>things you can't do here</h2>
<p>anything that requires logging in</p>
</p>
</div>
<script src="data/toakue.js"></script>
<script src="helper.js"></script>
<script src="events.js"></script>
<script>
$`search`.removeAttribute("disabled");
$`search`.setAttribute("placeholder", "joaıteoq");
worker = new Worker("worker.js");
worker.addEventListener("message", function(e) {
res = e.data;
if (res.err) {
$`res`.innerHTML = res.err;
$`bottom`.innerHTML = "";
return;
}
$`res`.innerHTML = "";
$`len`.innerHTML = "joaıse\u{00a0}<b>" + res.length + "</b>\u{00a0}raı";
page = 0;
load(res, page);
checkLength();
});
window.addEventListener("DOMContentLoaded", function(e) {
var par = new URLSearchParams(window.location.search);
var par_q = par.get("q");
$`search`.value = par_q;
dispatchSearch();
$`search`.focus();
});
</script>
</body>
</html>
<p><code>~</code> is similar but will also match word-internally: <code>~◌</code> = <code>=*◌*</code></p>
<p><code>@ user</code> searches word authors</p>
<p><code># id</code> finds the word with id <i>x</i></p>
<p><code>/ arity</code> finds definitions with <i>x</i> slots</p>
<p><code>$ scope</code> shows words defined under a particular language code</p>
<p><code>! - not</code> negate a query, e.g. <code>-@official</code></p>
<p><code>^ score</code> finds definitions with at least +<i>x</i> votes. you can do <code>!^</code> for less
than <i>x</i>, and <code>^=</code> for exactly <i>x</i>.</p>
<h2>things you can't do here</h2>
<p>anything that requires logging in</p>
</div>
<script src="data/toakue.js"></script>
<script src="helper.js"></script>
<script src="events.js"></script>
<script>
$`search`.removeAttribute("disabled");
$`search`.setAttribute("placeholder", "joaıteoq");
worker = new Worker("worker.js");
worker.addEventListener("message", function (e) {
res = e.data;
if (res.err) {
$`res`.innerHTML = res.err;
$`bottom`.innerHTML = "";
return;
}
$`res`.innerHTML = "";
$`len`.innerHTML = "joaıse\u{00a0}<b>" + res.length + "</b>\u{00a0}raı";
page = 0;
load(res, page);
checkLength();
});
function updateFromQuery() {
var par = new URLSearchParams(window.location.search);
navigate(par.get("q"), false);
$`search`.focus();
}
window.addEventListener("DOMContentLoaded", updateFromQuery);
window.addEventListener("popstate", updateFromQuery);
</script>
</body>

</html>

0 comments on commit 25e4946

Please sign in to comment.