|
@@ -0,0 +1,246 @@
|
|
|
|
+//
|
|
|
|
+// Brat fast mode : add a fast annotation mode for document level labelling
|
|
|
|
+//
|
|
|
|
+
|
|
|
|
+// Detect brat document : activate the extension only if brat detected
|
|
|
|
+try {
|
|
|
|
+ is_brat = document.getElementById("mainlogo").textContent == "brat"
|
|
|
|
+} catch (e) {
|
|
|
|
+ is_brat = false
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+if (is_brat == false) {
|
|
|
|
+ exit()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Script start here : if brat = true
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ Event for fast annotation
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+//// Fast annotator :
|
|
|
|
+// Detect trigger word
|
|
|
|
+// If trigger word exist : raise an event of trigger on selected word
|
|
|
|
+// Fast annotator is triggered on each refresh of document
|
|
|
|
+
|
|
|
|
+function initiateFastAnnotator () {
|
|
|
|
+
|
|
|
|
+ // Remove event listener
|
|
|
|
+ document.removeEventListener("keyup", triggerLabel)
|
|
|
|
+
|
|
|
|
+ // Search for trigger word id
|
|
|
|
+ text_documents = document.querySelectorAll("tspan")
|
|
|
|
+ for (i in text_documents) {
|
|
|
|
+ if (text_documents[i].textContent == targetWord) {
|
|
|
|
+ // Get word id
|
|
|
|
+ word_id = text_documents[i].getAttribute("data-chunk-id");
|
|
|
|
+
|
|
|
|
+ // Get word trigered
|
|
|
|
+ triggerWord(word_id);
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function fastAnnotator () {
|
|
|
|
+ // The observer will check for content change and trigger fastAnnotator action
|
|
|
|
+ observer = new MutationObserver(initiateFastAnnotator);
|
|
|
|
+
|
|
|
|
+ observer.observe(document.getElementById("svg"), { attributes: true, childList: true, subtree: true });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function triggerWord (word_id) {
|
|
|
|
+ // Display word triggering
|
|
|
|
+ node = document.querySelector("tspan[data-chunk-id='"+word_id+"']")
|
|
|
|
+
|
|
|
|
+ // Adding CSS rule
|
|
|
|
+ if (typeof(observer) != 'undefined') {
|
|
|
|
+ observer.disconnect();
|
|
|
|
+ }
|
|
|
|
+ node.classList.add("triggerWord")
|
|
|
|
+ fastAnnotator();
|
|
|
|
+
|
|
|
|
+ // Trigger label event
|
|
|
|
+ document.addEventListener("keyup", triggerLabel)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ Function for page interaction
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+function createEvent(node, eventType) {
|
|
|
|
+ var x = node.getBoundingClientRect()["x"];
|
|
|
|
+ var y = node.getBoundingClientRect()["y"];
|
|
|
|
+ var x_coor = x+node.getBoundingClientRect()["width"]/2;
|
|
|
|
+ var y_coor = y+node.getBoundingClientRect()["height"]/2;
|
|
|
|
+
|
|
|
|
+ if (eventType == 'mousedown') {
|
|
|
|
+ var x_start = x;
|
|
|
|
+ var y_start = y;
|
|
|
|
+ } else {
|
|
|
|
+ var x_start = x+node.getBoundingClientRect()["width"]-1;
|
|
|
|
+ var y_start = y+node.getBoundingClientRect()["height"]-1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var evt = new MouseEvent(eventType, {
|
|
|
|
+ bubbles: true,
|
|
|
|
+ view: window,
|
|
|
|
+ altKey: false,
|
|
|
|
+ ctrlKey: false,
|
|
|
|
+ metaKey: false,
|
|
|
|
+ shiftKey: false,
|
|
|
|
+ clientX: x_start,
|
|
|
|
+ clientY: y_start,
|
|
|
|
+ movementX: 0,
|
|
|
|
+ movementY: 0,
|
|
|
|
+
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ return(evt)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function simulateClick(mouseClickList, obj) {
|
|
|
|
+ for (clickValue in mouseClickList) {
|
|
|
|
+ node.dispatchEvent(createEvent(obj, mouseClickList[clickValue]));
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function SelectText(text) {
|
|
|
|
+ var selection = window.getSelection();
|
|
|
|
+ var range = document.createRange();
|
|
|
|
+ range.selectNodeContents(text);
|
|
|
|
+ selection.removeAllRanges();
|
|
|
|
+ selection.addRange(range);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function triggerLabel (e) {
|
|
|
|
+ if (["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","z","s","t","u","v","w","x","y","z"].indexOf(e.key) != -1) {
|
|
|
|
+
|
|
|
|
+ // Simulate click
|
|
|
|
+ node = document.querySelector("tspan[data-chunk-id='"+word_id+"']")
|
|
|
|
+ SelectText(node)
|
|
|
|
+ simulateClick(["mousedown","mouseup","dblclick"], node)
|
|
|
|
+
|
|
|
|
+ // Simulate label selection
|
|
|
|
+
|
|
|
|
+ // Select label
|
|
|
|
+ document.dispatchEvent(new KeyboardEvent('keydown', {
|
|
|
|
+ 'keyCode':e.keyCode
|
|
|
|
+ }));
|
|
|
|
+
|
|
|
|
+ // Click on ok button
|
|
|
|
+ document.getElementById("span_form-ok").click()
|
|
|
|
+
|
|
|
|
+ // Go to next document
|
|
|
|
+ document.getElementById("next").click()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ UI Creation
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+//// Select target word
|
|
|
|
+
|
|
|
|
+function createWordSelectionUI () {
|
|
|
|
+ // Hiding existing title
|
|
|
|
+ var currentTitle = document.querySelector("#document_name input")
|
|
|
|
+ currentTitle.classList.add("hidden") // Hiding existing
|
|
|
|
+
|
|
|
|
+ // Adding new title
|
|
|
|
+ var newTitle = document.createElement("input");
|
|
|
|
+ currentTitle.parentNode.insertBefore(newTitle, currentTitle.nextSibling);
|
|
|
|
+ newTitle.classList.add("ui-widget-header");
|
|
|
|
+ newTitle.classList.add("targetWordSelection");
|
|
|
|
+ newTitle.setAttribute("readonly","readonly");
|
|
|
|
+ newTitle.setAttribute("value","Select the target word");
|
|
|
|
+ newTitle.id = 'wordSelection';
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function destroyWordSelectionUI () {
|
|
|
|
+ // Displaying existing title
|
|
|
|
+ var currentTitle = document.querySelector("#document_name input");
|
|
|
|
+ currentTitle.classList.remove("hidden"); // Hiding existing
|
|
|
|
+
|
|
|
|
+ // Remove new title
|
|
|
|
+ var newTitle = document.getElementById("wordSelection");
|
|
|
|
+ newTitle.remove();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function selectTargetWord () {
|
|
|
|
+ /*
|
|
|
|
+ Get UI for target word selection
|
|
|
|
+ The target word is then stored in a global variable
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ // UI Creation
|
|
|
|
+ createWordSelectionUI()
|
|
|
|
+
|
|
|
|
+ // Event trigger
|
|
|
|
+ document.getElementsByClassName("text")[0].addEventListener("click", function (e) {
|
|
|
|
+ // Getting trigger word
|
|
|
|
+ targetWord = e.target.textContent;
|
|
|
|
+
|
|
|
|
+ // Removing UI
|
|
|
|
+ destroyWordSelectionUI();
|
|
|
|
+
|
|
|
|
+ // Getting fastAnnotator enabled
|
|
|
|
+ initiateFastAnnotator();
|
|
|
|
+ }, { "once":true })
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//// Creating main UI button
|
|
|
|
+
|
|
|
|
+// Functions relative to the button
|
|
|
|
+
|
|
|
|
+function activateButton (buttonElement) {
|
|
|
|
+ // Set has activate
|
|
|
|
+ buttonNode.setAttribute("activate", true)
|
|
|
|
+
|
|
|
|
+ // Change button class
|
|
|
|
+ buttonNode.classList.add("activate")
|
|
|
|
+ buttonNode.classList.remove("desactivate")
|
|
|
|
+
|
|
|
|
+ // Get target word
|
|
|
|
+ var targetWord = selectTargetWord();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function inactivateButton (buttonElement) {
|
|
|
|
+ // Set has activate
|
|
|
|
+ buttonNode.setAttribute("activate", false)
|
|
|
|
+
|
|
|
|
+ // Change button class
|
|
|
|
+ buttonNode.classList.remove("activate")
|
|
|
|
+ buttonNode.classList.add("desactivate")
|
|
|
|
+
|
|
|
|
+ // Remove observer
|
|
|
|
+ if (typeof(observer) != 'undefined') {
|
|
|
|
+ observer.disconnect()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Button initiation
|
|
|
|
+var buttonName = "FM";
|
|
|
|
+var buttonId = "bratFastModeUI";
|
|
|
|
+
|
|
|
|
+var buttonNode = document.createElement("div");
|
|
|
|
+var nextNode = document.getElementById("navbuttons");
|
|
|
|
+nextNode.parentNode.insertBefore(buttonNode, nextNode)
|
|
|
|
+
|
|
|
|
+buttonNode.id = buttonId;
|
|
|
|
+buttonNode.textContent = buttonName;
|
|
|
|
+buttonNode.classList.add("unselectable");
|
|
|
|
+inactivateButton(buttonNode);
|
|
|
|
+
|
|
|
|
+buttonNode.addEventListener("click", function(e) {
|
|
|
|
+ var node = e.target;
|
|
|
|
+
|
|
|
|
+ if (node.attributes.activate.value == "true") {
|
|
|
|
+ inactivateButton(node);
|
|
|
|
+ } else {
|
|
|
|
+ activateButton(node);
|
|
|
|
+ }
|
|
|
|
+})
|