-
-
Save danielvy/9953c722446ccbef27292534e62b117b to your computer and use it in GitHub Desktop.
Userscript to add addtional UI to Prodigy's NER manual interface
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Prodigy NER extended info | |
// @version 1 | |
// @grant none | |
// @include http://localhost:8080/ | |
// @run-at document-start | |
// ==/UserScript== | |
let displayElement; | |
let metaDataElement; | |
let annotationsElement; | |
let metaLinkElement; | |
let googleSearchLinkElement; | |
const displayElementClassName = ".prodigy-container"; | |
const metaDataElementClassName = ".prodigy-meta"; | |
const annotationsElementClassName = ".prodigy-content"; | |
function createContainer() { | |
let style = document.createElement("style"); | |
style.innerHTML = css_string | |
document.body.appendChild(style) | |
let container = document.createElement("div"); | |
container.classList.add("extended_info"); | |
let divElement; | |
divElement = document.createElement("div"); | |
divElement.innerHTML = '<a href="#" target="_blank"></a>'; | |
metaLinkElement = divElement.firstChild; | |
metaLinkElement.insertAdjacentHTML("beforebegin", "Go To Youtube: "); | |
container.appendChild(divElement); | |
divElement = document.createElement("div"); | |
divElement.innerHTML = '<a href="#" target="_blank"></a>'; | |
googleSearchLinkElement = divElement.firstChild; | |
googleSearchLinkElement.insertAdjacentHTML("beforebegin", "Search Google: "); | |
container.appendChild(divElement); | |
displayElement.after(container); | |
} | |
// This will be called whenever the meta info displayed changes | |
function metaDataChanged() { | |
// The key for meta data to look for | |
let metaDataKeyName = "VIDEO_ID"; | |
let span = Array.from(metaDataElement.getElementsByTagName("span")).find(span => | |
(t = span.getElementsByTagName("strong")) ? t[0].textContent.trim() == metaDataKeyName + ":": false | |
); | |
let videoId; | |
if (span) { | |
videoId = (t = Array.from(span.childNodes).filter(node => node.nodeType == Node.TEXT_NODE)) ? t[0].data : null; | |
}; | |
if (videoId) { | |
metaLinkElement.innerHTML = "video " + videoId; | |
metaLinkElement.setAttribute("href", "https://www.youtube.com/watch?v=" + videoId) | |
} | |
} | |
// This will be called whenever the annotation changes | |
function annotationsChanged() { | |
// Get an array of text in for "marked" tokens | |
let marked = Array.from(annotationsElement.getElementsByTagName("mark")).map( node => | |
(t = Array.from(node.childNodes).filter(node => node.nodeType == Node.TEXT_NODE)) ? t[0].data : null | |
) | |
let query = marked.filter((v, i, a) => a.indexOf(v) === i).map((item, i, a) => `<span class="ner_label">${item}</span>`) | |
.join(" ") | |
googleSearchLinkElement.setAttribute("href", "https://www.google.com/search?q=" + encodeURI(marked.join(" "))); | |
googleSearchLinkElement.innerHTML = query; | |
} | |
// Observer for meta data changes | |
let metaDataChangedObserver = new MutationObserver( function(mutationsList) { | |
metaDataChanged(); | |
}); | |
// Observer for annotation changes | |
let annotationsChangedObserver = new MutationObserver( function(mutationsList) { | |
annotationsChanged(); | |
}); | |
let rootElement = document.getElementById("root"); | |
// Observes when the root div initialized | |
let rootObserver = new MutationObserver( function(mutationsList) { | |
// Find Prodigy's "main" display container div (by class name) | |
displayElement = document.querySelector(displayElementClassName); | |
if (displayElement != null) { | |
// find the meta data div container (by class name) and set up observing | |
metaDataElement = document.querySelector(metaDataElementClassName); | |
metaDataChangedObserver.observe(metaDataElement, {subtree: true, characterData: true}); | |
// find the annotations div container (by class name) and set up observing | |
annotationsElement = document.querySelector(annotationsElementClassName); | |
annotationsChangedObserver.observe(annotationsElement, {childList: true, subtree: true, characterData: true}); | |
// No need to observe root anymore | |
rootObserver.disconnect(); | |
// Create the container for the extended information | |
createContainer(); | |
// Need to call these the first time | |
metaDataChanged(); | |
annotationsChanged(); | |
} | |
}); | |
rootObserver.observe(rootElement, {childList: true, subtree: true}); | |
const css_string = ` | |
.extended_info { | |
padding: 2rem; | |
font-size: 2rem; | |
border-radius: 0; | |
border: 1px solid #ddd; | |
max-width: 675px; | |
min-height: 100px; | |
min-width: 300px; | |
margin: 3rem auto 0 auto; | |
background: #fff; | |
} | |
.extended_info a { | |
text-decoration: none; | |
border-bottom: 1px solid #c8c8c8; | |
transition: border 0.2s ease; | |
} | |
.extended_info a:hover { | |
color: #252a33; | |
border-bottom-color: #565656; | |
} | |
.ner_label { | |
box-decoration-break: clone; | |
color: inherit; | |
display: inline; | |
font-weight: bold; | |
line-height: 1; | |
background: rgba(255, 225, 132, .4) none repeat scroll 0% 0%; | |
} | |
` | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment