NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// Merged from __tampermonkey__\HeaderStart.tampermonkey // ==UserScript== // Merged from __tampermonkey__\HeaderName.tampermonkey // @name Majoryzator // Merged from __tampermonkey__\HeaderEnd.tampermonkey // @namespace https://gitlab.com/sukhoi191/majoryzator // @version 1.4.6-beta // @license MIT // @description Spraw, aby dowolna strona internetowa stała się wypowiedzią Majora Suchodolskiego. // @author sukhoi191 // @match *://*/* // @updateURL https://openuserjs.org/meta/sukhoi191/Majoryzator.meta.js // @downloadURL https://openuserjs.org/install/sukhoi191/Majoryzator.user.js // @copyright 2019, sukhoi191 (https://openuserjs.org/users/sukhoi191) // @resource css https://gitlab.com/sukhoi191/majoryzator/raw/master/Majoryzator.css // @resource knownAbbreviationsJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/KnownAbbreviations.json // @resource conjunctionAfterBlacklistJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/ConjunctionAfterBlacklist.json // @resource conjunctionBeforeBlacklistJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/ConjunctionBeforeBlacklist.json // @resource tentativeEndsJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/TentativeEnds.json // @resource kononSentencesJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/Konon_Sentences.json // @resource kononWordsJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/Konon_Words.json // @resource kononFarewellsJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/Konon_Farewells.json // @resource kononWelcomesJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/Konon_Welcomes.json // @resource kononTranslationsJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/Konon_Translations.json // @resource majorSentencesJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/Major_Sentences.json // @resource majorWordsJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/Major_Words.json // @resource majorFarewellsJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/Major_Farewells.json // @resource majorWelcomesJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/Major_Welcomes.json // @resource majorTranslationsJson https://gitlab.com/sukhoi191/majoryzator/raw/master/__data__/Major_Translations.json // @require https://raw.githubusercontent.com/lodash/lodash/4.17.15-npm/lodash.js // @grant GM_getResourceText // @run-at document-end // ==/UserScript== (function() { // Merged from __modules__\UseStrict.js 'use strict'; // Merged from __modules__\TranslationType.js /** * Enumeracja dla typu tłumaczenia. */ const TranslationType = { ANY: 1, BEGIN_ONLY: 2, INSIDE_ONLY: 3, END_ONLY: 4 }; // Merged from __modules__\TranslationCapitalizationType.js /** * Enumeracja dla typu indeksu tłumaczenia. */ const TranslationCapitalizationType = { UPPERCASE: 1, LOWERCASE: 2, TITLECASE: 3, UNKNOWN: 4, NOT_FOUND: 5 }; // Merged from __modules__\SplittedTextPart.js class SplittedTextPart { constructor(text, splitter) { this.text = text; this.splitter = splitter; } getText() { return this.text; } setText(text) { this.text = text; } getSplitter() { return this.splitter; } setSplitter(splitter) { this.splitter = splitter; } removeSplitter() { this.setSplitter(null); } getJoined() { return this.getText() + (this.getSplitter() != null ? this.getSplitter() : ""); } toString() { return 'text: "' + this.getText() + '" | splitter: "' + this.getSplitter() + '"'; } } // Merged from __modules__\Placeholder.js class Placeholder { constructor(content, func) { this.content = content; this.func = func; } swap(textArray) { for (let i = 0; i < textArray.length; i++) { textArray[i] = textArray[i].replace(this.content, this.func()); } return textArray; } } // Merged from __modules__\Person.js /** * Reprezentuje osobę. */ class Person { constructor(name) { this.name = name; this.welcomeSwaps = [ new Placeholder("{PrzywitaniePoraDnia}", () => this.getCorrectWelcomeForTime(new Date())), new Placeholder("{DzienTygodnia}", () => this.getDayOfWeek(new Date())), new Placeholder("{Data}", () => this.getDateAsString(new Date())), new Placeholder("{Godzina}", () => this.getTimeAsString(new Date())) ]; } /** * Imię i nazwisko osoby. */ getName() { return this.name; } /** * Słowa ("spójniki") do wstawienia. */ getWords() { throw new Error('Method is not implemented.'); } /** * Pełne zdania do wstawienia. */ getFullSentences() { throw new Error('Method is not implemented.'); } /** * Powitania. */ getWelcomes() { throw new Error('Method is not implemented.'); } /** * Pożegnania. */ getFarewells() { throw new Error('Method is not implemented.'); } /** * Prawdopodobieństwo, że po dotarciu do miejsca, w którym można dodać nowe słowo, * zostanie ono wstawione. * 0 oznacza 0% szansy, 100 oznacza 100% szansy. */ getProbabilityOfAddingNewWord() { throw new Error('Method is not implemented.'); } /** * Prawdopodobieństwo, że po dotarciu do miejsca, w którym można dodać nowe zdanie, * zostanie ono wstawione. * 0 oznacza 0% szansy, 100 oznacza 100% szansy. */ getProbabilityOfAddingNewSentence() { throw new Error('Method is not implemented.'); } /** * Lista tłumaczeń. * Każdy element listy składa się z kilku informacji: * * [słowo do znalezienia, funkcja zamieniająca słowo] * * Funkcja zamieniająca słowo przyjmuje jako parametr tekst do przetłumaczenia * oraz instancję translatora. * * Standardową implementacją funkcji jest zamiana poszczególnych liter w słowie. * Dla przykładu, jeśli element poniższej listy będzie wyglądał tak: * * ["Cześć", function(str, instane) { * return instance.replaceWithCasing(str, [["ś", "si"], ["ć", "ci"]]) * }] * * W tej sytuacji każde wystąpienie litery "ś" zostanie zmienione na "si", a każde * wystąpienie litery "ć" zostanie zmienione na "ci", co da nam jako wynik "czesici" * (tak, to cudny przykład). * * Użycie metody replaceWithCasing() pozwala na uporanie się z możliwością otrzymania * stringa z różnymi wielkościami liter. Dzięki temu przetłumaczone zostaną wszelkie * możliwe opcje: * - Cześć * - cześć * - cZeŚĆ * - CZEŚĆ * - itd. */ getTranslations() { throw new Error('Method is not implemented.'); } getCorrectWelcomeForTime(date) { if (date.getHours() >= 19 || (date.getHours() >= 0 && date.getHours() <= 4)) { return "dobry wieczór"; } else { return "dzień dobry"; } } swapPlaceholders(textArray) { for (let i = 0; i < this.welcomeSwaps.length; i++) { textArray = this.welcomeSwaps[i].swap(textArray); } return textArray; } getTimeAsString(date) { // https://stackoverflow.com/a/12230363/3470545 return ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2); } getDateAsString(date) { let month = ''; switch (date.getMonth()) { case 0: month = "stycznia"; break; case 1: month = "lutego"; break; case 2: month = "marca"; break; case 3: month = "kwietnia"; break; case 4: month = "maja"; break; case 5: month = "czerwca"; break; case 6: month = "lipca"; break; case 7: month = "sierpnia"; break; case 8: month = "września"; break; case 9: month = "października"; break; case 10: month = "listopada"; break; case 11: month = "grudnia"; break; } return date.getDate() + " " + month; } getDayOfWeek(date) { switch (date.getDay()) { case 0: return "niedzielę"; case 1: return "poniedziałek"; case 2: return "wtorek"; case 3: return "środę"; case 4: return "czwartek"; case 5: return "piątek"; case 6: return "sobotę"; default: return "chuj wie co"; } } } // Merged from __modules__\PersonMajor.js class PersonMajor extends Person { constructor() { super('Major Wojciech Suchodoski'); } getWords() { return this.swapPlaceholders(JSON.parse(GM_getResourceText("majorWordsJson")).words); } getFullSentences() { return this.swapPlaceholders(JSON.parse(GM_getResourceText("majorSentencesJson")).sentences); } getWelcomes() { return this.swapPlaceholders(JSON.parse(GM_getResourceText("majorWelcomesJson")).welcomes); } getFarewells() { return this.swapPlaceholders(JSON.parse(GM_getResourceText("majorFarewellsJson")).farewells); } getTranslations() { return JSON.parse(GM_getResourceText("majorTranslationsJson")).translations; } getProbabilityOfAddingNewWord() { return 35; } getProbabilityOfAddingNewSentence() { return 30; } } // Merged from __modules__\PersonKonon.js class PersonKonon extends Person { constructor() { super('Krzysztof Kononowicz'); } getWords() { return this.swapPlaceholders(JSON.parse(GM_getResourceText("kononWordsJson")).words); } getFullSentences() { return this.swapPlaceholders(JSON.parse(GM_getResourceText("kononSentencesJson")).sentences); } getWelcomes() { return this.swapPlaceholders(JSON.parse(GM_getResourceText("kononWelcomesJson")).welcomes); } getFarewells() { return this.swapPlaceholders(JSON.parse(GM_getResourceText("kononFarewellsJson")).farewells); } getTranslations() { return JSON.parse(GM_getResourceText("kononTranslationsJson")).translations; } getProbabilityOfAddingNewWord() { return 1; } getProbabilityOfAddingNewSentence() { return 40; } getCorrectWelcomeForTime(date) { let welcome = super.getCorrectWelcomeForTime(date); welcome = welcome[0].toUpperCase() + welcome.substr(1); return welcome + " państwu"; } } // Merged from __modules__\Configuration.Functional.js /** * Tłumaczymy? */ const TRANSLATE = true; /** * Wstawiamy pełne zdania? */ const ADD_SENTENCES = true; /** * Wstawiamy spójniki? */ const ADD_WORDS = true; /** * Wstawiamy powitanie? */ const ADD_WELCOME = true; /** * Wstawiamy pożegnanie? */ const ADD_FAREWELL = true; /** * Fragment wyrażenia regularnego dla wyszukiwania liter. */ const REGEX_LETTERS = "a-zA-ZąćęłńóśźżĄĆĘŁŃÓŚŹŻ"; // Merged from __modules__\Translator.js /** * Translator. */ class Translator { constructor(translations) { this.translations = translations; } /** * Podmienia podane stringi w tekście, dodatkowo podmieniając wersje lowercase * i uppercase podanych stringów. * @param {string} str String do zmiany. * @param {string} originalWord Oryginalne słowo do zamiany. * @param {string} findReplace Dane zmiany. * @param {TranslationType} translationType Określa typ tłumaczenia. * @param {boolean} matchWholeWord Czy wykonać tłumaczenie tylko w przypadku znalezienia całego słowa? */ replaceWithCasing(str, originalWord, findReplace, translationType = TranslationType.ANY, matchWholeWord = false) { if (matchWholeWord && str.toLowerCase() != originalWord.toLowerCase()) { return str; } let indexSearchResult = this.findIndex(str, originalWord); let index = indexSearchResult[0]; if (index == -1) { return str; } if (translationType == TranslationType.BEGIN_ONLY && index > 0) { return str; } if (translationType == TranslationType.INSIDE_ONLY && (index == 0 || index + originalWord.length == str.length)) { return str; } if (translationType == TranslationType.END_ONLY && index + originalWord.length != str.length) { return str; } let swapped = originalWord; let find = findReplace[0]; let replace = findReplace[1]; swapped = this.replaceExact(swapped, find, replace); swapped = this.replaceExact(swapped, find.toLowerCase(), replace.toLowerCase()); swapped = this.replaceExact(swapped, find.toUpperCase(), replace.toUpperCase()); if (indexSearchResult[1] == TranslationCapitalizationType.LOWERCASE) { swapped = swapped.toLowerCase(); } else if (indexSearchResult[1] == TranslationCapitalizationType.UPPERCASE) { swapped = swapped.toUpperCase(); } else if (indexSearchResult[1] == TranslationCapitalizationType.TITLECASE) { swapped = this.capitalizeFirstLetter(swapped); } return str.substring(0, index) + swapped + str.substring(index + originalWord.length); } /** * Wyszukuje indeks wystąpienia podanego tekstu w innym tekście. * Sprawdza różne możliwości wielkości liter. * @param {string} str Tekst do przeszukania. * @param {string} originalWord Tekst do znalezienia. * @returns Lista elementów - pierwszy to indeks, drugi określa sposób, * w jaki znaleziono tekst: N = bez zmian, L = lowercase, U = uppercase, * ? = nie znaleziono. */ findIndex(str, originalWord) { let index = str.indexOf(originalWord); if (index != -1) { return [index, TranslationCapitalizationType.NOT_FOUND]; } index = str.indexOf(originalWord.toLowerCase()); if (index != -1) { return [index, TranslationCapitalizationType.LOWERCASE]; } index = str.indexOf(originalWord.toUpperCase()); if (index != -1) { return [index, TranslationCapitalizationType.UPPERCASE]; } index = str.indexOf(this.capitalizeFirstLetter(originalWord)); if (index != -1) { return [index, TranslationCapitalizationType.TITLECASE]; } return [index, TranslationCapitalizationType.UNKNOWN]; } /** * Zmienia pierwszą literę tekstu na wielką. * @param {string} str Tekst do zmiany. */ capitalizeFirstLetter(str) { return str[0].toLocaleUpperCase() + str.substring(1); } /** * Dokonuje dokładną zamianę, bez rozróżnienia na wielkość liter. * @param {string} str String do zmiany. * @param {string} find String do znalezienia. * @param {string} replaceWord Tekst do wstawienia. */ replaceExact(str, find, replaceWord) { return str.replace(new RegExp(find, "g"), replaceWord); } /** * Wykonuje tłumaczenie. * @param {array} textArray Tablica tekstu do przetłumaczenia. */ translate(textArray) { textArray.forEach(function (text) { this.translations.forEach(function (translation) { let sourceWord = translation["sourceWord"]; if (!new RegExp(translation["sourceWord"], "i").test(text.getText())) { return; } let translatedWord = sourceWord; translation["operations"].forEach(function (operation) { if (operation["method"] == "replaceWithCasing") { let stringToReplace = operation["stringToReplace"]; let replacementString = operation["replacementString"]; let type = TranslationType.ANY; let matchWholeWord = false; if ("type" in operation) { switch (operation["type"]) { case "any": type = TranslationType.ANY; break; case "begin_only": type = TranslationType.BEGIN_ONLY; break; case "inside_only": type = TranslationType.INSIDE_ONLY; break; case "end_only": type = TranslationType.END_ONLY; break; } } if ("matchWholeWord" in operation) { matchWholeWord = operation["matchWholeWord"]; } text.setText(this.replaceWithCasing(text.getText(), translatedWord, [stringToReplace, replacementString], type, matchWholeWord)); translatedWord = text.getText(); } }.bind(this)); }.bind(this)); }.bind(this)); return textArray; } } // Merged from __modules__\Generator.js /** * Generator majorowych wstawek w tekście. */ class Generator { /** * Tworzy nową instancję. * @param {Person} person Osoba. * @param {string} knownAbbreviationsJson Znane skróty. * @param {string} tentativeEndsJson Niepewne końcówki. */ constructor(person, knownAbbreviationsJson, tentativeEndsJson) { this.person = person; this.wordsArray = person.getWords(); this.sentencesArray = person.getFullSentences(); this.textSplitters = [' ', '\n']; this.knownAbbreviations = JSON.parse(knownAbbreviationsJson).abbreviations; this.tentativeEnds = JSON.parse(tentativeEndsJson).ends; this.createWordsQueue(); this.createSentencesQueue(); } /** * Tworzy kolejkę spójników. */ createWordsQueue() { this.wordsQueue = this.wordsArray.slice(0); this.shuffleArray(this.wordsQueue); } /** * Tworzy kolejkę zdań. */ createSentencesQueue() { this.sentencesQueue = this.sentencesArray.slice(0); this.shuffleArray(this.sentencesQueue); } /** * Miesza elementy w tablicy (generuje losową permutację). * Kod z https://stackoverflow.com/a/12646864/3470545 (a co, ja też jestem * czasem leniwy). * @param {array} array Tablica do wymieszania. */ shuffleArray(array) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } } /** * Losowo wstawia słowa / zdania do tekstu. * @param {string} text Tekst do zmiany. * @param {boolean} addWelcomeNow Czy wstawiamy powitanie na początku podanego tekstu? * @param {boolean} addFarewellNow Czy wstawiamy pożegnanie na końcu podanego tekstu? * @param {string} conjunctionBeforeBlacklist Czarna lista słów, przed którymi nie można wstawić spójnika. * @param {string} conjunctionAfterBlacklistJson Czarna lista słów, po których nie można wstawić spójnika. */ generate(text, addWelcomeNow, addFarewellNow, conjunctionBeforeBlacklistJson, conjunctionAfterBlacklistJson) { let splittedText = this.splitText(text, this.textSplitters); let conjunctionBeforeBlacklist = JSON.parse(conjunctionBeforeBlacklistJson).blacklist; let conjunctionAfterBlacklist = JSON.parse(conjunctionAfterBlacklistJson).blacklist; this.joinNonSplittableParts(splittedText); this.majorizeTextArray(splittedText, conjunctionBeforeBlacklist, conjunctionAfterBlacklist); if (addWelcomeNow && ADD_WELCOME) { this.addWelcome(splittedText, this.person.getWelcomes()); } if (addFarewellNow && ADD_FAREWELL) { this.addFarewell(splittedText, this.person.getFarewells()); } if (TRANSLATE) { this.translate(splittedText); } return this.joinStringArray(splittedText); } /** * Tłumaczy podaną tablicę tekstu. * @param {array} textArray Tablica ze słowami do przetłumaczenia. */ translate(textArray) { textArray = new Translator(this.person.getTranslations()).translate(textArray); } /** * Dzieli tekst w miejcach wystąpienia podanych znaków. * @param {string} text Tekst do podzielenia. * @param {array} splittersArray Tablica z tekstami dzielącymi. */ splitText(text, splittersArray) { if (text == null) { return []; } let result = [new SplittedTextPart(text, '')]; splittersArray.forEach(function (splitter) { result = this.splitTextWith(result, splitter); }.bind(this)); return result; } /** * Dzieli elementy na tablicy tekstowej w miejscach wystąpienia podanego tekstu. * @param {string} textArray Tablica z tekstem. * @param {string} splitter Tekst dzielący. */ splitTextWith(textArray, splitter) { let newArray = []; textArray.forEach(splittedTextPart => { let splitted = splittedTextPart.getText().split(splitter); if (splitted.length <= 1) { newArray.push(splittedTextPart); } else { splitted.forEach(element => newArray.push(new SplittedTextPart(element, splitter))); newArray[newArray.length - 1].setSplitter(splittedTextPart.getSplitter()); } }); if (newArray.length > 0) { newArray[newArray.length - 1].removeSplitter(); } return newArray; } /** * Dokonuje majoryzacji tekstu. * @param {array} textArray Tablica ze słowami do majoryzacji. * @param {array} conjunctionBeforeBlacklist Czarna lista słów, przed którymi nie można wstawić spójnika. * @param {array} conjunctionAfterBlacklist Czarna lista słów, po których nie można wstawić spójnika. */ majorizeTextArray(textArray, conjunctionBeforeBlacklist, conjunctionAfterBlacklist) { for (let i = 1; i <= textArray.length; i++) { if (i < textArray.length && (this.isWhitespaceOnly(textArray[i].getText()) || this.isEndingWithTentativeText(textArray[i].getText(), this.tentativeEnds))) { continue; } let addNewSentence = false; let addNewWord = false; addNewSentence = this.shouldAddNewSentence(this.person.getProbabilityOfAddingNewSentence()) && this.isEndOfSentence(textArray[i - 1].getText()); if (!addNewSentence) { addNewWord = this.shouldAddNewWord(this.person.getProbabilityOfAddingNewWord()); } if (ADD_SENTENCES && addNewSentence) { if (this.sentencesQueue.length == 0) { this.createSentencesQueue(); } let addedWordsCount = this.addNewSentence(textArray, i, this.sentencesQueue); i += addedWordsCount; } else if (ADD_WORDS && addNewWord) { if (this.wordsQueue.length == 0) { this.createWordsQueue(); } if (!this.canAddWordBetweenWords(textArray, i, conjunctionAfterBlacklist, conjunctionBeforeBlacklist)) { continue; } let addedWordsCount = this.addNewWord(textArray, i, this.wordsQueue); this.addCommaBeforePositionIfNecessary(textArray, i); i += addedWordsCount; } } } /** * Sprawdza, czy w podanym miejscu można wstawić nowe słowo, biorąc pod uwagę * słowa znajdujące się bezpośrednio po i przed obecnie wstawianym. * @param {array} textArray Tablica ze słowami do majoryzacji. * @param {number} position Pozycja nowego słowa. * @param {array} conjunctionBeforeBlacklist Czarna lista słów, przed którymi nie można wstawić spójnika. * @param {array} conjunctionAfterBlacklist Czarna lista słów, po których nie można wstawić spójnika. */ canAddWordBetweenWords(textArray, position, conjunctionAfterBlacklist, conjunctionBeforeBlacklist) { if (position == 0 || position >= textArray.length) { return false; } return this.canAddConjunctionAfter(textArray[position - 1].getText(), conjunctionAfterBlacklist) && this.canAddConjunctionBefore(textArray[position].getText(), conjunctionBeforeBlacklist); } /** * Sprawdza, czy podany tekst składa się tylko z białych znaków. * @param {string} str Tekst do sprawdzenia. */ isWhitespaceOnly(str) { return str == "" || /^\s*$/.test(str); } /** * Biorąc pod uwagę prawdopodobieństwo dodania nowego słowa, generuje liczbę informującą o tym, * czy zostanie ono dodane. * @param {number} probabilityOfNewWord Prawdopodobieństwo dodania nowego słowa. */ shouldAddNewWord(probabilityOfNewWord) { return _.random(0, 100, false) < probabilityOfNewWord; } /** * Biorąc pod uwagę prawdopodobieństwo dodania nowego zdania, generuje liczbę informującą o tym, * czy zostanie ono dodane. * @param {number} probabilityOfNewSentence Prawdopodobieństwo dodania nowego zdania. */ shouldAddNewSentence(probabilityOfNewSentence) { return _.random(0, 100, false) < probabilityOfNewSentence; } /** * Biorąc pod uwagę prawdopodobieństwo dodania nowej czynności, generuje liczbę informującą o tym, * czy zostanie ona dodana. * @param {number} probabilityOfNewAction Prawdopodobieństwo dodania nowej czynności. */ shouldAddNewAction(probabilityOfNewAction) { return _.random(0, 100, false) < probabilityOfNewAction; } /** * Dodaje losowe powitanie. * @param {array} textArray Tablica ze słowami. * @param {array} welcomes Tablica z dostępnymi powitaniami. */ addWelcome(textArray, welcomes) { let splittedWelcome = this.splitText(_.sample(welcomes), this.textSplitters); splittedWelcome[splittedWelcome.length - 1].setSplitter(' '); Array.prototype.unshift.apply(textArray, [].concat(splittedWelcome)); } /** * Dodaje losowe pożegnanie. * @param {array} textArray Tablica ze słowami. * @param {array} farewells Tablica z dostępnymi pożegnaniami. */ addFarewell(textArray, farewells) { textArray[textArray.length - 1].setSplitter(' '); let splittedFarewell = this.splitText(_.sample(farewells), this.textSplitters); splittedFarewell[splittedFarewell.length - 1].setSplitter(' '); Array.prototype.push.apply(textArray, [].concat(splittedFarewell)); } /** * Wstawia losowe zdanie na podanej pozycji. * @param {array} textArray Tablica ze słowami. * @param {number} position Pozycja do wstawienia nowego zdania. * @param {array} sentencesQueue Kolejka z dostępnymi zdaniami. * @returns Ilość słów w dodanej tablicy. */ addNewSentence(textArray, position, sentencesQueue) { if (position == textArray.length) { textArray[position - 1].setSplitter(' '); } let splittedSentence = this.splitText(sentencesQueue.shift(), this.textSplitters); splittedSentence[splittedSentence.length - 1].setSplitter(' '); Array.prototype.splice.apply(textArray, [position, 0].concat(splittedSentence)); return splittedSentence.length; } /** * Wstawia nowe losowe słowo na podanej pozycji i dopisuje przecinek. * @param {array} textArray Tablica ze słowami. * @param {number} position Pozycja do wstawienia nowego zdania. * @param {array} wordsQueue Kolejka z dostępnymi słowami. * @returns Ilość słów w dodanej tablicy. */ addNewWord(textArray, position, wordsQueue) { let splittedWord = this.splitText(wordsQueue.shift() + ",", this.textSplitters); splittedWord[splittedWord.length - 1].setSplitter(' '); Array.prototype.splice.apply(textArray, [position, 0].concat(splittedWord)); return splittedWord.length; } /** * Sprawdza, czy można wstawić spójnik przed podanym tekstem. * @param {string} text Tekst do sprawdzenia. * @param {array} conjunctionBeforeBlacklist Czarna lista słów, przed którymi nie można wstawić spójnika. */ canAddConjunctionBefore(text, conjunctionBeforeBlacklist = []) { return !/[\[|\(|\{|\-|–].*/.test(text) && !this.isConjunctionOnBlacklist(text, conjunctionBeforeBlacklist); } /** * Sprawdza, czy można wstawić spójnik za podanym tekstem. * @param {string} text Tekst do sprawdzenia. * @param {array} conjunctionBeforeBlacklist Czarna lista słów, po których nie można wstawić spójnika. */ canAddConjunctionAfter(text, conjunctionAfterBlacklist = []) { return !this.isWhitespaceOnly(text) && !this.isEndOfSentence(text) && !/.*[;|:|\-|–|\)\]\}]$/.test(text) && !this.isConjunctionOnBlacklist(text, conjunctionAfterBlacklist) && !this.isEndingWithTentativeText(text, this.tentativeEnds); } /** * Sprawdza, czy podany tekst jest na czarnej liście słów. * @param {string} text Tekst do sprawdzenia. */ isConjunctionOnBlacklist(text, blacklist) { for (let i = 0; i < blacklist.length; i++) { if (new RegExp('^[ "\'\\(\\[\\{]*(' + blacklist[i].toLowerCase() + ')$').test(text.toLowerCase())) { return true; } } return false; } /** * Dodaje przecinek przed podaną pozycję, o ile jest to potrzebne. * @param {array} textArray Tablica ze słowami. * @param {number} position Pozycja do sprawdzenia. */ addCommaBeforePositionIfNecessary(textArray, position) { if (position > 0 && position <= textArray.length && !textArray[position - 1].getText().endsWith(",")) { textArray[position - 1].setText(textArray[position - 1].getText() + ","); } } addSpaceIfNecessary(textArray, position) { if (position > 0 && position <= textArray.length && textArray[position - 1].getSplitter() == null) { textArray[position - 1].setText(textArray[position - 1].getText() + " "); } } /** * Łączy te części tekstu, które nie powinny być podzielone. * @param {array} textArray Tablica z tekstem. */ joinNonSplittableParts(textArray) { let nonSplitabbleParts = [ "-", "–", "" ]; for (let i = 0; i < textArray.length; i++) { let startIndex = -1; if (nonSplitabbleParts.includes(textArray[i].getText())) { startIndex = i; } while (i < textArray.length && nonSplitabbleParts.includes(textArray[i].getText())) { // Znajdujemy następny dozwolony znak. i++; } if (i == textArray.length) { i--; } if (startIndex != -1) { let slice = textArray.slice(startIndex, i + 1); let newElement = ''; let lastSplitter = ''; slice.forEach(function (element) { newElement += element.getJoined(); lastSplitter = element.getSplitter(); }); if (lastSplitter != null) { newElement = newElement.slice(0, -lastSplitter.length); } textArray.splice(startIndex, i - startIndex); textArray[startIndex].setText(newElement); textArray[startIndex].setSplitter(lastSplitter); i -= (i - startIndex); } } } /** * Łączy tablicę tekstu do stringa, używając podanego znaku lub tekstu do połączenia * kolejnych elementów. * @param {array} textArray Tablica ze słowami. */ joinStringArray(textArray) { if (textArray == null) { return ''; } let str = ""; let lastSplitter = ''; textArray.forEach(element => { str += element.getJoined(); lastSplitter = element.getSplitter(); }); if (lastSplitter == null) { return str; } return str.length > 0 && lastSplitter.length > 0 ? str.slice(0, -lastSplitter.length) : str; } /** * Określa, czy podany string jest końcem zdania. * @param {string} str Tekst do sprawdzenia. */ isEndOfSentence(str) { if (this.isAbbreviation(str, this.knownAbbreviations)) { return false; } let endOfSentence = new RegExp('[' + REGEX_LETTERS + '0-9 \\[\\{\\(\\]\\}\\)"\']+(\\.|[!|?]+)$').test(str); if (endOfSentence) { return true; } if (this.isPunctuationMarksOnlyEndOfSentence(str)) { return true; } return false; } /** * Sprawdza, czy podany tekst zawiera tylko znaki interpunkcyjne, które określają koniec zdania, * np. kropka, wykrzyknik (lub więcej) itd. * @param {string} str Tekst do sprawdzenia. */ isPunctuationMarksOnlyEndOfSentence(str) { if (str.length == 0) { return false; } if (str.length == 1 && str[0] == '.') { return true; } for (let i = 0; i < str.length; i++) { if (str[i] != '!' && str[i] != '?') { return false; } } return true; } /** * Sprawdza, czy podany tekst jest znanym skrótem. * @param {string} str Tekst do sprawdzenia. * @param {array} abbreviations Tablica znanych skrótów. */ isAbbreviation(str, abbreviations) { for (let i = 0; i < abbreviations.length; i++) { let abbreviation = abbreviations[i]; if (new RegExp('^[ "\'\\(\\[\\{]*(' + abbreviation.toLowerCase() + ')$').test(str.toLowerCase())) { return true; } } return false; } /** * Sprawdza, czy podany tekst kończy się znakami, które nie dają pewności * pod względem tego, czy mamy do czynienia z końcem zdania, czy nie. * @param {string} str Tekst do sprawdzenia. * @param {array} tentativeEndsArray Tablica niepewnych zakończeń. */ isEndingWithTentativeText(str, tentativeEndsArray) { for (let i = 0; i < tentativeEndsArray.length; i++) { if (str.toLowerCase().endsWith(tentativeEndsArray[i])) { return true; } } return false; } } // Merged from __modules__\WebsiteMajorizator.js /** * Majoryzator stron internetowych. */ class WebsiteMajorizator { /** * Tworzy nową instancję. * @param {Person} person Osoba. */ constructor(person) { this.nodesToMajorize = []; this.person = person; } /** * Sprawdza, czy dzieci podanego węzła mogą * zostać poddane edycji. * @param {Node} node Węzeł do sprawdzenia. */ areNodeChildrenMajorizable(node) { let tagsToOmmit = [ "SCRIPT", "STYLE" ]; return node != null && !tagsToOmmit.includes(node.tagName) && node.nodeType == 1; } /** * Sprawdza, czy węzeł może zostać poddany modyfikacji. * @param {Node} node Węzeł do sprawdzenia. */ isNodeEditable(node) { if (node == null || typeof node != "object") { return false; } if (node.data === undefined || node.data == null || node.data == "" || !new RegExp('[' + REGEX_LETTERS + ']+').test(node.data)) { return false; } if (node.nodeType === undefined || node.nodeType != 3) { return false; } if (node.childNodes === undefined || typeof node.childNodes != "object") { return false; } return true; } /** * Dokonuje rekursywnej majoryzacji podanego węzła ze strony internetowej. * @param {Node} node Węzeł, dla którego wykonujemy majoryzację. */ findNodesToMajorize(node) { if (this.isNodeEditable(node)) { this.nodesToMajorize.push(node); } if (this.areNodeChildrenMajorizable(node)) { node.childNodes.forEach(function (child) { this.findNodesToMajorize(child); }.bind(this)); } } /** * Majoryzuje znalezione węzły. * @param {Generator} generator Instanacja Generatora. * @param {string} conjunctionBeforeBlacklistJson Czarna lista słów, po których nie można wstawić spójnika. * @param {string} conjunctionAfterBlacklistJson Czarna lista słów, przed którymi nie można wstawić spójnika. */ majorizeNodes(generator, conjunctionBeforeBlacklistJson, conjunctionAfterBlacklistJson) { for (let i = 0; i < this.nodesToMajorize.length; i++) { let node = this.nodesToMajorize[i]; node.data = generator.generate(node.data, i == 0, i == this.nodesToMajorize.length - 1, conjunctionBeforeBlacklistJson, conjunctionAfterBlacklistJson); } } /** * Uruchamia majoryzację całej strony. */ majorizeWholeWebsite(conjunctionBeforeBlacklistJson, conjunctionAfterBlacklistJson, knownAbbreviationsJson, tentativeEndsJson) { this.findNodesToMajorize(document.body); this.majorizeNodes(new Generator(this.person, knownAbbreviationsJson, tentativeEndsJson), conjunctionBeforeBlacklistJson, conjunctionAfterBlacklistJson); } } // Merged from __modules__\Launcher.js class Launcher { addCss() { let style = document.createElement("style"); style.innerHTML = GM_getResourceText("css"); document.body.appendChild(style); } createButton(person, text, buttonId) { let button = document.createElement("input"); button.type = "button"; button.value = text; button.classList.add("majoryzator-button"); button.id = buttonId; button.onclick = () => new WebsiteMajorizator(person).majorizeWholeWebsite( GM_getResourceText("conjunctionBeforeBlacklistJson"), GM_getResourceText("conjunctionAfterBlacklistJson"), GM_getResourceText("knownAbbreviationsJson"), GM_getResourceText("tentativeEndsJson") ); document.body.appendChild(button); } launch() { this.addCss(); this.createButton(new PersonMajor(), "M", "majoryzator-suchodolski"); this.createButton(new PersonKonon(), "K", "majoryzator-kononowicz"); } } new Launcher().launch(); // Merged from __tampermonkey__\Footer.tampermonkey })();