diff --git a/static/abaev-global.js b/static/abaev-global.js index 8e9071a..6398f17 100644 --- a/static/abaev-global.js +++ b/static/abaev-global.js @@ -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('
'); }); + + // 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 = ` + + ${pos+1} + + ${result.entryForm} + + + ${result.fragment} + + + ` + $(this).find('tbody').append($(html)); + } + // $(this).find('tbody').append($(html)); + }); }); diff --git a/static/abaev-html.css b/static/abaev-html.css index 837dfe6..305ad68 100644 --- a/static/abaev-html.css +++ b/static/abaev-html.css @@ -216,7 +216,7 @@ a.abv-map img { height: 2ex; } -a.link:hover { +a.link:hover, a.abv-map:hover { cursor: pointer; } diff --git a/static/abaev.js b/static/abaev.js index 6409e8b..c720252 100644 --- a/static/abaev.js +++ b/static/abaev.js @@ -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 () { diff --git a/xq/abv-mod.xqm b/xq/abv-mod.xqm index 841ec71..bbe2a38 100644 --- a/xq/abv-mod.xqm +++ b/xq/abv-mod.xqm @@ -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': {util:strip-namespaces(($mark//*[tei:mark])[1])/child::node()} diff --git a/xq/restx_dict.xq.old b/xq/restx_dict.xq.old deleted file mode 100644 index 7076d6c..0000000 --- a/xq/restx_dict.xq.old +++ /dev/null @@ -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 - - - - - - - - - - - Abaev - - -
- -
- - - -
- {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} -
- - - -
-
-

Map

-
-

-

-

- -
-
- - -}; - -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'}) -}; \ No newline at end of file diff --git a/xq/restx_dict_cached.xq b/xq/restx_dict_cached.xq deleted file mode 100644 index 22d02d1..0000000 --- a/xq/restx_dict_cached.xq +++ /dev/null @@ -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()* := ()) { - - - - - - - - - {$script} - - {$title} - -}; - -(: Navigation header :) -declare function page:header($lang as xs:string, $href-other as xs:string) { -
- -
-}; - -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) { - - {page:head(if ($lang='ru') then 'ИЭСОЯ — Главная' else 'Abaevdict — Home',())} - - - {page:header($lang,`../{page:invert-lang($lang)}/home`)} - -
- { - switch($lang) - case "ru" return ( -

-Вы находитесь на сайте электронной двуязычной версии -Историко-этимологического -словаря осетинского языка (ИЭСОЯ) В. И. Абаева. -Оцифровка и перевод словаря выполнены группой сотрудников, студентов и аспирантов -отделения теоретической и -прикладной лингвистики МГУ имени М. В. Ломоносова и - -сектора иранских языков Института языкознания РАН. -

, -

- Электронная версия словаря и перевод III и IV томов выполнены за счёт - гранта Российского научного фонда № - 22-28-01639. -

, -

-Мы выражаем особую благодарность Амирхану Михайловичу Торчинову, который -выступил инициатором этого проекта и продолжает оказывать нам неоценимую -поддержку в нашей работе. Мы также благодарны московской осетинской общине за -поддержку перевода I–II томов словаря и помощь в печатном издании их английской -версии, в особенности Александру Тотоонову, Валерию Дзгоеву, Олегу Пухову, -Владиславу Хаблиеву, Руслану Бестолову, Виталию Даурову, Игорю Дзуцеву, Марине -Каболовой, Владимиру Туганову, Зоинбеку Абаеву, Виктору Джиоеву, Владимиру -Бароеву и Борису Базаеву. -

, -

-Электронная версия словаря основана на адаптации системы XML-разметки -TEI P5. Сервер базы данных использует систему -BaseX. Модель разметки словаря и реализация её -программного отображения разработаны О. И. Беляевым. Все исходные -данные доступны в репозиториях -проекта. -

, -

-Дизайн и эмблема сайта выполнены А. А. Осиповой. -

, -

-В предыдущей версии электронного словаря использовалась реляционная -модель представления данных, -разработанная Ю. Ю. Макаровым (ИЯз РАН, Кембриджский университет) -на платформе OnLex. -

, -
Как ссылаться
, -
Belyaev, Oleg, Irina Khomchenkova, Julia Sinitsyna, Vadim Dyachkov. Digitizing print dictionaries using TEI: The Abaev Dictionary Project // IWCLUL 2021: The Seventh International Workshop on Computational Linguistics of Uralic Languages. Proceedings of the Workshop. Stroudsburg, USA: Association for Computational Linguistics, 2021. P. 12–19. -
, -
Участники проекта
, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Научный руководительО. И. Беляев(МГУ имени - М. В. Ломоносова, ИЯз РАН)
Основные участникиЮ. В. Синицына(МГУ имени - М. В. Ломоносова)
И. А. Хомченкова(МГУ имени М. В. Ломоносова, ИРЯ РАН)
Оцифровка и переводВ. В. Дьячков(ИЯз РАН)
А. А. Осипова(МГУ имени М. В. Ломоносова)
А. О. Бадеев(ИЯз РАН, НИУ ВШЭ)
Д. А. Алексеев(МГУ имени М. В. Ломоносова)
) - default return - ( -

-This is the website of the electronic version of V. I. Abaev's -Historical-Etymological Dictionary -of Ossetic (HEDO). Its digitization and English translation have been -carried out by staff members and students of the -department of theoretical and applied -linguistics, Lomonosov Moscow State University, and the -Department of Iranian languages, Institute of Linguistics RAS. -

, -

- The electronic version of the dictionary and the translation of vols. 3 and 4 - have been supported by the Russian Science Foundation, project no. - 22-28-01639. -

, -

-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. -

, -

-The electronic edition of the dictionary is based on an adaptation of the -XML-based TEI P5 markup system. The database -server runs on BaseX. The markup model and its -software realization have been developed by Oleg Belyaev. All sources are -available in our repositories. -

, -

-Site design and logo are by Anna Osipova. -

, -

-The previous version of the electronic dictionary used a relational -data model developed by Yury Makarov -(IL RAS, Cambridge University) using the OnLex platform. -

, -
How to cite
, -
Belyaev, Oleg, Irina Khomchenkova, Julia Sinitsyna, Vadim Dyachkov. Digitizing print dictionaries using TEI: The Abaev Dictionary Project // IWCLUL 2021: The Seventh International Workshop on Computational Linguistics of Uralic Languages. Proceedings of the Workshop. Stroudsburg, USA: Association for Computational Linguistics, 2021. P. 12–19. -
, -
Project participants
, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Project leaderOleg Belyaev(Lomonosov MSU, IL RAS)
Core teamIrina Khomchenkova(Lomonosov MSU, Vinogradov RLI RAS)
Julia Sinitsyna(Lomonosov MSU)
Digitization and translationVadim Dyachkov(IL RAS, LLACAN CNRS)
Anna Osipova(Lomonosov MSU)
Artyom Badeev(IL RAS, HSE University)
Danil Alekseev(Lomonosov MSU)
) - } -
- - - }; - -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) { - - {page:head('HEDO – Dictionary', - (, - , - ))} - - - {page:header($lang,`../{page:invert-lang($lang)}/dict`)} - - - - - - - -
- {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
{( - (: Block with icons to the left of entry (floating) :) -
- { - - - - - - , - 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 - - }
, - $html)}
- } -
- - - - - - -
-
- -

{if ($lang = 'ru') then 'Карта' else 'Map'}

-
-

-

-

- -
-
- - - {if (exists(session:get('searchData'))) then - -
-
-
- - - - - - - - - - { - for $res in session:get('searchData')?* - count $pos - return - - - - - } - -
{if ($lang = 'ru') then '№' else 'No.'}{if ($lang = 'ru') then 'Лемма' else 'Lemma'}{if ($lang = 'ru') then 'Фрагмент' else 'Fragment'}
{$pos} - - { - abv-m:entry-form-by-id($res('entry')) - } - - - { - $res('fragment') - } -
- -
-
} - - -}; - -(: == 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 - -{page:head('HEDO – Index', )} - -{page:header($lang, `../{page:invert-lang($lang)}/index`)} -
-
-
- - -
-
- - -
-
- - -
-
-
- -
-
- - - }; - -(: Default to English :) -declare %rest:path("index") - %output:method("html") - %output:html-version('5') - function page:index() { - page:index('en') - }; \ No newline at end of file diff --git a/xq/site/components/dictionary.xq b/xq/site/components/dictionary.xq new file mode 100644 index 0000000..68af40e --- /dev/null +++ b/xq/site/components/dictionary.xq @@ -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) { + ( + , + , + + ) +}; + +declare function dict:main-view($lang as xs:string, + $p as xs:integer, + $xpath as xs:string, + $entry as xs:string) { + (dict:sidebar($lang), +
+ {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
{( + (: Block with icons to the left of entry (floating) :) +
+ { + + + + + + , + 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 + + }
, + $html)}
+ } +
, + , + +
+
+ +

{if ($lang = 'ru') then 'Карта' else 'Map'}

+
+

+

+

+ +
+
) +}; \ No newline at end of file diff --git a/xq/site/components/home.xq b/xq/site/components/home.xq new file mode 100644 index 0000000..53f73fd --- /dev/null +++ b/xq/site/components/home.xq @@ -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 ( +

+Вы находитесь на сайте электронной двуязычной версии +Историко-этимологического +словаря осетинского языка (ИЭСОЯ) В. И. Абаева. +Оцифровка и перевод словаря выполнены группой сотрудников, студентов и аспирантов +отделения теоретической и +прикладной лингвистики МГУ имени М. В. Ломоносова и + +сектора иранских языков Института языкознания РАН. +

, +

+ Электронная версия словаря и перевод III и IV томов выполнены за счёт + гранта Российского научного фонда № + 22-28-01639. +

, +

+Мы выражаем особую благодарность Амирхану Михайловичу Торчинову, который +выступил инициатором этого проекта и продолжает оказывать нам неоценимую +поддержку в нашей работе. Мы также благодарны московской осетинской общине за +поддержку перевода I–II томов словаря и помощь в печатном издании их английской +версии, в особенности Александру Тотоонову, Валерию Дзгоеву, Олегу Пухову, +Владиславу Хаблиеву, Руслану Бестолову, Виталию Даурову, Игорю Дзуцеву, Марине +Каболовой, Владимиру Туганову, Зоинбеку Абаеву, Виктору Джиоеву, Владимиру +Бароеву и Борису Базаеву. +

, +

+Электронная версия словаря основана на адаптации системы XML-разметки +TEI P5. Сервер базы данных использует систему +BaseX. Модель разметки словаря и реализация её +программного отображения разработаны О. И. Беляевым. Все исходные +данные доступны в репозиториях +проекта. +

, +

+Дизайн и эмблема сайта выполнены А. А. Осиповой. +

, +

+В предыдущей версии электронного словаря использовалась реляционная +модель представления данных, +разработанная Ю. Ю. Макаровым (ИЯз РАН, Кембриджский университет) +на платформе OnLex. +

, +
Как ссылаться
, +
Belyaev, Oleg, Irina Khomchenkova, Julia Sinitsyna, Vadim Dyachkov. Digitizing print dictionaries using TEI: The Abaev Dictionary Project // IWCLUL 2021: The Seventh International Workshop on Computational Linguistics of Uralic Languages. Proceedings of the Workshop. Stroudsburg, USA: Association for Computational Linguistics, 2021. P. 12–19. +
, +
Участники проекта
, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Научный руководительО. И. Беляев(МГУ имени + М. В. Ломоносова, ИЯз РАН)
Основные участникиЮ. В. Синицына(МГУ имени + М. В. Ломоносова)
И. А. Хомченкова(МГУ имени М. В. Ломоносова, ИРЯ РАН)
Оцифровка и переводВ. В. Дьячков(ИЯз РАН)
А. А. Осипова(МГУ имени М. В. Ломоносова)
А. О. Бадеев(ИЯз РАН, НИУ ВШЭ)
Д. А. Алексеев(МГУ имени М. В. Ломоносова)
) + default return + ( +

+This is the website of the electronic version of V. I. Abaev's +Historical-Etymological Dictionary +of Ossetic (HEDO). Its digitization and English translation have been +carried out by staff members and students of the +department of theoretical and applied +linguistics, Lomonosov Moscow State University, and the +Department of Iranian languages, Institute of Linguistics RAS. +

, +

+ The electronic version of the dictionary and the translation of vols. 3 and 4 + have been supported by the Russian Science Foundation, project no. + 22-28-01639. +

, +

+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. +

, +

+The electronic edition of the dictionary is based on an adaptation of the +XML-based TEI P5 markup system. The database +server runs on BaseX. The markup model and its +software realization have been developed by Oleg Belyaev. All sources are +available in our repositories. +

, +

+Site design and logo are by Anna Osipova. +

, +

+The previous version of the electronic dictionary used a relational +data model developed by Yury Makarov +(IL RAS, Cambridge University) using the OnLex platform. +

, +
How to cite
, +
Belyaev, Oleg, Irina Khomchenkova, Julia Sinitsyna, Vadim Dyachkov. Digitizing print dictionaries using TEI: The Abaev Dictionary Project // IWCLUL 2021: The Seventh International Workshop on Computational Linguistics of Uralic Languages. Proceedings of the Workshop. Stroudsburg, USA: Association for Computational Linguistics, 2021. P. 12–19. +
, +
Project participants
, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Project leaderOleg Belyaev(Lomonosov MSU, IL RAS)
Core teamIrina Khomchenkova(Lomonosov MSU, Vinogradov RLI RAS)
Julia Sinitsyna(Lomonosov MSU)
Digitization and translationVadim Dyachkov(IL RAS, LLACAN CNRS)
Anna Osipova(Lomonosov MSU)
Artyom Badeev(IL RAS, HSE University)
Danil Alekseev(Lomonosov MSU)
) +}; \ No newline at end of file diff --git a/xq/site/components/index.xq b/xq/site/components/index.xq new file mode 100644 index 0000000..4e7c1ad --- /dev/null +++ b/xq/site/components/index.xq @@ -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 + +{shared:head('HEDO – Index', )} + +{shared:header($lang, `../{shared:invert-lang($lang)}/index`)} +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+
+ + +}; \ No newline at end of file diff --git a/xq/site/components/search.xq b/xq/site/components/search.xq new file mode 100644 index 0000000..12efccf --- /dev/null +++ b/xq/site/components/search.xq @@ -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 + +
+
+
+ + + + + + + + + + +
{if ($lang = 'ru') then '№' else 'No.'}{if ($lang = 'ru') then 'Лемма' else 'Lemma'}{if ($lang = 'ru') then 'Фрагмент' else 'Fragment'}
+ +
+
+}; \ No newline at end of file diff --git a/xq/restx_api.xq b/xq/site/restx_api.xq similarity index 96% rename from xq/restx_api.xq rename to xq/site/restx_api.xq index 6d8cea0..9ea4cb5 100644 --- a/xq/restx_api.xq +++ b/xq/site/restx_api.xq @@ -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 ======================== :) @@ -199,5 +199,12 @@ declare %rest:path("{$db-lang}/api/search") $query as xs:string) { 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 \ No newline at end of file diff --git a/xq/site/restx_dict.xq b/xq/site/restx_dict.xq new file mode 100644 index 0000000..823e706 --- /dev/null +++ b/xq/site/restx_dict.xq @@ -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) { + + {shared:head(if ($lang='ru') then 'ИЭСОЯ — Главная' else 'Abaevdict — Home',())} + + + {shared:header($lang,`../{shared:invert-lang($lang)}/home`)} + +
+ { + home:content($lang) + } +
+ + + }; + +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) { + + {shared:head('HEDO – Dictionary', + (, + , + ))} + + + {( + shared:header($lang,`../{shared:invert-lang($lang)}/dict`), + dict:main-view($lang, $p, $xpath, $entry) + )} + + +}; + +(: =============================================================== :) +(: ======================= 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') + }; \ No newline at end of file diff --git a/xq/site/restx_entrypoints.xq b/xq/site/restx_entrypoints.xq new file mode 100644 index 0000000..3d3b176 --- /dev/null +++ b/xq/site/restx_entrypoints.xq @@ -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)) + }; \ No newline at end of file diff --git a/xq/site/restx_search.xq b/xq/site/restx_search.xq new file mode 100644 index 0000000..e27f8e5 --- /dev/null +++ b/xq/site/restx_search.xq @@ -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') + }; \ No newline at end of file diff --git a/xq/site/shared/shared.xq b/xq/site/shared/shared.xq new file mode 100644 index 0000000..05efd96 --- /dev/null +++ b/xq/site/shared/shared.xq @@ -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()* := ()) { + + + + + + + + + {$script} + + {$title} + +}; + +(: Navigation header and search dialog :) +declare function shared:header($lang as xs:string, $href-other as xs:string) { + ( +
+ +
, + search:content($lang) + ) +}; + +declare function shared:invert-lang($lang as xs:string) as xs:string { + if($lang = 'en') then 'ru' else 'en' +}; \ No newline at end of file