reworked file structure; changed search results to be faster
This commit is contained in:
parent
a0fa864475
commit
a65037f8ea
15 changed files with 880 additions and 853 deletions
|
@ -1,3 +1,80 @@
|
|||
var md5 = (function() {
|
||||
var MD5 = function (d) {
|
||||
return M(V(Y(X(d), 8 * d.length)))
|
||||
}
|
||||
function M (d) {
|
||||
for (var _, m = '0123456789abcdef', f = '', r = 0; r < d.length; r++) {
|
||||
_ = d.charCodeAt(r)
|
||||
f += m.charAt(_ >>> 4 & 15) + m.charAt(15 & _)
|
||||
}
|
||||
return f
|
||||
}
|
||||
function X (d) {
|
||||
for (var _ = Array(d.length >> 2), m = 0; m < _.length; m++) {
|
||||
_[m] = 0
|
||||
}
|
||||
for (m = 0; m < 8 * d.length; m += 8) {
|
||||
_[m >> 5] |= (255 & d.charCodeAt(m / 8)) << m % 32
|
||||
}
|
||||
return _
|
||||
}
|
||||
function V (d) {
|
||||
for (var _ = '', m = 0; m < 32 * d.length; m += 8) _ += String.fromCharCode(d[m >> 5] >>> m % 32 & 255)
|
||||
return _
|
||||
}
|
||||
function Y (d, _) {
|
||||
d[_ >> 5] |= 128 << _ % 32
|
||||
d[14 + (_ + 64 >>> 9 << 4)] = _
|
||||
for (var m = 1732584193, f = -271733879, r = -1732584194, i = 271733878, n = 0; n < d.length; n += 16) {
|
||||
var h = m
|
||||
var t = f
|
||||
var g = r
|
||||
var e = i
|
||||
f = md5ii(f = md5ii(f = md5ii(f = md5ii(f = md5hh(f = md5hh(f = md5hh(f = md5hh(f = md5gg(f = md5gg(f = md5gg(f = md5gg(f = md5ff(f = md5ff(f = md5ff(f = md5ff(f, r = md5ff(r, i = md5ff(i, m = md5ff(m, f, r, i, d[n + 0], 7, -680876936), f, r, d[n + 1], 12, -389564586), m, f, d[n + 2], 17, 606105819), i, m, d[n + 3], 22, -1044525330), r = md5ff(r, i = md5ff(i, m = md5ff(m, f, r, i, d[n + 4], 7, -176418897), f, r, d[n + 5], 12, 1200080426), m, f, d[n + 6], 17, -1473231341), i, m, d[n + 7], 22, -45705983), r = md5ff(r, i = md5ff(i, m = md5ff(m, f, r, i, d[n + 8], 7, 1770035416), f, r, d[n + 9], 12, -1958414417), m, f, d[n + 10], 17, -42063), i, m, d[n + 11], 22, -1990404162), r = md5ff(r, i = md5ff(i, m = md5ff(m, f, r, i, d[n + 12], 7, 1804603682), f, r, d[n + 13], 12, -40341101), m, f, d[n + 14], 17, -1502002290), i, m, d[n + 15], 22, 1236535329), r = md5gg(r, i = md5gg(i, m = md5gg(m, f, r, i, d[n + 1], 5, -165796510), f, r, d[n + 6], 9, -1069501632), m, f, d[n + 11], 14, 643717713), i, m, d[n + 0], 20, -373897302), r = md5gg(r, i = md5gg(i, m = md5gg(m, f, r, i, d[n + 5], 5, -701558691), f, r, d[n + 10], 9, 38016083), m, f, d[n + 15], 14, -660478335), i, m, d[n + 4], 20, -405537848), r = md5gg(r, i = md5gg(i, m = md5gg(m, f, r, i, d[n + 9], 5, 568446438), f, r, d[n + 14], 9, -1019803690), m, f, d[n + 3], 14, -187363961), i, m, d[n + 8], 20, 1163531501), r = md5gg(r, i = md5gg(i, m = md5gg(m, f, r, i, d[n + 13], 5, -1444681467), f, r, d[n + 2], 9, -51403784), m, f, d[n + 7], 14, 1735328473), i, m, d[n + 12], 20, -1926607734), r = md5hh(r, i = md5hh(i, m = md5hh(m, f, r, i, d[n + 5], 4, -378558), f, r, d[n + 8], 11, -2022574463), m, f, d[n + 11], 16, 1839030562), i, m, d[n + 14], 23, -35309556), r = md5hh(r, i = md5hh(i, m = md5hh(m, f, r, i, d[n + 1], 4, -1530992060), f, r, d[n + 4], 11, 1272893353), m, f, d[n + 7], 16, -155497632), i, m, d[n + 10], 23, -1094730640), r = md5hh(r, i = md5hh(i, m = md5hh(m, f, r, i, d[n + 13], 4, 681279174), f, r, d[n + 0], 11, -358537222), m, f, d[n + 3], 16, -722521979), i, m, d[n + 6], 23, 76029189), r = md5hh(r, i = md5hh(i, m = md5hh(m, f, r, i, d[n + 9], 4, -640364487), f, r, d[n + 12], 11, -421815835), m, f, d[n + 15], 16, 530742520), i, m, d[n + 2], 23, -995338651), r = md5ii(r, i = md5ii(i, m = md5ii(m, f, r, i, d[n + 0], 6, -198630844), f, r, d[n + 7], 10, 1126891415), m, f, d[n + 14], 15, -1416354905), i, m, d[n + 5], 21, -57434055), r = md5ii(r, i = md5ii(i, m = md5ii(m, f, r, i, d[n + 12], 6, 1700485571), f, r, d[n + 3], 10, -1894986606), m, f, d[n + 10], 15, -1051523), i, m, d[n + 1], 21, -2054922799), r = md5ii(r, i = md5ii(i, m = md5ii(m, f, r, i, d[n + 8], 6, 1873313359), f, r, d[n + 15], 10, -30611744), m, f, d[n + 6], 15, -1560198380), i, m, d[n + 13], 21, 1309151649), r = md5ii(r, i = md5ii(i, m = md5ii(m, f, r, i, d[n + 4], 6, -145523070), f, r, d[n + 11], 10, -1120210379), m, f, d[n + 2], 15, 718787259), i, m, d[n + 9], 21, -343485551)
|
||||
m = safeadd(m, h)
|
||||
f = safeadd(f, t)
|
||||
r = safeadd(r, g)
|
||||
i = safeadd(i, e)
|
||||
}
|
||||
return [m, f, r, i]
|
||||
}
|
||||
function md5cmn (d, _, m, f, r, i) {
|
||||
return safeadd(bitrol(safeadd(safeadd(_, d), safeadd(f, i)), r), m)
|
||||
}
|
||||
function md5ff (d, _, m, f, r, i, n) {
|
||||
return md5cmn(_ & m | ~_ & f, d, _, r, i, n)
|
||||
}
|
||||
function md5gg (d, _, m, f, r, i, n) {
|
||||
return md5cmn(_ & f | m & ~f, d, _, r, i, n)
|
||||
}
|
||||
function md5hh (d, _, m, f, r, i, n) {
|
||||
return md5cmn(_ ^ m ^ f, d, _, r, i, n)
|
||||
}
|
||||
function md5ii (d, _, m, f, r, i, n) {
|
||||
return md5cmn(m ^ (_ | ~f), d, _, r, i, n)
|
||||
}
|
||||
function safeadd (d, _) {
|
||||
var m = (65535 & d) + (65535 & _)
|
||||
return (d >> 16) + (_ >> 16) + (m >> 16) << 16 | 65535 & m
|
||||
}
|
||||
function bitrol (d, _) {
|
||||
return d << _ | d >>> 32 - _
|
||||
}
|
||||
function MD5Unicode(buffer){
|
||||
if (!(buffer instanceof Uint8Array)) {
|
||||
buffer = new TextEncoder().encode(typeof buffer==='string' ? buffer : JSON.stringify(buffer));
|
||||
}
|
||||
var binary = [];
|
||||
var bytes = new Uint8Array(buffer);
|
||||
for (var i = 0, il = bytes.byteLength; i < il; i++) {
|
||||
binary.push(String.fromCharCode(bytes[i]));
|
||||
}
|
||||
return MD5(binary.join(''));
|
||||
}
|
||||
|
||||
return MD5Unicode;
|
||||
})();
|
||||
|
||||
$( document ).ready(function() {
|
||||
// GLOBALS;
|
||||
|
||||
|
@ -9,4 +86,48 @@ $( document ).ready(function() {
|
|||
$('#abv-search').on("submit", function () {
|
||||
$('#abv-search-icon').replaceWith('<div class="loader"></div>');
|
||||
});
|
||||
|
||||
// SEARCH RESULTS MODAL
|
||||
$('#abv-btn-searchResults').on("click", function () {
|
||||
$('#modal_searchResults')[0].showModal();
|
||||
});
|
||||
|
||||
// Close search modal
|
||||
$('.abv-close-search').on("click", function () {
|
||||
$('#modal_searchResults')[0].close();
|
||||
});
|
||||
|
||||
$('#modal_searchResults').on("toggle", async function () {
|
||||
// let html = "";
|
||||
async function getResults() {
|
||||
let url = "./api/search/current";
|
||||
const response = await fetch(url);
|
||||
const result = await response.json();
|
||||
return result;
|
||||
}
|
||||
async function getEntryForm(id) {
|
||||
let url = `./api/entries/${md5(id).toUpperCase()}`;
|
||||
const response = await fetch(url);
|
||||
const result = await response.json();
|
||||
return result.form;
|
||||
}
|
||||
searchResults = await getResults();
|
||||
for (result of searchResults) {
|
||||
let pos = searchResults.indexOf(result);
|
||||
// let form = await getEntryForm(result.entry);
|
||||
let html = `
|
||||
<tr>
|
||||
<td>${pos+1}</td>
|
||||
<td>
|
||||
<a href="./search/position?p=${pos+1}">${result.entryForm}</a>
|
||||
</td>
|
||||
<td>
|
||||
${result.fragment}
|
||||
</td>
|
||||
</tr>
|
||||
`
|
||||
$(this).find('tbody').append($(html));
|
||||
}
|
||||
// $(this).find('tbody').append($(html));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -216,7 +216,7 @@ a.abv-map img {
|
|||
height: 2ex;
|
||||
}
|
||||
|
||||
a.link:hover {
|
||||
a.link:hover, a.abv-map:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,16 +20,6 @@ $( document ).ready(function() {
|
|||
//hideNav: '.pagination',
|
||||
});
|
||||
|
||||
// SEARCH RESULTS MODAL
|
||||
$('#abv-btn-searchResults').on("click", function () {
|
||||
$('#modal_searchResults')[0].showModal();
|
||||
});
|
||||
|
||||
// Close search modal
|
||||
$('.abv-close-search').on("click", function () {
|
||||
$('#modal_searchResults')[0].close();
|
||||
});
|
||||
|
||||
// MAP MODAL
|
||||
// This event binding is done on page load and also whenever new entries are loaded.
|
||||
bindMapOpen = function () {
|
||||
|
|
|
@ -324,11 +324,12 @@ declare function abv-m:search($db-lang as xs:string,
|
|||
}
|
||||
let $hits := $docs//tei:entry[1][$test(.)]
|
||||
return array:build(for $hit in $hits
|
||||
let $entry-id := $hit/@xml:id
|
||||
let $entry-id as xs:string := $hit/@xml:id
|
||||
(: group by $entry-id :)
|
||||
let $mark := ft:mark($hit[$test(.)])
|
||||
order by abv-m:sortKey($hit/@xml:id)
|
||||
return {'entry': $entry-id,
|
||||
'entryForm': abv-m:entry-form-by-id($entry-id),
|
||||
(: 'nodes': array:build(for $node in $hit return path($node)), :)
|
||||
'tei': ft:mark($hit[$test(.)]),
|
||||
'fragment': <span>{util:strip-namespaces(($mark//*[tei:mark])[1])/child::node()}</span>
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
module namespace page = 'http://ossetic-studies.org/ns/abaevdict-site';
|
||||
|
||||
declare namespace tei = "http://www.tei-c.org/ns/1.0";
|
||||
|
||||
import module namespace abv-m = 'http://ossetic-studies.org/ns/abaevdict-mod' at './abv-mod.xqm';
|
||||
|
||||
declare variable $page:items as xs:integer := 20;
|
||||
|
||||
declare %rest:path("{$lang}/dict/page{$p}")
|
||||
(: %rest:GET :)
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:dict($lang, $p) {
|
||||
let $pagetotal := ceiling(count(collection('abaevdict_en')) div $page:items)
|
||||
let $sorted := abv-m:sort-collection(collection(`abaevdict_{$lang}`))
|
||||
return
|
||||
<html>
|
||||
<head>
|
||||
<script src="/static/jquery-3.7.1.min.js">
|
||||
</script>
|
||||
<script src="/static/infinite-scroll.pkgd.min.js">
|
||||
</script>
|
||||
<script src="/static/plotly-3.0.1.min.js" charset="utf-8"></script>
|
||||
|
||||
<script src="/static/abaev.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"/>
|
||||
<link rel="stylesheet" href="{web:create-url('/static/abaev-html.css')}"/>
|
||||
<title>Abaev</title>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><strong>Abaevdict</strong></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="#">Home</a></li>
|
||||
<li><a href="#">Dictionary</a></li>
|
||||
<li><a href="#">Index</a></li>
|
||||
<li><a href="#">References</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<button id="open-leftbar">
|
||||
{html:doc('../static/chevron-right.svg')}
|
||||
</button>
|
||||
<button id="close-leftbar">
|
||||
{html:doc('../static/chevron-left.svg')}
|
||||
</button>
|
||||
<aside id="leftbar">
|
||||
<input type="text" id="filter-entries" placeholder="Quick filter…"/>
|
||||
<nav id="entrylist">
|
||||
<ul>
|
||||
{for $doc in $sorted
|
||||
return <li id="link_{$doc/tei:entry[1]/@xml:id}">
|
||||
<a href="by-id/{$doc/tei:entry[1]/@xml:id}">
|
||||
{$doc/tei:entry[1]/tei:form[1]/tei:orth[1]/text()}
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
<main>
|
||||
{for $doc at $i in $sorted
|
||||
where $i > ($p - 1) * $page:items and $i <= $p * $page:items
|
||||
let $html := xslt:transform($doc,
|
||||
doc('../xsl/abaev2html.xsl'), {'lang': $lang})
|
||||
return $html}
|
||||
</main>
|
||||
<footer>
|
||||
<nav class="pagination">
|
||||
<ul>
|
||||
<li>
|
||||
{if ($p > 1) then <a href="page{$p - 1}">Previous page</a> else ()}
|
||||
</li>
|
||||
</ul>
|
||||
<!-- <ul><li>Page {$p} of {$pagetotal}</li></ul> -->
|
||||
<ul>
|
||||
<li>
|
||||
{if ($p < $pagetotal) then
|
||||
<a class="pagination__next" href="page{$p + 1}">Next page</a> else ()}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</footer>
|
||||
|
||||
<dialog id="modal_map">
|
||||
<article>
|
||||
<header><button class="abv-close-map" aria-label="Close" rel="prev"></button>
|
||||
<p>Map</p>
|
||||
</header>
|
||||
<p>
|
||||
<div id="map_display" style="width:100%;height:80%;"></div>
|
||||
</p>
|
||||
<footer><button class="abv-close-map">Close</button></footer>
|
||||
</article>
|
||||
</dialog>
|
||||
</body>
|
||||
</html>
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/dict/by-id/{$id}")
|
||||
(: %rest:GET :)
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:by-id($lang, $id) {
|
||||
|
||||
let $seq := abv-m:sort-collection(collection(`abaevdict_{$lang}`))
|
||||
let $doc-index := index-of($seq, $seq[tei:entry[@xml:id=`{$id}`]])
|
||||
let $pagenum := ceiling($doc-index div $page:items)
|
||||
return web:redirect(`../page{$pagenum}`, {}, web:decode-url($id))
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/dict/map-info/{$entry}")
|
||||
%rest:produces("application/json")
|
||||
%rest:GET function page:map-info($lang, $entry) {
|
||||
let $ments := abv-m:make-geomap(doc(`abaevdict_{$lang}/{$entry}.xml`),
|
||||
$lang)
|
||||
return json:serialize($ments, {'format': 'xquery'})
|
||||
};
|
|
@ -1,718 +0,0 @@
|
|||
module namespace page = 'http://ossetic-studies.org/ns/abaevdict-site';
|
||||
|
||||
declare namespace tei = "http://www.tei-c.org/ns/1.0";
|
||||
|
||||
import module namespace abv-m = 'http://ossetic-studies.org/ns/abaevdict-mod' at './abv-mod.xqm';
|
||||
|
||||
|
||||
(: =========================================================== :)
|
||||
(: ================== GLOBAL VARIABLES ======================= :)
|
||||
(: =========================================================== :)
|
||||
|
||||
(: Number of items per page :)
|
||||
declare variable $page:items as xs:integer := 20;
|
||||
|
||||
(: These variables are declared in module scope because they are needed in
|
||||
different places, but they are still dynamically evaluated :)
|
||||
declare variable $page:lookup := doc('abaevdict_index/lookup.xml')/tei:table/tei:entry;
|
||||
declare variable $page:lookup-all := doc('abaevdict_index/lookup.xml')/tei:table/*;
|
||||
|
||||
declare variable $page:total := ceiling(count($page:lookup) div $page:items);
|
||||
(: This is still called sorted, because I haven't changed the code.
|
||||
But it's now equal to lookup, because the lookup itself is now sorted. :)
|
||||
declare variable $page:sorted := $page:lookup;
|
||||
|
||||
(: =============================================================== :)
|
||||
(: ======================= COMMON STUFF ========================== :)
|
||||
(: =============================================================== :)
|
||||
|
||||
declare function page:head($title as xs:string, $script as node()* := ()) {
|
||||
<head>
|
||||
<script src="/static/jquery-3.7.1.min.js">
|
||||
</script>
|
||||
<script src="/static/abaev-global.js">
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"/>
|
||||
|
||||
<link rel="stylesheet" href="{web:create-url('/static/abaev-html.css')}"/>
|
||||
|
||||
{$script}
|
||||
|
||||
<title>{$title}</title>
|
||||
</head>
|
||||
};
|
||||
|
||||
(: Navigation header :)
|
||||
declare function page:header($lang as xs:string, $href-other as xs:string) {
|
||||
<header>
|
||||
<nav>
|
||||
<ul class="abv-brand">
|
||||
<li><img class="abv-logo" src="/static/Abaev_logo.png" alt="Abaevdict logo"></img>
|
||||
<strong>{
|
||||
switch($lang)
|
||||
case 'ru' return 'ИЭСОЯ'
|
||||
default return `Abaevdict`
|
||||
}</strong><i> β</i></li>
|
||||
<li>{
|
||||
(element {if ($lang = 'ru') then 'mark' else 'a'}{
|
||||
if ($lang != 'ru') then
|
||||
(attribute class {'link'},
|
||||
attribute data-href {`{$href-other}`}) else (),
|
||||
'ru'
|
||||
}, ' / ',
|
||||
element {if ($lang = 'ru') then 'a' else 'mark'}{
|
||||
if ($lang = 'ru') then
|
||||
(attribute class {'link'},
|
||||
attribute data-href {`{$href-other}`}) else (),
|
||||
'en'
|
||||
})
|
||||
}
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<form role="search" action="./search/new" id="abv-search">
|
||||
{if (session:get('searchQuery')) then
|
||||
<button onclick="location.href='./search/clear'" type="button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x-lg" viewBox="0 0 16 16">
|
||||
<path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z"/>
|
||||
</svg>
|
||||
</button>
|
||||
else
|
||||
<select name="searchType" required="1">
|
||||
<option selected="1" value="full">{if ($lang = 'ru')
|
||||
then 'Везде' else 'All'}</option>
|
||||
<option value="form">{if ($lang = 'ru')
|
||||
then 'Формы' else 'Forms'}</option>
|
||||
<option value="sense">{if ($lang = 'ru')
|
||||
then 'Значения' else 'Senses'}</option>
|
||||
<option value="example">{if ($lang = 'ru')
|
||||
then 'Примеры' else 'Examples'}</option>
|
||||
<option value="translation">{if ($lang = 'ru')
|
||||
then 'Переводы' else 'Translations'}</option>
|
||||
<option value="mentioned">{if ($lang = 'ru')
|
||||
then 'Цит. формы' else 'Mentioned'}</option>
|
||||
<option value="gloss">{if ($lang = 'ru')
|
||||
then 'Глоссы' else 'Glosses'}</option>
|
||||
<option value="etym">{if ($lang = 'ru')
|
||||
then 'Этимологии' else 'Etymology'}</option>
|
||||
</select>
|
||||
}
|
||||
<input name="searchQuery"
|
||||
placeholder="{if ($lang = 'ru') then 'Искать' else 'Search'}"
|
||||
value="{session:get('searchQuery')}"
|
||||
aria-label="Search">
|
||||
{if (exists(session:get('searchQuery'))) then
|
||||
attribute disabled {"1"} }
|
||||
</input>
|
||||
{if (not(session:get('searchQuery'))) then
|
||||
<button type="submit">
|
||||
<svg id="abv-search-icon" xmlns="http://www.w3.org/2000/svg"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor" class="bi bi-search">
|
||||
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0"/>
|
||||
</svg>
|
||||
</button>
|
||||
else
|
||||
(
|
||||
if (session:get('searchN') > 1) then
|
||||
<button type="button" class="link" data-href="./search/prev">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8"/>
|
||||
</svg>
|
||||
</button>,
|
||||
<button type="button" id="abv-btn-searchResults">{session:get('searchN')}/{array:size(session:get('searchData'))}</button>
|
||||
,
|
||||
if (session:get('searchN') and session:get('searchN') < array:size(session:get('searchData'))) then
|
||||
<button type="button" class="link" data-href="./search/next">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-right" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M1 8a.5.5 0 0 1 .5-.5h11.793l-3.147-3.146a.5.5 0 0 1 .708-.708l4 4a.5.5 0 0 1 0 .708l-4 4a.5.5 0 0 1-.708-.708L13.293 8.5H1.5A.5.5 0 0 1 1 8"/>
|
||||
</svg>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
</form>
|
||||
</li>
|
||||
<li><a href="./home">{
|
||||
switch($lang)
|
||||
case 'ru' return 'Главная'
|
||||
default return 'Home'
|
||||
}
|
||||
</a></li>
|
||||
<li><a href="./dict">{switch($lang)
|
||||
case 'ru' return 'Словарь'
|
||||
default return 'Dictionary'
|
||||
}
|
||||
</a></li>
|
||||
<li><a href="./index">{switch($lang)
|
||||
case 'ru' return 'Указатель'
|
||||
default return 'Index'
|
||||
}</a></li>
|
||||
<li><a href="#">{switch($lang)
|
||||
case 'ru' return 'Литература'
|
||||
default return 'References'
|
||||
}</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
};
|
||||
|
||||
declare function page:invert-lang($lang as xs:string) as xs:string {
|
||||
if($lang = 'en') then 'ru' else 'en'
|
||||
};
|
||||
|
||||
(: =============================================================== :)
|
||||
(: ============================ FAVICON ========================== :)
|
||||
(: =============================================================== :)
|
||||
|
||||
declare %rest:path("/favicon.ico")
|
||||
%rest:GET
|
||||
function page:favicon() {
|
||||
fetch:binary('../static/favicon.ico')
|
||||
};
|
||||
|
||||
(: =============================================================== :)
|
||||
(: ======================= SEARCH ENTRYPOINT ===================== :)
|
||||
(: =============================================================== :)
|
||||
|
||||
declare function page:entry-for-node($lang as xs:string, $node as node()) {
|
||||
db:get(`abaevdict_{$lang}`,db:path($node))/tei:entry[1]/string(@xml:id)
|
||||
};
|
||||
|
||||
declare %rest:path("/search/{$path=.+}")
|
||||
%rest:GET
|
||||
function page:search-default($path as xs:string) {
|
||||
web:forward(`/en/search/{$path}`)
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/search/new")
|
||||
%rest:query-param("searchType", "{$searchType}", 'full')
|
||||
%rest:query-param("searchQuery", "{$searchQuery}")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:search($lang, $searchType, $searchQuery) {
|
||||
let $sd := abv-m:search($lang,$searchType,$searchQuery)
|
||||
let $r1 := session:set('searchType', $searchType)
|
||||
let $r2 := session:set('searchQuery', $searchQuery)
|
||||
let $r3 := session:set('searchN', 1)
|
||||
let $r4 := session:set('searchData', $sd)
|
||||
return
|
||||
if(array:size($sd) > 0) then
|
||||
page:by-id($lang,
|
||||
$sd(1)('entry'),
|
||||
'')
|
||||
else
|
||||
web:redirect('../search/clear')
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/search/next")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:search-next($lang) {
|
||||
let $n as xs:integer := session:get('searchN')+1
|
||||
let $r1 := session:set('searchN', $n)
|
||||
let $sd := session:get('searchData')
|
||||
return page:by-id($lang, $sd($n)('entry'), ())
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/search/prev")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:search-prev($lang) {
|
||||
let $n as xs:integer := session:get('searchN')-1
|
||||
let $r1 := session:set('searchN', $n)
|
||||
let $sd := session:get('searchData')
|
||||
return page:by-id($lang, $sd($n)('entry'), ())
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/search/position")
|
||||
%rest:query-param("p", "{$p}")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:search-position($lang, $p as xs:integer) {
|
||||
let $r1 := session:set('searchN', $p)
|
||||
let $sd := session:get('searchData')
|
||||
return page:by-id($lang, $sd($p)('entry'), ())
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/search/clear")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:clearSearch($lang) {
|
||||
let $r1 := session:delete('searchType')
|
||||
let $r2 := session:delete('searchQuery')
|
||||
let $r3 := session:delete('searchN')
|
||||
let $r4 := session:delete('searchData')
|
||||
return web:redirect('../dict')
|
||||
};
|
||||
|
||||
(: =============================================================== :)
|
||||
(: ======================= HOMEPAGE ============================== :)
|
||||
(: =============================================================== :)
|
||||
|
||||
declare %rest:path("{$lang}")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:zero($lang) {
|
||||
page:home($lang)
|
||||
};
|
||||
|
||||
declare %rest:path("/")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:zero() {
|
||||
page:zero('en')
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/home")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:home($lang) {
|
||||
<html>
|
||||
{page:head(if ($lang='ru') then 'ИЭСОЯ — Главная' else 'Abaevdict — Home',())}
|
||||
|
||||
<body>
|
||||
{page:header($lang,`../{page:invert-lang($lang)}/home`)}
|
||||
|
||||
<main>
|
||||
{
|
||||
switch($lang)
|
||||
case "ru" return (
|
||||
<p>
|
||||
Вы находитесь на сайте электронной двуязычной версии
|
||||
<a href="https://ironau.ru/iesoja.html">Историко-этимологического
|
||||
словаря осетинского языка</a> (ИЭСОЯ) В. И. Абаева.
|
||||
Оцифровка и перевод словаря выполнены группой сотрудников, студентов и аспирантов
|
||||
<a href="https://tipl.philol.msu.ru/">отделения теоретической и
|
||||
прикладной лингвистики</a> МГУ имени М. В. Ломоносова и
|
||||
<a href="https://iling-ran.ru/web/ru/departments/indo-european/iranian">
|
||||
сектора иранских языков</a> Института языкознания РАН.
|
||||
</p>,
|
||||
<p>
|
||||
Электронная версия словаря и перевод III и IV томов выполнены за счёт
|
||||
гранта Российского научного фонда №
|
||||
<a href="https://rscf.ru/project/22-28-01639/">22-28-01639</a>.
|
||||
</p>,
|
||||
<p>
|
||||
Мы выражаем особую благодарность Амирхану Михайловичу Торчинову, который
|
||||
выступил инициатором этого проекта и продолжает оказывать нам неоценимую
|
||||
поддержку в нашей работе. Мы также благодарны московской осетинской общине за
|
||||
поддержку перевода I–II томов словаря и помощь в печатном издании их английской
|
||||
версии, в особенности Александру Тотоонову, Валерию Дзгоеву, Олегу Пухову,
|
||||
Владиславу Хаблиеву, Руслану Бестолову, Виталию Даурову, Игорю Дзуцеву, Марине
|
||||
Каболовой, Владимиру Туганову, Зоинбеку Абаеву, Виктору Джиоеву, Владимиру
|
||||
Бароеву и Борису Базаеву.
|
||||
</p>,
|
||||
<p>
|
||||
Электронная версия словаря основана на адаптации системы XML-разметки
|
||||
<a href="https://tei-c.org/">TEI P5</a>. Сервер базы данных использует систему
|
||||
<a href="https://basex.org">BaseX</a>. Модель разметки словаря и реализация её
|
||||
программного отображения разработаны О. И. Беляевым. Все исходные
|
||||
данные доступны в <a href="https://code.cucurri.ru/abaevdict">репозиториях</a>
|
||||
проекта.
|
||||
</p>,
|
||||
<p>
|
||||
Дизайн и эмблема сайта выполнены А. А. Осиповой.
|
||||
</p>,
|
||||
<p>
|
||||
В предыдущей версии электронного словаря использовалась реляционная
|
||||
<a href="https://ossetic.iranic.space">модель</a> представления данных,
|
||||
разработанная Ю. Ю. Макаровым (ИЯз РАН, Кембриджский университет)
|
||||
на платформе OnLex.
|
||||
</p>,
|
||||
<h5>Как ссылаться</h5>,
|
||||
<blockquote>Belyaev, Oleg, Irina Khomchenkova, Julia Sinitsyna, Vadim Dyachkov. Digitizing print dictionaries using TEI: The Abaev Dictionary Project // <i>IWCLUL 2021: The Seventh International Workshop on Computational Linguistics of Uralic Languages. Proceedings of the Workshop</i>. Stroudsburg, USA: Association for Computational Linguistics, 2021. P. 12–19.
|
||||
</blockquote>,
|
||||
<h5>Участники проекта</h5>,
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Научный руководитель</th>
|
||||
<td>О. И. Беляев</td>
|
||||
<td>(МГУ имени
|
||||
М. В. Ломоносова, ИЯз РАН)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Основные участники</th>
|
||||
<td>Ю. В. Синицына</td>
|
||||
<td>(МГУ имени
|
||||
М. В. Ломоносова)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>И. А. Хомченкова</td>
|
||||
<td>(МГУ имени М. В. Ломоносова, ИРЯ РАН)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Оцифровка и перевод</th>
|
||||
<td>В. В. Дьячков</td>
|
||||
<td>(ИЯз РАН)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>А. А. Осипова</td>
|
||||
<td>(МГУ имени М. В. Ломоносова)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>А. О. Бадеев</td>
|
||||
<td>(ИЯз РАН, НИУ ВШЭ)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Д. А. Алексеев</td>
|
||||
<td>(МГУ имени М. В. Ломоносова)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>)
|
||||
default return
|
||||
(
|
||||
<p>
|
||||
This is the website of the electronic version of V. I. Abaev's
|
||||
<a href="https://ironau.ru/iesoja.html">Historical-Etymological Dictionary
|
||||
of Ossetic</a> (HEDO). Its digitization and English translation have been
|
||||
carried out by staff members and students of the
|
||||
<a href="https://tipl.philol.msu.ru/">department of theoretical and applied
|
||||
linguistics</a>, Lomonosov Moscow State University, and the <a
|
||||
href="https://iling-ran.ru/web/ru/departments/indo-european/iranian">
|
||||
Department of Iranian languages</a>, Institute of Linguistics RAS.
|
||||
</p>,
|
||||
<p>
|
||||
The electronic version of the dictionary and the translation of vols. 3 and 4
|
||||
have been supported by the Russian Science Foundation, project no.
|
||||
<a href="https://rscf.ru/project/22-28-01639/">22-28-01639</a>.
|
||||
</p>,
|
||||
<p>
|
||||
We are deeply grateful to Amirkhan Torchinov, who has been the initiator of this
|
||||
project and is still providing us with invaluable support in our work. We are
|
||||
also grateful to the Ossetian community of Moscow for their support of the
|
||||
translation of vols. 1 and 2 and the help in publishing its preliminary English
|
||||
version; in particular, to Alexander Totoonov, Valery Dzgoev, Oleg Pukhov,
|
||||
Vladislav Khabliev, Ruslan Bestolov, Vitaly Daurov, Igor Dzutsev, Marina
|
||||
Kabolova, Vladimir Tuganov, Zoinbek Abaev, Viktor Dzhioev, Vladimir
|
||||
Baroev and Boris Bazaev.
|
||||
</p>,
|
||||
<p>
|
||||
The electronic edition of the dictionary is based on an adaptation of the
|
||||
XML-based <a href="https://tei-c.org/">TEI P5</a> markup system. The database
|
||||
server runs on <a href="https://basex.org">BaseX</a>. The markup model and its
|
||||
software realization have been developed by Oleg Belyaev. All sources are
|
||||
available in our <a href="https://code.cucurri.ru/abaevdict">repositories</a>.
|
||||
</p>,
|
||||
<p>
|
||||
Site design and logo are by Anna Osipova.
|
||||
</p>,
|
||||
<p>
|
||||
The previous version of the electronic dictionary used a relational
|
||||
data <a href="https://ossetic.iranic.space">model</a> developed by Yury Makarov
|
||||
(IL RAS, Cambridge University) using the OnLex platform.
|
||||
</p>,
|
||||
<h5>How to cite</h5>,
|
||||
<blockquote>Belyaev, Oleg, Irina Khomchenkova, Julia Sinitsyna, Vadim Dyachkov. Digitizing print dictionaries using TEI: The Abaev Dictionary Project // <i>IWCLUL 2021: The Seventh International Workshop on Computational Linguistics of Uralic Languages. Proceedings of the Workshop</i>. Stroudsburg, USA: Association for Computational Linguistics, 2021. P. 12–19.
|
||||
</blockquote>,
|
||||
<h5>Project participants</h5>,
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Project leader</th>
|
||||
<td>Oleg Belyaev</td>
|
||||
<td>(Lomonosov MSU, IL RAS)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Core team</th>
|
||||
<td>Irina Khomchenkova</td>
|
||||
<td>(Lomonosov MSU, Vinogradov RLI RAS)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Julia Sinitsyna</td>
|
||||
<td>(Lomonosov MSU)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Digitization and translation</th>
|
||||
<td>Vadim Dyachkov</td>
|
||||
<td>(IL RAS, LLACAN CNRS)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Anna Osipova</td>
|
||||
<td>(Lomonosov MSU)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Artyom Badeev</td>
|
||||
<td>(IL RAS, HSE University)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Danil Alekseev</td>
|
||||
<td>(Lomonosov MSU)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>)
|
||||
}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
};
|
||||
|
||||
declare %rest:path("home")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:home() {
|
||||
page:home('en')
|
||||
};
|
||||
|
||||
(: =============================================================== :)
|
||||
(: ======================= THE DICTIONARY ======================== :)
|
||||
(: =============================================================== :)
|
||||
|
||||
(: If no language defined, default to English :)
|
||||
declare %rest:path("dict")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:dict() {
|
||||
web:forward('/en/dict')
|
||||
};
|
||||
|
||||
(: The main dictionary view :)
|
||||
declare %rest:path("{$lang}/dict")
|
||||
%rest:query-param("page","{$p}", 1)
|
||||
%rest:query-param("xpath","{$xpath}", '')
|
||||
%rest:query-param("entry","{$entry}", '')
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:dict($lang, $p, $xpath, $entry) {
|
||||
<html>
|
||||
{page:head('HEDO – Dictionary',
|
||||
(<script src="/static/infinite-scroll.pkgd.min.js">
|
||||
</script>,
|
||||
<script src="/static/plotly-3.0.1.min.js" charset="utf-8"></script>,
|
||||
<script src="/static/abaev.js"></script>))}
|
||||
|
||||
<body>
|
||||
{page:header($lang,`../{page:invert-lang($lang)}/dict`)}
|
||||
|
||||
<!-- Sidebar with entry list -->
|
||||
<button id="open-leftbar">
|
||||
{html:doc('../static/chevron-right.svg')}
|
||||
</button>
|
||||
<button id="close-leftbar">
|
||||
{html:doc('../static/chevron-left.svg')}
|
||||
</button>
|
||||
<aside id="leftbar">
|
||||
<fieldset>
|
||||
<input type="text" id="filter-entries"
|
||||
placeholder="{if ($lang = 'ru') then 'Быстрый фильтр' else 'Quick filter…'}"/>
|
||||
<label>
|
||||
<input id="show-re" type="checkbox" role="switch"></input>
|
||||
{if ($lang = 'ru') then 'Производные' else 'Show subentries'}
|
||||
</label>
|
||||
</fieldset>
|
||||
<nav id="entrylist"></nav> <!-- To be filled dynamically in js -->
|
||||
</aside>
|
||||
|
||||
<!-- The dictionary itself. The entries are displayed as articles retrieved
|
||||
from the database in HTML. On-the-fly generation is only when required -->
|
||||
<main>
|
||||
{for $doc at $i in $page:sorted
|
||||
where $i > ($p - 1) * $page:items and $i <= $p * $page:items
|
||||
let $html := if ($xpath != '' and $entry = $doc/@xml:id)
|
||||
then abv-m:mark-element(
|
||||
doc(`abaevdict_{$lang}/xml/{$doc/@xml:id}.xml`),
|
||||
$xpath) => abv-m:make-html($lang)
|
||||
else
|
||||
let $sd := session:get('searchData')
|
||||
let $sn := session:get('searchN')
|
||||
return if (exists($sd) and $sd($sn)('entry') = $doc/@xml:id)
|
||||
then abv-m:make-html($sd($sn)('tei'), $lang)
|
||||
else doc(`abaevdict_{$lang}/html/{$doc/@xml:id}.html`)
|
||||
return <div class="abv-lex">{(
|
||||
(: Block with icons to the left of entry (floating) :)
|
||||
<div class="icons">
|
||||
{
|
||||
<a href="dict/{$doc/@xml:id}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-link-45deg" viewBox="0 0 16 16">
|
||||
<path d="M4.715 6.542 3.343 7.914a3 3 0 1 0 4.243 4.243l1.828-1.829A3 3 0 0 0 8.586 5.5L8 6.086a1 1 0 0 0-.154.199 2 2 0 0 1 .861 3.337L6.88 11.45a2 2 0 1 1-2.83-2.83l.793-.792a4 4 0 0 1-.128-1.287z"/>
|
||||
<path d="M6.586 4.672A3 3 0 0 0 7.414 9.5l.775-.776a2 2 0 0 1-.896-3.346L9.12 3.55a2 2 0 1 1 2.83 2.83l-.793.792c.112.42.155.855.128 1.287l1.372-1.372a3 3 0 1 0-4.243-4.243z"/>
|
||||
</svg>
|
||||
</a>,
|
||||
if (doc('abaevdict_index/mentioned_en.xml')/lang-index
|
||||
/lang[@id != 'os' and
|
||||
not(starts-with(@id,'os-'))]/word/entry[@id=string($doc/@xml:id)])
|
||||
then <a class="abv-map" data-abv-entry="{$doc/@xml:id}">
|
||||
<img src="/static/map.png"></img>
|
||||
</a>}</div>,
|
||||
$html)}</div>
|
||||
}
|
||||
</main>
|
||||
|
||||
<!-- Footer for page navigation -->
|
||||
<footer>
|
||||
<nav class="pagination">
|
||||
<ul>
|
||||
<li>
|
||||
{if ($p > 1) then <a href="?page={$p - 1}">Previous page</a> else ()}
|
||||
</li>
|
||||
</ul>
|
||||
<!-- <ul><li>Page {$p} of {$page:total}</li></ul> -->
|
||||
<ul class="abv-nextpage">
|
||||
<li>
|
||||
{if ($p < $page:total) then
|
||||
<a class="pagination__next" href="?page={$p + 1}">Next page</a> else ()}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</footer>
|
||||
|
||||
<!-- Modal for map display -->
|
||||
<dialog id="modal_map">
|
||||
<article>
|
||||
<header>
|
||||
<button class="abv-close-map" aria-label="Close" rel="prev">
|
||||
</button>
|
||||
<p>{if ($lang = 'ru') then 'Карта' else 'Map'}</p>
|
||||
</header>
|
||||
<p>
|
||||
<div id="map_display" style="width:100%;height:80%;"></div>
|
||||
</p>
|
||||
<footer><button class="abv-close-map">{if ($lang = 'ru') then 'Закрыть' else 'Close'}</button></footer>
|
||||
</article>
|
||||
</dialog>
|
||||
|
||||
<!-- Modal for search results -->
|
||||
{if (exists(session:get('searchData'))) then
|
||||
<dialog id="modal_searchResults">
|
||||
<article>
|
||||
<header>
|
||||
<button class="abv-close-search" aria-label="Close" rel="prev"/>
|
||||
<p>{if ($lang = 'ru') then 'Результаты поиска'
|
||||
else 'Search results'}</p>
|
||||
</header>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{if ($lang = 'ru') then '№' else 'No.'}</td>
|
||||
<td>{if ($lang = 'ru') then 'Лемма' else 'Lemma'}</td>
|
||||
<td>{if ($lang = 'ru') then 'Фрагмент' else 'Fragment'}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
for $res in session:get('searchData')?*
|
||||
count $pos
|
||||
return <tr>
|
||||
<td>{$pos}</td>
|
||||
<td>
|
||||
<a href="./search/position?p={$pos}">
|
||||
{
|
||||
abv-m:entry-form-by-id($res('entry'))
|
||||
}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{
|
||||
$res('fragment')
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<footer>
|
||||
<button class="abv-close-search">{if ($lang = 'ru') then 'Закрыть' else 'Close'}</button>
|
||||
</footer>
|
||||
</article>
|
||||
</dialog>}
|
||||
</body>
|
||||
</html>
|
||||
};
|
||||
|
||||
(: == ENTRY BY ID == :)
|
||||
(: English as default language :)
|
||||
declare %rest:path("dict/{$id}")
|
||||
%rest:query-param("xpath", "{$xpath}", '')
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:by-id($id, $xpath) {
|
||||
page:by-id('en', $id, $xpath)
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/dict/{$id}")
|
||||
%rest:query-param("xpath", "{$xpath}", '')
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:by-id($lang, $id, $xpath) {
|
||||
(: let $doc-index := index-of($page:sorted, $page:sorted[@xml:id=`{$id}`]) :)
|
||||
let $doc-index := index-where($page:sorted, fn { ./@xml:id=$id })
|
||||
let $pagenum := ceiling($doc-index div $page:items)
|
||||
return web:redirect('../dict',
|
||||
map:merge(({'page': $pagenum,
|
||||
'entry': web:decode-url($id)},
|
||||
if ($xpath != '') then {'xpath': $xpath})),
|
||||
web:decode-url($id))
|
||||
};
|
||||
|
||||
(: =============================================================== :)
|
||||
(: ======================= THE INDEX ============================= :)
|
||||
(: =============================================================== :)
|
||||
|
||||
(: Mentioned index :)
|
||||
declare %rest:path("{$lang}/index")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:index($lang) {
|
||||
let $mlangs := doc(`abaevdict_index/langnames.xml`)/csv[1]/record
|
||||
return
|
||||
<html>
|
||||
{page:head('HEDO – Index', <script src="/static/abaev-index.js"></script>)}
|
||||
<body>
|
||||
{page:header($lang, `../{page:invert-lang($lang)}/index`)}
|
||||
<main>
|
||||
<div class="index">
|
||||
<div class="langs">
|
||||
<label>{if ($lang = 'ru') then 'Языки' else 'Languages'}</label>
|
||||
<select id="abv-select-lang" size="99999">
|
||||
{
|
||||
for $mlang in $mlangs
|
||||
let $mlang-id := $mlang/code/text()
|
||||
let $mlang-name := if ($lang = 'ru') then $mlang/ru/text() else $mlang/en/text()
|
||||
where $mlang-name != ''
|
||||
order by $mlang-name
|
||||
return
|
||||
<option value="{$mlang-id}">
|
||||
{
|
||||
$mlang-name
|
||||
}
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="forms">
|
||||
<Label>{if ($lang = 'ru') then 'Формы' else 'Forms'}</Label>
|
||||
<select id="abv-select-word" size="99999">
|
||||
</select>
|
||||
</div>
|
||||
<div class="entries">
|
||||
<Label>{if ($lang = 'ru') then 'Лексемы' else 'Lexemes'}</Label>
|
||||
<select id="abv-select-entry" size="99999">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="index-submit">
|
||||
<button id="btn-index-submit" hidden="1">{if ($lang = 'ru') then 'К форме' else 'Go to form'}</button>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
};
|
||||
|
||||
(: Default to English :)
|
||||
declare %rest:path("index")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:index() {
|
||||
page:index('en')
|
||||
};
|
96
xq/site/components/dictionary.xq
Normal file
96
xq/site/components/dictionary.xq
Normal file
|
@ -0,0 +1,96 @@
|
|||
module namespace dict = 'http://ossetic-studies.org/ns/abaevdict-site/dictionary';
|
||||
|
||||
import module namespace shared = 'http://ossetic-studies.org/ns/abaevdict-site/shared' at '../shared/shared.xq';
|
||||
import module namespace abv-m = 'http://ossetic-studies.org/ns/abaevdict-mod' at '../../abv-mod.xqm';
|
||||
|
||||
(: Sidebar with entry list. Requires abaev.js to be loaded. :)
|
||||
|
||||
declare function dict:sidebar($lang as xs:string) {
|
||||
(
|
||||
<button id="open-leftbar">
|
||||
{html:doc('../../../static/chevron-right.svg')}
|
||||
</button>,
|
||||
<button id="close-leftbar">
|
||||
{html:doc('../../../static/chevron-left.svg')}
|
||||
</button>,
|
||||
<aside id="leftbar">
|
||||
<fieldset>
|
||||
<input type="text" id="filter-entries"
|
||||
placeholder="{if ($lang = 'ru') then 'Быстрый фильтр' else 'Quick filter…'}"/>
|
||||
<label>
|
||||
<input id="show-re" type="checkbox" role="switch"></input>
|
||||
{if ($lang = 'ru') then 'Производные' else 'Show subentries'}
|
||||
</label>
|
||||
</fieldset>
|
||||
<nav id="entrylist"></nav> <!-- To be filled dynamically in js -->
|
||||
</aside>
|
||||
)
|
||||
};
|
||||
|
||||
declare function dict:main-view($lang as xs:string,
|
||||
$p as xs:integer,
|
||||
$xpath as xs:string,
|
||||
$entry as xs:string) {
|
||||
(dict:sidebar($lang),
|
||||
<main>
|
||||
{for $doc at $i in $shared:sorted
|
||||
where $i > ($p - 1) * $shared:items-per-page and $i <= $p * $shared:items-per-page
|
||||
let $html := if ($xpath != '' and $entry = $doc/@xml:id)
|
||||
then abv-m:mark-element(
|
||||
doc(`abaevdict_{$lang}/xml/{$doc/@xml:id}.xml`),
|
||||
$xpath) => abv-m:make-html($lang)
|
||||
else
|
||||
let $sd := session:get('searchData')
|
||||
let $sn := session:get('searchN')
|
||||
return if (exists($sd) and $sd($sn)('entry') = $doc/@xml:id)
|
||||
then abv-m:make-html($sd($sn)('tei'), $lang)
|
||||
else doc(`abaevdict_{$lang}/html/{$doc/@xml:id}.html`)
|
||||
return <div class="abv-lex">{(
|
||||
(: Block with icons to the left of entry (floating) :)
|
||||
<div class="icons">
|
||||
{
|
||||
<a href="dict/{$doc/@xml:id}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-link-45deg" viewBox="0 0 16 16">
|
||||
<path d="M4.715 6.542 3.343 7.914a3 3 0 1 0 4.243 4.243l1.828-1.829A3 3 0 0 0 8.586 5.5L8 6.086a1 1 0 0 0-.154.199 2 2 0 0 1 .861 3.337L6.88 11.45a2 2 0 1 1-2.83-2.83l.793-.792a4 4 0 0 1-.128-1.287z"/>
|
||||
<path d="M6.586 4.672A3 3 0 0 0 7.414 9.5l.775-.776a2 2 0 0 1-.896-3.346L9.12 3.55a2 2 0 1 1 2.83 2.83l-.793.792c.112.42.155.855.128 1.287l1.372-1.372a3 3 0 1 0-4.243-4.243z"/>
|
||||
</svg>
|
||||
</a>,
|
||||
if (doc('abaevdict_index/mentioned_en.xml')/lang-index
|
||||
/lang[@id != 'os' and
|
||||
not(starts-with(@id,'os-'))]/word/entry[@id=string($doc/@xml:id)])
|
||||
then <a class="abv-map" data-abv-entry="{$doc/@xml:id}">
|
||||
<img src="/static/map.png"></img>
|
||||
</a>}</div>,
|
||||
$html)}</div>
|
||||
}
|
||||
</main>,
|
||||
<footer>
|
||||
<nav class="pagination">
|
||||
<ul>
|
||||
<li>
|
||||
{if ($p > 1) then <a href="?page={$p - 1}">Previous page</a> else ()}
|
||||
</li>
|
||||
</ul>
|
||||
<!-- <ul><li>Page {$p} of {$page:total}</li></ul> -->
|
||||
<ul class="abv-nextpage">
|
||||
<li>
|
||||
{if ($p < $shared:total) then
|
||||
<a class="pagination__next" href="?page={$p + 1}">Next page</a> else ()}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</footer>,
|
||||
<dialog id="modal_map">
|
||||
<article>
|
||||
<header>
|
||||
<button class="abv-close-map" aria-label="Close" rel="prev">
|
||||
</button>
|
||||
<p>{if ($lang = 'ru') then 'Карта' else 'Map'}</p>
|
||||
</header>
|
||||
<p>
|
||||
<div id="map_display" style="width:100%;height:80%;"></div>
|
||||
</p>
|
||||
<footer><button class="abv-close-map">{if ($lang = 'ru') then 'Закрыть' else 'Close'}</button></footer>
|
||||
</article>
|
||||
</dialog>)
|
||||
};
|
178
xq/site/components/home.xq
Normal file
178
xq/site/components/home.xq
Normal file
|
@ -0,0 +1,178 @@
|
|||
module namespace home = 'http://ossetic-studies.org/ns/abaevdict-site/home';
|
||||
|
||||
declare function home:content($lang as xs:string) {
|
||||
switch($lang)
|
||||
case "ru" return (
|
||||
<p>
|
||||
Вы находитесь на сайте электронной двуязычной версии
|
||||
<a href="https://ironau.ru/iesoja.html">Историко-этимологического
|
||||
словаря осетинского языка</a> (ИЭСОЯ) В. И. Абаева.
|
||||
Оцифровка и перевод словаря выполнены группой сотрудников, студентов и аспирантов
|
||||
<a href="https://tipl.philol.msu.ru/">отделения теоретической и
|
||||
прикладной лингвистики</a> МГУ имени М. В. Ломоносова и
|
||||
<a href="https://iling-ran.ru/web/ru/departments/indo-european/iranian">
|
||||
сектора иранских языков</a> Института языкознания РАН.
|
||||
</p>,
|
||||
<p>
|
||||
Электронная версия словаря и перевод III и IV томов выполнены за счёт
|
||||
гранта Российского научного фонда №
|
||||
<a href="https://rscf.ru/project/22-28-01639/">22-28-01639</a>.
|
||||
</p>,
|
||||
<p>
|
||||
Мы выражаем особую благодарность Амирхану Михайловичу Торчинову, который
|
||||
выступил инициатором этого проекта и продолжает оказывать нам неоценимую
|
||||
поддержку в нашей работе. Мы также благодарны московской осетинской общине за
|
||||
поддержку перевода I–II томов словаря и помощь в печатном издании их английской
|
||||
версии, в особенности Александру Тотоонову, Валерию Дзгоеву, Олегу Пухову,
|
||||
Владиславу Хаблиеву, Руслану Бестолову, Виталию Даурову, Игорю Дзуцеву, Марине
|
||||
Каболовой, Владимиру Туганову, Зоинбеку Абаеву, Виктору Джиоеву, Владимиру
|
||||
Бароеву и Борису Базаеву.
|
||||
</p>,
|
||||
<p>
|
||||
Электронная версия словаря основана на адаптации системы XML-разметки
|
||||
<a href="https://tei-c.org/">TEI P5</a>. Сервер базы данных использует систему
|
||||
<a href="https://basex.org">BaseX</a>. Модель разметки словаря и реализация её
|
||||
программного отображения разработаны О. И. Беляевым. Все исходные
|
||||
данные доступны в <a href="https://code.cucurri.ru/abaevdict">репозиториях</a>
|
||||
проекта.
|
||||
</p>,
|
||||
<p>
|
||||
Дизайн и эмблема сайта выполнены А. А. Осиповой.
|
||||
</p>,
|
||||
<p>
|
||||
В предыдущей версии электронного словаря использовалась реляционная
|
||||
<a href="https://ossetic.iranic.space">модель</a> представления данных,
|
||||
разработанная Ю. Ю. Макаровым (ИЯз РАН, Кембриджский университет)
|
||||
на платформе OnLex.
|
||||
</p>,
|
||||
<h5>Как ссылаться</h5>,
|
||||
<blockquote>Belyaev, Oleg, Irina Khomchenkova, Julia Sinitsyna, Vadim Dyachkov. Digitizing print dictionaries using TEI: The Abaev Dictionary Project // <i>IWCLUL 2021: The Seventh International Workshop on Computational Linguistics of Uralic Languages. Proceedings of the Workshop</i>. Stroudsburg, USA: Association for Computational Linguistics, 2021. P. 12–19.
|
||||
</blockquote>,
|
||||
<h5>Участники проекта</h5>,
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Научный руководитель</th>
|
||||
<td>О. И. Беляев</td>
|
||||
<td>(МГУ имени
|
||||
М. В. Ломоносова, ИЯз РАН)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Основные участники</th>
|
||||
<td>Ю. В. Синицына</td>
|
||||
<td>(МГУ имени
|
||||
М. В. Ломоносова)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>И. А. Хомченкова</td>
|
||||
<td>(МГУ имени М. В. Ломоносова, ИРЯ РАН)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Оцифровка и перевод</th>
|
||||
<td>В. В. Дьячков</td>
|
||||
<td>(ИЯз РАН)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>А. А. Осипова</td>
|
||||
<td>(МГУ имени М. В. Ломоносова)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>А. О. Бадеев</td>
|
||||
<td>(ИЯз РАН, НИУ ВШЭ)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Д. А. Алексеев</td>
|
||||
<td>(МГУ имени М. В. Ломоносова)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>)
|
||||
default return
|
||||
(
|
||||
<p>
|
||||
This is the website of the electronic version of V. I. Abaev's
|
||||
<a href="https://ironau.ru/iesoja.html">Historical-Etymological Dictionary
|
||||
of Ossetic</a> (HEDO). Its digitization and English translation have been
|
||||
carried out by staff members and students of the
|
||||
<a href="https://tipl.philol.msu.ru/">department of theoretical and applied
|
||||
linguistics</a>, Lomonosov Moscow State University, and the <a
|
||||
href="https://iling-ran.ru/web/ru/departments/indo-european/iranian">
|
||||
Department of Iranian languages</a>, Institute of Linguistics RAS.
|
||||
</p>,
|
||||
<p>
|
||||
The electronic version of the dictionary and the translation of vols. 3 and 4
|
||||
have been supported by the Russian Science Foundation, project no.
|
||||
<a href="https://rscf.ru/project/22-28-01639/">22-28-01639</a>.
|
||||
</p>,
|
||||
<p>
|
||||
We are deeply grateful to Amirkhan Torchinov, who has been the initiator of this
|
||||
project and is still providing us with invaluable support in our work. We are
|
||||
also grateful to the Ossetian community of Moscow for their support of the
|
||||
translation of vols. 1 and 2 and the help in publishing its preliminary English
|
||||
version; in particular, to Alexander Totoonov, Valery Dzgoev, Oleg Pukhov,
|
||||
Vladislav Khabliev, Ruslan Bestolov, Vitaly Daurov, Igor Dzutsev, Marina
|
||||
Kabolova, Vladimir Tuganov, Zoinbek Abaev, Viktor Dzhioev, Vladimir
|
||||
Baroev and Boris Bazaev.
|
||||
</p>,
|
||||
<p>
|
||||
The electronic edition of the dictionary is based on an adaptation of the
|
||||
XML-based <a href="https://tei-c.org/">TEI P5</a> markup system. The database
|
||||
server runs on <a href="https://basex.org">BaseX</a>. The markup model and its
|
||||
software realization have been developed by Oleg Belyaev. All sources are
|
||||
available in our <a href="https://code.cucurri.ru/abaevdict">repositories</a>.
|
||||
</p>,
|
||||
<p>
|
||||
Site design and logo are by Anna Osipova.
|
||||
</p>,
|
||||
<p>
|
||||
The previous version of the electronic dictionary used a relational
|
||||
data <a href="https://ossetic.iranic.space">model</a> developed by Yury Makarov
|
||||
(IL RAS, Cambridge University) using the OnLex platform.
|
||||
</p>,
|
||||
<h5>How to cite</h5>,
|
||||
<blockquote>Belyaev, Oleg, Irina Khomchenkova, Julia Sinitsyna, Vadim Dyachkov. Digitizing print dictionaries using TEI: The Abaev Dictionary Project // <i>IWCLUL 2021: The Seventh International Workshop on Computational Linguistics of Uralic Languages. Proceedings of the Workshop</i>. Stroudsburg, USA: Association for Computational Linguistics, 2021. P. 12–19.
|
||||
</blockquote>,
|
||||
<h5>Project participants</h5>,
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Project leader</th>
|
||||
<td>Oleg Belyaev</td>
|
||||
<td>(Lomonosov MSU, IL RAS)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Core team</th>
|
||||
<td>Irina Khomchenkova</td>
|
||||
<td>(Lomonosov MSU, Vinogradov RLI RAS)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Julia Sinitsyna</td>
|
||||
<td>(Lomonosov MSU)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Digitization and translation</th>
|
||||
<td>Vadim Dyachkov</td>
|
||||
<td>(IL RAS, LLACAN CNRS)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Anna Osipova</td>
|
||||
<td>(Lomonosov MSU)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Artyom Badeev</td>
|
||||
<td>(IL RAS, HSE University)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Danil Alekseev</td>
|
||||
<td>(Lomonosov MSU)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>)
|
||||
};
|
49
xq/site/components/index.xq
Normal file
49
xq/site/components/index.xq
Normal file
|
@ -0,0 +1,49 @@
|
|||
module namespace index = 'http://ossetic-studies.org/ns/abaevdict-site/index';
|
||||
|
||||
import module namespace shared = 'http://ossetic-studies.org/ns/abaevdict-site/shared' at '../shared/shared.xq';
|
||||
|
||||
declare function index:content($lang as xs:string) {
|
||||
let $mlangs := doc(`abaevdict_index/langnames.xml`)/csv[1]/record
|
||||
return
|
||||
<html>
|
||||
{shared:head('HEDO – Index', <script src="/static/abaev-index.js"></script>)}
|
||||
<body>
|
||||
{shared:header($lang, `../{shared:invert-lang($lang)}/index`)}
|
||||
<main>
|
||||
<div class="index">
|
||||
<div class="langs">
|
||||
<label>{if ($lang = 'ru') then 'Языки' else 'Languages'}</label>
|
||||
<select id="abv-select-lang" size="99999">
|
||||
{
|
||||
for $mlang in $mlangs
|
||||
let $mlang-id := $mlang/code/text()
|
||||
let $mlang-name := if ($lang = 'ru') then $mlang/ru/text() else $mlang/en/text()
|
||||
where $mlang-name != ''
|
||||
order by $mlang-name
|
||||
return
|
||||
<option value="{$mlang-id}">
|
||||
{
|
||||
$mlang-name
|
||||
}
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="forms">
|
||||
<Label>{if ($lang = 'ru') then 'Формы' else 'Forms'}</Label>
|
||||
<select id="abv-select-word" size="99999">
|
||||
</select>
|
||||
</div>
|
||||
<div class="entries">
|
||||
<Label>{if ($lang = 'ru') then 'Лексемы' else 'Lexemes'}</Label>
|
||||
<select id="abv-select-entry" size="99999">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="index-submit">
|
||||
<button id="btn-index-submit" hidden="1">{if ($lang = 'ru') then 'К форме' else 'Go to form'}</button>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
};
|
31
xq/site/components/search.xq
Normal file
31
xq/site/components/search.xq
Normal file
|
@ -0,0 +1,31 @@
|
|||
module namespace search = 'http://ossetic-studies.org/ns/abaevdict-site/search-modal';
|
||||
|
||||
import module namespace abv-m = 'http://ossetic-studies.org/ns/abaevdict-mod' at '../../abv-mod.xqm';
|
||||
|
||||
(: Modal that appears on all pages, with search results :)
|
||||
declare function search:content($lang as xs:string) {
|
||||
if (exists(session:get('searchData'))) then
|
||||
<dialog id="modal_searchResults">
|
||||
<article>
|
||||
<header>
|
||||
<button class="abv-close-search" aria-label="Close" rel="prev"/>
|
||||
<p>{if ($lang = 'ru') then 'Результаты поиска'
|
||||
else 'Search results'}</p>
|
||||
</header>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{if ($lang = 'ru') then '№' else 'No.'}</td>
|
||||
<td>{if ($lang = 'ru') then 'Лемма' else 'Lemma'}</td>
|
||||
<td>{if ($lang = 'ru') then 'Фрагмент' else 'Fragment'}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<footer>
|
||||
<button class="abv-close-search">{if ($lang = 'ru') then 'Закрыть' else 'Close'}</button>
|
||||
</footer>
|
||||
</article>
|
||||
</dialog>
|
||||
};
|
|
@ -2,7 +2,7 @@ declare namespace api = 'http://ossetic-studies.org/ns/abaevdict-api';
|
|||
|
||||
declare namespace tei = "http://www.tei-c.org/ns/1.0";
|
||||
|
||||
import module namespace abv-m = 'http://ossetic-studies.org/ns/abaevdict-mod' at './abv-mod.xqm';
|
||||
import module namespace abv-m = 'http://ossetic-studies.org/ns/abaevdict-mod' at '../abv-mod.xqm';
|
||||
|
||||
(: ======================================================= :)
|
||||
(: ==================== API STUFF ======================== :)
|
||||
|
@ -200,4 +200,11 @@ declare %rest:path("{$db-lang}/api/search")
|
|||
abv-m:search($db-lang,$type,$query)
|
||||
};
|
||||
|
||||
(: Get current search results :)
|
||||
declare %rest:path("{$db-lang}/api/search/current")
|
||||
%rest:GET
|
||||
function api:search-current($db-lang as xs:string) {
|
||||
session:get('searchData')
|
||||
};
|
||||
|
||||
0
|
123
xq/site/restx_dict.xq
Normal file
123
xq/site/restx_dict.xq
Normal file
|
@ -0,0 +1,123 @@
|
|||
module namespace page = 'http://ossetic-studies.org/ns/abaevdict-site';
|
||||
|
||||
declare namespace tei = "http://www.tei-c.org/ns/1.0";
|
||||
|
||||
import module namespace abv-m = 'http://ossetic-studies.org/ns/abaevdict-mod' at '../abv-mod.xqm';
|
||||
import module namespace shared = 'http://ossetic-studies.org/ns/abaevdict-site/shared' at './shared/shared.xq';
|
||||
|
||||
(: COMPONENTS :)
|
||||
(: To make the codebase more manageable, components are split into separate
|
||||
files included as modules. :)
|
||||
import module namespace home = 'http://ossetic-studies.org/ns/abaevdict-site/home' at './components/home.xq';
|
||||
import module namespace dict = 'http://ossetic-studies.org/ns/abaevdict-site/dictionary' at './components/dictionary.xq';
|
||||
import module namespace index = 'http://ossetic-studies.org/ns/abaevdict-site/index' at './components/index.xq';
|
||||
|
||||
(: =============================================================== :)
|
||||
(: ============================ FAVICON ========================== :)
|
||||
(: =============================================================== :)
|
||||
|
||||
declare %rest:path("/favicon.ico")
|
||||
%rest:GET
|
||||
function page:favicon() {
|
||||
fetch:binary('../../static/favicon.ico')
|
||||
};
|
||||
|
||||
(: =============================================================== :)
|
||||
(: ======================= HOMEPAGE ============================== :)
|
||||
(: =============================================================== :)
|
||||
|
||||
declare %rest:path("{$lang}")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:zero($lang) {
|
||||
page:home($lang)
|
||||
};
|
||||
|
||||
declare %rest:path("/")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:zero() {
|
||||
page:zero('en')
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/home")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:home($lang) {
|
||||
<html>
|
||||
{shared:head(if ($lang='ru') then 'ИЭСОЯ — Главная' else 'Abaevdict — Home',())}
|
||||
|
||||
<body>
|
||||
{shared:header($lang,`../{shared:invert-lang($lang)}/home`)}
|
||||
|
||||
<main>
|
||||
{
|
||||
home:content($lang)
|
||||
}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
};
|
||||
|
||||
declare %rest:path("home")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:home() {
|
||||
page:home('en')
|
||||
};
|
||||
|
||||
(: =============================================================== :)
|
||||
(: ======================= THE DICTIONARY ======================== :)
|
||||
(: =============================================================== :)
|
||||
|
||||
(: If no language defined, default to English :)
|
||||
declare %rest:path("dict")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:dict() {
|
||||
web:forward('/en/dict')
|
||||
};
|
||||
|
||||
(: The main dictionary view :)
|
||||
declare %rest:path("{$lang}/dict")
|
||||
%rest:query-param("page","{$p}", 1)
|
||||
%rest:query-param("xpath","{$xpath}", '')
|
||||
%rest:query-param("entry","{$entry}", '')
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:dict($lang, $p, $xpath, $entry) {
|
||||
<html>
|
||||
{shared:head('HEDO – Dictionary',
|
||||
(<script src="/static/infinite-scroll.pkgd.min.js">
|
||||
</script>,
|
||||
<script src="/static/plotly-3.0.1.min.js" charset="utf-8"></script>,
|
||||
<script src="/static/abaev.js"></script>))}
|
||||
|
||||
<body>
|
||||
{(
|
||||
shared:header($lang,`../{shared:invert-lang($lang)}/dict`),
|
||||
dict:main-view($lang, $p, $xpath, $entry)
|
||||
)}
|
||||
</body>
|
||||
</html>
|
||||
};
|
||||
|
||||
(: =============================================================== :)
|
||||
(: ======================= THE INDEX ============================= :)
|
||||
(: =============================================================== :)
|
||||
|
||||
(: Mentioned index :)
|
||||
declare %rest:path("{$lang}/index")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:index($lang) {
|
||||
index:content($lang)
|
||||
};
|
||||
|
||||
(: Default to English :)
|
||||
declare %rest:path("index")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function page:index() {
|
||||
page:index('en')
|
||||
};
|
31
xq/site/restx_entrypoints.xq
Normal file
31
xq/site/restx_entrypoints.xq
Normal file
|
@ -0,0 +1,31 @@
|
|||
module namespace entry = 'http://ossetic-studies.org/ns/abaevdict-site/entrypoints';
|
||||
|
||||
import module namespace shared = 'http://ossetic-studies.org/ns/abaevdict-site/shared' at './shared/shared.xq';
|
||||
|
||||
(: This module includes various ways of accessing dictionary resources by
|
||||
their identifiers. Right now, this only applies to entries, but may apply to
|
||||
other things as well :)
|
||||
|
||||
(: == ENTRY BY ID == :)
|
||||
(: English as default language :)
|
||||
declare %rest:path("dict/{$id}")
|
||||
%rest:query-param("xpath", "{$xpath}", '')
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function entry:by-id($id, $xpath) {
|
||||
entry:by-id('en', $id, $xpath)
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/dict/{$id}")
|
||||
%rest:query-param("xpath", "{$xpath}", '')
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function entry:by-id($lang, $id, $xpath) {
|
||||
let $doc-index := index-where($shared:sorted, fn { ./@xml:id=$id })
|
||||
let $pagenum := ceiling($doc-index div $shared:items-per-page)
|
||||
return web:redirect('../dict',
|
||||
map:merge(({'page': $pagenum,
|
||||
'entry': web:decode-url($id)},
|
||||
if ($xpath != '') then {'xpath': $xpath})),
|
||||
web:decode-url($id))
|
||||
};
|
75
xq/site/restx_search.xq
Normal file
75
xq/site/restx_search.xq
Normal file
|
@ -0,0 +1,75 @@
|
|||
module namespace search = 'http://ossetic-studies.org/ns/abaevdict-site/search';
|
||||
|
||||
import module namespace abv-m = 'http://ossetic-studies.org/ns/abaevdict-mod' at '../abv-mod.xqm';
|
||||
import module namespace entry = 'http://ossetic-studies.org/ns/abaevdict-site/entrypoints' at './restx_entrypoints.xq';
|
||||
|
||||
(: =============================================================== :)
|
||||
(: ======================= SEARCH ENTRYPOINT ===================== :)
|
||||
(: =============================================================== :)
|
||||
|
||||
declare %rest:path("/search/{$path=.+}")
|
||||
%rest:GET
|
||||
function search:search-default($path as xs:string) {
|
||||
web:forward(`/en/search/{$path}`)
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/search/new")
|
||||
%rest:query-param("searchType", "{$searchType}", 'full')
|
||||
%rest:query-param("searchQuery", "{$searchQuery}")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function search:search($lang, $searchType, $searchQuery) {
|
||||
let $sd := abv-m:search($lang,$searchType,$searchQuery)
|
||||
let $r1 := session:set('searchType', $searchType)
|
||||
let $r2 := session:set('searchQuery', $searchQuery)
|
||||
let $r3 := session:set('searchN', 1)
|
||||
let $r4 := session:set('searchData', $sd)
|
||||
return
|
||||
if(array:size($sd) > 0) then
|
||||
entry:by-id($lang,
|
||||
$sd(1)('entry'),
|
||||
'')
|
||||
else
|
||||
web:redirect('../search/clear')
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/search/next")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function search:search-next($lang) {
|
||||
let $n as xs:integer := session:get('searchN')+1
|
||||
let $r1 := session:set('searchN', $n)
|
||||
let $sd := session:get('searchData')
|
||||
return entry:by-id($lang, $sd($n)('entry'), ())
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/search/prev")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function search:search-prev($lang) {
|
||||
let $n as xs:integer := session:get('searchN')-1
|
||||
let $r1 := session:set('searchN', $n)
|
||||
let $sd := session:get('searchData')
|
||||
return entry:by-id($lang, $sd($n)('entry'), ())
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/search/position")
|
||||
%rest:query-param("p", "{$p}")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function search:search-position($lang, $p as xs:integer) {
|
||||
let $r1 := session:set('searchN', $p)
|
||||
let $sd := session:get('searchData')
|
||||
return entry:by-id($lang, $sd($p)('entry'), ())
|
||||
};
|
||||
|
||||
declare %rest:path("{$lang}/search/clear")
|
||||
%output:method("html")
|
||||
%output:html-version('5')
|
||||
function search:clearSearch($lang) {
|
||||
let $r1 := session:delete('searchType')
|
||||
let $r2 := session:delete('searchQuery')
|
||||
let $r3 := session:delete('searchN')
|
||||
let $r4 := session:delete('searchData')
|
||||
return web:redirect('../dict')
|
||||
};
|
165
xq/site/shared/shared.xq
Normal file
165
xq/site/shared/shared.xq
Normal file
|
@ -0,0 +1,165 @@
|
|||
module namespace shared = 'http://ossetic-studies.org/ns/abaevdict-site/shared';
|
||||
|
||||
declare namespace tei = "http://www.tei-c.org/ns/1.0";
|
||||
import module namespace search = 'http://ossetic-studies.org/ns/abaevdict-site/search-modal' at '../components/search.xq';
|
||||
|
||||
(: =========================================================== :)
|
||||
(: ================== GLOBAL VARIABLES ======================= :)
|
||||
(: =========================================================== :)
|
||||
|
||||
(: Number of items per page :)
|
||||
declare variable $shared:items-per-page as xs:integer := 20;
|
||||
|
||||
(: These variables are declared in module scope because they are needed in
|
||||
different places, but they are still dynamically evaluated :)
|
||||
declare variable $shared:lookup := doc('abaevdict_index/lookup.xml')/tei:table/tei:entry;
|
||||
declare variable $shared:lookup-all := doc('abaevdict_index/lookup.xml')/tei:table/*;
|
||||
|
||||
declare variable $shared:total := ceiling(count($shared:lookup) div $shared:items-per-page);
|
||||
(: This is still called sorted, because I haven't changed the code.
|
||||
But it's now equal to lookup, because the lookup itself is now sorted. :)
|
||||
declare variable $shared:sorted := $shared:lookup;
|
||||
|
||||
(: =============================================================== :)
|
||||
(: ======================= COMMON STUFF ========================== :)
|
||||
(: =============================================================== :)
|
||||
|
||||
declare function shared:head($title as xs:string, $script as node()* := ()) {
|
||||
<head>
|
||||
<script src="/static/jquery-3.7.1.min.js">
|
||||
</script>
|
||||
<script src="/static/abaev-global.js">
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"/>
|
||||
|
||||
<link rel="stylesheet" href="{web:create-url('/static/abaev-html.css')}"/>
|
||||
|
||||
{$script}
|
||||
|
||||
<title>{$title}</title>
|
||||
</head>
|
||||
};
|
||||
|
||||
(: Navigation header and search dialog :)
|
||||
declare function shared:header($lang as xs:string, $href-other as xs:string) {
|
||||
(
|
||||
<header>
|
||||
<nav>
|
||||
<ul class="abv-brand">
|
||||
<li><img class="abv-logo" src="/static/Abaev_logo.png" alt="Abaevdict logo"></img>
|
||||
<strong>{
|
||||
switch($lang)
|
||||
case 'ru' return 'ИЭСОЯ'
|
||||
default return `Abaevdict`
|
||||
}</strong><i> β</i></li>
|
||||
<li>{
|
||||
(element {if ($lang = 'ru') then 'mark' else 'a'}{
|
||||
if ($lang != 'ru') then
|
||||
(attribute class {'link'},
|
||||
attribute data-href {`{$href-other}`}) else (),
|
||||
'ru'
|
||||
}, ' / ',
|
||||
element {if ($lang = 'ru') then 'a' else 'mark'}{
|
||||
if ($lang = 'ru') then
|
||||
(attribute class {'link'},
|
||||
attribute data-href {`{$href-other}`}) else (),
|
||||
'en'
|
||||
})
|
||||
}
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<form role="search" action="./search/new" id="abv-search">
|
||||
{if (session:get('searchQuery')) then
|
||||
<button class="link" data-href="./search/clear" type="button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x-lg" viewBox="0 0 16 16">
|
||||
<path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z"/>
|
||||
</svg>
|
||||
</button>
|
||||
else
|
||||
<select name="searchType" required="1">
|
||||
<option selected="1" value="full">{if ($lang = 'ru')
|
||||
then 'Везде' else 'All'}</option>
|
||||
<option value="form">{if ($lang = 'ru')
|
||||
then 'Формы' else 'Forms'}</option>
|
||||
<option value="sense">{if ($lang = 'ru')
|
||||
then 'Значения' else 'Senses'}</option>
|
||||
<option value="example">{if ($lang = 'ru')
|
||||
then 'Примеры' else 'Examples'}</option>
|
||||
<option value="translation">{if ($lang = 'ru')
|
||||
then 'Переводы' else 'Translations'}</option>
|
||||
<option value="mentioned">{if ($lang = 'ru')
|
||||
then 'Цит. формы' else 'Mentioned'}</option>
|
||||
<option value="gloss">{if ($lang = 'ru')
|
||||
then 'Глоссы' else 'Glosses'}</option>
|
||||
<option value="etym">{if ($lang = 'ru')
|
||||
then 'Этимологии' else 'Etymology'}</option>
|
||||
</select>
|
||||
}
|
||||
<input name="searchQuery"
|
||||
placeholder="{if ($lang = 'ru') then 'Искать' else 'Search'}"
|
||||
value="{session:get('searchQuery')}"
|
||||
aria-label="Search">
|
||||
{if (exists(session:get('searchQuery'))) then
|
||||
attribute disabled {"1"} }
|
||||
</input>
|
||||
{if (not(session:get('searchQuery'))) then
|
||||
<button type="submit">
|
||||
<svg id="abv-search-icon" xmlns="http://www.w3.org/2000/svg"
|
||||
width="16" height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor" class="bi bi-search">
|
||||
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0"/>
|
||||
</svg>
|
||||
</button>
|
||||
else
|
||||
(
|
||||
if (session:get('searchN') > 1) then
|
||||
<button type="button" class="link" data-href="./search/prev">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8"/>
|
||||
</svg>
|
||||
</button>,
|
||||
<button type="button" id="abv-btn-searchResults">{session:get('searchN')}/{array:size(session:get('searchData'))}</button>
|
||||
,
|
||||
if (session:get('searchN') and session:get('searchN') < array:size(session:get('searchData'))) then
|
||||
<button type="button" class="link" data-href="./search/next">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-right" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M1 8a.5.5 0 0 1 .5-.5h11.793l-3.147-3.146a.5.5 0 0 1 .708-.708l4 4a.5.5 0 0 1 0 .708l-4 4a.5.5 0 0 1-.708-.708L13.293 8.5H1.5A.5.5 0 0 1 1 8"/>
|
||||
</svg>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
</form>
|
||||
</li>
|
||||
<li><a href="./home">{
|
||||
switch($lang)
|
||||
case 'ru' return 'Главная'
|
||||
default return 'Home'
|
||||
}
|
||||
</a></li>
|
||||
<li><a href="./dict">{switch($lang)
|
||||
case 'ru' return 'Словарь'
|
||||
default return 'Dictionary'
|
||||
}
|
||||
</a></li>
|
||||
<li><a href="./index">{switch($lang)
|
||||
case 'ru' return 'Указатель'
|
||||
default return 'Index'
|
||||
}</a></li>
|
||||
<li><a href="#">{switch($lang)
|
||||
case 'ru' return 'Литература'
|
||||
default return 'References'
|
||||
}</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>,
|
||||
search:content($lang)
|
||||
)
|
||||
};
|
||||
|
||||
declare function shared:invert-lang($lang as xs:string) as xs:string {
|
||||
if($lang = 'en') then 'ru' else 'en'
|
||||
};
|
Loading…
Add table
Reference in a new issue