Advertisement
kippo77

Untitled

Feb 16th, 2019
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 32.83 KB | None | 0 0
  1. //META{"name":"SpellCheck"}*//
  2.  
  3. class SpellCheck {
  4. initConstructor () {
  5. this.languages = {};
  6. this.langDictionary = [];
  7. this.dictionary = [];
  8.  
  9. this.spellCheckContextEntryMarkup =
  10. `<div class="${BDFDB.disCN.contextmenuitemgroup}">
  11. <div class="${BDFDB.disCN.contextmenuitem} similarwords-item ${BDFDB.disCN.contextmenuitemsubmenu}">
  12. <span>REPLACE_context_similarwords_text</span>
  13. <div class="${BDFDB.disCN.contextmenuhint}"></div>
  14. </div>
  15. <div class="${BDFDB.disCN.contextmenuitem} spellcheck-item">
  16. <span>REPLACE_context_spellcheck_text</span>
  17. <div class="${BDFDB.disCN.contextmenuhint}"></div>
  18. </div>
  19. </div>`;
  20.  
  21. this.similarWordsContextSubMenuMarkup =
  22. `<div class="${BDFDB.disCN.contextmenu} spellcheck-submenu">
  23. <div class="${BDFDB.disCN.contextmenuitem} nosimilars-item">
  24. <span>REPLACE_similarwordssubmenu_none_text</span>
  25. <div class="${BDFDB.disCN.contextmenuhint}"></div>
  26. </div>
  27. </div>`;
  28.  
  29. this.spellCheckLayerMarkup =
  30. `<div class="spellcheck-overlay" style="position:absolute !important; pointer-events:none !important; background:transparent !important; color:transparent !important;"></div>`;
  31.  
  32. this.css =
  33. `.spellcheck-overlay {
  34. display: inline-block;
  35. font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
  36. white-space: pre-wrap !important;
  37. word-wrap: break-word !important;
  38. overflow-x: hidden !important;
  39. overflow-y: scroll !important;
  40. }
  41. .spellcheck-overlay::-webkit-scrollbar,
  42. .spellcheck-overlay::-webkit-scrollbar-button,
  43. .spellcheck-overlay::-webkit-scrollbar-track,
  44. .spellcheck-overlay::-webkit-scrollbar-track-piece,
  45. .spellcheck-overlay::-webkit-scrollbar-thumb,
  46. .spellcheck-overlay::-webkit-scrollbar-corner,
  47. .spellcheck-overlay::-webkit-resizer {
  48. visibility: hidden !important;
  49. }
  50. .spellcheck-overlay .spelling-error {
  51. background-image: url('data:image/png;base64,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');
  52. background-repeat: repeat-x;
  53. background-position: bottom;
  54. }`;
  55.  
  56.  
  57. this.defaults = {
  58. settings: {
  59. disableDiscordSpellcheck: {value:true, description:"Disable Discord's internal Spellcheck:"}
  60. },
  61. choices: {
  62. dictionaryLanguage: {value:"en", description:"Dictionay Language:"}
  63. },
  64. amounts: {
  65. maxSimilarAmount: {value:6, description:"Maximal Amount of suggested Words:"}
  66. }
  67. };
  68. }
  69.  
  70. getName () {return "SpellCheck";}
  71.  
  72. getDescription () {return "Adds a spellcheck to all textareas. Select a word and rightclick it to add it to your dictionary.";}
  73.  
  74. getVersion () {return "1.2.6";}
  75.  
  76. getAuthor () {return "DevilBro";}
  77.  
  78. getSettingsPanel () {
  79. if (!this.started || typeof BDFDB !== "object") return;
  80. var settings = BDFDB.getAllData(this, "settings");
  81. var choices = BDFDB.getAllData(this, "choices");
  82. var amounts = BDFDB.getAllData(this, "amounts");
  83. var settingshtml = `<div class="${this.getName()}-settings DevilBro-settings"><div class="${BDFDB.disCNS.titledefault + BDFDB.disCNS.title + BDFDB.disCNS.size18 + BDFDB.disCNS.height24 + BDFDB.disCNS.weightnormal + BDFDB.disCN.marginbottom8}">${this.getName()}</div><div class="DevilBro-settings-inner">`;
  84. for (let key in settings) {
  85. settingshtml += `<div class="${BDFDB.disCNS.flex + BDFDB.disCNS.flex2 + BDFDB.disCNS.horizontal + BDFDB.disCNS.horizontal2 + BDFDB.disCNS.directionrow + BDFDB.disCNS.justifystart + BDFDB.disCNS.aligncenter + BDFDB.disCNS.nowrap + BDFDB.disCN.marginbottom8}" style="flex: 1 1 auto;"><h3 class="${BDFDB.disCNS.titledefault + BDFDB.disCNS.title + BDFDB.disCNS.marginreset + BDFDB.disCNS.weightmedium + BDFDB.disCNS.size16 + BDFDB.disCNS.height24 + BDFDB.disCN.flexchild}" style="flex: 1 1 auto;">${this.defaults.settings[key].description}</h3><div class="${BDFDB.disCNS.flexchild + BDFDB.disCNS.switchenabled + BDFDB.disCNS.switch + BDFDB.disCNS.switchvalue + BDFDB.disCNS.switchsizedefault + BDFDB.disCNS.switchsize + BDFDB.disCN.switchthemedefault}" style="flex: 0 0 auto;"><input type="checkbox" value="${key}" class="${BDFDB.disCNS.switchinnerenabled + BDFDB.disCN.switchinner}"${settings[key] ? " checked" : ""}></div></div>`;
  86. }
  87. for (let key in choices) {
  88. settingshtml += `<div class="${BDFDB.disCNS.flex + BDFDB.disCNS.flex2 + BDFDB.disCNS.horizontal + BDFDB.disCNS.horizontal2 + BDFDB.disCNS.directionrow + BDFDB.disCNS.justifystart + BDFDB.disCNS.aligncenter + BDFDB.disCNS.nowrap + BDFDB.disCN.marginbottom8}" style="flex: 1 1 auto;"><h3 class="${BDFDB.disCNS.titledefault + BDFDB.disCNS.title + BDFDB.disCNS.weightmedium + BDFDB.disCNS.size16 + BDFDB.disCN.flexchild}" style="flex: 0 0 50%;">${this.defaults.choices[key].description}</h3><div class="${BDFDB.disCN.selectwrap}" style="flex: 1 1 auto"><div class="${BDFDB.disCNS.select + BDFDB.disCNS.selectsingle + BDFDB.disCN.selecthasvalue}" type="${key}" value="${choices[key]}"><div class="${BDFDB.disCN.selectcontrol}"><div class="${BDFDB.disCNS.flex + BDFDB.disCNS.flex2 + BDFDB.disCNS.horizontal + BDFDB.disCNS.horizontal2 + BDFDB.disCNS.directionrow + BDFDB.disCNS.justifystart + BDFDB.disCNS.alignbaseline + BDFDB.disCNS.nowrap + BDFDB.disCN.selectvalue}" style="flex: 1 1 auto;"><div class="${BDFDB.disCNS.title + BDFDB.disCNS.medium + BDFDB.disCNS.size16 + BDFDB.disCNS.height20 + BDFDB.disCNS.primary + BDFDB.disCN.weightnormal}" style="padding:0;">${this.languages[choices[key]].name}</div></div><span class="${BDFDB.disCN.selectarrowzone}"><span class="${BDFDB.disCN.selectarrow}"></span></span></div></div></div></div>`;
  89. }
  90. for (let key in amounts) {
  91. settingshtml += `<div class="${BDFDB.disCNS.flex + BDFDB.disCNS.flex2 + BDFDB.disCNS.horizontal + BDFDB.disCNS.horizontal2 + BDFDB.disCNS.directionrow + BDFDB.disCNS.justifystart + BDFDB.disCNS.aligncenter + BDFDB.disCNS.nowrap + BDFDB.disCN.marginbottom8}" style="flex: 1 1 auto;"><h3 class="${BDFDB.disCNS.titledefault + BDFDB.disCNS.title + BDFDB.disCNS.weightmedium + BDFDB.disCNS.size16 + BDFDB.disCN.flexchild}" style="flex: 0 0 50%; line-height: 38px;">${this.defaults.amounts[key].description}</h3><div class="${BDFDB.disCN.inputwrapper} inputNumberWrapper ${BDFDB.disCNS.vertical + BDFDB.disCNS.flex + BDFDB.disCNS.directioncolumn}" style="flex: 1 1 auto;"><span class="numberinput-buttons-zone"><span class="numberinput-button-up"></span><span class="numberinput-button-down"></span></span><input type="number" min="0" option="${key}" value="${amounts[key]}" class="${BDFDB.disCNS.inputdefault + BDFDB.disCNS.input + BDFDB.disCN.size16} amountInput"></div></div>`;
  92. }
  93. var ownDictionary = BDFDB.loadData(choices.dictionaryLanguage, this, "owndics") || [];
  94. settingshtml += `<h3 class="${BDFDB.disCNS.titledefault + BDFDB.disCNS.title + BDFDB.disCNS.marginreset + BDFDB.disCNS.weightmedium + BDFDB.disCNS.size16 + BDFDB.disCNS.height24 + BDFDB.disCN.flexchild}" style="flex: 1 1 auto;">Your own Dictionary:</h3><div class="DevilBro-settings-inner-list word-list ${BDFDB.disCN.marginbottom8}">`;
  95. for (let word of ownDictionary) {
  96. settingshtml += `<div class="${BDFDB.disCNS.flex + BDFDB.disCNS.flex2 + BDFDB.disCNS.vertical + BDFDB.disCNS.directionrow + BDFDB.disCNS.justifystart + BDFDB.disCNS.alignstretch + BDFDB.disCNS.nowrap + BDFDB.disCNS.margintop4 + BDFDB.disCNS.marginbottom4 + BDFDB.disCN.hovercard}"><div class="${BDFDB.disCN.hovercardinner}"><div class="${BDFDB.disCNS.description + BDFDB.disCNS.formtext + BDFDB.disCNS.note + BDFDB.disCNS.margintop4 + BDFDB.disCNS.modedefault + BDFDB.disCNS.primary + BDFDB.disCN.ellipsis} entryword">${word}</div></div><div class="${BDFDB.disCN.hovercardbutton} remove-word"></div></div>`;
  97. }
  98. settingshtml += `</div>`;
  99. settingshtml += `</div></div>`;
  100.  
  101. var settingspanel = $(settingshtml)[0];
  102.  
  103. BDFDB.initElements(settingspanel);
  104.  
  105. $(settingspanel)
  106. .on("click", BDFDB.dotCN.switchinner, () => {this.updateSettings(settingspanel);})
  107. .on("click", BDFDB.dotCN.selectcontrol, (e) => {this.openDropdownMenu(settingspanel, e);})
  108. .on("click", ".remove-word", (e) => {this.removeFromOwnDictionary(e);})
  109. .on("input", ".amountInput", (e) => {
  110. var input = parseInt(e.currentTarget.value);
  111. if (!isNaN(input) && input > -1) BDFDB.saveData(e.currentTarget.getAttribute("option"), input, this, "amounts");
  112. });
  113. return settingspanel;
  114. }
  115.  
  116. //legacy
  117. load () {}
  118.  
  119. start () {
  120. var libraryScript = null;
  121. if (typeof BDFDB !== "object" || typeof BDFDB.isLibraryOutdated !== "function" || BDFDB.isLibraryOutdated()) {
  122. libraryScript = document.querySelector('head script[src="https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.js"]');
  123. if (libraryScript) libraryScript.remove();
  124. libraryScript = document.createElement("script");
  125. libraryScript.setAttribute("type", "text/javascript");
  126. libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.js");
  127. document.head.appendChild(libraryScript);
  128. }
  129. this.startTimeout = setTimeout(() => {this.initialize();}, 30000);
  130. if (typeof BDFDB === "object" && typeof BDFDB.isLibraryOutdated === "function") this.initialize();
  131. else libraryScript.addEventListener("load", () => {this.initialize();});
  132. }
  133.  
  134. initialize () {
  135. if (typeof BDFDB === "object") {
  136. BDFDB.loadMessage(this);
  137.  
  138. var observer = null;
  139.  
  140. observer = new MutationObserver((changes, _) => {
  141. changes.forEach(
  142. (change, i) => {
  143. if (change.addedNodes) {
  144. change.addedNodes.forEach((node) => {
  145. if (node.nodeType == 1 && node.className.includes(BDFDB.disCN.contextmenu)) {
  146. this.onContextMenu(node);
  147. }
  148. });
  149. }
  150. }
  151. );
  152. });
  153. BDFDB.addObserver(this, BDFDB.dotCN.appmount, {name:"messageContextObserver",instance:observer}, {childList: true});
  154.  
  155. observer = new MutationObserver((changes, _) => {
  156. changes.forEach(
  157. (change, i) => {
  158. if (change.addedNodes) {
  159. change.addedNodes.forEach((node) => {
  160. if (node && node.tagName && node.querySelector(BDFDB.dotCN.textareainner + ":not(" + BDFDB.dotCN.textareainnerdisabled + ")")) {
  161. this.addSpellCheck(node.querySelector(BDFDB.dotCN.textarea));
  162. }
  163. });
  164. }
  165. }
  166. );
  167. });
  168. BDFDB.addObserver(this, BDFDB.dotCN.appmount, {name:"textareaObserver",instance:observer}, {childList: true, subtree:true});
  169.  
  170. document.querySelectorAll(BDFDB.dotCN.textarea).forEach(textarea => {this.addSpellCheck(textarea);});
  171.  
  172. this.languages = Object.assign({},BDFDB.languages);
  173. this.languages = BDFDB.filterObject(this.languages , (lang) => {return lang.dic == true ? lang : null});
  174.  
  175. this.setDictionary(BDFDB.getData("dictionaryLanguage", this, "choices"));
  176. }
  177. else {
  178. console.error(this.getName() + ": Fatal Error: Could not load BD functions!");
  179. }
  180. }
  181.  
  182. stop () {
  183. if (typeof BDFDB === "object") {
  184. $(".spellcheck-overlay").remove();
  185.  
  186. BDFDB.unloadMessage(this);
  187. }
  188. }
  189.  
  190.  
  191. // begin of own functions
  192.  
  193. changeLanguageStrings () {
  194. this.spellCheckContextEntryMarkup = this.spellCheckContextEntryMarkup.replace("REPLACE_context_spellcheck_text", this.labels.context_spellcheck_text);
  195. this.spellCheckContextEntryMarkup = this.spellCheckContextEntryMarkup.replace("REPLACE_context_similarwords_text", this.labels.context_similarwords_text);
  196.  
  197. this.similarWordsContextSubMenuMarkup = this.similarWordsContextSubMenuMarkup.replace("REPLACE_similarwordssubmenu_none_text", this.labels.similarwordssubmenu_none_text);
  198. }
  199.  
  200. updateSettings (settingspanel) {
  201. var settings = {};
  202. for (var input of settingspanel.querySelectorAll(BDFDB.dotCN.switchinner)) {
  203. settings[input.value] = input.checked;
  204. }
  205. BDFDB.saveAllData(settings, this, "settings");
  206. }
  207.  
  208. onContextMenu (context) {
  209. if (!context || !context.tagName || !context.parentElement || context.querySelector(".spellcheck-item")) return;
  210. var word = window.getSelection().toString();
  211. if (word && BDFDB.getKeyInformation({"node":context, "key":"handleCutItem"}) && this.isWordNotInDictionary(word)) {
  212. var group = $(this.spellCheckContextEntryMarkup);
  213. $(context).append(group)
  214. .on("click", ".spellcheck-item", (e) => {
  215. $(context).hide();
  216. this.addToOwnDictionary(word);
  217. })
  218. .on("mouseenter", ".similarwords-item", (e) => {
  219. this.createContextSubMenu(word, e, context);
  220. });
  221.  
  222. BDFDB.updateContextPosition(context);
  223. }
  224. }
  225.  
  226. createContextSubMenu (word, e, context) {
  227. var similarWordsContextSubMenu = $(this.similarWordsContextSubMenuMarkup);
  228.  
  229. var similarWords = this.getSimilarWords(word.toLowerCase().trim());
  230.  
  231. if (similarWords.length > 0) {
  232. similarWordsContextSubMenu.find(".nosimilars-item").remove();
  233. for (let foundWord of similarWords.sort()) {
  234. similarWordsContextSubMenu.append(`<div value="${foundWord}" class="${BDFDB.disCN.contextmenuitem} similarword-item"><span>${foundWord}</span><div class="${BDFDB.disCN.contextmenuhint}"></div></div>`);
  235. }
  236. }
  237.  
  238. var textarea = window.getSelection().getRangeAt(0).startContainer.querySelector("textarea");
  239. similarWordsContextSubMenu
  240. .on("click", ".similarword-item", (e) => {
  241. $(context).hide();
  242. this.replaceWord(textarea, word, e.currentTarget.getAttribute("value"));
  243. });
  244.  
  245. BDFDB.appendSubMenu(e.currentTarget, similarWordsContextSubMenu);
  246. }
  247.  
  248. replaceWord (textarea, word, replacement) {
  249. textarea.focus();
  250. textarea.selectionStart = 0;
  251. textarea.selectionEnd = textarea.value.length;
  252. if (document.activeElement == textarea) {
  253. var firstLetter = word.charAt(0);
  254. var isCapitalised = firstLetter.toUpperCase() == firstLetter && firstLetter.toLowerCase() != firstLetter;
  255. replacement = isCapitalised ? replacement.charAt(0).toUpperCase() + replacement.slice(1) : replacement;
  256. document.execCommand("insertText", false, textarea.value.replace(new RegExp(word.trim(), "i"), replacement));
  257. $(textarea).trigger("keyup");
  258. }
  259. }
  260.  
  261. addToOwnDictionary (word) {
  262. word = word.split(" ")[0].split("\n")[0].split("\r")[0].split("\t")[0];
  263. if (word) {
  264. var wordlow = word.toLowerCase();
  265. var lang = BDFDB.getData("dictionaryLanguage", this, "choices");
  266. var ownDictionary = BDFDB.loadData(lang, this, "owndics") || [];
  267. if (!ownDictionary.includes(wordlow)) {
  268. ownDictionary.push(wordlow);
  269. BDFDB.saveData(lang, ownDictionary, this, "owndics");
  270. var message = this.labels.toast_wordadd_text ?
  271. this.labels.toast_wordadd_text.replace("${word}", word).replace("${dicname}", this.languages[lang].name) : "";
  272. BDFDB.showToast(message, {type:"success"});
  273. this.dictionary = this.langDictionary.concat(ownDictionary);
  274. }
  275. }
  276. }
  277.  
  278. removeFromOwnDictionary (e) {
  279. var entry = e.currentTarget.parentElement;
  280. var word = entry.querySelector(".entryword").textContent;
  281. entry.remove();
  282. var lang = BDFDB.getData("dictionaryLanguage", this, "choices");
  283. var ownDictionary = BDFDB.loadData(lang, this, "owndics") || [];
  284. BDFDB.removeFromArray(ownDictionary, word);
  285. BDFDB.saveData(lang, ownDictionary, this, "owndics");
  286. this.dictionary = this.langDictionary.concat(ownDictionary);
  287. }
  288.  
  289. openDropdownMenu (settingspanel, e) {
  290. var selectControl = e.currentTarget;
  291. var selectWrap = selectControl.parentElement;
  292.  
  293. if (selectWrap.classList.contains(BDFDB.disCN.selectisopen)) return;
  294.  
  295. selectWrap.classList.add(BDFDB.disCN.selectisopen);
  296. $("li").has(selectWrap).css("overflow", "visible");
  297.  
  298. var type = selectWrap.getAttribute("type");
  299. var selectMenu = this.createDropdownMenu(selectWrap.getAttribute("value"), type);
  300. selectWrap.appendChild(selectMenu);
  301.  
  302. $(selectMenu).on("mousedown." + this.getName(), BDFDB.dotCN.selectoption, (e2) => {
  303. var language = e2.currentTarget.getAttribute("value");
  304. selectWrap.setAttribute("value", language);
  305. selectControl.querySelector(BDFDB.dotCN.title).innerText = this.languages[language].name;
  306. this.setDictionary(language);
  307. BDFDB.saveData(type, language, this, "choices");
  308.  
  309. var listcontainer = settingspanel.querySelector(".word-list");
  310. if (listcontainer) {
  311. var ownDictionary = BDFDB.loadData(language, this, "owndics") || [];
  312. var containerhtml = ``;
  313. for (let word of ownDictionary) {
  314. containerhtml += `<div class="${BDFDB.disCNS.flex + BDFDB.disCNS.flex2 + BDFDB.disCNS.vertical + BDFDB.disCNS.directionrow + BDFDB.disCNS.justifystart + BDFDB.disCNS.alignstretch + BDFDB.disCNS.nowrap + BDFDB.disCNS.margintop4 + BDFDB.disCNS.marginbottom4 + BDFDB.disCN.hovercard}"><div class="${BDFDB.disCN.hovercardinner}"><div class="${BDFDB.disCNS.description + BDFDB.disCNS.formtext + BDFDB.disCNS.note + BDFDB.disCNS.margintop4 + BDFDB.disCNS.modedefault + BDFDB.disCNS.primary + BDFDB.disCN.ellipsis} entryword">${word}</div></div><div class="${BDFDB.disCN.hovercardbutton} remove-word"></div></div>`;
  315. }
  316. listcontainer.innerHTML = containerhtml;
  317. }
  318. });
  319. $(document).on("mousedown.select" + this.getName(), (e2) => {
  320. if (e2.target.parentElement == selectMenu) return;
  321. $(document).off("mousedown.select" + this.getName());
  322. selectMenu.remove();
  323. $("li").has(selectWrap).css("overflow", "auto");
  324. setTimeout(() => {selectWrap.classList.remove(BDFDB.disCN.selectisopen);},100);
  325. });
  326. }
  327.  
  328. createDropdownMenu (choice, type) {
  329. var menuhtml = `<div class="${BDFDB.disCN.selectmenuouter}"><div class="${BDFDB.disCN.selectmenu}">`;
  330. for (var key in this.languages) {
  331. var isSelected = key == choice ? ` ${BDFDB.disCN.selectselected}` : ``;
  332. menuhtml += `<div value="${key}" class="${BDFDB.disCNS.flex + BDFDB.disCNS.flex2 + BDFDB.disCNS.horizontal + BDFDB.disCNS.horizontal2 + BDFDB.disCNS.directionrow + BDFDB.disCNS.justifystart + BDFDB.disCNS.alignbaseline + BDFDB.disCNS.nowrap + BDFDB.disCN.selectoption + isSelected}" style="flex: 1 1 auto; display:flex;"><div class="${BDFDB.disCNS.title + BDFDB.disCNS.medium + BDFDB.disCNS.size16 + BDFDB.disCNS.height20 + BDFDB.disCNS.primary + BDFDB.disCN.weightnormal}" style="flex: 1 1 42%;">${this.languages[key].name}</div></div>`
  333. }
  334. menuhtml += `</div></div>`;
  335. return $(menuhtml)[0];
  336. }
  337.  
  338. addSpellCheck (textarea) {
  339. if (!textarea) return;
  340. var textareaWrap = textarea.parentElement;
  341. if (textareaWrap && !textareaWrap.querySelector(".spellcheck-overlay")) {
  342. var textareaInstance = BDFDB.getOwnerInstance({"node":textarea, "props":["handlePaste","saveCurrentText"], "up":true});
  343. if (textareaInstance) {
  344. var wrapper = $(BDFDB.dotCN.textareawrapall).has(textarea)[0];
  345.  
  346. var updateSpellcheck = () => {
  347. $(spellcheck)
  348. .css("visibility", "hidden")
  349. .html(this.spellCheckText(textarea.value))
  350. .css("left", textarea.getBoundingClientRect().left - wrapper.getBoundingClientRect().left)
  351. .css("margin", $(textarea).css("margin"))
  352. .css("padding", $(textarea).css("padding"))
  353. .css("width", parseInt($(textarea).css("width")) + (parseInt($(textarea).css("height")) >= parseInt($(textarea).css("max-height")) ? 0 : 10))
  354. .css("height", $(textarea).css("height"))
  355. .scrollTop(textarea.scrollTop)
  356. .css("visibility", "visible");
  357. }
  358.  
  359. var spellcheck = $(this.spellCheckLayerMarkup)[0];
  360. textarea.classList.forEach(classname => {spellcheck.classList.add(classname);});
  361. textarea.setAttribute("spellcheck", !BDFDB.getData("disableDiscordSpellcheck", this, "settings"));
  362. $(spellcheck).appendTo(textareaWrap)
  363.  
  364. updateSpellcheck();
  365.  
  366. $(textarea)
  367. .off("keyup." + this.getName()).off("scroll." + this.getName())
  368. .on("keyup." + this.getName(), (e) => {
  369. clearTimeout(textarea.spellchecktimeout);
  370. textarea.spellchecktimeout = setTimeout(() => {updateSpellcheck();},100);
  371. })
  372. .on("scroll." + this.getName(), (e) => {
  373. $(spellcheck).scrollTop(textarea.scrollTop);
  374. });
  375. }
  376. }
  377. }
  378.  
  379. setDictionary (lang) {
  380. this.dictionary = BDFDB.loadData(lang, this, "owndics") || [];
  381. let request = require("request");
  382. request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/SpellCheck/dic/" + lang + ".dic", (error, response, result) => {
  383. if (response) {
  384. this.langDictionary = result.replace(new RegExp("[\\r|\\t]", "g"), "").split("\n");
  385. this.dictionary = this.langDictionary.concat(this.dictionary);
  386. this.dictionary = this.dictionary.map(word => word.toLowerCase());
  387. }
  388. });
  389. }
  390.  
  391. spellCheckText (string) {
  392. var htmlString = [];
  393. string.replace(/[\n]/g, "\n ").split(" ").forEach((word, i) => {
  394. htmlString.push(`<label class="${this.isWordNotInDictionary(word) ? "spelling-error" : "nospelling-error"}">${BDFDB.encodeToHTML(word)}</label>`);
  395. });
  396. return htmlString.join(" ");
  397. }
  398.  
  399. isWordNotInDictionary (word) {
  400. var wordLow = word.toLowerCase();
  401. var wordWithoutSymbols = wordLow.replace(/[0-9\µ\@\$\£\€\¥\¢\²\³\>\<\|\,\;\.\:\_\#\+\*\~\?\¿\\\´\`\}\=\]\)\[\(\{\/\&\%\§\"\!\¡\^\°\n\t\r]/g, "");
  402. return (wordLow.indexOf("http://") != 0 && wordLow.indexOf("https://") != 0 && wordWithoutSymbols && Array.isArray(this.dictionary) && this.dictionary.length > 0 && !this.dictionary.includes(wordLow) && !this.dictionary.includes(wordWithoutSymbols));
  403. }
  404.  
  405.  
  406. getSimilarWords (word) {
  407. var maxAmount = BDFDB.getData("maxSimilarAmount", this, "amounts"), similarWords = [];
  408. if (maxAmount > 0) {
  409. var sameLetterDic = this.dictionary.filter(string => string.indexOf(word.toLowerCase().charAt(0)) == 0 ? string : null);
  410. var similarities = {};
  411. for (let string of sameLetterDic) {
  412. let value = this.wordSimilarity(word, string);
  413. if (!similarities[value]) similarities[value] = [];
  414. similarities[value].push(string);
  415. }
  416. var amount = 0;
  417. for (let value of Object.keys(similarities).sort().reverse()) {
  418. for (let similarWord of similarities[value]) {
  419. if (amount < maxAmount && !similarWords.includes(similarWord)) {
  420. similarWords.push(similarWord);
  421. amount++;
  422. }
  423. if (amount >= maxAmount) break;
  424. }
  425. if (amount >= maxAmount) break;
  426. }
  427. }
  428. return similarWords;
  429. }
  430.  
  431. wordSimilarity (a, b) {
  432. var temp;
  433. if (a.length === 0 || b.length === 0 || a.length - b.length > 3 || b.length - a.length > 3) { return 0; }
  434. if (a.length > b.length) {
  435. temp = a;
  436. a = b;
  437. b = temp;
  438. }
  439. let result = 0;
  440. let row = [...Array(a.length + 1).keys()];
  441. for (let i = 1; i <= b.length; i++) {
  442. result = i;
  443. for (let j = 1; j <= a.length; j++) {
  444. temp = row[j - 1];
  445. row[j - 1] = result;
  446. result = b[i - 1] === a[j - 1] ? temp : Math.min(temp + 1, Math.min(result + 1, row[j] + 1));
  447. }
  448. }
  449. return (b.length - result) / b.length;
  450. }
  451.  
  452. setLabelsByLanguage () {
  453. switch (BDFDB.getDiscordLanguage().id) {
  454. case "hr": //croatian
  455. return {
  456. context_spellcheck_text: "Dodaj u rječnik",
  457. context_similarwords_text: "Pretraga sličnih riječi...",
  458. similarwordssubmenu_none_text: "Nema sličnih riječi",
  459. toast_wordadd_text: "Riječ ${word} dodana je u rječnik ${dicname}."
  460. };
  461. case "da": //danish
  462. return {
  463. context_spellcheck_text: "Tilføj til ordbog",
  464. context_similarwords_text: "Søg lignende ord...",
  465. similarwordssubmenu_none_text: "Ingen lignende ord",
  466. toast_wordadd_text: "Ord ${word} tilføjet til ordbog ${dicname}."
  467. };
  468. case "de": //german
  469. return {
  470. context_spellcheck_text: "Zum Wörterbuch hinzufügen",
  471. context_similarwords_text: "Ähnliche Wörter suchen...",
  472. similarwordssubmenu_none_text: "Keine ähnlichen Wörter",
  473. toast_wordadd_text: "Wort ${word} wurde zum Wörterbuch ${dicname} hinzugefügt."
  474. };
  475. case "es": //spanish
  476. return {
  477. context_spellcheck_text: "Agregar al diccionario",
  478. context_similarwords_text: "Buscar palabras similares...",
  479. similarwordssubmenu_none_text: "No hay palabras similares",
  480. toast_wordadd_text: "Se agregó la palabra ${word} al diccionario ${dicname}."
  481. };
  482. case "fr": //french
  483. return {
  484. context_spellcheck_text: "Ajouter au dictionnaire",
  485. context_similarwords_text: "Chercher des mots similaires...",
  486. similarwordssubmenu_none_text: "Pas de mots similaires",
  487. toast_wordadd_text: "Le mot ${word} a été ajouté au dictionnaire ${dicname}."
  488. };
  489. case "it": //italian
  490. return {
  491. context_spellcheck_text: "Aggiungi al dizionario",
  492. context_similarwords_text: "Cerca parole simili...",
  493. similarwordssubmenu_none_text: "Nessuna parola simile",
  494. toast_wordadd_text: "Parola ${word} aggiunta al dizionario ${dicname}."
  495. };
  496. case "nl": //dutch
  497. return {
  498. context_spellcheck_text: "Toevoegen aan woordenboek",
  499. context_similarwords_text: "Zoek vergelijkbare woorden...",
  500. similarwordssubmenu_none_text: "Geen vergelijkbare woorden",
  501. toast_wordadd_text: "Word ${word} toegevoegd aan woordenboek ${dicname}."
  502. };
  503. case "no": //norwegian
  504. return {
  505. context_spellcheck_text: "Legg til i ordbok",
  506. context_similarwords_text: "Søk lignende ord...",
  507. similarwordssubmenu_none_text: "Ingen lignende ord",
  508. toast_wordadd_text: "Ord ${word} legges til ordbok ${dicname}."
  509. };
  510. case "pl": //polish
  511. return {
  512. context_spellcheck_text: "Dodaj do słownika",
  513. context_similarwords_text: "Wyszukaj podobne słowa...",
  514. similarwordssubmenu_none_text: "Brak podobnych słów",
  515. toast_wordadd_text: "Słowo ${word} dodane do słownika ${dicname}."
  516. };
  517. case "pt-BR": //portuguese (brazil)
  518. return {
  519. context_spellcheck_text: "Adicionar ao dicionário",
  520. context_similarwords_text: "Pesquisar palavras similares...",
  521. similarwordssubmenu_none_text: "Sem palavras semelhantes",
  522. toast_wordadd_text: "Palavra ${word} adicionado ao dicionário ${dicname}."
  523. };
  524. case "fi": //finnish
  525. return {
  526. context_spellcheck_text: "Lisää sanakirjaan",
  527. context_similarwords_text: "Hae samankaltaisia sanoja...",
  528. similarwordssubmenu_none_text: "Ei vastaavia sanoja",
  529. toast_wordadd_text: "Sana ${word} lisättiin sanakirjaan ${dicname}."
  530. };
  531. case "sv": //swedish
  532. return {
  533. context_spellcheck_text: "Lägg till i ordbok",
  534. context_similarwords_text: "Sök liknande ord...",
  535. similarwordssubmenu_none_text: "Inga liknande ord",
  536. toast_wordadd_text: "Ord ${word} läggs till ordbok ${dicname}."
  537. };
  538. case "tr": //turkish
  539. return {
  540. context_spellcheck_text: "Sözlükye Ekle",
  541. context_similarwords_text: "Benzer Kelimeler Ara...",
  542. similarwordssubmenu_none_text: "Benzer kelime yoktur",
  543. toast_wordadd_text: "Sözcük ${word} sözlük ${dicname}'ye eklendi."
  544. };
  545. case "cs": //czech
  546. return {
  547. context_spellcheck_text: "Přidat do slovníku",
  548. context_similarwords_text: "Hledat podobné výrazy...",
  549. similarwordssubmenu_none_text: "Žádné podobné slova",
  550. toast_wordadd_text: "Slovo ${word} bylo přidáno do slovníku ${dicname}."
  551. };
  552. case "bg": //bulgarian
  553. return {
  554. context_spellcheck_text: "Добави в речника",
  555. context_similarwords_text: "Търсене на подобни думи...",
  556. similarwordssubmenu_none_text: "Няма подобни думи",
  557. toast_wordadd_text: "Думата ${word} е добавена към речника ${dicname}."
  558. };
  559. case "ru": //russian
  560. return {
  561. context_spellcheck_text: "Добавить в словарь",
  562. context_similarwords_text: "Поиск похожих слов...",
  563. similarwordssubmenu_none_text: "Нет похожих слов",
  564. toast_wordadd_text: "Слово ${word} добавлено в словарь ${dicname}."
  565. };
  566. case "uk": //ukrainian
  567. return {
  568. context_spellcheck_text: "Додати до словника",
  569. context_similarwords_text: "Шукати схожі слова...",
  570. similarwordssubmenu_none_text: "Немає подібних слів",
  571. toast_wordadd_text: "Словник ${word} додається до словника ${dicname}."
  572. };
  573. case "ja": //japanese
  574. return {
  575. context_spellcheck_text: "辞書に追加",
  576. context_similarwords_text: "類似のワードを検索...",
  577. similarwordssubmenu_none_text: "類似の単語はありません",
  578. toast_wordadd_text: "単語 ${word} が辞書 ${dicname} に追加されました。"
  579. };
  580. case "zh-TW": //chinese (traditional)
  581. return {
  582. context_spellcheck_text: "添加到詞典",
  583. context_similarwords_text: "搜索類似的單詞...",
  584. similarwordssubmenu_none_text: "沒有類似的詞",
  585. toast_wordadd_text: "單詞 ${word} 添加到字典 ${dicname}。"
  586. };
  587. case "ko": //korean
  588. return {
  589. context_spellcheck_text: "사전에 추가",
  590. context_similarwords_text: "비슷한 단어 검색...",
  591. similarwordssubmenu_none_text: "유사한 단어 없음",
  592. toast_wordadd_text: "단어 ${word} 사전 ${dicname} 에 추가되었습니다."
  593. };
  594. default: //default: english
  595. return {
  596. context_spellcheck_text: "Add to Dictionay",
  597. context_similarwords_text: "Search similar Words...",
  598. similarwordssubmenu_none_text: "No similar Words",
  599. toast_wordadd_text: "Word ${word} added to dictionary ${dicname}."
  600. };
  601. }
  602. }
  603. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement