diff --git a/app/server/static/bundle/document_classification.js b/app/server/static/bundle/document_classification.js index f7b25b21..bdfcdb0f 100644 --- a/app/server/static/bundle/document_classification.js +++ b/app/server/static/bundle/document_classification.js @@ -471,7 +471,19 @@ eval("var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn th /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var _mixin__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./mixin */ \"./static/js/mixin.js\");\n/* harmony import */ var _http__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./http */ \"./static/js/http.js\");\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].use(__webpack_require__(/*! vue-shortkey */ \"./node_modules/vue-shortkey/dist/index.js\"), {\n prevent: ['input', 'textarea'],\n});\n\n\nconst vm = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"]({\n el: '#mail-app',\n delimiters: ['[[', ']]'],\n mixins: [_mixin__WEBPACK_IMPORTED_MODULE_1__[\"default\"]],\n\n methods: {\n isIn(label) {\n for (let i = 0; i < this.annotations[this.pageNumber].length; i++) {\n const a = this.annotations[this.pageNumber][i];\n if (a.label === label.id) {\n return a;\n }\n }\n return false;\n },\n\n async addLabel(label) {\n const a = this.isIn(label);\n if (a) {\n this.removeLabel(a);\n } else {\n const docId = this.docs[this.pageNumber].id;\n const payload = {\n label: label.id,\n };\n await _http__WEBPACK_IMPORTED_MODULE_2__[\"default\"].post(`docs/${docId}/annotations/`, payload).then((response) => {\n this.annotations[this.pageNumber].push(response.data);\n });\n }\n },\n },\n});\n\n\n//# sourceURL=webpack:///./static/js/document_classification.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var _mixin__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./mixin */ \"./static/js/mixin.js\");\n/* harmony import */ var _http__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./http */ \"./static/js/http.js\");\n/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./filter */ \"./static/js/filter.js\");\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].use(__webpack_require__(/*! vue-shortkey */ \"./node_modules/vue-shortkey/dist/index.js\"), {\n prevent: ['input', 'textarea'],\n});\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].filter('simpleShortcut', _filter__WEBPACK_IMPORTED_MODULE_3__[\"default\"]);\n\n\nconst vm = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"]({\n el: '#mail-app',\n delimiters: ['[[', ']]'],\n mixins: [_mixin__WEBPACK_IMPORTED_MODULE_1__[\"default\"]],\n\n methods: {\n isIn(label) {\n for (let i = 0; i < this.annotations[this.pageNumber].length; i++) {\n const a = this.annotations[this.pageNumber][i];\n if (a.label === label.id) {\n return a;\n }\n }\n return false;\n },\n\n async addLabel(label) {\n const a = this.isIn(label);\n if (a) {\n this.removeLabel(a);\n } else {\n const docId = this.docs[this.pageNumber].id;\n const payload = {\n label: label.id,\n };\n await _http__WEBPACK_IMPORTED_MODULE_2__[\"default\"].post(`docs/${docId}/annotations/`, payload).then((response) => {\n this.annotations[this.pageNumber].push(response.data);\n });\n }\n },\n },\n});\n\n\n//# sourceURL=webpack:///./static/js/document_classification.js?"); + +/***/ }), + +/***/ "./static/js/filter.js": +/*!*****************************!*\ + !*** ./static/js/filter.js ***! + \*****************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return simpleShortcut; });\nfunction simpleShortcut(shortcut) {\n if (shortcut === null) {\n shortcut = '';\n } else {\n shortcut = shortcut.replace('ctrl', 'C');\n shortcut = shortcut.replace('shift', 'S');\n shortcut = shortcut.split(' ').join('-');\n }\n return shortcut;\n}\n\n\n//# sourceURL=webpack:///./static/js/filter.js?"); /***/ }), @@ -495,7 +507,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var axio /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _http__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./http */ \"./static/js/http.js\");\n\n\nconst getOffsetFromUrl = function(url) {\n const offsetMatch = url.match(/[?#].*offset=(\\d+)/);\n if (offsetMatch == null) {\n return 0;\n }\n\n return parseInt(offsetMatch[1], 10);\n};\n\nconst storeOffsetInUrl = function(offset) {\n let href = window.location.href;\n\n const fragmentStart = href.indexOf('#') + 1;\n if (fragmentStart === 0) {\n href += '#offset=' + offset;\n } else {\n const prefix = href.substring(0, fragmentStart);\n const fragment = href.substring(fragmentStart);\n\n const newFragment = fragment.split('&').map(function(fragmentPart) {\n const keyValue = fragmentPart.split('=');\n return keyValue[0] === 'offset'\n ? 'offset=' + offset\n : fragmentPart;\n }).join('&');\n\n href = prefix + newFragment;\n }\n\n window.location.href = href;\n};\n\nconst annotationMixin = {\n data() {\n return {\n pageNumber: 0,\n docs: [],\n annotations: [],\n labels: [],\n guideline: '',\n total: 0,\n remaining: 0,\n searchQuery: '',\n url: '',\n offset: getOffsetFromUrl(window.location.href),\n picked: 'all',\n count: 0,\n isActive: false,\n };\n },\n\n methods: {\n async nextPage() {\n this.pageNumber += 1;\n if (this.pageNumber === this.docs.length) {\n if (this.next) {\n this.url = this.next;\n await this.search();\n this.pageNumber = 0;\n } else {\n this.pageNumber = this.docs.length - 1;\n }\n }\n },\n\n async prevPage() {\n this.pageNumber -= 1;\n if (this.pageNumber === -1) {\n if (this.prev) {\n this.url = this.prev;\n await this.search();\n this.pageNumber = this.docs.length - 1;\n } else {\n this.pageNumber = 0;\n }\n }\n },\n\n async search() {\n await _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get(this.url).then((response) => {\n this.docs = response.data.results;\n this.next = response.data.next;\n this.prev = response.data.previous;\n this.count = response.data.count;\n this.annotations = [];\n for (let i = 0; i < this.docs.length; i++) {\n const doc = this.docs[i];\n this.annotations.push(doc.annotations);\n }\n this.offset = getOffsetFromUrl(this.url);\n });\n },\n\n getState() {\n if (this.picked === 'all') {\n return '';\n }\n if (this.picked === 'active') {\n return 'true';\n }\n return 'false';\n },\n\n async submit() {\n const state = this.getState();\n this.url = `docs/?q=${this.searchQuery}&is_checked=${state}&offset=${this.offset}`;\n await this.search();\n this.pageNumber = 0;\n },\n\n removeLabel(annotation) {\n const docId = this.docs[this.pageNumber].id;\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].delete(`docs/${docId}/annotations/${annotation.id}`).then((response) => {\n const index = this.annotations[this.pageNumber].indexOf(annotation);\n this.annotations[this.pageNumber].splice(index, 1);\n });\n },\n },\n\n watch: {\n picked() {\n this.submit();\n },\n\n annotations() {\n // fetch progress info.\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get('progress').then((response) => {\n this.total = response.data.total;\n this.remaining = response.data.remaining;\n });\n },\n\n offset() {\n storeOffsetInUrl(this.offset);\n },\n },\n\n created() {\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get('labels').then((response) => {\n this.labels = response.data;\n });\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get().then((response) => {\n this.guideline = response.data.guideline;\n });\n this.submit();\n },\n\n computed: {\n achievement() {\n const done = this.total - this.remaining;\n const percentage = Math.round(done / this.total * 100);\n return this.total > 0 ? percentage : 0;\n },\n\n compiledMarkdown() {\n return marked(this.guideline, {\n sanitize: true,\n });\n },\n\n id2label() {\n let id2label = {};\n for (let i = 0; i < this.labels.length; i++) {\n const label = this.labels[i];\n id2label[label.id] = label;\n }\n return id2label;\n },\n\n progressColor() {\n if (this.achievement < 30) {\n return 'is-danger';\n }\n if (this.achievement < 70) {\n return 'is-warning';\n }\n return 'is-primary';\n },\n },\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (annotationMixin);\n\n\n//# sourceURL=webpack:///./static/js/mixin.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _http__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./http */ \"./static/js/http.js\");\n\n\nconst getOffsetFromUrl = function(url) {\n const offsetMatch = url.match(/[?#].*offset=(\\d+)/);\n if (offsetMatch == null) {\n return 0;\n }\n\n return parseInt(offsetMatch[1], 10);\n};\n\nconst storeOffsetInUrl = function(offset) {\n let href = window.location.href;\n\n const fragmentStart = href.indexOf('#') + 1;\n if (fragmentStart === 0) {\n href += '#offset=' + offset;\n } else {\n const prefix = href.substring(0, fragmentStart);\n const fragment = href.substring(fragmentStart);\n\n const newFragment = fragment.split('&').map(function(fragmentPart) {\n const keyValue = fragmentPart.split('=');\n return keyValue[0] === 'offset'\n ? 'offset=' + offset\n : fragmentPart;\n }).join('&');\n\n href = prefix + newFragment;\n }\n\n window.location.href = href;\n};\n\nconst annotationMixin = {\n data() {\n return {\n pageNumber: 0,\n docs: [],\n annotations: [],\n labels: [],\n guideline: '',\n total: 0,\n remaining: 0,\n searchQuery: '',\n url: '',\n offset: getOffsetFromUrl(window.location.href),\n picked: 'all',\n count: 0,\n isActive: false,\n };\n },\n\n methods: {\n async nextPage() {\n this.pageNumber += 1;\n if (this.pageNumber === this.docs.length) {\n if (this.next) {\n this.url = this.next;\n await this.search();\n this.pageNumber = 0;\n } else {\n this.pageNumber = this.docs.length - 1;\n }\n }\n },\n\n async prevPage() {\n this.pageNumber -= 1;\n if (this.pageNumber === -1) {\n if (this.prev) {\n this.url = this.prev;\n await this.search();\n this.pageNumber = this.docs.length - 1;\n } else {\n this.pageNumber = 0;\n }\n }\n },\n\n async search() {\n await _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get(this.url).then((response) => {\n this.docs = response.data.results;\n this.next = response.data.next;\n this.prev = response.data.previous;\n this.count = response.data.count;\n this.annotations = [];\n for (let i = 0; i < this.docs.length; i++) {\n const doc = this.docs[i];\n this.annotations.push(doc.annotations);\n }\n this.offset = getOffsetFromUrl(this.url);\n });\n },\n\n getState() {\n if (this.picked === 'all') {\n return '';\n }\n if (this.picked === 'active') {\n return 'true';\n }\n return 'false';\n },\n\n async submit() {\n const state = this.getState();\n this.url = `docs/?q=${this.searchQuery}&is_checked=${state}&offset=${this.offset}`;\n await this.search();\n this.pageNumber = 0;\n },\n\n removeLabel(annotation) {\n const docId = this.docs[this.pageNumber].id;\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].delete(`docs/${docId}/annotations/${annotation.id}`).then((response) => {\n const index = this.annotations[this.pageNumber].indexOf(annotation);\n this.annotations[this.pageNumber].splice(index, 1);\n });\n },\n\n replaceNull(shortcut) {\n if (shortcut === null) {\n shortcut = '';\n }\n shortcut = shortcut.split(' ');\n return shortcut;\n },\n },\n\n watch: {\n picked() {\n this.submit();\n },\n\n annotations() {\n // fetch progress info.\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get('progress').then((response) => {\n this.total = response.data.total;\n this.remaining = response.data.remaining;\n });\n },\n\n offset() {\n storeOffsetInUrl(this.offset);\n },\n },\n\n created() {\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get('labels').then((response) => {\n this.labels = response.data;\n });\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get().then((response) => {\n this.guideline = response.data.guideline;\n });\n this.submit();\n },\n\n computed: {\n achievement() {\n const done = this.total - this.remaining;\n const percentage = Math.round(done / this.total * 100);\n return this.total > 0 ? percentage : 0;\n },\n\n compiledMarkdown() {\n return marked(this.guideline, {\n sanitize: true,\n });\n },\n\n id2label() {\n let id2label = {};\n for (let i = 0; i < this.labels.length; i++) {\n const label = this.labels[i];\n id2label[label.id] = label;\n }\n return id2label;\n },\n\n progressColor() {\n if (this.achievement < 30) {\n return 'is-danger';\n }\n if (this.achievement < 70) {\n return 'is-warning';\n }\n return 'is-primary';\n },\n },\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (annotationMixin);\n\n\n//# sourceURL=webpack:///./static/js/mixin.js?"); /***/ }) diff --git a/app/server/static/bundle/label.js b/app/server/static/bundle/label.js index eba1fdc2..5021539c 100644 --- a/app/server/static/bundle/label.js +++ b/app/server/static/bundle/label.js @@ -452,6 +452,18 @@ eval("var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn th /***/ }), +/***/ "./static/js/filter.js": +/*!*****************************!*\ + !*** ./static/js/filter.js ***! + \*****************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return simpleShortcut; });\nfunction simpleShortcut(shortcut) {\n if (shortcut === null) {\n shortcut = '';\n } else {\n shortcut = shortcut.replace('ctrl', 'C');\n shortcut = shortcut.replace('shift', 'S');\n shortcut = shortcut.split(' ').join('-');\n }\n return shortcut;\n}\n\n\n//# sourceURL=webpack:///./static/js/filter.js?"); + +/***/ }), + /***/ "./static/js/http.js": /*!***************************!*\ !*** ./static/js/http.js ***! @@ -472,7 +484,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var axio /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var _http__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./http */ \"./static/js/http.js\");\n\n\n\n\nconst vm = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"]({\n el: '#mail-app',\n delimiters: ['[[', ']]'],\n data: {\n labels: [],\n labelText: '',\n selectedShortkey: '',\n backgroundColor: '#209cee',\n textColor: '#ffffff',\n },\n\n methods: {\n addLabel() {\n const payload = {\n text: this.labelText,\n shortcut: this.selectedShortkey,\n background_color: this.backgroundColor,\n text_color: this.textColor,\n };\n _http__WEBPACK_IMPORTED_MODULE_1__[\"default\"].post('labels/', payload).then((response) => {\n this.reset();\n this.labels.push(response.data);\n });\n },\n\n removeLabel(label) {\n const labelId = label.id;\n _http__WEBPACK_IMPORTED_MODULE_1__[\"default\"].delete(`labels/${labelId}`).then((response) => {\n const index = this.labels.indexOf(label);\n this.labels.splice(index, 1);\n });\n },\n\n reset() {\n this.labelText = '';\n this.selectedShortkey = '';\n this.backgroundColor = '#209cee';\n this.textColor = '#ffffff';\n },\n },\n created() {\n _http__WEBPACK_IMPORTED_MODULE_1__[\"default\"].get('labels').then((response) => {\n this.labels = response.data;\n });\n },\n});\n\n\n//# sourceURL=webpack:///./static/js/label.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var _http__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./http */ \"./static/js/http.js\");\n/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./filter */ \"./static/js/filter.js\");\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].filter('simpleShortcut', _filter__WEBPACK_IMPORTED_MODULE_2__[\"default\"]);\n\n\nconst vm = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"]({\n el: '#mail-app',\n delimiters: ['[[', ']]'],\n data: {\n labels: [],\n labelText: '',\n selectedKey: '',\n checkedKey: [],\n shortcutKey: '',\n backgroundColor: '#209cee',\n textColor: '#ffffff',\n },\n\n computed: {\n /**\n * combineKeys: Combine selectedKey and checkedKey to get shortcutKey\n * saveKeys: Save null to database if shortcutKey is empty string\n */\n combineKeys: function () {\n this.shortcutKey = '';\n\n // If checkedKey exits, add it to shortcutKey\n if (this.checkedKey.length > 0) {\n this.checkedKey.sort();\n this.shortcutKey = this.checkedKey.join(' ');\n\n // If selectedKey exist, add it to shortcutKey\n if (this.selectedKey.length !== 0) {\n this.shortcutKey = this.shortcutKey + ' ' + this.selectedKey;\n }\n }\n\n // If only selectedKey exist, assign to shortcutKey\n if (this.shortcutKey.length === 0 && this.selectedKey.length !== 0) {\n this.shortcutKey = this.selectedKey;\n }\n return this.shortcutKey;\n },\n\n saveKeys: function () {\n this.shortcutKey = this.combineKeys;\n if (this.shortcutKey === '') {\n return null;\n }\n return this.shortcutKey;\n },\n },\n \n methods: {\n addLabel() {\n const payload = {\n text: this.labelText,\n shortcut: this.saveKeys,\n background_color: this.backgroundColor,\n text_color: this.textColor,\n };\n _http__WEBPACK_IMPORTED_MODULE_1__[\"default\"].post('labels/', payload).then((response) => {\n this.reset();\n this.labels.push(response.data);\n });\n },\n\n removeLabel(label) {\n const labelId = label.id;\n _http__WEBPACK_IMPORTED_MODULE_1__[\"default\"].delete(`labels/${labelId}`).then((response) => {\n const index = this.labels.indexOf(label);\n this.labels.splice(index, 1);\n });\n },\n\n reset() {\n this.labelText = '';\n this.selectedKey = '';\n this.checkedKey = [];\n this.shortcutKey = '';\n this.backgroundColor = '#209cee';\n this.textColor = '#ffffff';\n },\n },\n created() {\n _http__WEBPACK_IMPORTED_MODULE_1__[\"default\"].get('labels').then((response) => {\n this.labels = response.data;\n });\n },\n});\n\n\n//# sourceURL=webpack:///./static/js/label.js?"); /***/ }) diff --git a/app/server/static/bundle/seq2seq.js b/app/server/static/bundle/seq2seq.js index bd57b9ed..32e00486 100644 --- a/app/server/static/bundle/seq2seq.js +++ b/app/server/static/bundle/seq2seq.js @@ -483,7 +483,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var axio /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _http__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./http */ \"./static/js/http.js\");\n\n\nconst getOffsetFromUrl = function(url) {\n const offsetMatch = url.match(/[?#].*offset=(\\d+)/);\n if (offsetMatch == null) {\n return 0;\n }\n\n return parseInt(offsetMatch[1], 10);\n};\n\nconst storeOffsetInUrl = function(offset) {\n let href = window.location.href;\n\n const fragmentStart = href.indexOf('#') + 1;\n if (fragmentStart === 0) {\n href += '#offset=' + offset;\n } else {\n const prefix = href.substring(0, fragmentStart);\n const fragment = href.substring(fragmentStart);\n\n const newFragment = fragment.split('&').map(function(fragmentPart) {\n const keyValue = fragmentPart.split('=');\n return keyValue[0] === 'offset'\n ? 'offset=' + offset\n : fragmentPart;\n }).join('&');\n\n href = prefix + newFragment;\n }\n\n window.location.href = href;\n};\n\nconst annotationMixin = {\n data() {\n return {\n pageNumber: 0,\n docs: [],\n annotations: [],\n labels: [],\n guideline: '',\n total: 0,\n remaining: 0,\n searchQuery: '',\n url: '',\n offset: getOffsetFromUrl(window.location.href),\n picked: 'all',\n count: 0,\n isActive: false,\n };\n },\n\n methods: {\n async nextPage() {\n this.pageNumber += 1;\n if (this.pageNumber === this.docs.length) {\n if (this.next) {\n this.url = this.next;\n await this.search();\n this.pageNumber = 0;\n } else {\n this.pageNumber = this.docs.length - 1;\n }\n }\n },\n\n async prevPage() {\n this.pageNumber -= 1;\n if (this.pageNumber === -1) {\n if (this.prev) {\n this.url = this.prev;\n await this.search();\n this.pageNumber = this.docs.length - 1;\n } else {\n this.pageNumber = 0;\n }\n }\n },\n\n async search() {\n await _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get(this.url).then((response) => {\n this.docs = response.data.results;\n this.next = response.data.next;\n this.prev = response.data.previous;\n this.count = response.data.count;\n this.annotations = [];\n for (let i = 0; i < this.docs.length; i++) {\n const doc = this.docs[i];\n this.annotations.push(doc.annotations);\n }\n this.offset = getOffsetFromUrl(this.url);\n });\n },\n\n getState() {\n if (this.picked === 'all') {\n return '';\n }\n if (this.picked === 'active') {\n return 'true';\n }\n return 'false';\n },\n\n async submit() {\n const state = this.getState();\n this.url = `docs/?q=${this.searchQuery}&is_checked=${state}&offset=${this.offset}`;\n await this.search();\n this.pageNumber = 0;\n },\n\n removeLabel(annotation) {\n const docId = this.docs[this.pageNumber].id;\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].delete(`docs/${docId}/annotations/${annotation.id}`).then((response) => {\n const index = this.annotations[this.pageNumber].indexOf(annotation);\n this.annotations[this.pageNumber].splice(index, 1);\n });\n },\n },\n\n watch: {\n picked() {\n this.submit();\n },\n\n annotations() {\n // fetch progress info.\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get('progress').then((response) => {\n this.total = response.data.total;\n this.remaining = response.data.remaining;\n });\n },\n\n offset() {\n storeOffsetInUrl(this.offset);\n },\n },\n\n created() {\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get('labels').then((response) => {\n this.labels = response.data;\n });\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get().then((response) => {\n this.guideline = response.data.guideline;\n });\n this.submit();\n },\n\n computed: {\n achievement() {\n const done = this.total - this.remaining;\n const percentage = Math.round(done / this.total * 100);\n return this.total > 0 ? percentage : 0;\n },\n\n compiledMarkdown() {\n return marked(this.guideline, {\n sanitize: true,\n });\n },\n\n id2label() {\n let id2label = {};\n for (let i = 0; i < this.labels.length; i++) {\n const label = this.labels[i];\n id2label[label.id] = label;\n }\n return id2label;\n },\n\n progressColor() {\n if (this.achievement < 30) {\n return 'is-danger';\n }\n if (this.achievement < 70) {\n return 'is-warning';\n }\n return 'is-primary';\n },\n },\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (annotationMixin);\n\n\n//# sourceURL=webpack:///./static/js/mixin.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _http__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./http */ \"./static/js/http.js\");\n\n\nconst getOffsetFromUrl = function(url) {\n const offsetMatch = url.match(/[?#].*offset=(\\d+)/);\n if (offsetMatch == null) {\n return 0;\n }\n\n return parseInt(offsetMatch[1], 10);\n};\n\nconst storeOffsetInUrl = function(offset) {\n let href = window.location.href;\n\n const fragmentStart = href.indexOf('#') + 1;\n if (fragmentStart === 0) {\n href += '#offset=' + offset;\n } else {\n const prefix = href.substring(0, fragmentStart);\n const fragment = href.substring(fragmentStart);\n\n const newFragment = fragment.split('&').map(function(fragmentPart) {\n const keyValue = fragmentPart.split('=');\n return keyValue[0] === 'offset'\n ? 'offset=' + offset\n : fragmentPart;\n }).join('&');\n\n href = prefix + newFragment;\n }\n\n window.location.href = href;\n};\n\nconst annotationMixin = {\n data() {\n return {\n pageNumber: 0,\n docs: [],\n annotations: [],\n labels: [],\n guideline: '',\n total: 0,\n remaining: 0,\n searchQuery: '',\n url: '',\n offset: getOffsetFromUrl(window.location.href),\n picked: 'all',\n count: 0,\n isActive: false,\n };\n },\n\n methods: {\n async nextPage() {\n this.pageNumber += 1;\n if (this.pageNumber === this.docs.length) {\n if (this.next) {\n this.url = this.next;\n await this.search();\n this.pageNumber = 0;\n } else {\n this.pageNumber = this.docs.length - 1;\n }\n }\n },\n\n async prevPage() {\n this.pageNumber -= 1;\n if (this.pageNumber === -1) {\n if (this.prev) {\n this.url = this.prev;\n await this.search();\n this.pageNumber = this.docs.length - 1;\n } else {\n this.pageNumber = 0;\n }\n }\n },\n\n async search() {\n await _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get(this.url).then((response) => {\n this.docs = response.data.results;\n this.next = response.data.next;\n this.prev = response.data.previous;\n this.count = response.data.count;\n this.annotations = [];\n for (let i = 0; i < this.docs.length; i++) {\n const doc = this.docs[i];\n this.annotations.push(doc.annotations);\n }\n this.offset = getOffsetFromUrl(this.url);\n });\n },\n\n getState() {\n if (this.picked === 'all') {\n return '';\n }\n if (this.picked === 'active') {\n return 'true';\n }\n return 'false';\n },\n\n async submit() {\n const state = this.getState();\n this.url = `docs/?q=${this.searchQuery}&is_checked=${state}&offset=${this.offset}`;\n await this.search();\n this.pageNumber = 0;\n },\n\n removeLabel(annotation) {\n const docId = this.docs[this.pageNumber].id;\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].delete(`docs/${docId}/annotations/${annotation.id}`).then((response) => {\n const index = this.annotations[this.pageNumber].indexOf(annotation);\n this.annotations[this.pageNumber].splice(index, 1);\n });\n },\n\n replaceNull(shortcut) {\n if (shortcut === null) {\n shortcut = '';\n }\n shortcut = shortcut.split(' ');\n return shortcut;\n },\n },\n\n watch: {\n picked() {\n this.submit();\n },\n\n annotations() {\n // fetch progress info.\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get('progress').then((response) => {\n this.total = response.data.total;\n this.remaining = response.data.remaining;\n });\n },\n\n offset() {\n storeOffsetInUrl(this.offset);\n },\n },\n\n created() {\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get('labels').then((response) => {\n this.labels = response.data;\n });\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get().then((response) => {\n this.guideline = response.data.guideline;\n });\n this.submit();\n },\n\n computed: {\n achievement() {\n const done = this.total - this.remaining;\n const percentage = Math.round(done / this.total * 100);\n return this.total > 0 ? percentage : 0;\n },\n\n compiledMarkdown() {\n return marked(this.guideline, {\n sanitize: true,\n });\n },\n\n id2label() {\n let id2label = {};\n for (let i = 0; i < this.labels.length; i++) {\n const label = this.labels[i];\n id2label[label.id] = label;\n }\n return id2label;\n },\n\n progressColor() {\n if (this.achievement < 30) {\n return 'is-danger';\n }\n if (this.achievement < 70) {\n return 'is-warning';\n }\n return 'is-primary';\n },\n },\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (annotationMixin);\n\n\n//# sourceURL=webpack:///./static/js/mixin.js?"); /***/ }), diff --git a/app/server/static/bundle/sequence_labeling.js b/app/server/static/bundle/sequence_labeling.js index 1c46be9c..4ef4a3f9 100644 --- a/app/server/static/bundle/sequence_labeling.js +++ b/app/server/static/bundle/sequence_labeling.js @@ -463,6 +463,18 @@ eval("var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn th /***/ }), +/***/ "./static/js/filter.js": +/*!*****************************!*\ + !*** ./static/js/filter.js ***! + \*****************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return simpleShortcut; });\nfunction simpleShortcut(shortcut) {\n if (shortcut === null) {\n shortcut = '';\n } else {\n shortcut = shortcut.replace('ctrl', 'C');\n shortcut = shortcut.replace('shift', 'S');\n shortcut = shortcut.split(' ').join('-');\n }\n return shortcut;\n}\n\n\n//# sourceURL=webpack:///./static/js/filter.js?"); + +/***/ }), + /***/ "./static/js/http.js": /*!***************************!*\ !*** ./static/js/http.js ***! @@ -483,7 +495,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var axio /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _http__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./http */ \"./static/js/http.js\");\n\n\nconst getOffsetFromUrl = function(url) {\n const offsetMatch = url.match(/[?#].*offset=(\\d+)/);\n if (offsetMatch == null) {\n return 0;\n }\n\n return parseInt(offsetMatch[1], 10);\n};\n\nconst storeOffsetInUrl = function(offset) {\n let href = window.location.href;\n\n const fragmentStart = href.indexOf('#') + 1;\n if (fragmentStart === 0) {\n href += '#offset=' + offset;\n } else {\n const prefix = href.substring(0, fragmentStart);\n const fragment = href.substring(fragmentStart);\n\n const newFragment = fragment.split('&').map(function(fragmentPart) {\n const keyValue = fragmentPart.split('=');\n return keyValue[0] === 'offset'\n ? 'offset=' + offset\n : fragmentPart;\n }).join('&');\n\n href = prefix + newFragment;\n }\n\n window.location.href = href;\n};\n\nconst annotationMixin = {\n data() {\n return {\n pageNumber: 0,\n docs: [],\n annotations: [],\n labels: [],\n guideline: '',\n total: 0,\n remaining: 0,\n searchQuery: '',\n url: '',\n offset: getOffsetFromUrl(window.location.href),\n picked: 'all',\n count: 0,\n isActive: false,\n };\n },\n\n methods: {\n async nextPage() {\n this.pageNumber += 1;\n if (this.pageNumber === this.docs.length) {\n if (this.next) {\n this.url = this.next;\n await this.search();\n this.pageNumber = 0;\n } else {\n this.pageNumber = this.docs.length - 1;\n }\n }\n },\n\n async prevPage() {\n this.pageNumber -= 1;\n if (this.pageNumber === -1) {\n if (this.prev) {\n this.url = this.prev;\n await this.search();\n this.pageNumber = this.docs.length - 1;\n } else {\n this.pageNumber = 0;\n }\n }\n },\n\n async search() {\n await _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get(this.url).then((response) => {\n this.docs = response.data.results;\n this.next = response.data.next;\n this.prev = response.data.previous;\n this.count = response.data.count;\n this.annotations = [];\n for (let i = 0; i < this.docs.length; i++) {\n const doc = this.docs[i];\n this.annotations.push(doc.annotations);\n }\n this.offset = getOffsetFromUrl(this.url);\n });\n },\n\n getState() {\n if (this.picked === 'all') {\n return '';\n }\n if (this.picked === 'active') {\n return 'true';\n }\n return 'false';\n },\n\n async submit() {\n const state = this.getState();\n this.url = `docs/?q=${this.searchQuery}&is_checked=${state}&offset=${this.offset}`;\n await this.search();\n this.pageNumber = 0;\n },\n\n removeLabel(annotation) {\n const docId = this.docs[this.pageNumber].id;\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].delete(`docs/${docId}/annotations/${annotation.id}`).then((response) => {\n const index = this.annotations[this.pageNumber].indexOf(annotation);\n this.annotations[this.pageNumber].splice(index, 1);\n });\n },\n },\n\n watch: {\n picked() {\n this.submit();\n },\n\n annotations() {\n // fetch progress info.\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get('progress').then((response) => {\n this.total = response.data.total;\n this.remaining = response.data.remaining;\n });\n },\n\n offset() {\n storeOffsetInUrl(this.offset);\n },\n },\n\n created() {\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get('labels').then((response) => {\n this.labels = response.data;\n });\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get().then((response) => {\n this.guideline = response.data.guideline;\n });\n this.submit();\n },\n\n computed: {\n achievement() {\n const done = this.total - this.remaining;\n const percentage = Math.round(done / this.total * 100);\n return this.total > 0 ? percentage : 0;\n },\n\n compiledMarkdown() {\n return marked(this.guideline, {\n sanitize: true,\n });\n },\n\n id2label() {\n let id2label = {};\n for (let i = 0; i < this.labels.length; i++) {\n const label = this.labels[i];\n id2label[label.id] = label;\n }\n return id2label;\n },\n\n progressColor() {\n if (this.achievement < 30) {\n return 'is-danger';\n }\n if (this.achievement < 70) {\n return 'is-warning';\n }\n return 'is-primary';\n },\n },\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (annotationMixin);\n\n\n//# sourceURL=webpack:///./static/js/mixin.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _http__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./http */ \"./static/js/http.js\");\n\n\nconst getOffsetFromUrl = function(url) {\n const offsetMatch = url.match(/[?#].*offset=(\\d+)/);\n if (offsetMatch == null) {\n return 0;\n }\n\n return parseInt(offsetMatch[1], 10);\n};\n\nconst storeOffsetInUrl = function(offset) {\n let href = window.location.href;\n\n const fragmentStart = href.indexOf('#') + 1;\n if (fragmentStart === 0) {\n href += '#offset=' + offset;\n } else {\n const prefix = href.substring(0, fragmentStart);\n const fragment = href.substring(fragmentStart);\n\n const newFragment = fragment.split('&').map(function(fragmentPart) {\n const keyValue = fragmentPart.split('=');\n return keyValue[0] === 'offset'\n ? 'offset=' + offset\n : fragmentPart;\n }).join('&');\n\n href = prefix + newFragment;\n }\n\n window.location.href = href;\n};\n\nconst annotationMixin = {\n data() {\n return {\n pageNumber: 0,\n docs: [],\n annotations: [],\n labels: [],\n guideline: '',\n total: 0,\n remaining: 0,\n searchQuery: '',\n url: '',\n offset: getOffsetFromUrl(window.location.href),\n picked: 'all',\n count: 0,\n isActive: false,\n };\n },\n\n methods: {\n async nextPage() {\n this.pageNumber += 1;\n if (this.pageNumber === this.docs.length) {\n if (this.next) {\n this.url = this.next;\n await this.search();\n this.pageNumber = 0;\n } else {\n this.pageNumber = this.docs.length - 1;\n }\n }\n },\n\n async prevPage() {\n this.pageNumber -= 1;\n if (this.pageNumber === -1) {\n if (this.prev) {\n this.url = this.prev;\n await this.search();\n this.pageNumber = this.docs.length - 1;\n } else {\n this.pageNumber = 0;\n }\n }\n },\n\n async search() {\n await _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get(this.url).then((response) => {\n this.docs = response.data.results;\n this.next = response.data.next;\n this.prev = response.data.previous;\n this.count = response.data.count;\n this.annotations = [];\n for (let i = 0; i < this.docs.length; i++) {\n const doc = this.docs[i];\n this.annotations.push(doc.annotations);\n }\n this.offset = getOffsetFromUrl(this.url);\n });\n },\n\n getState() {\n if (this.picked === 'all') {\n return '';\n }\n if (this.picked === 'active') {\n return 'true';\n }\n return 'false';\n },\n\n async submit() {\n const state = this.getState();\n this.url = `docs/?q=${this.searchQuery}&is_checked=${state}&offset=${this.offset}`;\n await this.search();\n this.pageNumber = 0;\n },\n\n removeLabel(annotation) {\n const docId = this.docs[this.pageNumber].id;\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].delete(`docs/${docId}/annotations/${annotation.id}`).then((response) => {\n const index = this.annotations[this.pageNumber].indexOf(annotation);\n this.annotations[this.pageNumber].splice(index, 1);\n });\n },\n\n replaceNull(shortcut) {\n if (shortcut === null) {\n shortcut = '';\n }\n shortcut = shortcut.split(' ');\n return shortcut;\n },\n },\n\n watch: {\n picked() {\n this.submit();\n },\n\n annotations() {\n // fetch progress info.\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get('progress').then((response) => {\n this.total = response.data.total;\n this.remaining = response.data.remaining;\n });\n },\n\n offset() {\n storeOffsetInUrl(this.offset);\n },\n },\n\n created() {\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get('labels').then((response) => {\n this.labels = response.data;\n });\n _http__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get().then((response) => {\n this.guideline = response.data.guideline;\n });\n this.submit();\n },\n\n computed: {\n achievement() {\n const done = this.total - this.remaining;\n const percentage = Math.round(done / this.total * 100);\n return this.total > 0 ? percentage : 0;\n },\n\n compiledMarkdown() {\n return marked(this.guideline, {\n sanitize: true,\n });\n },\n\n id2label() {\n let id2label = {};\n for (let i = 0; i < this.labels.length; i++) {\n const label = this.labels[i];\n id2label[label.id] = label;\n }\n return id2label;\n },\n\n progressColor() {\n if (this.achievement < 30) {\n return 'is-danger';\n }\n if (this.achievement < 70) {\n return 'is-warning';\n }\n return 'is-primary';\n },\n },\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (annotationMixin);\n\n\n//# sourceURL=webpack:///./static/js/mixin.js?"); /***/ }), @@ -495,7 +507,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _htt /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var _mixin__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./mixin */ \"./static/js/mixin.js\");\n/* harmony import */ var _http__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./http */ \"./static/js/http.js\");\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].use(__webpack_require__(/*! vue-shortkey */ \"./node_modules/vue-shortkey/dist/index.js\"), {\n prevent: ['input', 'textarea'],\n});\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('annotator', {\n template: '
\\\n {{ text.slice(r.start_offset, r.end_offset) }}\\\n
',\n props: {\n labels: Array, // [{id: Integer, color: String, text: String}]\n text: String,\n entityPositions: Array, // [{'startOffset': 10, 'endOffset': 15, 'label_id': 1}]\n },\n data() {\n return {\n startOffset: 0,\n endOffset: 0,\n };\n },\n\n methods: {\n setSelectedRange(e) {\n let start;\n let end;\n if (window.getSelection) {\n const range = window.getSelection().getRangeAt(0);\n const preSelectionRange = range.cloneRange();\n preSelectionRange.selectNodeContents(this.$el);\n preSelectionRange.setEnd(range.startContainer, range.startOffset);\n start = preSelectionRange.toString().length;\n end = start + range.toString().length;\n } else if (document.selection && document.selection.type !== 'Control') {\n const selectedTextRange = document.selection.createRange();\n const preSelectionTextRange = document.body.createTextRange();\n preSelectionTextRange.moveToElementText(this.$el);\n preSelectionTextRange.setEndPoint('EndToStart', selectedTextRange);\n start = preSelectionTextRange.text.length;\n end = start + selectedTextRange.text.length;\n }\n this.startOffset = start;\n this.endOffset = end;\n console.log(start, end);\n },\n\n validRange() {\n if (this.startOffset === this.endOffset) {\n return false;\n }\n if (this.startOffset > this.text.length || this.endOffset > this.text.length) {\n return false;\n }\n if (this.startOffset < 0 || this.endOffset < 0) {\n return false;\n }\n for (let i = 0; i < this.entityPositions.length; i++) {\n const e = this.entityPositions[i];\n if ((e.start_offset <= this.startOffset) && (this.startOffset < e.end_offset)) {\n return false;\n }\n if ((e.start_offset < this.endOffset) && (this.endOffset < e.end_offset)) {\n return false;\n }\n if ((this.startOffset < e.start_offset) && (e.start_offset < this.endOffset)) {\n return false;\n }\n if ((this.startOffset < e.end_offset) && (e.end_offset < this.endOffset)) {\n return false;\n }\n }\n return true;\n },\n\n resetRange() {\n this.startOffset = 0;\n this.endOffset = 0;\n },\n\n addLabel(labelId) {\n if (this.validRange()) {\n const label = {\n start_offset: this.startOffset,\n end_offset: this.endOffset,\n label: labelId,\n };\n this.$emit('add-label', label);\n }\n },\n\n removeLabel(index) {\n this.$emit('remove-label', index);\n },\n\n makeLabel(startOffset, endOffset) {\n const label = {\n id: 0,\n label: -1,\n start_offset: startOffset,\n end_offset: endOffset,\n };\n return label;\n },\n },\n\n watch: {\n entityPositions() {\n this.resetRange();\n },\n },\n\n computed: {\n sortedEntityPositions() {\n this.entityPositions = this.entityPositions.sort((a, b) => a.start_offset - b.start_offset);\n return this.entityPositions;\n },\n\n chunks() {\n const res = [];\n let left = 0;\n for (let i = 0; i < this.sortedEntityPositions.length; i++) {\n const e = this.sortedEntityPositions[i];\n const l = this.makeLabel(left, e.start_offset);\n res.push(l);\n res.push(e);\n left = e.end_offset;\n }\n const l = this.makeLabel(left, this.text.length);\n res.push(l);\n\n return res;\n },\n\n id2label() {\n let id2label = {};\n // default value;\n id2label[-1] = {\n text_color: '',\n background_color: '',\n };\n for (let i = 0; i < this.labels.length; i++) {\n const label = this.labels[i];\n id2label[label.id] = label;\n }\n return id2label;\n },\n },\n});\n\nconst vm = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"]({\n el: '#mail-app',\n delimiters: ['[[', ']]'],\n mixins: [_mixin__WEBPACK_IMPORTED_MODULE_1__[\"default\"]],\n methods: {\n annotate(labelId) {\n this.$refs.annotator.addLabel(labelId);\n },\n\n addLabel(annotation) {\n const docId = this.docs[this.pageNumber].id;\n _http__WEBPACK_IMPORTED_MODULE_2__[\"default\"].post(`docs/${docId}/annotations/`, annotation).then((response) => {\n this.annotations[this.pageNumber].push(response.data);\n });\n },\n },\n});\n\n\n//# sourceURL=webpack:///./static/js/sequence_labeling.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var _mixin__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./mixin */ \"./static/js/mixin.js\");\n/* harmony import */ var _http__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./http */ \"./static/js/http.js\");\n/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./filter */ \"./static/js/filter.js\");\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].use(__webpack_require__(/*! vue-shortkey */ \"./node_modules/vue-shortkey/dist/index.js\"), {\n prevent: ['input', 'textarea'],\n});\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].filter('simpleShortcut', _filter__WEBPACK_IMPORTED_MODULE_3__[\"default\"]);\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('annotator', {\n template: '
\\\n {{ text.slice(r.start_offset, r.end_offset) }}\\\n
',\n props: {\n labels: Array, // [{id: Integer, color: String, text: String}]\n text: String,\n entityPositions: Array, // [{'startOffset': 10, 'endOffset': 15, 'label_id': 1}]\n },\n data() {\n return {\n startOffset: 0,\n endOffset: 0,\n };\n },\n\n methods: {\n setSelectedRange(e) {\n let start;\n let end;\n if (window.getSelection) {\n const range = window.getSelection().getRangeAt(0);\n const preSelectionRange = range.cloneRange();\n preSelectionRange.selectNodeContents(this.$el);\n preSelectionRange.setEnd(range.startContainer, range.startOffset);\n start = preSelectionRange.toString().length;\n end = start + range.toString().length;\n } else if (document.selection && document.selection.type !== 'Control') {\n const selectedTextRange = document.selection.createRange();\n const preSelectionTextRange = document.body.createTextRange();\n preSelectionTextRange.moveToElementText(this.$el);\n preSelectionTextRange.setEndPoint('EndToStart', selectedTextRange);\n start = preSelectionTextRange.text.length;\n end = start + selectedTextRange.text.length;\n }\n this.startOffset = start;\n this.endOffset = end;\n console.log(start, end);\n },\n\n validRange() {\n if (this.startOffset === this.endOffset) {\n return false;\n }\n if (this.startOffset > this.text.length || this.endOffset > this.text.length) {\n return false;\n }\n if (this.startOffset < 0 || this.endOffset < 0) {\n return false;\n }\n for (let i = 0; i < this.entityPositions.length; i++) {\n const e = this.entityPositions[i];\n if ((e.start_offset <= this.startOffset) && (this.startOffset < e.end_offset)) {\n return false;\n }\n if ((e.start_offset < this.endOffset) && (this.endOffset < e.end_offset)) {\n return false;\n }\n if ((this.startOffset < e.start_offset) && (e.start_offset < this.endOffset)) {\n return false;\n }\n if ((this.startOffset < e.end_offset) && (e.end_offset < this.endOffset)) {\n return false;\n }\n }\n return true;\n },\n\n resetRange() {\n this.startOffset = 0;\n this.endOffset = 0;\n },\n\n addLabel(labelId) {\n if (this.validRange()) {\n const label = {\n start_offset: this.startOffset,\n end_offset: this.endOffset,\n label: labelId,\n };\n this.$emit('add-label', label);\n }\n },\n\n removeLabel(index) {\n this.$emit('remove-label', index);\n },\n\n makeLabel(startOffset, endOffset) {\n const label = {\n id: 0,\n label: -1,\n start_offset: startOffset,\n end_offset: endOffset,\n };\n return label;\n },\n },\n\n watch: {\n entityPositions() {\n this.resetRange();\n },\n },\n\n computed: {\n sortedEntityPositions() {\n this.entityPositions = this.entityPositions.sort((a, b) => a.start_offset - b.start_offset);\n return this.entityPositions;\n },\n\n chunks() {\n const res = [];\n let left = 0;\n for (let i = 0; i < this.sortedEntityPositions.length; i++) {\n const e = this.sortedEntityPositions[i];\n const l = this.makeLabel(left, e.start_offset);\n res.push(l);\n res.push(e);\n left = e.end_offset;\n }\n const l = this.makeLabel(left, this.text.length);\n res.push(l);\n\n return res;\n },\n\n id2label() {\n let id2label = {};\n // default value;\n id2label[-1] = {\n text_color: '',\n background_color: '',\n };\n for (let i = 0; i < this.labels.length; i++) {\n const label = this.labels[i];\n id2label[label.id] = label;\n }\n return id2label;\n },\n },\n});\n\nconst vm = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"]({\n el: '#mail-app',\n delimiters: ['[[', ']]'],\n mixins: [_mixin__WEBPACK_IMPORTED_MODULE_1__[\"default\"]],\n methods: {\n annotate(labelId) {\n this.$refs.annotator.addLabel(labelId);\n },\n\n addLabel(annotation) {\n const docId = this.docs[this.pageNumber].id;\n _http__WEBPACK_IMPORTED_MODULE_2__[\"default\"].post(`docs/${docId}/annotations/`, annotation).then((response) => {\n this.annotations[this.pageNumber].push(response.data);\n });\n },\n },\n});\n\n\n//# sourceURL=webpack:///./static/js/sequence_labeling.js?"); /***/ }) diff --git a/app/server/static/js/document_classification.js b/app/server/static/js/document_classification.js index 8ead902a..c2734901 100644 --- a/app/server/static/js/document_classification.js +++ b/app/server/static/js/document_classification.js @@ -1,11 +1,14 @@ import Vue from 'vue'; import annotationMixin from './mixin'; import HTTP from './http'; +import simpleShortcut from './filter'; Vue.use(require('vue-shortkey'), { prevent: ['input', 'textarea'], }); +Vue.filter('simpleShortcut', simpleShortcut); + const vm = new Vue({ el: '#mail-app', diff --git a/app/server/static/js/filter.js b/app/server/static/js/filter.js new file mode 100644 index 00000000..ce94eb09 --- /dev/null +++ b/app/server/static/js/filter.js @@ -0,0 +1,10 @@ +export default function simpleShortcut(shortcut) { + if (shortcut === null) { + shortcut = ''; + } else { + shortcut = shortcut.replace('ctrl', 'C'); + shortcut = shortcut.replace('shift', 'S'); + shortcut = shortcut.split(' ').join('-'); + } + return shortcut; +} diff --git a/app/server/static/js/label.js b/app/server/static/js/label.js index 8909cbf0..7774dc9c 100644 --- a/app/server/static/js/label.js +++ b/app/server/static/js/label.js @@ -1,5 +1,8 @@ import Vue from 'vue'; import HTTP from './http'; +import simpleShortcut from './filter'; + +Vue.filter('simpleShortcut', simpleShortcut); const vm = new Vue({ @@ -8,16 +11,53 @@ const vm = new Vue({ data: { labels: [], labelText: '', - selectedShortkey: '', + selectedKey: '', + checkedKey: [], + shortcutKey: '', backgroundColor: '#209cee', textColor: '#ffffff', }, + computed: { + /** + * combineKeys: Combine selectedKey and checkedKey to get shortcutKey + * saveKeys: Save null to database if shortcutKey is empty string + */ + combineKeys: function () { + this.shortcutKey = ''; + + // If checkedKey exits, add it to shortcutKey + if (this.checkedKey.length > 0) { + this.checkedKey.sort(); + this.shortcutKey = this.checkedKey.join(' '); + + // If selectedKey exist, add it to shortcutKey + if (this.selectedKey.length !== 0) { + this.shortcutKey = this.shortcutKey + ' ' + this.selectedKey; + } + } + + // If only selectedKey exist, assign to shortcutKey + if (this.shortcutKey.length === 0 && this.selectedKey.length !== 0) { + this.shortcutKey = this.selectedKey; + } + return this.shortcutKey; + }, + + saveKeys: function () { + this.shortcutKey = this.combineKeys; + if (this.shortcutKey === '') { + return null; + } + return this.shortcutKey; + }, + }, + methods: { addLabel() { const payload = { text: this.labelText, - shortcut: this.selectedShortkey, + shortcut: this.saveKeys, background_color: this.backgroundColor, text_color: this.textColor, }; @@ -37,7 +77,9 @@ const vm = new Vue({ reset() { this.labelText = ''; - this.selectedShortkey = ''; + this.selectedKey = ''; + this.checkedKey = []; + this.shortcutKey = ''; this.backgroundColor = '#209cee'; this.textColor = '#ffffff'; }, diff --git a/app/server/static/js/mixin.js b/app/server/static/js/mixin.js index 1de7b7f1..737ad578 100644 --- a/app/server/static/js/mixin.js +++ b/app/server/static/js/mixin.js @@ -117,6 +117,14 @@ const annotationMixin = { this.annotations[this.pageNumber].splice(index, 1); }); }, + + replaceNull(shortcut) { + if (shortcut === null) { + shortcut = ''; + } + shortcut = shortcut.split(' '); + return shortcut; + }, }, watch: { diff --git a/app/server/static/js/sequence_labeling.js b/app/server/static/js/sequence_labeling.js index 6804fdf2..055fe924 100644 --- a/app/server/static/js/sequence_labeling.js +++ b/app/server/static/js/sequence_labeling.js @@ -1,11 +1,14 @@ import Vue from 'vue'; import annotationMixin from './mixin'; import HTTP from './http'; +import simpleShortcut from './filter'; Vue.use(require('vue-shortkey'), { prevent: ['input', 'textarea'], }); +Vue.filter('simpleShortcut', simpleShortcut); + Vue.component('annotator', { template: '
\
-
@@ -24,7 +23,7 @@ [[ label.text ]] - [[ label.shortcut ]] + [[ label.shortcut | simpleShortcut ]]
@@ -36,23 +35,29 @@ [[ labelText ]] - [[ selectedShortkey ]] + [[ combineKeys | simpleShortcut ]]
- +
+ +

required

+
- -
+
+ +

optional

+
+
- {% for ch in 'abcdefghijklmnopqrstuvwxyz' %} @@ -60,18 +65,31 @@
+
+ + +
+
+ + +
- - +
+ +

optional

+
- +
+ +

optional

+
diff --git a/app/server/templates/annotation/document_classification.html b/app/server/templates/annotation/document_classification.html index 9dbe3fe7..fc40c5b4 100644 --- a/app/server/templates/annotation/document_classification.html +++ b/app/server/templates/annotation/document_classification.html @@ -8,10 +8,10 @@
diff --git a/app/server/templates/annotation/sequence_labeling.html b/app/server/templates/annotation/sequence_labeling.html index 08139081..522ed2a5 100644 --- a/app/server/templates/annotation/sequence_labeling.html +++ b/app/server/templates/annotation/sequence_labeling.html @@ -8,10 +8,10 @@
diff --git a/app/server/templates/base.html b/app/server/templates/base.html index c8a4c25c..42e16cf4 100644 --- a/app/server/templates/base.html +++ b/app/server/templates/base.html @@ -14,6 +14,7 @@ +