// Copyright (C) 2016-2017, Maxim Lihachev, // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // [ ] TODO: валидация //------------------------------------------------------------------------------ 'use strict'; //------------------------------------------------------------------------------ //Иерархия элементов на странице var HTML = { container: "", _select: function(element) { return document.getElementById(this.container + "-" + element); }, input: function() { return this._select("word"); }, button: function() { return this._select("convert"); }, dict: function() { return this._select("dict"); }, content: function() { return this._select("content"); }, full: function() { return this._select("full"); }, help: function() { return this._select("help"); }, image: function() { return this._select("image"); }, }; //Вывод справки с примерами использования function show_help() { HTML.vis(HTML.help()); HTML.vis(HTML.content()); } HTML.vis = function(e, v) { if (v !== undefined) { e.style.visibility = v; } else { e.style.visibility = e.style.visibility === "visible" ? "hidden" : "visible"; } } //Инициализация документа HTML.init = function(root) { //Задание базового id для всех элементов this.container = root; //Конвертирование по нажатию this.input().addEventListener('keyup', event => { event.preventDefault(); event.keyCode == 13 && tr(); }); //Конвертирование по нажатию кнопки this.button().onclick = () => tr(); }; //------------------------------------------------------------------------------ //Правила создания феминитивов var FEM = {}; FEM.endings = { 'ка' : [ ['[аео]р', 0], ['ан', 0], ['рг', 1], ['ст', 0], //специалист -> специалистка ['ль', 1], //создатель -> создателка ['ец', 2], //канадец -> канадка ['ет', 0], //авторитет -> авторитетка ['от', 0] //гот -> готка ], 'ина' : [ ['ас', 0] ], 'иня' : [ ['[аео]р', 0], ['[ои]к', 0], ['со', 1], //колесо -> колесиня ['ог', 0], //биолог -> биологиня ['рг', 0], ['ач', 0], //врач -> врачиня ['ль', 1], //создатель -> создателиня ['ст', 0], //специалист -> специалистиня ['од', 0], //метод -> методиня ['ет', 2], //авторитет -> авторитиня ['ец', 2], //канадец -> канадиня ['аф', 0] //граф -> графиня ], 'киня' : [ ['[аео]р', 0], ['ок', 0], ['ст', 0], //специалист -> специалисткиня ['ан', 0] ], 'есса' : [ ['[аео]р', 0], ['[ои]к', 0], ['ог', 0], //биолог -> биологесса ['ан', 0], ['ль', 1], //создатель -> создателесса ['рг', 0], ['ач', 0], //врач -> врачесса ['ый', 2], //учёный -> учёнесса ['ст', 0], //специалист -> специалистесса ['од', 0], //метод -> методесса ['ет', 2], //авторитет -> авторитесса ['ец', 2], //канадец -> канадесса ['от', 0], //гот -> готесса ['эт', 0] //поэт -> поэтесса ], 'ица' : [ ['[аео]р', 0], ['уч', 0], ['ик', 2], ['ог', 0], //биолог -> биологиня ['ан', 0], ['ив', 0], ['рг', 0], ['ас', 0], ['ач', 0], //врач -> врачица ['ст', 3], //специалист -> специалица ['од', 0], //метод -> методица ['ет', 2], //авторитет -> авторитица ['ец', 2] //канадец -> канадица ], 'ница' : [ ['ль', 0], //создатель -> создательница ['ас', 0], ['ет', 0], //авторитет -> авторитетица ['ец', 2] //канадец -> канадница ], 'ая' : [ ['[ыио]й', 2], //учёный -> учёная, знающий -> знающая ['ое', 2] ], //----- ДАЛЬШЕ ИДЁТ ШИЗА ----- 'ии' : [ ['и[ия]', 2], //металлургии -> металлург_ии, произведения -> произведении ], 'ца' : [ ['ие', 1], //металлургии -> металлург_ии, произведения -> произведении ], 'ми' : [ ['ми', 2] //знаниями -> знания_ми ], 'ой' : [ ['го', 3] //художественного -> художественн_ой ], 'инь' : [ ['ей', 2] //людей -> люд_ей ], 'ти' : [ ['ти', 2] //области -> облас_ти ], 'ю' : [ ['ью', 1] //матерью -> матерь_ю ], 'ны' : [ ['на', 2] //бассейна -> бассей_ны ], }; //Слова со специфичными определениями FEM.exceptions = { 'феминист' : [ ['профеминист', 'союзник'], "Мифическое создание, якобы поддерживающее феминизм. В реальности не встречается." ], 'жена' : [ ['мужерабка', 'подстилка патриархата'], "Женщина, прогнувшаяся под патриархат и получающая удовольствие от угнетения." ] }; //Проверка на исключение FEM.exceptions.contains = function(word) { return Object.keys(this).includes(word); }; //Список значений FEM.exceptions.feminitives = function(word) { return [random_word(this[word][0]), this[word][0]]; }; //Дефиниция слова-исключения FEM.exceptions.definition = function(word) { return this[word][1]; }; //Слова для замены FEM.words = { 'тот' : 'т_а', 'того' : 'т_у', 'кто' : 'котор_ая', 'её' : 'е_ё', 'ее' : 'е_е', 'ий' : 'ая', 'человек' : 'человека', 'муж' : 'жен' }; FEM.words.convert = function(string) { for (var fem_w in this) { string = string.replace(new RegExp(fem_w, "ig"), this[fem_w]) .replace(/(.)/, s => s.toUpperCase()); } return string; }; //------------------------------------------------------------------------------ //Первый элемент списка - окончание (в виде регулярного выражения) let ending = tuple => new RegExp("^.*" + tuple[0] + "$", "i"); //Второй элемент списка - смещение let offset = tuple => tuple[1]; //Случайный элемент списка let random_word = wordlist => wordlist[Math.floor(Math.random() * wordlist.length)]; //Оборачивание в с указанным классом let html_wrap = (str, cl) => `${str}`; //Цветовое выделение текста let css_end = ending => html_wrap(ending, "ending"); //Символ gender gap let css_gender_gap = html_wrap(' \u26A7 ', "queer"); //------------------------------------------------------------------------------ //Конструирование феминитива с gender_gap function construct_feminitive(stem, ending, gap) { return gap ? stem + css_gender_gap + css_end(ending) : stem + "_" + ending; } //Отправка адреса страницы в vk.com function share_page() { let vk_url = "http://vk.com/share.php" + "?url=" + URL.href + "&title=" + URL.title + "&description=" + URL.description.text; let new_tab = window.open(vk_url,'_blank'); new_tab.focus(); } //Сохранение изображения с феминитивом function download_image() { html2canvas(HTML.image(), { onrendered: canvas => { let a = document.createElement('a'); a.href = canvas.toDataURL(); a.download = HTML.content().innerHTML + '.png'; a.click(); } }); } //Создание феминитива function make_feminitives(word) { //Обрабатываем только слова длиннее трёх символов if (word.length < 3) return word; var stem = ""; //Основа слова var current_ending = word.slice(-2); //Текущее окончание var feminitives = []; //Массив феминитивов var femicards = []; //Массив феминитивов для карточки for (let fem_ending in FEM.endings) { FEM.endings[fem_ending].forEach(end => { if (ending(end).test(current_ending)) { //Удаление лишних букв из основы stem = offset(end) === 0 ? word : word.slice(0, -offset(end)); //Добавление фем-варианта слова в массив feminitives.push(construct_feminitive(stem, fem_ending, 1)); femicards.push(construct_feminitive(stem, fem_ending, 0)); } }); } //При отсутствии феминитивов считать корректным исходное слово return [random_word(femicards) || word, feminitives]; } //Поиск и феминизация дефиниции в викистранице function parseWikiPage(page) { var wiki = page.split("\\n"); var definition = ""; wiki.some((line, n) => { if (line.match(/^.*==== Значение ====.*$/)) { console.log(wiki[n+1]); //DEBUG definition = wiki[n+1] .replace(/^# ?/, "") //# дефиниция .replace(/\[{2}([^\]\|]*)\]{2}/g, "$1") //[[1]] .replace(/\[{2}[^\|]*\|([^\]]*)\]{2}/g, "$1") //[[1|2]] .replace(/\[{2}([^\]\|]*)\}{2}/g, "$1") //{{1}} .replace(/\{{2}[^\{\}]*\}{2} ?/g, "") //{{1|2}} .replace(/\{{2}[^\{\}]*\}{2} ?/g, "") //~ : возможна вложенность .replace(/\[[0-9]{1,}\]/g, "") //ссылки [n] .replace(/^ *, */g, "") //^, ... .replace(/ ?$/,"."); //Точка в конце предложения return true; } }); //Разделение дефиниции на массив слов и знаков препинания и феминизация слов var tokens = definition.match(/[\wа-яА-Яё]+|\d+| +|[^ \w\d\t]+/ig) || []; //Замена местоимений, предлогов и проч. HTML.full().innerHTML = FEM.words.convert(tokens.map(w => make_feminitives(w)[0]).join("")); //DEBUG console.log(definition); console.log(tokens); } //Запрос значения слова в викисловаре function get_wiktionary(term) { var cors_url = "https://cors.now.sh/"; var wiki_url = cors_url + "https://ru.wiktionary.org/w/index.php?action=raw&title=" + term; var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { parseWikiPage(xmlhttp.responseText); } }; xmlhttp.open("GET", wiki_url, true); xmlhttp.send(); } //Создание и вывод феминитива function tr(word) { //Исходное слово var wd = word || HTML.input().value.trim().toLowerCase().split(" ")[0]; var feminitives = ""; //Состояние по умолчанию HTML.content().innerHTML = "Введите слово"; HTML.dict().innerHTML = ""; HTML.full().innerHTML = ""; HTML.vis(HTML.help(), "hidden"); HTML.vis(HTML.content(), "visible"); //Изменение адреса URL.set(wd); //Вывод информации if (!wd) { show_help(); return; } else if (FEM.exceptions.contains(wd)) { HTML.full().innerHTML = FEM.exceptions.definition(wd); feminitives = FEM.exceptions.feminitives(wd); } else { get_wiktionary(wd); feminitives = make_feminitives(wd); } //Вывод информации HTML.input().value = wd; HTML.content().innerHTML = feminitives[0].replace(/(.)/, s => s.toUpperCase()); HTML.dict().innerHTML = feminitives[1].join(" | ") || "Это слово и так прекрасно. Оставим его как есть."; } //------------------------------------------------------------------------------ //Параметры URL var URL = { opt: {}, description: { clear: function() { this.text = "Как феминистки пишут разные слова."; }, set: function(wd) { this.text = 'Как феминистки пишут слово "' +wd+ '".'; }, }, set: function(wd) { if (!wd) { window.history.pushState({}, null, window.location.href.split('?')[0]); this.description.clear(); } else { window.history.pushState({}, null, window.location.href.split('?')[0]+'?word='+wd); this.description.set(wd); } this.href = encodeURIComponent(window.location.href); } }; //Разбор параметров URL URL.parse = function() { var gy = window.location.search.substring(1).split("&"); gy.forEach(arg => { let ft = arg.split("="); this.opt[ft[0]] = this.opt[ft[0]] || decodeURIComponent(ft[1]); }); URL.description.clear(); this.title = document.title; this.opt.href = encodeURIComponent(window.location.href); }; //Инициализация с разбором адресной строки function init(container) { HTML.init(container); URL.parse(); if (URL.opt.word) { HTML.input().value = URL.opt.word.replace(/\+/g," "); tr(); } else { show_help(); } }