Skip to content

Instantly share code, notes, and snippets.

@vpnry
Last active April 2, 2023 14:58
Show Gist options
  • Select an option

  • Save vpnry/f4d16b7ab71f30f4a6f5d4a3d66bd5da to your computer and use it in GitHub Desktop.

Select an option

Save vpnry/f4d16b7ab71f30f4a6f5d4a3d66bd5da to your computer and use it in GitHub Desktop.
Myanmar Popup Dictionary Userscript
// ==UserScript==
// @name MYENMY-Dictionary
// @namespace https://gist.github.com/vpnry/f4d16b7ab71f30f4a6f5d4a3d66bd5da
// @version 2023.04.02.2129
// @description MEM-Dictionary For Tampermonkey UserScript
// @author uPNRY with the assistance of ChatGPT
// @match http://*/*
// @match https://*/*
// @exclude http://google.com/*
// @exclude https://google.com/*
// @grant none
// ==/UserScript==
// @run-at document-end
/**
* You need to put your dictionary in const DICTOBJ = {"key", "value"};
* -------------------------------------------------------------------------
* On Android use this user script with https://github.com/bromite/bromite
* or Kiwi Browser http://play.google.com/store/apps/details?id=com.kiwibrowser.browser
* -------------------------------------------------------------------------
* You may want to use GNU nano editor to insert the large filesize dictionary content in to DICTOBJ.
* My dictionary is around 100 MB json! Still work.
* Some functions are generated/modified with chat GPT
*/
(function () {
"use strict";
var puncSpecialChars = "…‘’!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" + "။၊";
var punRex = new RegExp(
`^[${puncSpecialChars}]+|[${puncSpecialChars}]+$`,
"g"
);
var timeoutIdPopup = "";
let highlightedWord = null;
const filterN = 2;
// put your dictionaries into this DICTOBJ
const DICTOBJ = "INSERTDICTIONARYHEREINSERTDICTIONARYHERE";
const RESEGMENT_REGULAR_EX =
/(?:(?<!\u1039)([\u1000-\u102A\u103F\u104A-\u104F]|[\u1040-\u1049]+|[^\u1000-\u104F]+)(?![\u103E\u103B]?[\u1039\u103A\u1037]))/g;
function segment(text) {
// RESEGMENT_REGULAR_EX and this func are adapted from
// https://github.com/swanhtet1992/ReSegment/blob/master/Javascript/resegment.js
/**
*
* @author Chan Mrate Ko Ko
*
*/
var outArray = text.replace(RESEGMENT_REGULAR_EX, "𝕊$1").split("𝕊");
if (outArray.length > 0) {
outArray.shift();
//out.splice(0, 1);
}
return outArray;
}
function detectLatinWord(word) {
const latinPattern = /^[a-zA-Z\u00C0-\u00FF\s]*$/;
return latinPattern.test(word);
}
function countWordFrequency(n = 2) {
const textContent = document.body.textContent;
const words = textContent.trim().split(/\s+/);
const wordCount = {};
words.forEach((word) => {
word = word.trim().toLowerCase();
if (word.length > 0) {
if (!wordCount[word]) {
wordCount[word] = 1;
} else {
wordCount[word]++;
}
}
});
const totalUniqWord = Object.keys(wordCount).length;
const filteredWords = Object.keys(wordCount).filter((word) => {
return wordCount[word] >= n;
});
const filteredWordCount = {};
filteredWords.forEach((word) => {
filteredWordCount[word] = wordCount[word];
});
return {
totalUniqWord: totalUniqWord,
filteredWordCount: filteredWordCount,
};
}
function wrapWords(node) {
// Generated with ChatGPT
if (node.nodeType === Node.TEXT_NODE) {
const words = node.textContent.trim().split(/\s+/);
const fragment = document.createDocumentFragment();
words.forEach((word, i) => {
word = word.trim();
if (i > 0) {
fragment.appendChild(document.createTextNode(" ")); // Add a space after each word
}
const w = document.createElement("w");
w.textContent = word + " ";
fragment.appendChild(w);
w.addEventListener(
"click",
(e) => {
if (highlightedWord !== null) {
highlightedWord.classList.remove("hil1ghtd1");
}
highlightedWord = w;
w.classList.add("hil1ghtd1");
gText(e);
},
false
);
});
const wrappedText = fragment.cloneNode(true).textContent;
node.parentNode.replaceChild(fragment, node);
} else if (node.nodeType === Node.ELEMENT_NODE) {
for (let i = 0; i < node.childNodes.length; i++) {
wrapWords(node.childNodes[i]);
}
}
}
/* max z-index: 2147483647; on top, but avoid using it
font-family: Pyidaungsu, "Myanmar3", "Myanmar Sangam MN", "Myanmar MN", "Myanmar Text", Padauk, Tharlon, "Masterpiece Uni Sans", "Noto Sans Myanmar", sans-serif;
background-color: #3B3A38 !important;
*/
let popup_style = `
display: none;
position: fixed;
top: 0px;
right: 0%;
left: 0%;
z-index: 2147483647;
text-align: left;
font-size: medium;
max-height: 65%;
width: auto;
padding: 4px;
border-bottom: orange solid 1.5px;
background-color: cornsilk !important;
overflow-x: scroll;
overflow-y: scroll;
`;
const wFredDivSyle = `
text-align: left;
font-size: small;
padding: 4px;
border: brown solid 1px;
`;
// Get the <head> element
let head = document.head;
// If it doesn't exist, create it and add it to the document
if (!head) {
head = document.createElement("head");
document.documentElement.appendChild(head);
}
if (document.head) {
const styleHighlight = document.createElement("style");
styleHighlight.textContent = ".hil1ghtd1 { background-color: yellow; }";
document.head.appendChild(styleHighlight);
}
if (document) {
const { totalUniqWord, filteredWordCount } = countWordFrequency(filterN);
let dict = document.createElement("div");
dict.id = "pnrydict";
dict.setAttribute("style", popup_style);
var wFredDiv = document.createElement("div");
wFredDiv.id = "wFredDiv";
wFredDiv.setAttribute("style", wFredDivSyle);
if (document.body) {
const body = document.querySelector("body");
document.body.prepend(dict);
const highFreqCount = Object.keys(filteredWordCount).length;
if (highFreqCount > 0) {
const wFredDivHeader = document.createElement("b");
wFredDivHeader.textContent = `Unique words/phrases: ${totalUniqWord}. With freq >=${filterN} times: ${highFreqCount}`;
wFredDiv.prepend(wFredDivHeader);
// wFredDiv.append(document.createElement("hr"));
let countN = 0;
const wFredDivTable = document.createElement("table");
wFredDivTable.style.width = "100%";
wFredDivTable.style.borderCollapse = "collapse";
const wFredDivTableBody = document.createElement("tbody");
const wFredDivTableRow = document.createElement("tr");
const wFredDivTableCell1 = document.createElement("td");
wFredDivTableCell1.style.verticalAlign = "top";
wFredDivTableCell1.style.borderRight = "1px solid gray";
wFredDivTableRow.appendChild(wFredDivTableCell1);
const wFredDivTableCell2 = document.createElement("td");
wFredDivTableCell2.style.verticalAlign = "top";
wFredDivTableCell2.style.paddingLeft = "5px";
wFredDivTableRow.appendChild(wFredDivTableCell2);
wFredDivTableBody.appendChild(wFredDivTableRow);
wFredDivTable.appendChild(wFredDivTableBody);
Object.keys(filteredWordCount).forEach((word, index) => {
const freq = filteredWordCount[word];
if (freq >= filterN) {
const wordDiv = document.createElement("div");
countN++;
wordDiv.textContent = `${countN}. ${word} ${freq}`;
if (index < highFreqCount / 2) {
wFredDivTableCell1.appendChild(wordDiv);
} else {
wFredDivTableCell2.appendChild(wordDiv);
}
}
});
wFredDiv.appendChild(wFredDivTable);
dict.insertAdjacentElement("afterend", wFredDiv);
wFredDiv.insertAdjacentHTML("afterend", "<br>");
}
wrapWords(body);
}
}
function findStrFromSelection() {
// Adapted from https://stackoverflow.com/a/70541520
if (!window.getSelection) {
console.log("Not supported window.getSelection");
return;
}
var t = "";
var s = window.getSelection();
var range = s.getRangeAt(0);
var node = s.anchorNode;
var content = node.textContent;
var startOffset = range.startOffset;
var endOffset = range.endOffset;
// Find starting point
// We move the cursor back until we find a space a line break or the start of the node
do {
startOffset--;
} while (
startOffset > 0 &&
content[startOffset - 1] != " " &&
content[startOffset - 1] != "\n"
);
// Find ending point
// We move the cursor forward until we find a space a line break or the end of the node
do {
endOffset++;
} while (
content[endOffset] != " " &&
content[endOffset] != "\n" &&
endOffset < content.length
);
t = content.substring(startOffset, endOffset);
// Remove all punctuation from word
t = t.replace(punRex, "");
return t;
}
// function joinNestedArray(ary) {
// return ary.reduce((acc, val) => acc.concat(...val), []).join(" ");
// }
function wrapSection(x) {
return `<section class="pnryDefiClass" onclick="this.innerHTML = ''; this.style.display = 'none';" style="border: solid black 1px; border-radius: 2%;padding: 5px; box-shadow: 3px 3px 10px #888888;; display:;">${x}</section>`;
}
function wrapSectionHead(x) {
return `<section class="pnryWordHeadClass" onclick="document.getElementById('pnrydict').innerHTML=''; document.getElementById('pnrydict').style.display = 'none';" style="border: solid black 1.5px; border-radius: 2%; padding: 5px; box-shadow: 3px 3px 10px #888888; display:;">${x}</section>`;
}
function splitAndLookUp(text) {
text = text.trim();
const rawInput = text;
let syllables = segment(text);
// filter punctuation, whitespace
syllables = syllables
.filter((element) => element.replace(punRex, "").trim().length > 0)
.map((element) => element.trim());
let result = [];
let wordList = [];
let i = 0;
while (i < syllables.length) {
for (let j = syllables.length; j > i; j--) {
let word = syllables.slice(i, j).join("");
if (word in DICTOBJ) {
wordList.push(word);
// let x = `<p style='color:brown;'><b>${word}</b></p>${joinNestedArray(DICTOBJ[word])}`;
let x = `<p style='color:brown;'><b>${word}</b></p>${DICTOBJ[word]}`;
x = wrapSection(x);
result.push(x);
i = j;
break;
} else {
if (j === i + 1) {
let s = syllables[i];
wordList.push(s);
let x = `<p style='color:brown;'><b>${s}</b></p> ?`;
x = wrapSection(x);
result.push(x);
i++;
}
}
}
}
let split_list =
`<span style="color:blue"><b>${rawInput}</b></span>` +
`<br>=> (${wordList.length}): ` +
wordList.join(" + ") +
'<br><div style="text-align:center;">🤗</div>';
// console.log(result);
let html = wrapSectionHead(split_list) + result.join(" ");
return html;
}
function lookUpWord(input) {
let i = input.length;
if (DICTOBJ.hasOwnProperty(input)) {
let x = `<p style='color:brown;'>💯 <b>${input}</b></p>${DICTOBJ[input]}`;
x = wrapSection(x);
return x;
}
return splitAndLookUp(input);
}
function gText(e) {
// Modified from https://gist.github.com/shivprasad/1088985
window.clearTimeout(timeoutIdPopup);
var t = findStrFromSelection();
let ele = document.getElementById("pnrydict");
if (!ele) {
return;
}
if (ele.contains(e.target)) {
return;
}
ele.innerHTML = "";
if (t.length > 0) {
let w = t.toLowerCase();
//let res = DICTOBJ[w];
let res = lookUpWord(w);
if (res) {
ele.style.display = "";
ele.innerHTML = `${res}`;
if (detectLatinWord(w)) {
SKS(w);
}
// auto hide after 60s require JavaScript enabled
timeoutIdPopup = window.setTimeout(function () {
ele.innerHTML = "";
ele.style.display = "none";
}, 60000);
} else {
ele.style.display = "none";
}
// SKS(w);
} else {
ele.style.display = "none";
}
}
// document.addEventListener("click", gText, false);
// function getClickedWord(e) {
// /** Generated with Bing AI ChatGPT */
// var defiEl = document.getElementById("dictionary-res");
// var tocDivBox = document.getElementById("tocDivBox");
// /** Not getting words on these elements */
// if (
// !defiEl.contains(e.target) &&
// !tocDivBox.contains(e.target) &&
// !e.target.classList.contains("tocDivBox_a")
// ) {
// var node, offset;
// if (document.caretRangeFromPoint) {
// var range = document.caretRangeFromPoint(e.clientX, e.clientY);
// node = range.startContainer;
// offset = range.startOffset;
// } else if (document.caretPositionFromPoint) {
// var caretPos = document.caretPositionFromPoint(e.clientX, e.clientY);
// node = caretPos.offsetNode;
// offset = caretPos.offset;
// }
// var textNodeContent = node.textContent;
// var start = offset;
// var end = offset;
// while (start > 0 && /\S/.test(textNodeContent[start - 1])) {
// start--;
// }
// while (end < textNodeContent.length && /\S/.test(textNodeContent[end])) {
// end++;
// }
// var word = textNodeContent.slice(start, end);
// if (word) {
// word = word.toLowerCase();
// // Remove all punctuation from word
// word = word.replace(
// new RegExp(`^[${puncSpecialChars}]+|[${puncSpecialChars}]+$`, "g"),
// ""
// );
// return word.trim();
// }
// }
// }
// function appendCloseMe() {
// function closeMe(e, head = false) {
// if (head) {
// e = document.getElementById("pnrydict");
// }
// e.innerHTML = "";
// e.style.display = "none";
// }
// var head = document.getElementsByTagName("head")[0];
// var script = document.createElement("script");
// script.type = "text/javascript";
// script.innerHTML = closeMe;
// head.appendChild(script);
// }
// Text to speech
var TTS = "speechSynthesis" in window ? window.speechSynthesis : null;
function SKS(word) {
//Slow version
if (!TTS) {
console.log("TTS is not available in window");
return;
}
console.log("TTS is available in window");
// stop the previous speech
TTS.cancel();
let utterance = new SpeechSynthesisUtterance(word);
utterance.lang = "en-GB"; //en-US, en-GB
utterance.pitch = "0.8";
utterance.rate = "0.5";
TTS.speak(utterance);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment