Compare commits
No commits in common. "518a245133a8c8c1d46555f8b0fdecb8b6da0855" and "9ac626c64d06db516a2f84fd0c486703f0c26a55" have entirely different histories.
518a245133
...
9ac626c64d
@ -8,6 +8,5 @@
|
|||||||
!.flaskenv
|
!.flaskenv
|
||||||
!boot.sh
|
!boot.sh
|
||||||
!config.py
|
!config.py
|
||||||
!docker-nopaque-entrypoint.sh
|
|
||||||
!nopaque.py
|
!nopaque.py
|
||||||
!requirements.txt
|
!requirements.txt
|
||||||
|
210
.env.tpl
@ -1,32 +1,204 @@
|
|||||||
##############################################################################
|
################################################################################
|
||||||
# Variables for use in Docker Compose YAML files #
|
# Docker #
|
||||||
##############################################################################
|
################################################################################
|
||||||
|
# DEFAULT: ./data
|
||||||
|
# NOTE: Use `.` as <project-basedir>
|
||||||
|
# HOST_DATA_DIR=
|
||||||
|
|
||||||
|
# Example: 1000
|
||||||
# HINT: Use this bash command `id -u`
|
# HINT: Use this bash command `id -u`
|
||||||
# NOTE: 0 (= root user) is not allowed
|
|
||||||
HOST_UID=
|
HOST_UID=
|
||||||
|
|
||||||
|
# Example: 1000
|
||||||
# HINT: Use this bash command `id -g`
|
# HINT: Use this bash command `id -g`
|
||||||
HOST_GID=
|
HOST_GID=
|
||||||
|
|
||||||
|
# Example: 999
|
||||||
# HINT: Use this bash command `getent group docker | cut -d: -f3`
|
# HINT: Use this bash command `getent group docker | cut -d: -f3`
|
||||||
HOST_DOCKER_GID=
|
HOST_DOCKER_GID=
|
||||||
|
|
||||||
# DEFAULT: nopaque
|
# DEFAULT: ./logs
|
||||||
# DOCKER_DEFAULT_NETWORK_NAME=
|
# NOTES: Use `.` as <project-basedir>
|
||||||
|
# HOST_LOG_DIR=
|
||||||
|
|
||||||
# DEFAULT: ./volumes/db/data
|
# DEFAULT: nopaque_default
|
||||||
# NOTE: Use `.` as <project-basedir>
|
# DOCKER_NETWORK_NAME=
|
||||||
# DOCKER_DB_SERVICE_DATA_VOLUME_SOURCE_PATH=
|
|
||||||
|
|
||||||
# DEFAULT: ./volumes/mq/data
|
################################################################################
|
||||||
# NOTE: Use `.` as <project-basedir>
|
# Flask #
|
||||||
# DOCKER_MQ_SERVICE_DATA_VOLUME_SOURCE_PATH=
|
# https://flask.palletsprojects.com/en/1.1.x/config/ #
|
||||||
|
################################################################################
|
||||||
|
# CHOOSE ONE: http, https
|
||||||
|
# DEFAULT: http
|
||||||
|
# PREFERRED_URL_SCHEME=
|
||||||
|
|
||||||
# NOTE: This must be a network share and it must be available on all
|
# DEFAULT: hard to guess string
|
||||||
# Docker Swarm nodes, mounted to the same path with the same
|
# HINT: Use this bash command `python -c "import uuid; print(uuid.uuid4().hex)"`
|
||||||
# user and group ownership.
|
# SECRET_KEY=
|
||||||
DOCKER_NOPAQUE_SERVICE_DATA_VOLUME_SOURCE_PATH=
|
|
||||||
|
|
||||||
# DEFAULT: ./volumes/nopaque/logs
|
# DEFAULT: localhost:5000
|
||||||
# NOTE: Use `.` as <project-basedir>
|
# Example: nopaque.example.com/nopaque.example.com:5000
|
||||||
# DOCKER_NOPAQUE_SERVICE_LOGS_VOLUME_SOURCE_PATH=.
|
# HINT: If your instance is publicly available on a different Port then 80/443,
|
||||||
|
# you will have to add this to the server name
|
||||||
|
# SERVER_NAME=
|
||||||
|
|
||||||
|
# CHOOSE ONE: False, True
|
||||||
|
# DEFAULT: False
|
||||||
|
# HINT: Set to true if you redirect http to https
|
||||||
|
# SESSION_COOKIE_SECURE=
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Flask-Assets #
|
||||||
|
# https://webassets.readthedocs.io/en/latest/ #
|
||||||
|
################################################################################
|
||||||
|
# CHOOSE ONE: False, True
|
||||||
|
# DEFAULT: False
|
||||||
|
# ASSETS_DEBUG=
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Flask-Hashids #
|
||||||
|
# https://github.com/Pevtrick/Flask-Hashids #
|
||||||
|
################################################################################
|
||||||
|
# DEFAULT: 16
|
||||||
|
# HASHIDS_MIN_LENGTH=
|
||||||
|
|
||||||
|
# NOTE: Use this bash command `python -c "import uuid; print(uuid.uuid4().hex)"`
|
||||||
|
# It is strongly recommended that this is NEVER the same as the SECRET_KEY
|
||||||
|
HASHIDS_SALT=
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Flask-Login #
|
||||||
|
# https://flask-login.readthedocs.io/en/latest/ #
|
||||||
|
################################################################################
|
||||||
|
# CHOOSE ONE: False, True
|
||||||
|
# DEFAULT: False
|
||||||
|
# HINT: Set to true if you redirect http to https
|
||||||
|
# REMEMBER_COOKIE_SECURE=
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Flask-Mail #
|
||||||
|
# https://pythonhosted.org/Flask-Mail/ #
|
||||||
|
################################################################################
|
||||||
|
# EXAMPLE: nopaque Admin <nopaque@example.com>
|
||||||
|
MAIL_DEFAULT_SENDER=
|
||||||
|
|
||||||
|
MAIL_PASSWORD=
|
||||||
|
|
||||||
|
# EXAMPLE: smtp.example.com
|
||||||
|
MAIL_SERVER=
|
||||||
|
|
||||||
|
# EXAMPLE: 587
|
||||||
|
MAIL_PORT=
|
||||||
|
|
||||||
|
# CHOOSE ONE: False, True
|
||||||
|
# DEFAULT: False
|
||||||
|
# MAIL_USE_SSL=
|
||||||
|
|
||||||
|
# CHOOSE ONE: False, True
|
||||||
|
# DEFAULT: False
|
||||||
|
# MAIL_USE_TLS=
|
||||||
|
|
||||||
|
# EXAMPLE: nopaque@example.com
|
||||||
|
MAIL_USERNAME=
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Flask-SQLAlchemy #
|
||||||
|
# https://flask-sqlalchemy.palletsprojects.com/en/2.x/config/ #
|
||||||
|
################################################################################
|
||||||
|
# DEFAULT: 'sqlite:///<nopaque-basedir>/data.sqlite'
|
||||||
|
# NOTE: Use `.` as <nopaque-basedir>,
|
||||||
|
# Don't use a SQLite database when using Docker
|
||||||
|
# SQLALCHEMY_DATABASE_URI=
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# nopaque #
|
||||||
|
################################################################################
|
||||||
|
# An account is registered with this email adress gets automatically assigned
|
||||||
|
# the administrator role.
|
||||||
|
# EXAMPLE: admin.nopaque@example.com
|
||||||
|
NOPAQUE_ADMIN=
|
||||||
|
|
||||||
|
# DEFAULT: /mnt/nopaque
|
||||||
|
# NOTE: This must be a network share and it must be available on all Docker
|
||||||
|
# Swarm nodes
|
||||||
|
# NOPAQUE_DATA_DIR=
|
||||||
|
|
||||||
|
# CHOOSE ONE: False, True
|
||||||
|
# DEFAULT: True
|
||||||
|
# NOPAQUE_IS_PRIMARY_INSTANCE=
|
||||||
|
|
||||||
|
# transport://[userid:password]@hostname[:port]/[virtual_host]
|
||||||
|
NOPAQUE_SOCKETIO_MESSAGE_QUEUE_URI=
|
||||||
|
|
||||||
|
# NOTE: Get these from the nopaque development team
|
||||||
|
NOPAQUE_DOCKER_REGISTRY_USERNAME=
|
||||||
|
NOPAQUE_DOCKER_REGISTRY_PASSWORD=
|
||||||
|
|
||||||
|
# DEFAULT: %Y-%m-%d %H:%M:%S
|
||||||
|
# NOPAQUE_LOG_DATE_FORMAT=
|
||||||
|
|
||||||
|
# DEFAULT: [%(asctime)s] %(levelname)s in %(pathname)s (function: %(funcName)s, line: %(lineno)d): %(message)s
|
||||||
|
# NOPAQUE_LOG_FORMAT=
|
||||||
|
|
||||||
|
# DEFAULT: INFO
|
||||||
|
# CHOOSE ONE: CRITICAL, ERROR, WARNING, INFO, DEBUG
|
||||||
|
# NOPAQUE_LOG_LEVEL=
|
||||||
|
|
||||||
|
# CHOOSE ONE: False, True
|
||||||
|
# DEFAULT: True
|
||||||
|
# NOPAQUE_LOG_FILE_ENABLED=
|
||||||
|
|
||||||
|
# DEFAULT: <nopaque-basedir>/logs
|
||||||
|
# NOTE: Use `.` as <nopaque-basedir>
|
||||||
|
# NOPAQUE_LOG_FILE_DIR=
|
||||||
|
|
||||||
|
# DEFAULT: NOPAQUE_LOG_LEVEL
|
||||||
|
# CHOOSE ONE: CRITICAL, ERROR, WARNING, INFO, DEBUG
|
||||||
|
# NOPAQUE_LOG_FILE_LEVEL=
|
||||||
|
|
||||||
|
# CHOOSE ONE: False, True
|
||||||
|
# DEFAULT: False
|
||||||
|
# NOPAQUE_LOG_STDERR_ENABLED=
|
||||||
|
|
||||||
|
# CHOOSE ONE: CRITICAL, ERROR, WARNING, INFO, DEBUG
|
||||||
|
# DEFAULT: NOPAQUE_LOG_LEVEL
|
||||||
|
# NOPAQUE_LOG_STDERR_LEVEL=
|
||||||
|
|
||||||
|
# CHOOSE ONE: False, True
|
||||||
|
# DEFAULT: False
|
||||||
|
# HINT: Set this to True only if you are using a proxy in front of nopaque
|
||||||
|
# NOPAQUE_PROXY_FIX_ENABLED=
|
||||||
|
|
||||||
|
# DEFAULT: 0
|
||||||
|
# Number of values to trust for X-Forwarded-For
|
||||||
|
# NOPAQUE_PROXY_FIX_X_FOR=
|
||||||
|
|
||||||
|
# DEFAULT: 0
|
||||||
|
# Number of values to trust for X-Forwarded-Host
|
||||||
|
# NOPAQUE_PROXY_FIX_X_HOST=
|
||||||
|
|
||||||
|
# DEFAULT: 0
|
||||||
|
# Number of values to trust for X-Forwarded-Port
|
||||||
|
# NOPAQUE_PROXY_FIX_X_PORT=
|
||||||
|
|
||||||
|
# DEFAULT: 0
|
||||||
|
# Number of values to trust for X-Forwarded-Prefix
|
||||||
|
# NOPAQUE_PROXY_FIX_X_PREFIX=
|
||||||
|
|
||||||
|
# DEFAULT: 0
|
||||||
|
# Number of values to trust for X-Forwarded-Proto
|
||||||
|
# NOPAQUE_PROXY_FIX_X_PROTO=
|
||||||
|
|
||||||
|
# CHOOSE ONE: False, True
|
||||||
|
# DEFAULT: False
|
||||||
|
# NOPAQUE_TRANSKRIBUS_ENABLED=
|
||||||
|
|
||||||
|
# READ-COOP account data: https://readcoop.eu/
|
||||||
|
# NOPAQUE_READCOOP_USERNAME=
|
||||||
|
# NOPAQUE_READCOOP_PASSWORD=
|
||||||
|
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
|||||||
# nopaque specifics
|
# nopaque specifics
|
||||||
app/static/gen/
|
app/static/gen/
|
||||||
volumes/
|
data/
|
||||||
docker-compose.override.yml
|
docker-compose.override.yml
|
||||||
logs/
|
logs/
|
||||||
!logs/dummy
|
!logs/dummy
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
include:
|
|
||||||
- template: Security/Container-Scanning.gitlab-ci.yml
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# Pipeline stages in order of execution #
|
|
||||||
##############################################################################
|
|
||||||
stages:
|
|
||||||
- build
|
|
||||||
- publish
|
|
||||||
- sca
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# Pipeline behavior #
|
|
||||||
##############################################################################
|
|
||||||
workflow:
|
|
||||||
rules:
|
|
||||||
# Run the pipeline on commits to the default branch
|
|
||||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
||||||
variables:
|
|
||||||
# Set the Docker image tag to `latest`
|
|
||||||
DOCKER_IMAGE: $CI_REGISTRY_IMAGE:latest
|
|
||||||
when: always
|
|
||||||
# Run the pipeline on tag creation
|
|
||||||
- if: $CI_COMMIT_TAG
|
|
||||||
variables:
|
|
||||||
# Set the Docker image tag to the Git tag name
|
|
||||||
DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
|
|
||||||
when: always
|
|
||||||
# Don't run the pipeline on all other occasions
|
|
||||||
- when: never
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# Default values for pipeline jobs #
|
|
||||||
##############################################################################
|
|
||||||
default:
|
|
||||||
image: docker:24.0.6
|
|
||||||
services:
|
|
||||||
- docker:24.0.6-dind
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# CI/CD variables for all jobs in the pipeline #
|
|
||||||
##############################################################################
|
|
||||||
variables:
|
|
||||||
DOCKER_TLS_CERTDIR: /certs
|
|
||||||
DOCKER_BUILD_PATH: .
|
|
||||||
DOCKERFILE: Dockerfile
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# Pipeline jobs #
|
|
||||||
##############################################################################
|
|
||||||
build:
|
|
||||||
stage: build
|
|
||||||
script:
|
|
||||||
- docker build --tag $DOCKER_IMAGE --file $DOCKERFILE $DOCKER_BUILD_PATH
|
|
||||||
- docker save $DOCKER_IMAGE > docker_image.tar
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- docker_image.tar
|
|
||||||
|
|
||||||
publish:
|
|
||||||
stage: publish
|
|
||||||
before_script:
|
|
||||||
- docker login --username gitlab-ci-token --password $CI_JOB_TOKEN $CI_REGISTRY
|
|
||||||
script:
|
|
||||||
- docker load --input docker_image.tar
|
|
||||||
- docker push $DOCKER_IMAGE
|
|
||||||
after_script:
|
|
||||||
- docker logout $CI_REGISTRY
|
|
||||||
|
|
||||||
container_scanning:
|
|
||||||
stage: sca
|
|
||||||
rules:
|
|
||||||
# Run the job on commits to the default branch
|
|
||||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
||||||
when: always
|
|
||||||
# Run the job on tag creation
|
|
||||||
- if: $CI_COMMIT_TAG
|
|
||||||
when: always
|
|
||||||
# Don't run the job on all other occasions
|
|
||||||
- when: never
|
|
||||||
variables:
|
|
||||||
CS_IMAGE: $DOCKER_IMAGE
|
|
5
.vscode/extensions.json
vendored
@ -1,8 +1,7 @@
|
|||||||
{
|
{
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"irongeek.vscode-env",
|
"samuelcolvin.jinjahtml",
|
||||||
"ms-azuretools.vscode-docker",
|
"ms-azuretools.vscode-docker",
|
||||||
"ms-python.python",
|
"ms-python.python"
|
||||||
"samuelcolvin.jinjahtml"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
6
.vscode/settings.json
vendored
@ -1,9 +1,13 @@
|
|||||||
{
|
{
|
||||||
"editor.rulers": [79],
|
"editor.rulers": [79],
|
||||||
"files.insertFinalNewline": true,
|
"files.insertFinalNewline": true,
|
||||||
|
"python.terminal.activateEnvironment": false,
|
||||||
"[css]": {
|
"[css]": {
|
||||||
"editor.tabSize": 2
|
"editor.tabSize": 2
|
||||||
},
|
},
|
||||||
|
"[scss]": {
|
||||||
|
"editor.tabSize": 2
|
||||||
|
},
|
||||||
"[html]": {
|
"[html]": {
|
||||||
"editor.tabSize": 2
|
"editor.tabSize": 2
|
||||||
},
|
},
|
||||||
@ -13,7 +17,7 @@
|
|||||||
"[jinja-html]": {
|
"[jinja-html]": {
|
||||||
"editor.tabSize": 2
|
"editor.tabSize": 2
|
||||||
},
|
},
|
||||||
"[scss]": {
|
"[jinja-js]": {
|
||||||
"editor.tabSize": 2
|
"editor.tabSize": 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
41
Dockerfile
@ -1,9 +1,14 @@
|
|||||||
FROM python:3.10.13-slim-bookworm
|
FROM python:3.8.10-slim-buster
|
||||||
|
|
||||||
|
|
||||||
LABEL authors="Patrick Jentsch <p.jentsch@uni-bielefeld.de>"
|
LABEL authors="Patrick Jentsch <p.jentsch@uni-bielefeld.de>"
|
||||||
|
|
||||||
|
|
||||||
|
ARG DOCKER_GID
|
||||||
|
ARG UID
|
||||||
|
ARG GID
|
||||||
|
|
||||||
|
|
||||||
ENV LANG="C.UTF-8"
|
ENV LANG="C.UTF-8"
|
||||||
ENV PYTHONDONTWRITEBYTECODE="1"
|
ENV PYTHONDONTWRITEBYTECODE="1"
|
||||||
ENV PYTHONUNBUFFERED="1"
|
ENV PYTHONUNBUFFERED="1"
|
||||||
@ -12,42 +17,34 @@ ENV PYTHONUNBUFFERED="1"
|
|||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install --no-install-recommends --yes \
|
&& apt-get install --no-install-recommends --yes \
|
||||||
build-essential \
|
build-essential \
|
||||||
gosu \
|
|
||||||
libpq-dev \
|
libpq-dev \
|
||||||
&& rm --recursive /var/lib/apt/lists/*
|
&& rm --recursive /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|
||||||
RUN useradd --create-home --no-log-init nopaque \
|
RUN groupadd --gid "${DOCKER_GID}" docker \
|
||||||
&& groupadd docker \
|
&& groupadd --gid "${GID}" nopaque \
|
||||||
&& usermod --append --groups docker nopaque
|
&& useradd --create-home --gid nopaque --groups "${DOCKER_GID}" --no-log-init --uid "${UID}" nopaque
|
||||||
|
|
||||||
|
|
||||||
USER nopaque
|
USER nopaque
|
||||||
WORKDIR /home/nopaque
|
WORKDIR /home/nopaque
|
||||||
|
|
||||||
|
|
||||||
ENV NOPAQUE_PYTHON3_VENV_PATH="/home/nopaque/.venv"
|
ENV PYTHON3_VENV_PATH="/home/nopaque/venv"
|
||||||
RUN python3 -m venv "${NOPAQUE_PYTHON3_VENV_PATH}"
|
RUN python3 -m venv "${PYTHON3_VENV_PATH}"
|
||||||
ENV PATH="${NOPAQUE_PYTHON3_VENV_PATH}/bin:${PATH}"
|
ENV PATH="${PYTHON3_VENV_PATH}/bin:${PATH}"
|
||||||
|
|
||||||
|
|
||||||
|
COPY --chown=nopaque:nopaque requirements.txt .
|
||||||
|
RUN python3 -m pip install --requirement requirements.txt \
|
||||||
|
&& rm requirements.txt
|
||||||
|
|
||||||
|
|
||||||
COPY --chown=nopaque:nopaque app app
|
COPY --chown=nopaque:nopaque app app
|
||||||
COPY --chown=nopaque:nopaque migrations migrations
|
COPY --chown=nopaque:nopaque migrations migrations
|
||||||
COPY --chown=nopaque:nopaque tests tests
|
COPY --chown=nopaque:nopaque tests tests
|
||||||
COPY --chown=nopaque:nopaque .flaskenv boot.sh config.py nopaque.py requirements.txt ./
|
COPY --chown=nopaque:nopaque .flaskenv boot.sh config.py nopaque.py ./
|
||||||
|
|
||||||
|
|
||||||
RUN python3 -m pip install --requirement requirements.txt \
|
|
||||||
&& mkdir logs
|
|
||||||
|
|
||||||
|
|
||||||
USER root
|
|
||||||
|
|
||||||
|
|
||||||
COPY docker-nopaque-entrypoint.sh /usr/local/bin/
|
|
||||||
|
|
||||||
|
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|
||||||
|
|
||||||
ENTRYPOINT ["docker-nopaque-entrypoint.sh"]
|
ENTRYPOINT ["./boot.sh"]
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
# nopaque
|
# nopaque
|
||||||
|
|
||||||
![release badge](https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque/-/badges/release.svg)
|
|
||||||
![pipeline badge](https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque/badges/master/pipeline.svg?ignore_skipped=true)
|
|
||||||
|
|
||||||
nopaque bundles various tools and services that provide humanities scholars with DH methods and thus can support their various individual research processes. Using nopaque, researchers can subject digitized sources to Optical Character Recognition (OCR). The resulting text files can then be used as a data basis for Natural Language Processing (NLP). The texts are automatically subjected to various linguistic annotations. The data processed via NLP can then be summarized in the web application as corpora and analyzed by means of an information retrieval system through complex search queries. The range of functions of the web application will be successively extended according to the needs of the researchers.
|
nopaque bundles various tools and services that provide humanities scholars with DH methods and thus can support their various individual research processes. Using nopaque, researchers can subject digitized sources to Optical Character Recognition (OCR). The resulting text files can then be used as a data basis for Natural Language Processing (NLP). The texts are automatically subjected to various linguistic annotations. The data processed via NLP can then be summarized in the web application as corpora and analyzed by means of an information retrieval system through complex search queries. The range of functions of the web application will be successively extended according to the needs of the researchers.
|
||||||
|
|
||||||
## Prerequisites and requirements
|
## Prerequisites and requirements
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
pipeline_name: 'ca_core_news_md'
|
pipeline_name: 'ca_core_news_md'
|
||||||
version: '3.2.0'
|
version: '3.2.0'
|
||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- title: 'German'
|
- title: 'German'
|
||||||
description: 'German pipeline optimized for CPU. Components: tok2vec, tagger, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
|
description: 'German pipeline optimized for CPU. Components: tok2vec, tagger, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
|
||||||
url: 'https://github.com/explosion/spacy-models/releases/download/de_core_news_md-3.2.0/de_core_news_md-3.2.0.tar.gz'
|
url: 'https://github.com/explosion/spacy-models/releases/download/de_core_news_md-3.2.0/de_core_news_md-3.2.0.tar.gz'
|
||||||
@ -19,7 +19,7 @@
|
|||||||
pipeline_name: 'de_core_news_md'
|
pipeline_name: 'de_core_news_md'
|
||||||
version: '3.2.0'
|
version: '3.2.0'
|
||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- title: 'Greek'
|
- title: 'Greek'
|
||||||
description: 'Greek pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
|
description: 'Greek pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
|
||||||
url: 'https://github.com/explosion/spacy-models/releases/download/el_core_news_md-3.2.0/el_core_news_md-3.2.0.tar.gz'
|
url: 'https://github.com/explosion/spacy-models/releases/download/el_core_news_md-3.2.0/el_core_news_md-3.2.0.tar.gz'
|
||||||
@ -120,6 +120,7 @@
|
|||||||
version: '3.4.0'
|
version: '3.4.0'
|
||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
|
- '0.1.2'
|
||||||
- title: 'German'
|
- title: 'German'
|
||||||
description: 'German pipeline optimized for CPU. Components: tok2vec, tagger, morphologizer, parser, lemmatizer (trainable_lemmatizer), senter, ner.'
|
description: 'German pipeline optimized for CPU. Components: tok2vec, tagger, morphologizer, parser, lemmatizer (trainable_lemmatizer), senter, ner.'
|
||||||
url: 'https://github.com/explosion/spacy-models/releases/download/de_core_news_md-3.4.0/de_core_news_md-3.4.0.tar.gz'
|
url: 'https://github.com/explosion/spacy-models/releases/download/de_core_news_md-3.4.0/de_core_news_md-3.4.0.tar.gz'
|
||||||
@ -131,6 +132,7 @@
|
|||||||
version: '3.4.0'
|
version: '3.4.0'
|
||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
|
- '0.1.2'
|
||||||
- title: 'Greek'
|
- title: 'Greek'
|
||||||
description: 'Greek pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, lemmatizer (trainable_lemmatizer), senter, ner, attribute_ruler.'
|
description: 'Greek pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, lemmatizer (trainable_lemmatizer), senter, ner, attribute_ruler.'
|
||||||
url: 'https://github.com/explosion/spacy-models/releases/download/el_core_news_md-3.4.0/el_core_news_md-3.4.0.tar.gz'
|
url: 'https://github.com/explosion/spacy-models/releases/download/el_core_news_md-3.4.0/el_core_news_md-3.4.0.tar.gz'
|
||||||
@ -142,6 +144,7 @@
|
|||||||
version: '3.4.0'
|
version: '3.4.0'
|
||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
|
- '0.1.2'
|
||||||
- title: 'English'
|
- title: 'English'
|
||||||
description: 'English pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler, lemmatizer.'
|
description: 'English pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler, lemmatizer.'
|
||||||
url: 'https://github.com/explosion/spacy-models/releases/download/en_core_web_md-3.4.1/en_core_web_md-3.4.1.tar.gz'
|
url: 'https://github.com/explosion/spacy-models/releases/download/en_core_web_md-3.4.1/en_core_web_md-3.4.1.tar.gz'
|
||||||
@ -153,6 +156,7 @@
|
|||||||
version: '3.4.1'
|
version: '3.4.1'
|
||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
|
- '0.1.2'
|
||||||
- title: 'Spanish'
|
- title: 'Spanish'
|
||||||
description: 'Spanish pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
|
description: 'Spanish pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
|
||||||
url: 'https://github.com/explosion/spacy-models/releases/download/es_core_news_md-3.4.0/es_core_news_md-3.4.0.tar.gz'
|
url: 'https://github.com/explosion/spacy-models/releases/download/es_core_news_md-3.4.0/es_core_news_md-3.4.0.tar.gz'
|
||||||
@ -164,6 +168,7 @@
|
|||||||
version: '3.4.0'
|
version: '3.4.0'
|
||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
|
- '0.1.2'
|
||||||
- title: 'French'
|
- title: 'French'
|
||||||
description: 'French pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
|
description: 'French pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
|
||||||
url: 'https://github.com/explosion/spacy-models/releases/download/fr_core_news_md-3.4.0/fr_core_news_md-3.4.0.tar.gz'
|
url: 'https://github.com/explosion/spacy-models/releases/download/fr_core_news_md-3.4.0/fr_core_news_md-3.4.0.tar.gz'
|
||||||
@ -175,6 +180,7 @@
|
|||||||
version: '3.4.0'
|
version: '3.4.0'
|
||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
|
- '0.1.2'
|
||||||
- title: 'Italian'
|
- title: 'Italian'
|
||||||
description: 'Italian pipeline optimized for CPU. Components: tok2vec, morphologizer, tagger, parser, lemmatizer (trainable_lemmatizer), senter, ner'
|
description: 'Italian pipeline optimized for CPU. Components: tok2vec, morphologizer, tagger, parser, lemmatizer (trainable_lemmatizer), senter, ner'
|
||||||
url: 'https://github.com/explosion/spacy-models/releases/download/it_core_news_md-3.4.0/it_core_news_md-3.4.0.tar.gz'
|
url: 'https://github.com/explosion/spacy-models/releases/download/it_core_news_md-3.4.0/it_core_news_md-3.4.0.tar.gz'
|
||||||
@ -186,6 +192,7 @@
|
|||||||
version: '3.4.0'
|
version: '3.4.0'
|
||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
|
- '0.1.2'
|
||||||
- title: 'Polish'
|
- title: 'Polish'
|
||||||
description: 'Polish pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, lemmatizer (trainable_lemmatizer), tagger, senter, ner.'
|
description: 'Polish pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, lemmatizer (trainable_lemmatizer), tagger, senter, ner.'
|
||||||
url: 'https://github.com/explosion/spacy-models/releases/download/pl_core_news_md-3.4.0/pl_core_news_md-3.4.0.tar.gz'
|
url: 'https://github.com/explosion/spacy-models/releases/download/pl_core_news_md-3.4.0/pl_core_news_md-3.4.0.tar.gz'
|
||||||
@ -197,6 +204,7 @@
|
|||||||
version: '3.4.0'
|
version: '3.4.0'
|
||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
|
- '0.1.2'
|
||||||
- title: 'Russian'
|
- title: 'Russian'
|
||||||
description: 'Russian pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
|
description: 'Russian pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
|
||||||
url: 'https://github.com/explosion/spacy-models/releases/download/ru_core_news_md-3.4.0/ru_core_news_md-3.4.0.tar.gz'
|
url: 'https://github.com/explosion/spacy-models/releases/download/ru_core_news_md-3.4.0/ru_core_news_md-3.4.0.tar.gz'
|
||||||
@ -208,6 +216,7 @@
|
|||||||
version: '3.4.0'
|
version: '3.4.0'
|
||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
|
- '0.1.2'
|
||||||
- title: 'Chinese'
|
- title: 'Chinese'
|
||||||
description: 'Chinese pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler.'
|
description: 'Chinese pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler.'
|
||||||
url: 'https://github.com/explosion/spacy-models/releases/download/zh_core_web_md-3.4.0/zh_core_web_md-3.4.0.tar.gz'
|
url: 'https://github.com/explosion/spacy-models/releases/download/zh_core_web_md-3.4.0/zh_core_web_md-3.4.0.tar.gz'
|
||||||
@ -219,3 +228,4 @@
|
|||||||
version: '3.4.0'
|
version: '3.4.0'
|
||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
|
- '0.1.2'
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Amharic'
|
# - title: 'Amharic'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/amh.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/amh.traineddata'
|
||||||
@ -21,7 +20,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
- title: 'Arabic'
|
- title: 'Arabic'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ara.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ara.traineddata'
|
||||||
@ -33,7 +31,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
# - title: 'Assamese'
|
# - title: 'Assamese'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/asm.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/asm.traineddata'
|
||||||
@ -45,7 +42,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Azerbaijani'
|
# - title: 'Azerbaijani'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/aze.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/aze.traineddata'
|
||||||
@ -57,7 +53,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Azerbaijani - Cyrillic'
|
# - title: 'Azerbaijani - Cyrillic'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/aze_cyrl.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/aze_cyrl.traineddata'
|
||||||
@ -69,7 +64,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Belarusian'
|
# - title: 'Belarusian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/bel.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/bel.traineddata'
|
||||||
@ -81,7 +75,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Bengali'
|
# - title: 'Bengali'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ben.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ben.traineddata'
|
||||||
@ -93,7 +86,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Tibetan'
|
# - title: 'Tibetan'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/bod.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/bod.traineddata'
|
||||||
@ -105,7 +97,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Bosnian'
|
# - title: 'Bosnian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/bos.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/bos.traineddata'
|
||||||
@ -117,7 +108,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Bulgarian'
|
# - title: 'Bulgarian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/bul.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/bul.traineddata'
|
||||||
@ -129,7 +119,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Catalan; Valencian'
|
# - title: 'Catalan; Valencian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/cat.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/cat.traineddata'
|
||||||
@ -141,7 +130,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Cebuano'
|
# - title: 'Cebuano'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ceb.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ceb.traineddata'
|
||||||
@ -153,7 +141,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Czech'
|
# - title: 'Czech'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ces.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ces.traineddata'
|
||||||
@ -165,7 +152,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Chinese - Simplified'
|
# - title: 'Chinese - Simplified'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/chi_sim.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/chi_sim.traineddata'
|
||||||
@ -177,7 +163,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
- title: 'Chinese - Traditional'
|
- title: 'Chinese - Traditional'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/chi_tra.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/chi_tra.traineddata'
|
||||||
@ -189,7 +174,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
# - title: 'Cherokee'
|
# - title: 'Cherokee'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/chr.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/chr.traineddata'
|
||||||
@ -201,7 +185,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Welsh'
|
# - title: 'Welsh'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/cym.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/cym.traineddata'
|
||||||
@ -213,7 +196,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
- title: 'Danish'
|
- title: 'Danish'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/dan.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/dan.traineddata'
|
||||||
@ -225,7 +207,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
- title: 'German'
|
- title: 'German'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/deu.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/deu.traineddata'
|
||||||
@ -237,7 +218,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
# - title: 'Dzongkha'
|
# - title: 'Dzongkha'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/dzo.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/dzo.traineddata'
|
||||||
@ -249,7 +229,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
- title: 'Greek, Modern (1453-)'
|
- title: 'Greek, Modern (1453-)'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ell.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ell.traineddata'
|
||||||
@ -261,7 +240,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
- title: 'English'
|
- title: 'English'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/eng.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/eng.traineddata'
|
||||||
@ -273,7 +251,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
- title: 'English, Middle (1100-1500)'
|
- title: 'English, Middle (1100-1500)'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/enm.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/enm.traineddata'
|
||||||
@ -285,7 +262,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
# - title: 'Esperanto'
|
# - title: 'Esperanto'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/epo.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/epo.traineddata'
|
||||||
@ -297,7 +273,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Estonian'
|
# - title: 'Estonian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/est.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/est.traineddata'
|
||||||
@ -309,7 +284,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Basque'
|
# - title: 'Basque'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/eus.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/eus.traineddata'
|
||||||
@ -321,7 +295,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Persian'
|
# - title: 'Persian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/fas.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/fas.traineddata'
|
||||||
@ -333,7 +306,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Finnish'
|
# - title: 'Finnish'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/fin.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/fin.traineddata'
|
||||||
@ -345,7 +317,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
- title: 'French'
|
- title: 'French'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/fra.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/fra.traineddata'
|
||||||
@ -357,7 +328,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
- title: 'German Fraktur'
|
- title: 'German Fraktur'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/frk.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/frk.traineddata'
|
||||||
@ -369,7 +339,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
- title: 'French, Middle (ca. 1400-1600)'
|
- title: 'French, Middle (ca. 1400-1600)'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/frm.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/frm.traineddata'
|
||||||
@ -381,7 +350,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
# - title: 'Irish'
|
# - title: 'Irish'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/gle.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/gle.traineddata'
|
||||||
@ -393,7 +361,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Galician'
|
# - title: 'Galician'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/glg.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/glg.traineddata'
|
||||||
@ -405,7 +372,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
- title: 'Greek, Ancient (-1453)'
|
- title: 'Greek, Ancient (-1453)'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/grc.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/grc.traineddata'
|
||||||
@ -417,7 +383,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
# - title: 'Gujarati'
|
# - title: 'Gujarati'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/guj.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/guj.traineddata'
|
||||||
@ -429,7 +394,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Haitian; Haitian Creole'
|
# - title: 'Haitian; Haitian Creole'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/hat.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/hat.traineddata'
|
||||||
@ -441,7 +405,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Hebrew'
|
# - title: 'Hebrew'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/heb.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/heb.traineddata'
|
||||||
@ -453,7 +416,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Hindi'
|
# - title: 'Hindi'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/hin.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/hin.traineddata'
|
||||||
@ -465,7 +427,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Croatian'
|
# - title: 'Croatian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/hrv.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/hrv.traineddata'
|
||||||
@ -477,7 +438,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Hungarian'
|
# - title: 'Hungarian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/hun.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/hun.traineddata'
|
||||||
@ -489,7 +449,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Inuktitut'
|
# - title: 'Inuktitut'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/iku.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/iku.traineddata'
|
||||||
@ -501,7 +460,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Indonesian'
|
# - title: 'Indonesian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ind.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ind.traineddata'
|
||||||
@ -513,7 +471,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Icelandic'
|
# - title: 'Icelandic'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/isl.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/isl.traineddata'
|
||||||
@ -525,7 +482,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
- title: 'Italian'
|
- title: 'Italian'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ita.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ita.traineddata'
|
||||||
@ -537,7 +493,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
- title: 'Italian - Old'
|
- title: 'Italian - Old'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ita_old.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ita_old.traineddata'
|
||||||
@ -549,7 +504,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
# - title: 'Javanese'
|
# - title: 'Javanese'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/jav.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/jav.traineddata'
|
||||||
@ -561,7 +515,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Japanese'
|
# - title: 'Japanese'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/jpn.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/jpn.traineddata'
|
||||||
@ -573,7 +526,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Kannada'
|
# - title: 'Kannada'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kan.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kan.traineddata'
|
||||||
@ -585,7 +537,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Georgian'
|
# - title: 'Georgian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kat.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kat.traineddata'
|
||||||
@ -597,7 +548,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Georgian - Old'
|
# - title: 'Georgian - Old'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kat_old.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kat_old.traineddata'
|
||||||
@ -609,7 +559,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Kazakh'
|
# - title: 'Kazakh'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kaz.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kaz.traineddata'
|
||||||
@ -621,7 +570,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Central Khmer'
|
# - title: 'Central Khmer'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/khm.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/khm.traineddata'
|
||||||
@ -633,7 +581,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Kirghiz; Kyrgyz'
|
# - title: 'Kirghiz; Kyrgyz'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kir.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kir.traineddata'
|
||||||
@ -645,7 +592,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Korean'
|
# - title: 'Korean'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kor.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kor.traineddata'
|
||||||
@ -657,7 +603,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Kurdish'
|
# - title: 'Kurdish'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kur.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/kur.traineddata'
|
||||||
@ -669,7 +614,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Lao'
|
# - title: 'Lao'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/lao.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/lao.traineddata'
|
||||||
@ -681,7 +625,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Latin'
|
# - title: 'Latin'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/lat.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/lat.traineddata'
|
||||||
@ -693,7 +636,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Latvian'
|
# - title: 'Latvian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/lav.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/lav.traineddata'
|
||||||
@ -705,7 +647,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Lithuanian'
|
# - title: 'Lithuanian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/lit.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/lit.traineddata'
|
||||||
@ -717,7 +658,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Malayalam'
|
# - title: 'Malayalam'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/mal.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/mal.traineddata'
|
||||||
@ -729,7 +669,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Marathi'
|
# - title: 'Marathi'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/mar.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/mar.traineddata'
|
||||||
@ -741,7 +680,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Macedonian'
|
# - title: 'Macedonian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/mkd.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/mkd.traineddata'
|
||||||
@ -753,7 +691,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Maltese'
|
# - title: 'Maltese'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/mlt.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/mlt.traineddata'
|
||||||
@ -765,7 +702,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Malay'
|
# - title: 'Malay'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/msa.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/msa.traineddata'
|
||||||
@ -777,7 +713,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Burmese'
|
# - title: 'Burmese'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/mya.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/mya.traineddata'
|
||||||
@ -789,7 +724,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Nepali'
|
# - title: 'Nepali'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/nep.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/nep.traineddata'
|
||||||
@ -801,7 +735,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Dutch; Flemish'
|
# - title: 'Dutch; Flemish'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/nld.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/nld.traineddata'
|
||||||
@ -813,7 +746,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Norwegian'
|
# - title: 'Norwegian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/nor.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/nor.traineddata'
|
||||||
@ -825,7 +757,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Oriya'
|
# - title: 'Oriya'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ori.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ori.traineddata'
|
||||||
@ -837,7 +768,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Panjabi; Punjabi'
|
# - title: 'Panjabi; Punjabi'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/pan.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/pan.traineddata'
|
||||||
@ -849,7 +779,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Polish'
|
# - title: 'Polish'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/pol.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/pol.traineddata'
|
||||||
@ -861,7 +790,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
- title: 'Portuguese'
|
- title: 'Portuguese'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/por.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/por.traineddata'
|
||||||
@ -873,7 +801,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
# - title: 'Pushto; Pashto'
|
# - title: 'Pushto; Pashto'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/pus.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/pus.traineddata'
|
||||||
@ -885,7 +812,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Romanian; Moldavian; Moldovan'
|
# - title: 'Romanian; Moldavian; Moldovan'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ron.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ron.traineddata'
|
||||||
@ -897,7 +823,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
- title: 'Russian'
|
- title: 'Russian'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/rus.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/rus.traineddata'
|
||||||
@ -909,7 +834,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
# - title: 'Sanskrit'
|
# - title: 'Sanskrit'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/san.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/san.traineddata'
|
||||||
@ -921,7 +845,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Sinhala; Sinhalese'
|
# - title: 'Sinhala; Sinhalese'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/sin.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/sin.traineddata'
|
||||||
@ -933,7 +856,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Slovak'
|
# - title: 'Slovak'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/slk.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/slk.traineddata'
|
||||||
@ -945,7 +867,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Slovenian'
|
# - title: 'Slovenian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/slv.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/slv.traineddata'
|
||||||
@ -957,7 +878,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
- title: 'Spanish; Castilian'
|
- title: 'Spanish; Castilian'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/spa.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/spa.traineddata'
|
||||||
@ -969,7 +889,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
- title: 'Spanish; Castilian - Old'
|
- title: 'Spanish; Castilian - Old'
|
||||||
description: ''
|
description: ''
|
||||||
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/spa_old.traineddata'
|
url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/spa_old.traineddata'
|
||||||
@ -981,7 +900,6 @@
|
|||||||
compatible_service_versions:
|
compatible_service_versions:
|
||||||
- '0.1.0'
|
- '0.1.0'
|
||||||
- '0.1.1'
|
- '0.1.1'
|
||||||
- '0.1.2'
|
|
||||||
# - title: 'Albanian'
|
# - title: 'Albanian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/sqi.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/sqi.traineddata'
|
||||||
@ -993,7 +911,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Serbian'
|
# - title: 'Serbian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/srp.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/srp.traineddata'
|
||||||
@ -1005,7 +922,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Serbian - Latin'
|
# - title: 'Serbian - Latin'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/srp_latn.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/srp_latn.traineddata'
|
||||||
@ -1017,7 +933,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Swahili'
|
# - title: 'Swahili'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/swa.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/swa.traineddata'
|
||||||
@ -1029,7 +944,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Swedish'
|
# - title: 'Swedish'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/swe.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/swe.traineddata'
|
||||||
@ -1041,7 +955,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Syriac'
|
# - title: 'Syriac'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/syr.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/syr.traineddata'
|
||||||
@ -1053,7 +966,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Tamil'
|
# - title: 'Tamil'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tam.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tam.traineddata'
|
||||||
@ -1065,7 +977,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Telugu'
|
# - title: 'Telugu'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tel.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tel.traineddata'
|
||||||
@ -1077,7 +988,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Tajik'
|
# - title: 'Tajik'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tgk.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tgk.traineddata'
|
||||||
@ -1089,7 +999,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Tagalog'
|
# - title: 'Tagalog'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tgl.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tgl.traineddata'
|
||||||
@ -1101,7 +1010,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Thai'
|
# - title: 'Thai'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tha.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tha.traineddata'
|
||||||
@ -1113,7 +1021,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Tigrinya'
|
# - title: 'Tigrinya'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tir.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tir.traineddata'
|
||||||
@ -1125,7 +1032,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Turkish'
|
# - title: 'Turkish'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tur.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/tur.traineddata'
|
||||||
@ -1137,7 +1043,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Uighur; Uyghur'
|
# - title: 'Uighur; Uyghur'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/uig.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/uig.traineddata'
|
||||||
@ -1149,7 +1054,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Ukrainian'
|
# - title: 'Ukrainian'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ukr.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/ukr.traineddata'
|
||||||
@ -1161,7 +1065,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Urdu'
|
# - title: 'Urdu'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/urd.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/urd.traineddata'
|
||||||
@ -1173,7 +1076,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Uzbek'
|
# - title: 'Uzbek'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/uzb.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/uzb.traineddata'
|
||||||
@ -1185,7 +1087,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Uzbek - Cyrillic'
|
# - title: 'Uzbek - Cyrillic'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/uzb_cyrl.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/uzb_cyrl.traineddata'
|
||||||
@ -1197,7 +1098,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Vietnamese'
|
# - title: 'Vietnamese'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/vie.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/vie.traineddata'
|
||||||
@ -1209,7 +1109,6 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
# - title: 'Yiddish'
|
# - title: 'Yiddish'
|
||||||
# description: ''
|
# description: ''
|
||||||
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/yid.traineddata'
|
# url: 'https://github.com/tesseract-ocr/tessdata/raw/4.1.0/yid.traineddata'
|
||||||
@ -1221,4 +1120,3 @@
|
|||||||
# compatible_service_versions:
|
# compatible_service_versions:
|
||||||
# - '0.1.0'
|
# - '0.1.0'
|
||||||
# - '0.1.1'
|
# - '0.1.1'
|
||||||
# - '0.1.2'
|
|
||||||
|
@ -13,6 +13,7 @@ from flask_paranoid import Paranoid
|
|||||||
from flask_socketio import SocketIO
|
from flask_socketio import SocketIO
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
from flask_hashids import Hashids
|
from flask_hashids import Hashids
|
||||||
|
from werkzeug.exceptions import HTTPException
|
||||||
|
|
||||||
|
|
||||||
apifairy = APIFairy()
|
apifairy = APIFairy()
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
from cqi import CQiClient
|
from cqi import CQiClient
|
||||||
from cqi.errors import CQiException
|
from cqi.errors import CQiException
|
||||||
from cqi.status import CQiStatus
|
from cqi.status import CQiStatus
|
||||||
from docker.models.containers import Container
|
from flask import session
|
||||||
from flask import current_app, session
|
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from flask_socketio import Namespace
|
from flask_socketio import Namespace
|
||||||
from inspect import signature
|
from inspect import signature
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from typing import Callable, Dict, List, Optional
|
from typing import Callable, Dict, List
|
||||||
from app import db, docker_client, hashids, socketio
|
from app import db, hashids, socketio
|
||||||
from app.decorators import socketio_login_required
|
from app.decorators import socketio_login_required
|
||||||
from app.models import Corpus, CorpusStatus
|
from app.models import Corpus, CorpusStatus
|
||||||
from . import extensions
|
from . import extensions
|
||||||
@ -93,8 +92,8 @@ class CQiNamespace(Namespace):
|
|||||||
|
|
||||||
@socketio_login_required
|
@socketio_login_required
|
||||||
def on_init(self, db_corpus_hashid: str):
|
def on_init(self, db_corpus_hashid: str):
|
||||||
db_corpus_id: int = hashids.decode(db_corpus_hashid)
|
db_corpus_id = hashids.decode(db_corpus_hashid)
|
||||||
db_corpus: Optional[Corpus] = Corpus.query.get(db_corpus_id)
|
db_corpus = Corpus.query.get(db_corpus_id)
|
||||||
if db_corpus is None:
|
if db_corpus is None:
|
||||||
return {'code': 404, 'msg': 'Not Found'}
|
return {'code': 404, 'msg': 'Not Found'}
|
||||||
if not (db_corpus.user == current_user
|
if not (db_corpus.user == current_user
|
||||||
@ -113,7 +112,7 @@ class CQiNamespace(Namespace):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
db_corpus.num_analysis_sessions = Corpus.num_analysis_sessions + 1
|
db_corpus.num_analysis_sessions = Corpus.num_analysis_sessions + 1
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
retry_counter: int = 20
|
retry_counter = 20
|
||||||
while db_corpus.status != CorpusStatus.RUNNING_ANALYSIS_SESSION:
|
while db_corpus.status != CorpusStatus.RUNNING_ANALYSIS_SESSION:
|
||||||
if retry_counter == 0:
|
if retry_counter == 0:
|
||||||
db_corpus.num_analysis_sessions = Corpus.num_analysis_sessions - 1
|
db_corpus.num_analysis_sessions = Corpus.num_analysis_sessions - 1
|
||||||
@ -122,16 +121,11 @@ class CQiNamespace(Namespace):
|
|||||||
socketio.sleep(3)
|
socketio.sleep(3)
|
||||||
retry_counter -= 1
|
retry_counter -= 1
|
||||||
db.session.refresh(db_corpus)
|
db.session.refresh(db_corpus)
|
||||||
# cqi_client: CQiClient = CQiClient(f'cqpserver_{db_corpus_id}')
|
cqi_client = CQiClient(f'cqpserver_{db_corpus_id}', timeout=float('inf'))
|
||||||
cqpserver_container_name: str = f'cqpserver_{db_corpus_id}'
|
session['cqi_over_sio'] = {}
|
||||||
cqpserver_container: Container = docker_client.containers.get(cqpserver_container_name)
|
session['cqi_over_sio']['cqi_client'] = cqi_client
|
||||||
cqpserver_host: str = cqpserver_container.attrs['NetworkSettings']['Networks'][current_app.config['NOPAQUE_DOCKER_NETWORK_NAME']]['IPAddress']
|
session['cqi_over_sio']['cqi_client_lock'] = Lock()
|
||||||
cqi_client: CQiClient = CQiClient(cqpserver_host)
|
session['cqi_over_sio']['db_corpus_id'] = db_corpus_id
|
||||||
session['cqi_over_sio'] = {
|
|
||||||
'cqi_client': cqi_client,
|
|
||||||
'cqi_client_lock': Lock(),
|
|
||||||
'db_corpus_id': db_corpus_id
|
|
||||||
}
|
|
||||||
return {'code': 200, 'msg': 'OK'}
|
return {'code': 200, 'msg': 'OK'}
|
||||||
|
|
||||||
@socketio_login_required
|
@socketio_login_required
|
||||||
@ -199,8 +193,7 @@ class CQiNamespace(Namespace):
|
|||||||
except (BrokenPipeError, CQiException):
|
except (BrokenPipeError, CQiException):
|
||||||
pass
|
pass
|
||||||
cqi_client_lock.release()
|
cqi_client_lock.release()
|
||||||
db_corpus: Optional[Corpus] = Corpus.query.get(db_corpus_id)
|
db_corpus = Corpus.query.get(db_corpus_id)
|
||||||
if db_corpus is None:
|
if db_corpus is not None:
|
||||||
return
|
db_corpus.num_analysis_sessions = Corpus.num_analysis_sessions - 1
|
||||||
db_corpus.num_analysis_sessions = Corpus.num_analysis_sessions - 1
|
db.session.commit()
|
||||||
db.session.commit()
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
from collections import Counter
|
from collections import Counter
|
||||||
from cqi import CQiClient
|
from cqi import CQiClient
|
||||||
from cqi.models.corpora import Corpus as CQiCorpus
|
from cqi.models.corpora import Corpus as CQiCorpus
|
||||||
from cqi.models.subcorpora import Subcorpus as CQiSubcorpus
|
|
||||||
from cqi.models.attributes import (
|
from cqi.models.attributes import (
|
||||||
PositionalAttribute as CQiPositionalAttribute,
|
PositionalAttribute as CQiPositionalAttribute,
|
||||||
StructuralAttribute as CQiStructuralAttribute
|
StructuralAttribute as CQiStructuralAttribute
|
||||||
@ -41,132 +40,161 @@ def ext_corpus_update_db(corpus: str) -> CQiStatusOk:
|
|||||||
def ext_corpus_static_data(corpus: str) -> Dict:
|
def ext_corpus_static_data(corpus: str) -> Dict:
|
||||||
db_corpus_id: int = session['cqi_over_sio']['db_corpus_id']
|
db_corpus_id: int = session['cqi_over_sio']['db_corpus_id']
|
||||||
db_corpus: Corpus = Corpus.query.get(db_corpus_id)
|
db_corpus: Corpus = Corpus.query.get(db_corpus_id)
|
||||||
|
cache_file_path: str = os.path.join(db_corpus.path, 'cwb', 'static.json.gz')
|
||||||
static_data_file_path: str = os.path.join(db_corpus.path, 'cwb', 'static.json.gz')
|
if os.path.exists(cache_file_path):
|
||||||
if os.path.exists(static_data_file_path):
|
with open(cache_file_path, 'rb') as f:
|
||||||
with open(static_data_file_path, 'rb') as f:
|
|
||||||
return f.read()
|
return f.read()
|
||||||
|
|
||||||
cqi_client: CQiClient = session['cqi_over_sio']['cqi_client']
|
cqi_client: CQiClient = session['cqi_over_sio']['cqi_client']
|
||||||
cqi_corpus: CQiCorpus = cqi_client.corpora.get(corpus)
|
cqi_corpus: CQiCorpus = cqi_client.corpora.get(corpus)
|
||||||
cqi_p_attrs: List[CQiPositionalAttribute] = cqi_corpus.positional_attributes.list()
|
cqi_p_attrs: Dict[str, CQiPositionalAttribute] = {
|
||||||
cqi_s_attrs: List[CQiStructuralAttribute] = cqi_corpus.structural_attributes.list()
|
p_attr.name: p_attr
|
||||||
|
for p_attr in cqi_corpus.positional_attributes.list()
|
||||||
static_data = {
|
}
|
||||||
|
cqi_s_attrs: Dict[str, CQiStructuralAttribute] = {
|
||||||
|
s_attr.name: s_attr
|
||||||
|
for s_attr in cqi_corpus.structural_attributes.list()
|
||||||
|
}
|
||||||
|
static_corpus_data = {
|
||||||
'corpus': {
|
'corpus': {
|
||||||
'bounds': [0, cqi_corpus.size - 1],
|
'bounds': [0, cqi_corpus.size - 1],
|
||||||
|
'counts': {
|
||||||
|
'token': cqi_corpus.size
|
||||||
|
},
|
||||||
'freqs': {}
|
'freqs': {}
|
||||||
},
|
},
|
||||||
'p_attrs': {},
|
'p_attrs': {},
|
||||||
's_attrs': {},
|
's_attrs': {},
|
||||||
'values': {'p_attrs': {}, 's_attrs': {}}
|
'values': {'p_attrs': {}, 's_attrs': {}}
|
||||||
}
|
}
|
||||||
|
for p_attr in cqi_p_attrs.values():
|
||||||
for p_attr in cqi_p_attrs:
|
static_corpus_data['corpus']['freqs'][p_attr.name] = {}
|
||||||
print(f'corpus.freqs.{p_attr.name}')
|
chunk_size = 10000
|
||||||
static_data['corpus']['freqs'][p_attr.name] = []
|
p_attr_id_list = list(range(p_attr.lexicon_size))
|
||||||
p_attr_id_list: List[int] = list(range(p_attr.lexicon_size))
|
chunks = [p_attr_id_list[i:i+chunk_size] for i in range(0, len(p_attr_id_list), chunk_size)]
|
||||||
static_data['corpus']['freqs'][p_attr.name].extend(p_attr.freqs_by_ids(p_attr_id_list))
|
|
||||||
del p_attr_id_list
|
del p_attr_id_list
|
||||||
|
for chunk in chunks:
|
||||||
print(f'p_attrs.{p_attr.name}')
|
# print(f'corpus.freqs.{p_attr.name}: {chunk[0]} - {chunk[-1]}')
|
||||||
static_data['p_attrs'][p_attr.name] = []
|
static_corpus_data['corpus']['freqs'][p_attr.name].update(
|
||||||
cpos_list: List[int] = list(range(cqi_corpus.size))
|
dict(zip(chunk, p_attr.freqs_by_ids(chunk)))
|
||||||
static_data['p_attrs'][p_attr.name].extend(p_attr.ids_by_cpos(cpos_list))
|
)
|
||||||
|
del chunks
|
||||||
|
static_corpus_data['p_attrs'][p_attr.name] = {}
|
||||||
|
cpos_list = list(range(cqi_corpus.size))
|
||||||
|
chunks = [cpos_list[i:i+chunk_size] for i in range(0, len(cpos_list), chunk_size)]
|
||||||
del cpos_list
|
del cpos_list
|
||||||
|
for chunk in chunks:
|
||||||
print(f'values.p_attrs.{p_attr.name}')
|
# print(f'p_attrs.{p_attr.name}: {chunk[0]} - {chunk[-1]}')
|
||||||
static_data['values']['p_attrs'][p_attr.name] = []
|
static_corpus_data['p_attrs'][p_attr.name].update(
|
||||||
p_attr_id_list: List[int] = list(range(p_attr.lexicon_size))
|
dict(zip(chunk, p_attr.ids_by_cpos(chunk)))
|
||||||
static_data['values']['p_attrs'][p_attr.name].extend(p_attr.values_by_ids(p_attr_id_list))
|
)
|
||||||
|
del chunks
|
||||||
|
static_corpus_data['values']['p_attrs'][p_attr.name] = {}
|
||||||
|
p_attr_id_list = list(range(p_attr.lexicon_size))
|
||||||
|
chunks = [p_attr_id_list[i:i+chunk_size] for i in range(0, len(p_attr_id_list), chunk_size)]
|
||||||
del p_attr_id_list
|
del p_attr_id_list
|
||||||
|
for chunk in chunks:
|
||||||
for s_attr in cqi_s_attrs:
|
# print(f'values.p_attrs.{p_attr.name}: {chunk[0]} - {chunk[-1]}')
|
||||||
|
static_corpus_data['values']['p_attrs'][p_attr.name].update(
|
||||||
|
dict(zip(chunk, p_attr.values_by_ids(chunk)))
|
||||||
|
)
|
||||||
|
del chunks
|
||||||
|
for s_attr in cqi_s_attrs.values():
|
||||||
if s_attr.has_values:
|
if s_attr.has_values:
|
||||||
continue
|
continue
|
||||||
|
static_corpus_data['corpus']['counts'][s_attr.name] = s_attr.size
|
||||||
static_data['s_attrs'][s_attr.name] = {'lexicon': [], 'values': None}
|
static_corpus_data['s_attrs'][s_attr.name] = {'lexicon': {}, 'values': None}
|
||||||
|
static_corpus_data['values']['s_attrs'][s_attr.name] = {}
|
||||||
if s_attr.name in ['s', 'ent']:
|
##########################################################################
|
||||||
##############################################################
|
# A faster way to get cpos boundaries for smaller s_attrs #
|
||||||
# A faster way to get cpos boundaries for smaller s_attrs #
|
##########################################################################
|
||||||
# Note: Needs more testing, don't use it in production #
|
# if s_attr.name in ['s', 'ent']:
|
||||||
##############################################################
|
# cqi_corpus.query('Last', f'<{s_attr.name}> []* </{s_attr.name}>;')
|
||||||
cqi_corpus.query('Last', f'<{s_attr.name}> []* </{s_attr.name}>;')
|
# cqi_subcorpus = cqi_corpus.subcorpora.get('Last')
|
||||||
cqi_subcorpus: CQiSubcorpus = cqi_corpus.subcorpora.get('Last')
|
# first_match = 0
|
||||||
first_match: int = 0
|
# last_match = cqi_subcorpus.size - 1
|
||||||
last_match: int = cqi_subcorpus.size - 1
|
# match_boundaries = zip(
|
||||||
match_boundaries = zip(
|
# range(first_match, last_match + 1),
|
||||||
range(first_match, last_match + 1),
|
# cqi_subcorpus.dump(cqi_subcorpus.fields['match'], first_match, last_match),
|
||||||
cqi_subcorpus.dump(
|
# cqi_subcorpus.dump(cqi_subcorpus.fields['matchend'], first_match, last_match)
|
||||||
cqi_subcorpus.fields['match'],
|
# )
|
||||||
first_match,
|
# for id, lbound, rbound in match_boundaries:
|
||||||
last_match
|
# static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id] = {}
|
||||||
),
|
# static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['bounds'] = [lbound, rbound]
|
||||||
cqi_subcorpus.dump(
|
# static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['counts'] = {}
|
||||||
cqi_subcorpus.fields['matchend'],
|
# static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['counts']['token'] = rbound - lbound + 1
|
||||||
first_match,
|
# cqi_subcorpus.drop()
|
||||||
last_match
|
|
||||||
)
|
|
||||||
)
|
|
||||||
cqi_subcorpus.drop()
|
|
||||||
del cqi_subcorpus, first_match, last_match
|
|
||||||
for id, lbound, rbound in match_boundaries:
|
|
||||||
static_data['s_attrs'][s_attr.name]['lexicon'].append({})
|
|
||||||
print(f's_attrs.{s_attr.name}.lexicon.{id}.bounds')
|
|
||||||
static_data['s_attrs'][s_attr.name]['lexicon'][id]['bounds'] = [lbound, rbound]
|
|
||||||
del match_boundaries
|
|
||||||
|
|
||||||
if s_attr.name != 'text':
|
|
||||||
continue
|
|
||||||
|
|
||||||
for id in range(0, s_attr.size):
|
for id in range(0, s_attr.size):
|
||||||
static_data['s_attrs'][s_attr.name]['lexicon'].append({})
|
# print(f's_attrs.{s_attr.name}.lexicon.{id}')
|
||||||
# This is a very slow operation, thats why we only use it for
|
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id] = {
|
||||||
# the text attribute
|
'bounds': None,
|
||||||
|
'counts': None,
|
||||||
|
'freqs': None
|
||||||
|
}
|
||||||
|
if s_attr.name != 'text':
|
||||||
|
continue
|
||||||
lbound, rbound = s_attr.cpos_by_id(id)
|
lbound, rbound = s_attr.cpos_by_id(id)
|
||||||
print(f's_attrs.{s_attr.name}.lexicon.{id}.bounds')
|
# print(f's_attrs.{s_attr.name}.lexicon.{id}.bounds')
|
||||||
static_data['s_attrs'][s_attr.name]['lexicon'][id]['bounds'] = [lbound, rbound]
|
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['bounds'] = [lbound, rbound]
|
||||||
static_data['s_attrs'][s_attr.name]['lexicon'][id]['freqs'] = {}
|
# print(f's_attrs.{s_attr.name}.lexicon.{id}.counts')
|
||||||
cpos_list: List[int] = list(range(lbound, rbound + 1))
|
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['counts'] = {}
|
||||||
for p_attr in cqi_p_attrs:
|
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['counts']['token'] = rbound - lbound + 1
|
||||||
p_attr_ids: List[int] = []
|
cpos_list = list(range(lbound, rbound + 1))
|
||||||
p_attr_ids.extend(p_attr.ids_by_cpos(cpos_list))
|
chunks = [cpos_list[i:i+chunk_size] for i in range(0, len(cpos_list), chunk_size)]
|
||||||
print(f's_attrs.{s_attr.name}.lexicon.{id}.freqs.{p_attr.name}')
|
|
||||||
static_data['s_attrs'][s_attr.name]['lexicon'][id]['freqs'][p_attr.name] = dict(Counter(p_attr_ids))
|
|
||||||
del p_attr_ids
|
|
||||||
del cpos_list
|
del cpos_list
|
||||||
|
ent_ids = set()
|
||||||
sub_s_attrs: List[CQiStructuralAttribute] = cqi_corpus.structural_attributes.list(filters={'part_of': s_attr})
|
for chunk in chunks:
|
||||||
print(f's_attrs.{s_attr.name}.values')
|
# print(f'Gather ent_ids from cpos: {chunk[0]} - {chunk[-1]}')
|
||||||
static_data['s_attrs'][s_attr.name]['values'] = [
|
ent_ids.update({x for x in cqi_s_attrs['ent'].ids_by_cpos(chunk) if x != -1})
|
||||||
|
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['counts']['ent'] = len(ent_ids)
|
||||||
|
del ent_ids
|
||||||
|
s_ids = set()
|
||||||
|
for chunk in chunks:
|
||||||
|
# print(f'Gather s_ids from cpos: {chunk[0]} - {chunk[-1]}')
|
||||||
|
s_ids.update({x for x in cqi_s_attrs['s'].ids_by_cpos(chunk) if x != -1})
|
||||||
|
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['counts']['s'] = len(s_ids)
|
||||||
|
del s_ids
|
||||||
|
# print(f's_attrs.{s_attr.name}.lexicon.{id}.freqs')
|
||||||
|
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['freqs'] = {}
|
||||||
|
for p_attr in cqi_p_attrs.values():
|
||||||
|
p_attr_ids = []
|
||||||
|
for chunk in chunks:
|
||||||
|
# print(f'Gather p_attr_ids from cpos: {chunk[0]} - {chunk[-1]}')
|
||||||
|
p_attr_ids.extend(p_attr.ids_by_cpos(chunk))
|
||||||
|
static_corpus_data['s_attrs'][s_attr.name]['lexicon'][id]['freqs'][p_attr.name] = dict(Counter(p_attr_ids))
|
||||||
|
del p_attr_ids
|
||||||
|
del chunks
|
||||||
|
sub_s_attrs = cqi_corpus.structural_attributes.list(filters={'part_of': s_attr})
|
||||||
|
s_attr_value_names: List[str] = [
|
||||||
sub_s_attr.name[(len(s_attr.name) + 1):]
|
sub_s_attr.name[(len(s_attr.name) + 1):]
|
||||||
for sub_s_attr in sub_s_attrs
|
for sub_s_attr in sub_s_attrs
|
||||||
]
|
]
|
||||||
s_attr_id_list: List[int] = list(range(s_attr.size))
|
s_attr_id_list = list(range(s_attr.size))
|
||||||
sub_s_attr_values: List[str] = []
|
chunks = [s_attr_id_list[i:i+chunk_size] for i in range(0, len(s_attr_id_list), chunk_size)]
|
||||||
|
del s_attr_id_list
|
||||||
|
sub_s_attr_values = []
|
||||||
for sub_s_attr in sub_s_attrs:
|
for sub_s_attr in sub_s_attrs:
|
||||||
tmp = []
|
tmp = []
|
||||||
tmp.extend(sub_s_attr.values_by_ids(s_attr_id_list))
|
for chunk in chunks:
|
||||||
|
tmp.extend(sub_s_attr.values_by_ids(chunk))
|
||||||
sub_s_attr_values.append(tmp)
|
sub_s_attr_values.append(tmp)
|
||||||
del tmp
|
del tmp
|
||||||
del s_attr_id_list
|
del chunks
|
||||||
print(f'values.s_attrs.{s_attr.name}')
|
# print(f's_attrs.{s_attr.name}.values')
|
||||||
static_data['values']['s_attrs'][s_attr.name] = [
|
static_corpus_data['s_attrs'][s_attr.name]['values'] = s_attr_value_names
|
||||||
{
|
# print(f'values.s_attrs.{s_attr.name}')
|
||||||
s_attr_value_name: sub_s_attr_values[s_attr_value_name_idx][s_attr_id]
|
static_corpus_data['values']['s_attrs'][s_attr.name] = {
|
||||||
|
s_attr_id: {
|
||||||
|
s_attr_value_name: sub_s_attr_values[s_attr_value_name_idx][s_attr_id_idx]
|
||||||
for s_attr_value_name_idx, s_attr_value_name in enumerate(
|
for s_attr_value_name_idx, s_attr_value_name in enumerate(
|
||||||
static_data['s_attrs'][s_attr.name]['values']
|
static_corpus_data['s_attrs'][s_attr.name]['values']
|
||||||
)
|
)
|
||||||
} for s_attr_id in range(0, s_attr.size)
|
} for s_attr_id_idx, s_attr_id in enumerate(range(0, s_attr.size))
|
||||||
]
|
}
|
||||||
del sub_s_attr_values
|
del sub_s_attr_values
|
||||||
print('Saving static data to file')
|
with gzip.open(cache_file_path, 'wt') as f:
|
||||||
with gzip.open(static_data_file_path, 'wt') as f:
|
json.dump(static_corpus_data, f)
|
||||||
json.dump(static_data, f)
|
del static_corpus_data
|
||||||
del static_data
|
with open(cache_file_path, 'rb') as f:
|
||||||
print('Sending static data to client')
|
|
||||||
with open(static_data_file_path, 'rb') as f:
|
|
||||||
return f.read()
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,44 +1,46 @@
|
|||||||
from cqi.models.corpora import Corpus as CQiCorpus
|
from cqi.models.corpora import Corpus
|
||||||
from cqi.models.subcorpora import Subcorpus as CQiSubcorpus
|
from cqi.models.subcorpora import Subcorpus
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
from app.models import Corpus
|
||||||
|
|
||||||
|
|
||||||
def lookups_by_cpos(corpus: CQiCorpus, cpos_list: List[int]) -> Dict:
|
def lookups_by_cpos(corpus: Corpus, cpos_list: List[int]) -> Dict:
|
||||||
lookups = {}
|
lookups = {}
|
||||||
lookups['cpos_lookup'] = {cpos: {} for cpos in cpos_list}
|
lookups['cpos_lookup'] = {cpos: {} for cpos in cpos_list}
|
||||||
for attr in corpus.positional_attributes.list():
|
for attr in corpus.positional_attributes.list():
|
||||||
cpos_attr_values: List[str] = attr.values_by_cpos(cpos_list)
|
cpos_attr_values = attr.values_by_cpos(cpos_list)
|
||||||
for i, cpos in enumerate(cpos_list):
|
for i, cpos in enumerate(cpos_list):
|
||||||
lookups['cpos_lookup'][cpos][attr.name] = cpos_attr_values[i]
|
lookups['cpos_lookup'][cpos][attr.attrs['name']] = \
|
||||||
|
cpos_attr_values[i]
|
||||||
for attr in corpus.structural_attributes.list():
|
for attr in corpus.structural_attributes.list():
|
||||||
# We only want to iterate over non subattributes, identifiable by
|
# We only want to iterate over non subattributes, identifiable by
|
||||||
# attr.has_values == False
|
# attr.attrs['has_values'] == False
|
||||||
if attr.has_values:
|
if attr.attrs['has_values']:
|
||||||
continue
|
continue
|
||||||
cpos_attr_ids: List[int] = attr.ids_by_cpos(cpos_list)
|
cpos_attr_ids = attr.ids_by_cpos(cpos_list)
|
||||||
for i, cpos in enumerate(cpos_list):
|
for i, cpos in enumerate(cpos_list):
|
||||||
if cpos_attr_ids[i] == -1:
|
if cpos_attr_ids[i] == -1:
|
||||||
continue
|
continue
|
||||||
lookups['cpos_lookup'][cpos][attr.name] = cpos_attr_ids[i]
|
lookups['cpos_lookup'][cpos][attr.attrs['name']] = cpos_attr_ids[i]
|
||||||
occured_attr_ids = [x for x in set(cpos_attr_ids) if x != -1]
|
occured_attr_ids = [x for x in set(cpos_attr_ids) if x != -1]
|
||||||
if len(occured_attr_ids) == 0:
|
if not occured_attr_ids:
|
||||||
continue
|
continue
|
||||||
subattrs = corpus.structural_attributes.list(filters={'part_of': attr})
|
subattrs = corpus.structural_attributes.list(filters={'part_of': attr})
|
||||||
if len(subattrs) == 0:
|
if not subattrs:
|
||||||
continue
|
continue
|
||||||
lookup_name: str = f'{attr.name}_lookup'
|
lookup_name = f'{attr.attrs["name"]}_lookup'
|
||||||
lookups[lookup_name] = {}
|
lookups[lookup_name] = {}
|
||||||
for attr_id in occured_attr_ids:
|
for attr_id in occured_attr_ids:
|
||||||
lookups[lookup_name][attr_id] = {}
|
lookups[lookup_name][attr_id] = {}
|
||||||
for subattr in subattrs:
|
for subattr in subattrs:
|
||||||
subattr_name = subattr.name[(len(attr.name) + 1):] # noqa
|
subattr_name = subattr.attrs['name'][(len(attr.attrs['name']) + 1):] # noqa
|
||||||
for i, subattr_value in enumerate(subattr.values_by_ids(occured_attr_ids)): # noqa
|
for i, subattr_value in enumerate(subattr.values_by_ids(occured_attr_ids)): # noqa
|
||||||
lookups[lookup_name][occured_attr_ids[i]][subattr_name] = subattr_value # noqa
|
lookups[lookup_name][occured_attr_ids[i]][subattr_name] = subattr_value # noqa
|
||||||
return lookups
|
return lookups
|
||||||
|
|
||||||
|
|
||||||
def partial_export_subcorpus(
|
def partial_export_subcorpus(
|
||||||
subcorpus: CQiSubcorpus,
|
subcorpus: Subcorpus,
|
||||||
match_id_list: List[int],
|
match_id_list: List[int],
|
||||||
context: int = 25
|
context: int = 25
|
||||||
) -> Dict:
|
) -> Dict:
|
||||||
@ -87,7 +89,7 @@ def partial_export_subcorpus(
|
|||||||
|
|
||||||
|
|
||||||
def export_subcorpus(
|
def export_subcorpus(
|
||||||
subcorpus: CQiSubcorpus,
|
subcorpus: Subcorpus,
|
||||||
context: int = 25,
|
context: int = 25,
|
||||||
cutoff: float = float('inf'),
|
cutoff: float = float('inf'),
|
||||||
offset: int = 0
|
offset: int = 0
|
||||||
|
@ -12,65 +12,65 @@ from ..decorators import corpus_follower_permission_required
|
|||||||
from . import bp
|
from . import bp
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<hashid:corpus_id>/followers', methods=['POST'])
|
# @bp.route('/<hashid:corpus_id>/followers', methods=['POST'])
|
||||||
@corpus_follower_permission_required('MANAGE_FOLLOWERS')
|
# @corpus_follower_permission_required('MANAGE_FOLLOWERS')
|
||||||
@content_negotiation(consumes='application/json', produces='application/json')
|
# @content_negotiation(consumes='application/json', produces='application/json')
|
||||||
def create_corpus_followers(corpus_id):
|
# def create_corpus_followers(corpus_id):
|
||||||
usernames = request.json
|
# usernames = request.json
|
||||||
if not (isinstance(usernames, list) or all(isinstance(u, str) for u in usernames)):
|
# if not (isinstance(usernames, list) or all(isinstance(u, str) for u in usernames)):
|
||||||
abort(400)
|
# abort(400)
|
||||||
corpus = Corpus.query.get_or_404(corpus_id)
|
# corpus = Corpus.query.get_or_404(corpus_id)
|
||||||
for username in usernames:
|
# for username in usernames:
|
||||||
user = User.query.filter_by(username=username, is_public=True).first_or_404()
|
# user = User.query.filter_by(username=username, is_public=True).first_or_404()
|
||||||
user.follow_corpus(corpus)
|
# user.follow_corpus(corpus)
|
||||||
db.session.commit()
|
# db.session.commit()
|
||||||
response_data = {
|
# response_data = {
|
||||||
'message': f'Users are now following "{corpus.title}"',
|
# 'message': f'Users are now following "{corpus.title}"',
|
||||||
'category': 'corpus'
|
# 'category': 'corpus'
|
||||||
}
|
# }
|
||||||
return response_data, 200
|
# return response_data, 200
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<hashid:corpus_id>/followers/<hashid:follower_id>/role', methods=['PUT'])
|
# @bp.route('/<hashid:corpus_id>/followers/<hashid:follower_id>/role', methods=['PUT'])
|
||||||
@corpus_follower_permission_required('MANAGE_FOLLOWERS')
|
# @corpus_follower_permission_required('MANAGE_FOLLOWERS')
|
||||||
@content_negotiation(consumes='application/json', produces='application/json')
|
# @content_negotiation(consumes='application/json', produces='application/json')
|
||||||
def update_corpus_follower_role(corpus_id, follower_id):
|
# def update_corpus_follower_role(corpus_id, follower_id):
|
||||||
role_name = request.json
|
# role_name = request.json
|
||||||
if not isinstance(role_name, str):
|
# if not isinstance(role_name, str):
|
||||||
abort(400)
|
# abort(400)
|
||||||
cfr = CorpusFollowerRole.query.filter_by(name=role_name).first()
|
# cfr = CorpusFollowerRole.query.filter_by(name=role_name).first()
|
||||||
if cfr is None:
|
# if cfr is None:
|
||||||
abort(400)
|
# abort(400)
|
||||||
cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=follower_id).first_or_404()
|
# cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=follower_id).first_or_404()
|
||||||
cfa.role = cfr
|
# cfa.role = cfr
|
||||||
db.session.commit()
|
# db.session.commit()
|
||||||
response_data = {
|
# response_data = {
|
||||||
'message': f'User "{cfa.follower.username}" is now {cfa.role.name}',
|
# 'message': f'User "{cfa.follower.username}" is now {cfa.role.name}',
|
||||||
'category': 'corpus'
|
# 'category': 'corpus'
|
||||||
}
|
# }
|
||||||
return response_data, 200
|
# return response_data, 200
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<hashid:corpus_id>/followers/<hashid:follower_id>', methods=['DELETE'])
|
# @bp.route('/<hashid:corpus_id>/followers/<hashid:follower_id>', methods=['DELETE'])
|
||||||
def delete_corpus_follower(corpus_id, follower_id):
|
# def delete_corpus_follower(corpus_id, follower_id):
|
||||||
cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=follower_id).first_or_404()
|
# cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=follower_id).first_or_404()
|
||||||
if not (
|
# if not (
|
||||||
current_user.id == follower_id
|
# current_user.id == follower_id
|
||||||
or current_user == cfa.corpus.user
|
# or current_user == cfa.corpus.user
|
||||||
or CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first().role.has_permission('MANAGE_FOLLOWERS')
|
# or CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first().role.has_permission('MANAGE_FOLLOWERS')
|
||||||
or current_user.is_administrator()):
|
# or current_user.is_administrator()):
|
||||||
abort(403)
|
# abort(403)
|
||||||
if current_user.id == follower_id:
|
# if current_user.id == follower_id:
|
||||||
flash(f'You are no longer following "{cfa.corpus.title}"', 'corpus')
|
# flash(f'You are no longer following "{cfa.corpus.title}"', 'corpus')
|
||||||
response = make_response()
|
# response = make_response()
|
||||||
response.status_code = 204
|
# response.status_code = 204
|
||||||
else:
|
# else:
|
||||||
response_data = {
|
# response_data = {
|
||||||
'message': f'"{cfa.follower.username}" is not following "{cfa.corpus.title}" anymore',
|
# 'message': f'"{cfa.follower.username}" is not following "{cfa.corpus.title}" anymore',
|
||||||
'category': 'corpus'
|
# 'category': 'corpus'
|
||||||
}
|
# }
|
||||||
response = jsonify(response_data)
|
# response = jsonify(response_data)
|
||||||
response.status_code = 200
|
# response.status_code = 200
|
||||||
cfa.follower.unfollow_corpus(cfa.corpus)
|
# cfa.follower.unfollow_corpus(cfa.corpus)
|
||||||
db.session.commit()
|
# db.session.commit()
|
||||||
return response
|
# return response
|
||||||
|
@ -61,7 +61,7 @@ def build_corpus(corpus_id):
|
|||||||
@bp.route('/stopwords')
|
@bp.route('/stopwords')
|
||||||
@content_negotiation(produces='application/json')
|
@content_negotiation(produces='application/json')
|
||||||
def get_stopwords():
|
def get_stopwords():
|
||||||
nltk.download('stopwords', quiet=True)
|
nltk.download('stopwords')
|
||||||
languages = ["german", "english", "catalan", "greek", "spanish", "french", "italian", "russian", "chinese"]
|
languages = ["german", "english", "catalan", "greek", "spanish", "french", "italian", "russian", "chinese"]
|
||||||
stopwords = {}
|
stopwords = {}
|
||||||
for language in languages:
|
for language in languages:
|
||||||
@ -71,55 +71,55 @@ def get_stopwords():
|
|||||||
response_data = stopwords
|
response_data = stopwords
|
||||||
return response_data, 202
|
return response_data, 202
|
||||||
|
|
||||||
@bp.route('/<hashid:corpus_id>/generate-share-link', methods=['POST'])
|
# @bp.route('/<hashid:corpus_id>/generate-share-link', methods=['POST'])
|
||||||
@corpus_follower_permission_required('MANAGE_FOLLOWERS')
|
# @corpus_follower_permission_required('MANAGE_FOLLOWERS')
|
||||||
@content_negotiation(consumes='application/json', produces='application/json')
|
# @content_negotiation(consumes='application/json', produces='application/json')
|
||||||
def generate_corpus_share_link(corpus_id):
|
# def generate_corpus_share_link(corpus_id):
|
||||||
data = request.json
|
# data = request.json
|
||||||
if not isinstance(data, dict):
|
# if not isinstance(data, dict):
|
||||||
abort(400)
|
# abort(400)
|
||||||
expiration = data.get('expiration')
|
# expiration = data.get('expiration')
|
||||||
if not isinstance(expiration, str):
|
# if not isinstance(expiration, str):
|
||||||
abort(400)
|
# abort(400)
|
||||||
role_name = data.get('role')
|
# role_name = data.get('role')
|
||||||
if not isinstance(role_name, str):
|
# if not isinstance(role_name, str):
|
||||||
abort(400)
|
# abort(400)
|
||||||
expiration_date = datetime.strptime(expiration, '%b %d, %Y')
|
# expiration_date = datetime.strptime(expiration, '%b %d, %Y')
|
||||||
cfr = CorpusFollowerRole.query.filter_by(name=role_name).first()
|
# cfr = CorpusFollowerRole.query.filter_by(name=role_name).first()
|
||||||
if cfr is None:
|
# if cfr is None:
|
||||||
abort(400)
|
# abort(400)
|
||||||
corpus = Corpus.query.get_or_404(corpus_id)
|
# corpus = Corpus.query.get_or_404(corpus_id)
|
||||||
token = current_user.generate_follow_corpus_token(corpus.hashid, role_name, expiration_date)
|
# token = current_user.generate_follow_corpus_token(corpus.hashid, role_name, expiration_date)
|
||||||
corpus_share_link = url_for(
|
# corpus_share_link = url_for(
|
||||||
'corpora.follow_corpus',
|
# 'corpora.follow_corpus',
|
||||||
corpus_id=corpus_id,
|
# corpus_id=corpus_id,
|
||||||
token=token,
|
# token=token,
|
||||||
_external=True
|
# _external=True
|
||||||
)
|
# )
|
||||||
response_data = {
|
# response_data = {
|
||||||
'message': 'Corpus share link generated',
|
# 'message': 'Corpus share link generated',
|
||||||
'category': 'corpus',
|
# 'category': 'corpus',
|
||||||
'corpusShareLink': corpus_share_link
|
# 'corpusShareLink': corpus_share_link
|
||||||
}
|
# }
|
||||||
return response_data, 200
|
# return response_data, 200
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<hashid:corpus_id>/is_public', methods=['PUT'])
|
# @bp.route('/<hashid:corpus_id>/is_public', methods=['PUT'])
|
||||||
@corpus_owner_or_admin_required
|
# @corpus_owner_or_admin_required
|
||||||
@content_negotiation(consumes='application/json', produces='application/json')
|
# @content_negotiation(consumes='application/json', produces='application/json')
|
||||||
def update_corpus_is_public(corpus_id):
|
# def update_corpus_is_public(corpus_id):
|
||||||
is_public = request.json
|
# is_public = request.json
|
||||||
if not isinstance(is_public, bool):
|
# if not isinstance(is_public, bool):
|
||||||
abort(400)
|
# abort(400)
|
||||||
corpus = Corpus.query.get_or_404(corpus_id)
|
# corpus = Corpus.query.get_or_404(corpus_id)
|
||||||
corpus.is_public = is_public
|
# corpus.is_public = is_public
|
||||||
db.session.commit()
|
# db.session.commit()
|
||||||
response_data = {
|
# response_data = {
|
||||||
'message': (
|
# 'message': (
|
||||||
f'Corpus "{corpus.title}" is now'
|
# f'Corpus "{corpus.title}" is now'
|
||||||
f' {"public" if is_public else "private"}'
|
# f' {"public" if is_public else "private"}'
|
||||||
),
|
# ),
|
||||||
'category': 'corpus'
|
# 'category': 'corpus'
|
||||||
}
|
# }
|
||||||
return response_data, 200
|
# return response_data, 200
|
||||||
|
@ -68,19 +68,20 @@ def corpus(corpus_id):
|
|||||||
corpus=corpus,
|
corpus=corpus,
|
||||||
cfr=cfr,
|
cfr=cfr,
|
||||||
cfrs=cfrs,
|
cfrs=cfrs,
|
||||||
users=users
|
users = users
|
||||||
)
|
)
|
||||||
if (current_user.is_following_corpus(corpus) or corpus.is_public):
|
if (current_user.is_following_corpus(corpus) or corpus.is_public):
|
||||||
cfas = CorpusFollowerAssociation.query.filter(Corpus.id == corpus_id, CorpusFollowerAssociation.follower_id != corpus.user.id).all()
|
abort(404)
|
||||||
return render_template(
|
# cfas = CorpusFollowerAssociation.query.filter(Corpus.id == corpus_id, CorpusFollowerAssociation.follower_id != corpus.user.id).all()
|
||||||
'corpora/public_corpus.html.j2',
|
# return render_template(
|
||||||
title=corpus.title,
|
# 'corpora/public_corpus.html.j2',
|
||||||
corpus=corpus,
|
# title=corpus.title,
|
||||||
cfrs=cfrs,
|
# corpus=corpus,
|
||||||
cfr=cfr,
|
# cfrs=cfrs,
|
||||||
cfas=cfas,
|
# cfr=cfr,
|
||||||
users=users
|
# cfas=cfas,
|
||||||
)
|
# users = users
|
||||||
|
# )
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|
||||||
|
|
||||||
@ -97,14 +98,14 @@ def analysis(corpus_id):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<hashid:corpus_id>/follow/<token>')
|
# @bp.route('/<hashid:corpus_id>/follow/<token>')
|
||||||
def follow_corpus(corpus_id, token):
|
# def follow_corpus(corpus_id, token):
|
||||||
corpus = Corpus.query.get_or_404(corpus_id)
|
# corpus = Corpus.query.get_or_404(corpus_id)
|
||||||
if current_user.follow_corpus_by_token(token):
|
# if current_user.follow_corpus_by_token(token):
|
||||||
db.session.commit()
|
# db.session.commit()
|
||||||
flash(f'You are following "{corpus.title}" now', category='corpus')
|
# flash(f'You are following "{corpus.title}" now', category='corpus')
|
||||||
return redirect(url_for('corpora.corpus', corpus_id=corpus_id))
|
# return redirect(url_for('corpora.corpus', corpus_id=corpus_id))
|
||||||
abort(403)
|
# abort(403)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/import', methods=['GET', 'POST'])
|
@bp.route('/import', methods=['GET', 'POST'])
|
||||||
|
@ -45,7 +45,7 @@ def _create_build_corpus_service(corpus):
|
|||||||
''' ## Constraints ## '''
|
''' ## Constraints ## '''
|
||||||
constraints = ['node.role==worker']
|
constraints = ['node.role==worker']
|
||||||
''' ## Image ## '''
|
''' ## Image ## '''
|
||||||
image = f'{current_app.config["NOPAQUE_DOCKER_IMAGE_PREFIX"]}cwb:r1879'
|
image = f'{current_app.config["NOPAQUE_DOCKER_IMAGE_PREFIX"]}cwb:r1702'
|
||||||
''' ## Labels ## '''
|
''' ## Labels ## '''
|
||||||
labels = {
|
labels = {
|
||||||
'origin': current_app.config['SERVER_NAME'],
|
'origin': current_app.config['SERVER_NAME'],
|
||||||
@ -139,11 +139,11 @@ def _create_cqpserver_container(corpus):
|
|||||||
''' ## Entrypoint ## '''
|
''' ## Entrypoint ## '''
|
||||||
entrypoint = ['bash', '-c']
|
entrypoint = ['bash', '-c']
|
||||||
''' ## Image ## '''
|
''' ## Image ## '''
|
||||||
image = f'{current_app.config["NOPAQUE_DOCKER_IMAGE_PREFIX"]}cwb:r1879'
|
image = f'{current_app.config["NOPAQUE_DOCKER_IMAGE_PREFIX"]}cwb:r1702'
|
||||||
''' ## Name ## '''
|
''' ## Name ## '''
|
||||||
name = f'cqpserver_{corpus.id}'
|
name = f'cqpserver_{corpus.id}'
|
||||||
''' ## Network ## '''
|
''' ## Network ## '''
|
||||||
network = f'{current_app.config["NOPAQUE_DOCKER_NETWORK_NAME"]}'
|
network = f'{current_app.config["DOCKER_NETWORK_NAME"]}'
|
||||||
''' ## Volumes ## '''
|
''' ## Volumes ## '''
|
||||||
volumes = []
|
volumes = []
|
||||||
''' ### Corpus data volume ### '''
|
''' ### Corpus data volume ### '''
|
||||||
|
@ -43,5 +43,3 @@ def deploy():
|
|||||||
SpaCyNLPPipelineModel.insert_defaults()
|
SpaCyNLPPipelineModel.insert_defaults()
|
||||||
print('Insert/Update default TesseractOCRPipelineModels')
|
print('Insert/Update default TesseractOCRPipelineModels')
|
||||||
TesseractOCRPipelineModel.insert_defaults()
|
TesseractOCRPipelineModel.insert_defaults()
|
||||||
|
|
||||||
# TODO: Implement checks for if the nopaque network exists
|
|
||||||
|
@ -45,6 +45,12 @@ def dashboard():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# @bp.route('/user_manual')
|
||||||
|
# @register_breadcrumb(bp, '.user_manual', '<i class="material-icons left">help</i>User manual')
|
||||||
|
# def user_manual():
|
||||||
|
# return render_template('main/user_manual.html.j2', title='User manual')
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/news')
|
@bp.route('/news')
|
||||||
@register_breadcrumb(bp, '.news', '<i class="material-icons left">email</i>News')
|
@register_breadcrumb(bp, '.news', '<i class="material-icons left">email</i>News')
|
||||||
def news():
|
def news():
|
||||||
@ -72,17 +78,15 @@ def terms_of_use():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/social-area')
|
# @bp.route('/social-area')
|
||||||
@register_breadcrumb(bp, '.social_area', '<i class="material-icons left">group</i>Social Area')
|
# @register_breadcrumb(bp, '.social_area', '<i class="material-icons left">group</i>Social Area')
|
||||||
@login_required
|
# @login_required
|
||||||
def social_area():
|
# def social_area():
|
||||||
print('test')
|
# corpora = Corpus.query.filter(Corpus.is_public == True, Corpus.user != current_user).all()
|
||||||
corpora = Corpus.query.filter(Corpus.is_public == True, Corpus.user != current_user).all()
|
# users = User.query.filter(User.is_public == True, User.id != current_user.id).all()
|
||||||
print(corpora)
|
# return render_template(
|
||||||
users = User.query.filter(User.is_public == True, User.id != current_user.id).all()
|
# 'main/social_area.html.j2',
|
||||||
return render_template(
|
# title='Social Area',
|
||||||
'main/social_area.html.j2',
|
# corpora=corpora,
|
||||||
title='Social Area',
|
# users=users
|
||||||
corpora=corpora,
|
# )
|
||||||
users=users
|
|
||||||
)
|
|
||||||
|
140
app/models.py
@ -853,7 +853,7 @@ class User(HashidMixin, UserMixin, db.Model):
|
|||||||
json_serializeable = {
|
json_serializeable = {
|
||||||
'id': self.hashid,
|
'id': self.hashid,
|
||||||
'confirmed': self.confirmed,
|
'confirmed': self.confirmed,
|
||||||
'avatar': url_for('users.user_avatar', user_id=self.id),
|
# 'avatar': url_for('users.user_avatar', user_id=self.id),
|
||||||
'email': self.email,
|
'email': self.email,
|
||||||
'last_seen': (
|
'last_seen': (
|
||||||
None if self.last_seen is None
|
None if self.last_seen is None
|
||||||
@ -953,7 +953,7 @@ class TesseractOCRPipelineModel(FileMixin, HashidMixin, db.Model):
|
|||||||
return self.user.hashid
|
return self.user.hashid
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def insert_defaults(force_download=False):
|
def insert_defaults():
|
||||||
nopaque_user = User.query.filter_by(username='nopaque').first()
|
nopaque_user = User.query.filter_by(username='nopaque').first()
|
||||||
defaults_file = os.path.join(
|
defaults_file = os.path.join(
|
||||||
os.path.dirname(os.path.abspath(__file__)),
|
os.path.dirname(os.path.abspath(__file__)),
|
||||||
@ -966,7 +966,6 @@ class TesseractOCRPipelineModel(FileMixin, HashidMixin, db.Model):
|
|||||||
if model is not None:
|
if model is not None:
|
||||||
model.compatible_service_versions = m['compatible_service_versions']
|
model.compatible_service_versions = m['compatible_service_versions']
|
||||||
model.description = m['description']
|
model.description = m['description']
|
||||||
model.filename = f'{model.id}.traineddata'
|
|
||||||
model.publisher = m['publisher']
|
model.publisher = m['publisher']
|
||||||
model.publisher_url = m['publisher_url']
|
model.publisher_url = m['publisher_url']
|
||||||
model.publishing_url = m['publishing_url']
|
model.publishing_url = m['publishing_url']
|
||||||
@ -974,39 +973,38 @@ class TesseractOCRPipelineModel(FileMixin, HashidMixin, db.Model):
|
|||||||
model.is_public = True
|
model.is_public = True
|
||||||
model.title = m['title']
|
model.title = m['title']
|
||||||
model.version = m['version']
|
model.version = m['version']
|
||||||
else:
|
continue
|
||||||
model = TesseractOCRPipelineModel(
|
model = TesseractOCRPipelineModel(
|
||||||
compatible_service_versions=m['compatible_service_versions'],
|
compatible_service_versions=m['compatible_service_versions'],
|
||||||
description=m['description'],
|
description=m['description'],
|
||||||
publisher=m['publisher'],
|
publisher=m['publisher'],
|
||||||
publisher_url=m['publisher_url'],
|
publisher_url=m['publisher_url'],
|
||||||
publishing_url=m['publishing_url'],
|
publishing_url=m['publishing_url'],
|
||||||
publishing_year=m['publishing_year'],
|
publishing_year=m['publishing_year'],
|
||||||
is_public=True,
|
is_public=True,
|
||||||
title=m['title'],
|
title=m['title'],
|
||||||
user=nopaque_user,
|
user=nopaque_user,
|
||||||
version=m['version']
|
version=m['version']
|
||||||
)
|
)
|
||||||
db.session.add(model)
|
db.session.add(model)
|
||||||
db.session.flush(objects=[model])
|
db.session.flush(objects=[model])
|
||||||
db.session.refresh(model)
|
db.session.refresh(model)
|
||||||
model.filename = f'{model.id}.traineddata'
|
model.filename = f'{model.id}.traineddata'
|
||||||
if not os.path.exists(model.path) or force_download:
|
r = requests.get(m['url'], stream=True)
|
||||||
r = requests.get(m['url'], stream=True)
|
pbar = tqdm(
|
||||||
pbar = tqdm(
|
desc=f'{model.title} ({model.filename})',
|
||||||
desc=f'{model.title} ({model.filename})',
|
unit="B",
|
||||||
unit="B",
|
unit_scale=True,
|
||||||
unit_scale=True,
|
unit_divisor=1024,
|
||||||
unit_divisor=1024,
|
total=int(r.headers['Content-Length'])
|
||||||
total=int(r.headers['Content-Length'])
|
)
|
||||||
)
|
pbar.clear()
|
||||||
pbar.clear()
|
with open(model.path, 'wb') as f:
|
||||||
with open(model.path, 'wb') as f:
|
for chunk in r.iter_content(chunk_size=1024):
|
||||||
for chunk in r.iter_content(chunk_size=1024):
|
if chunk: # filter out keep-alive new chunks
|
||||||
if chunk: # filter out keep-alive new chunks
|
pbar.update(len(chunk))
|
||||||
pbar.update(len(chunk))
|
f.write(chunk)
|
||||||
f.write(chunk)
|
pbar.close()
|
||||||
pbar.close()
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
@ -1082,7 +1080,7 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model):
|
|||||||
return self.user.hashid
|
return self.user.hashid
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def insert_defaults(force_download=False):
|
def insert_defaults():
|
||||||
nopaque_user = User.query.filter_by(username='nopaque').first()
|
nopaque_user = User.query.filter_by(username='nopaque').first()
|
||||||
defaults_file = os.path.join(
|
defaults_file = os.path.join(
|
||||||
os.path.dirname(os.path.abspath(__file__)),
|
os.path.dirname(os.path.abspath(__file__)),
|
||||||
@ -1095,7 +1093,6 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model):
|
|||||||
if model is not None:
|
if model is not None:
|
||||||
model.compatible_service_versions = m['compatible_service_versions']
|
model.compatible_service_versions = m['compatible_service_versions']
|
||||||
model.description = m['description']
|
model.description = m['description']
|
||||||
model.filename = m['url'].split('/')[-1]
|
|
||||||
model.publisher = m['publisher']
|
model.publisher = m['publisher']
|
||||||
model.publisher_url = m['publisher_url']
|
model.publisher_url = m['publisher_url']
|
||||||
model.publishing_url = m['publishing_url']
|
model.publishing_url = m['publishing_url']
|
||||||
@ -1104,40 +1101,39 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model):
|
|||||||
model.title = m['title']
|
model.title = m['title']
|
||||||
model.version = m['version']
|
model.version = m['version']
|
||||||
model.pipeline_name = m['pipeline_name']
|
model.pipeline_name = m['pipeline_name']
|
||||||
else:
|
continue
|
||||||
model = SpaCyNLPPipelineModel(
|
model = SpaCyNLPPipelineModel(
|
||||||
compatible_service_versions=m['compatible_service_versions'],
|
compatible_service_versions=m['compatible_service_versions'],
|
||||||
description=m['description'],
|
description=m['description'],
|
||||||
filename=m['url'].split('/')[-1],
|
publisher=m['publisher'],
|
||||||
publisher=m['publisher'],
|
publisher_url=m['publisher_url'],
|
||||||
publisher_url=m['publisher_url'],
|
publishing_url=m['publishing_url'],
|
||||||
publishing_url=m['publishing_url'],
|
publishing_year=m['publishing_year'],
|
||||||
publishing_year=m['publishing_year'],
|
is_public=True,
|
||||||
is_public=True,
|
title=m['title'],
|
||||||
title=m['title'],
|
user=nopaque_user,
|
||||||
user=nopaque_user,
|
version=m['version'],
|
||||||
version=m['version'],
|
pipeline_name=m['pipeline_name']
|
||||||
pipeline_name=m['pipeline_name']
|
)
|
||||||
)
|
db.session.add(model)
|
||||||
db.session.add(model)
|
db.session.flush(objects=[model])
|
||||||
db.session.flush(objects=[model])
|
db.session.refresh(model)
|
||||||
db.session.refresh(model)
|
model.filename = m['url'].split('/')[-1]
|
||||||
if not os.path.exists(model.path) or force_download:
|
r = requests.get(m['url'], stream=True)
|
||||||
r = requests.get(m['url'], stream=True)
|
pbar = tqdm(
|
||||||
pbar = tqdm(
|
desc=f'{model.title} ({model.filename})',
|
||||||
desc=f'{model.title} ({model.filename})',
|
unit="B",
|
||||||
unit="B",
|
unit_scale=True,
|
||||||
unit_scale=True,
|
unit_divisor=1024,
|
||||||
unit_divisor=1024,
|
total=int(r.headers['Content-Length'])
|
||||||
total=int(r.headers['Content-Length'])
|
)
|
||||||
)
|
pbar.clear()
|
||||||
pbar.clear()
|
with open(model.path, 'wb') as f:
|
||||||
with open(model.path, 'wb') as f:
|
for chunk in r.iter_content(chunk_size=1024):
|
||||||
for chunk in r.iter_content(chunk_size=1024):
|
if chunk: # filter out keep-alive new chunks
|
||||||
if chunk: # filter out keep-alive new chunks
|
pbar.update(len(chunk))
|
||||||
pbar.update(len(chunk))
|
f.write(chunk)
|
||||||
f.write(chunk)
|
pbar.close()
|
||||||
pbar.close()
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
|
@ -10,7 +10,7 @@ file-setup-pipeline:
|
|||||||
tesseract-ocr-pipeline:
|
tesseract-ocr-pipeline:
|
||||||
name: 'Tesseract OCR Pipeline'
|
name: 'Tesseract OCR Pipeline'
|
||||||
publisher: 'Bielefeld University - CRC 1288 - INF'
|
publisher: 'Bielefeld University - CRC 1288 - INF'
|
||||||
latest_version: '0.1.2'
|
latest_version: '0.1.1'
|
||||||
versions:
|
versions:
|
||||||
0.1.0:
|
0.1.0:
|
||||||
methods:
|
methods:
|
||||||
@ -23,12 +23,6 @@ tesseract-ocr-pipeline:
|
|||||||
- 'ocropus_nlbin_threshold'
|
- 'ocropus_nlbin_threshold'
|
||||||
publishing_year: 2022
|
publishing_year: 2022
|
||||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/tesseract-ocr-pipeline/-/releases/v0.1.1'
|
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/tesseract-ocr-pipeline/-/releases/v0.1.1'
|
||||||
0.1.2:
|
|
||||||
methods:
|
|
||||||
- 'binarization'
|
|
||||||
- 'ocropus_nlbin_threshold'
|
|
||||||
publishing_year: 2023
|
|
||||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/tesseract-ocr-pipeline/-/releases/v0.1.2'
|
|
||||||
transkribus-htr-pipeline:
|
transkribus-htr-pipeline:
|
||||||
name: 'Transkribus HTR Pipeline'
|
name: 'Transkribus HTR Pipeline'
|
||||||
publisher: 'Bielefeld University - CRC 1288 - INF'
|
publisher: 'Bielefeld University - CRC 1288 - INF'
|
||||||
@ -47,7 +41,7 @@ transkribus-htr-pipeline:
|
|||||||
spacy-nlp-pipeline:
|
spacy-nlp-pipeline:
|
||||||
name: 'SpaCy NLP Pipeline'
|
name: 'SpaCy NLP Pipeline'
|
||||||
publisher: 'Bielefeld University - CRC 1288 - INF'
|
publisher: 'Bielefeld University - CRC 1288 - INF'
|
||||||
latest_version: '0.1.1'
|
latest_version: '0.1.2'
|
||||||
versions:
|
versions:
|
||||||
0.1.0:
|
0.1.0:
|
||||||
methods:
|
methods:
|
||||||
@ -59,3 +53,8 @@ spacy-nlp-pipeline:
|
|||||||
- 'encoding_detection'
|
- 'encoding_detection'
|
||||||
publishing_year: 2022
|
publishing_year: 2022
|
||||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/releases/v0.1.1'
|
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/releases/v0.1.1'
|
||||||
|
0.1.2:
|
||||||
|
methods:
|
||||||
|
- 'encoding_detection'
|
||||||
|
publishing_year: 2022
|
||||||
|
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/releases/v0.1.2'
|
||||||
|
@ -1,108 +1,132 @@
|
|||||||
#corpus-analysis-concordance-query-builder-input-field {
|
.modal-conent {
|
||||||
border-bottom: #9E9E9E 1px solid;
|
|
||||||
min-height: 38px;
|
|
||||||
margin-top: 23px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#corpus-analysis-concordance-query-builder-input-field-placeholder {
|
|
||||||
color: #9E9E9E;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#corpus-analysis-concordance-positional-attr-modal, #corpus-analysis-concordance-corpus-analysis-concordance-structural-attr-modal {
|
#concordance-query-builder {
|
||||||
width: 70%;
|
width: 70%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#corpus-analysis-concordance-general-options-query-builder-tutorial-info-icon {
|
#concordance-query-builder nav {
|
||||||
|
background-color: #6B3F89;
|
||||||
|
margin-top: -25px;
|
||||||
|
margin-left: -25px;
|
||||||
|
width: 105%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#query-builder-nav{
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#close-query-builder {
|
||||||
|
margin-right: 50px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#general-options-query-builder-tutorial-info-icon {
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
#corpus-analysis-concordance-insert-query-button {
|
#your-query {
|
||||||
|
border-bottom-style: solid;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#insert-query-button {
|
||||||
background-color: #00426f;
|
background-color: #00426f;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attr-modal-header {
|
#structural-attr h6 {
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#add-structural-attribute-tutorial-info-icon {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sentence {
|
||||||
|
background-color:#FD9720;
|
||||||
|
}
|
||||||
|
|
||||||
|
#entity {
|
||||||
|
background-color: #A6E22D;
|
||||||
|
}
|
||||||
|
|
||||||
|
#text-annotation {
|
||||||
|
background-color: #2FBBAB;
|
||||||
|
}
|
||||||
|
|
||||||
|
#no-value-metadata-message {
|
||||||
|
padding-top: 25px;
|
||||||
|
margin-left: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#token-kind-selector {
|
||||||
background-color: #f2eff7;
|
background-color: #f2eff7;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
padding-left: 25px;
|
border-top-style: solid;
|
||||||
border-top: 10px solid #6B3F89;
|
border-color: #6B3F89;
|
||||||
margin-left: -24px;
|
|
||||||
margin-top: -24px;
|
|
||||||
margin-right: -24px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.attr-modal-header h6 {
|
#token-kind-selector.s5 {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#token-kind-selector h6 {
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#corpus-analysis-concordance-add-structural-attribute-tutorial-info-icon {
|
#token-tutorial-info-icon {
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-structural-attr-modal-action-button="sentence"]{
|
#no-value-message {
|
||||||
background-color:#FD9720 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-structural-attr-modal-action-button="entity"]{
|
|
||||||
background-color: #A6E22D !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-structural-attr-modal-action-button="meta-data"]{
|
|
||||||
background-color: #2FBBAB !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#corpus-analysis-concordance-no-value-metadata-message {
|
|
||||||
padding-top: 25px;
|
padding-top: 25px;
|
||||||
margin-left: -20px;
|
margin-left: -20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attr-modal-header.input-field {
|
#token-edit-options h6 {
|
||||||
margin-left: 41px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#corpus-analysis-concordance-token-attr {
|
|
||||||
margin-left: 41px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#corpus-analysis-concordance-token-tutorial-info-icon {
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
#corpus-analysis-concordance-no-value-message {
|
|
||||||
padding-top: 25px;
|
|
||||||
margin-left: -20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#corpus-analysis-concordance-token-edit-options h6 {
|
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#corpus-analysis-concordance-edit-options-tutorial-info-icon {
|
#edit-options-tutorial-info-icon {
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-toggle-area="input-field-options"] a {
|
#incidence-modifiers-button a{
|
||||||
margin-right: 10px;
|
background-color: #2FBBAB;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-target="corpus-analysis-concordance-character-incidence-modifiers-dropdown"], [data-target="corpus-analysis-concordance-token-incidence-modifiers-dropdown"] {
|
#incidence-modifiers a{
|
||||||
background-color: #2FBBAB !important;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
#corpus-analysis-concordance-exactly-n-token-modal, #corpus-analysis-concordance-between-nm-token-modal {
|
#ignore-case {
|
||||||
width: 30%;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-modal-id="corpus-analysis-concordance-exactly-n-token-modal"], [data-modal-id="corpus-analysis-concordance-between-nm-token-modal"] {
|
#or, #and {
|
||||||
margin-top: 15px !important;
|
background-color: #fc0;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-options-action="and"], [data-options-action="or"] {
|
#betweenNM {
|
||||||
background-color: #fc0 !important;
|
width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#query-builder-tutorial-modal {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#query-builder-tutorial-modal ul {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#query-builder-tutorial {
|
||||||
|
padding:15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#scroll-up-button-query-builder-tutorial {
|
||||||
|
background-color: #28B3D1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-type="start-sentence"], [data-type="end-sentence"] {
|
[data-type="start-sentence"], [data-type="end-sentence"] {
|
||||||
@ -110,18 +134,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[data-type="start-empty-entity"], [data-type="start-entity"], [data-type="end-entity"] {
|
[data-type="start-empty-entity"], [data-type="start-entity"], [data-type="end-entity"] {
|
||||||
background-color: #a6e22d;
|
background-color: #A6E22D;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-type="text-annotation"]{
|
[data-type="start-text-annotation"]{
|
||||||
background-color: #2FBBAB;
|
background-color: #2FBBAB;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-type="token"] {
|
[data-type="token"] {
|
||||||
background-color: #28B3D1;
|
background-color: #28B3D1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-type="token-incidence-modifier"] {
|
|
||||||
background-color: #4db6ac;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 222 KiB |
Before Width: | Height: | Size: 402 KiB After Width: | Height: | Size: 378 KiB |
Before Width: | Height: | Size: 720 KiB |
Before Width: | Height: | Size: 589 KiB After Width: | Height: | Size: 854 KiB |
Before Width: | Height: | Size: 436 KiB |
Before Width: | Height: | Size: 189 KiB |
Before Width: | Height: | Size: 381 KiB After Width: | Height: | Size: 511 KiB |
Before Width: | Height: | Size: 759 KiB After Width: | Height: | Size: 1009 KiB |
Before Width: | Height: | Size: 750 KiB After Width: | Height: | Size: 903 KiB |
Before Width: | Height: | Size: 524 KiB After Width: | Height: | Size: 413 KiB |
Before Width: | Height: | Size: 23 KiB |
104
app/static/js/App.js
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
class App {
|
||||||
|
constructor() {
|
||||||
|
this.data = {
|
||||||
|
promises: {getUser: {}, subscribeUser: {}},
|
||||||
|
users: {},
|
||||||
|
};
|
||||||
|
this.socket = io({transports: ['websocket'], upgrade: false});
|
||||||
|
this.socket.on('PATCH', (patch) => {this.onPatch(patch);});
|
||||||
|
}
|
||||||
|
|
||||||
|
getUser(userId) {
|
||||||
|
if (userId in this.data.promises.getUser) {
|
||||||
|
return this.data.promises.getUser[userId];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data.promises.getUser[userId] = new Promise((resolve, reject) => {
|
||||||
|
this.socket.emit('GET /users/<user_id>', userId, (response) => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
this.data.users[userId] = response.body;
|
||||||
|
resolve(this.data.users[userId]);
|
||||||
|
} else {
|
||||||
|
reject(`[${response.status}] ${response.statusText}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.data.promises.getUser[userId];
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribeUser(userId) {
|
||||||
|
if (userId in this.data.promises.subscribeUser) {
|
||||||
|
return this.data.promises.subscribeUser[userId];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data.promises.subscribeUser[userId] = new Promise((resolve, reject) => {
|
||||||
|
this.socket.emit('SUBSCRIBE /users/<user_id>', userId, (response) => {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
reject(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(response);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.data.promises.subscribeUser[userId];
|
||||||
|
}
|
||||||
|
|
||||||
|
flash(message, category) {
|
||||||
|
let iconPrefix = '';
|
||||||
|
switch (category) {
|
||||||
|
case 'corpus': {
|
||||||
|
iconPrefix = '<i class="left material-icons">book</i>';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'error': {
|
||||||
|
iconPrefix = '<i class="error-color-text left material-icons">error</i>';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'job': {
|
||||||
|
iconPrefix = '<i class="left nopaque-icons">J</i>';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'settings': {
|
||||||
|
iconPrefix = '<i class="left material-icons">settings</i>';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
iconPrefix = '<i class="left material-icons">notifications</i>';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let toast = M.toast(
|
||||||
|
{
|
||||||
|
html: `
|
||||||
|
<span>${iconPrefix}${message}</span>
|
||||||
|
<button class="action-button btn-flat toast-action white-text" data-action="close">
|
||||||
|
<i class="material-icons">close</i>
|
||||||
|
</button>
|
||||||
|
`.trim()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
let toastCloseActionElement = toast.el.querySelector('.action-button[data-action="close"]');
|
||||||
|
toastCloseActionElement.addEventListener('click', () => {toast.dismiss();});
|
||||||
|
}
|
||||||
|
|
||||||
|
onPatch(patch) {
|
||||||
|
// Filter Patch to only include operations on users that are initialized
|
||||||
|
let regExp = new RegExp(`^/users/(${Object.keys(this.data.users).join('|')})`);
|
||||||
|
let filteredPatch = patch.filter(operation => regExp.test(operation.path));
|
||||||
|
|
||||||
|
// Handle job status updates
|
||||||
|
let subRegExp = new RegExp(`^/users/([A-Za-z0-9]*)/jobs/([A-Za-z0-9]*)/status$`);
|
||||||
|
let subFilteredPatch = filteredPatch
|
||||||
|
.filter((operation) => {return operation.op === 'replace';})
|
||||||
|
.filter((operation) => {return subRegExp.test(operation.path);});
|
||||||
|
for (let operation of subFilteredPatch) {
|
||||||
|
let [match, userId, jobId] = operation.path.match(subRegExp);
|
||||||
|
this.flash(`[<a href="/jobs/${jobId}">${this.data.users[userId].jobs[jobId].title}</a>] New status: <span class="job-status-text" data-status="${operation.value}"></span>`, 'job');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply Patch
|
||||||
|
jsonpatch.applyPatch(this.data, filteredPatch);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
nopaque.corpus_analysis.App = class App {
|
class CorpusAnalysisApp {
|
||||||
constructor(corpusId) {
|
constructor(corpusId) {
|
||||||
this.corpusId = corpusId;
|
this.corpusId = corpusId;
|
||||||
|
|
||||||
@ -6,10 +6,10 @@ nopaque.corpus_analysis.App = class App {
|
|||||||
|
|
||||||
// HTML elements
|
// HTML elements
|
||||||
this.elements = {
|
this.elements = {
|
||||||
container: document.querySelector('#corpus-analysis-container'),
|
container: document.querySelector('#corpus-analysis-app-container'),
|
||||||
extensionCards: document.querySelector('#corpus-analysis-extension-cards'),
|
extensionCards: document.querySelector('#corpus-analysis-app-extension-cards'),
|
||||||
extensionTabs: document.querySelector('#corpus-analysis-extension-tabs'),
|
extensionTabs: document.querySelector('#corpus-analysis-app-extension-tabs'),
|
||||||
initModal: document.querySelector('#corpus-analysis-init-modal')
|
initModal: document.querySelector('#corpus-analysis-app-init-modal')
|
||||||
};
|
};
|
||||||
// Materialize elements
|
// Materialize elements
|
||||||
this.elements.m = {
|
this.elements.m = {
|
||||||
@ -25,12 +25,12 @@ nopaque.corpus_analysis.App = class App {
|
|||||||
async init() {
|
async init() {
|
||||||
this.disableActionElements();
|
this.disableActionElements();
|
||||||
this.elements.m.initModal.open();
|
this.elements.m.initModal.open();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Setup CQi over SocketIO connection and gather data from the CQPServer
|
// Setup CQi over SocketIO connection and gather data from the CQPServer
|
||||||
const statusTextElement = this.elements.initModal.querySelector('.status-text');
|
const statusTextElement = this.elements.initModal.querySelector('.status-text');
|
||||||
statusTextElement.innerText = 'Creating CQi over SocketIO client...';
|
statusTextElement.innerText = 'Creating CQi over SocketIO client...';
|
||||||
const cqiClient = new nopaque.corpus_analysis.cqi.Client('/cqi_over_sio');
|
const cqiClient = new cqi.CQiClient('/cqi_over_sio');
|
||||||
statusTextElement.innerText += ' Done';
|
statusTextElement.innerText += ' Done';
|
||||||
statusTextElement.innerHTML = 'Waiting for the CQP server...';
|
statusTextElement.innerHTML = 'Waiting for the CQP server...';
|
||||||
const response = await cqiClient.api.socket.emitWithAck('init', this.corpusId);
|
const response = await cqiClient.api.socket.emitWithAck('init', this.corpusId);
|
@ -1,4 +1,4 @@
|
|||||||
nopaque.corpus_analysis.ConcordanceExtension = class ConcordanceExtension {
|
class CorpusAnalysisConcordance {
|
||||||
name = 'Concordance';
|
name = 'Concordance';
|
||||||
|
|
||||||
constructor(app) {
|
constructor(app) {
|
||||||
@ -7,38 +7,33 @@ nopaque.corpus_analysis.ConcordanceExtension = class ConcordanceExtension {
|
|||||||
this.data = {};
|
this.data = {};
|
||||||
|
|
||||||
this.elements = {
|
this.elements = {
|
||||||
container: document.querySelector(`#corpus-analysis-concordance-container`),
|
// TODO: Prefix elements with "corpus-analysis-app-"
|
||||||
error: document.querySelector(`#corpus-analysis-concordance-error`),
|
container: document.querySelector('#concordance-extension-container'),
|
||||||
userInterfaceForm: document.querySelector(`#corpus-analysis-concordance-user-interface-form`),
|
error: document.querySelector('#concordance-extension-error'),
|
||||||
expertModeForm: document.querySelector(`#corpus-analysis-concordance-expert-mode-form`),
|
form: document.querySelector('#concordance-extension-form'),
|
||||||
queryBuilderForm: document.querySelector(`#corpus-analysis-concordance-query-builder-form`),
|
progress: document.querySelector('#concordance-extension-progress'),
|
||||||
progress: document.querySelector(`#corpus-analysis-concordance-progress`),
|
subcorpusInfo: document.querySelector('#concordance-extension-subcorpus-info'),
|
||||||
subcorpusInfo: document.querySelector(`#corpus-analysis-concordance-subcorpus-info`),
|
subcorpusActions: document.querySelector('#concordance-extension-subcorpus-actions'),
|
||||||
subcorpusActions: document.querySelector(`#corpus-analysis-concordance-subcorpus-actions`),
|
subcorpusItems: document.querySelector('#concordance-extension-subcorpus-items'),
|
||||||
subcorpusItems: document.querySelector(`#corpus-analysis-concordance-subcorpus-items`),
|
subcorpusList: document.querySelector('#concordance-extension-subcorpus-list'),
|
||||||
subcorpusList: document.querySelector(`#corpus-analysis-concordance-subcorpus-list`),
|
subcorpusPagination: document.querySelector('#concordance-extension-subcorpus-pagination')
|
||||||
subcorpusPagination: document.querySelector(`#corpus-analysis-concordance-subcorpus-pagination`)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.settings = {
|
this.settings = {
|
||||||
context: parseInt(this.elements.userInterfaceForm['context'].value),
|
context: parseInt(this.elements.form['context'].value),
|
||||||
perPage: parseInt(this.elements.userInterfaceForm['per-page'].value),
|
perPage: parseInt(this.elements.form['per-page'].value),
|
||||||
selectedSubcorpus: undefined,
|
selectedSubcorpus: undefined,
|
||||||
textStyle: parseInt(this.elements.userInterfaceForm['text-style'].value),
|
textStyle: parseInt(this.elements.form['text-style'].value),
|
||||||
tokenRepresentation: this.elements.userInterfaceForm['token-representation'].value
|
tokenRepresentation: this.elements.form['token-representation'].value
|
||||||
};
|
};
|
||||||
|
|
||||||
this.app.registerExtension(this);
|
this.app.registerExtension(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async submitForm(queryModeId) {
|
async submitForm() {
|
||||||
this.app.disableActionElements();
|
this.app.disableActionElements();
|
||||||
let queryBuilderQuery = nopaque.Utils.unescape(document.querySelector('#corpus-analysis-concordance-query-preview').innerHTML.trim());
|
let query = this.elements.form.query.value.trim();
|
||||||
let expertModeQuery = this.elements.expertModeForm.query.value.trim();
|
let subcorpusName = this.elements.form['subcorpus-name'].value;
|
||||||
let query = queryModeId === 'corpus-analysis-concordance-expert-mode-form' ? expertModeQuery : queryBuilderQuery;
|
|
||||||
let form = queryModeId === 'corpus-analysis-concordance-expert-mode-form' ? this.elements.expertModeForm : this.elements.queryBuilderForm;
|
|
||||||
|
|
||||||
let subcorpusName = form['subcorpus-name'].value;
|
|
||||||
this.elements.error.innerText = '';
|
this.elements.error.innerText = '';
|
||||||
this.elements.error.classList.add('hide');
|
this.elements.error.classList.add('hide');
|
||||||
this.elements.progress.classList.remove('hide');
|
this.elements.progress.classList.remove('hide');
|
||||||
@ -77,29 +72,25 @@ nopaque.corpus_analysis.ConcordanceExtension = class ConcordanceExtension {
|
|||||||
this.data.corpus = this.app.data.corpus;
|
this.data.corpus = this.app.data.corpus;
|
||||||
this.data.subcorpora = {};
|
this.data.subcorpora = {};
|
||||||
// Add event listeners
|
// Add event listeners
|
||||||
this.elements.expertModeForm.addEventListener('submit', (event) => {
|
this.elements.form.addEventListener('submit', (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.submitForm(this.elements.expertModeForm.id);
|
this.submitForm();
|
||||||
});
|
});
|
||||||
this.elements.queryBuilderForm.addEventListener('submit', (event) => {
|
this.elements.form.addEventListener('change', (event) => {
|
||||||
event.preventDefault();
|
if (event.target === this.elements.form['context']) {
|
||||||
this.submitForm(this.elements.queryBuilderForm.id);
|
this.settings.context = parseInt(this.elements.form['context'].value);
|
||||||
});
|
|
||||||
this.elements.userInterfaceForm.addEventListener('change', (event) => {
|
|
||||||
if (event.target === this.elements.userInterfaceForm['context']) {
|
|
||||||
this.settings.context = parseInt(this.elements.userInterfaceForm['context'].value);
|
|
||||||
this.submitForm();
|
this.submitForm();
|
||||||
}
|
}
|
||||||
if (event.target === this.elements.userInterfaceForm['per-page']) {
|
if (event.target === this.elements.form['per-page']) {
|
||||||
this.settings.perPage = parseInt(this.elements.userInterfaceForm['per-page'].value);
|
this.settings.perPage = parseInt(this.elements.form['per-page'].value);
|
||||||
this.submitForm();
|
this.submitForm();
|
||||||
}
|
}
|
||||||
if (event.target === this.elements.userInterfaceForm['text-style']) {
|
if (event.target === this.elements.form['text-style']) {
|
||||||
this.settings.textStyle = parseInt(this.elements.userInterfaceForm['text-style'].value);
|
this.settings.textStyle = parseInt(this.elements.form['text-style'].value);
|
||||||
this.setTextStyle();
|
this.setTextStyle();
|
||||||
}
|
}
|
||||||
if (event.target === this.elements.userInterfaceForm['token-representation']) {
|
if (event.target === this.elements.form['token-representation']) {
|
||||||
this.settings.tokenRepresentation = this.elements.userInterfaceForm['token-representation'].value;
|
this.settings.tokenRepresentation = this.elements.form['token-representation'].value;
|
||||||
this.setTokenRepresentation();
|
this.setTokenRepresentation();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -171,11 +162,11 @@ nopaque.corpus_analysis.ConcordanceExtension = class ConcordanceExtension {
|
|||||||
this.elements.subcorpusActions.querySelector('.subcorpus-export-trigger').addEventListener('click', (event) => {
|
this.elements.subcorpusActions.querySelector('.subcorpus-export-trigger').addEventListener('click', (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let subcorpus = this.data.subcorpora[this.settings.selectedSubcorpus];
|
let subcorpus = this.data.subcorpora[this.settings.selectedSubcorpus];
|
||||||
let modalElementId = nopaque.Utils.generateElementId('export-subcorpus-modal-');
|
let modalElementId = Utils.generateElementId('export-subcorpus-modal-');
|
||||||
let exportFormatSelectElementId = nopaque.Utils.generateElementId('export-format-select-');
|
let exportFormatSelectElementId = Utils.generateElementId('export-format-select-');
|
||||||
let exportSelectedMatchesOnlyCheckboxElementId = nopaque.Utils.generateElementId('export-selected-matches-only-checkbox-');
|
let exportSelectedMatchesOnlyCheckboxElementId = Utils.generateElementId('export-selected-matches-only-checkbox-');
|
||||||
let exportFileNameInputElementId = nopaque.Utils.generateElementId('export-file-name-input-');
|
let exportFileNameInputElementId = Utils.generateElementId('export-file-name-input-');
|
||||||
let modalElement = nopaque.Utils.HTMLToElement(
|
let modalElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<div class="modal" id="${modalElementId}">
|
<div class="modal" id="${modalElementId}">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -387,9 +378,7 @@ nopaque.corpus_analysis.ConcordanceExtension = class ConcordanceExtension {
|
|||||||
document.getSelection().removeAllRanges();
|
document.getSelection().removeAllRanges();
|
||||||
document.getSelection().addRange(range);
|
document.getSelection().addRange(range);
|
||||||
});
|
});
|
||||||
this.app.elements.m.extensionTabs.select(
|
this.app.elements.m.extensionTabs.select('reader-extension-container');
|
||||||
this.app.extensions.Reader.elements.container.id
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (let selectTriggerElement of this.elements.subcorpusItems.querySelectorAll('.select-trigger')) {
|
for (let selectTriggerElement of this.elements.subcorpusItems.querySelectorAll('.select-trigger')) {
|
@ -1,4 +1,4 @@
|
|||||||
nopaque.corpus_analysis.ReaderExtension = class ReaderExtension {
|
class CorpusAnalysisReader {
|
||||||
name = 'Reader';
|
name = 'Reader';
|
||||||
|
|
||||||
constructor(app) {
|
constructor(app) {
|
||||||
@ -7,18 +7,19 @@ nopaque.corpus_analysis.ReaderExtension = class ReaderExtension {
|
|||||||
this.data = {};
|
this.data = {};
|
||||||
|
|
||||||
this.elements = {
|
this.elements = {
|
||||||
container: document.querySelector(`#corpus-analysis-reader-container`),
|
// TODO: Prefix elements with "corpus-analysis-app-"
|
||||||
corpus: document.querySelector(`#corpus-analysis-reader-corpus`),
|
container: document.querySelector('#reader-extension-container'),
|
||||||
corpusPagination: document.querySelector(`#corpus-analysis-reader-corpus-pagination`),
|
error: document.querySelector('#reader-extension-error'),
|
||||||
error: document.querySelector(`#corpus-analysis-reader-error`),
|
form: document.querySelector('#reader-extension-form'),
|
||||||
progress: document.querySelector(`#corpus-analysis-reader-progress`),
|
progress: document.querySelector('#reader-extension-progress'),
|
||||||
userInterfaceForm: document.querySelector(`#corpus-analysis-reader-user-interface-form`)
|
corpus: document.querySelector('#reader-extension-corpus'),
|
||||||
|
corpusPagination: document.querySelector('#reader-extension-corpus-pagination')
|
||||||
};
|
};
|
||||||
|
|
||||||
this.settings = {
|
this.settings = {
|
||||||
perPage: parseInt(this.elements.userInterfaceForm['per-page'].value),
|
perPage: parseInt(this.elements.form['per-page'].value),
|
||||||
textStyle: parseInt(this.elements.userInterfaceForm['text-style'].value),
|
textStyle: parseInt(this.elements.form['text-style'].value),
|
||||||
tokenRepresentation: this.elements.userInterfaceForm['token-representation'].value,
|
tokenRepresentation: this.elements.form['token-representation'].value,
|
||||||
pagination: {
|
pagination: {
|
||||||
innerWindow: 5,
|
innerWindow: 5,
|
||||||
outerWindow: 1
|
outerWindow: 1
|
||||||
@ -56,21 +57,21 @@ nopaque.corpus_analysis.ReaderExtension = class ReaderExtension {
|
|||||||
// Init data
|
// Init data
|
||||||
this.data.corpus = this.app.data.corpus;
|
this.data.corpus = this.app.data.corpus;
|
||||||
// Add event listeners
|
// Add event listeners
|
||||||
this.elements.userInterfaceForm.addEventListener('submit', (event) => {
|
this.elements.form.addEventListener('submit', (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.submitForm();
|
this.submitForm();
|
||||||
});
|
});
|
||||||
this.elements.userInterfaceForm.addEventListener('change', (event) => {
|
this.elements.form.addEventListener('change', (event) => {
|
||||||
if (event.target === this.elements.userInterfaceForm['per-page']) {
|
if (event.target === this.elements.form['per-page']) {
|
||||||
this.settings.perPage = parseInt(this.elements.userInterfaceForm['per-page'].value);
|
this.settings.perPage = parseInt(this.elements.form['per-page'].value);
|
||||||
this.submitForm();
|
this.submitForm();
|
||||||
}
|
}
|
||||||
if (event.target === this.elements.userInterfaceForm['text-style']) {
|
if (event.target === this.elements.form['text-style']) {
|
||||||
this.settings.textStyle = parseInt(this.elements.userInterfaceForm['text-style'].value);
|
this.settings.textStyle = parseInt(this.elements.form['text-style'].value);
|
||||||
this.setTextStyle();
|
this.setTextStyle();
|
||||||
}
|
}
|
||||||
if (event.target === this.elements.userInterfaceForm['token-representation']) {
|
if (event.target === this.elements.form['token-representation']) {
|
||||||
this.settings.tokenRepresentation = this.elements.userInterfaceForm['token-representation'].value;
|
this.settings.tokenRepresentation = this.elements.form['token-representation'].value;
|
||||||
this.setTokenRepresentation();
|
this.setTokenRepresentation();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -112,7 +113,7 @@ nopaque.corpus_analysis.ReaderExtension = class ReaderExtension {
|
|||||||
if (this.data.corpus.p.pages === 0) {return;}
|
if (this.data.corpus.p.pages === 0) {return;}
|
||||||
let pageElement;
|
let pageElement;
|
||||||
// First page button. Disables first page button if on first page
|
// First page button. Disables first page button if on first page
|
||||||
pageElement = nopaque.Utils.HTMLToElement(
|
pageElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<li class="${this.data.corpus.p.page === 1 ? 'disabled' : 'waves-effect'}">
|
<li class="${this.data.corpus.p.page === 1 ? 'disabled' : 'waves-effect'}">
|
||||||
<a class="corpus-analysis-action pagination-trigger" ${this.data.corpus.p.page === 1 ? '' : 'data-target="1"'}>
|
<a class="corpus-analysis-action pagination-trigger" ${this.data.corpus.p.page === 1 ? '' : 'data-target="1"'}>
|
||||||
@ -123,7 +124,7 @@ nopaque.corpus_analysis.ReaderExtension = class ReaderExtension {
|
|||||||
);
|
);
|
||||||
this.elements.corpusPagination.appendChild(pageElement);
|
this.elements.corpusPagination.appendChild(pageElement);
|
||||||
// Previous page button. Disables previous page button if on first page
|
// Previous page button. Disables previous page button if on first page
|
||||||
pageElement = nopaque.Utils.HTMLToElement(
|
pageElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<li class="${this.data.corpus.p.has_prev ? 'waves-effect' : 'disabled'}">
|
<li class="${this.data.corpus.p.has_prev ? 'waves-effect' : 'disabled'}">
|
||||||
<a class="corpus-analysis-action pagination-trigger" ${this.data.corpus.p.has_prev ? 'data-target="' + this.data.corpus.p.prev_num + '"' : ''}>
|
<a class="corpus-analysis-action pagination-trigger" ${this.data.corpus.p.has_prev ? 'data-target="' + this.data.corpus.p.prev_num + '"' : ''}>
|
||||||
@ -135,7 +136,7 @@ nopaque.corpus_analysis.ReaderExtension = class ReaderExtension {
|
|||||||
this.elements.corpusPagination.appendChild(pageElement);
|
this.elements.corpusPagination.appendChild(pageElement);
|
||||||
// First page as number. Hides first page button if on first page
|
// First page as number. Hides first page button if on first page
|
||||||
if (this.data.corpus.p.page > 6) {
|
if (this.data.corpus.p.page > 6) {
|
||||||
pageElement = nopaque.Utils.HTMLToElement(
|
pageElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<li class="waves-effect">
|
<li class="waves-effect">
|
||||||
<a class="corpus-analysis-action pagination-trigger" data-target="1">1</a>
|
<a class="corpus-analysis-action pagination-trigger" data-target="1">1</a>
|
||||||
@ -143,14 +144,14 @@ nopaque.corpus_analysis.ReaderExtension = class ReaderExtension {
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
this.elements.corpusPagination.appendChild(pageElement);
|
this.elements.corpusPagination.appendChild(pageElement);
|
||||||
pageElement = nopaque.Utils.HTMLToElement("<li style='margin-top: 5px;'>…</li>");
|
pageElement = Utils.HTMLToElement("<li style='margin-top: 5px;'>…</li>");
|
||||||
this.elements.corpusPagination.appendChild(pageElement);
|
this.elements.corpusPagination.appendChild(pageElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
// render page buttons (5 before and 5 after current page)
|
// render page buttons (5 before and 5 after current page)
|
||||||
for (let i = this.data.corpus.p.page - this.settings.pagination.innerWindow; i <= this.data.corpus.p.page; i++) {
|
for (let i = this.data.corpus.p.page - this.settings.pagination.innerWindow; i <= this.data.corpus.p.page; i++) {
|
||||||
if (i <= 0) {continue;}
|
if (i <= 0) {continue;}
|
||||||
pageElement = nopaque.Utils.HTMLToElement(
|
pageElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<li class="${i === this.data.corpus.p.page ? 'active' : 'waves-effect'}">
|
<li class="${i === this.data.corpus.p.page ? 'active' : 'waves-effect'}">
|
||||||
<a class="corpus-analysis-action pagination-trigger" ${i === this.data.corpus.p.page ? '' : 'data-target="' + i + '"'}>${i}</a>
|
<a class="corpus-analysis-action pagination-trigger" ${i === this.data.corpus.p.page ? '' : 'data-target="' + i + '"'}>${i}</a>
|
||||||
@ -161,7 +162,7 @@ nopaque.corpus_analysis.ReaderExtension = class ReaderExtension {
|
|||||||
};
|
};
|
||||||
for (let i = this.data.corpus.p.page +1; i <= this.data.corpus.p.page + this.settings.pagination.innerWindow; i++) {
|
for (let i = this.data.corpus.p.page +1; i <= this.data.corpus.p.page + this.settings.pagination.innerWindow; i++) {
|
||||||
if (i > this.data.corpus.p.pages) {break;}
|
if (i > this.data.corpus.p.pages) {break;}
|
||||||
pageElement = nopaque.Utils.HTMLToElement(
|
pageElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<li class="${i === this.data.corpus.p.page ? 'active' : 'waves-effect'}">
|
<li class="${i === this.data.corpus.p.page ? 'active' : 'waves-effect'}">
|
||||||
<a class="corpus-analysis-action pagination-trigger" ${i === this.data.corpus.p.page ? '' : 'data-target="' + i + '"'}>${i}</a>
|
<a class="corpus-analysis-action pagination-trigger" ${i === this.data.corpus.p.page ? '' : 'data-target="' + i + '"'}>${i}</a>
|
||||||
@ -172,9 +173,9 @@ nopaque.corpus_analysis.ReaderExtension = class ReaderExtension {
|
|||||||
};
|
};
|
||||||
// Last page as number. Hides last page button if on last page
|
// Last page as number. Hides last page button if on last page
|
||||||
if (this.data.corpus.p.page < this.data.corpus.p.pages - 6) {
|
if (this.data.corpus.p.page < this.data.corpus.p.pages - 6) {
|
||||||
pageElement = nopaque.Utils.HTMLToElement("<li style='margin-top: 5px;'>…</li>");
|
pageElement = Utils.HTMLToElement("<li style='margin-top: 5px;'>…</li>");
|
||||||
this.elements.corpusPagination.appendChild(pageElement);
|
this.elements.corpusPagination.appendChild(pageElement);
|
||||||
pageElement = nopaque.Utils.HTMLToElement(
|
pageElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<li class="waves-effect">
|
<li class="waves-effect">
|
||||||
<a class="corpus-analysis-action pagination-trigger" data-target="${this.data.corpus.p.pages}">${this.data.corpus.p.pages}</a>
|
<a class="corpus-analysis-action pagination-trigger" data-target="${this.data.corpus.p.pages}">${this.data.corpus.p.pages}</a>
|
||||||
@ -184,7 +185,7 @@ nopaque.corpus_analysis.ReaderExtension = class ReaderExtension {
|
|||||||
this.elements.corpusPagination.appendChild(pageElement);
|
this.elements.corpusPagination.appendChild(pageElement);
|
||||||
}
|
}
|
||||||
// Next page button. Disables next page button if on last page
|
// Next page button. Disables next page button if on last page
|
||||||
pageElement = nopaque.Utils.HTMLToElement(
|
pageElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<li class="${this.data.corpus.p.has_next ? 'waves-effect' : 'disabled'}">
|
<li class="${this.data.corpus.p.has_next ? 'waves-effect' : 'disabled'}">
|
||||||
<a class="corpus-analysis-action pagination-trigger" ${this.data.corpus.p.has_next ? 'data-target="' + this.data.corpus.p.next_num + '"' : ''}>
|
<a class="corpus-analysis-action pagination-trigger" ${this.data.corpus.p.has_next ? 'data-target="' + this.data.corpus.p.next_num + '"' : ''}>
|
||||||
@ -195,7 +196,7 @@ nopaque.corpus_analysis.ReaderExtension = class ReaderExtension {
|
|||||||
);
|
);
|
||||||
this.elements.corpusPagination.appendChild(pageElement);
|
this.elements.corpusPagination.appendChild(pageElement);
|
||||||
// Last page button. Disables last page button if on last page
|
// Last page button. Disables last page button if on last page
|
||||||
pageElement = nopaque.Utils.HTMLToElement(
|
pageElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<li class="${this.data.corpus.p.page === this.data.corpus.p.pages ? 'disabled' : 'waves-effect'}">
|
<li class="${this.data.corpus.p.page === this.data.corpus.p.pages ? 'disabled' : 'waves-effect'}">
|
||||||
<a class="corpus-analysis-action pagination-trigger" ${this.data.corpus.p.page === this.data.corpus.p.pages ? '' : 'data-target="' + this.data.corpus.p.pages + '"'}>
|
<a class="corpus-analysis-action pagination-trigger" ${this.data.corpus.p.page === this.data.corpus.p.pages ? '' : 'data-target="' + this.data.corpus.p.pages + '"'}>
|
@ -1,4 +1,4 @@
|
|||||||
nopaque.corpus_analysis.StaticVisualizationExtension = class StaticVisualizationExtension {
|
class CorpusAnalysisStaticVisualization {
|
||||||
name = 'Static Visualization (beta)';
|
name = 'Static Visualization (beta)';
|
||||||
|
|
||||||
constructor(app) {
|
constructor(app) {
|
||||||
@ -75,7 +75,7 @@ nopaque.corpus_analysis.StaticVisualizationExtension = class StaticVisualization
|
|||||||
|
|
||||||
getStopwords() {
|
getStopwords() {
|
||||||
this.data.promises.getStopwords = new Promise((resolve, reject) => {
|
this.data.promises.getStopwords = new Promise((resolve, reject) => {
|
||||||
nopaque.requests.corpora.entity.getStopwords()
|
Requests.corpora.entity.getStopwords()
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
response.json()
|
response.json()
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
@ -93,8 +93,8 @@ nopaque.corpus_analysis.StaticVisualizationExtension = class StaticVisualization
|
|||||||
|
|
||||||
renderGeneralCorpusInfo() {
|
renderGeneralCorpusInfo() {
|
||||||
let corpusData = this.data.corpus.o.staticData;
|
let corpusData = this.data.corpus.o.staticData;
|
||||||
document.querySelector('.corpus-num-tokens').innerHTML = corpusData.corpus.bounds[1] - corpusData.corpus.bounds[0];
|
document.querySelector('.corpus-num-tokens').innerHTML = corpusData.corpus.counts.token;
|
||||||
document.querySelector('.corpus-num-s').innerHTML = corpusData.s_attrs.s.lexicon.length;
|
document.querySelector('.corpus-num-s').innerHTML = corpusData.corpus.counts.s;
|
||||||
document.querySelector('.corpus-num-unique-words').innerHTML = Object.entries(corpusData.corpus.freqs.word).length;
|
document.querySelector('.corpus-num-unique-words').innerHTML = Object.entries(corpusData.corpus.freqs.word).length;
|
||||||
document.querySelector('.corpus-num-unique-lemmas').innerHTML = Object.entries(corpusData.corpus.freqs.lemma).length;
|
document.querySelector('.corpus-num-unique-lemmas').innerHTML = Object.entries(corpusData.corpus.freqs.lemma).length;
|
||||||
document.querySelector('.corpus-num-unique-pos').innerHTML = Object.entries(corpusData.corpus.freqs.pos).length;
|
document.querySelector('.corpus-num-unique-pos').innerHTML = Object.entries(corpusData.corpus.freqs.pos).length;
|
||||||
@ -104,18 +104,15 @@ nopaque.corpus_analysis.StaticVisualizationExtension = class StaticVisualization
|
|||||||
renderTextInfoList() {
|
renderTextInfoList() {
|
||||||
let corpusData = this.data.corpus.o.staticData;
|
let corpusData = this.data.corpus.o.staticData;
|
||||||
let corpusTextInfoListElement = document.querySelector('.corpus-text-info-list');
|
let corpusTextInfoListElement = document.querySelector('.corpus-text-info-list');
|
||||||
let corpusTextInfoList = new nopaque.resource_lists.CorpusTextInfoList(corpusTextInfoListElement);
|
let corpusTextInfoList = new CorpusTextInfoList(corpusTextInfoListElement);
|
||||||
let texts = corpusData.s_attrs.text.lexicon;
|
let texts = corpusData.s_attrs.text.lexicon;
|
||||||
let textData = [];
|
let textData = [];
|
||||||
for (let i = 0; i < Object.entries(texts).length; i++) {
|
for (let i = 0; i < Object.entries(texts).length; i++) {
|
||||||
let resource = {
|
let resource = {
|
||||||
title: corpusData.values.s_attrs.text[i].title,
|
title: corpusData.values.s_attrs.text[i].title,
|
||||||
publishing_year: corpusData.values.s_attrs.text[i].publishing_year,
|
publishing_year: corpusData.values.s_attrs.text[i].publishing_year,
|
||||||
// num_sentences: corpusData.s_attrs.text.lexicon[i].counts.s,
|
num_tokens: corpusData.s_attrs.text.lexicon[i].counts.token,
|
||||||
num_tokens: corpusData.s_attrs.text.lexicon[i].bounds[1] - corpusData.s_attrs.text.lexicon[i].bounds[0],
|
num_sentences: corpusData.s_attrs.text.lexicon[i].counts.s,
|
||||||
num_sentences: corpusData.s_attrs.s.lexicon.filter((s) => {
|
|
||||||
return s.bounds[0] >= corpusData.s_attrs.text.lexicon[i].bounds[0] && s.bounds[1] <= corpusData.s_attrs.text.lexicon[i].bounds[1];
|
|
||||||
}).length,
|
|
||||||
num_unique_words: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.word).length,
|
num_unique_words: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.word).length,
|
||||||
num_unique_lemmas: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.lemma).length,
|
num_unique_lemmas: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.lemma).length,
|
||||||
num_unique_pos: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.pos).length,
|
num_unique_pos: Object.entries(corpusData.s_attrs.text.lexicon[i].freqs.pos).length,
|
||||||
@ -128,7 +125,7 @@ nopaque.corpus_analysis.StaticVisualizationExtension = class StaticVisualization
|
|||||||
corpusTextInfoList.add(textData);
|
corpusTextInfoList.add(textData);
|
||||||
|
|
||||||
let textCountChipElement = document.querySelector('.text-count-chip');
|
let textCountChipElement = document.querySelector('.text-count-chip');
|
||||||
textCountChipElement.innerHTML = `Text count: ${corpusData.s_attrs.text.lexicon.length}`;
|
textCountChipElement.innerHTML = `Text count: ${corpusData.corpus.counts.text}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTextProportionsGraphic() {
|
renderTextProportionsGraphic() {
|
||||||
@ -201,7 +198,7 @@ nopaque.corpus_analysis.StaticVisualizationExtension = class StaticVisualization
|
|||||||
default:
|
default:
|
||||||
graphData = [
|
graphData = [
|
||||||
{
|
{
|
||||||
values: texts.map(text => text[1].bounds[1] - text[1].bounds[0]),
|
values: texts.map(text => text[1].counts.token),
|
||||||
labels: texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`),
|
labels: texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`),
|
||||||
type: graphtype
|
type: graphtype
|
||||||
}
|
}
|
||||||
@ -213,7 +210,7 @@ nopaque.corpus_analysis.StaticVisualizationExtension = class StaticVisualization
|
|||||||
|
|
||||||
async renderTokenList() {
|
async renderTokenList() {
|
||||||
let corpusTokenListElement = document.querySelector('.corpus-token-list');
|
let corpusTokenListElement = document.querySelector('.corpus-token-list');
|
||||||
let corpusTokenList = new nopaque.resource_lists.CorpusTokenList(corpusTokenListElement);
|
let corpusTokenList = new CorpusTokenList(corpusTokenListElement);
|
||||||
let filteredData = this.filterData();
|
let filteredData = this.filterData();
|
||||||
let stopwords = this.data.stopwords;
|
let stopwords = this.data.stopwords;
|
||||||
if (this.data.stopwords === undefined) {
|
if (this.data.stopwords === undefined) {
|
||||||
@ -358,7 +355,7 @@ nopaque.corpus_analysis.StaticVisualizationExtension = class StaticVisualization
|
|||||||
if (stopwordLanguageSelection.children.length === 0) {
|
if (stopwordLanguageSelection.children.length === 0) {
|
||||||
Object.keys(stopwords).forEach(language => {
|
Object.keys(stopwords).forEach(language => {
|
||||||
if (language !== 'user_stopwords') {
|
if (language !== 'user_stopwords') {
|
||||||
let optionElement = nopaque.Utils.HTMLToElement(`<option value="${language}" ${language === 'english' ? 'selected' : ''}>${language}</option>`);
|
let optionElement = Utils.HTMLToElement(`<option value="${language}" ${language === 'english' ? 'selected' : ''}>${language}</option>`);
|
||||||
stopwordLanguageSelection.appendChild(optionElement);
|
stopwordLanguageSelection.appendChild(optionElement);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -367,7 +364,7 @@ nopaque.corpus_analysis.StaticVisualizationExtension = class StaticVisualization
|
|||||||
// Render user stopwords over input field.
|
// Render user stopwords over input field.
|
||||||
if (this.data.stopwords['user_stopwords'].length > 0) {
|
if (this.data.stopwords['user_stopwords'].length > 0) {
|
||||||
for (let word of this.data.stopwords['user_stopwords']) {
|
for (let word of this.data.stopwords['user_stopwords']) {
|
||||||
let chipElement = nopaque.Utils.HTMLToElement(`<div class="chip">${word}<i class="close material-icons">close</i></div>`);
|
let chipElement = Utils.HTMLToElement(`<div class="chip">${word}<i class="close material-icons">close</i></div>`);
|
||||||
chipElement.addEventListener('click', (event) => {
|
chipElement.addEventListener('click', (event) => {
|
||||||
let removedListItem = event.target.closest('.chip').firstChild.textContent;
|
let removedListItem = event.target.closest('.chip').firstChild.textContent;
|
||||||
this.data.stopwords['user_stopwords'] = structuredClone(this.data.stopwords['user_stopwords'].filter(item => item !== removedListItem));
|
this.data.stopwords['user_stopwords'] = structuredClone(this.data.stopwords['user_stopwords'].filter(item => item !== removedListItem));
|
||||||
@ -433,7 +430,7 @@ nopaque.corpus_analysis.StaticVisualizationExtension = class StaticVisualization
|
|||||||
let stopwordLanguageChipList = document.querySelector('#stopword-language-chip-list');
|
let stopwordLanguageChipList = document.querySelector('#stopword-language-chip-list');
|
||||||
stopwordLanguageChipList.innerHTML = '';
|
stopwordLanguageChipList.innerHTML = '';
|
||||||
for (let word of stopwords) {
|
for (let word of stopwords) {
|
||||||
let chipElement = nopaque.Utils.HTMLToElement(`<div class="chip">${word}<i class="close material-icons">close</i></div>`);
|
let chipElement = Utils.HTMLToElement(`<div class="chip">${word}<i class="close material-icons">close</i></div>`);
|
||||||
chipElement.addEventListener('click', (event) => {
|
chipElement.addEventListener('click', (event) => {
|
||||||
let removedListItem = event.target.closest('.chip').firstChild.textContent;
|
let removedListItem = event.target.closest('.chip').firstChild.textContent;
|
||||||
this.data.stopwords[language] = structuredClone(this.data.stopwords[language].filter(item => item !== removedListItem));
|
this.data.stopwords[language] = structuredClone(this.data.stopwords[language].filter(item => item !== removedListItem));
|
1007
app/static/js/CorpusAnalysis/QueryBuilder.js
Normal file
18
app/static/js/Forms/CreateContributionForm.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
class CreateContributionForm extends Form {
|
||||||
|
static autoInit() {
|
||||||
|
let createContributionFormElements = document.querySelectorAll('.create-contribution-form');
|
||||||
|
for (let createContributionFormElement of createContributionFormElements) {
|
||||||
|
new CreateContributionForm(createContributionFormElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(formElement) {
|
||||||
|
super(formElement);
|
||||||
|
|
||||||
|
this.addEventListener('requestLoad', (event) => {
|
||||||
|
if (event.target.status === 201) {
|
||||||
|
window.location.href = event.target.getResponseHeader('Location');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
18
app/static/js/Forms/CreateCorpusFileForm.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
class CreateCorpusFileForm extends Form {
|
||||||
|
static autoInit() {
|
||||||
|
let createCorpusFileFormElements = document.querySelectorAll('.create-corpus-file-form');
|
||||||
|
for (let createCorpusFileFormElement of createCorpusFileFormElements) {
|
||||||
|
new CreateCorpusFileForm(createCorpusFileFormElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(formElement) {
|
||||||
|
super(formElement);
|
||||||
|
|
||||||
|
this.addEventListener('requestLoad', (event) => {
|
||||||
|
if (event.target.status === 201) {
|
||||||
|
window.location.href = event.target.getResponseHeader('Location');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,10 @@
|
|||||||
nopaque.forms.CreateJobForm = class CreateJobForm extends nopaque.forms.BaseForm {
|
class CreateJobForm extends Form {
|
||||||
static htmlClass = 'create-job-form';
|
static autoInit() {
|
||||||
|
let createJobFormElements = document.querySelectorAll('.create-job-form');
|
||||||
|
for (let createJobFormElement of createJobFormElements) {
|
||||||
|
new CreateJobForm(createJobFormElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(formElement) {
|
constructor(formElement) {
|
||||||
super(formElement);
|
super(formElement);
|
||||||
@ -17,4 +22,4 @@ nopaque.forms.CreateJobForm = class CreateJobForm extends nopaque.forms.BaseForm
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,5 +1,9 @@
|
|||||||
nopaque.forms.BaseForm = class BaseForm {
|
class Form {
|
||||||
static htmlClass;
|
static autoInit() {
|
||||||
|
CreateContributionForm.autoInit();
|
||||||
|
CreateCorpusFileForm.autoInit();
|
||||||
|
CreateJobForm.autoInit();
|
||||||
|
}
|
||||||
|
|
||||||
constructor(formElement) {
|
constructor(formElement) {
|
||||||
this.formElement = formElement;
|
this.formElement = formElement;
|
||||||
@ -28,7 +32,7 @@ nopaque.forms.BaseForm = class BaseForm {
|
|||||||
|
|
||||||
submit(event) {
|
submit(event) {
|
||||||
let request = new XMLHttpRequest();
|
let request = new XMLHttpRequest();
|
||||||
let modalElement = nopaque.Utils.HTMLToElement(
|
let modalElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -67,7 +71,7 @@ nopaque.forms.BaseForm = class BaseForm {
|
|||||||
for (let selectElement of this.formElement.querySelectorAll('select')) {
|
for (let selectElement of this.formElement.querySelectorAll('select')) {
|
||||||
if (selectElement.value === '') {
|
if (selectElement.value === '') {
|
||||||
let inputFieldElement = selectElement.closest('.input-field');
|
let inputFieldElement = selectElement.closest('.input-field');
|
||||||
let errorHelperTextElement = nopaque.Utils.HTMLToElement(
|
let errorHelperTextElement = Utils.HTMLToElement(
|
||||||
'<span class="helper-text error-color-text" data-helper-text-type="error">Please select an option.</span>'
|
'<span class="helper-text error-color-text" data-helper-text-type="error">Please select an option.</span>'
|
||||||
);
|
);
|
||||||
inputFieldElement.appendChild(errorHelperTextElement);
|
inputFieldElement.appendChild(errorHelperTextElement);
|
||||||
@ -93,7 +97,7 @@ nopaque.forms.BaseForm = class BaseForm {
|
|||||||
.querySelector(`input[name$="${inputName}"], select[name$="${inputName}"]`)
|
.querySelector(`input[name$="${inputName}"], select[name$="${inputName}"]`)
|
||||||
.closest('.input-field');
|
.closest('.input-field');
|
||||||
for (let inputError of inputErrors) {
|
for (let inputError of inputErrors) {
|
||||||
let errorHelperTextElement = nopaque.Utils.HTMLToElement(
|
let errorHelperTextElement = Utils.HTMLToElement(
|
||||||
`<span class="helper-text error-color-text" data-helper-type="error">${inputError}</span>`
|
`<span class="helper-text error-color-text" data-helper-type="error">${inputError}</span>`
|
||||||
);
|
);
|
||||||
inputFieldElement.appendChild(errorHelperTextElement);
|
inputFieldElement.appendChild(errorHelperTextElement);
|
||||||
@ -135,4 +139,4 @@ nopaque.forms.BaseForm = class BaseForm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,6 +1,6 @@
|
|||||||
nopaque.requests = {};
|
let Requests = {};
|
||||||
|
|
||||||
nopaque.requests.JSONfetch = (input, init={}) => {
|
Requests.JSONfetch = (input, init={}) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let fixedInit = {};
|
let fixedInit = {};
|
||||||
fixedInit.headers = {};
|
fixedInit.headers = {};
|
||||||
@ -8,7 +8,7 @@ nopaque.requests.JSONfetch = (input, init={}) => {
|
|||||||
if (init.hasOwnProperty('body')) {
|
if (init.hasOwnProperty('body')) {
|
||||||
fixedInit.headers['Content-Type'] = 'application/json';
|
fixedInit.headers['Content-Type'] = 'application/json';
|
||||||
}
|
}
|
||||||
fetch(input, nopaque.Utils.mergeObjectsDeep(init, fixedInit))
|
fetch(input, Utils.mergeObjectsDeep(init, fixedInit))
|
||||||
.then(
|
.then(
|
||||||
(response) => {
|
(response) => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
20
app/static/js/Requests/admin/admin.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Admin *
|
||||||
|
* Fetch requests for /admin routes *
|
||||||
|
*****************************************************************************/
|
||||||
|
Requests.admin = {};
|
||||||
|
|
||||||
|
Requests.admin.users = {};
|
||||||
|
|
||||||
|
Requests.admin.users.entity = {};
|
||||||
|
|
||||||
|
Requests.admin.users.entity.confirmed = {};
|
||||||
|
|
||||||
|
Requests.admin.users.entity.confirmed.update = (userId, value) => {
|
||||||
|
let input = `/admin/users/${userId}/confirmed`;
|
||||||
|
let init = {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify(value)
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
5
app/static/js/Requests/contributions/contributions.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Contributions *
|
||||||
|
* Fetch requests for /contributions routes *
|
||||||
|
*****************************************************************************/
|
||||||
|
Requests.contributions = {};
|
@ -0,0 +1,26 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* SpaCy NLP Pipeline Models *
|
||||||
|
* Fetch requests for /contributions/spacy-nlp-pipeline-models routes *
|
||||||
|
*****************************************************************************/
|
||||||
|
Requests.contributions.spacy_nlp_pipeline_models = {};
|
||||||
|
|
||||||
|
Requests.contributions.spacy_nlp_pipeline_models.entity = {};
|
||||||
|
|
||||||
|
Requests.contributions.spacy_nlp_pipeline_models.entity.delete = (spacyNlpPipelineModelId) => {
|
||||||
|
let input = `/contributions/spacy-nlp-pipeline-models/${spacyNlpPipelineModelId}`;
|
||||||
|
let init = {
|
||||||
|
method: 'DELETE'
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
||||||
|
|
||||||
|
Requests.contributions.spacy_nlp_pipeline_models.entity.isPublic = {};
|
||||||
|
|
||||||
|
Requests.contributions.spacy_nlp_pipeline_models.entity.isPublic.update = (spacyNlpPipelineModelId, value) => {
|
||||||
|
let input = `/contributions/spacy-nlp-pipeline-models/${spacyNlpPipelineModelId}/is_public`;
|
||||||
|
let init = {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify(value)
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
@ -0,0 +1,26 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Tesseract OCR Pipeline Models *
|
||||||
|
* Fetch requests for /contributions/tesseract-ocr-pipeline-models routes *
|
||||||
|
*****************************************************************************/
|
||||||
|
Requests.contributions.tesseract_ocr_pipeline_models = {};
|
||||||
|
|
||||||
|
Requests.contributions.tesseract_ocr_pipeline_models.entity = {};
|
||||||
|
|
||||||
|
Requests.contributions.tesseract_ocr_pipeline_models.entity.delete = (tesseractOcrPipelineModelId) => {
|
||||||
|
let input = `/contributions/tesseract-ocr-pipeline-models/${tesseractOcrPipelineModelId}`;
|
||||||
|
let init = {
|
||||||
|
method: 'DELETE'
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
||||||
|
|
||||||
|
Requests.contributions.tesseract_ocr_pipeline_models.entity.isPublic = {};
|
||||||
|
|
||||||
|
Requests.contributions.tesseract_ocr_pipeline_models.entity.isPublic.update = (tesseractOcrPipelineModelId, value) => {
|
||||||
|
let input = `/contributions/tesseract-ocr-pipeline-models/${tesseractOcrPipelineModelId}/is_public`;
|
||||||
|
let init = {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify(value)
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
53
app/static/js/Requests/corpora/corpora.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Corpora *
|
||||||
|
* Fetch requests for /corpora routes *
|
||||||
|
*****************************************************************************/
|
||||||
|
Requests.corpora = {};
|
||||||
|
|
||||||
|
Requests.corpora.entity = {};
|
||||||
|
|
||||||
|
Requests.corpora.entity.delete = (corpusId) => {
|
||||||
|
let input = `/corpora/${corpusId}`;
|
||||||
|
let init = {
|
||||||
|
method: 'DELETE'
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
||||||
|
|
||||||
|
Requests.corpora.entity.build = (corpusId) => {
|
||||||
|
let input = `/corpora/${corpusId}/build`;
|
||||||
|
let init = {
|
||||||
|
method: 'POST',
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
||||||
|
|
||||||
|
Requests.corpora.entity.generateShareLink = (corpusId, role, expiration) => {
|
||||||
|
let input = `/corpora/${corpusId}/generate-share-link`;
|
||||||
|
let init = {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({role: role, expiration: expiration})
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
||||||
|
|
||||||
|
Requests.corpora.entity.getStopwords = () => {
|
||||||
|
let input = `/corpora/stopwords`;
|
||||||
|
let init = {
|
||||||
|
method: 'GET'
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
||||||
|
|
||||||
|
Requests.corpora.entity.isPublic = {};
|
||||||
|
|
||||||
|
Requests.corpora.entity.isPublic.update = (corpusId, isPublic) => {
|
||||||
|
let input = `/corpora/${corpusId}/is_public`;
|
||||||
|
let init = {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify(isPublic)
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
15
app/static/js/Requests/corpora/files.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Corpora *
|
||||||
|
* Fetch requests for /corpora/<entity>/files routes *
|
||||||
|
*****************************************************************************/
|
||||||
|
Requests.corpora.entity.files = {};
|
||||||
|
|
||||||
|
Requests.corpora.entity.files.ent = {};
|
||||||
|
|
||||||
|
Requests.corpora.entity.files.ent.delete = (corpusId, corpusFileId) => {
|
||||||
|
let input = `/corpora/${corpusId}/files/${corpusFileId}`;
|
||||||
|
let init = {
|
||||||
|
method: 'DELETE',
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
35
app/static/js/Requests/corpora/followers.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Corpora *
|
||||||
|
* Fetch requests for /corpora/<entity>/followers routes *
|
||||||
|
*****************************************************************************/
|
||||||
|
Requests.corpora.entity.followers = {};
|
||||||
|
|
||||||
|
Requests.corpora.entity.followers.add = (corpusId, usernames) => {
|
||||||
|
let input = `/corpora/${corpusId}/followers`;
|
||||||
|
let init = {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(usernames)
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
||||||
|
|
||||||
|
Requests.corpora.entity.followers.entity = {};
|
||||||
|
|
||||||
|
Requests.corpora.entity.followers.entity.delete = (corpusId, followerId) => {
|
||||||
|
let input = `/corpora/${corpusId}/followers/${followerId}`;
|
||||||
|
let init = {
|
||||||
|
method: 'DELETE',
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
||||||
|
|
||||||
|
Requests.corpora.entity.followers.entity.role = {};
|
||||||
|
|
||||||
|
Requests.corpora.entity.followers.entity.role.update = (corpusId, followerId, value) => {
|
||||||
|
let input = `/corpora/${corpusId}/followers/${followerId}/role`;
|
||||||
|
let init = {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify(value)
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
31
app/static/js/Requests/jobs/jobs.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Jobs *
|
||||||
|
* Fetch requests for /jobs routes *
|
||||||
|
*****************************************************************************/
|
||||||
|
Requests.jobs = {};
|
||||||
|
|
||||||
|
Requests.jobs.entity = {};
|
||||||
|
|
||||||
|
Requests.jobs.entity.delete = (jobId) => {
|
||||||
|
let input = `/jobs/${jobId}`;
|
||||||
|
let init = {
|
||||||
|
method: 'DELETE'
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
}
|
||||||
|
|
||||||
|
Requests.jobs.entity.log = (jobId) => {
|
||||||
|
let input = `/jobs/${jobId}/log`;
|
||||||
|
let init = {
|
||||||
|
method: 'GET'
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
}
|
||||||
|
|
||||||
|
Requests.jobs.entity.restart = (jobId) => {
|
||||||
|
let input = `/jobs/${jobId}/restart`;
|
||||||
|
let init = {
|
||||||
|
method: 'POST'
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
}
|
17
app/static/js/Requests/users/settings.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Settings *
|
||||||
|
* Fetch requests for /users/<entity>/settings routes *
|
||||||
|
*****************************************************************************/
|
||||||
|
Requests.users.entity.settings = {};
|
||||||
|
|
||||||
|
Requests.users.entity.settings.profilePrivacy = {};
|
||||||
|
|
||||||
|
Requests.users.entity.settings.profilePrivacy.update = (userId, profilePrivacySetting, enabled) => {
|
||||||
|
let input = `/users/${userId}/settings/profile-privacy/${profilePrivacySetting}`;
|
||||||
|
let init = {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify(enabled)
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
||||||
|
|
35
app/static/js/Requests/users/users.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Users *
|
||||||
|
* Fetch requests for /users routes *
|
||||||
|
*****************************************************************************/
|
||||||
|
Requests.users = {};
|
||||||
|
|
||||||
|
Requests.users.entity = {};
|
||||||
|
|
||||||
|
Requests.users.entity.delete = (userId) => {
|
||||||
|
let input = `/users/${userId}`;
|
||||||
|
let init = {
|
||||||
|
method: 'DELETE'
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
||||||
|
|
||||||
|
Requests.users.entity.acceptTermsOfUse = () => {
|
||||||
|
let input = `/users/accept-terms-of-use`;
|
||||||
|
let init = {
|
||||||
|
method: 'POST'
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Requests.users.entity.avatar = {};
|
||||||
|
|
||||||
|
Requests.users.entity.avatar.delete = (userId) => {
|
||||||
|
let input = `/users/${userId}/avatar`;
|
||||||
|
let init = {
|
||||||
|
method: 'DELETE'
|
||||||
|
};
|
||||||
|
return Requests.JSONfetch(input, init);
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,11 @@
|
|||||||
nopaque.resource_displays.CorpusDisplay = class CorpusDisplay extends nopaque.resource_displays.ResourceDisplay {
|
class CorpusDisplay extends ResourceDisplay {
|
||||||
static htmlClass = 'corpus-display';
|
|
||||||
|
|
||||||
constructor(displayElement) {
|
constructor(displayElement) {
|
||||||
super(displayElement);
|
super(displayElement);
|
||||||
this.corpusId = displayElement.dataset.corpusId;
|
this.corpusId = displayElement.dataset.corpusId;
|
||||||
this.displayElement
|
this.displayElement
|
||||||
.querySelector('.action-button[data-action="build-request"]')
|
.querySelector('.action-button[data-action="build-request"]')
|
||||||
.addEventListener('click', (event) => {
|
.addEventListener('click', (event) => {
|
||||||
nopaque.requests.corpora.entity.build(this.corpusId);
|
Requests.corpora.entity.build(this.corpusId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,4 +102,4 @@ nopaque.resource_displays.CorpusDisplay = class CorpusDisplay extends nopaque.re
|
|||||||
new Date(creationDate).toLocaleString("en-US")
|
new Date(creationDate).toLocaleString("en-US")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,6 +1,4 @@
|
|||||||
nopaque.resource_displays.JobDisplay = class JobDisplay extends nopaque.resource_displays.ResourceDisplay {
|
class JobDisplay extends ResourceDisplay {
|
||||||
static htmlClass = 'job-display';
|
|
||||||
|
|
||||||
constructor(displayElement) {
|
constructor(displayElement) {
|
||||||
super(displayElement);
|
super(displayElement);
|
||||||
this.jobId = this.displayElement.dataset.jobId;
|
this.jobId = this.displayElement.dataset.jobId;
|
||||||
@ -125,4 +123,4 @@ nopaque.resource_displays.JobDisplay = class JobDisplay extends nopaque.resource
|
|||||||
setServiceVersion(serviceVersion) {
|
setServiceVersion(serviceVersion) {
|
||||||
this.setElements(this.displayElement.querySelectorAll('.job-service-version'), serviceVersion);
|
this.setElements(this.displayElement.querySelectorAll('.job-service-version'), serviceVersion);
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,6 +1,4 @@
|
|||||||
nopaque.resource_displays.ResourceDisplay = class ResourceDisplay {
|
class ResourceDisplay {
|
||||||
static htmlClass;
|
|
||||||
|
|
||||||
constructor(displayElement) {
|
constructor(displayElement) {
|
||||||
this.displayElement = displayElement;
|
this.displayElement = displayElement;
|
||||||
this.userId = this.displayElement.dataset.userId;
|
this.userId = this.displayElement.dataset.userId;
|
||||||
@ -43,4 +41,4 @@ nopaque.resource_displays.ResourceDisplay = class ResourceDisplay {
|
|||||||
this.setElement(element, value);
|
this.setElement(element, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,5 +1,9 @@
|
|||||||
nopaque.resource_lists.AdminUserList = class AdminUserList extends nopaque.resource_lists.ResourceList {
|
class AdminUserList extends ResourceList {
|
||||||
static htmlClass = 'admin-user-list';
|
static autoInit() {
|
||||||
|
for (let adminUserListElement of document.querySelectorAll('.admin-user-list:not(.no-autoinit)')) {
|
||||||
|
new AdminUserList(adminUserListElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(listContainerElement, options = {}) {
|
constructor(listContainerElement, options = {}) {
|
||||||
super(listContainerElement, options);
|
super(listContainerElement, options);
|
||||||
@ -37,9 +41,9 @@ nopaque.resource_lists.AdminUserList = class AdminUserList extends nopaque.resou
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('user-list-');
|
this.listContainerElement.id = Utils.generateElementId('user-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -87,7 +91,7 @@ nopaque.resource_lists.AdminUserList = class AdminUserList extends nopaque.resou
|
|||||||
let listAction = listActionElement === null ? 'view' : listActionElement.dataset.listAction;
|
let listAction = listActionElement === null ? 'view' : listActionElement.dataset.listAction;
|
||||||
switch (listAction) {
|
switch (listAction) {
|
||||||
case 'delete': {
|
case 'delete': {
|
||||||
nopaque.requests.users.entity.delete(itemId);
|
Requests.users.entity.delete(itemId);
|
||||||
if (itemId === currentUserId) {window.location.href = '/';}
|
if (itemId === currentUserId) {window.location.href = '/';}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -104,4 +108,4 @@ nopaque.resource_lists.AdminUserList = class AdminUserList extends nopaque.resou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,5 +1,9 @@
|
|||||||
nopaque.resource_lists.CorpusFileList = class CorpusFileList extends nopaque.resource_lists.ResourceList {
|
class CorpusFileList extends ResourceList {
|
||||||
static htmlClass = 'corpus-file-list';
|
static autoInit() {
|
||||||
|
for (let corpusFileListElement of document.querySelectorAll('.corpus-file-list:not(.no-autoinit)')) {
|
||||||
|
new CorpusFileList(corpusFileListElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(listContainerElement, options = {}) {
|
constructor(listContainerElement, options = {}) {
|
||||||
super(listContainerElement, options);
|
super(listContainerElement, options);
|
||||||
@ -62,9 +66,9 @@ nopaque.resource_lists.CorpusFileList = class CorpusFileList extends nopaque.res
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('corpus-file-list-');
|
this.listContainerElement.id = Utils.generateElementId('corpus-file-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -121,7 +125,7 @@ nopaque.resource_lists.CorpusFileList = class CorpusFileList extends nopaque.res
|
|||||||
switch (listAction) {
|
switch (listAction) {
|
||||||
case 'delete': {
|
case 'delete': {
|
||||||
let values = this.listjs.get('id', itemId)[0].values();
|
let values = this.listjs.get('id', itemId)[0].values();
|
||||||
let modalElement = nopaque.Utils.HTMLToElement(
|
let modalElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -149,12 +153,12 @@ nopaque.resource_lists.CorpusFileList = class CorpusFileList extends nopaque.res
|
|||||||
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
||||||
confirmElement.addEventListener('click', (event) => {
|
confirmElement.addEventListener('click', (event) => {
|
||||||
if (currentUserId != this.userId) {
|
if (currentUserId != this.userId) {
|
||||||
nopaque.requests.corpora.entity.files.ent.delete(this.corpusId, itemId)
|
Requests.corpora.entity.files.ent.delete(this.corpusId, itemId)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
nopaque.requests.corpora.entity.files.ent.delete(this.corpusId, itemId)
|
Requests.corpora.entity.files.ent.delete(this.corpusId, itemId)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
modal.open();
|
modal.open();
|
||||||
@ -208,7 +212,7 @@ nopaque.resource_lists.CorpusFileList = class CorpusFileList extends nopaque.res
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'delete': {
|
case 'delete': {
|
||||||
let modalElement = nopaque.Utils.HTMLToElement(
|
let modalElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -229,7 +233,7 @@ nopaque.resource_lists.CorpusFileList = class CorpusFileList extends nopaque.res
|
|||||||
this.selectedItemIds.forEach(selectedItemId => {
|
this.selectedItemIds.forEach(selectedItemId => {
|
||||||
let listItem = this.listjs.get('id', selectedItemId)[0].elm;
|
let listItem = this.listjs.get('id', selectedItemId)[0].elm;
|
||||||
let values = this.listjs.get('id', listItem.dataset.id)[0].values();
|
let values = this.listjs.get('id', listItem.dataset.id)[0].values();
|
||||||
let itemElement = nopaque.Utils.HTMLToElement(`<li> - ${values.title}</li>`);
|
let itemElement = Utils.HTMLToElement(`<li> - ${values.title}</li>`);
|
||||||
itemList.appendChild(itemElement);
|
itemList.appendChild(itemElement);
|
||||||
});
|
});
|
||||||
let modal = M.Modal.init(
|
let modal = M.Modal.init(
|
||||||
@ -246,12 +250,12 @@ nopaque.resource_lists.CorpusFileList = class CorpusFileList extends nopaque.res
|
|||||||
confirmElement.addEventListener('click', (event) => {
|
confirmElement.addEventListener('click', (event) => {
|
||||||
this.selectedItemIds.forEach(selectedItemId => {
|
this.selectedItemIds.forEach(selectedItemId => {
|
||||||
if (currentUserId != this.userId) {
|
if (currentUserId != this.userId) {
|
||||||
nopaque.requests.corpora.entity.files.ent.delete(this.corpusId, selectedItemId)
|
Requests.corpora.entity.files.ent.delete(this.corpusId, selectedItemId)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
nopaque.requests.corpora.entity.files.ent.delete(this.corpusId, selectedItemId);
|
Requests.corpora.entity.files.ent.delete(this.corpusId, selectedItemId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.selectedItemIds.clear();
|
this.selectedItemIds.clear();
|
||||||
@ -365,4 +369,4 @@ nopaque.resource_lists.CorpusFileList = class CorpusFileList extends nopaque.res
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,5 +1,9 @@
|
|||||||
nopaque.resource_lists.CorpusFollowerList = class CorpusFollowerList extends nopaque.resource_lists.ResourceList {
|
class CorpusFollowerList extends ResourceList {
|
||||||
static htmlClass = 'corpus-follower-list';
|
static autoInit() {
|
||||||
|
for (let corpusFollowerListElement of document.querySelectorAll('.corpus-follower-list:not(.no-autoinit)')) {
|
||||||
|
new CorpusFollowerList(corpusFollowerListElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(listContainerElement, options = {}) {
|
constructor(listContainerElement, options = {}) {
|
||||||
super(listContainerElement, options);
|
super(listContainerElement, options);
|
||||||
@ -18,7 +22,7 @@ nopaque.resource_lists.CorpusFollowerList = class CorpusFollowerList extends nop
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
app.getUser(this.userId).then((user) => {
|
app.getUser(this.userId).then((user) => {
|
||||||
// let corpusFollowerAssociations = Object.values(user.corpora[this.corpusId].corpus_follower_associations);
|
let corpusFollowerAssociations = Object.values(user.corpora[this.corpusId].corpus_follower_associations);
|
||||||
// let filteredList = corpusFollowerAssociations.filter(association => association.follower.id != currentUserId);
|
// let filteredList = corpusFollowerAssociations.filter(association => association.follower.id != currentUserId);
|
||||||
// this.add(filteredList);
|
// this.add(filteredList);
|
||||||
this.add(Object.values(user.corpora[this.corpusId].corpus_follower_associations));
|
this.add(Object.values(user.corpora[this.corpusId].corpus_follower_associations));
|
||||||
@ -68,9 +72,9 @@ nopaque.resource_lists.CorpusFollowerList = class CorpusFollowerList extends nop
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('corpus-follower-list-');
|
this.listContainerElement.id = Utils.generateElementId('corpus-follower-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -120,7 +124,7 @@ nopaque.resource_lists.CorpusFollowerList = class CorpusFollowerList extends nop
|
|||||||
case 'update-role': {
|
case 'update-role': {
|
||||||
let followerId = listItemElement.dataset.followerId;
|
let followerId = listItemElement.dataset.followerId;
|
||||||
let roleName = event.target.value;
|
let roleName = event.target.value;
|
||||||
nopaque.requests.corpora.entity.followers.entity.role.update(this.corpusId, followerId, roleName);
|
Requests.corpora.entity.followers.entity.role.update(this.corpusId, followerId, roleName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@ -140,12 +144,12 @@ nopaque.resource_lists.CorpusFollowerList = class CorpusFollowerList extends nop
|
|||||||
case 'unfollow-request': {
|
case 'unfollow-request': {
|
||||||
let followerId = listItemElement.dataset.followerId;
|
let followerId = listItemElement.dataset.followerId;
|
||||||
if (currentUserId != this.userId) {
|
if (currentUserId != this.userId) {
|
||||||
nopaque.requests.corpora.entity.followers.entity.delete(this.corpusId, followerId)
|
Requests.corpora.entity.followers.entity.delete(this.corpusId, followerId)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
nopaque.requests.corpora.entity.followers.entity.delete(this.corpusId, followerId);
|
Requests.corpora.entity.followers.entity.delete(this.corpusId, followerId);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -192,4 +196,4 @@ nopaque.resource_lists.CorpusFollowerList = class CorpusFollowerList extends nop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,5 +1,9 @@
|
|||||||
nopaque.resource_lists.CorpusList = class CorpusList extends nopaque.resource_lists.ResourceList {
|
class CorpusList extends ResourceList {
|
||||||
static htmlClass = 'corpus-list';
|
static autoInit() {
|
||||||
|
for (let corpusListElement of document.querySelectorAll('.corpus-list:not(.no-autoinit)')) {
|
||||||
|
new CorpusList(corpusListElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(listContainerElement, options = {}) {
|
constructor(listContainerElement, options = {}) {
|
||||||
super(listContainerElement, options);
|
super(listContainerElement, options);
|
||||||
@ -93,9 +97,9 @@ nopaque.resource_lists.CorpusList = class CorpusList extends nopaque.resource_li
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('corpus-list-');
|
this.listContainerElement.id = Utils.generateElementId('corpus-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -139,7 +143,7 @@ nopaque.resource_lists.CorpusList = class CorpusList extends nopaque.resource_li
|
|||||||
switch (listAction) {
|
switch (listAction) {
|
||||||
case 'delete-request': {
|
case 'delete-request': {
|
||||||
let values = this.listjs.get('id', itemId)[0].values();
|
let values = this.listjs.get('id', itemId)[0].values();
|
||||||
let modalElement = nopaque.Utils.HTMLToElement(
|
let modalElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -167,12 +171,12 @@ nopaque.resource_lists.CorpusList = class CorpusList extends nopaque.resource_li
|
|||||||
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
||||||
confirmElement.addEventListener('click', (event) => {
|
confirmElement.addEventListener('click', (event) => {
|
||||||
if (!values['is-owner']) {
|
if (!values['is-owner']) {
|
||||||
nopaque.requests.corpora.entity.followers.entity.delete(itemId, currentUserId)
|
Requests.corpora.entity.followers.entity.delete(itemId, currentUserId)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
nopaque.requests.corpora.entity.delete(itemId);
|
Requests.corpora.entity.delete(itemId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
modal.open();
|
modal.open();
|
||||||
@ -224,7 +228,7 @@ nopaque.resource_lists.CorpusList = class CorpusList extends nopaque.resource_li
|
|||||||
// Saved for future use:
|
// Saved for future use:
|
||||||
// <p class="hide">Do you really want to unfollow this Corpora?</p>
|
// <p class="hide">Do you really want to unfollow this Corpora?</p>
|
||||||
// <ul id="selected-unfollow-items-list"></ul>
|
// <ul id="selected-unfollow-items-list"></ul>
|
||||||
let modalElement = nopaque.Utils.HTMLToElement(
|
let modalElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -245,7 +249,7 @@ nopaque.resource_lists.CorpusList = class CorpusList extends nopaque.resource_li
|
|||||||
this.selectedItemIds.forEach(selectedItemId => {
|
this.selectedItemIds.forEach(selectedItemId => {
|
||||||
let listItem = this.listjs.get('id', selectedItemId)[0].elm;
|
let listItem = this.listjs.get('id', selectedItemId)[0].elm;
|
||||||
let values = this.listjs.get('id', listItem.dataset.id)[0].values();
|
let values = this.listjs.get('id', listItem.dataset.id)[0].values();
|
||||||
let itemElement = nopaque.Utils.HTMLToElement(`<li> - ${values.title}</li>`);
|
let itemElement = Utils.HTMLToElement(`<li> - ${values.title}</li>`);
|
||||||
// if (!values['is-owner']) {
|
// if (!values['is-owner']) {
|
||||||
// itemUnfollowList.appendChild(itemElement);
|
// itemUnfollowList.appendChild(itemElement);
|
||||||
// } else {
|
// } else {
|
||||||
@ -268,9 +272,9 @@ nopaque.resource_lists.CorpusList = class CorpusList extends nopaque.resource_li
|
|||||||
let listItem = this.listjs.get('id', selectedItemId)[0].elm;
|
let listItem = this.listjs.get('id', selectedItemId)[0].elm;
|
||||||
let values = this.listjs.get('id', listItem.dataset.id)[0].values();
|
let values = this.listjs.get('id', listItem.dataset.id)[0].values();
|
||||||
if (values['is-owner']) {
|
if (values['is-owner']) {
|
||||||
nopaque.requests.corpora.entity.delete(selectedItemId);
|
Requests.corpora.entity.delete(selectedItemId);
|
||||||
} else {
|
} else {
|
||||||
nopaque.requests.corpora.entity.followers.entity.delete(selectedItemId, currentUserId);
|
Requests.corpora.entity.followers.entity.delete(selectedItemId, currentUserId);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
@ -366,4 +370,4 @@ nopaque.resource_lists.CorpusList = class CorpusList extends nopaque.resource_li
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,13 +1,18 @@
|
|||||||
nopaque.resource_lists.CorpusTextInfoList = class CorpusTextInfoList extends nopaque.resource_lists.ResourceList {
|
class CorpusTextInfoList extends ResourceList {
|
||||||
static htmlClass = 'corpus-text-info-list';
|
|
||||||
|
static autoInit() {
|
||||||
|
for (let corpusTextInfoListElement of document.querySelectorAll('.corpus-text-info-list:not(.no-autoinit)')) {
|
||||||
|
new CorpusTextInfoList(corpusTextInfoListElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static defaultOptions = {
|
static defaultOptions = {
|
||||||
page: 5
|
page: 5
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(listContainerElement, options = {}) {
|
constructor(listContainerElement, options = {}) {
|
||||||
let _options = nopaque.Utils.mergeObjectsDeep(
|
let _options = Utils.mergeObjectsDeep(
|
||||||
nopaque.resource_lists.CorpusTextInfoList.defaultOptions,
|
CorpusTextInfoList.defaultOptions,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
super(listContainerElement, _options);
|
super(listContainerElement, _options);
|
||||||
@ -21,7 +26,7 @@ nopaque.resource_lists.CorpusTextInfoList = class CorpusTextInfoList extends nop
|
|||||||
get item() {
|
get item() {
|
||||||
return (values) => {
|
return (values) => {
|
||||||
return `
|
return `
|
||||||
<tr class="list-item hoverable">
|
<tr class="list-item clickable hoverable">
|
||||||
<td><span class="title"></span> (<span class="publishing_year"></span>)</td>
|
<td><span class="title"></span> (<span class="publishing_year"></span>)</td>
|
||||||
<td><span class="num_tokens"></span></td>
|
<td><span class="num_tokens"></span></td>
|
||||||
<td><span class="num_sentences"></span></td>
|
<td><span class="num_sentences"></span></td>
|
||||||
@ -49,9 +54,9 @@ nopaque.resource_lists.CorpusTextInfoList = class CorpusTextInfoList extends nop
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('corpus-file-list-');
|
this.listContainerElement.id = Utils.generateElementId('corpus-file-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -104,4 +109,4 @@ nopaque.resource_lists.CorpusTextInfoList = class CorpusTextInfoList extends nop
|
|||||||
clickedSortElement.style.color = '#aa9cc9';
|
clickedSortElement.style.color = '#aa9cc9';
|
||||||
clickedSortElement.innerHTML = clickedSortElement.classList.contains('asc') ? 'arrow_drop_down' : 'arrow_drop_up';
|
clickedSortElement.innerHTML = clickedSortElement.classList.contains('asc') ? 'arrow_drop_down' : 'arrow_drop_up';
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,13 +1,17 @@
|
|||||||
nopaque.resource_lists.CorpusTokenList = class CorpusTokenList extends nopaque.resource_lists.ResourceList {
|
class CorpusTokenList extends ResourceList {
|
||||||
static htmlClass = 'corpus-token-list';
|
static autoInit() {
|
||||||
|
for (let corpusTokenListElement of document.querySelectorAll('.corpus-token-list:not(.no-autoinit)')) {
|
||||||
|
new CorpusTokenList(corpusTokenListElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static defaultOptions = {
|
static defaultOptions = {
|
||||||
page: 7
|
page: 7
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(listContainerElement, options = {}) {
|
constructor(listContainerElement, options = {}) {
|
||||||
let _options = nopaque.Utils.mergeObjectsDeep(
|
let _options = Utils.mergeObjectsDeep(
|
||||||
nopaque.resource_lists.CorpusTokenList.defaultOptions,
|
CorpusTokenList.defaultOptions,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
super(listContainerElement, _options);
|
super(listContainerElement, _options);
|
||||||
@ -72,9 +76,9 @@ nopaque.resource_lists.CorpusTokenList = class CorpusTokenList extends nopaque.r
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('corpus-token-list-');
|
this.listContainerElement.id = Utils.generateElementId('corpus-token-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -134,4 +138,4 @@ nopaque.resource_lists.CorpusTokenList = class CorpusTokenList extends nopaque.r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
@ -1,6 +1,4 @@
|
|||||||
nopaque.resource_lists.DetailedPublicCorpusList = class DetailedPublicCorpusList extends nopaque.resource_lists.ResourceList {
|
class DetailledPublicCorpusList extends CorpusList {
|
||||||
static htmlClass = 'detailed-public-corpus-list';
|
|
||||||
|
|
||||||
get item() {
|
get item() {
|
||||||
return (values) => {
|
return (values) => {
|
||||||
return `
|
return `
|
||||||
@ -32,9 +30,9 @@ nopaque.resource_lists.DetailedPublicCorpusList = class DetailedPublicCorpusList
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('corpus-list-');
|
this.listContainerElement.id = Utils.generateElementId('corpus-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -70,4 +68,4 @@ nopaque.resource_lists.DetailedPublicCorpusList = class DetailedPublicCorpusList
|
|||||||
'current-user-is-following': Object.values(corpus.corpus_follower_associations).some(association => association.follower.id === currentUserId)
|
'current-user-is-following': Object.values(corpus.corpus_follower_associations).some(association => association.follower.id === currentUserId)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,5 +1,9 @@
|
|||||||
nopaque.resource_lists.JobInputList = class JobInputList extends nopaque.resource_lists.ResourceList {
|
class JobInputList extends ResourceList {
|
||||||
static htmlClass = 'job-input-list';
|
static autoInit() {
|
||||||
|
for (let jobInputListElement of document.querySelectorAll('.job-input-list:not(.no-autoinit)')) {
|
||||||
|
new JobInputList(jobInputListElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(listContainerElement, options = {}) {
|
constructor(listContainerElement, options = {}) {
|
||||||
super(listContainerElement, options);
|
super(listContainerElement, options);
|
||||||
@ -36,9 +40,9 @@ nopaque.resource_lists.JobInputList = class JobInputList extends nopaque.resourc
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('job-input-list-');
|
this.listContainerElement.id = Utils.generateElementId('job-input-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -86,4 +90,4 @@ nopaque.resource_lists.JobInputList = class JobInputList extends nopaque.resourc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,5 +1,9 @@
|
|||||||
nopaque.resource_lists.JobList = class JobList extends nopaque.resource_lists.ResourceList {
|
class JobList extends ResourceList {
|
||||||
static htmlClass = 'job-list';
|
static autoInit() {
|
||||||
|
for (let jobListElement of document.querySelectorAll('.job-list:not(.no-autoinit)')) {
|
||||||
|
new JobList(jobListElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(listContainerElement, options = {}) {
|
constructor(listContainerElement, options = {}) {
|
||||||
super(listContainerElement, options);
|
super(listContainerElement, options);
|
||||||
@ -25,7 +29,7 @@ nopaque.resource_lists.JobList = class JobList extends nopaque.resource_lists.Re
|
|||||||
|
|
||||||
get item() {
|
get item() {
|
||||||
return `
|
return `
|
||||||
<tr class="list-item service-scheme clickable hoverable">
|
<tr class="list-item service-scheme">
|
||||||
<td>
|
<td>
|
||||||
<label class="list-action-trigger" data-list-action="select">
|
<label class="list-action-trigger" data-list-action="select">
|
||||||
<input class="select-checkbox" type="checkbox">
|
<input class="select-checkbox" type="checkbox">
|
||||||
@ -56,9 +60,9 @@ nopaque.resource_lists.JobList = class JobList extends nopaque.resource_lists.Re
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('job-list-');
|
this.listContainerElement.id = Utils.generateElementId('job-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -108,11 +112,11 @@ nopaque.resource_lists.JobList = class JobList extends nopaque.resource_lists.Re
|
|||||||
if (listItemElement === null) {return;}
|
if (listItemElement === null) {return;}
|
||||||
let itemId = listItemElement.dataset.id;
|
let itemId = listItemElement.dataset.id;
|
||||||
let listActionElement = event.target.closest('.list-action-trigger[data-list-action]');
|
let listActionElement = event.target.closest('.list-action-trigger[data-list-action]');
|
||||||
let listAction = listActionElement === null ? 'view' : listActionElement.dataset.listAction;
|
let listAction = listActionElement === null ? '' : listActionElement.dataset.listAction;
|
||||||
switch (listAction) {
|
switch (listAction) {
|
||||||
case 'delete-request': {
|
case 'delete-request': {
|
||||||
let values = this.listjs.get('id', itemId)[0].values();
|
let values = this.listjs.get('id', itemId)[0].values();
|
||||||
let modalElement = nopaque.Utils.HTMLToElement(
|
let modalElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -139,7 +143,7 @@ nopaque.resource_lists.JobList = class JobList extends nopaque.resource_lists.Re
|
|||||||
);
|
);
|
||||||
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
||||||
confirmElement.addEventListener('click', (event) => {
|
confirmElement.addEventListener('click', (event) => {
|
||||||
nopaque.requests.jobs.entity.delete(itemId);
|
Requests.jobs.entity.delete(itemId);
|
||||||
});
|
});
|
||||||
modal.open();
|
modal.open();
|
||||||
break;
|
break;
|
||||||
@ -187,7 +191,7 @@ nopaque.resource_lists.JobList = class JobList extends nopaque.resource_lists.Re
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'delete': {
|
case 'delete': {
|
||||||
let modalElement = nopaque.Utils.HTMLToElement(
|
let modalElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -208,7 +212,7 @@ nopaque.resource_lists.JobList = class JobList extends nopaque.resource_lists.Re
|
|||||||
this.selectedItemIds.forEach(selectedItemId => {
|
this.selectedItemIds.forEach(selectedItemId => {
|
||||||
let listItem = this.listjs.get('id', selectedItemId)[0].elm;
|
let listItem = this.listjs.get('id', selectedItemId)[0].elm;
|
||||||
let values = this.listjs.get('id', listItem.dataset.id)[0].values();
|
let values = this.listjs.get('id', listItem.dataset.id)[0].values();
|
||||||
let itemElement = nopaque.Utils.HTMLToElement(`<li> - ${values.title}</li>`);
|
let itemElement = Utils.HTMLToElement(`<li> - ${values.title}</li>`);
|
||||||
itemList.appendChild(itemElement);
|
itemList.appendChild(itemElement);
|
||||||
});
|
});
|
||||||
let modal = M.Modal.init(
|
let modal = M.Modal.init(
|
||||||
@ -224,7 +228,7 @@ nopaque.resource_lists.JobList = class JobList extends nopaque.resource_lists.Re
|
|||||||
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
||||||
confirmElement.addEventListener('click', (event) => {
|
confirmElement.addEventListener('click', (event) => {
|
||||||
this.selectedItemIds.forEach(selectedItemId => {
|
this.selectedItemIds.forEach(selectedItemId => {
|
||||||
nopaque.requests.jobs.entity.delete(selectedItemId);
|
Requests.jobs.entity.delete(selectedItemId);
|
||||||
});
|
});
|
||||||
this.selectedItemIds.clear();
|
this.selectedItemIds.clear();
|
||||||
this.renderingItemSelection();
|
this.renderingItemSelection();
|
||||||
@ -319,4 +323,4 @@ nopaque.resource_lists.JobList = class JobList extends nopaque.resource_lists.Re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,5 +1,9 @@
|
|||||||
nopaque.resource_lists.JobResultList = class JobResultList extends nopaque.resource_lists.ResourceList {
|
class JobResultList extends ResourceList {
|
||||||
static htmlClass = 'job-result-list';
|
static autoInit() {
|
||||||
|
for (let jobResultListElement of document.querySelectorAll('.job-result-list:not(.no-autoinit)')) {
|
||||||
|
new JobResultList(jobResultListElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(listContainerElement, options = {}) {
|
constructor(listContainerElement, options = {}) {
|
||||||
super(listContainerElement, options);
|
super(listContainerElement, options);
|
||||||
@ -42,9 +46,9 @@ nopaque.resource_lists.JobResultList = class JobResultList extends nopaque.resou
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('job-result-list-');
|
this.listContainerElement.id = Utils.generateElementId('job-result-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -111,4 +115,4 @@ nopaque.resource_lists.JobResultList = class JobResultList extends nopaque.resou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,11 +1,4 @@
|
|||||||
nopaque.resource_lists.PublicCorpusList = class PublicCorpusList extends nopaque.resource_lists.ResourceList {
|
class PublicCorpusList extends CorpusList {
|
||||||
static htmlClass = 'public-corpus-list';
|
|
||||||
|
|
||||||
constructor(listContainerElement, options = {}) {
|
|
||||||
super(listContainerElement, options);
|
|
||||||
this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
|
|
||||||
}
|
|
||||||
|
|
||||||
get item() {
|
get item() {
|
||||||
return (values) => {
|
return (values) => {
|
||||||
return `
|
return `
|
||||||
@ -21,19 +14,6 @@ nopaque.resource_lists.PublicCorpusList = class PublicCorpusList extends nopaque
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get valueNames() {
|
|
||||||
return [
|
|
||||||
{data: ['id']},
|
|
||||||
{data: ['creation-date']},
|
|
||||||
{name: 'status', attr: 'data-status'},
|
|
||||||
'description',
|
|
||||||
'title',
|
|
||||||
'owner',
|
|
||||||
'is-owner',
|
|
||||||
'current-user-is-following'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
mapResourceToValue(corpus) {
|
mapResourceToValue(corpus) {
|
||||||
return {
|
return {
|
||||||
'id': corpus.id,
|
'id': corpus.id,
|
||||||
@ -49,9 +29,9 @@ nopaque.resource_lists.PublicCorpusList = class PublicCorpusList extends nopaque
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('corpus-list-');
|
this.listContainerElement.id = Utils.generateElementId('corpus-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -72,21 +52,4 @@ nopaque.resource_lists.PublicCorpusList = class PublicCorpusList extends nopaque
|
|||||||
<ul class="pagination"></ul>
|
<ul class="pagination"></ul>
|
||||||
`.trim();
|
`.trim();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
onClick(event) {
|
|
||||||
let listItemElement = event.target.closest('.list-item[data-id]');
|
|
||||||
if (listItemElement === null) {return;}
|
|
||||||
let itemId = listItemElement.dataset.id;
|
|
||||||
let listActionElement = event.target.closest('.list-action-trigger[data-list-action]');
|
|
||||||
let listAction = listActionElement === null ? 'view' : listActionElement.dataset.listAction;
|
|
||||||
switch (listAction) {
|
|
||||||
case 'view': {
|
|
||||||
window.location.href = `/corpora/${itemId}`;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,10 +1,23 @@
|
|||||||
nopaque.resource_lists.ResourceList = class ResourceList {
|
class ResourceList {
|
||||||
/* A wrapper class for the list.js list.
|
/* A wrapper class for the list.js list.
|
||||||
* This class is not meant to be used directly, instead it should be used as
|
* This class is not meant to be used directly, instead it should be used as
|
||||||
* a base class for concrete resource list implementations.
|
* a base class for concrete resource list implementations.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static htmlClass;
|
static autoInit() {
|
||||||
|
CorpusList.autoInit();
|
||||||
|
CorpusFileList.autoInit();
|
||||||
|
JobList.autoInit();
|
||||||
|
JobInputList.autoInit();
|
||||||
|
JobResultList.autoInit();
|
||||||
|
SpaCyNLPPipelineModelList.autoInit();
|
||||||
|
TesseractOCRPipelineModelList.autoInit();
|
||||||
|
UserList.autoInit();
|
||||||
|
AdminUserList.autoInit();
|
||||||
|
CorpusFollowerList.autoInit();
|
||||||
|
CorpusTextInfoList.autoInit();
|
||||||
|
CorpusTokenList.autoInit();
|
||||||
|
}
|
||||||
|
|
||||||
static defaultOptions = {
|
static defaultOptions = {
|
||||||
page: 5,
|
page: 5,
|
||||||
@ -21,9 +34,9 @@ nopaque.resource_lists.ResourceList = class ResourceList {
|
|||||||
if ('valueNames' in options) {
|
if ('valueNames' in options) {
|
||||||
throw '"valueNames" is not supported as an option, define it as a getter in the list class';
|
throw '"valueNames" is not supported as an option, define it as a getter in the list class';
|
||||||
}
|
}
|
||||||
let _options = nopaque.Utils.mergeObjectsDeep(
|
let _options = Utils.mergeObjectsDeep(
|
||||||
{item: this.item, valueNames: this.valueNames},
|
{item: this.item, valueNames: this.valueNames},
|
||||||
nopaque.resource_lists.ResourceList.defaultOptions,
|
ResourceList.defaultOptions,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
this.listContainerElement = listContainerElement;
|
this.listContainerElement = listContainerElement;
|
@ -1,5 +1,9 @@
|
|||||||
nopaque.resource_lists.SpaCyNLPPipelineModelList = class SpaCyNLPPipelineModelList extends nopaque.resource_lists.ResourceList {
|
class SpaCyNLPPipelineModelList extends ResourceList {
|
||||||
static htmlClass = 'spacy-nlp-pipeline-model-list';
|
static autoInit() {
|
||||||
|
for (let spaCyNLPPipelineModelListElement of document.querySelectorAll('.spacy-nlp-pipeline-model-list:not(.no-autoinit)')) {
|
||||||
|
new SpaCyNLPPipelineModelList(spaCyNLPPipelineModelListElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(listContainerElement, options = {}) {
|
constructor(listContainerElement, options = {}) {
|
||||||
super(listContainerElement, options);
|
super(listContainerElement, options);
|
||||||
@ -60,9 +64,9 @@ nopaque.resource_lists.SpaCyNLPPipelineModelList = class SpaCyNLPPipelineModelLi
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('spacy-nlp-pipeline-model-list-');
|
this.listContainerElement.id = Utils.generateElementId('spacy-nlp-pipeline-model-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -116,7 +120,7 @@ nopaque.resource_lists.SpaCyNLPPipelineModelList = class SpaCyNLPPipelineModelLi
|
|||||||
switch (listAction) {
|
switch (listAction) {
|
||||||
case 'toggle-is-public': {
|
case 'toggle-is-public': {
|
||||||
let newIsPublicValue = listActionElement.checked;
|
let newIsPublicValue = listActionElement.checked;
|
||||||
nopaque.requests.contributions.spacy_nlp_pipeline_models.entity.isPublic.update(itemId, newIsPublicValue)
|
Requests.contributions.spacy_nlp_pipeline_models.entity.isPublic.update(itemId, newIsPublicValue)
|
||||||
.catch((response) => {
|
.catch((response) => {
|
||||||
listActionElement.checked = !newIsPublicValue;
|
listActionElement.checked = !newIsPublicValue;
|
||||||
});
|
});
|
||||||
@ -138,7 +142,7 @@ nopaque.resource_lists.SpaCyNLPPipelineModelList = class SpaCyNLPPipelineModelLi
|
|||||||
switch (listAction) {
|
switch (listAction) {
|
||||||
case 'delete-request': {
|
case 'delete-request': {
|
||||||
let values = this.listjs.get('id', itemId)[0].values();
|
let values = this.listjs.get('id', itemId)[0].values();
|
||||||
let modalElement = nopaque.Utils.HTMLToElement(
|
let modalElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -165,7 +169,7 @@ nopaque.resource_lists.SpaCyNLPPipelineModelList = class SpaCyNLPPipelineModelLi
|
|||||||
);
|
);
|
||||||
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
||||||
confirmElement.addEventListener('click', (event) => {
|
confirmElement.addEventListener('click', (event) => {
|
||||||
nopaque.requests.contributions.spacy_nlp_pipeline_models.entity.delete(itemId);
|
Requests.contributions.spacy_nlp_pipeline_models.entity.delete(itemId);
|
||||||
});
|
});
|
||||||
modal.open();
|
modal.open();
|
||||||
break;
|
break;
|
||||||
@ -216,4 +220,4 @@ nopaque.resource_lists.SpaCyNLPPipelineModelList = class SpaCyNLPPipelineModelLi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,5 +1,9 @@
|
|||||||
nopaque.resource_lists.TesseractOCRPipelineModelList = class TesseractOCRPipelineModelList extends nopaque.resource_lists.ResourceList {
|
class TesseractOCRPipelineModelList extends ResourceList {
|
||||||
static htmlClass = 'tesseract-ocr-pipeline-model-list';
|
static autoInit() {
|
||||||
|
for (let tesseractOCRPipelineModelListElement of document.querySelectorAll('.tesseract-ocr-pipeline-model-list:not(.no-autoinit)')) {
|
||||||
|
new TesseractOCRPipelineModelList(tesseractOCRPipelineModelListElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(listContainerElement, options = {}) {
|
constructor(listContainerElement, options = {}) {
|
||||||
super(listContainerElement, options);
|
super(listContainerElement, options);
|
||||||
@ -69,9 +73,9 @@ nopaque.resource_lists.TesseractOCRPipelineModelList = class TesseractOCRPipelin
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('tesseract-ocr-pipeline-model-list-');
|
this.listContainerElement.id = Utils.generateElementId('tesseract-ocr-pipeline-model-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -125,7 +129,7 @@ nopaque.resource_lists.TesseractOCRPipelineModelList = class TesseractOCRPipelin
|
|||||||
switch (listAction) {
|
switch (listAction) {
|
||||||
case 'toggle-is-public': {
|
case 'toggle-is-public': {
|
||||||
let newIsPublicValue = listActionElement.checked;
|
let newIsPublicValue = listActionElement.checked;
|
||||||
nopaque.requests.contributions.tesseract_ocr_pipeline_models.entity.isPublic.update(itemId, newIsPublicValue)
|
Requests.contributions.tesseract_ocr_pipeline_models.entity.isPublic.update(itemId, newIsPublicValue)
|
||||||
.catch((response) => {
|
.catch((response) => {
|
||||||
listActionElement.checked = !newIsPublicValue;
|
listActionElement.checked = !newIsPublicValue;
|
||||||
});
|
});
|
||||||
@ -147,7 +151,7 @@ nopaque.resource_lists.TesseractOCRPipelineModelList = class TesseractOCRPipelin
|
|||||||
switch (listAction) {
|
switch (listAction) {
|
||||||
case 'delete-request': {
|
case 'delete-request': {
|
||||||
let values = this.listjs.get('id', itemId)[0].values();
|
let values = this.listjs.get('id', itemId)[0].values();
|
||||||
let modalElement = nopaque.Utils.HTMLToElement(
|
let modalElement = Utils.HTMLToElement(
|
||||||
`
|
`
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -174,7 +178,7 @@ nopaque.resource_lists.TesseractOCRPipelineModelList = class TesseractOCRPipelin
|
|||||||
);
|
);
|
||||||
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
||||||
confirmElement.addEventListener('click', (event) => {
|
confirmElement.addEventListener('click', (event) => {
|
||||||
nopaque.requests.contributions.tesseract_ocr_pipeline_models.entity.delete(itemId);
|
Requests.contributions.tesseract_ocr_pipeline_models.entity.delete(itemId);
|
||||||
});
|
});
|
||||||
modal.open();
|
modal.open();
|
||||||
break;
|
break;
|
||||||
@ -225,4 +229,4 @@ nopaque.resource_lists.TesseractOCRPipelineModelList = class TesseractOCRPipelin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,5 +1,9 @@
|
|||||||
nopaque.resource_lists.PublicUserList = class PublicUserList extends nopaque.resource_lists.ResourceList {
|
class UserList extends ResourceList {
|
||||||
static htmlClass = 'public-user-list';
|
static autoInit() {
|
||||||
|
for (let userListElement of document.querySelectorAll('.user-list:not(.no-autoinit)')) {
|
||||||
|
new UserList(userListElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructor(listContainerElement, options = {}) {
|
constructor(listContainerElement, options = {}) {
|
||||||
super(listContainerElement, options);
|
super(listContainerElement, options);
|
||||||
@ -37,9 +41,9 @@ nopaque.resource_lists.PublicUserList = class PublicUserList extends nopaque.res
|
|||||||
|
|
||||||
initListContainerElement() {
|
initListContainerElement() {
|
||||||
if (!this.listContainerElement.hasAttribute('id')) {
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
this.listContainerElement.id = nopaque.Utils.generateElementId('user-list-');
|
this.listContainerElement.id = Utils.generateElementId('user-list-');
|
||||||
}
|
}
|
||||||
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
this.listContainerElement.innerHTML = `
|
this.listContainerElement.innerHTML = `
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">search</i>
|
<i class="material-icons prefix">search</i>
|
||||||
@ -97,4 +101,4 @@ nopaque.resource_lists.PublicUserList = class PublicUserList extends nopaque.res
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
@ -1,7 +1,7 @@
|
|||||||
nopaque.Utils = class Utils {
|
class Utils {
|
||||||
static escape(text) {
|
static escape(text) {
|
||||||
// https://codereview.stackexchange.com/a/126722
|
// https://codereview.stackexchange.com/a/126722
|
||||||
let lookup = {
|
var table = {
|
||||||
'<': 'lt',
|
'<': 'lt',
|
||||||
'>': 'gt',
|
'>': 'gt',
|
||||||
'"': 'quot',
|
'"': 'quot',
|
||||||
@ -10,31 +10,11 @@ nopaque.Utils = class Utils {
|
|||||||
'\r': '#10',
|
'\r': '#10',
|
||||||
'\n': '#13'
|
'\n': '#13'
|
||||||
};
|
};
|
||||||
|
|
||||||
return text.toString().replace(/[<>"'\r\n&]/g, (chr) => {
|
|
||||||
return '&' + lookup[chr] + ';';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static unescape(escapedText) {
|
|
||||||
let lookup = {
|
|
||||||
'lt': '<',
|
|
||||||
'gt': '>',
|
|
||||||
'quot': '"',
|
|
||||||
'apos': "'",
|
|
||||||
'amp': '&',
|
|
||||||
'#10': '\r',
|
|
||||||
'#13': '\n'
|
|
||||||
};
|
|
||||||
|
|
||||||
return escapedText.replace(/&(#?\w+);/g, (match, entity) => {
|
return text.toString().replace(/[<>"'\r\n&]/g, (chr) => {
|
||||||
if (lookup.hasOwnProperty(entity)) {
|
return '&' + table[chr] + ';';
|
||||||
return lookup[entity];
|
|
||||||
}
|
|
||||||
|
|
||||||
return match;
|
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
static HTMLToElement(HTMLString) {
|
static HTMLToElement(HTMLString) {
|
||||||
let templateElement = document.createElement('template');
|
let templateElement = document.createElement('template');
|
||||||
@ -58,16 +38,16 @@ nopaque.Utils = class Utils {
|
|||||||
if (objects.length === 0) {
|
if (objects.length === 0) {
|
||||||
return mergedObject;
|
return mergedObject;
|
||||||
}
|
}
|
||||||
if (!this.isObject(objects[0])) {throw 'Cannot merge non-object';}
|
if (!Utils.isObject(objects[0])) {throw 'Cannot merge non-object';}
|
||||||
if (objects.length === 1) {
|
if (objects.length === 1) {
|
||||||
return this.mergeObjectsDeep(mergedObject, objects[0]);
|
return Utils.mergeObjectsDeep(mergedObject, objects[0]);
|
||||||
}
|
}
|
||||||
if (!this.isObject(objects[1])) {throw 'Cannot merge non-object';}
|
if (!Utils.isObject(objects[1])) {throw 'Cannot merge non-object';}
|
||||||
for (let key in objects[0]) {
|
for (let key in objects[0]) {
|
||||||
if (objects[0].hasOwnProperty(key)) {
|
if (objects[0].hasOwnProperty(key)) {
|
||||||
if (objects[1].hasOwnProperty(key)) {
|
if (objects[1].hasOwnProperty(key)) {
|
||||||
if (this.isObject(objects[0][key]) && this.isObject(objects[1][key])) {
|
if (Utils.isObject(objects[0][key]) && Utils.isObject(objects[1][key])) {
|
||||||
mergedObject[key] = this.mergeObjectsDeep(objects[0][key], objects[1][key]);
|
mergedObject[key] = Utils.mergeObjectsDeep(objects[0][key], objects[1][key]);
|
||||||
} else {
|
} else {
|
||||||
mergedObject[key] = objects[1][key];
|
mergedObject[key] = objects[1][key];
|
||||||
}
|
}
|
||||||
@ -86,6 +66,7 @@ nopaque.Utils = class Utils {
|
|||||||
if (objects.length === 2) {
|
if (objects.length === 2) {
|
||||||
return mergedObject;
|
return mergedObject;
|
||||||
}
|
}
|
||||||
return this.mergeObjectsDeep(mergedObject, ...objects.slice(2));
|
return Utils.mergeObjectsDeep(mergedObject, ...objects.slice(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,204 +0,0 @@
|
|||||||
nopaque.App = class App {
|
|
||||||
constructor() {
|
|
||||||
this.data = {
|
|
||||||
promises: {getUser: {}, subscribeUser: {}},
|
|
||||||
users: {},
|
|
||||||
};
|
|
||||||
this.socket = io({transports: ['websocket'], upgrade: false});
|
|
||||||
this.socket.on('PATCH', (patch) => {this.onPatch(patch);});
|
|
||||||
}
|
|
||||||
|
|
||||||
getUser(userId) {
|
|
||||||
if (userId in this.data.promises.getUser) {
|
|
||||||
return this.data.promises.getUser[userId];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.data.promises.getUser[userId] = new Promise((resolve, reject) => {
|
|
||||||
this.socket.emit('GET /users/<user_id>', userId, (response) => {
|
|
||||||
if (response.status === 200) {
|
|
||||||
this.data.users[userId] = response.body;
|
|
||||||
resolve(this.data.users[userId]);
|
|
||||||
} else {
|
|
||||||
reject(`[${response.status}] ${response.statusText}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.data.promises.getUser[userId];
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribeUser(userId) {
|
|
||||||
if (userId in this.data.promises.subscribeUser) {
|
|
||||||
return this.data.promises.subscribeUser[userId];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.data.promises.subscribeUser[userId] = new Promise((resolve, reject) => {
|
|
||||||
this.socket.emit('SUBSCRIBE /users/<user_id>', userId, (response) => {
|
|
||||||
if (response.status !== 200) {
|
|
||||||
reject(response);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve(response);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.data.promises.subscribeUser[userId];
|
|
||||||
}
|
|
||||||
|
|
||||||
flash(message, category) {
|
|
||||||
let iconPrefix = '';
|
|
||||||
switch (category) {
|
|
||||||
case 'corpus': {
|
|
||||||
iconPrefix = '<i class="left material-icons">book</i>';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'error': {
|
|
||||||
iconPrefix = '<i class="error-color-text left material-icons">error</i>';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'job': {
|
|
||||||
iconPrefix = '<i class="left nopaque-icons">J</i>';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'settings': {
|
|
||||||
iconPrefix = '<i class="left material-icons">settings</i>';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
iconPrefix = '<i class="left material-icons">notifications</i>';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let toast = M.toast(
|
|
||||||
{
|
|
||||||
html: `
|
|
||||||
<span>${iconPrefix}${message}</span>
|
|
||||||
<button class="action-button btn-flat toast-action white-text" data-action="close">
|
|
||||||
<i class="material-icons">close</i>
|
|
||||||
</button>
|
|
||||||
`.trim()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
let toastCloseActionElement = toast.el.querySelector('.action-button[data-action="close"]');
|
|
||||||
toastCloseActionElement.addEventListener('click', () => {toast.dismiss();});
|
|
||||||
}
|
|
||||||
|
|
||||||
onPatch(patch) {
|
|
||||||
// Filter Patch to only include operations on users that are initialized
|
|
||||||
let regExp = new RegExp(`^/users/(${Object.keys(this.data.users).join('|')})`);
|
|
||||||
let filteredPatch = patch.filter(operation => regExp.test(operation.path));
|
|
||||||
|
|
||||||
// Handle job status updates
|
|
||||||
let subRegExp = new RegExp(`^/users/([A-Za-z0-9]*)/jobs/([A-Za-z0-9]*)/status$`);
|
|
||||||
let subFilteredPatch = filteredPatch
|
|
||||||
.filter((operation) => {return operation.op === 'replace';})
|
|
||||||
.filter((operation) => {return subRegExp.test(operation.path);});
|
|
||||||
for (let operation of subFilteredPatch) {
|
|
||||||
let [match, userId, jobId] = operation.path.match(subRegExp);
|
|
||||||
this.flash(`[<a href="/jobs/${jobId}">${this.data.users[userId].jobs[jobId].title}</a>] New status: <span class="job-status-text" data-status="${operation.value}"></span>`, 'job');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply Patch
|
|
||||||
jsonpatch.applyPatch(this.data, filteredPatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
this.initUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
initUi() {
|
|
||||||
/* Pre-Initialization fixes */
|
|
||||||
// #region
|
|
||||||
|
|
||||||
// Flask-WTF sets the standard HTML maxlength Attribute on input/textarea
|
|
||||||
// elements to specify their maximum length (in characters). Unfortunatly
|
|
||||||
// Materialize won't recognize the maxlength Attribute, instead it uses
|
|
||||||
// the data-length Attribute. It's conversion time :)
|
|
||||||
for (let elem of document.querySelectorAll('input[maxlength], textarea[maxlength]')) {
|
|
||||||
elem.dataset.length = elem.getAttribute('maxlength');
|
|
||||||
elem.removeAttribute('maxlength');
|
|
||||||
}
|
|
||||||
|
|
||||||
// To work around some limitations with the Form setup of Flask-WTF.
|
|
||||||
// HTML option elements with an empty value are considered as placeholder
|
|
||||||
// elements. The user should not be able to actively select these options.
|
|
||||||
// So they get the disabled attribute.
|
|
||||||
for (let optionElement of document.querySelectorAll('option[value=""]')) {
|
|
||||||
optionElement.disabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Check why we are doing this.
|
|
||||||
for (let optgroupElement of document.querySelectorAll('optgroup[label=""]')) {
|
|
||||||
for (let c of optgroupElement.children) {
|
|
||||||
optgroupElement.parentElement.insertAdjacentElement('afterbegin', c);
|
|
||||||
}
|
|
||||||
optgroupElement.remove();
|
|
||||||
}
|
|
||||||
// #endregion
|
|
||||||
|
|
||||||
|
|
||||||
/* Initialize Materialize Components */
|
|
||||||
// #region
|
|
||||||
|
|
||||||
// Automatically initialize Materialize Components that do not require
|
|
||||||
// additional configuration.
|
|
||||||
M.AutoInit();
|
|
||||||
|
|
||||||
// CharacterCounters
|
|
||||||
// Materialize didn't include the CharacterCounter plugin within the
|
|
||||||
// AutoInit method (maybe they forgot it?). Anyway... We do it here. :)
|
|
||||||
M.CharacterCounter.init(document.querySelectorAll('input[data-length]:not(.no-autoinit), textarea[data-length]:not(.no-autoinit)'));
|
|
||||||
|
|
||||||
// Header navigation "more" Dropdown.
|
|
||||||
M.Dropdown.init(
|
|
||||||
document.querySelector('#nav-more-dropdown-trigger'),
|
|
||||||
{
|
|
||||||
alignment: 'right',
|
|
||||||
constrainWidth: false,
|
|
||||||
coverTrigger: false
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Manual modal
|
|
||||||
M.Modal.init(
|
|
||||||
document.querySelector('#manual-modal'),
|
|
||||||
{
|
|
||||||
onOpenStart: (modalElement, modalTriggerElement) => {
|
|
||||||
if ('manualModalChapter' in modalTriggerElement.dataset) {
|
|
||||||
let manualModalTocElement = document.querySelector('#manual-modal-toc');
|
|
||||||
let manualModalToc = M.Tabs.getInstance(manualModalTocElement);
|
|
||||||
manualModalToc.select(modalTriggerElement.dataset.manualModalChapter);
|
|
||||||
// TODO: Make this work.
|
|
||||||
// if ('manualModalChapterAnchor' in modalTriggerElement.dataset) {
|
|
||||||
// let manualModalChapterAnchor = document.querySelector(`#${modalTriggerElement.dataset.manualModalChapterAnchor}`);
|
|
||||||
// let xCoord = manualModalChapterAnchor.getBoundingClientRect().left;
|
|
||||||
// let yCoord = manualModalChapterAnchor.getBoundingClientRect().top;
|
|
||||||
// let modalContentElement = modalElement.querySelector('.modal-content');
|
|
||||||
// modalContentElement.scroll(xCoord, yCoord);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Terms of use modal
|
|
||||||
M.Modal.init(
|
|
||||||
document.querySelector('#terms-of-use-modal'),
|
|
||||||
{
|
|
||||||
dismissible: false,
|
|
||||||
onCloseEnd: (modalElement) => {
|
|
||||||
nopaque.requests.users.entity.acceptTermsOfUse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
// #endregion
|
|
||||||
|
|
||||||
|
|
||||||
/* Initialize nopaque Components */
|
|
||||||
// #region
|
|
||||||
nopaque.resource_displays.AutoInit();
|
|
||||||
nopaque.resource_lists.AutoInit();
|
|
||||||
nopaque.forms.AutoInit();
|
|
||||||
// #endregion
|
|
||||||
}
|
|
||||||
};
|
|
@ -1 +0,0 @@
|
|||||||
nopaque.corpus_analysis.cqi.api = {};
|
|
@ -1,43 +0,0 @@
|
|||||||
nopaque.corpus_analysis.cqi.constants = {};
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_KEYWORD = 9;
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_MATCH = 16;
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_MATCHEND = 17;
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_TARGET = 0;
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_0 = 0;
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_1 = 1;
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_2 = 2;
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_3 = 3;
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_4 = 4;
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_5 = 5;
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_6 = 6;
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_7 = 7;
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_8 = 8;
|
|
||||||
|
|
||||||
/** @type {number} */
|
|
||||||
nopaque.corpus_analysis.cqi.constants.FIELD_TARGET_9 = 9;
|
|
@ -1,185 +0,0 @@
|
|||||||
nopaque.corpus_analysis.cqi.errors = {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A base class from which all other errors inherit.
|
|
||||||
* If you want to catch all errors that the CQi package might throw,
|
|
||||||
* catch this base error.
|
|
||||||
*/
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CQiError = class CQiError extends Error {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = undefined;
|
|
||||||
this.description = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.Error = class Error extends nopaque.corpus_analysis.cqi.errors.CQiError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 2;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.ErrorGeneralError = class ErrorGeneralError extends nopaque.corpus_analysis.cqi.errors.Error {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 513;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.ErrorConnectRefused = class ErrorConnectRefused extends nopaque.corpus_analysis.cqi.errors.Error {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 514;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.ErrorUserAbort = class ErrorUserAbort extends nopaque.corpus_analysis.cqi.errors.Error {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 515;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.ErrorSyntaxError = class ErrorSyntaxError extends nopaque.corpus_analysis.cqi.errors.Error {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 516;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CLError = class Error extends nopaque.corpus_analysis.cqi.errors.CQiError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 4;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CLErrorNoSuchAttribute = class CLErrorNoSuchAttribute extends nopaque.corpus_analysis.cqi.errors.CLError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 1025;
|
|
||||||
this.description = "CQi server couldn't open attribute";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CLErrorWrongAttributeType = class CLErrorWrongAttributeType extends nopaque.corpus_analysis.cqi.errors.CLError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 1026;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CLErrorOutOfRange = class CLErrorOutOfRange extends nopaque.corpus_analysis.cqi.errors.CLError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 1027;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CLErrorRegex = class CLErrorRegex extends nopaque.corpus_analysis.cqi.errors.CLError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 1028;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CLErrorCorpusAccess = class CLErrorCorpusAccess extends nopaque.corpus_analysis.cqi.errors.CLError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 1029;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CLErrorOutOfMemory = class CLErrorOutOfMemory extends nopaque.corpus_analysis.cqi.errors.CLError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 1030;
|
|
||||||
this.description = 'CQi server has run out of memory; try discarding some other corpora and/or subcorpora';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CLErrorInternal = class CLErrorInternal extends nopaque.corpus_analysis.cqi.errors.CLError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 1031;
|
|
||||||
this.description = "The classical 'please contact technical support' error";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CQPError = class Error extends nopaque.corpus_analysis.cqi.errors.CQiError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 5;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CQPErrorGeneral = class CQPErrorGeneral extends nopaque.corpus_analysis.cqi.errors.CQPError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 1281;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CQPErrorNoSuchCorpus = class CQPErrorNoSuchCorpus extends nopaque.corpus_analysis.cqi.errors.CQPError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 1282;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CQPErrorInvalidField = class CQPErrorInvalidField extends nopaque.corpus_analysis.cqi.errors.CQPError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 1283;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.CQPErrorOutOfRange = class CQPErrorOutOfRange extends nopaque.corpus_analysis.cqi.errors.CQPError {
|
|
||||||
constructor(message) {
|
|
||||||
super(message);
|
|
||||||
this.code = 1284;
|
|
||||||
this.description = 'A number is out of range';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.errors.lookup = {
|
|
||||||
2: nopaque.corpus_analysis.cqi.errors.Error,
|
|
||||||
513: nopaque.corpus_analysis.cqi.errors.ErrorGeneralError,
|
|
||||||
514: nopaque.corpus_analysis.cqi.errors.ErrorConnectRefused,
|
|
||||||
515: nopaque.corpus_analysis.cqi.errors.ErrorUserAbort,
|
|
||||||
516: nopaque.corpus_analysis.cqi.errors.ErrorSyntaxError,
|
|
||||||
4: nopaque.corpus_analysis.cqi.errors.CLError,
|
|
||||||
1025: nopaque.corpus_analysis.cqi.errors.CLErrorNoSuchAttribute,
|
|
||||||
1026: nopaque.corpus_analysis.cqi.errors.CLErrorWrongAttributeType,
|
|
||||||
1027: nopaque.corpus_analysis.cqi.errors.CLErrorOutOfRange,
|
|
||||||
1028: nopaque.corpus_analysis.cqi.errors.CLErrorRegex,
|
|
||||||
1029: nopaque.corpus_analysis.cqi.errors.CLErrorCorpusAccess,
|
|
||||||
1030: nopaque.corpus_analysis.cqi.errors.CLErrorOutOfMemory,
|
|
||||||
1031: nopaque.corpus_analysis.cqi.errors.CLErrorInternal,
|
|
||||||
5: nopaque.corpus_analysis.cqi.errors.CQPError,
|
|
||||||
1281: nopaque.corpus_analysis.cqi.errors.CQPErrorGeneral,
|
|
||||||
1282: nopaque.corpus_analysis.cqi.errors.CQPErrorNoSuchCorpus,
|
|
||||||
1283: nopaque.corpus_analysis.cqi.errors.CQPErrorInvalidField,
|
|
||||||
1284: nopaque.corpus_analysis.cqi.errors.CQPErrorOutOfRange
|
|
||||||
};
|
|
@ -1 +0,0 @@
|
|||||||
nopaque.corpus_analysis.cqi = {};
|
|
@ -1 +0,0 @@
|
|||||||
nopaque.corpus_analysis.cqi.models = {};
|
|
@ -1,51 +0,0 @@
|
|||||||
nopaque.corpus_analysis.cqi.status = {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A base class from which all other status inherit.
|
|
||||||
*/
|
|
||||||
nopaque.corpus_analysis.cqi.status.CQiStatus = class CQiStatus {
|
|
||||||
constructor() {
|
|
||||||
this.code = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.status.StatusOk = class StatusOk extends nopaque.corpus_analysis.cqi.status.CQiStatus {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.code = 257;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.status.StatusConnectOk = class StatusConnectOk extends nopaque.corpus_analysis.cqi.status.CQiStatus {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.code = 258;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.status.StatusByeOk = class StatusByeOk extends nopaque.corpus_analysis.cqi.status.CQiStatus {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.code = 259;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.status.StatusPingOk = class StatusPingOk extends nopaque.corpus_analysis.cqi.status.CQiStatus {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.code = 260;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.status.lookup = {
|
|
||||||
257: nopaque.corpus_analysis.cqi.status.StatusOk,
|
|
||||||
258: nopaque.corpus_analysis.cqi.status.StatusConnectOk,
|
|
||||||
259: nopaque.corpus_analysis.cqi.status.StatusByeOk,
|
|
||||||
260: nopaque.corpus_analysis.cqi.status.StatusPingOk
|
|
||||||
};
|
|
@ -1 +0,0 @@
|
|||||||
nopaque.corpus_analysis = {};
|
|
@ -1,28 +0,0 @@
|
|||||||
nopaque.corpus_analysis.query_builder.ElementReferences = class ElementReferences {
|
|
||||||
constructor() {
|
|
||||||
// General Elements
|
|
||||||
this.queryInputField = document.querySelector('#corpus-analysis-concordance-query-builder-input-field');
|
|
||||||
this.queryChipElements = [];
|
|
||||||
this.queryElementTarget = document.querySelector('.query-element-target')
|
|
||||||
this.editingModusOn = false;
|
|
||||||
this.editedQueryChipElementIndex = undefined;
|
|
||||||
this.deleteQueryButton = document.querySelector('#corpus-analysis-concordance-delete-query-button');
|
|
||||||
|
|
||||||
// Structural Attribute Builder Elements
|
|
||||||
this.structuralAttrModal = M.Modal.getInstance(document.querySelector('#corpus-analysis-concordance-structural-attr-modal'));
|
|
||||||
this.englishEntTypeSelection = document.querySelector('#corpus-analysis-concordance-english-ent-type-selection');
|
|
||||||
this.germanEntTypeSelection = document.querySelector('#corpus-analysis-concordance-german-ent-type-selection');
|
|
||||||
|
|
||||||
// Token Attribute Builder Elements
|
|
||||||
this.positionalAttrModal = M.Modal.getInstance(document.querySelector('#corpus-analysis-concordance-positional-attr-modal'));
|
|
||||||
this.positionalAttrSelection = document.querySelector('#corpus-analysis-concordance-positional-attr-selection');
|
|
||||||
this.tokenBuilderContent = document.querySelector('#corpus-analysis-concordance-token-builder-content');
|
|
||||||
this.tokenQuery = document.querySelector('#corpus-analysis-concordance-token-query');
|
|
||||||
this.tokenQueryTemplate = document.querySelector('#corpus-analysis-concordance-token-query-template');
|
|
||||||
this.tokenSubmitButton = document.querySelector('#corpus-analysis-concordance-token-submit');
|
|
||||||
this.noValueMessage = document.querySelector('#corpus-analysis-concordance-no-value-message');
|
|
||||||
this.isTokenQueryInvalid = false;
|
|
||||||
|
|
||||||
this.ignoreCaseCheckbox = document.querySelector('#corpus-analysis-concordance-ignore-case-checkbox');
|
|
||||||
}
|
|
||||||
};
|
|
@ -1 +0,0 @@
|
|||||||
nopaque.corpus_analysis.query_builder = {};
|
|
@ -1,500 +0,0 @@
|
|||||||
nopaque.corpus_analysis.query_builder.QueryBuilder = class QueryBuilder {
|
|
||||||
constructor() {
|
|
||||||
this.elements = new nopaque.corpus_analysis.query_builder.ElementReferences();
|
|
||||||
|
|
||||||
this.addEventListenersToQueryElementTarget();
|
|
||||||
this.addEventListenersToIncidenceModifier();
|
|
||||||
this.addEventListenersToNAndMInputSubmit();
|
|
||||||
|
|
||||||
this.elements.deleteQueryButton.addEventListener('click', () => {this.resetQueryInputField()});
|
|
||||||
this.expertModeQueryBuilderSwitchHandler();
|
|
||||||
|
|
||||||
this.extensions = {
|
|
||||||
structuralAttributeBuilderFunctions: new nopaque.corpus_analysis.query_builder.StructuralAttributeBuilderFunctions(this),
|
|
||||||
tokenAttributeBuilderFunctions: new nopaque.corpus_analysis.query_builder.TokenAttributeBuilderFunctions(this),
|
|
||||||
};
|
|
||||||
|
|
||||||
this.dropdown = M.Dropdown.init(
|
|
||||||
document.querySelector('.dropdown-trigger[data-toggle-area="token-incidence-modifiers"]'),
|
|
||||||
{
|
|
||||||
onCloseStart: () => {
|
|
||||||
this.unselectChipElement(this.elements.queryInputField.querySelector('.chip.teal'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
addEventListenersToQueryElementTarget() {
|
|
||||||
this.elements.queryElementTarget.addEventListener('click', () => {
|
|
||||||
this.elements.positionalAttrModal.open();
|
|
||||||
});
|
|
||||||
this.elements.queryElementTarget.addEventListener('dragstart', this.handleDragStart.bind(this, this.elements.queryElementTarget));
|
|
||||||
this.elements.queryElementTarget.addEventListener('dragend', this.handleDragEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
addEventListenersToIncidenceModifier() {
|
|
||||||
// Eventlisteners for the incidence modifiers. There are two different types of incidence modifiers: token and character incidence modifiers.
|
|
||||||
document.querySelectorAll('.incidence-modifier-selection').forEach(button => {
|
|
||||||
let dropdownId = button.parentNode.parentNode.id;
|
|
||||||
if (dropdownId === 'corpus-analysis-concordance-token-incidence-modifiers-dropdown') {
|
|
||||||
button.addEventListener('click', () => this.tokenIncidenceModifierHandler(button.dataset.token, button.innerHTML));
|
|
||||||
} else if (dropdownId === 'corpus-analysis-concordance-character-incidence-modifiers-dropdown') {
|
|
||||||
button.addEventListener('click', () => this.extensions.tokenAttributeBuilderFunctions.characterIncidenceModifierHandler(button));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
addEventListenersToNAndMInputSubmit() {
|
|
||||||
// Eventlisteners for the submit of n- and m-values of the incidence modifier modal for "exactly n" or "between n and m".
|
|
||||||
document.querySelectorAll('.n-m-submit-button').forEach(button => {
|
|
||||||
let modalId = button.dataset.modalId;
|
|
||||||
if (modalId === 'corpus-analysis-concordance-exactly-n-token-modal' || modalId === 'corpus-analysis-concordance-between-nm-token-modal') {
|
|
||||||
button.addEventListener('click', () => this.tokenNMSubmitHandler(modalId));
|
|
||||||
} else if (modalId === 'corpus-analysis-concordance-exactly-n-character-modal' || modalId === 'corpus-analysis-concordance-between-nm-character-modal') {
|
|
||||||
button.addEventListener('click', () => this.extensions.tokenAttributeBuilderFunctions.characterNMSubmitHandler(modalId));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleClass(elements, className, action) {
|
|
||||||
elements.forEach(element => {
|
|
||||||
document.querySelector(`[data-toggle-area="${element}"]`).classList[action](className);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
resetQueryInputField() {
|
|
||||||
this.elements.queryInputField.innerHTML = '';
|
|
||||||
this.addQueryElementTarget();
|
|
||||||
this.updateChipList();
|
|
||||||
this.queryPreviewBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
addQueryElementTarget() {
|
|
||||||
let queryElementTarget = nopaque.Utils.HTMLToElement(
|
|
||||||
`
|
|
||||||
<a class="query-element-target btn-floating btn-small blue-grey lighten-4 waves-effect waves-light tooltipped" style="margin-bottom:10px; margin-right:5px;" draggable="true" data-position="bottom" data-tooltip="Add an Element to your query">
|
|
||||||
<i class="material-icons">add</i>
|
|
||||||
</a>
|
|
||||||
`
|
|
||||||
);
|
|
||||||
this.elements.queryInputField.appendChild(queryElementTarget);
|
|
||||||
this.elements.queryElementTarget = queryElementTarget;
|
|
||||||
this.addEventListenersToQueryElementTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateChipList() {
|
|
||||||
this.elements.queryChipElements = this.elements.queryInputField.querySelectorAll('.query-component');
|
|
||||||
}
|
|
||||||
|
|
||||||
resetMaterializeSelection(selectionElements, value = "default") {
|
|
||||||
selectionElements.forEach(selectionElement => {
|
|
||||||
if (selectionElement.querySelector(`option[value=${value}]`) !== null) {
|
|
||||||
selectionElement.querySelector(`option[value=${value}]`).selected = true;
|
|
||||||
}
|
|
||||||
let instance = M.FormSelect.getInstance(selectionElement);
|
|
||||||
instance.destroy();
|
|
||||||
M.FormSelect.init(selectionElement);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
submitQueryChipElement(dataType=undefined, prettyQueryText=undefined, queryText=undefined, index=null, isClosingTag=false, isEditable=false) {
|
|
||||||
if (this.elements.editingModusOn) {
|
|
||||||
let editedQueryChipElement = this.elements.queryChipElements[this.elements.editedQueryChipElementIndex];
|
|
||||||
editedQueryChipElement.dataset.type = dataType;
|
|
||||||
editedQueryChipElement.dataset.query = queryText;
|
|
||||||
editedQueryChipElement.firstChild.textContent = prettyQueryText;
|
|
||||||
this.updateChipList();
|
|
||||||
this.queryPreviewBuilder();
|
|
||||||
} else {
|
|
||||||
this.queryChipFactory(dataType, prettyQueryText, queryText, index, isClosingTag, isEditable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
queryChipFactory(dataType, prettyQueryText, queryText, index=null, isClosingTag=false, isEditable=false) {
|
|
||||||
// Creates a new query chip element, adds Eventlisteners for selection, deletion and drag and drop and appends it to the query input field.
|
|
||||||
queryText = nopaque.Utils.escape(queryText);
|
|
||||||
prettyQueryText = nopaque.Utils.escape(prettyQueryText);
|
|
||||||
let queryChipElement = nopaque.Utils.HTMLToElement(
|
|
||||||
`
|
|
||||||
<span class="chip query-component" data-type="${dataType}" data-query="${queryText}" draggable="true"">
|
|
||||||
${prettyQueryText}${isEditable ? '<i class="material-icons chip-action-button" data-chip-action="edit" style="padding-left:5px; font-size:18px; cursor:pointer;">edit</i>': ''}
|
|
||||||
${isClosingTag ? '' : '<i class="material-icons close chip-action-button" data-chip-action="delete">close</i>'}
|
|
||||||
</span>
|
|
||||||
`
|
|
||||||
);
|
|
||||||
this.addActionListeners(queryChipElement);
|
|
||||||
queryChipElement.addEventListener('dragstart', this.handleDragStart.bind(this, queryChipElement));
|
|
||||||
queryChipElement.addEventListener('dragend', this.handleDragEnd);
|
|
||||||
// If an index is given, inserts the query chip after the given index (only relevant for Incidence Modifier) and if there is a closing tag, inserts the query chip before the closing tag.
|
|
||||||
if (index !== null) {
|
|
||||||
this.updateChipList();
|
|
||||||
this.elements.queryChipElements[index].after(queryChipElement);
|
|
||||||
} else {
|
|
||||||
this.elements.queryInputField.insertBefore(queryChipElement, this.elements.queryElementTarget);
|
|
||||||
}
|
|
||||||
if (isClosingTag) {
|
|
||||||
this.moveQueryElementTarget(queryChipElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateChipList();
|
|
||||||
this.queryPreviewBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
moveQueryElementTarget(element) {
|
|
||||||
this.elements.queryInputField.insertBefore(this.elements.queryElementTarget, element);
|
|
||||||
}
|
|
||||||
|
|
||||||
addActionListeners(queryChipElement) {
|
|
||||||
let notQuantifiableDataTypes = ['start-sentence', 'end-sentence', 'start-entity', 'start-empty-entity', 'end-entity', 'token-incidence-modifier'];
|
|
||||||
queryChipElement.addEventListener('click', (event) => {
|
|
||||||
if (event.target.classList.contains('chip')) {
|
|
||||||
if (!notQuantifiableDataTypes.includes(queryChipElement.dataset.type)) {
|
|
||||||
this.selectChipElement(queryChipElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let chipActionButtons = queryChipElement.querySelectorAll('.chip-action-button');
|
|
||||||
chipActionButtons.forEach(button => {
|
|
||||||
button.addEventListener('click', (event) => {
|
|
||||||
if (event.target.dataset.chipAction === 'delete') {
|
|
||||||
this.deleteChipElement(queryChipElement);
|
|
||||||
} else if (event.target.dataset.chipAction === 'edit') {
|
|
||||||
this.editChipElement(queryChipElement);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
editChipElement(queryChipElement) {
|
|
||||||
this.elements.editingModusOn = true;
|
|
||||||
this.elements.editedQueryChipElementIndex = Array.from(this.elements.queryInputField.children).indexOf(queryChipElement);
|
|
||||||
switch (queryChipElement.dataset.type) {
|
|
||||||
case 'start-entity':
|
|
||||||
this.extensions.structuralAttributeBuilderFunctions.editStartEntityChipElement(queryChipElement);
|
|
||||||
break;
|
|
||||||
case 'token':
|
|
||||||
let queryElementsContent = this.extensions.tokenAttributeBuilderFunctions.prepareTokenQueryElementsContent(queryChipElement);
|
|
||||||
this.extensions.tokenAttributeBuilderFunctions.editTokenChipElement(queryElementsContent);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteChipElement(attr) {
|
|
||||||
let elementIndex = Array.from(this.elements.queryInputField.children).indexOf(attr);
|
|
||||||
switch (attr.dataset.type) {
|
|
||||||
case 'start-sentence':
|
|
||||||
this.deleteClosingTagHandler(elementIndex, 'end-sentence');
|
|
||||||
break;
|
|
||||||
case 'start-empty-entity':
|
|
||||||
case 'start-entity':
|
|
||||||
this.deleteClosingTagHandler(elementIndex, 'end-entity');
|
|
||||||
break;
|
|
||||||
case 'token':
|
|
||||||
let nextElement = Array.from(this.elements.queryInputField.children)[elementIndex+1];
|
|
||||||
if (nextElement !== undefined && nextElement.dataset.type === 'token-incidence-modifier') {
|
|
||||||
this.deleteChipElement(nextElement);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.elements.queryInputField.removeChild(attr);
|
|
||||||
this.updateChipList();
|
|
||||||
this.queryPreviewBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteClosingTagHandler(elementIndex, closingTagType) {
|
|
||||||
let closingTags = this.elements.queryInputField.querySelectorAll(`[data-type="${closingTagType}"]`);
|
|
||||||
for (let i = 0; i < closingTags.length; i++) {
|
|
||||||
let closingTag = closingTags[i];
|
|
||||||
|
|
||||||
if (Array.from(this.elements.queryInputField.children).indexOf(closingTag) > elementIndex) {
|
|
||||||
this.deleteChipElement(closingTag);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDragStart(queryChipElement) {
|
|
||||||
// is called when a query chip is dragged. It creates a dropzone (in form of a chip) for the dragged chip and adds it to the query input field.
|
|
||||||
let queryChips = this.elements.queryInputField.querySelectorAll('.query-component');
|
|
||||||
if (queryChipElement.dataset.type === 'token-incidence-modifier') {
|
|
||||||
queryChips = this.elements.queryInputField.querySelectorAll('.query-component[data-type="token"]');
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
|
||||||
let targetChipElement = nopaque.Utils.HTMLToElement('<span class="chip drop-target">Drop here</span>');
|
|
||||||
for (let element of queryChips) {
|
|
||||||
if (element === this.elements.queryInputField.querySelectorAll('.query-component')[0]) {
|
|
||||||
let secondTargetChipClone = targetChipElement.cloneNode(true);
|
|
||||||
element.insertAdjacentElement('beforebegin', secondTargetChipClone);
|
|
||||||
this.addDragDropListeners(secondTargetChipClone, queryChipElement);
|
|
||||||
}
|
|
||||||
if (element === queryChipElement || element.nextSibling === queryChipElement) {continue;}
|
|
||||||
|
|
||||||
let targetChipClone = targetChipElement.cloneNode(true);
|
|
||||||
element.insertAdjacentElement('afterend', targetChipClone);
|
|
||||||
//TODO: Change to two different functions for drag and drop
|
|
||||||
this.addDragDropListeners(targetChipClone, queryChipElement);
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDragEnd(event) {
|
|
||||||
// is called when a query chip is dropped. It removes the dropzones and initializes the tooltips if the dragged element is the query element target.
|
|
||||||
if (event.target.classList.contains('query-element-target')) {
|
|
||||||
M.Tooltip.init(event.target);
|
|
||||||
}
|
|
||||||
document.querySelectorAll('.drop-target').forEach(target => target.remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
addDragDropListeners(targetChipClone, queryChipElement) {
|
|
||||||
targetChipClone.addEventListener('dragover', (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
targetChipClone.addEventListener('dragenter', (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.target.style.borderStyle = 'solid dotted';
|
|
||||||
});
|
|
||||||
targetChipClone.addEventListener('dragleave', (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.target.style.borderStyle = 'hidden';
|
|
||||||
});
|
|
||||||
targetChipClone.addEventListener('drop', (event) => {
|
|
||||||
let dropzone = event.target;
|
|
||||||
dropzone.parentElement.replaceChild(queryChipElement, dropzone);
|
|
||||||
this.updateChipList();
|
|
||||||
this.queryPreviewBuilder();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
queryPreviewBuilder() {
|
|
||||||
// Builds the query preview in the form of pure CQL and displays it in the query preview field.
|
|
||||||
let queryPreview = document.querySelector('#corpus-analysis-concordance-query-preview');
|
|
||||||
let queryInputFieldContent = [];
|
|
||||||
this.elements.queryChipElements.forEach(element => {
|
|
||||||
let queryElement = element.dataset.query;
|
|
||||||
if (queryElement !== undefined) {
|
|
||||||
queryElement = nopaque.Utils.escape(queryElement);
|
|
||||||
}
|
|
||||||
queryInputFieldContent.push(queryElement);
|
|
||||||
});
|
|
||||||
|
|
||||||
let queryString = queryInputFieldContent.join(' ');
|
|
||||||
let replacements = {
|
|
||||||
' +': '+',
|
|
||||||
' *': '*',
|
|
||||||
' ?': '?',
|
|
||||||
' {': '{'
|
|
||||||
};
|
|
||||||
|
|
||||||
for (let key in replacements) {
|
|
||||||
queryString = queryString.replace(key, replacements[key]);
|
|
||||||
}
|
|
||||||
queryString += ';';
|
|
||||||
|
|
||||||
queryPreview.innerHTML = queryString;
|
|
||||||
queryPreview.parentNode.classList.toggle('hide', queryString === ';');
|
|
||||||
}
|
|
||||||
|
|
||||||
selectChipElement(attr) {
|
|
||||||
if (attr.classList.contains('teal')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.toggleClass(['token-incidence-modifiers'], 'disabled', 'toggle');
|
|
||||||
attr.classList.toggle('teal');
|
|
||||||
attr.classList.toggle('lighten-5');
|
|
||||||
|
|
||||||
M.Dropdown.getInstance(document.querySelector('.dropdown-trigger[data-toggle-area="token-incidence-modifiers"]')).open();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
unselectChipElement(attr) {
|
|
||||||
let nModalInstance = M.Modal.getInstance(document.querySelector('#corpus-analysis-concordance-exactly-n-token-modal'));
|
|
||||||
let nmModalInstance = M.Modal.getInstance(document.querySelector('#corpus-analysis-concordance-between-nm-token-modal'));
|
|
||||||
if (nModalInstance.isOpen || nmModalInstance.isOpen) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
attr.classList.remove('teal', 'lighten-5');
|
|
||||||
this.toggleClass(['token-incidence-modifiers'], 'disabled', 'add');
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenIncidenceModifierHandler(incidenceModifier, incidenceModifierPretty, nOrNM = false) {
|
|
||||||
// Adds a token incidence modifier to the query input field.
|
|
||||||
let selectedChip = this.elements.queryInputField.querySelector('.chip.teal');
|
|
||||||
let selectedChipIndex = Array.from(this.elements.queryChipElements).indexOf(selectedChip);
|
|
||||||
if (nOrNM) {
|
|
||||||
this.unselectChipElement(selectedChip);
|
|
||||||
}
|
|
||||||
this.submitQueryChipElement('token-incidence-modifier', incidenceModifierPretty, incidenceModifier, selectedChipIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenNMSubmitHandler(modalId) {
|
|
||||||
// Adds a token incidence modifier (exactly n or between n and m) to the query input field.
|
|
||||||
let modal = document.querySelector(`#${modalId}`);
|
|
||||||
let input_n = modal.querySelector('.n-m-input[data-value-type="n"]').value;
|
|
||||||
let input_m = modal.querySelector('.n-m-input[data-value-type="m"]') || undefined;
|
|
||||||
input_m = input_m !== undefined ? input_m.value : '';
|
|
||||||
let input = `{${input_n}${input_m !== '' ? ',' : ''}${input_m}}`;
|
|
||||||
let pretty_input = `between ${input_n} and ${input_m} (${input})`;
|
|
||||||
if (input_m === '') {
|
|
||||||
pretty_input = `exactly ${input_n} (${input})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
let instance = M.Modal.getInstance(modal);
|
|
||||||
instance.close();
|
|
||||||
|
|
||||||
this.tokenIncidenceModifierHandler(input, pretty_input, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
expertModeQueryBuilderSwitchHandler() {
|
|
||||||
let queryBuilderDisplay = document.querySelector("#corpus-analysis-concordance-query-builder-display");
|
|
||||||
let expertModeDisplay = document.querySelector("#corpus-analysis-concordance-expert-mode-display");
|
|
||||||
let expertModeSwitch = document.querySelector("#corpus-analysis-concordance-expert-mode-switch");
|
|
||||||
let submitModal = M.Modal.getInstance(document.querySelector('#corpus-analysis-concordance-switch-to-query-builder-submit-modal'));
|
|
||||||
|
|
||||||
let confirmSwitchToQueryBuilderButton = document.querySelector('.switch-action[data-switch-action="confirm"]');
|
|
||||||
confirmSwitchToQueryBuilderButton.addEventListener("click", () => {
|
|
||||||
queryBuilderDisplay.classList.remove("hide");
|
|
||||||
expertModeDisplay.classList.add("hide");
|
|
||||||
this.switchToQueryBuilderParser();
|
|
||||||
});
|
|
||||||
|
|
||||||
expertModeSwitch.addEventListener("change", () => {
|
|
||||||
const isChecked = expertModeSwitch.checked;
|
|
||||||
if (isChecked) {
|
|
||||||
queryBuilderDisplay.classList.add("hide");
|
|
||||||
expertModeDisplay.classList.remove("hide");
|
|
||||||
this.switchToExpertModeParser();
|
|
||||||
} else {
|
|
||||||
submitModal.open();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
switchToExpertModeParser() {
|
|
||||||
let expertModeInputField = document.querySelector('#corpus-analysis-concordance-form-query');
|
|
||||||
expertModeInputField.value = '';
|
|
||||||
let queryBuilderInputFieldValue = nopaque.Utils.unescape(document.querySelector('#corpus-analysis-concordance-query-preview').innerHTML.trim());
|
|
||||||
if (queryBuilderInputFieldValue !== "" && queryBuilderInputFieldValue !== ";") {
|
|
||||||
expertModeInputField.value = queryBuilderInputFieldValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switchToQueryBuilderParser() {
|
|
||||||
this.resetQueryInputField();
|
|
||||||
let expertModeInputFieldValue = document.querySelector('#corpus-analysis-concordance-form-query').value;
|
|
||||||
let chipElements = this.parseTextToChip(expertModeInputFieldValue);
|
|
||||||
let editableElements = ['start-entity', 'token'];
|
|
||||||
for (let chipElement of chipElements) {
|
|
||||||
let isEditable = editableElements.includes(chipElement['type']);
|
|
||||||
if (chipElement['query'] === '[]'){
|
|
||||||
isEditable = false;
|
|
||||||
}
|
|
||||||
this.submitQueryChipElement(chipElement['type'], chipElement['pretty'], chipElement['query'], null, false, isEditable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parseTextToChip(query) {
|
|
||||||
const parsingElementDict = {
|
|
||||||
'<s>': {
|
|
||||||
pretty: 'Sentence Start',
|
|
||||||
type: 'start-sentence'
|
|
||||||
},
|
|
||||||
'<\/s>': {
|
|
||||||
pretty: 'Sentence End',
|
|
||||||
type: 'end-sentence'
|
|
||||||
},
|
|
||||||
'<ent>': {
|
|
||||||
pretty: 'Entity Start',
|
|
||||||
type: 'start-empty-entity'
|
|
||||||
},
|
|
||||||
'<ent_type="([A-Z]+)">': {
|
|
||||||
pretty: '',
|
|
||||||
type: 'start-entity'
|
|
||||||
},
|
|
||||||
'<\\\/ent(_type)?>': {
|
|
||||||
pretty: 'Entity End',
|
|
||||||
type: 'end-entity'
|
|
||||||
},
|
|
||||||
'\\[(word|lemma|pos|simple_pos)=("(?:[^"\\\\]|\\\\")*") ?(%c)? ?((\\&|\\|) ?(word|lemma|pos|simple_pos)=("(?:[^"\\\\]|\\\\")*") ?(%c)? ?)*\\]': {
|
|
||||||
pretty: '',
|
|
||||||
type: 'token'
|
|
||||||
},
|
|
||||||
'\\[\\]': {
|
|
||||||
pretty: 'Empty Token',
|
|
||||||
type: 'token'
|
|
||||||
},
|
|
||||||
'(?<!\\[) ?\\+ ?(?![^\\]]\\])': {
|
|
||||||
pretty: ' one or more (+)',
|
|
||||||
type: 'token-incidence-modifier'
|
|
||||||
},
|
|
||||||
'(?<!\\[) ?\\* ?(?![^\\]]\\])': {
|
|
||||||
pretty: 'zero or more (*)',
|
|
||||||
type: 'token-incidence-modifier'
|
|
||||||
},
|
|
||||||
'(?<!\\[) ?\\? ?(?![^\\]]\\])': {
|
|
||||||
pretty: 'zero or one (?)',
|
|
||||||
type: 'token-incidence-modifier'
|
|
||||||
},
|
|
||||||
'(?<!\\[) ?\\{[0-9]+} ?(?![^\\]]\\])': {
|
|
||||||
pretty: '',
|
|
||||||
type: 'token-incidence-modifier'
|
|
||||||
},
|
|
||||||
'(?<!\\[) ?\\{[0-9]+(,[0-9]+)?} ?(?![^\\]]\\])': {
|
|
||||||
pretty: '',
|
|
||||||
type: 'token-incidence-modifier'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let chipElements = [];
|
|
||||||
let regexPattern = Object.keys(parsingElementDict).map(pattern => `(${pattern})`).join('|');
|
|
||||||
const regex = new RegExp(regexPattern, 'gi');
|
|
||||||
let match;
|
|
||||||
|
|
||||||
while ((match = regex.exec(query)) !== null) {
|
|
||||||
// this is necessary to avoid infinite loops with zero-width matches
|
|
||||||
if (match.index === regex.lastIndex) {
|
|
||||||
regex.lastIndex++;
|
|
||||||
}
|
|
||||||
let stringElement = match[0];
|
|
||||||
for (let [pattern, chipElement] of Object.entries(parsingElementDict)) {
|
|
||||||
const parsingRegex = new RegExp(pattern, 'gi');
|
|
||||||
if (parsingRegex.exec(stringElement)) {
|
|
||||||
// Creating the pretty text for the chip element
|
|
||||||
let prettyText;
|
|
||||||
switch (pattern) {
|
|
||||||
case '<ent_type="([A-Z]+)">':
|
|
||||||
prettyText = `Entity Type=${stringElement.replace(/<ent_type="|">/g, '')}`;
|
|
||||||
break;
|
|
||||||
case ':: ?match\\.text_[A-Za-z]+="[^"]+"':
|
|
||||||
prettyText = stringElement.replace(/:: ?match\.text_|"|"/g, '');
|
|
||||||
break;
|
|
||||||
case '\\[(word|lemma|pos|simple_pos)=("(?:[^"\\\\]|\\\\")*") ?(%c)? ?((\\&|\\|) ?(word|lemma|pos|simple_pos)=("(?:[^"\\\\]|\\\\")*") ?(%c)? ?)*\\]':
|
|
||||||
prettyText = stringElement.replace(/^\[|\]$|(?<!\\)"/g, '');
|
|
||||||
prettyText = prettyText.replace(/\&/g, ' and ').replace(/\|/g, ' or ');
|
|
||||||
break;
|
|
||||||
case '(?<!\\[) ?\\{[0-9]+} ?(?![^\\]]\\])':
|
|
||||||
prettyText = `exactly ${stringElement.replace(/{|}/g, '')} (${stringElement})`;
|
|
||||||
break;
|
|
||||||
case '(?<!\\[) ?\\{[0-9]+(,[0-9]+)?} ?(?![^\\]]\\])':
|
|
||||||
prettyText = `between${stringElement.replace(/{|}/g, ' ').replace(',', ' and ')}(${stringElement})`;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
prettyText = chipElement.pretty;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
chipElements.push({
|
|
||||||
type: chipElement.type,
|
|
||||||
pretty: prettyText,
|
|
||||||
query: stringElement
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return chipElements;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,82 +0,0 @@
|
|||||||
nopaque.corpus_analysis.query_builder.StructuralAttributeBuilderFunctions = class StructuralAttributeBuilderFunctions {
|
|
||||||
constructor(app) {
|
|
||||||
this.app = app;
|
|
||||||
this.elements = app.elements;
|
|
||||||
|
|
||||||
this.structuralAttrModalEventlisteners();
|
|
||||||
|
|
||||||
this.elements.structuralAttrModal = M.Modal.init(
|
|
||||||
document.querySelector('#corpus-analysis-concordance-structural-attr-modal'),
|
|
||||||
{
|
|
||||||
onCloseStart: () => {
|
|
||||||
this.resetStructuralAttrModal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
structuralAttrModalEventlisteners() {
|
|
||||||
document.querySelectorAll('[data-structural-attr-modal-action-button]').forEach(button => {
|
|
||||||
button.addEventListener('click', () => {
|
|
||||||
this.actionButtonInStrucAttrModalHandler(button.dataset.structuralAttrModalActionButton);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
document.querySelector('.ent-type-selection-action[data-ent-type="any"]').addEventListener('click', () => {
|
|
||||||
this.app.submitQueryChipElement('start-empty-entity', 'Entity Start', '<ent>');
|
|
||||||
this.app.submitQueryChipElement('end-entity', 'Entity End', '</ent>', null, true);
|
|
||||||
this.elements.structuralAttrModal.close();
|
|
||||||
});
|
|
||||||
document.querySelector('.ent-type-selection-action[data-ent-type="english"]').addEventListener('change', (event) => {
|
|
||||||
this.app.submitQueryChipElement('start-entity', `Entity Type=${event.target.value}`, `<ent_type="${event.target.value}">`, null, false, true);
|
|
||||||
if (!this.elements.editingModusOn) {
|
|
||||||
this.app.submitQueryChipElement('end-entity', 'Entity End', '</ent_type>', null, true);
|
|
||||||
}
|
|
||||||
this.elements.structuralAttrModal.close();
|
|
||||||
});
|
|
||||||
document.querySelector('.ent-type-selection-action[data-ent-type="german"]').addEventListener('change', (event) => {
|
|
||||||
this.app.submitQueryChipElement('start-entity', `Entity Type=${event.target.value}`, `<ent_type="${event.target.value}">`, null, false, true);
|
|
||||||
if (!this.elements.editingModusOn) {
|
|
||||||
this.app.submitQueryChipElement('end-entity', 'Entity End', '</ent_type>', null, true);
|
|
||||||
}
|
|
||||||
this.elements.structuralAttrModal.close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
resetStructuralAttrModal() {
|
|
||||||
this.app.resetMaterializeSelection([this.elements.englishEntTypeSelection, this.elements.germanEntTypeSelection]);
|
|
||||||
this.app.toggleClass(['entity-builder'], 'hide', 'add');
|
|
||||||
this.toggleEditingAreaStructuralAttrModal('remove');
|
|
||||||
this.elements.editingModusOn = false;
|
|
||||||
this.elements.editedQueryChipElementIndex = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
actionButtonInStrucAttrModalHandler(action) {
|
|
||||||
switch (action) {
|
|
||||||
case 'sentence':
|
|
||||||
this.app.submitQueryChipElement('start-sentence', 'Sentence Start', '<s>');
|
|
||||||
this.app.submitQueryChipElement('end-sentence', 'Sentence End', '</s>', null, true);
|
|
||||||
this.elements.structuralAttrModal.close();
|
|
||||||
break;
|
|
||||||
case 'entity':
|
|
||||||
this.app.toggleClass(['entity-builder'], 'hide', 'toggle');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleEditingAreaStructuralAttrModal(action) {
|
|
||||||
// If the user edits a query chip element, the corresponding editing area is displayed and the other areas are hidden or disabled.
|
|
||||||
this.app.toggleClass(['sentence-button', 'entity-button', 'any-type-entity-button'], 'disabled', action);
|
|
||||||
}
|
|
||||||
|
|
||||||
editStartEntityChipElement(queryChipElement) {
|
|
||||||
this.elements.structuralAttrModal.open();
|
|
||||||
this.app.toggleClass(['entity-builder'], 'hide', 'remove');
|
|
||||||
this.toggleEditingAreaStructuralAttrModal('add');
|
|
||||||
let entType = queryChipElement.dataset.query.replace(/<ent_type="|">/g, '');
|
|
||||||
let isEnglishEntType = this.elements.englishEntTypeSelection.querySelector(`option[value=${entType}]`) !== null;
|
|
||||||
let selection = isEnglishEntType ? this.elements.englishEntTypeSelection : this.elements.germanEntTypeSelection;
|
|
||||||
this.app.resetMaterializeSelection([selection], entType);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,329 +0,0 @@
|
|||||||
nopaque.corpus_analysis.query_builder.TokenAttributeBuilderFunctions = class TokenAttributeBuilderFunctions {
|
|
||||||
constructor(app) {
|
|
||||||
this.app = app;
|
|
||||||
this.elements = app.elements;
|
|
||||||
|
|
||||||
this.elements.positionalAttrSelection.addEventListener('change', () => {
|
|
||||||
this.preparePositionalAttrModal();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Options for positional attribute selection
|
|
||||||
document.querySelectorAll('.positional-attr-options-action-button[data-options-action]').forEach(button => {
|
|
||||||
button.addEventListener('click', () => {this.actionButtonInOptionSectionHandler(button.dataset.optionsAction);});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.elements.tokenSubmitButton.addEventListener('click', () => {this.addTokenToQuery();});
|
|
||||||
|
|
||||||
this.elements.positionalAttrModal = M.Modal.init(
|
|
||||||
document.querySelector('#corpus-analysis-concordance-positional-attr-modal'),
|
|
||||||
{
|
|
||||||
onOpenStart: () => {
|
|
||||||
this.preparePositionalAttrModal();
|
|
||||||
},
|
|
||||||
onCloseStart: () => {
|
|
||||||
this.resetPositionalAttrModal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
resetPositionalAttrModal() {
|
|
||||||
let originalSelectionList =
|
|
||||||
`
|
|
||||||
<option value="word" selected>word</option>
|
|
||||||
<option value="lemma" >lemma</option>
|
|
||||||
<option value="english-pos">english pos</option>
|
|
||||||
<option value="german-pos">german pos</option>
|
|
||||||
<option value="simple_pos">simple_pos</option>
|
|
||||||
<option value="empty-token">empty token</option>
|
|
||||||
`;
|
|
||||||
this.elements.positionalAttrSelection.innerHTML = originalSelectionList;
|
|
||||||
this.elements.tokenQuery.innerHTML = '';
|
|
||||||
this.elements.tokenBuilderContent.innerHTML = '';
|
|
||||||
this.app.toggleClass(['input-field-options'], 'hide', 'remove');
|
|
||||||
this.app.toggleClass(['incidence-modifiers', 'or', 'and'], 'disabled', 'add');
|
|
||||||
this.app.resetMaterializeSelection([this.elements.positionalAttrSelection], "word");
|
|
||||||
this.elements.ignoreCaseCheckbox.checked = false;
|
|
||||||
this.elements.editingModusOn = false;
|
|
||||||
this.elements.editedQueryChipElementIndex = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
actionButtonInOptionSectionHandler(elem) {
|
|
||||||
let input = this.tokenInputCheck(this.elements.tokenBuilderContent);
|
|
||||||
switch (elem) {
|
|
||||||
case 'option-group':
|
|
||||||
this.cursorPositionInputfieldHandler(input, '(option1|option2)');
|
|
||||||
let firstIndex = input.value.indexOf('option1');
|
|
||||||
let lastIndex = firstIndex + 'option1'.length;
|
|
||||||
input.setSelectionRange(firstIndex, lastIndex);
|
|
||||||
break;
|
|
||||||
case 'wildcard-char':
|
|
||||||
this.cursorPositionInputfieldHandler(input, '.');
|
|
||||||
input.focus();
|
|
||||||
break;
|
|
||||||
case 'and':
|
|
||||||
this.conditionHandler('and');
|
|
||||||
break;
|
|
||||||
case 'or':
|
|
||||||
this.conditionHandler('or');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.optionToggleHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
cursorPositionInputfieldHandler(input, addedInput) {
|
|
||||||
let cursorPosition = input.selectionStart;
|
|
||||||
let textBeforeCursor = input.value.substring(0, cursorPosition);
|
|
||||||
let textAfterCursor = input.value.substring(cursorPosition);
|
|
||||||
let newInputValue = textBeforeCursor + addedInput + textAfterCursor;
|
|
||||||
input.value = newInputValue;
|
|
||||||
let newCursorPosition = cursorPosition + addedInput.length;
|
|
||||||
input.setSelectionRange(newCursorPosition, newCursorPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
characterIncidenceModifierHandler(elem) {
|
|
||||||
let input = this.tokenInputCheck(this.elements.tokenBuilderContent);
|
|
||||||
this.cursorPositionInputfieldHandler(input, elem.dataset.token);
|
|
||||||
}
|
|
||||||
|
|
||||||
characterNMSubmitHandler(modalId) {
|
|
||||||
let modal = document.querySelector(`#${modalId}`);
|
|
||||||
let input_n = modal.querySelector('.n-m-input[data-value-type="n"]').value;
|
|
||||||
let input_m = modal.querySelector('.n-m-input[data-value-type="m"]') || undefined;
|
|
||||||
input_m = input_m !== undefined ? ',' + input_m.value : '';
|
|
||||||
let addedInput = `${input_n}${input_m}`;
|
|
||||||
|
|
||||||
let instance = M.Modal.getInstance(modal);
|
|
||||||
instance.close();
|
|
||||||
let input = this.tokenInputCheck(this.elements.tokenBuilderContent);
|
|
||||||
this.cursorPositionInputfieldHandler(input, `{${addedInput}}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
conditionHandler(conditionText) {
|
|
||||||
let tokenQueryTemplateClone = this.elements.tokenQueryTemplate.content.cloneNode(true);
|
|
||||||
tokenQueryTemplateClone.querySelector('.token-query-template-content').appendChild(this.elements.tokenBuilderContent.firstElementChild);
|
|
||||||
let notSelectedButton = tokenQueryTemplateClone.querySelector(`[data-condition-pretty-text]:not([data-condition-pretty-text="${conditionText}"])`);
|
|
||||||
let deleteButton = tokenQueryTemplateClone.querySelector(`[data-token-query-content-action="delete"]`);
|
|
||||||
deleteButton.addEventListener('click', (event) => {
|
|
||||||
this.deleteTokenQueryRow(event.target);
|
|
||||||
});
|
|
||||||
notSelectedButton.parentNode.removeChild(notSelectedButton);
|
|
||||||
this.elements.tokenQuery.appendChild(tokenQueryTemplateClone);
|
|
||||||
|
|
||||||
let lastTokenQueryRow = this.elements.tokenQuery.lastElementChild;
|
|
||||||
if(lastTokenQueryRow.querySelector('[data-kind-of-token="word"]') || lastTokenQueryRow.querySelector('[data-kind-of-token="lemma"]')) {
|
|
||||||
this.appendIgnoreCaseCheckbox(lastTokenQueryRow.querySelector('.token-query-template-content'), this.elements.ignoreCaseCheckbox.checked);
|
|
||||||
}
|
|
||||||
this.elements.ignoreCaseCheckbox.checked = false;
|
|
||||||
this.setTokenSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteTokenQueryRow(deleteButton) {
|
|
||||||
let deletedRow = deleteButton.closest('.row');
|
|
||||||
let condition = deletedRow.querySelector('[data-condition-pretty-text]').dataset.conditionPrettyText;
|
|
||||||
if (condition === 'and') {
|
|
||||||
let kindOfToken = deletedRow.querySelector('[data-kind-of-token]').dataset.kindOfToken;
|
|
||||||
switch (kindOfToken) {
|
|
||||||
case 'english-pos' || 'german-pos':
|
|
||||||
this.createOptionElementForPosAttrSelection('english-pos');
|
|
||||||
this.createOptionElementForPosAttrSelection('german-pos');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.createOptionElementForPosAttrSelection(kindOfToken);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
M.FormSelect.init(this.elements.positionalAttrSelection);
|
|
||||||
}
|
|
||||||
deletedRow.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
createOptionElementForPosAttrSelection(kindOfToken) {
|
|
||||||
let option = document.createElement('option');
|
|
||||||
option.value = kindOfToken;
|
|
||||||
option.text = kindOfToken;
|
|
||||||
this.elements.positionalAttrSelection.appendChild(option);
|
|
||||||
}
|
|
||||||
|
|
||||||
appendIgnoreCaseCheckbox(parentElement, checked=false) {
|
|
||||||
let ignoreCaseCheckboxClone = document.querySelector('#ignore-case-checkbox-template').content.cloneNode(true);
|
|
||||||
parentElement.appendChild(ignoreCaseCheckboxClone);
|
|
||||||
M.Tooltip.init(parentElement.querySelectorAll('.tooltipped'));
|
|
||||||
if (checked) {
|
|
||||||
parentElement.querySelector('input[type="checkbox"]').checked = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setTokenSelection(selection="word", optionDeleteList=['empty-token']) {
|
|
||||||
optionDeleteList.forEach(option => {
|
|
||||||
if (this.elements.positionalAttrSelection.querySelector(`option[value=${option}]`) !== null) {
|
|
||||||
this.elements.positionalAttrSelection.querySelector(`option[value=${option}]`).remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.app.resetMaterializeSelection([this.elements.positionalAttrSelection], selection);
|
|
||||||
this.preparePositionalAttrModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
preparePositionalAttrModal() {
|
|
||||||
let selection = this.elements.positionalAttrSelection.value;
|
|
||||||
if (selection !== 'empty-token') {
|
|
||||||
let selectionTemplate = document.querySelector(`.token-builder-section[data-token-builder-section="${selection}"]`);
|
|
||||||
let selectionTemplateClone = selectionTemplate.content.cloneNode(true);
|
|
||||||
|
|
||||||
this.elements.tokenBuilderContent.innerHTML = '';
|
|
||||||
this.elements.tokenBuilderContent.appendChild(selectionTemplateClone);
|
|
||||||
if (this.elements.tokenBuilderContent.querySelector('select') !== null) {
|
|
||||||
let selectElement = this.elements.tokenBuilderContent.querySelector('select');
|
|
||||||
M.FormSelect.init(selectElement);
|
|
||||||
selectElement.addEventListener('change', () => {this.optionToggleHandler();});
|
|
||||||
} else {
|
|
||||||
this.elements.tokenBuilderContent.querySelector('input').addEventListener('input', () => {this.optionToggleHandler();});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.optionToggleHandler();
|
|
||||||
|
|
||||||
if (selection === 'word' || selection === 'lemma') {
|
|
||||||
this.app.toggleClass(['input-field-options'], 'hide', 'remove');
|
|
||||||
} else if (selection === 'empty-token'){
|
|
||||||
this.addTokenToQuery();
|
|
||||||
} else {
|
|
||||||
this.app.toggleClass(['input-field-options'], 'hide', 'add');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenInputCheck(elem) {
|
|
||||||
return elem.querySelector('select') !== null ? elem.querySelector('select') : elem.querySelector('input');
|
|
||||||
}
|
|
||||||
|
|
||||||
optionToggleHandler() {
|
|
||||||
let input = this.tokenInputCheck(this.elements.tokenBuilderContent);
|
|
||||||
if (input.value === '' && this.elements.editingModusOn === false) {
|
|
||||||
this.app.toggleClass(['incidence-modifiers', 'or', 'and'], 'disabled', 'add');
|
|
||||||
} else if (this.elements.positionalAttrSelection.querySelectorAll('option').length === 1) {
|
|
||||||
this.app.toggleClass(['and'], 'disabled', 'add');
|
|
||||||
this.app.toggleClass(['or'], 'disabled', 'remove');
|
|
||||||
} else {
|
|
||||||
this.app.toggleClass(['incidence-modifiers', 'or', 'and'], 'disabled', 'remove');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addTokenToQuery() {
|
|
||||||
let tokenQueryPrettyText = '';
|
|
||||||
let tokenQueryCQLText = '';
|
|
||||||
let input;
|
|
||||||
let kindOfToken = this.kindOfTokenCheck(this.elements.positionalAttrSelection.value);
|
|
||||||
|
|
||||||
// Takes all rows of the token query (if there is a query concatenation).
|
|
||||||
// Adds their contents to tokenQueryPrettyText and tokenQueryCQLText, which will later be expanded with the current input field.
|
|
||||||
let tokenQueryRows = this.elements.tokenQuery.querySelectorAll('.row');
|
|
||||||
tokenQueryRows.forEach(row => {
|
|
||||||
let ignoreCaseCheckbox = row.querySelector('input[type="checkbox"]');
|
|
||||||
let c = ignoreCaseCheckbox !== null && ignoreCaseCheckbox.checked ? ' %c' : '';
|
|
||||||
let tokenQueryRowInput = this.tokenInputCheck(row.querySelector('.token-query-template-content'));
|
|
||||||
let tokenQueryKindOfToken = this.kindOfTokenCheck(tokenQueryRowInput.closest('.input-field').dataset.kindOfToken);
|
|
||||||
let tokenConditionPrettyText = row.querySelector('[data-condition-pretty-text]').dataset.conditionPrettyText;
|
|
||||||
let tokenConditionCQLText = row.querySelector('[data-condition-cql-text]').dataset.conditionCqlText;
|
|
||||||
tokenQueryPrettyText += `${tokenQueryKindOfToken}=${tokenQueryRowInput.value}${c} ${tokenConditionPrettyText} `;
|
|
||||||
tokenQueryCQLText += `${tokenQueryKindOfToken}="${tokenQueryRowInput.value}"${c} ${tokenConditionCQLText}`;
|
|
||||||
});
|
|
||||||
if (kindOfToken === 'empty-token') {
|
|
||||||
tokenQueryPrettyText += 'empty token';
|
|
||||||
} else {
|
|
||||||
let c = this.elements.ignoreCaseCheckbox.checked ? ' %c' : '';
|
|
||||||
input = this.tokenInputCheck(this.elements.tokenBuilderContent);
|
|
||||||
tokenQueryPrettyText += `${kindOfToken}=${input.value}${c}`;
|
|
||||||
tokenQueryCQLText += `${kindOfToken}="${input.value}"${c}`;
|
|
||||||
}
|
|
||||||
// isTokenQueryInvalid looks if a valid value is passed. If the input fields/dropdowns are empty (isTokenQueryInvalid === true), no token is added.
|
|
||||||
if (this.elements.positionalAttrSelection.value !== 'empty-token' && input.value === '') {
|
|
||||||
this.disableTokenSubmit();
|
|
||||||
} else {
|
|
||||||
tokenQueryCQLText = `[${tokenQueryCQLText}]`;
|
|
||||||
this.app.submitQueryChipElement('token', tokenQueryPrettyText, tokenQueryCQLText, null, false, kindOfToken === 'empty-token' ? false : true);
|
|
||||||
this.elements.positionalAttrModal.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
kindOfTokenCheck(kindOfToken) {
|
|
||||||
return kindOfToken === 'english-pos' || kindOfToken === 'german-pos' ? 'pos' : kindOfToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
disableTokenSubmit() {
|
|
||||||
this.elements.tokenSubmitButton.classList.add('red');
|
|
||||||
this.elements.noValueMessage.classList.remove('hide');
|
|
||||||
setTimeout(() => {
|
|
||||||
this.elements.tokenSubmitButton.classList.remove('red');
|
|
||||||
}, 500);
|
|
||||||
setTimeout(() => {
|
|
||||||
this.elements.noValueMessage.classList.add('hide');
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
editTokenChipElement(queryElementsContent) {
|
|
||||||
this.elements.positionalAttrModal.open();
|
|
||||||
queryElementsContent.forEach((queryElement) => {
|
|
||||||
this.app.resetMaterializeSelection([this.elements.positionalAttrSelection], queryElement.tokenAttr);
|
|
||||||
this.preparePositionalAttrModal();
|
|
||||||
switch (queryElement.tokenAttr) {
|
|
||||||
case 'word':
|
|
||||||
case 'lemma':
|
|
||||||
this.elements.tokenBuilderContent.querySelector('input').value = queryElement.tokenValue;
|
|
||||||
break;
|
|
||||||
case 'english-pos':
|
|
||||||
// English-pos is selected by default. Then it is checked whether the passed token value occurs in the english-pos selection. If not, the selection is reseted and changed to german-pos.
|
|
||||||
let selection = this.elements.tokenBuilderContent.querySelector('select');
|
|
||||||
queryElement.tokenAttr = selection.querySelector(`option[value=${queryElement.tokenValue}]`) ? 'english-pos' : 'german-pos';
|
|
||||||
this.app.resetMaterializeSelection([this.elements.positionalAttrSelection], queryElement.tokenAttr);
|
|
||||||
this.preparePositionalAttrModal();
|
|
||||||
this.app.resetMaterializeSelection([this.elements.tokenBuilderContent.querySelector('select')], queryElement.tokenValue);
|
|
||||||
break;
|
|
||||||
case 'simple_pos':
|
|
||||||
this.app.resetMaterializeSelection([this.elements.tokenBuilderContent.querySelector('select')], queryElement.tokenValue);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (queryElement.ignoreCase) {
|
|
||||||
this.elements.ignoreCaseCheckbox.checked = true;
|
|
||||||
}
|
|
||||||
if (queryElement.condition !== undefined) {
|
|
||||||
this.conditionHandler(queryElement.condition, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
prepareTokenQueryElementsContent(queryChipElement) {
|
|
||||||
//this regex searches for word or lemma or pos or simple_pos="any string (also quotation marks escaped by backslash) within double quotes" followed by one or no ignore case markers, followed by one or no condition characters.
|
|
||||||
let regex = new RegExp('(word|lemma|pos|simple_pos)=("(?:[^"\\\\]|\\\\")*") ?(%c)? ?(\\&|\\|)?', 'gm');
|
|
||||||
let m;
|
|
||||||
let queryElementsContent = [];
|
|
||||||
while ((m = regex.exec(queryChipElement.dataset.query)) !== null) {
|
|
||||||
// this is necessary to avoid infinite loops with zero-width matches
|
|
||||||
if (m.index === regex.lastIndex) {
|
|
||||||
regex.lastIndex++;
|
|
||||||
}
|
|
||||||
let tokenAttr = m[1];
|
|
||||||
// Passes english-pos by default so that the template is added. In editTokenChipElement it is then checked whether it is english-pos or german-pos.
|
|
||||||
if (tokenAttr === 'pos') {
|
|
||||||
tokenAttr = 'english-pos';
|
|
||||||
}
|
|
||||||
let tokenValue = m[2].replace(/(?<!\\)"/g, '');
|
|
||||||
let ignoreCase = false;
|
|
||||||
let condition = undefined;
|
|
||||||
m.forEach((match) => {
|
|
||||||
if (match === "%c") {
|
|
||||||
ignoreCase = true;
|
|
||||||
} else if (match === "&") {
|
|
||||||
condition = "and";
|
|
||||||
} else if (match === "|") {
|
|
||||||
condition = "or";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
queryElementsContent.push({tokenAttr: tokenAttr, tokenValue: tokenValue, ignoreCase: ignoreCase, condition: condition});
|
|
||||||
}
|
|
||||||
return queryElementsContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
nopaque.corpus_analysis.cqi.api.Client = class Client {
|
cqi.api.APIClient = class APIClient {
|
||||||
/**
|
/**
|
||||||
* @param {string} host
|
* @param {string} host
|
||||||
* @param {number} [timeout=60] timeout
|
* @param {number} [timeout=60] timeout
|
||||||
@ -30,10 +30,10 @@ nopaque.corpus_analysis.cqi.api.Client = class Client {
|
|||||||
} else if (response.code === 500) {
|
} else if (response.code === 500) {
|
||||||
throw new Error(`[${response.code}] ${response.msg}`);
|
throw new Error(`[${response.code}] ${response.msg}`);
|
||||||
} else if (response.code === 502) {
|
} else if (response.code === 502) {
|
||||||
if (response.payload.code in nopaque.corpus_analysis.cqi.errors.lookup) {
|
if (response.payload.code in cqi.errors.lookup) {
|
||||||
throw new nopaque.corpus_analysis.cqi.errors.lookup[response.payload.code]();
|
throw new cqi.errors.lookup[response.payload.code]();
|
||||||
} else {
|
} else {
|
||||||
throw new nopaque.corpus_analysis.cqi.errors.CQiError();
|
throw new cqi.errors.CQiError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,22 +41,22 @@ nopaque.corpus_analysis.cqi.api.Client = class Client {
|
|||||||
/**
|
/**
|
||||||
* @param {string} username
|
* @param {string} username
|
||||||
* @param {string} password
|
* @param {string} password
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusConnectOk>}
|
* @returns {Promise<cqi.status.StatusConnectOk>}
|
||||||
*/
|
*/
|
||||||
async ctrl_connect(username, password) {
|
async ctrl_connect(username, password) {
|
||||||
const fn_name = 'ctrl_connect';
|
const fn_name = 'ctrl_connect';
|
||||||
const fn_args = {username: username, password: password};
|
const fn_args = {username: username, password: password};
|
||||||
let payload = await this.#request(fn_name, fn_args);
|
let payload = await this.#request(fn_name, fn_args);
|
||||||
return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
|
return new cqi.status.lookup[payload.code]();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusByeOk>}
|
* @returns {Promise<cqi.status.StatusByeOk>}
|
||||||
*/
|
*/
|
||||||
async ctrl_bye() {
|
async ctrl_bye() {
|
||||||
const fn_name = 'ctrl_bye';
|
const fn_name = 'ctrl_bye';
|
||||||
let payload = await this.#request(fn_name);
|
let payload = await this.#request(fn_name);
|
||||||
return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
|
return new cqi.status.lookup[payload.code]();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,12 +68,12 @@ nopaque.corpus_analysis.cqi.api.Client = class Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusPingOk>}
|
* @returns {Promise<cqi.status.StatusPingOk>}
|
||||||
*/
|
*/
|
||||||
async ctrl_ping() {
|
async ctrl_ping() {
|
||||||
const fn_name = 'ctrl_ping';
|
const fn_name = 'ctrl_ping';
|
||||||
let payload = await this.#request(fn_name);
|
let payload = await this.#request(fn_name);
|
||||||
return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
|
return new cqi.status.lookup[payload.code]();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -208,13 +208,13 @@ nopaque.corpus_analysis.cqi.api.Client = class Client {
|
|||||||
* try to unload a corpus and all its attributes from memory
|
* try to unload a corpus and all its attributes from memory
|
||||||
*
|
*
|
||||||
* @param {string} corpus
|
* @param {string} corpus
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
|
* @returns {Promise<cqi.status.StatusOk>}
|
||||||
*/
|
*/
|
||||||
async corpus_drop_corpus(corpus) {
|
async corpus_drop_corpus(corpus) {
|
||||||
const fn_name = 'corpus_drop_corpus';
|
const fn_name = 'corpus_drop_corpus';
|
||||||
const fn_args = {corpus: corpus};
|
const fn_args = {corpus: corpus};
|
||||||
let payload = await this.#request(fn_name, fn_args);
|
let payload = await this.#request(fn_name, fn_args);
|
||||||
return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
|
return new cqi.status.lookup[payload.code]();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -250,13 +250,13 @@ nopaque.corpus_analysis.cqi.api.Client = class Client {
|
|||||||
* unload attribute from memory
|
* unload attribute from memory
|
||||||
*
|
*
|
||||||
* @param {string} attribute
|
* @param {string} attribute
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
|
* @returns {Promise<cqi.status.StatusOk>}
|
||||||
*/
|
*/
|
||||||
async cl_drop_attribute(attribute) {
|
async cl_drop_attribute(attribute) {
|
||||||
const fn_name = 'cl_drop_attribute';
|
const fn_name = 'cl_drop_attribute';
|
||||||
const fn_args = {attribute: attribute};
|
const fn_args = {attribute: attribute};
|
||||||
let payload = await this.#request(fn_name, fn_args);
|
let payload = await this.#request(fn_name, fn_args);
|
||||||
return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
|
return new cqi.status.lookup[payload.code]();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -482,13 +482,13 @@ nopaque.corpus_analysis.cqi.api.Client = class Client {
|
|||||||
* @param {string} mother_corpus
|
* @param {string} mother_corpus
|
||||||
* @param {string} subcorpus_name
|
* @param {string} subcorpus_name
|
||||||
* @param {string} query
|
* @param {string} query
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
|
* @returns {Promise<cqi.status.StatusOk>}
|
||||||
*/
|
*/
|
||||||
async cqp_query(mother_corpus, subcorpus_name, query) {
|
async cqp_query(mother_corpus, subcorpus_name, query) {
|
||||||
const fn_name = 'cqp_query';
|
const fn_name = 'cqp_query';
|
||||||
const fn_args = {mother_corpus: mother_corpus, subcorpus_name: subcorpus_name, query: query};
|
const fn_args = {mother_corpus: mother_corpus, subcorpus_name: subcorpus_name, query: query};
|
||||||
let payload = await this.#request(fn_name, fn_args);
|
let payload = await this.#request(fn_name, fn_args);
|
||||||
return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
|
return new cqi.status.lookup[payload.code]();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -524,7 +524,7 @@ nopaque.corpus_analysis.cqi.api.Client = class Client {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Dump the values of <field> for match ranges <first> .. <last>
|
* Dump the values of <field> for match ranges <first> .. <last>
|
||||||
* in <subcorpus>. <field> is one of the nopaque.corpus_analysis.cqi.constants.FIELD_* constants.
|
* in <subcorpus>. <field> is one of the CQI_CONST_FIELD_* constants.
|
||||||
*
|
*
|
||||||
* @param {string} subcorpus
|
* @param {string} subcorpus
|
||||||
* @param {number} field
|
* @param {number} field
|
||||||
@ -542,13 +542,13 @@ nopaque.corpus_analysis.cqi.api.Client = class Client {
|
|||||||
* delete a subcorpus from memory
|
* delete a subcorpus from memory
|
||||||
*
|
*
|
||||||
* @param {string} subcorpus
|
* @param {string} subcorpus
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
|
* @returns {Promise<cqi.status.StatusOk>}
|
||||||
*/
|
*/
|
||||||
async cqp_drop_subcorpus(subcorpus) {
|
async cqp_drop_subcorpus(subcorpus) {
|
||||||
const fn_name = 'cqp_drop_subcorpus';
|
const fn_name = 'cqp_drop_subcorpus';
|
||||||
const fn_args = {subcorpus: subcorpus};
|
const fn_args = {subcorpus: subcorpus};
|
||||||
let payload = await this.#request(fn_name, fn_args);
|
let payload = await this.#request(fn_name, fn_args);
|
||||||
return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
|
return new cqi.status.lookup[payload.code]();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -561,9 +561,9 @@ nopaque.corpus_analysis.cqi.api.Client = class Client {
|
|||||||
*
|
*
|
||||||
* returns <n> (id, frequency) pairs flattened into a list of size 2*<n>
|
* returns <n> (id, frequency) pairs flattened into a list of size 2*<n>
|
||||||
* field is one of
|
* field is one of
|
||||||
* - nopaque.corpus_analysis.cqi.constants.FIELD_MATCH
|
* - CQI_CONST_FIELD_MATCH
|
||||||
* - nopaque.corpus_analysis.cqi.constants.FIELD_TARGET
|
* - CQI_CONST_FIELD_TARGET
|
||||||
* - nopaque.corpus_analysis.cqi.constants.FIELD_KEYWORD
|
* - CQI_CONST_FIELD_KEYWORD
|
||||||
*
|
*
|
||||||
* NB: pairs are sorted by frequency desc.
|
* NB: pairs are sorted by frequency desc.
|
||||||
*
|
*
|
||||||
@ -610,13 +610,13 @@ nopaque.corpus_analysis.cqi.api.Client = class Client {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} corpus
|
* @param {string} corpus
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
|
* @returns {Promise<cqi.status.StatusOk>}
|
||||||
*/
|
*/
|
||||||
async ext_corpus_update_db(corpus) {
|
async ext_corpus_update_db(corpus) {
|
||||||
const fn_name = 'ext_corpus_update_db';
|
const fn_name = 'ext_corpus_update_db';
|
||||||
const fn_args = {corpus: corpus};
|
const fn_args = {corpus: corpus};
|
||||||
let payload = await this.#request(fn_name, fn_args);
|
let payload = await this.#request(fn_name, fn_args);
|
||||||
return new nopaque.corpus_analysis.cqi.status.lookup[payload.code]();
|
return new cqi.status.lookup[payload.code]();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
1
app/static/js/cqi/api/package.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
cqi.api = {};
|
@ -1,23 +1,23 @@
|
|||||||
nopaque.corpus_analysis.cqi.Client = class Client {
|
cqi.CQiClient = class CQiClient {
|
||||||
/**
|
/**
|
||||||
* @param {string} host
|
* @param {string} host
|
||||||
* @param {number} [timeout=60] timeout
|
* @param {number} [timeout=60] timeout
|
||||||
* @param {string} [version=0.1] version
|
* @param {string} [version=0.1] version
|
||||||
*/
|
*/
|
||||||
constructor(host, timeout = 60, version = '0.1') {
|
constructor(host, timeout = 60, version = '0.1') {
|
||||||
/** @type {nopaque.corpus_analysis.cqi.api.Client} */
|
/** @type {cqi.api.APIClient} */
|
||||||
this.api = new nopaque.corpus_analysis.cqi.api.Client(host, timeout, version);
|
this.api = new cqi.api.APIClient(host, timeout, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {nopaque.corpus_analysis.cqi.models.corpora.CorpusCollection}
|
* @returns {cqi.models.corpora.CorpusCollection}
|
||||||
*/
|
*/
|
||||||
get corpora() {
|
get corpora() {
|
||||||
return new nopaque.corpus_analysis.cqi.models.corpora.CorpusCollection(this);
|
return new cqi.models.corpora.CorpusCollection(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusByeOk>}
|
* @returns {Promise<cqi.status.StatusByeOk>}
|
||||||
*/
|
*/
|
||||||
async bye() {
|
async bye() {
|
||||||
return await this.api.ctrl_bye();
|
return await this.api.ctrl_bye();
|
||||||
@ -26,14 +26,14 @@ nopaque.corpus_analysis.cqi.Client = class Client {
|
|||||||
/**
|
/**
|
||||||
* @param {string} username
|
* @param {string} username
|
||||||
* @param {string} password
|
* @param {string} password
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusConnectOk>}
|
* @returns {Promise<cqi.status.StatusConnectOk>}
|
||||||
*/
|
*/
|
||||||
async connect(username, password) {
|
async connect(username, password) {
|
||||||
return await this.api.ctrl_connect(username, password);
|
return await this.api.ctrl_connect(username, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusPingOk>}
|
* @returns {Promise<cqi.status.StatusPingOk>}
|
||||||
*/
|
*/
|
||||||
async ping() {
|
async ping() {
|
||||||
return await this.api.ctrl_ping();
|
return await this.api.ctrl_ping();
|
||||||
@ -49,7 +49,7 @@ nopaque.corpus_analysis.cqi.Client = class Client {
|
|||||||
/**
|
/**
|
||||||
* Alias for "bye" method
|
* Alias for "bye" method
|
||||||
*
|
*
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusByeOk>}
|
* @returns {Promise<cqi.status.StatusByeOk>}
|
||||||
*/
|
*/
|
||||||
async disconnect() {
|
async disconnect() {
|
||||||
return await this.api.ctrl_bye();
|
return await this.api.ctrl_bye();
|
185
app/static/js/cqi/errors.js
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
cqi.errors = {};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base class from which all other errors inherit.
|
||||||
|
* If you want to catch all errors that the CQi package might throw,
|
||||||
|
* catch this base error.
|
||||||
|
*/
|
||||||
|
cqi.errors.CQiError = class CQiError extends Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = undefined;
|
||||||
|
this.description = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.Error = class Error extends cqi.errors.CQiError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.ErrorGeneralError = class ErrorGeneralError extends cqi.errors.Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 513;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.ErrorConnectRefused = class ErrorConnectRefused extends cqi.errors.Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 514;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.ErrorUserAbort = class ErrorUserAbort extends cqi.errors.Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 515;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.ErrorSyntaxError = class ErrorSyntaxError extends cqi.errors.Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 516;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.CLError = class Error extends cqi.errors.CQiError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 4;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.CLErrorNoSuchAttribute = class CLErrorNoSuchAttribute extends cqi.errors.CLError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 1025;
|
||||||
|
this.description = "CQi server couldn't open attribute";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.CLErrorWrongAttributeType = class CLErrorWrongAttributeType extends cqi.errors.CLError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 1026;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.CLErrorOutOfRange = class CLErrorOutOfRange extends cqi.errors.CLError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 1027;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.CLErrorRegex = class CLErrorRegex extends cqi.errors.CLError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 1028;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.CLErrorCorpusAccess = class CLErrorCorpusAccess extends cqi.errors.CLError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 1029;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.CLErrorOutOfMemory = class CLErrorOutOfMemory extends cqi.errors.CLError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 1030;
|
||||||
|
this.description = 'CQi server has run out of memory; try discarding some other corpora and/or subcorpora';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.CLErrorInternal = class CLErrorInternal extends cqi.errors.CLError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 1031;
|
||||||
|
this.description = "The classical 'please contact technical support' error";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.CQPError = class Error extends cqi.errors.CQiError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 5;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.CQPErrorGeneral = class CQPErrorGeneral extends cqi.errors.CQPError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 1281;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.CQPErrorNoSuchCorpus = class CQPErrorNoSuchCorpus extends cqi.errors.CQPError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 1282;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.CQPErrorInvalidField = class CQPErrorInvalidField extends cqi.errors.CQPError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 1283;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.CQPErrorOutOfRange = class CQPErrorOutOfRange extends cqi.errors.CQPError {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.code = 1284;
|
||||||
|
this.description = 'A number is out of range';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.errors.lookup = {
|
||||||
|
2: cqi.errors.Error,
|
||||||
|
513: cqi.errors.ErrorGeneralError,
|
||||||
|
514: cqi.errors.ErrorConnectRefused,
|
||||||
|
515: cqi.errors.ErrorUserAbort,
|
||||||
|
516: cqi.errors.ErrorSyntaxError,
|
||||||
|
4: cqi.errors.CLError,
|
||||||
|
1025: cqi.errors.CLErrorNoSuchAttribute,
|
||||||
|
1026: cqi.errors.CLErrorWrongAttributeType,
|
||||||
|
1027: cqi.errors.CLErrorOutOfRange,
|
||||||
|
1028: cqi.errors.CLErrorRegex,
|
||||||
|
1029: cqi.errors.CLErrorCorpusAccess,
|
||||||
|
1030: cqi.errors.CLErrorOutOfMemory,
|
||||||
|
1031: cqi.errors.CLErrorInternal,
|
||||||
|
5: cqi.errors.CQPError,
|
||||||
|
1281: cqi.errors.CQPErrorGeneral,
|
||||||
|
1282: cqi.errors.CQPErrorNoSuchCorpus,
|
||||||
|
1283: cqi.errors.CQPErrorInvalidField,
|
||||||
|
1284: cqi.errors.CQPErrorOutOfRange
|
||||||
|
};
|
@ -1,7 +1,7 @@
|
|||||||
nopaque.corpus_analysis.cqi.models.attributes = {};
|
cqi.models.attributes = {};
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.models.attributes.Attribute = class Attribute extends nopaque.corpus_analysis.cqi.models.resource.Model {
|
cqi.models.attributes.Attribute = class Attribute extends cqi.models.resource.Model {
|
||||||
/**
|
/**
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
@ -24,7 +24,7 @@ nopaque.corpus_analysis.cqi.models.attributes.Attribute = class Attribute extend
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
|
* @returns {Promise<cqi.status.StatusOk>}
|
||||||
*/
|
*/
|
||||||
async drop() {
|
async drop() {
|
||||||
return await this.client.api.cl_drop_attribute(this.apiName);
|
return await this.client.api.cl_drop_attribute(this.apiName);
|
||||||
@ -32,17 +32,17 @@ nopaque.corpus_analysis.cqi.models.attributes.Attribute = class Attribute extend
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.models.attributes.AttributeCollection = class AttributeCollection extends nopaque.corpus_analysis.cqi.models.resource.Collection {
|
cqi.models.attributes.AttributeCollection = class AttributeCollection extends cqi.models.resource.Collection {
|
||||||
/** @type{typeof nopaque.corpus_analysis.cqi.models.attributes.Attribute} */
|
/** @type{typeof cqi.models.attributes.Attribute} */
|
||||||
static model = nopaque.corpus_analysis.cqi.models.attributes.Attribute;
|
static model = cqi.models.attributes.Attribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {nopaque.corpus_analysis.cqi.Client} client
|
* @param {cqi.CQiClient} client
|
||||||
* @param {nopaque.corpus_analysis.cqi.models.corpora.Corpus} corpus
|
* @param {cqi.models.corpora.Corpus} corpus
|
||||||
*/
|
*/
|
||||||
constructor(client, corpus) {
|
constructor(client, corpus) {
|
||||||
super(client);
|
super(client);
|
||||||
/** @type {nopaque.corpus_analysis.cqi.models.corpora.Corpus} */
|
/** @type {cqi.models.corpora.Corpus} */
|
||||||
this.corpus = corpus;
|
this.corpus = corpus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ nopaque.corpus_analysis.cqi.models.attributes.AttributeCollection = class Attrib
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} attributeName
|
* @param {string} attributeName
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.models.attributes.Attribute>}
|
* @returns {Promise<cqi.models.attributes.Attribute>}
|
||||||
*/
|
*/
|
||||||
async get(attributeName) {
|
async get(attributeName) {
|
||||||
return this.prepareModel(await this._get(attributeName));
|
return this.prepareModel(await this._get(attributeName));
|
||||||
@ -70,7 +70,7 @@ nopaque.corpus_analysis.cqi.models.attributes.AttributeCollection = class Attrib
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttribute = class AlignmentAttribute extends nopaque.corpus_analysis.cqi.models.attributes.Attribute {
|
cqi.models.attributes.AlignmentAttribute = class AlignmentAttribute extends cqi.models.attributes.Attribute {
|
||||||
/**
|
/**
|
||||||
* @param {number} id
|
* @param {number} id
|
||||||
* @returns {Promise<[number, number, number, number]>}
|
* @returns {Promise<[number, number, number, number]>}
|
||||||
@ -89,17 +89,17 @@ nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttribute = class Alignme
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttributeCollection = class AlignmentAttributeCollection extends nopaque.corpus_analysis.cqi.models.attributes.AttributeCollection {
|
cqi.models.attributes.AlignmentAttributeCollection = class AlignmentAttributeCollection extends cqi.models.attributes.AttributeCollection {
|
||||||
/** @type{typeof nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttribute} */
|
/** @type{typeof cqi.models.attributes.AlignmentAttribute} */
|
||||||
static model = nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttribute;
|
static model = cqi.models.attributes.AlignmentAttribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttribute[]>}
|
* @returns {Promise<cqi.models.attributes.AlignmentAttribute[]>}
|
||||||
*/
|
*/
|
||||||
async list() {
|
async list() {
|
||||||
/** @type {string[]} */
|
/** @type {string[]} */
|
||||||
let alignmentAttributeNames = await this.client.api.corpus_alignment_attributes(this.corpus.apiName);
|
let alignmentAttributeNames = await this.client.api.corpus_alignment_attributes(this.corpus.apiName);
|
||||||
/** @type {nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttribute[]} */
|
/** @type {cqi.models.attributes.AlignmentAttribute[]} */
|
||||||
let alignmentAttributes = [];
|
let alignmentAttributes = [];
|
||||||
for (let alignmentAttributeName of alignmentAttributeNames) {
|
for (let alignmentAttributeName of alignmentAttributeNames) {
|
||||||
alignmentAttributes.push(await this.get(alignmentAttributeName));
|
alignmentAttributes.push(await this.get(alignmentAttributeName));
|
||||||
@ -109,7 +109,7 @@ nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttributeCollection = cla
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute = class PositionalAttribute extends nopaque.corpus_analysis.cqi.models.attributes.Attribute {
|
cqi.models.attributes.PositionalAttribute = class PositionalAttribute extends cqi.models.attributes.Attribute {
|
||||||
/**
|
/**
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
@ -183,9 +183,9 @@ nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute = class Positi
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.models.attributes.PositionalAttributeCollection = class PositionalAttributeCollection extends nopaque.corpus_analysis.cqi.models.attributes.AttributeCollection {
|
cqi.models.attributes.PositionalAttributeCollection = class PositionalAttributeCollection extends cqi.models.attributes.AttributeCollection {
|
||||||
/** @type{typeof nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute} */
|
/** @type{typeof cqi.models.attributes.PositionalAttribute} */
|
||||||
static model = nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute;
|
static model = cqi.models.attributes.PositionalAttribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} positionalAttributeName
|
* @param {string} positionalAttributeName
|
||||||
@ -198,7 +198,7 @@ nopaque.corpus_analysis.cqi.models.attributes.PositionalAttributeCollection = cl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute[]>}
|
* @returns {Promise<cqi.models.attributes.PositionalAttribute[]>}
|
||||||
*/
|
*/
|
||||||
async list() {
|
async list() {
|
||||||
let positionalAttributeNames = await this.client.api.corpus_positional_attributes(this.corpus.apiName);
|
let positionalAttributeNames = await this.client.api.corpus_positional_attributes(this.corpus.apiName);
|
||||||
@ -211,7 +211,7 @@ nopaque.corpus_analysis.cqi.models.attributes.PositionalAttributeCollection = cl
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.models.attributes.StructuralAttribute = class StructuralAttribute extends nopaque.corpus_analysis.cqi.models.attributes.Attribute {
|
cqi.models.attributes.StructuralAttribute = class StructuralAttribute extends cqi.models.attributes.Attribute {
|
||||||
/**
|
/**
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
@ -261,9 +261,9 @@ nopaque.corpus_analysis.cqi.models.attributes.StructuralAttribute = class Struct
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.models.attributes.StructuralAttributeCollection = class StructuralAttributeCollection extends nopaque.corpus_analysis.cqi.models.attributes.AttributeCollection {
|
cqi.models.attributes.StructuralAttributeCollection = class StructuralAttributeCollection extends cqi.models.attributes.AttributeCollection {
|
||||||
/** @type{typeof nopaque.corpus_analysis.cqi.models.attributes.StructuralAttribute} */
|
/** @type{typeof cqi.models.attributes.StructuralAttribute} */
|
||||||
static model = nopaque.corpus_analysis.cqi.models.attributes.StructuralAttribute;
|
static model = cqi.models.attributes.StructuralAttribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} structuralAttributeName
|
* @param {string} structuralAttributeName
|
||||||
@ -276,7 +276,7 @@ nopaque.corpus_analysis.cqi.models.attributes.StructuralAttributeCollection = cl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.models.attributes.StructuralAttribute[]>}
|
* @returns {Promise<cqi.models.attributes.StructuralAttribute[]>}
|
||||||
*/
|
*/
|
||||||
async list() {
|
async list() {
|
||||||
let structuralAttributeNames = await this.client.api.corpus_structural_attributes(this.corpus.apiName);
|
let structuralAttributeNames = await this.client.api.corpus_structural_attributes(this.corpus.apiName);
|
@ -1,7 +1,7 @@
|
|||||||
nopaque.corpus_analysis.cqi.models.corpora = {};
|
cqi.models.corpora = {};
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.models.corpora.Corpus = class Corpus extends nopaque.corpus_analysis.cqi.models.resource.Model {
|
cqi.models.corpora.Corpus = class Corpus extends cqi.models.resource.Model {
|
||||||
/**
|
/**
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
@ -38,35 +38,35 @@ nopaque.corpus_analysis.cqi.models.corpora.Corpus = class Corpus extends nopaque
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttributeCollection}
|
* @returns {cqi.models.attributes.AlignmentAttributeCollection}
|
||||||
*/
|
*/
|
||||||
get alignmentAttributes() {
|
get alignmentAttributes() {
|
||||||
return new nopaque.corpus_analysis.cqi.models.attributes.AlignmentAttributeCollection(this.client, this);
|
return new cqi.models.attributes.AlignmentAttributeCollection(this.client, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {nopaque.corpus_analysis.cqi.models.attributes.PositionalAttributeCollection}
|
* @returns {cqi.models.attributes.PositionalAttributeCollection}
|
||||||
*/
|
*/
|
||||||
get positionalAttributes() {
|
get positionalAttributes() {
|
||||||
return new nopaque.corpus_analysis.cqi.models.attributes.PositionalAttributeCollection(this.client, this);
|
return new cqi.models.attributes.PositionalAttributeCollection(this.client, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {nopaque.corpus_analysis.cqi.models.attributes.StructuralAttributeCollection}
|
* @returns {cqi.models.attributes.StructuralAttributeCollection}
|
||||||
*/
|
*/
|
||||||
get structuralAttributes() {
|
get structuralAttributes() {
|
||||||
return new nopaque.corpus_analysis.cqi.models.attributes.StructuralAttributeCollection(this.client, this);
|
return new cqi.models.attributes.StructuralAttributeCollection(this.client, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {nopaque.corpus_analysis.cqi.models.subcorpora.SubcorpusCollection}
|
* @returns {cqi.models.subcorpora.SubcorpusCollection}
|
||||||
*/
|
*/
|
||||||
get subcorpora() {
|
get subcorpora() {
|
||||||
return new nopaque.corpus_analysis.cqi.models.subcorpora.SubcorpusCollection(this.client, this);
|
return new cqi.models.subcorpora.SubcorpusCollection(this.client, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
|
* @returns {Promise<cqi.status.StatusOk>}
|
||||||
*/
|
*/
|
||||||
async drop() {
|
async drop() {
|
||||||
return await this.client.api.corpus_drop_corpus(this.apiName);
|
return await this.client.api.corpus_drop_corpus(this.apiName);
|
||||||
@ -75,7 +75,7 @@ nopaque.corpus_analysis.cqi.models.corpora.Corpus = class Corpus extends nopaque
|
|||||||
/**
|
/**
|
||||||
* @param {string} subcorpusName
|
* @param {string} subcorpusName
|
||||||
* @param {string} query
|
* @param {string} query
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
|
* @returns {Promise<cqi.status.StatusOk>}
|
||||||
*/
|
*/
|
||||||
async query(subcorpusName, query) {
|
async query(subcorpusName, query) {
|
||||||
return await this.client.api.cqp_query(this.apiName, subcorpusName, query);
|
return await this.client.api.cqp_query(this.apiName, subcorpusName, query);
|
||||||
@ -96,7 +96,7 @@ nopaque.corpus_analysis.cqi.models.corpora.Corpus = class Corpus extends nopaque
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {nopaque.corpus_analysis.cqi.status.StatusOk}
|
* @returns {cqi.status.StatusOk}
|
||||||
*/
|
*/
|
||||||
async updateDb() {
|
async updateDb() {
|
||||||
return await this.client.api.ext_corpus_update_db(this.apiName);
|
return await this.client.api.ext_corpus_update_db(this.apiName);
|
||||||
@ -113,9 +113,9 @@ nopaque.corpus_analysis.cqi.models.corpora.Corpus = class Corpus extends nopaque
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.models.corpora.CorpusCollection = class CorpusCollection extends nopaque.corpus_analysis.cqi.models.resource.Collection {
|
cqi.models.corpora.CorpusCollection = class CorpusCollection extends cqi.models.resource.Collection {
|
||||||
/** @type {typeof nopaque.corpus_analysis.cqi.models.corpora.Corpus} */
|
/** @type {typeof cqi.models.corpora.Corpus} */
|
||||||
static model = nopaque.corpus_analysis.cqi.models.corpora.Corpus;
|
static model = cqi.models.corpora.Corpus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} corpusName
|
* @param {string} corpusName
|
||||||
@ -144,19 +144,19 @@ nopaque.corpus_analysis.cqi.models.corpora.CorpusCollection = class CorpusCollec
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} corpusName
|
* @param {string} corpusName
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.models.corpora.Corpus>}
|
* @returns {Promise<cqi.models.corpora.Corpus>}
|
||||||
*/
|
*/
|
||||||
async get(corpusName) {
|
async get(corpusName) {
|
||||||
return this.prepareModel(await this._get(corpusName));
|
return this.prepareModel(await this._get(corpusName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.models.corpora.Corpus[]>}
|
* @returns {Promise<cqi.models.corpora.Corpus[]>}
|
||||||
*/
|
*/
|
||||||
async list() {
|
async list() {
|
||||||
/** @type {string[]} */
|
/** @type {string[]} */
|
||||||
let corpusNames = await this.client.api.corpus_list_corpora();
|
let corpusNames = await this.client.api.corpus_list_corpora();
|
||||||
/** @type {nopaque.corpus_analysis.cqi.models.corpora.Corpus[]} */
|
/** @type {cqi.models.corpora.Corpus[]} */
|
||||||
let corpora = [];
|
let corpora = [];
|
||||||
for (let corpusName of corpusNames) {
|
for (let corpusName of corpusNames) {
|
||||||
corpora.push(await this.get(corpusName));
|
corpora.push(await this.get(corpusName));
|
1
app/static/js/cqi/models/package.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
cqi.models = {};
|
@ -1,26 +1,26 @@
|
|||||||
nopaque.corpus_analysis.cqi.models.resource = {};
|
cqi.models.resource = {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base class for representing a single object on the server.
|
* A base class for representing a single object on the server.
|
||||||
*/
|
*/
|
||||||
nopaque.corpus_analysis.cqi.models.resource.Model = class Model {
|
cqi.models.resource.Model = class Model {
|
||||||
/**
|
/**
|
||||||
* @param {object} attrs
|
* @param {object} attrs
|
||||||
* @param {nopaque.corpus_analysis.cqi.CQiClient} client
|
* @param {cqi.CQiClient} client
|
||||||
* @param {nopaque.corpus_analysis.cqi.models.resource.Collection} collection
|
* @param {cqi.models.resource.Collection} collection
|
||||||
*/
|
*/
|
||||||
constructor(attrs, client, collection) {
|
constructor(attrs, client, collection) {
|
||||||
/**
|
/**
|
||||||
* A client pointing at the server that this object is on.
|
* A client pointing at the server that this object is on.
|
||||||
*
|
*
|
||||||
* @type {nopaque.corpus_analysis.cqi.CQiClient}
|
* @type {cqi.CQiClient}
|
||||||
*/
|
*/
|
||||||
this.client = client;
|
this.client = client;
|
||||||
/**
|
/**
|
||||||
* The collection that this model is part of.
|
* The collection that this model is part of.
|
||||||
*
|
*
|
||||||
* @type {nopaque.corpus_analysis.cqi.models.resource.Collection}
|
* @type {cqi.models.resource.Collection}
|
||||||
*/
|
*/
|
||||||
this.collection = collection;
|
this.collection = collection;
|
||||||
/**
|
/**
|
||||||
@ -50,22 +50,22 @@ nopaque.corpus_analysis.cqi.models.resource.Model = class Model {
|
|||||||
/**
|
/**
|
||||||
* A base class for representing all objects of a particular type on the server.
|
* A base class for representing all objects of a particular type on the server.
|
||||||
*/
|
*/
|
||||||
nopaque.corpus_analysis.cqi.models.resource.Collection = class Collection {
|
cqi.models.resource.Collection = class Collection {
|
||||||
/**
|
/**
|
||||||
* The type of object this collection represents, set by subclasses
|
* The type of object this collection represents, set by subclasses
|
||||||
*
|
*
|
||||||
* @type {typeof nopaque.corpus_analysis.cqi.models.resource.Model}
|
* @type {typeof cqi.models.resource.Model}
|
||||||
*/
|
*/
|
||||||
static model;
|
static model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {nopaque.corpus_analysis.cqi.CQiClient} client
|
* @param {cqi.CQiClient} client
|
||||||
*/
|
*/
|
||||||
constructor(client) {
|
constructor(client) {
|
||||||
/**
|
/**
|
||||||
* A client pointing at the server that this object is on.
|
* A client pointing at the server that this object is on.
|
||||||
*
|
*
|
||||||
* @type {nopaque.corpus_analysis.cqi.CQiClient}
|
* @type {cqi.CQiClient}
|
||||||
*/
|
*/
|
||||||
this.client = client;
|
this.client = client;
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ nopaque.corpus_analysis.cqi.models.resource.Collection = class Collection {
|
|||||||
* Create a model from a set of attributes.
|
* Create a model from a set of attributes.
|
||||||
*
|
*
|
||||||
* @param {object} attrs
|
* @param {object} attrs
|
||||||
* @returns {nopaque.corpus_analysis.cqi.models.resource.Model}
|
* @returns {cqi.models.resource.Model}
|
||||||
*/
|
*/
|
||||||
prepareModel(attrs) {
|
prepareModel(attrs) {
|
||||||
return new this.constructor.model(attrs, this.client, this);
|
return new this.constructor.model(attrs, this.client, this);
|
@ -1,7 +1,7 @@
|
|||||||
nopaque.corpus_analysis.cqi.models.subcorpora = {};
|
cqi.models.subcorpora = {};
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus = class Subcorpus extends nopaque.corpus_analysis.cqi.models.resource.Model {
|
cqi.models.subcorpora.Subcorpus = class Subcorpus extends cqi.models.resource.Model {
|
||||||
/**
|
/**
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
@ -31,7 +31,7 @@ nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus = class Subcorpus extend
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.status.StatusOk>}
|
* @returns {Promise<cqi.status.StatusOk>}
|
||||||
*/
|
*/
|
||||||
async drop() {
|
async drop() {
|
||||||
return await this.client.api.cqp_drop_subcorpus(this.apiName);
|
return await this.client.api.cqp_drop_subcorpus(this.apiName);
|
||||||
@ -55,7 +55,7 @@ nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus = class Subcorpus extend
|
|||||||
/**
|
/**
|
||||||
* @param {number} cutoff
|
* @param {number} cutoff
|
||||||
* @param {number} field
|
* @param {number} field
|
||||||
* @param {nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute} attribute
|
* @param {cqi.models.attributes.PositionalAttribute} attribute
|
||||||
* @returns {Promise<number[]>}
|
* @returns {Promise<number[]>}
|
||||||
*/
|
*/
|
||||||
async fdist1(cutoff, field, attribute) {
|
async fdist1(cutoff, field, attribute) {
|
||||||
@ -70,9 +70,9 @@ nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus = class Subcorpus extend
|
|||||||
/**
|
/**
|
||||||
* @param {number} cutoff
|
* @param {number} cutoff
|
||||||
* @param {number} field1
|
* @param {number} field1
|
||||||
* @param {nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute} attribute1
|
* @param {cqi.models.attributes.PositionalAttribute} attribute1
|
||||||
* @param {number} field2
|
* @param {number} field2
|
||||||
* @param {nopaque.corpus_analysis.cqi.models.attributes.PositionalAttribute} attribute2
|
* @param {cqi.models.attributes.PositionalAttribute} attribute2
|
||||||
* @returns {Promise<number[]>}
|
* @returns {Promise<number[]>}
|
||||||
*/
|
*/
|
||||||
async fdist2(cutoff, field1, attribute1, field2, attribute2) {
|
async fdist2(cutoff, field1, attribute1, field2, attribute2) {
|
||||||
@ -122,17 +122,17 @@ nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus = class Subcorpus extend
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
nopaque.corpus_analysis.cqi.models.subcorpora.SubcorpusCollection = class SubcorpusCollection extends nopaque.corpus_analysis.cqi.models.resource.Collection {
|
cqi.models.subcorpora.SubcorpusCollection = class SubcorpusCollection extends cqi.models.resource.Collection {
|
||||||
/** @type {typeof nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus} */
|
/** @type {typeof cqi.models.subcorpora.Subcorpus} */
|
||||||
static model = nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus;
|
static model = cqi.models.subcorpora.Subcorpus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {nopaque.corpus_analysis.cqi.CQiClient} client
|
* @param {cqi.CQiClient} client
|
||||||
* @param {nopaque.corpus_analysis.cqi.models.corpora.Corpus} corpus
|
* @param {cqi.models.corpora.Corpus} corpus
|
||||||
*/
|
*/
|
||||||
constructor(client, corpus) {
|
constructor(client, corpus) {
|
||||||
super(client);
|
super(client);
|
||||||
/** @type {nopaque.corpus_analysis.cqi.models.corpora.Corpus} */
|
/** @type {cqi.models.corpora.Corpus} */
|
||||||
this.corpus = corpus;
|
this.corpus = corpus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,17 +145,17 @@ nopaque.corpus_analysis.cqi.models.subcorpora.SubcorpusCollection = class Subcor
|
|||||||
let apiName = `${this.corpus.apiName}:${subcorpusName}`;
|
let apiName = `${this.corpus.apiName}:${subcorpusName}`;
|
||||||
/** @type {object} */
|
/** @type {object} */
|
||||||
let fields = {};
|
let fields = {};
|
||||||
if (await this.client.api.cqp_subcorpus_has_field(apiName, nopaque.corpus_analysis.cqi.constants.FIELD_MATCH)) {
|
if (await this.client.api.cqp_subcorpus_has_field(apiName, cqi.CONST_FIELD_MATCH)) {
|
||||||
fields.match = nopaque.corpus_analysis.cqi.constants.FIELD_MATCH;
|
fields.match = cqi.CONST_FIELD_MATCH;
|
||||||
}
|
}
|
||||||
if (await this.client.api.cqp_subcorpus_has_field(apiName, nopaque.corpus_analysis.cqi.constants.FIELD_MATCHEND)) {
|
if (await this.client.api.cqp_subcorpus_has_field(apiName, cqi.CONST_FIELD_MATCHEND)) {
|
||||||
fields.matchend = nopaque.corpus_analysis.cqi.constants.FIELD_MATCHEND
|
fields.matchend = cqi.CONST_FIELD_MATCHEND
|
||||||
}
|
}
|
||||||
if (await this.client.api.cqp_subcorpus_has_field(apiName, nopaque.corpus_analysis.cqi.constants.FIELD_TARGET)) {
|
if (await this.client.api.cqp_subcorpus_has_field(apiName, cqi.CONST_FIELD_TARGET)) {
|
||||||
fields.target = nopaque.corpus_analysis.cqi.constants.FIELD_TARGET
|
fields.target = cqi.CONST_FIELD_TARGET
|
||||||
}
|
}
|
||||||
if (await this.client.api.cqp_subcorpus_has_field(apiName, nopaque.corpus_analysis.cqi.constants.FIELD_KEYWORD)) {
|
if (await this.client.api.cqp_subcorpus_has_field(apiName, cqi.CONST_FIELD_KEYWORD)) {
|
||||||
fields.keyword = nopaque.corpus_analysis.cqi.constants.FIELD_KEYWORD
|
fields.keyword = cqi.CONST_FIELD_KEYWORD
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
api_name: apiName,
|
api_name: apiName,
|
||||||
@ -167,19 +167,19 @@ nopaque.corpus_analysis.cqi.models.subcorpora.SubcorpusCollection = class Subcor
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} subcorpusName
|
* @param {string} subcorpusName
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus>}
|
* @returns {Promise<cqi.models.subcorpora.Subcorpus>}
|
||||||
*/
|
*/
|
||||||
async get(subcorpusName) {
|
async get(subcorpusName) {
|
||||||
return this.prepareModel(await this._get(subcorpusName));
|
return this.prepareModel(await this._get(subcorpusName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus[]>}
|
* @returns {Promise<cqi.models.subcorpora.Subcorpus[]>}
|
||||||
*/
|
*/
|
||||||
async list() {
|
async list() {
|
||||||
/** @type {string[]} */
|
/** @type {string[]} */
|
||||||
let subcorpusNames = await this.client.api.cqp_list_subcorpora(this.corpus.apiName);
|
let subcorpusNames = await this.client.api.cqp_list_subcorpora(this.corpus.apiName);
|
||||||
/** @type {nopaque.corpus_analysis.cqi.models.subcorpora.Subcorpus[]} */
|
/** @type {cqi.models.subcorpora.Subcorpus[]} */
|
||||||
let subcorpora = [];
|
let subcorpora = [];
|
||||||
for (let subcorpusName of subcorpusNames) {
|
for (let subcorpusName of subcorpusNames) {
|
||||||
subcorpora.push(await this.get(subcorpusName));
|
subcorpora.push(await this.get(subcorpusName));
|
6
app/static/js/cqi/package.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
var cqi = {};
|
||||||
|
|
||||||
|
cqi.CONST_FIELD_KEYWORD = 9;
|
||||||
|
cqi.CONST_FIELD_MATCH = 16;
|
||||||
|
cqi.CONST_FIELD_MATCHEND = 17;
|
||||||
|
cqi.CONST_FIELD_TARGET = 0;
|
51
app/static/js/cqi/status.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
cqi.status = {};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base class from which all other status inherit.
|
||||||
|
*/
|
||||||
|
cqi.status.CQiStatus = class CQiStatus {
|
||||||
|
constructor() {
|
||||||
|
this.code = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.status.StatusOk = class StatusOk extends cqi.status.CQiStatus {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.code = 257;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.status.StatusConnectOk = class StatusConnectOk extends cqi.status.CQiStatus {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.code = 258;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.status.StatusByeOk = class StatusByeOk extends cqi.status.CQiStatus {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.code = 259;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.status.StatusPingOk = class StatusPingOk extends cqi.status.CQiStatus {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.code = 260;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cqi.status.lookup = {
|
||||||
|
257: cqi.status.StatusOk,
|
||||||
|
258: cqi.status.StatusConnectOk,
|
||||||
|
259: cqi.status.StatusByeOk,
|
||||||
|
260: cqi.status.StatusPingOk
|
||||||
|
};
|
@ -1,13 +0,0 @@
|
|||||||
nopaque.forms.CreateContributionForm = class CreateContributionForm extends nopaque.forms.BaseForm {
|
|
||||||
static htmlClass = 'create-contribution-form';
|
|
||||||
|
|
||||||
constructor(formElement) {
|
|
||||||
super(formElement);
|
|
||||||
|
|
||||||
this.addEventListener('requestLoad', (event) => {
|
|
||||||
if (event.target.status === 201) {
|
|
||||||
window.location.href = event.target.getResponseHeader('Location');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|