diff --git a/README.md b/README.md
index 7882b2d..77eb610 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,5 @@
# ner.edith

+
+- use mouse wheel to scroll up and down
+- use navigation << and >> to move faster
\ No newline at end of file
diff --git a/ner-edith.js b/ner-edith.js
new file mode 100644
index 0000000..381debf
--- /dev/null
+++ b/ner-edith.js
@@ -0,0 +1,272 @@
+var data;
+
+var file = null;
+
+var displayRows=30
+var startIndex=0;
+var endIndex=displayRows;
+
+function loadFile(evt) {
+
+ let table_html =
+ `
+
+
+
+ OFFSET |
+ POSITION |
+ TOKEN |
+ NE-TAG |
+ NE-EMB |
+
+
+
+
+
+
+ `;
+
+ let save_html =
+ ``
+
+ $("#tableregion").html(table_html)
+
+ $("#btn-region").html(save_html)
+
+ $('.saveButton').on('click', saveFile)
+
+ let editingTd;
+
+ function finishTdEdit(td, isOk) {
+
+ if (isOk) {
+ let newValue = $('#edit-area').val();
+
+ $(td).html(newValue);
+
+ let tableInfo = $(td).data('tableInfo');
+
+ data.data[tableInfo.nRow][tableInfo.column] = newValue;
+ }
+ else {
+ $(td).html(editingTd.data);
+ }
+
+ editingTd = null;
+ }
+
+ function makeTdEditable(td) {
+
+ editingTd = {
+ elem: td,
+ data: td.innerHTML
+ };
+
+ let textArea = document.createElement('textarea');
+ textArea.style.width = td.clientWidth + 'px';
+ textArea.style.height = td.clientHeight + 'px';
+ textArea.id = 'edit-area';
+
+ $(textArea).val($(td).html());
+ $(td).html('');
+ $(td).append(textArea);
+ textArea.focus();
+
+ let edit_html =
+ `
+
+
+
`
+
+ td.insertAdjacentHTML("beforeEnd", edit_html);
+
+ $('#edit-ok').on('click',
+ function(evt) {
+ finishTdEdit(editingTd.elem, true);
+ });
+
+ $('#edit-cancel').on('click',
+ function(evt) {
+ finishTdEdit(editingTd.elem, false);
+ });
+ }
+
+ $('#table').on('click',
+ function(event) {
+
+ let target = event.target.closest('.editable');
+
+ if (editingTd) {
+
+ if (target == editingTd.elem) return;
+
+ finishTdEdit(editingTd.elem, true);
+ }
+
+ if (!$.contains($('#table')[0], target)) return
+
+ makeTdEditable(target);
+ });
+
+ file = evt.target.files[0];
+
+ // TODO: adapt to streaming with 'chunk' callback for large file support, see https://www.papaparse.com/docs
+ Papa.parse(file, {
+ header: true,
+ delimiter: '\t',
+ comments: "#",
+ skipEmptyLines: true,
+ dynamicTyping: true,
+ complete: function(results) {
+ //console.log(results);
+ data = results;
+
+ updateTable();
+
+ $("#file-region").html('' + file.name + '
');
+
+ $('#tableregion')[0].addEventListener("wheel",
+ function(event) {
+
+ if (event.deltaY < 0) {
+
+ if (startIndex <= 0) return;
+
+ startIndex -= 1;
+ endIndex -= 1;
+ }
+ else {
+
+ if (endIndex >= data.data.length) return;
+
+ startIndex += 1;
+ endIndex += 1;
+ }
+
+ updateTable();
+ });
+
+ $('#back').on('click',
+ function(evt) {
+
+ if (startIndex >= displayRows) {
+ startIndex -= displayRows;
+ endIndex -= displayRows;
+ }
+ else {
+ startIndex = 0;
+ endIndex = displayRows;
+ }
+
+ updateTable();
+ }
+ );
+
+ $('#next').on('click',
+ function(evt) {
+
+ if (endIndex + displayRows < data.data.length) {
+ endIndex += displayRows;
+ startIndex = endIndex - displayRows;
+ }
+ else {
+ endIndex = data.data.length;
+ startIndex = endIndex - displayRows;
+ }
+
+ updateTable();
+ }
+ );
+ }
+ });
+}
+
+function updateTable() {
+
+ let editable_html =
+ `
+
+ `;
+
+ $('#table-body').empty();
+
+ $.each(data.data,
+ function(nRow, el) {
+
+ if (nRow < startIndex) return;
+ if (nRow >= endIndex) return;
+
+ var row = $(" |
");
+ row.append($(" | ").text(nRow));
+
+ $.each(el,
+ function(column, content) {
+ row.append(
+ $(editable_html).
+ text(content).
+ data('tableInfo', { 'nRow': nRow, 'column': column })
+ );
+ });
+
+ $("#table tbody").append(row);
+ });
+
+ $("#table td:contains('B-PER')").addClass('ner_per');
+ $("#table td:contains('I-PER')").addClass('ner_per');
+ $("#table td:contains('B-LOC')").addClass('ner_loc');
+ $("#table td:contains('I-LOC')").addClass('ner_loc');
+ $("#table td:contains('B-ORG')").addClass('ner_org');
+ $("#table td:contains('I-ORG')").addClass('ner_org');
+ $("#table td:contains('B-OTH')").addClass('ner_oth');
+ $("#table td:contains('I-OTH')").addClass('ner_oth');
+}
+
+function saveFile(evt) {
+
+ let csv =
+ Papa.unparse(data,
+ {
+ header: true,
+ delimiter: '\t',
+ comments: "#",
+ skipEmptyLines: true,
+ dynamicTyping: true
+ });
+
+ openSaveFileDialog (csv, file.name, null)
+}
+
+
+function openSaveFileDialog (data, filename, mimetype) {
+
+ if (!data) return;
+
+ var blob = data.constructor !== Blob
+ ? new Blob([data], {type: mimetype || 'application/octet-stream'})
+ : data ;
+
+ if (navigator.msSaveBlob) {
+ navigator.msSaveBlob(blob, filename);
+ return;
+ }
+
+ var lnk = document.createElement('a'),
+ url = window.URL,
+ objectURL;
+
+ if (mimetype) {
+ lnk.type = mimetype;
+ }
+
+ lnk.download = filename || 'untitled';
+ lnk.href = objectURL = url.createObjectURL(blob);
+ lnk.dispatchEvent(new MouseEvent('click'));
+ setTimeout(url.revokeObjectURL.bind(url, objectURL));
+
+}
+
+$(document).ready(
+ function() {
+ $('#tsv-file').change(loadFile);
+ }
+);
\ No newline at end of file
diff --git a/ner.edith.html b/ner.edith.html
index d32a80f..07899ae 100644
--- a/ner.edith.html
+++ b/ner.edith.html
@@ -3,130 +3,66 @@
ner.edith
+
- ner.edith: named entity recognition editor in html
- Please upload a TSV (tab-separated-values) file in the GermEval2014 data format[i]:
-
-
-
- OFFSET |
- POSITION |
- TOKEN |
- NE-TAG |
- NE-EMB |
-
-
-
-
-
+