1// 2// Copyright (C) 2016-2019, Maxim Lihachev, <[email protected]> 3// 4// This program is free software: you can redistribute it and/or modify it 5// under the terms of the GNU General Public License as published by the Free 6// Software Foundation, version 3. 7// 8// This program is distributed in the hope that it will be useful, but WITHOUT 9// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11// more details. 12// 13// You should have received a copy of the GNU General Public License along with 14// this program. If not, see <https://www.gnu.org/licenses/>. 15// 16 17//------------------------------------------------------------------------------ 18 19'use strict'; 20 21//------------------------------------------------------------------------------ 22 23//ÐеÑаÑÑ Ð¸Ñ ÑлеменÑов на ÑÑÑаниÑе 24var HTML = { 25 container: "", 26 _select: function(element) { return document.getElementById(this.container + "-" + element); }, 27 input: function() { return this._select("word"); }, 28 button: function() { return this._select("convert"); }, 29 dict: function() { return this._select("dict"); }, 30 content: function() { return this._select("content"); }, 31 full: function() { return this._select("full"); }, 32 help: function() { return this._select("help"); }, 33 image: function() { return this._select("image"); }, 34}; 35 36//ÐÑвод ÑпÑавки Ñ Ð¿ÑимеÑами иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ 37function show_help() { 38 HTML.vis(HTML.help()); 39 HTML.vis(HTML.content()); 40} 41 42//Смена Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾ ÐºÐ»Ð¸ÐºÑ 43function swap_title(id) { 44 var e = document.getElementById(id); 45 if(e.style.display == 'inline') { 46 e.style.display = 'none'; 47 } else { 48 e.style.display = 'inline'; 49 } 50} 51 52HTML.vis = function(e, v) { 53 if (v !== undefined) { 54 e.style.visibility = v; 55 } else { 56 e.style.visibility = e.style.visibility === "visible" ? "hidden" : "visible"; 57 } 58} 59 60//ÐниÑиализаÑÐ¸Ñ Ð´Ð¾ÐºÑменÑа 61HTML.init = function(root) { 62 //Ðадание базового id Ð´Ð»Ñ Ð²ÑÐµÑ ÑлеменÑов 63 this.container = root; 64 65 //ÐонвеÑÑиÑование по нажаÑÐ¸Ñ <Enter> 66 this.input().addEventListener('keyup', event => { 67 event.preventDefault(); 68 event.keyCode == 13 && tr(); 69 }); 70 71 //ÐонвеÑÑиÑование по нажаÑÐ¸Ñ ÐºÐ½Ð¾Ð¿ÐºÐ¸ 72 this.button().onclick = () => tr(); 73}; 74 75//------------------------------------------------------------------------------ 76 77FEM.words.convert = function(string) { 78 for (var fem_w in this) { 79 string = string.replace(new RegExp('(^|\\s)+' + fem_w, "ig"), '$1' + this[fem_w]) 80 .replace(/(.)/, s => s.toUpperCase()); 81 } 82 return string; 83}; 84 85//------------------------------------------------------------------------------ 86 87//ÐеÑвÑй ÑÐ»ÐµÐ¼ÐµÐ½Ñ ÑпиÑка - оконÑание (в виде ÑегÑлÑÑного вÑÑажениÑ) 88let ending = tuple => new RegExp("^.*" + tuple[0] + "$", "i"); 89 90//ÐÑоÑой ÑÐ»ÐµÐ¼ÐµÐ½Ñ ÑпиÑка - ÑмеÑение 91let offset = tuple => tuple[1]; 92 93//СлÑÑайнÑй ÑÐ»ÐµÐ¼ÐµÐ½Ñ ÑпиÑка 94let random_word = wordlist => wordlist[Math.floor(Math.random() * wordlist.length)]; 95 96//ÐбоÑаÑивание в <span> Ñ ÑказаннÑм клаÑÑом 97let html_wrap = (str, cl) => `<span class="${cl}">${str}</span>`; 98 99//ЦвеÑовое вÑделение ÑекÑÑа 100let css_end = ending => html_wrap(ending, "ending"); 101 102//Символ gender gap 103let css_gender_gap = html_wrap(' \u26A7 ', "queer"); 104 105//------------------------------------------------------------------------------ 106 107//ÐонÑÑÑÑиÑование ÑеминиÑива Ñ gender_gap 108function construct_feminitive(stem, ending, gap) { 109 return gap ? stem + css_gender_gap + css_end(ending) : stem + "_" + ending; 110} 111 112//Ðлина Ñаблона, подпадаÑÑего под ÑегÑлÑÑное вÑÑажение r 113function regex_len(r) { 114 return r.replace(/\[[^\[\]]*\]/g, "x").length; 115} 116 117//ÐÑпÑавка адÑеÑа ÑÑÑаниÑÑ Ð² vk.com
118function share_page() { 119 let vk_url = "http://vk.com/share.php" 120 + "?url=" + URL.href 121 + "&title=" + URL.title 122 + "&description=" + URL.description.text; 123 124 let new_tab = window.open(vk_url,'_blank'); 125 new_tab.focus(); 126} 127 128//Ð¡Ð¾Ñ Ñанение изобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ñ ÑеминиÑивом 129function download_image() { 130 html2canvas(HTML.image(), { 131 onrendered: canvas => { 132 let a = document.createElement('a'); 133 a.href = canvas.toDataURL(); 134 a.download = HTML.content().innerHTML + '.png'; 135 a.click(); 136 } 137 }); 138} 139 140//Создание ÑеминиÑива 141function make_feminitives(word, visibleGaps) { 142 //ÐбÑабаÑÑваем ÑолÑко Ñлова длиннее ÑÑÑÑ Ñимволов 143 if (word.length < 3) return [word, word]; 144 145 if (FEM.words[word] != undefined) { 146 let wrd = visibleGaps ? FEM.words[word] : FEM.words[word].replace("_", ""); 147 148 return [wrd, wrd]; 149 } 150 151 var stem = ""; //ÐÑнова Ñлова 152 // var current_ending = word.slice(-2); //ТекÑÑее оконÑание 153 var current_endings = [word.slice(-4), word.slice(-3), word.slice(-2)]; 154 var feminitives = []; //ÐаÑÑив ÑеминиÑивов 155 var femicards = []; //ÐаÑÑив ÑеминиÑивов Ð´Ð»Ñ ÐºÐ°ÑÑоÑки 156 157 var found = false; 158
159 current_endings.forEach(current_ending => { 160 if (!found) { 161 for (let fem_ending in FEM.endings) { 162 FEM.endings[fem_ending].forEach(end => { 163 if (regex_len(end[0]) === current_ending.length 164 && ending(end).test(current_ending)) { 165 //Удаление лиÑÐ½Ð¸Ñ Ð±Ñкв из оÑÐ½Ð¾Ð²Ñ 166 stem = offset(end) === 0 ? word : word.slice(0, -offset(end)); 167 168 let rule = fem_ending.split("+"); 169 170 let prefix, all_fem_endings; 171 172 if (rule.length > 1) { 173 prefix = rule[0]; 174 all_fem_endings = rule[1]; 175 } else { 176 prefix = ""; 177 all_fem_endings = fem_ending; 178 } 179 180 all_fem_endings.split("|").forEach(e => { 181 //Ðобавление Ñем-ваÑианÑа Ñлова в маÑÑив 182 feminitives.push(construct_feminitive(stem + prefix, e, 1, visibleGaps)); 183 femicards.push(construct_feminitive(stem + prefix, e, 0, visibleGaps)); 184 185 }); 186 187 found = true; 188 } 189 }); 190 } 191 } 192 }); 193 194 //ÐÑи оÑÑÑÑÑÑвии ÑеминиÑивов ÑÑиÑаÑÑ ÐºÐ¾ÑÑекÑнÑм иÑÑ Ð¾Ð´Ð½Ð¾Ðµ Ñлово 195 return [FEM.random_word(femicards) || word, feminitives]; 196} 197 198//Создание ÑеминиÑива 199function make_feminitives_old(word) { 200 //ÐбÑабаÑÑваем ÑолÑко Ñлова длиннее ÑÑÑÑ Ñимволов 201 if (word.length < 3) return [word, word]; 202 203 var stem = ""; //ÐÑнова Ñлова 204 var current_ending = word.slice(-2); //ТекÑÑее оконÑание 205 var feminitives = []; //ÐаÑÑив ÑеминиÑивов 206 var femicards = []; //ÐаÑÑив ÑеминиÑивов Ð´Ð»Ñ ÐºÐ°ÑÑоÑки 207 208 for (let fem_ending in FEM.endings) { 209 FEM.endings[fem_ending].forEach(end => { 210 if (ending(end).test(current_ending)) { 211 //Удаление лиÑÐ½Ð¸Ñ Ð±Ñкв из оÑÐ½Ð¾Ð²Ñ 212 stem = offset(end) === 0 ? word : word.slice(0, -offset(end)); 213 214 //Ðобавление Ñем-ваÑианÑа Ñлова в маÑÑив 215 feminitives.push(construct_feminitive(stem, fem_ending, 1)); 216 femicards.push(construct_feminitive(stem, fem_ending, 0)); 217 } 218 }); 219 } 220 //ÐÑи оÑÑÑÑÑÑвии ÑеминиÑивов ÑÑиÑаÑÑ ÐºÐ¾ÑÑекÑнÑм иÑÑ Ð¾Ð´Ð½Ð¾Ðµ Ñлово 221 return [random_word(femicards) || word, feminitives]; 222} 223 224//ÐоиÑк и ÑеминизаÑÐ¸Ñ Ð´ÐµÑиниÑии в викиÑÑÑаниÑе 225function parseWikiPage(page) { 226 var wiki = page.split('\n'); 227 var definition = ""; 228 229 console.log(wiki) 230 231 wiki.some((line, n) => { 232 if (line.match(/^.*==== ÐнаÑение ====.*$/)) { 233 let definition_line = n + 1; 234 235 //ÐоÑле заголовка возможна пÑÑÑÐ°Ñ ÑÑÑока или помеÑа (напÑимеÑ, {{воен.}}) 236 if (wiki[n+1].trim().length === 0 237 || wiki[n+1].trim().match(/^{{[^}]*}}$/)) { 238 definition_line = n + 2; 239 } 240 241 definition = wiki[definition_line] 242 //# деÑиниÑÐ¸Ñ 243 .replace(/^# ?/, "") 244 245 //[[1]] 246 .replace(/\[{2}([^\]|]*)\]{2}/g, "$1") 247 248 //[[1|2]] 249 .replace(/\[{2}[^|]*\|([^\]]*)\]{2}/g, "$1") 250 251 //{{ÑокÑ.|Ñлово<!--ком.-->.*$ 252 .replace(/\{{2}[а-ÑÐ-Я]+\.[^{}]*\|[^{}]*\}{2}\s*/g, "") 253 254 //~ : возможна вложенноÑÑÑ 255 .replace(/\{{2}[а-ÑÐ-Я]+\.[^{}]*\|[^{}]*\}{2}\s*/g, "") 256 257 //{{-}}$ 258 .replace(/\{\{-\}\}/g, "") 259 260 //{{помеÑа|...}}$ 261 .replace(/\{{2}помеÑа\s*\|[^}]+\}{2}/g, "") 262 263 //{{дейÑÑвие|(глагол)#...lang=LC}}$ 264 .replace(/\{{2}(дейÑÑвие)\s*\|([^#|]+)([#|].*lang=\w{2})?\}{2}/g, "$1 «$2»") 265 266 //{{пÑимеÑ/ÑеманÑика|.*$ или {{пÑимеÑ/ÑеманÑика}} 267 .replace(/\{{2}(пÑимеÑ|ÑеманÑика)(\}{2}|\s*\|.*$)/g, "") 268 269 //{{1|Ñлово<!--комменÑаÑий-->.*$ 270 .replace(/\{{2}[^{}]*\|(lang=\w{2})?/g, "") 271 272 //{{1}} 273 .replace(/\{{2}([^\]|]*)\}{2}/g, "$1") 274 275 //'''ÑдаÑение''' 276 .replace(/'''([^']*)'''/g, "«$1»") 277 278 //<!--комменÑаÑий--> 279 .replace(/<!--[^>]*-->/g, "") 280 281 //}} 282 .replace(/\}{2}/g, "") 283 284 //ÑÑÑлки [n] 285 .replace(/\[[0-9]{1,}\]/g, "") 286 287 //^,; ... 288 .replace(/^\s*[,;]\s*/g, "") 289 290 //{{.*$ 291 .replace(/\{{2}[^}]*$/g, "") 292 293 //HTML 294 .replace(/(<([^>]+)>)/ig, "") 295 296 //ÐеÑазÑÑвнÑй пÑобел 297 .replace(/ /g, " ") 298 299 //ТоÑка в конÑе пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ 300 .replace(/ ?$/,"."); 301 302 return true; 303 } 304 }); 305 306 //Разделение деÑиниÑии на маÑÑив Ñлов и знаков пÑÐµÐ¿Ð¸Ð½Ð°Ð½Ð¸Ñ Ð¸ ÑеминизаÑÐ¸Ñ Ñлов 307 var tokens = definition.match(/[\wа-ÑÐ-ЯÑ]+|\d+| +|[.;,]|[^ \w\d\t.;,]+/ig) || []; 308 console.log(tokens); 309 310 //Ðамена меÑÑоимений, пÑедлогов и пÑоÑ.
311 HTML.full().innerHTML = FEM.words.convert(tokens.map(w => make_feminitives(w)[0]).join("")); 312 313 //DEBUG 314 console.log(definition); 315 console.log(tokens); 316} 317 318//ÐапÑÐ¾Ñ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ñлова в викиÑловаÑе 319function get_wiktionary(term) { 320 var cors_url = "https://api.allorigins.win/get?url="; 321 var wiki_url = cors_url + encodeURIComponent("https://ru.wiktionary.org/w/index.php?action=raw&title=" + term); 322 323 var xmlhttp = window.XMLHttpRequest 324 ? new XMLHttpRequest() 325 : new ActiveXObject("Microsoft.XMLHTTP"); 326 327 xmlhttp.onreadystatechange = function() { 328 if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { 329 console.log(JSON.parse(xmlhttp.response)); 330 parseWikiPage(JSON.parse(xmlhttp.responseText).contents); 331 } 332 }; 333 334 xmlhttp.open("GET", wiki_url, true); 335 xmlhttp.send(); 336} 337 338//Создание и вÑвод ÑеминиÑива 339function tr(word) { 340 //ÐÑÑ Ð¾Ð´Ð½Ð¾Ðµ Ñлово 341 var wd = word || HTML.input().value.trim().toLowerCase().replace(/<\/?[^>]+(>|$)/g, "").split(" ")[0]; 342 var feminitives = ""; 343 344 //СоÑÑоÑние по ÑмолÑÐ°Ð½Ð¸Ñ 345 HTML.content().innerHTML = "ÐведиÑе Ñлово"; 346 HTML.dict().innerHTML = ""; 347 HTML.full().innerHTML = ""; 348 349 HTML.vis(HTML.help(), "hidden"); 350 HTML.vis(HTML.content(), "visible"); 351 352 //Ðзменение адÑеÑа 353 URL.set(wd); 354 355 //ÐÑвод инÑоÑмаÑии 356 if (!wd) { 357 show_help(); 358 359 return; 360 } else if (FEM.exceptions.contains(wd)) { 361 HTML.full().innerHTML = FEM.exceptions.definition(wd); 362 feminitives = FEM.exceptions.feminitives(wd); 363 } else { 364 get_wiktionary(wd); 365 feminitives = make_feminitives(wd); 366 } 367 //ÐÑвод инÑоÑмаÑии 368 HTML.input().value = wd; 369 HTML.content().innerHTML = feminitives[0].replace(/(.)/, s => s.toUpperCase()); 370 HTML.dict().innerHTML = feminitives[1].join(" | ") 371 || "ÐÑо Ñлово и Ñак пÑекÑаÑно. ÐÑÑавим его как еÑÑÑ."; 372} 373 374//------------------------------------------------------------------------------ 375 376//ÐаÑамеÑÑÑ URL 377var URL = { 378 opt: {}, 379 description: { 380 clear: function() { this.text = "Ðак ÑеминиÑÑки пиÑÑÑ ÑазнÑе Ñлова."; }, 381 set: function(wd) { this.text = 'Ðак ÑеминиÑÑки пиÑÑÑ Ñлово "' +wd+ '".'; }, 382 }, 383 set: function(wd) { 384 if (!wd) { 385 window.history.pushState({}, null, window.location.href.split('?')[0]); 386 this.description.clear(); 387 } else { 388 window.history.pushState({}, null, window.location.href.split('?')[0]+'?word='+wd); 389 this.description.set(wd); 390 } 391 this.href = encodeURIComponent(window.location.href); 392 } 393}; 394 395//Ð Ð°Ð·Ð±Ð¾Ñ Ð¿Ð°ÑамеÑÑов URL 396URL.parse = function() { 397 var gy = window.location.search.substring(1).split("&"); 398 gy.forEach(arg => { 399 let ft = arg.split("="); 400 this.opt[ft[0]] = this.opt[ft[0]] || decodeURIComponent(ft[1]); 401 }); 402 403 URL.description.clear(); 404 this.title = document.title; 405 this.opt.href = encodeURIComponent(window.location.href); 406}; 407 408//ÐниÑиализаÑÐ¸Ñ Ñ ÑазбоÑом адÑеÑной ÑÑÑоки 409function init(container) { 410 HTML.init(container); 411 URL.parse(); 412 413 if (URL.opt.word) { 414 HTML.input().value = URL.opt.word.replace(/\+/g," "); 415 tr(); 416 } else { 417 show_help(); 418 } 419}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.