mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2025-01-15 20:40:34 +00:00
Compare commits
26 Commits
8182cccecd
...
05bccc7f88
Author | SHA1 | Date | |
---|---|---|---|
|
05bccc7f88 | ||
|
8b887d79ef | ||
|
37f9e1281d | ||
|
5eef2292e7 | ||
|
351da5d4e9 | ||
|
27fe4a95e4 | ||
|
0627b27ec7 | ||
|
adfd229e66 | ||
|
ae6a7cb86d | ||
|
2dd6015ba6 | ||
|
f80b635ca3 | ||
|
0e8a87d34e | ||
|
ccf7f449dd | ||
|
dd05657362 | ||
|
cef82d9001 | ||
|
656eef17db | ||
|
104c2fe468 | ||
|
d08f95e944 | ||
|
87e2c2b484 | ||
|
7a925b6a19 | ||
|
e4f435c5ee | ||
|
7721926d6c | ||
|
691d4757ff | ||
|
6c744fc3ba | ||
|
e46f0032bd | ||
|
9da1a6e987 |
@ -75,9 +75,9 @@ def create_app(config: Config = Config) -> Flask:
|
||||
|
||||
from .corpora import bp as corpora_blueprint
|
||||
from .corpora.cqi_over_sio import CQiNamespace
|
||||
socketio.on_namespace(CQiNamespace('/cqi_over_sio'))
|
||||
default_breadcrumb_root(corpora_blueprint, '.corpora')
|
||||
app.register_blueprint(corpora_blueprint, cli_group='corpus', url_prefix='/corpora')
|
||||
socketio.on_namespace(CQiNamespace('/cqi_over_sio'))
|
||||
|
||||
from .errors import bp as errors_bp
|
||||
app.register_blueprint(errors_bp)
|
||||
@ -102,4 +102,7 @@ def create_app(config: Config = Config) -> Flask:
|
||||
default_breadcrumb_root(users_blueprint, '.users')
|
||||
app.register_blueprint(users_blueprint, url_prefix='/users')
|
||||
|
||||
from .workshops import bp as workshops_blueprint
|
||||
app.register_blueprint(workshops_blueprint, url_prefix='/workshops')
|
||||
|
||||
return app
|
||||
|
@ -121,7 +121,7 @@ class CQiNamespace(Namespace):
|
||||
socketio.sleep(3)
|
||||
retry_counter -= 1
|
||||
db.session.refresh(db_corpus)
|
||||
cqi_client = CQiClient(f'cqpserver_{db_corpus_id}', timeout=None)
|
||||
cqi_client = CQiClient(f'cqpserver_{db_corpus_id}', timeout=float('inf'))
|
||||
session['cqi_over_sio'] = {}
|
||||
session['cqi_over_sio']['cqi_client'] = cqi_client
|
||||
session['cqi_over_sio']['cqi_client_lock'] = Lock()
|
||||
|
@ -66,7 +66,7 @@ def get_stopwords():
|
||||
stopwords = {}
|
||||
for language in languages:
|
||||
stopwords[language] = nltk.corpus.stopwords.words(language)
|
||||
stopwords['punctuation'] = list(punctuation) + ['—', '|']
|
||||
stopwords['punctuation'] = list(punctuation) + ['—', '|', '–', '“', '„', '--']
|
||||
stopwords['user_stopwords'] = []
|
||||
response_data = stopwords
|
||||
return response_data, 202
|
||||
|
@ -61,7 +61,7 @@ def file_setup_pipeline():
|
||||
return {}, 201, {'Location': job.url}
|
||||
return render_template(
|
||||
'services/file_setup_pipeline.html.j2',
|
||||
title=service_manifest['name'],
|
||||
service_manifest=service_manifest,
|
||||
form=form
|
||||
)
|
||||
|
||||
@ -110,7 +110,7 @@ def tesseract_ocr_pipeline():
|
||||
user_tesseract_ocr_pipeline_models_count = len(current_user.tesseract_ocr_pipeline_models.all())
|
||||
return render_template(
|
||||
'services/tesseract_ocr_pipeline.html.j2',
|
||||
title=service_manifest['name'],
|
||||
service_manifest=service_manifest,
|
||||
form=form,
|
||||
tesseract_ocr_pipeline_models=tesseract_ocr_pipeline_models,
|
||||
user_tesseract_ocr_pipeline_models_count=user_tesseract_ocr_pipeline_models_count
|
||||
@ -169,7 +169,7 @@ def transkribus_htr_pipeline():
|
||||
return {}, 201, {'Location': job.url}
|
||||
return render_template(
|
||||
'services/transkribus_htr_pipeline.html.j2',
|
||||
title=service_manifest['name'],
|
||||
service_manifest=service_manifest,
|
||||
form=form,
|
||||
transkribus_htr_pipeline_models=transkribus_htr_pipeline_models
|
||||
)
|
||||
@ -215,7 +215,7 @@ def spacy_nlp_pipeline():
|
||||
return {}, 201, {'Location': job.url}
|
||||
return render_template(
|
||||
'services/spacy_nlp_pipeline.html.j2',
|
||||
title=service_manifest['name'],
|
||||
service_manifest=service_manifest,
|
||||
form=form,
|
||||
spacy_nlp_pipeline_models=spacy_nlp_pipeline_models,
|
||||
user_spacy_nlp_pipeline_models_count=user_spacy_nlp_pipeline_models_count
|
||||
|
@ -7,22 +7,39 @@ file-setup-pipeline:
|
||||
0.1.0:
|
||||
publishing_year: 2022
|
||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/file-setup-pipeline/-/releases/v0.1.0'
|
||||
code_url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/file-setup-pipeline/-/tree/v0.1.0'
|
||||
tesseract-ocr-pipeline:
|
||||
name: 'Tesseract OCR Pipeline'
|
||||
publisher: 'Bielefeld University - CRC 1288 - INF'
|
||||
latest_version: '0.1.1'
|
||||
latest_version: '0.1.3'
|
||||
versions:
|
||||
0.1.0:
|
||||
methods:
|
||||
- 'binarization'
|
||||
publishing_year: 2022
|
||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/tesseract-ocr-pipeline/-/releases/v0.1.0'
|
||||
code_url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/tesseract-ocr-pipeline/-/tree/v0.1.0'
|
||||
0.1.1:
|
||||
methods:
|
||||
- 'binarization'
|
||||
- 'ocropus_nlbin_threshold'
|
||||
publishing_year: 2022
|
||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/tesseract-ocr-pipeline/-/releases/v0.1.1'
|
||||
code_url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/tesseract-ocr-pipeline/-/tree/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'
|
||||
code_url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/tesseract-ocr-pipeline/-/tree/v0.1.2'
|
||||
0.1.3:
|
||||
methods:
|
||||
- 'binarization'
|
||||
- 'ocropus_nlbin_threshold'
|
||||
publishing_year: 2023
|
||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/tesseract-ocr-pipeline/-/releases/v0.1.3'
|
||||
code_url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/tesseract-ocr-pipeline/-/tree/v0.1.3'
|
||||
transkribus-htr-pipeline:
|
||||
name: 'Transkribus HTR Pipeline'
|
||||
publisher: 'Bielefeld University - CRC 1288 - INF'
|
||||
@ -33,28 +50,51 @@ transkribus-htr-pipeline:
|
||||
- 'binarization'
|
||||
publishing_year: 2022
|
||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/transkribus-htr-pipeline/-/releases/v0.1.0'
|
||||
code_url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/transkribus-htr-pipeline/-/tree/v0.1.0'
|
||||
0.1.1:
|
||||
methods:
|
||||
- 'binarization'
|
||||
publishing_year: 2022
|
||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/transkribus-htr-pipeline/-/releases/v0.1.1'
|
||||
code_url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/transkribus-htr-pipeline/-/tree/v0.1.1'
|
||||
spacy-nlp-pipeline:
|
||||
name: 'SpaCy NLP Pipeline'
|
||||
publisher: 'Bielefeld University - CRC 1288 - INF'
|
||||
latest_version: '0.1.2'
|
||||
latest_version: '0.1.5'
|
||||
versions:
|
||||
0.1.0:
|
||||
methods:
|
||||
- 'encoding_detection'
|
||||
publishing_year: 2022
|
||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/releases/v0.1.0'
|
||||
code_url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/tree/v0.1.0'
|
||||
0.1.1:
|
||||
methods:
|
||||
- 'encoding_detection'
|
||||
publishing_year: 2022
|
||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/releases/v0.1.1'
|
||||
code_url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/tree/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'
|
||||
code_url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/tree/v0.1.2'
|
||||
0.1.3:
|
||||
methods:
|
||||
- 'encoding_detection'
|
||||
publishing_year: 2023
|
||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/releases/v0.1.3'
|
||||
code_url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/tree/v0.1.3'
|
||||
0.1.4:
|
||||
methods:
|
||||
- 'encoding_detection'
|
||||
publishing_year: 2023
|
||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/releases/v0.1.4'
|
||||
code_url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/tree/v0.1.4'
|
||||
0.1.5:
|
||||
methods:
|
||||
- 'encoding_detection'
|
||||
publishing_year: 2023
|
||||
url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/releases/v0.1.5'
|
||||
code_url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/spacy-nlp-pipeline/-/tree/v0.1.5'
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 160 KiB |
BIN
app/static/images/workshops/fgho_sommerschule_2023/corpus.png
Normal file
BIN
app/static/images/workshops/fgho_sommerschule_2023/corpus.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 182 KiB |
Binary file not shown.
After Width: | Height: | Size: 155 KiB |
BIN
app/static/images/workshops/fgho_sommerschule_2023/dashboard.png
Normal file
BIN
app/static/images/workshops/fgho_sommerschule_2023/dashboard.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 104 KiB |
Binary file not shown.
After Width: | Height: | Size: 115 KiB |
@ -8,19 +8,19 @@ class App {
|
||||
this.socket.on('PATCH', (patch) => {this.onPatch(patch);});
|
||||
}
|
||||
|
||||
getUser(userId, backrefs=true, relationships=true) {
|
||||
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, backrefs, relationships, (response) => {
|
||||
if (response.status !== 200) {
|
||||
reject(response);
|
||||
return;
|
||||
}
|
||||
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}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -26,22 +26,42 @@ class CorpusAnalysisApp {
|
||||
this.disableActionElements();
|
||||
this.elements.m.initModal.open();
|
||||
|
||||
// Setup CQi over SocketIO connection and gather data from the CQPServer
|
||||
try {
|
||||
// Setup CQi over SocketIO connection and gather data from the CQPServer
|
||||
const statusTextElement = this.elements.initModal.querySelector('.status-text');
|
||||
statusTextElement.innerText = 'Creating CQi over SocketIO client...';
|
||||
const cqiClient = new cqi.CQiClient('/cqi_over_sio');
|
||||
statusTextElement.innerText += ' Done';
|
||||
statusTextElement.innerHTML = 'Waiting for the CQP server...';
|
||||
const response = await cqiClient.api.socket.emitWithAck('init', this.corpusId);
|
||||
if (response.code !== 200) {throw new Error();}
|
||||
statusTextElement.innerText += ' Done';
|
||||
statusTextElement.innerHTML = 'Connecting to the CQP server...';
|
||||
await cqiClient.connect('anonymous', '');
|
||||
statusTextElement.innerText += ' Done';
|
||||
statusTextElement.innerHTML = 'Building and receiving corpus data cache from the server (This may take a while)...';
|
||||
const cqiCorpus = await cqiClient.corpora.get(`NOPAQUE-${this.corpusId.toUpperCase()}`);
|
||||
statusTextElement.innerText += ' Done';
|
||||
// TODO: Don't do this hgere
|
||||
await cqiCorpus.updateDb();
|
||||
this.data.cqiClient = cqiClient;
|
||||
this.data.cqiCorpus = cqiCorpus;
|
||||
this.data.corpus = {o: cqiCorpus}; // legacy
|
||||
// Initialize extensions
|
||||
for (const extension of Object.values(this.extensions)) {
|
||||
statusTextElement.innerHTML = `Initializing ${extension.name} extension...`;
|
||||
await extension.init();
|
||||
statusTextElement.innerText += ' Done'
|
||||
}
|
||||
} catch (error) {
|
||||
// TODO: Currently we can only handle CQiErrors here,
|
||||
// but we should also handle other errors.
|
||||
const errorString = `${error.code}: ${error.constructor.name}`;
|
||||
let errorString = '';
|
||||
if ('code' in error && error.code !== undefined && error.code !== null) {
|
||||
errorString += `[${error.code}] `;
|
||||
}
|
||||
errorString += `${error.constructor.name}`;
|
||||
if ('description' in error && error.description !== undefined && error.description !== null) {
|
||||
errorString += `: ${error.description}`;
|
||||
}
|
||||
const errorsElement = this.elements.initModal.querySelector('.errors');
|
||||
const progressElement = this.elements.initModal.querySelector('.progress');
|
||||
errorsElement.innerText = errorString;
|
||||
@ -50,8 +70,6 @@ class CorpusAnalysisApp {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize extensions
|
||||
for (const extension of Object.values(this.extensions)) {extension.init();}
|
||||
for (const extensionSelectorElement of this.elements.extensionCards.querySelectorAll('.extension-selector')) {
|
||||
extensionSelectorElement.addEventListener('click', () => {
|
||||
this.elements.m.extensionTabs.select(extensionSelectorElement.dataset.target);
|
||||
|
@ -30,33 +30,22 @@ class CorpusAnalysisConcordance {
|
||||
this.app.registerExtension(this);
|
||||
}
|
||||
|
||||
init() {
|
||||
// Init data
|
||||
this.data.corpus = this.app.data.corpus;
|
||||
this.data.subcorpora = {};
|
||||
// Add event listeners
|
||||
this.elements.form.addEventListener('submit', event => {
|
||||
event.preventDefault();
|
||||
async submitForm() {
|
||||
this.app.disableActionElements();
|
||||
let query = this.elements.form.query.value.trim();
|
||||
let subcorpusName = this.elements.form['subcorpus-name'].value;
|
||||
this.elements.error.innerText = '';
|
||||
this.elements.error.classList.add('hide');
|
||||
this.elements.progress.classList.remove('hide');
|
||||
let subcorpus = {};
|
||||
this.data.corpus.o.query(subcorpusName, query)
|
||||
.then((cqiStatus) => {
|
||||
try {
|
||||
const subcorpus = {};
|
||||
subcorpus.q = query;
|
||||
subcorpus.selectedItems = new Set();
|
||||
await this.data.corpus.o.query(subcorpusName, query);
|
||||
if (subcorpusName !== 'Last') {this.data.subcorpora.Last = subcorpus;}
|
||||
return this.data.corpus.o.subcorpora.get(subcorpusName);
|
||||
})
|
||||
.then((cqiSubcorpus) => {
|
||||
const cqiSubcorpus = await this.data.corpus.o.subcorpora.get(subcorpusName);
|
||||
subcorpus.o = cqiSubcorpus;
|
||||
return cqiSubcorpus.paginate(this.settings.context, 1, this.settings.perPage);
|
||||
})
|
||||
.then(
|
||||
(paginatedSubcorpus) => {
|
||||
const paginatedSubcorpus = await cqiSubcorpus.paginate(this.settings.context, 1, this.settings.perPage);
|
||||
subcorpus.p = paginatedSubcorpus;
|
||||
this.data.subcorpora[subcorpusName] = subcorpus;
|
||||
this.settings.selectedSubcorpus = subcorpusName;
|
||||
@ -66,26 +55,35 @@ class CorpusAnalysisConcordance {
|
||||
this.renderSubcorpusItems();
|
||||
this.renderSubcorpusPagination();
|
||||
this.elements.progress.classList.add('hide');
|
||||
this.app.enableActionElements();
|
||||
},
|
||||
(cqiError) => {
|
||||
let errorString = `${cqiError.code}: ${cqiError.constructor.name}`;
|
||||
} catch (error) {
|
||||
let errorString = '';
|
||||
if ('code' in error) {errorString += `[${error.code}] `;}
|
||||
errorString += `${error.constructor.name}`;
|
||||
this.elements.error.innerText = errorString;
|
||||
this.elements.error.classList.remove('hide');
|
||||
app.flash(errorString, 'error');
|
||||
this.elements.progress.classList.add('hide');
|
||||
}
|
||||
this.app.enableActionElements();
|
||||
}
|
||||
);
|
||||
|
||||
async init() {
|
||||
// Init data
|
||||
this.data.corpus = this.app.data.corpus;
|
||||
this.data.subcorpora = {};
|
||||
// Add event listeners
|
||||
this.elements.form.addEventListener('submit', (event) => {
|
||||
event.preventDefault();
|
||||
this.submitForm();
|
||||
});
|
||||
this.elements.form.addEventListener('change', event => {
|
||||
this.elements.form.addEventListener('change', (event) => {
|
||||
if (event.target === this.elements.form['context']) {
|
||||
this.settings.context = parseInt(this.elements.form['context'].value);
|
||||
this.elements.form.submit.click();
|
||||
this.submitForm();
|
||||
}
|
||||
if (event.target === this.elements.form['per-page']) {
|
||||
this.settings.perPage = parseInt(this.elements.form['per-page'].value);
|
||||
this.elements.form.submit.click();
|
||||
this.submitForm();
|
||||
}
|
||||
if (event.target === this.elements.form['text-style']) {
|
||||
this.settings.textStyle = parseInt(this.elements.form['text-style'].value);
|
||||
@ -161,7 +159,7 @@ class CorpusAnalysisConcordance {
|
||||
</a>
|
||||
`.trim();
|
||||
M.Tooltip.init(this.elements.subcorpusActions.querySelectorAll('.tooltipped'));
|
||||
this.elements.subcorpusActions.querySelector('.subcorpus-export-trigger').addEventListener('click', event => {
|
||||
this.elements.subcorpusActions.querySelector('.subcorpus-export-trigger').addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
let subcorpus = this.data.subcorpora[this.settings.selectedSubcorpus];
|
||||
let modalElementId = Utils.generateElementId('export-subcorpus-modal-');
|
||||
@ -218,7 +216,7 @@ class CorpusAnalysisConcordance {
|
||||
}
|
||||
}
|
||||
);
|
||||
exportButton.addEventListener('click', event => {
|
||||
exportButton.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
this.app.disableActionElements();
|
||||
this.elements.progress.classList.remove('hide');
|
||||
@ -240,7 +238,7 @@ class CorpusAnalysisConcordance {
|
||||
promise = subcorpus.o.export(50);
|
||||
}
|
||||
promise.then(
|
||||
data => {
|
||||
(data) => {
|
||||
let blob;
|
||||
if (exportFormat === 'csv') {
|
||||
let csvContent = 'sep=,\r\n';
|
||||
@ -286,7 +284,7 @@ class CorpusAnalysisConcordance {
|
||||
});
|
||||
modal.open();
|
||||
});
|
||||
this.elements.subcorpusActions.querySelector('.subcorpus-delete-trigger').addEventListener('click', event => {
|
||||
this.elements.subcorpusActions.querySelector('.subcorpus-delete-trigger').addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
let subcorpus = this.data.subcorpora[this.settings.selectedSubcorpus];
|
||||
subcorpus.o.drop().then(
|
||||
@ -362,7 +360,7 @@ class CorpusAnalysisConcordance {
|
||||
this.setTextStyle();
|
||||
this.setTokenRepresentation();
|
||||
for (let gotoReaderTriggerElement of this.elements.subcorpusItems.querySelectorAll('.goto-reader-trigger')) {
|
||||
gotoReaderTriggerElement.addEventListener('click', event => {
|
||||
gotoReaderTriggerElement.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
let corpusAnalysisReader = this.app.extensions.Reader;
|
||||
let itemId = parseInt(gotoReaderTriggerElement.closest('.item').dataset.id);
|
||||
@ -384,7 +382,7 @@ class CorpusAnalysisConcordance {
|
||||
});
|
||||
}
|
||||
for (let selectTriggerElement of this.elements.subcorpusItems.querySelectorAll('.select-trigger')) {
|
||||
selectTriggerElement.addEventListener('click', event => {
|
||||
selectTriggerElement.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
let itemElement = selectTriggerElement.closest('.item');
|
||||
let itemId = parseInt(itemElement.dataset.id);
|
||||
@ -446,14 +444,14 @@ class CorpusAnalysisConcordance {
|
||||
</li>
|
||||
`.trim();
|
||||
for (let paginationTriggerElement of this.elements.subcorpusPagination.querySelectorAll('.pagination-trigger[data-target]')) {
|
||||
paginationTriggerElement.addEventListener('click', event => {
|
||||
paginationTriggerElement.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
this.app.disableActionElements();
|
||||
this.elements.progress.classList.remove('hide');
|
||||
let page = parseInt(paginationTriggerElement.dataset.target);
|
||||
subcorpus.o.paginate(page, this.settings.perPage, this.settings.context)
|
||||
subcorpus.o.paginate(this.settings.context, page, this.settings.perPage)
|
||||
.then(
|
||||
paginatedSubcorpus => {
|
||||
(paginatedSubcorpus) => {
|
||||
subcorpus.p = paginatedSubcorpus;
|
||||
this.renderSubcorpusItems();
|
||||
this.renderSubcorpusPagination();
|
||||
|
@ -29,39 +29,42 @@ class CorpusAnalysisReader {
|
||||
this.app.registerExtension(this);
|
||||
}
|
||||
|
||||
init() {
|
||||
async submitForm() {
|
||||
this.app.disableActionElements();
|
||||
this.elements.error.innerText = '';
|
||||
this.elements.error.classList.add('hide');
|
||||
this.elements.progress.classList.remove('hide');
|
||||
try {
|
||||
const paginatedCorpus = await this.data.corpus.o.paginate(1, this.settings.perPage);
|
||||
this.data.corpus.p = paginatedCorpus;
|
||||
this.renderCorpus();
|
||||
this.renderCorpusPagination();
|
||||
this.elements.progress.classList.add('hide');
|
||||
} catch (error) {
|
||||
let errorString = '';
|
||||
if ('code' in error) {errorString += `[${error.code}] `;}
|
||||
errorString += `${error.constructor.name}`;
|
||||
if ('description' in error) {errorString += `: ${error.description}`;}
|
||||
this.elements.error.innerText = errorString;
|
||||
this.elements.error.classList.remove('hide');
|
||||
app.flash(errorString, 'error');
|
||||
this.elements.progress.classList.add('hide');
|
||||
}
|
||||
this.app.enableActionElements();
|
||||
}
|
||||
|
||||
async init() {
|
||||
// Init data
|
||||
this.data.corpus = this.app.data.corpus;
|
||||
// Add event listeners
|
||||
this.elements.form.addEventListener('submit', (event) => {
|
||||
event.preventDefault();
|
||||
this.app.disableActionElements();
|
||||
this.elements.error.innerText = '';
|
||||
this.elements.error.classList.add('hide');
|
||||
this.elements.progress.classList.remove('hide');
|
||||
this.data.corpus.o.paginate(1, this.settings.perPage)
|
||||
.then(
|
||||
(paginatedCorpus) => {
|
||||
this.data.corpus.p = paginatedCorpus;
|
||||
this.renderCorpus();
|
||||
this.renderCorpusPagination();
|
||||
this.elements.progress.classList.add('hide');
|
||||
this.app.enableActionElements();
|
||||
},
|
||||
(cqiError) => {
|
||||
let errorString = `${cqiError.code}: ${cqiError.constructor.name}`;
|
||||
this.elements.error.innerText = errorString;
|
||||
this.elements.error.classList.remove('hide');
|
||||
app.flash(errorString, 'error');
|
||||
this.elements.progress.classList.add('hide');
|
||||
this.app.enableActionElements();
|
||||
}
|
||||
);
|
||||
this.submitForm();
|
||||
});
|
||||
this.elements.form.addEventListener('change', event => {
|
||||
this.elements.form.addEventListener('change', (event) => {
|
||||
if (event.target === this.elements.form['per-page']) {
|
||||
this.settings.perPage = parseInt(this.elements.form['per-page'].value);
|
||||
this.elements.form.submit.click();
|
||||
this.submitForm();
|
||||
}
|
||||
if (event.target === this.elements.form['text-style']) {
|
||||
this.settings.textStyle = parseInt(this.elements.form['text-style'].value);
|
||||
@ -73,7 +76,7 @@ class CorpusAnalysisReader {
|
||||
}
|
||||
});
|
||||
// Load initial data
|
||||
this.elements.form.submit.click();
|
||||
await this.submitForm();
|
||||
}
|
||||
|
||||
clearCorpus() {
|
||||
@ -205,7 +208,7 @@ class CorpusAnalysisReader {
|
||||
this.elements.corpusPagination.appendChild(pageElement);
|
||||
|
||||
for (let paginateTriggerElement of this.elements.corpusPagination.querySelectorAll('.pagination-trigger[data-target]')) {
|
||||
paginateTriggerElement.addEventListener('click', event => {
|
||||
paginateTriggerElement.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
let page = parseInt(paginateTriggerElement.dataset.target);
|
||||
this.page(page);
|
||||
|
@ -1,5 +1,5 @@
|
||||
class CorpusAnalysisStaticVisualization {
|
||||
name = 'Static Visualization';
|
||||
name = 'Static Visualization (beta)';
|
||||
|
||||
constructor(app) {
|
||||
this.app = app;
|
||||
@ -7,7 +7,8 @@ class CorpusAnalysisStaticVisualization {
|
||||
stopwords: undefined,
|
||||
originalStopwords: {},
|
||||
stopwordCache: {},
|
||||
promises: {getStopwords: undefined}
|
||||
promises: {getStopwords: undefined},
|
||||
tokenSet: new Set()
|
||||
};
|
||||
|
||||
this.app.registerExtension(this);
|
||||
@ -18,9 +19,10 @@ class CorpusAnalysisStaticVisualization {
|
||||
this.data.corpus = this.app.data.corpus;
|
||||
this.renderGeneralCorpusInfo();
|
||||
this.renderTextInfoList();
|
||||
this.renderTextProportionsGraphic()
|
||||
this.renderFrequenciesGraphic();
|
||||
this.renderBoundsGraphic();
|
||||
this.renderTextProportionsGraphic();
|
||||
this.renderTokenList();
|
||||
// this.renderFrequenciesGraphic();
|
||||
|
||||
// Add event listeners
|
||||
let frequenciesStopwordSettingModal = document.querySelector('#frequencies-stopwords-setting-modal');
|
||||
let frequenciesStopwordSettingModalButton = document.querySelector('#frequencies-stopwords-setting-modal-button');
|
||||
@ -30,11 +32,40 @@ class CorpusAnalysisStaticVisualization {
|
||||
M.Modal.init(frequenciesStopwordSettingModal, {dismissible: false});
|
||||
});
|
||||
|
||||
let textProportionsGraphModeButtons = document.querySelectorAll('.text-proportions-graph-mode-button');
|
||||
textProportionsGraphModeButtons.forEach(graphModeButton => {
|
||||
graphModeButton.addEventListener('click', (event) => {
|
||||
textProportionsGraphModeButtons.forEach(btn => {
|
||||
btn.classList.remove('disabled');
|
||||
});
|
||||
event.target.closest('.text-proportions-graph-mode-button').classList.add('disabled');
|
||||
this.renderTextProportionsGraphic();
|
||||
});
|
||||
});
|
||||
|
||||
let frequenciesTokenCategoryDropdownElement = document.querySelector('[data-target="frequencies-token-category-dropdown"]');
|
||||
let frequenciesTokenCategoryDropdownListElement = document.querySelector("#frequencies-token-category-dropdown");
|
||||
frequenciesTokenCategoryDropdownListElement.addEventListener('click', (event) => {
|
||||
frequenciesTokenCategoryDropdownElement.firstChild.textContent = event.target.innerHTML;
|
||||
this.renderTokenList();
|
||||
});
|
||||
|
||||
let frequenciesGraphModeButtons = document.querySelectorAll('.frequencies-graph-mode-button');
|
||||
frequenciesGraphModeButtons.forEach(graphModeButton => {
|
||||
graphModeButton.addEventListener('click', (event) => {
|
||||
frequenciesGraphModeButtons.forEach(btn => {
|
||||
btn.classList.remove('disabled');
|
||||
});
|
||||
event.target.closest('.frequencies-graph-mode-button').classList.add('disabled');
|
||||
this.renderFrequenciesGraphic(this.data.tokenSet);
|
||||
});
|
||||
});
|
||||
|
||||
for (let actionButton of document.querySelectorAll('.frequencies-stopword-setting-modal-action-buttons')) {
|
||||
actionButton.addEventListener('click', (event) => {
|
||||
let action = event.target.closest('.frequencies-stopword-setting-modal-action-buttons').dataset.action;
|
||||
if (action === 'submit') {
|
||||
this.renderFrequenciesGraphic();
|
||||
this.renderTokenList();
|
||||
} else if (action === 'cancel') {
|
||||
this.data.stopwords = structuredClone(this.data.stopwordCache);
|
||||
}
|
||||
@ -101,73 +132,154 @@ class CorpusAnalysisStaticVisualization {
|
||||
let corpusData = this.data.corpus.o.staticData;
|
||||
let textProportionsGraphicElement = document.querySelector('#text-proportions-graphic');
|
||||
let texts = Object.entries(corpusData.s_attrs.text.lexicon);
|
||||
let graphData = [
|
||||
{
|
||||
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})`),
|
||||
type: 'pie'
|
||||
let graphtype = document.querySelector('.text-proportions-graph-mode-button.disabled').dataset.graphType;
|
||||
let textProportionsTitleElement = document.querySelector('#text-proportions-title-element');
|
||||
|
||||
if (graphtype === 'bar') {
|
||||
textProportionsTitleElement.innerHTML = 'Bounds';
|
||||
} else if (graphtype === 'pie') {
|
||||
textProportionsTitleElement.innerHTML = 'Proportions';
|
||||
}
|
||||
];
|
||||
|
||||
let graphData = this.createTextProportionsGraphData(texts, graphtype);
|
||||
let graphLayout = {
|
||||
showlegend: true,
|
||||
height: 486,
|
||||
barmode: graphtype === 'bar' ? 'relative' : '',
|
||||
type: graphtype,
|
||||
showgrid: false,
|
||||
height: 447,
|
||||
margin: {
|
||||
l: 10,
|
||||
r: 10,
|
||||
b: 10,
|
||||
t: 10
|
||||
b: graphtype === 'bar' ? 80 : 10,
|
||||
t: graphtype === 'bar' ? 80 : 10,
|
||||
},
|
||||
legend: {
|
||||
"orientation": "h",
|
||||
font: {
|
||||
size: 10
|
||||
}
|
||||
},
|
||||
xaxis: {
|
||||
rangemode: 'nonnegative',
|
||||
autorange: true
|
||||
},
|
||||
yaxis: {
|
||||
autorange: true,
|
||||
showticklabels: false
|
||||
}
|
||||
};
|
||||
let config = {
|
||||
responsive: true,
|
||||
modeBarButtonsToRemove: ['zoom2d', 'select2d', 'lasso2d', 'zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'],
|
||||
displaylogo: false
|
||||
};
|
||||
|
||||
Plotly.newPlot(textProportionsGraphicElement, graphData, graphLayout, config);
|
||||
}
|
||||
|
||||
async renderFrequenciesGraphic() {
|
||||
createTextProportionsGraphData(texts, graphtype) {
|
||||
let corpusData = this.data.corpus.o.staticData;
|
||||
let graphData = [];
|
||||
switch (graphtype) {
|
||||
case 'bar':
|
||||
for (let text of texts) {
|
||||
let textData = {
|
||||
type: 'bar',
|
||||
orientation: 'h',
|
||||
x: [text[1].bounds[1] - text[1].bounds[0]],
|
||||
y: [0.5],
|
||||
text: [`${text[1].bounds[0]} - ${text[1].bounds[1]}`],
|
||||
name: `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`,
|
||||
hovertemplate: `${text[1].bounds[0]} - ${text[1].bounds[1]}`,
|
||||
};
|
||||
graphData.push(textData);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
graphData = [
|
||||
{
|
||||
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})`),
|
||||
type: graphtype
|
||||
}
|
||||
];
|
||||
break;
|
||||
}
|
||||
return graphData;
|
||||
}
|
||||
|
||||
async renderTokenList() {
|
||||
let corpusTokenListElement = document.querySelector('.corpus-token-list');
|
||||
let corpusTokenList = new CorpusTokenList(corpusTokenListElement);
|
||||
let filteredData = this.filterData();
|
||||
let stopwords = this.data.stopwords;
|
||||
if (this.data.stopwords === undefined) {
|
||||
stopwords = await this.getStopwords();
|
||||
}
|
||||
stopwords = Object.values(stopwords).flat();
|
||||
let mostFrequent = Object.entries(filteredData)
|
||||
.sort((a, b) => b[1].count - a[1].count)
|
||||
.filter(item => !stopwords.includes(item[0].toLowerCase()))
|
||||
.slice(0, 4)
|
||||
.map(item => item[0])
|
||||
|
||||
let tokenData = [];
|
||||
Object.entries(filteredData).forEach(item => {
|
||||
let resource = {
|
||||
term: item[0],
|
||||
count: item[1].count,
|
||||
mostFrequent: mostFrequent.includes(item[0])
|
||||
};
|
||||
if (!Object.values(stopwords).includes(resource.term)) {
|
||||
tokenData.push(resource);
|
||||
}
|
||||
});
|
||||
corpusTokenList.add(tokenData);
|
||||
}
|
||||
|
||||
filterData() {
|
||||
let frequenciesTokenCategoryDropdownElement = document.querySelector('[data-target="frequencies-token-category-dropdown"]');
|
||||
let tokenCategory = frequenciesTokenCategoryDropdownElement.firstChild.textContent.toLowerCase();
|
||||
let corpusData = this.data.corpus.o.staticData;
|
||||
let filteredData = {};
|
||||
|
||||
for (let i = 0; i < Object.values(corpusData.corpus.freqs[tokenCategory]).length; i++) {
|
||||
let term = corpusData.values.p_attrs[tokenCategory][i].toLowerCase();
|
||||
let count = corpusData.corpus.freqs[tokenCategory][i];
|
||||
|
||||
if (filteredData[term]) {
|
||||
filteredData[term].count += count;
|
||||
filteredData[term].originalIds.push(i);
|
||||
} else {
|
||||
filteredData[term] = {
|
||||
count: count,
|
||||
originalIds: [i]
|
||||
};
|
||||
}
|
||||
}
|
||||
return filteredData;
|
||||
}
|
||||
|
||||
|
||||
renderFrequenciesGraphic(tokenSet) {
|
||||
this.data.tokenSet = tokenSet;
|
||||
let corpusData = this.data.corpus.o.staticData;
|
||||
let frequenciesTokenCategoryDropdownElement = document.querySelector('[data-target="frequencies-token-category-dropdown"]');
|
||||
let frequenciesTokenCategoryDropdownListElement = document.querySelector("#frequencies-token-category-dropdown");
|
||||
let frequenciesGraphicElement = document.querySelector('#frequencies-graphic');
|
||||
let texts = Object.entries(corpusData.s_attrs.text.lexicon);
|
||||
let graphtype = document.querySelector('.frequencies-graph-mode-button.disabled').dataset.graphType;
|
||||
let graphModeButtons = document.querySelectorAll('.frequencies-graph-mode-button');
|
||||
|
||||
frequenciesTokenCategoryDropdownListElement.addEventListener('click', (event) => {
|
||||
frequenciesTokenCategoryDropdownElement.firstChild.textContent = event.target.innerHTML;
|
||||
this.renderFrequenciesGraphic(corpusData);
|
||||
});
|
||||
|
||||
graphModeButtons.forEach(graphModeButton => {
|
||||
graphModeButton.addEventListener('click', (event) => {
|
||||
graphModeButtons.forEach(btn => {
|
||||
btn.classList.remove('disabled');
|
||||
});
|
||||
event.target.closest('.frequencies-graph-mode-button').classList.add('disabled');
|
||||
this.renderFrequenciesGraphic(corpusData);
|
||||
});
|
||||
});
|
||||
|
||||
let tokenCategory = frequenciesTokenCategoryDropdownElement.firstChild.textContent.toLowerCase();
|
||||
|
||||
let graphData = await this.createFrequenciesGraphData(tokenCategory, texts, corpusData, graphtype);
|
||||
let graphData = this.createFrequenciesGraphData(tokenCategory, texts, graphtype, tokenSet);
|
||||
let graphLayout = {
|
||||
barmode: graphtype === 'bar' ? 'stack' : '',
|
||||
margin: {
|
||||
t: 20,
|
||||
l: 50
|
||||
},
|
||||
yaxis: {
|
||||
showticklabels: graphtype === 'markers' ? false : true
|
||||
},
|
||||
height: 627,
|
||||
margin: {
|
||||
l: 33
|
||||
}
|
||||
};
|
||||
let config = {
|
||||
responsive: true,
|
||||
@ -177,44 +289,52 @@ class CorpusAnalysisStaticVisualization {
|
||||
Plotly.newPlot(frequenciesGraphicElement, graphData, graphLayout, config);
|
||||
}
|
||||
|
||||
async createFrequenciesGraphData(category, texts, corpusData, graphtype) {
|
||||
let stopwords = this.data.stopwords;
|
||||
if (this.data.stopwords === undefined) {
|
||||
stopwords = await this.getStopwords();
|
||||
}
|
||||
let stopwordList = Object.values(stopwords).flat();
|
||||
createFrequenciesGraphData(tokenCategory, texts, graphtype, tokenSet) {
|
||||
let corpusData = this.data.corpus.o.staticData;
|
||||
let graphData = [];
|
||||
let filteredData = Object.entries(corpusData.corpus.freqs[category])
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.filter(item => !stopwordList.includes(corpusData.values.p_attrs[category][item[0]].toLowerCase()))
|
||||
.slice(0, 5);
|
||||
|
||||
if (graphtype !== 'markers') {
|
||||
for (let item of filteredData) {
|
||||
let data = {
|
||||
x: texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`),
|
||||
y: texts.map(text => text[1].freqs[category][item[0]] || 0),
|
||||
name: corpusData.values.p_attrs[category][item[0]],
|
||||
type: graphtype
|
||||
};
|
||||
graphData.push(data);
|
||||
let filteredData = this.filterData();
|
||||
switch (graphtype) {
|
||||
case 'markers':
|
||||
for (let item of tokenSet) {
|
||||
let textTitles = texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`);
|
||||
let tokenCountPerText = [];
|
||||
for (let originalId of filteredData[item].originalIds) {
|
||||
for (let i = 0; i < texts.length; i++) {
|
||||
tokenCountPerText[i] = (tokenCountPerText[i] || 0) + (texts[i][1].freqs[tokenCategory][originalId] || 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let item of filteredData) {
|
||||
let size = texts.map(text => text[1].freqs[category][item[0]] || 0);
|
||||
let data = {
|
||||
x: texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`),
|
||||
y: texts.map(text => corpusData.values.p_attrs[category][item[0]]),
|
||||
name: corpusData.values.p_attrs[category][item[0]],
|
||||
text: texts.map(text => `${corpusData.values.p_attrs[category][item[0]]}<br>${text[1].freqs[category][item[0]] || 0}`),
|
||||
x: textTitles,
|
||||
y: texts.map(text => item),
|
||||
name: item,
|
||||
text: texts.map(text => `${item}<br>${tokenCountPerText || 0}`),
|
||||
mode: 'markers',
|
||||
marker: {
|
||||
size: size,
|
||||
size: tokenCountPerText,
|
||||
sizeref: 0.4
|
||||
}
|
||||
};
|
||||
graphData.push(data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (let item of tokenSet) {
|
||||
let textTitles = texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`);
|
||||
let tokenCountPerText = [];
|
||||
for (let originalId of filteredData[item].originalIds) {
|
||||
for (let i = 0; i < texts.length; i++) {
|
||||
tokenCountPerText[i] = (tokenCountPerText[i] || 0) + (texts[i][1].freqs[tokenCategory][originalId] || 0);
|
||||
}
|
||||
}
|
||||
let data = {
|
||||
x: textTitles,
|
||||
y: tokenCountPerText,
|
||||
name: item,
|
||||
type: graphtype
|
||||
};
|
||||
graphData.push(data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return graphData;
|
||||
}
|
||||
@ -320,45 +440,4 @@ class CorpusAnalysisStaticVisualization {
|
||||
}
|
||||
this.buttonRendering();
|
||||
}
|
||||
|
||||
renderBoundsGraphic() {
|
||||
let corpusData = this.data.corpus.o.staticData;
|
||||
let boundsGraphicElement = document.querySelector('#bounds-graphic');
|
||||
|
||||
let graphData = [];
|
||||
let texts = Object.entries(corpusData.s_attrs.text.lexicon);
|
||||
|
||||
graphData = [{
|
||||
type: 'bar',
|
||||
x: texts.map(text => text[1].bounds[1] - text[1].bounds[0]),
|
||||
y: texts.map(text => corpusData.values.s_attrs.text[text[0]].title),
|
||||
base: texts.map(text => text[1].bounds[0]),
|
||||
text: texts.map(text => `${corpusData.values.s_attrs.text[text[0]].title} (${corpusData.values.s_attrs.text[text[0]].publishing_year})`),
|
||||
orientation: 'h',
|
||||
hovertemplate: '%{base} - %{x} <br>%{y}',
|
||||
showlegend: false
|
||||
}];
|
||||
|
||||
let graphLayout = {
|
||||
barmode: 'stack',
|
||||
type: 'bar',
|
||||
showgrid: false,
|
||||
xaxis: {
|
||||
rangemode: 'nonnegative',
|
||||
autorange: true
|
||||
},
|
||||
yaxis: {
|
||||
autorange: true,
|
||||
showticklabels: false
|
||||
}
|
||||
};
|
||||
|
||||
let config = {
|
||||
responsive: true,
|
||||
modeBarButtonsToRemove: ['zoom2d', 'select2d', 'lasso2d', 'zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'],
|
||||
displaylogo: false
|
||||
};
|
||||
|
||||
Plotly.newPlot(boundsGraphicElement, graphData, graphLayout, config);
|
||||
}
|
||||
}
|
||||
|
@ -162,9 +162,21 @@ class ConcordanceQueryBuilder {
|
||||
this.elements.or.addEventListener('click', () => {this.orHandler();});
|
||||
this.elements.and.addEventListener('click', () => {this.andHandler();});
|
||||
|
||||
|
||||
//#endregion Token Attribute Event Listeners
|
||||
|
||||
let selectInstances = this.elements.concordanceQueryBuilder.querySelectorAll('select');
|
||||
M.FormSelect.init(
|
||||
selectInstances,
|
||||
{
|
||||
dropdownOptions: {
|
||||
alignment: 'bottom',
|
||||
coverTrigger: false
|
||||
}
|
||||
}
|
||||
)
|
||||
let dropdownContents = this.elements.concordanceQueryBuilder.querySelectorAll('.dropdown-content');
|
||||
dropdownContents.forEach((dropdownContent) => {
|
||||
dropdownContent.style.paddingBottom = '15px';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -182,6 +194,7 @@ class ConcordanceQueryBuilder {
|
||||
|
||||
showPositionalAttrArea() {
|
||||
this.elements.positionalAttrArea.classList.remove('hide');
|
||||
this.elements.structuralAttrArea.classList.add('hide');
|
||||
this.wordBuilder();
|
||||
|
||||
this.elements.tokenQueryFilled = false;
|
||||
@ -195,6 +208,7 @@ class ConcordanceQueryBuilder {
|
||||
}
|
||||
|
||||
queryChipFactory(dataType, prettyQueryText, queryText) {
|
||||
this.elements.counter++;
|
||||
window.location.href = '#query-container';
|
||||
queryText = Utils.escape(queryText);
|
||||
prettyQueryText = Utils.escape(prettyQueryText);
|
||||
@ -274,9 +288,9 @@ class ConcordanceQueryBuilder {
|
||||
queryPreviewBuilder() {
|
||||
this.elements.yourQueryContent = [];
|
||||
for (let element of this.elements.yourQuery.childNodes) {
|
||||
let queryElement = decodeURI(element.dataset.query);
|
||||
let queryElement = element.dataset.query;
|
||||
if (queryElement !== undefined) {
|
||||
queryElement = Utils.escape(queryElement);
|
||||
if (queryElement !== 'undefined') {
|
||||
this.elements.yourQueryContent.push(queryElement);
|
||||
}
|
||||
}
|
||||
@ -306,7 +320,7 @@ class ConcordanceQueryBuilder {
|
||||
this.validateValue();
|
||||
if (this.elements.valueValidator) {
|
||||
for (let element of this.elements.yourQuery.childNodes) {
|
||||
let queryElement = decodeURI(element.dataset.query);
|
||||
let queryElement = element.dataset.query;
|
||||
if (queryElement !== 'undefined') {
|
||||
this.elements.yourQueryContent.push(queryElement);
|
||||
}
|
||||
@ -632,8 +646,11 @@ class ConcordanceQueryBuilder {
|
||||
englishPosHandler() {
|
||||
this.hideEverything();
|
||||
this.elements.englishPosBuilder.classList.remove('hide');
|
||||
// this.elements.incidenceModifiersButton.classList.remove('hide');
|
||||
this.elements.incidenceModifiersButton.classList.remove('hide');
|
||||
this.elements.conditionContainer.classList.remove('hide');
|
||||
this.elements.incidenceModifiersButton.firstElementChild.classList.remove('disabled');
|
||||
this.elements.or.classList.remove('disabled');
|
||||
this.elements.and.classList.remove('disabled');
|
||||
|
||||
// Resets materialize select dropdown
|
||||
let selectInstance = M.FormSelect.getInstance(this.elements.englishPos);
|
||||
@ -644,8 +661,11 @@ class ConcordanceQueryBuilder {
|
||||
germanPosHandler() {
|
||||
this.hideEverything();
|
||||
this.elements.germanPosBuilder.classList.remove('hide');
|
||||
// this.elements.incidenceModifiersButton.classList.remove('hide');
|
||||
this.elements.incidenceModifiersButton.classList.remove('hide');
|
||||
this.elements.conditionContainer.classList.remove('hide');
|
||||
this.elements.incidenceModifiersButton.firstElementChild.classList.remove('disabled');
|
||||
this.elements.or.classList.remove('disabled');
|
||||
this.elements.and.classList.remove('disabled');
|
||||
|
||||
// Resets materialize select dropdown
|
||||
let selectInstance = M.FormSelect.getInstance(this.elements.germanPos);
|
||||
@ -656,14 +676,27 @@ class ConcordanceQueryBuilder {
|
||||
simplePosBuilder() {
|
||||
this.hideEverything();
|
||||
this.elements.simplePosBuilder.classList.remove('hide');
|
||||
// this.elements.incidenceModifiersButton.classList.remove('hide');
|
||||
this.elements.incidenceModifiersButton.classList.remove('hide');
|
||||
this.elements.conditionContainer.classList.remove('hide');
|
||||
this.elements.simplePos.selectedIndex = 0;
|
||||
this.elements.incidenceModifiersButton.firstElementChild.classList.remove('disabled');
|
||||
this.elements.or.classList.remove('disabled');
|
||||
this.elements.and.classList.remove('disabled');
|
||||
|
||||
// Resets materialize select dropdown
|
||||
let selectInstance = M.FormSelect.getInstance(this.elements.simplePos);
|
||||
selectInstance.input.value = 'simple_pos tagset';
|
||||
this.elements.simplePos.value = 'default';
|
||||
M.FormSelect.init(
|
||||
selectInstance,
|
||||
{
|
||||
dropdownOptions: {
|
||||
direction: 'bottom',
|
||||
coverTrigger: false
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
emptyTokenHandler() {
|
||||
@ -671,6 +704,8 @@ class ConcordanceQueryBuilder {
|
||||
this.elements.tokenQueryFilled = true;
|
||||
this.hideEverything();
|
||||
this.elements.incidenceModifiersButton.classList.remove('hide');
|
||||
this.elements.incidenceModifiersButton.firstElementChild.classList.remove('disabled');
|
||||
|
||||
}
|
||||
//#endregion Dropdown Select Handler
|
||||
|
||||
@ -694,6 +729,7 @@ class ConcordanceQueryBuilder {
|
||||
} else if (elem === this.elements.wildcardChar) {
|
||||
input.value += '.';
|
||||
}
|
||||
this.inputFieldHandler();
|
||||
}
|
||||
|
||||
nSubmitHandler() {
|
||||
@ -807,8 +843,7 @@ class ConcordanceQueryBuilder {
|
||||
} else {
|
||||
input = this.elements.lemmaInput;
|
||||
}
|
||||
|
||||
input.value += ' ' + elem.dataset.token;
|
||||
input.value += elem.dataset.token;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -91,8 +91,7 @@ class AdminUserList extends ResourceList {
|
||||
let listAction = listActionElement === null ? 'view' : listActionElement.dataset.listAction;
|
||||
switch (listAction) {
|
||||
case 'delete': {
|
||||
console.log('delete', itemId);
|
||||
Utils.deleteUserRequest(itemId);
|
||||
Requests.users.entity.delete(itemId);
|
||||
if (itemId === currentUserId) {window.location.href = '/';}
|
||||
break;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ class CorpusTextInfoList extends ResourceList {
|
||||
}
|
||||
|
||||
static defaultOptions = {
|
||||
page: 4
|
||||
page: 5
|
||||
};
|
||||
|
||||
constructor(listContainerElement, options = {}) {
|
||||
@ -67,12 +67,12 @@ class CorpusTextInfoList extends ResourceList {
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Text<span class="sort right material-icons" data-sort="title" style="cursor:pointer; color:#aa9cc9">arrow_drop_down</span></th>
|
||||
<th>Number of tokens<span class="sort right material-icons" data-sort="num_tokens" style="cursor:pointer">arrow_drop_down</span></th>
|
||||
<th>Number of sentences<span class="sort right material-icons" data-sort="num_sentences" style="cursor:pointer">arrow_drop_down</span></th>
|
||||
<th>Number of unique words<span class="sort right material-icons" data-sort="num_unique_words" style="cursor:pointer">arrow_drop_down</span></th>
|
||||
<th>Number of unique lemmas<span class="sort right material-icons" data-sort="num_unique_lemmas" style="cursor:pointer">arrow_drop_down</span></th>
|
||||
<th>Number of unique pos<span class="sort right material-icons" data-sort="num_unique_pos" style="cursor:pointer">arrow_drop_down</span></th>
|
||||
<th>Number of unique simple pos<span class="sort right material-icons" data-sort="num_unique_simple_pos" style="cursor:pointer">arrow_drop_down</span></th>
|
||||
<th>Tokens<span class="sort right material-icons" data-sort="num_tokens" style="cursor:pointer">arrow_drop_down</span></th>
|
||||
<th>Sentences<span class="sort right material-icons" data-sort="num_sentences" style="cursor:pointer">arrow_drop_down</span></th>
|
||||
<th>Unique words<span class="sort right material-icons" data-sort="num_unique_words" style="cursor:pointer">arrow_drop_down</span></th>
|
||||
<th>Unique lemmas<span class="sort right material-icons" data-sort="num_unique_lemmas" style="cursor:pointer">arrow_drop_down</span></th>
|
||||
<th>Unique pos<span class="sort right material-icons" data-sort="num_unique_pos" style="cursor:pointer">arrow_drop_down</span></th>
|
||||
<th>Unique simple pos<span class="sort right material-icons" data-sort="num_unique_simple_pos" style="cursor:pointer">arrow_drop_down</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="list"></tbody>
|
||||
|
141
app/static/js/ResourceLists/CorpusTokenList.js
Normal file
141
app/static/js/ResourceLists/CorpusTokenList.js
Normal file
@ -0,0 +1,141 @@
|
||||
class CorpusTokenList extends ResourceList {
|
||||
static autoInit() {
|
||||
for (let corpusTokenListElement of document.querySelectorAll('.corpus-token-list:not(.no-autoinit)')) {
|
||||
new CorpusTokenList(corpusTokenListElement);
|
||||
}
|
||||
}
|
||||
|
||||
static defaultOptions = {
|
||||
page: 7
|
||||
};
|
||||
|
||||
constructor(listContainerElement, options = {}) {
|
||||
let _options = Utils.mergeObjectsDeep(
|
||||
CorpusTokenList.defaultOptions,
|
||||
options
|
||||
);
|
||||
super(listContainerElement, _options);
|
||||
this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
|
||||
this.selectedItemTerms = new Set();
|
||||
this.listjs.on('sortComplete', () => {
|
||||
let listItems = Array.from(this.listjs.items).filter(item => item.elm);
|
||||
for (let item of listItems) {
|
||||
let termElement = item.elm.querySelector('.term');
|
||||
let mostFrequent = item.elm.dataset.mostfrequent === 'true';
|
||||
if (mostFrequent) {
|
||||
this.selectedItemTerms.add(termElement.textContent);
|
||||
}
|
||||
}
|
||||
corpusAnalysisApp.extensions['Static Visualization (beta)'].renderFrequenciesGraphic(this.selectedItemTerms);
|
||||
});
|
||||
|
||||
let tokenListResetButtonElement = this.listContainerElement.querySelector('#token-list-reset-button');
|
||||
tokenListResetButtonElement.addEventListener('click', () => {
|
||||
this.selectedItemTerms.clear();
|
||||
let listItems = Array.from(this.listjs.items).filter(item => item.elm);
|
||||
for (let item of listItems) {
|
||||
let termElement = item.elm.querySelector('.term');
|
||||
let mostFrequent = item.elm.dataset.mostfrequent === 'true';
|
||||
if (mostFrequent) {
|
||||
item.elm.querySelector('.select-checkbox').checked = true;
|
||||
this.selectedItemTerms.add(termElement.textContent);
|
||||
} else {
|
||||
item.elm.querySelector('.select-checkbox').checked = false;
|
||||
}
|
||||
}
|
||||
corpusAnalysisApp.extensions['Static Visualization (beta)'].renderFrequenciesGraphic(this.selectedItemTerms);
|
||||
});
|
||||
}
|
||||
|
||||
get item() {
|
||||
return (values) => {
|
||||
return `
|
||||
<tr class="list-item clickable hoverable">
|
||||
<td>
|
||||
<label class="list-action-trigger" data-list-action="select">
|
||||
<input class="select-checkbox" type="checkbox" ${values.mostFrequent ? 'checked="checked"' : ''}>
|
||||
<span class="disable-on-click"></span>
|
||||
</label>
|
||||
</td>
|
||||
<td><span class="term"></span></td>
|
||||
<td><span class="count"></span></td>
|
||||
<td><span class="frequency"></span></td>
|
||||
</tr>
|
||||
`.trim();
|
||||
}
|
||||
}
|
||||
|
||||
get valueNames() {
|
||||
return [
|
||||
'term',
|
||||
'count',
|
||||
{data: ['mostFrequent']},
|
||||
'frequency'
|
||||
];
|
||||
}
|
||||
|
||||
initListContainerElement() {
|
||||
if (!this.listContainerElement.hasAttribute('id')) {
|
||||
this.listContainerElement.id = Utils.generateElementId('corpus-token-list-');
|
||||
}
|
||||
let listSearchElementId = Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||
this.listContainerElement.innerHTML = `
|
||||
<div class="input-field">
|
||||
<i class="material-icons prefix">search</i>
|
||||
<input id="${listSearchElementId}" class="search" type="text"></input>
|
||||
<label for="${listSearchElementId}">Search token</label>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:15%;">
|
||||
<span class="material-icons" style="cursor:pointer" id="token-list-reset-button">refresh</span>
|
||||
</th>
|
||||
<th>Term</th>
|
||||
<th>Count</th>
|
||||
<th>Frequency</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="list"></tbody>
|
||||
</table>
|
||||
<ul class="pagination"></ul>
|
||||
`.trim();
|
||||
}
|
||||
|
||||
mapResourceToValue(corpusTokenData) {
|
||||
return {
|
||||
term: corpusTokenData.term,
|
||||
count: corpusTokenData.count,
|
||||
mostFrequent: corpusTokenData.mostFrequent,
|
||||
frequency: '-'
|
||||
};
|
||||
}
|
||||
|
||||
sort() {
|
||||
this.listjs.sort('count', {order: 'desc'});
|
||||
}
|
||||
|
||||
onClick(event) {
|
||||
if (event.target.closest('.disable-on-click') !== null) {return;}
|
||||
let listItemElement = event.target.closest('.list-item');
|
||||
if (listItemElement === null) {return;}
|
||||
let item = listItemElement.querySelector('.term').textContent;
|
||||
let listActionElement = event.target.closest('.list-action-trigger[data-list-action]');
|
||||
let listAction = listActionElement === null ? '' : listActionElement.dataset.listAction;
|
||||
switch (listAction) {
|
||||
case 'select': {
|
||||
if (event.target.checked) {
|
||||
this.selectedItemTerms.add(item);
|
||||
} else {
|
||||
this.selectedItemTerms.delete(item);
|
||||
}
|
||||
corpusAnalysisApp.extensions['Static Visualization (beta)'].renderFrequenciesGraphic(this.selectedItemTerms);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -16,6 +16,7 @@ class ResourceList {
|
||||
AdminUserList.autoInit();
|
||||
CorpusFollowerList.autoInit();
|
||||
CorpusTextInfoList.autoInit();
|
||||
CorpusTokenList.autoInit();
|
||||
}
|
||||
|
||||
static defaultOptions = {
|
||||
|
@ -30,7 +30,11 @@ cqi.api.APIClient = class APIClient {
|
||||
} else if (response.code === 500) {
|
||||
throw new Error(`[${response.code}] ${response.msg}`);
|
||||
} else if (response.code === 502) {
|
||||
if (response.payload.code in cqi.errors.lookup) {
|
||||
throw new cqi.errors.lookup[response.payload.code]();
|
||||
} else {
|
||||
throw new cqi.errors.CQiError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,8 @@
|
||||
'js/ResourceLists/AdminUserList.js',
|
||||
'js/ResourceLists/CorpusFollowerList.js',
|
||||
'js/ResourceLists/CorpusTextInfoList.js',
|
||||
'js/ResourceLists/DetailledPublicCorpusList.js'
|
||||
'js/ResourceLists/DetailledPublicCorpusList.js',
|
||||
'js/ResourceLists/CorpusTokenList.js'
|
||||
%}
|
||||
<script src="{{ ASSET_URL }}"></script>
|
||||
{%- endassets %}
|
||||
|
@ -154,6 +154,410 @@ Query your corpus with the CQP query language utilizing a KWIC view.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal" id="concordance-query-builder">
|
||||
<div class="modal-content">
|
||||
<div>
|
||||
<nav>
|
||||
<div class="nav-wrapper" id="query-builder-nav">
|
||||
<a href="#!" class="brand-logo"><i class="material-icons">build</i>Query Builder (beta)</a>
|
||||
<i class="material-icons close right" id="close-query-builder">close</i>
|
||||
<a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal">
|
||||
<i class="material-icons right tooltipped" id="query-builder-tutorial-info-icon" data-position="bottom" data-tooltip="Click here if you are unsure how to use the Query Builder <br>and want to find out what other options it offers.">help</i>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<p></p>
|
||||
|
||||
<div id="query-container" class="hide">
|
||||
|
||||
<div class="row">
|
||||
<h6 class="col s2">Your Query:
|
||||
<a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal">
|
||||
<i class="material-icons left" id="general-options-query-builder-tutorial-info-icon">help_outline</i></a>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col s10" id="your-query"></div>
|
||||
<a class="btn-small waves-effect waves-teal col s1" id="insert-query-button">
|
||||
<i class="material-icons">send</i>
|
||||
</a>
|
||||
</div>
|
||||
<p><i> Preview:</i></p>
|
||||
<p id="query-preview"></p>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
|
||||
<h6>Use the following options to build your query. If you need help, click on the question mark in the upper right corner!</h6>
|
||||
<p></p>
|
||||
<a class="btn-large waves-effect waves-light tooltipped" id="positional-attr-button" data-position="bottom" data-tooltip="Search for any token, for example a word, a lemma or a part-of-speech tag">Add new token to your query</a>
|
||||
<a class="btn-large waves-effect waves-light tooltipped" id="structural-attr-button" data-position="bottom" data-tooltip="Structure your query with structural attributes, for example sentences, entities or annotate the text">Add structural attributes to your query</a>
|
||||
|
||||
<div id="structural-attr" class="hide">
|
||||
<p></p>
|
||||
<h6>Which structural attribute do you want to add to your query?<a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal"><i class="material-icons left" id="add-structural-attribute-tutorial-info-icon">help_outline</i></a></h6>
|
||||
<p></p>
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<a class="btn-small waves-effect waves-light" id="sentence">sentence</a>
|
||||
<a class="btn-small waves-effect waves-light" id="entity">entity</a>
|
||||
<a class="btn-small waves-effect waves-light" id="text-annotation">Meta Data</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="entity-builder" class="hide">
|
||||
<p></p>
|
||||
<br>
|
||||
<div class="row">
|
||||
<a class="btn waves-effect waves-light col s4" id="empty-entity">Add Entity of any type</a>
|
||||
<p class="col s1 l1"></p>
|
||||
<div class= "input-field col s3">
|
||||
<select name="englishenttype" id="english-ent-type">
|
||||
<option value="" disabled selected>English ent_type</option>
|
||||
<option value="CARDINAL">CARDINAL</option>
|
||||
<option value="DATE">DATE</option>
|
||||
<option value="EVENT">EVENT</option>
|
||||
<option value="FAC">FAC</option>
|
||||
<option value="GPE">GPE</option>
|
||||
<option value="LANGUAGE">LANGUAGE</option>
|
||||
<option value="LAW">LAW</option>
|
||||
<option value="LOC">LOC</option>
|
||||
<option value="MONEY">MONEY</option>
|
||||
<option value="NORP">NORP</option>
|
||||
<option value="ORDINAL">ORDINAL</option>
|
||||
<option value="ORG">ORG</option>
|
||||
<option value="PERCENT">PERCENT</option>
|
||||
<option value="PERSON">PERSON</option>
|
||||
<option value="PRODUCT">PRODUCT</option>
|
||||
<option value="QUANTITY">QUANTITY</option>
|
||||
<option value="TIME">TIME</option>
|
||||
<option value="WORK_OF_ART">WORK_OF_ART</option>
|
||||
</select>
|
||||
<label>Entity Type</label>
|
||||
</div>
|
||||
<div class= "input-field col s3">
|
||||
<select name="germanenttype" id="german-ent-type">
|
||||
<option value="" disabled selected>German ent_type</option>
|
||||
<option value="LOC">LOC</option>
|
||||
<option value="MISC">MISC</option>
|
||||
<option value="ORG">ORG</option>
|
||||
<option value="PER">PER</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="text-annotation-builder" class="hide">
|
||||
<p></p>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class= "input-field col s4 l3">
|
||||
<select name="text-annotation-options" id="text-annotation-options">
|
||||
<option class="btn-small waves-effect waves-light" value="address">address</option>
|
||||
<option class="btn-small waves-effect waves-light" value="author">author</option>
|
||||
<option class="btn-small waves-effect waves-light" value="booktitle">booktitle</option>
|
||||
<option class="btn-small waves-effect waves-light" value="chapter">chapter</option>
|
||||
<option class="btn-small waves-effect waves-light" value="editor">editor</option>
|
||||
<option class="btn-small waves-effect waves-light" value="institution">institution</option>
|
||||
<option class="btn-small waves-effect waves-light" value="journal">journal</option>
|
||||
<option class="btn-small waves-effect waves-light" value="pages">pages</option>
|
||||
<option class="btn-small waves-effect waves-light" value="publisher">publisher</option>
|
||||
<option class="btn-small waves-effect waves-light" value="publishing_year">publishing year</option>
|
||||
<option class="btn-small waves-effect waves-light" value="school">school</option>
|
||||
<option class="btn-small waves-effect waves-light" value="title">title</option>
|
||||
</select>
|
||||
<label>Meta data</label>
|
||||
</div>
|
||||
<div class= "input-field col s7 l5">
|
||||
<i class="material-icons prefix">mode_edit</i>
|
||||
<input placeholder="Type in your text annotation" type="text" id="text-annotation-input">
|
||||
</div>
|
||||
<div class="col s1 l1 center-align">
|
||||
<p class="btn-floating waves-effect waves-light" id="text-annotation-submit">
|
||||
<i class="material-icons right">send</i>
|
||||
</p>
|
||||
</div>
|
||||
<div class="hide" id="no-value-metadata-message"><i>No value entered!</i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="positional-attr" class="hide">
|
||||
<p></p>
|
||||
<div class="row" id="token-kind-selector">
|
||||
<div class="col s5">
|
||||
<h6>Which kind of token are you looking for? <a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal"><i class="material-icons left" id="token-tutorial-info-icon">help_outline</i></a></h6>
|
||||
</div>
|
||||
<div class="input-field col s3">
|
||||
<select id="token-attr">
|
||||
<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-button">simple_pos</option>
|
||||
<option value="empty-token">empty token</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p></p>
|
||||
<div id="token-builder-content">
|
||||
<div class="row" >
|
||||
<div id="token-query"></div>
|
||||
|
||||
<div id="word-builder">
|
||||
<div class= "input-field col s3 l4">
|
||||
<i class="material-icons prefix">mode_edit</i>
|
||||
<input placeholder="Type in your word" type="text" id="word-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="lemma-builder" class="hide" >
|
||||
<div class= "input-field col s3 l4">
|
||||
<i class="material-icons prefix">mode_edit</i>
|
||||
<input placeholder="Type in your lemma" type="text" id="lemma-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="english-pos-builder" class="hide">
|
||||
<div class="col s6 m4 l4">
|
||||
<div class="row">
|
||||
<div class= "input-field col s12">
|
||||
<select name="englishpos" id="english-pos">
|
||||
<option value="default" disabled selected>English pos tagset</option>
|
||||
<option value="ADD">email</option>
|
||||
<option value="AFX">affix</option>
|
||||
<option value="CC">conjunction, coordinating</option>
|
||||
<option value="CD">cardinal number</option>
|
||||
<option value="DT">determiner</option>
|
||||
<option value="EX">existential there</option>
|
||||
<option value="FW">foreign word</option>
|
||||
<option value="HYPH">punctuation mark, hyphen</option>
|
||||
<option value="IN">conjunction, subordinating or preposition</option>
|
||||
<option value="JJ">adjective</option>
|
||||
<option value="JJR">adjective, comparative</option>
|
||||
<option value="JJS">adjective, superlative</option>
|
||||
<option value="LS">list item marker</option>
|
||||
<option value="MD">verb, modal auxillary</option>
|
||||
<option value="NFP">superfluous punctuation</option>
|
||||
<option value="NN">noun, singular or mass</option>
|
||||
<option value="NNP">noun, proper singular</option>
|
||||
<option value="NNPS">noun, proper plural</option>
|
||||
<option value="NNS">noun, plural</option>
|
||||
<option value="PDT">predeterminer</option>
|
||||
<option value="POS">possessive ending</option>
|
||||
<option value="PRP">pronoun, personal</option>
|
||||
<option value="PRP$">pronoun, possessive</option>
|
||||
<option value="RBR">adverb, comparative</option>
|
||||
<option value="RBS">adverb, superlative</option>
|
||||
<option value="RP">adverb, particle</option>
|
||||
<option value="SYM">symbol</option>
|
||||
<option value="TO">infinitival to</option>
|
||||
<option value="UH">interjection</option>
|
||||
<option value="VB">verb, base form</option>
|
||||
<option value="VBD">verb, past tense</option>
|
||||
<option value="VBG">verb, gerund or present participle</option>
|
||||
<option value="VBN">verb, past participle</option>
|
||||
<option value="VBP">verb, non-3rd person singular present</option>
|
||||
<option value="VBZ">verb, 3rd person singular present</option>
|
||||
<option value="WDT">wh-determiner</option>
|
||||
<option value="WP">wh-pronoun, personal</option>
|
||||
<option value="WP$">wh-pronoun, possessive</option>
|
||||
<option value="WRB">wh-adverb</option>
|
||||
<option value="XX">unknown</option>
|
||||
<option value="``">opening quotation mark</option>
|
||||
<option value="$">symbol, currency</option>
|
||||
<option value='""'>closing quotation mark</option>
|
||||
<option value="-LRB-">left round bracket</option>
|
||||
<option value="-RRB-">right round bracket</option>
|
||||
<option value=".">punctuation mark, sentence closer</option>
|
||||
<option value=":">punctuation mark, colon or ellipsis</option>
|
||||
</select>
|
||||
<label>Part-of-speech tags</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="german-pos-builder" class="hide">
|
||||
<div class="col s6 m4 l4">
|
||||
<div class="row">
|
||||
<div class= "input-field col s12">
|
||||
<select name="germanpos" id="german-pos">
|
||||
<option value="default" disabled selected>German pos tagset</option>
|
||||
<option value="ADJA">adjective, attributive</option>
|
||||
<option value="ADJD">adjective, adverbial or predicative</option>
|
||||
<option value="ADV">adverb</option>
|
||||
<option value="APPO">postposition</option>
|
||||
<option value="APPR">preposition; circumposition left</option>
|
||||
<option value="APPRART">preposition with article</option>
|
||||
<option value="APZR">circumposition right</option>
|
||||
<option value="ART">definite or indefinite article</option>
|
||||
<option value="CARD">cardinal number</option>
|
||||
<option value="FM">foreign word</option>
|
||||
<option value="ITJ">interjection</option>
|
||||
<option value="KOKOM">comparative conjunction</option>
|
||||
<option value="KON">coordinating conjunction</option>
|
||||
<option value="KOUI">subordinating conjunction with "zu" and infinitive</option>
|
||||
<option value="KOUS">subordinating conjunction with sentence</option>
|
||||
<option value="NE">proper noun</option>
|
||||
<option value="NN">noun, singular or mass</option>
|
||||
<option value="NNE">proper noun</option>
|
||||
<option value="PDAT">attributive demonstrative pronoun</option>
|
||||
<option value="PDS">substituting demonstrative pronoun</option>
|
||||
<option value="PIAT">attributive indefinite pronoun without determiner</option>
|
||||
<option value="PIS">substituting indefinite pronoun</option>
|
||||
<option value="PPER">non-reflexive personal pronoun</option>
|
||||
<option value="PPOSAT">attributive possessive pronoun</option>
|
||||
<option value="PPOSS">substituting possessive pronoun</option>
|
||||
<option value="PRELAT">attributive relative pronoun</option>
|
||||
<option value="PRELS">substituting relative pronoun</option>
|
||||
<option value="PRF">reflexive personal pronoun</option>
|
||||
<option value="PROAV">pronominal adverb</option>
|
||||
<option value="PTKA">particle with adjective or adverb</option>
|
||||
<option value="PTKANT">answer particle</option>
|
||||
<option value="PTKNEG">negative particle</option>
|
||||
<option value="PTKVZ">separable verbal particle</option>
|
||||
<option value="PTKZU">"zu" before infinitive</option>
|
||||
<option value="PWAT">attributive interrogative pronoun</option>
|
||||
<option value="PWAV">adverbial interrogative or relative pronoun</option>
|
||||
<option value="PWS">substituting interrogative pronoun</option>
|
||||
<option value="TRUNC">word remnant</option>
|
||||
<option value="VAFIN">finite verb, auxiliary</option>
|
||||
<option value="VAIMP">imperative, auxiliary</option>
|
||||
<option value="VAINF">infinitive, auxiliary</option>
|
||||
<option value="VAPP">perfect participle, auxiliary</option>
|
||||
<option value="VMFIN">finite verb, modal</option>
|
||||
<option value="VMINF">infinitive, modal</option>
|
||||
<option value="VMPP">perfect participle, modal</option>
|
||||
<option value="VVFIN">finite verb, full</option>
|
||||
<option value="VVIMP">imperative, full</option>
|
||||
<option value="VVINF">infinitive, full</option>
|
||||
<option value="VVIZU">infinitive with "zu", full</option>
|
||||
<option value="VVPP">perfect participle, full</option>
|
||||
<option value="XY">non-word containing non-letter</option>
|
||||
<option value="$(">other sentence-internal punctuation mark</option>
|
||||
<option value="$,">comma</option>
|
||||
<option value="$.">sentence-final punctuation mark</option>
|
||||
</select>
|
||||
<label>Part-of-speech tags</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="simplepos-builder" class="hide">
|
||||
<div class="col s6 m4 l4">
|
||||
<div class="row">
|
||||
<div class= "input-field col s12">
|
||||
<select name="simplepos" id="simple-pos">
|
||||
<option value="default" disabled selected>simple_pos tagset</option>
|
||||
<option value="ADJ">adjective</option>
|
||||
<option value="ADP">adposition</option>
|
||||
<option value="ADV">adverb</option>
|
||||
<option value="AUX">auxiliary verb</option>
|
||||
<option value="CONJ">coordinating conjunction</option>
|
||||
<option value="DET">determiner</option>
|
||||
<option value="INTJ">interjection</option>
|
||||
<option value="NOUN">noun</option>
|
||||
<option value="NUM">numeral</option>
|
||||
<option value="PART">particle</option>
|
||||
<option value="PRON">pronoun</option>
|
||||
<option value="PROPN">proper noun</option>
|
||||
<option value="PUNCT">punctuation</option>
|
||||
<option value="SCONJ">subordinating conjunction</option>
|
||||
<option value="SYM">symbol</option>
|
||||
<option value="VERB">verb</option>
|
||||
<option value="X">other</option>
|
||||
</select>
|
||||
<label>Simple part-of-speech tags</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col s1 l1 center-align">
|
||||
<p class="btn-floating waves-effect waves-light" id="token-submit">
|
||||
<i class="material-icons right">send</i>
|
||||
</p>
|
||||
</div>
|
||||
<div class="hide" id="no-value-message"><i>No value entered!</i></div>
|
||||
</div>
|
||||
<div id="token-edit-options">
|
||||
<div class="row">
|
||||
<h6>Options to edit your token: <a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal"><i class="material-icons left" id="edit-options-tutorial-info-icon">help_outline</i></a></h6>
|
||||
</div>
|
||||
<p></p>
|
||||
<div class="row">
|
||||
<div id="input-options" class="col s5 m5 l5 xl4">
|
||||
<a id="wildcard-char" class="btn-small waves-effect waves-light tooltipped" data-position="top" data-tooltip="Look for a variable character (also called wildcard character)">Wildcard character</a>
|
||||
<a id="option-group" class="btn-small waves-effect waves-light tooltipped" data-position="top" data-tooltip="Find character sequences from a list of options">Option Group</a>
|
||||
</div>
|
||||
<div class="col s3 m3 l3 xl3" id="incidence-modifiers-button">
|
||||
<a class="dropdown-trigger btn-small waves-effect waves-light" href="#" data-target="incidence-modifiers" data-position="top" data-tooltip="Incidence Modifiers are special characters or patterns, <br>which determine how often a character represented previously should occur.">incidence modifiers</a>
|
||||
</div>
|
||||
|
||||
<ul id="incidence-modifiers" class="dropdown-content">
|
||||
<li><a id="one-or-more" data-token="+" class="tooltipped" data-position ="top" data-tooltip="...occurrences of the character/token before">one or more (+)</a></li>
|
||||
<li><a id="zero-or-more" data-token="*" class="tooltipped" data-position ="top" data-tooltip="...occurrences of the character/token before">zero or more (*)</a></li>
|
||||
<li><a id="zero-or-one" data-token="?" class="tooltipped" data-position ="top" data-tooltip="...occurrences of the character/token before">zero or one (?)</a></li>
|
||||
<li><a id="exactly-n" class="modal-trigger tooltipped" href="#exactlyN" data-token="{n}" class="" data-position ="top" data-tooltip="...occurrences of the character/token before">exactly n ({n})</a></li>
|
||||
<li><a id="between-n-m" class="modal-trigger tooltipped" href="#betweenNM" data-token="{n,m}" class="" data-position ="top" data-tooltip="...occurrences of the character/token before">between n and m ({n,m})</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="ignore-case-checkbox" class="col s2 m2 l2 xl2">
|
||||
<p id="ignore-case">
|
||||
<label>
|
||||
<input type="checkbox" class="filled-in" />
|
||||
<span>Ignore Case</span>
|
||||
</label>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col s2 m2 l2 xl2" id="condition-container">
|
||||
<a class="btn-small tooltipped waves-effect waves-light" id="or" data-position="bottom" data-tooltip="You can add another condition to your token. <br>At least one must be fulfilled">or</a>
|
||||
<a class="btn-small tooltipped waves-effect waves-light" id="and" data-position="bottom" data-tooltip="You can add another condition to your token. <br>Both must be fulfilled">and</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="exactlyN" class="modal">
|
||||
<div class="row modal-content">
|
||||
<div class="input-field col s10">
|
||||
<i class="material-icons prefix">mode_edit</i>
|
||||
<input placeholder="type in a number for 'n'" type="text" id="n-input">
|
||||
</div>
|
||||
<div class="col s2">
|
||||
<p class="btn-floating waves-effect waves-light" id="n-submit">
|
||||
<i class="material-icons right">send</i>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="betweenNM" class="modal">
|
||||
<div class="row modal-content">
|
||||
<div class= "input-field col s5">
|
||||
<i class="material-icons prefix">mode_edit</i>
|
||||
<input placeholder="number for 'n'" type="text" id="n-m-input">
|
||||
</div>
|
||||
<div class= "input-field col s5">
|
||||
<i class="material-icons prefix">mode_edit</i>
|
||||
<input placeholder="number for 'm'" type="text" id="m-input">
|
||||
</div>
|
||||
<div class="col s2">
|
||||
<p class="btn-floating waves-effect waves-light" id="n-m-submit">
|
||||
<i class="material-icons right">send</i>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endset %}
|
||||
|
||||
{% set scripts %}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% set name = 'Static Visualization' %}
|
||||
{% set name = 'Static Visualization (beta)' %}
|
||||
|
||||
{% set description = '' %}
|
||||
|
||||
@ -63,7 +63,18 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<div class="col s4">
|
||||
<div class="card hoverable">
|
||||
<div class="card-content">
|
||||
<span class="card-title" id="text-proportions-title-element">Proportions</span>
|
||||
<p>of texts within the corpus</p>
|
||||
<div id="text-proportions-graphic"></div>
|
||||
<a class="btn disabled text-proportions-graph-mode-button" data-graph-type="pie"><i class="material-icons">incomplete_circle</i></a>
|
||||
<a class="btn text-proportions-graph-mode-button" data-graph-type="bar"><i class="material-icons">sort</i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col s8">
|
||||
<div class="card hoverable">
|
||||
<div class="card-content">
|
||||
<span class="card-title">Text Information Overview</span>
|
||||
@ -74,46 +85,39 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col s4">
|
||||
<div class="card hoverable">
|
||||
<div class="card-content">
|
||||
<span class="card-title">Proportions</span>
|
||||
<p>of texts within the corpus</p>
|
||||
<div id="text-proportions-graphic" style="width:100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col s8">
|
||||
<div class="col s12">
|
||||
<div class="card hoverable">
|
||||
<div class="card-content">
|
||||
<span class="card-title">Frequencies</span>
|
||||
<div class="row">
|
||||
<div class="col s4">
|
||||
<div class="corpus-token-list no-autoinit" style="transform: scale(0.91);"></div>
|
||||
<a class="dropdown-trigger btn" data-target="frequencies-token-category-dropdown">Word<i class="material-icons right">arrow_drop_down</i></a>
|
||||
<a class="btn-flat modal-trigger no-autoinit" id="frequencies-stopwords-setting-modal-button" href="#frequencies-stopwords-setting-modal">
|
||||
<i class="material-icons grey-text text-darken-2">settings</i>
|
||||
</a>
|
||||
<ul id="frequencies-token-category-dropdown" class="dropdown-content">
|
||||
<li><a data-token-category="word">Word</a></li>
|
||||
<li><a data-token-category="lemma">Lemma</a></li>
|
||||
<li><a data-token-category="pos">Pos</a></li>
|
||||
<li><a data-token-category="simple_pos">Simple_pos</a></li>
|
||||
</ul>
|
||||
<p>within the texts of the 5 most frequent words in the corpus</p>
|
||||
</div>
|
||||
<div class="col s8">
|
||||
<div id="frequencies-graphic"></div>
|
||||
<a class="dropdown-trigger btn" data-target="frequencies-token-category-dropdown">Word<i class="material-icons right">arrow_drop_down</i></a>
|
||||
<a class="btn disabled frequencies-graph-mode-button" data-graph-type="bar"><i class="material-icons">equalizer</i></a>
|
||||
<div>
|
||||
<a class="btn disabled frequencies-graph-mode-button" data-graph-type="bar"><i class="material-icons">stacked_bar_chart</i></a>
|
||||
<a class="btn frequencies-graph-mode-button" data-graph-type="scatter"><i class="material-icons">show_chart</i></a>
|
||||
<a class="btn frequencies-graph-mode-button" data-graph-type="markers"><i class="material-icons">bubble_chart</i></a>
|
||||
<a class="btn-flat modal-trigger no-autoinit" id="frequencies-stopwords-setting-modal-button" href="#frequencies-stopwords-setting-modal"><i class="material-icons grey-text text-darken-2">settings</i></a>
|
||||
{# <a class="btn frequencies-graph-mode-button" data-graph-type="markers"><i class="material-icons">bubble_chart</i></a> #}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<div class="card hoverable">
|
||||
<div class="card-content">
|
||||
<span class="card-title">Text Bounds</span>
|
||||
<div id="bounds-graphic"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endset %}
|
||||
|
||||
@ -126,8 +130,7 @@
|
||||
like "the" or "and," that carry little meaning and are often removed in text analysis
|
||||
to improve efficiency and accuracy.</p>
|
||||
<div id="user-stopword-list-container"></div>
|
||||
<div class="chips col s8 no-autoinit input-field" id="stopword-input-field">
|
||||
</div>
|
||||
<div class="chips col s8 no-autoinit input-field" id="stopword-input-field"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p>Below you can find a list of all stopwords that are always filtered out.
|
||||
@ -155,3 +158,4 @@
|
||||
const corpusAnalysisStaticVisualization = new CorpusAnalysisStaticVisualization(corpusAnalysisApp);
|
||||
</script>
|
||||
{% endset %}
|
||||
|
@ -12,7 +12,7 @@
|
||||
{% block page_content %}
|
||||
<ul class="row tabs no-autoinit" id="corpus-analysis-app-extension-tabs">
|
||||
<li class="tab col s3"><a class="active" href="#corpus-analysis-app-home-container"><i class="nopaque-icons service-icons left" data-service="corpus-analysis"></i>Corpus analysis</a></li>
|
||||
{% for extension in extensions if extension.name != 'Static Visualization' %}
|
||||
{% for extension in extensions if extension.name != 'Static Visualization (beta)' %}
|
||||
<li class="tab col s3"><a href="#{{ extension.id_prefix }}-container">{{ extension.tab_content }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
@ -21,7 +21,7 @@
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
<div class="row" id="corpus-analysis-app-extension-cards">
|
||||
{% for extension in extensions if extension.name != 'Static Visualization' %}
|
||||
{% for extension in extensions if extension.name != 'Static Visualization (beta)' %}
|
||||
<div class="col s3">
|
||||
<div class="card extension-selector hoverable" data-target="{{ extension.id_prefix }}-container">
|
||||
<div class="card-content">
|
||||
@ -32,10 +32,12 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{{ static_visualization_extension.container_content }}
|
||||
</div>
|
||||
|
||||
|
||||
{% for extension in extensions %}
|
||||
{% for extension in extensions if extension.name != 'Static Visualization (beta)' %}
|
||||
<div id="{{ extension.id_prefix }}-container">
|
||||
{{ extension.container_content }}
|
||||
</div>
|
||||
@ -46,13 +48,15 @@
|
||||
{{ super() }}
|
||||
<div class="modal no-autoinit" id="corpus-analysis-app-init-modal">
|
||||
<div class="modal-content">
|
||||
<h4>Initializing session</h4>
|
||||
<h4>We are preparing your analysis session</h4>
|
||||
<p>
|
||||
Our server works as hard as it can to prepare your analysis session. Please be patient and give it some time.<br>
|
||||
If initialization takes longer than usual or an error occurs, <a onclick="window.location.reload()" href="#">reload the page</a>.
|
||||
</p>
|
||||
<div class="progress">
|
||||
<div class="indeterminate"></div>
|
||||
</div>
|
||||
<p class="status-text"></p>
|
||||
<p class="errors error-color-text hide"></p>
|
||||
</div>
|
||||
</div>
|
||||
@ -61,328 +65,6 @@
|
||||
{{ extension.modals }}
|
||||
{% endfor %}
|
||||
|
||||
<div class="modal" id="concordance-query-builder">
|
||||
<div class="modal-content">
|
||||
<div>
|
||||
<nav>
|
||||
<div class="nav-wrapper" id="query-builder-nav">
|
||||
<a href="#!" class="brand-logo"><i class="material-icons">build</i>Query Builder (beta)</a>
|
||||
<i class="material-icons close right" id="close-query-builder">close</i>
|
||||
<a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal">
|
||||
<i class="material-icons right tooltipped" id="query-builder-tutorial-info-icon" data-position="bottom" data-tooltip="Click here if you are unsure how to use the Query Builder <br>and want to find out what other options it offers.">help</i>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<p></p>
|
||||
|
||||
<div id="query-container" class="hide">
|
||||
|
||||
<div class="row">
|
||||
<h6 class="col s2">Your Query:
|
||||
<a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal">
|
||||
<i class="material-icons left" id="general-options-query-builder-tutorial-info-icon">help_outline</i></a>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col s10" id="your-query"></div>
|
||||
<a class="btn-small waves-effect waves-teal col s1" id="insert-query-button">
|
||||
<i class="material-icons">send</i>
|
||||
</a>
|
||||
</div>
|
||||
<p><i> Preview:</i></p>
|
||||
<p id="query-preview"></p>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
|
||||
<h6>Use the following options to build your query. If you need help, click on the question mark in the upper right corner!</h6>
|
||||
<p></p>
|
||||
<a class="btn-large waves-effect waves-light tooltipped" id="positional-attr-button" data-position="bottom" data-tooltip="Search for any token, for example a word, a lemma or a part-of-speech tag">Add new token to your query</a>
|
||||
<a class="btn-large waves-effect waves-light tooltipped" id="structural-attr-button" data-position="bottom" data-tooltip="Structure your query with structural attributes, for example sentences, entities or annotate the text">Add structural attributes to your query</a>
|
||||
|
||||
<div id="structural-attr" class="hide">
|
||||
<p></p>
|
||||
<h6>Which structural attribute do you want to add to your query?<a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal"><i class="material-icons left" id="add-structural-attribute-tutorial-info-icon">help_outline</i></a></h6>
|
||||
<p></p>
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<a class="btn-small waves-effect waves-light" id="sentence">sentence</a>
|
||||
<a class="btn-small waves-effect waves-light" id="entity">entity</a>
|
||||
<a class="btn-small waves-effect waves-light" id="text-annotation">Meta Data</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="entity-builder" class="hide">
|
||||
<p></p>
|
||||
<br>
|
||||
<div class="row">
|
||||
<a class="btn waves-effect waves-light col s4" id="empty-entity">Add Entity of any type</a>
|
||||
<p class="col s1 l1"></p>
|
||||
<div class= "input-field col s3">
|
||||
<select name="englishenttype" id="english-ent-type">
|
||||
<option value="" disabled selected>English ent_type</option>
|
||||
<option value="CARDINAL">CARDINAL</option>
|
||||
<option value="DATE">DATE</option>
|
||||
<option value="EVENT">EVENT</option>
|
||||
<option value="FAC">FAC</option>
|
||||
<option value="GPE">GPE</option>
|
||||
<option value="LANGUAGE">LANGUAGE</option>
|
||||
<option value="LAW">LAW</option>
|
||||
<option value="LOC">LOC</option>
|
||||
<option value="MONEY">MONEY</option>
|
||||
<option value="NORP">NORP</option>
|
||||
<option value="ORDINAL">ORDINAL</option>
|
||||
<option value="ORG">ORG</option>
|
||||
<option value="PERCENT">PERCENT</option>
|
||||
<option value="PERSON">PERSON</option>
|
||||
<option value="PRODUCT">PRODUCT</option>
|
||||
<option value="QUANTITY">QUANTITY</option>
|
||||
<option value="TIME">TIME</option>
|
||||
<option value="WORK_OF_ART">WORK_OF_ART</option>
|
||||
</select>
|
||||
<label>Entity Type</label>
|
||||
</div>
|
||||
<div class= "input-field col s3">
|
||||
<select name="germanenttype" id="german-ent-type">
|
||||
<option value="" disabled selected>German ent_type</option>
|
||||
<option value="LOC">LOC</option>
|
||||
<option value="MISC">MISC</option>
|
||||
<option value="ORG">ORG</option>
|
||||
<option value="PER">PER</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="text-annotation-builder" class="hide">
|
||||
<p></p>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class= "input-field col s4 l3">
|
||||
<select name="text-annotation-options" id="text-annotation-options">
|
||||
<option class="btn-small waves-effect waves-light" value="address">address</option>
|
||||
<option class="btn-small waves-effect waves-light" value="author">author</option>
|
||||
<option class="btn-small waves-effect waves-light" value="booktitle">booktitle</option>
|
||||
<option class="btn-small waves-effect waves-light" value="chapter">chapter</option>
|
||||
<option class="btn-small waves-effect waves-light" value="editor">editor</option>
|
||||
<option class="btn-small waves-effect waves-light" value="institution">institution</option>
|
||||
<option class="btn-small waves-effect waves-light" value="journal">journal</option>
|
||||
<option class="btn-small waves-effect waves-light" value="pages">pages</option>
|
||||
<option class="btn-small waves-effect waves-light" value="publisher">publisher</option>
|
||||
<option class="btn-small waves-effect waves-light" value="publishing_year">publishing year</option>
|
||||
<option class="btn-small waves-effect waves-light" value="school">school</option>
|
||||
<option class="btn-small waves-effect waves-light" value="title">title</option>
|
||||
</select>
|
||||
<label>Meta data</label>
|
||||
</div>
|
||||
<div class= "input-field col s7 l5">
|
||||
<i class="material-icons prefix">mode_edit</i>
|
||||
<input placeholder="Type in your text annotation" type="text" id="text-annotation-input">
|
||||
</div>
|
||||
<div class="col s1 l1 center-align">
|
||||
<p class="btn-floating waves-effect waves-light" id="text-annotation-submit">
|
||||
<i class="material-icons right">send</i>
|
||||
</p>
|
||||
</div>
|
||||
<div class="hide" id="no-value-metadata-message"><i>No value entered!</i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="positional-attr" class="hide">
|
||||
<p></p>
|
||||
<div class="row" id="token-kind-selector">
|
||||
<div class="col s5">
|
||||
<h6>Which kind of token are you looking for? <a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal"><i class="material-icons left" id="token-tutorial-info-icon">help_outline</i></a></h6>
|
||||
</div>
|
||||
<div class="input-field col s3">
|
||||
<select id="token-attr">
|
||||
<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-button">simple_pos</option>
|
||||
<option value="empty-token">empty token</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p></p>
|
||||
<div id="token-builder-content">
|
||||
<div class="row" >
|
||||
<div id="token-query"></div>
|
||||
|
||||
<div id="word-builder">
|
||||
<div class= "input-field col s3 l4">
|
||||
<i class="material-icons prefix">mode_edit</i>
|
||||
<input placeholder="Type in your word" type="text" id="word-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="lemma-builder" class="hide" >
|
||||
<div class= "input-field col s3 l4">
|
||||
<i class="material-icons prefix">mode_edit</i>
|
||||
<input placeholder="Type in your lemma" type="text" id="lemma-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="english-pos-builder" class="hide">
|
||||
<div class="col s6 m4 l4">
|
||||
<div class="row">
|
||||
<div class= "input-field col s12">
|
||||
<select name="englishpos" id="english-pos">
|
||||
<option value="default" disabled selected>English pos tagset</option>
|
||||
<option value="ADD">email</option>
|
||||
<option value="AFX">affix</option>
|
||||
<option value="CC">conjunction, coordinating</option>
|
||||
<option value="CD">cardinal number</option>
|
||||
<option value="DT">determiner</option>
|
||||
<option value="EX">existential there</option>
|
||||
<option value="FW">foreign word</option>
|
||||
<option value="HYPH">punctuation mark, hyphen</option>
|
||||
<option value="IN">conjunction, subordinating or preposition</option>
|
||||
<option value="JJ">adjective</option>
|
||||
<option value="JJR">adjective, comparative</option>
|
||||
<option value="JJS">adjective, superlative</option>
|
||||
</select>
|
||||
<label>Part-of-speech tags</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="german-pos-builder" class="hide">
|
||||
<div class="col s6 m4 l4">
|
||||
<div class="row">
|
||||
<div class= "input-field col s12">
|
||||
<select name="germanpos" id="german-pos">
|
||||
<option value="default" disabled selected>German pos tagset</option>
|
||||
<option value="ADJA">adjective, attributive</option>
|
||||
<option value="ADJD">adjective, adverbial or predicative</option>
|
||||
<option value="ADV">adverb</option>
|
||||
<option value="APPO">postposition</option>
|
||||
<option value="APPR">preposition; circumposition left</option>
|
||||
<option value="APPRART">preposition with article</option>
|
||||
<option value="APZR">circumposition right</option>
|
||||
<option value="ART">definite or indefinite article</option>
|
||||
</select>
|
||||
<label>Part-of-speech tags</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="simplepos-builder" class="hide">
|
||||
<div class="col s6 m4 l4">
|
||||
<div class="row">
|
||||
<div class= "input-field col s12">
|
||||
<select name="simplepos" id="simple-pos">
|
||||
<option value="default" disabled selected>simple_pos tagset</option>
|
||||
<option value="ADJ">adjective</option>
|
||||
<option value="ADP">adposition</option>
|
||||
<option value="ADV">adverb</option>
|
||||
<option value="AUX">auxiliary verb</option>
|
||||
<option value="CONJ">coordinating conjunction</option>
|
||||
<option value="DET">determiner</option>
|
||||
<option value="INTJ">interjection</option>
|
||||
<option value="NOUN">noun</option>
|
||||
<option value="NUM">numeral</option>
|
||||
<option value="PART">particle</option>
|
||||
<option value="PRON">pronoun</option>
|
||||
<option value="PROPN">proper noun</option>
|
||||
<option value="PUNCT">punctuation</option>
|
||||
<option value="SCONJ">subordinating conjunction</option>
|
||||
<option value="SYM">symbol</option>
|
||||
<option value="VERB">verb</option>
|
||||
<option value="X">other</option>
|
||||
</select>
|
||||
<label>Simple part-of-speech tags</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col s1 l1 center-align">
|
||||
<p class="btn-floating waves-effect waves-light" id="token-submit">
|
||||
<i class="material-icons right">send</i>
|
||||
</p>
|
||||
</div>
|
||||
<div class="hide" id="no-value-message"><i>No value entered!</i></div>
|
||||
</div>
|
||||
<div id="token-edit-options">
|
||||
<div class="row">
|
||||
<h6>Options to edit your token: <a class="modal-trigger" data-manual-modal-chapter="manual-modal-query-builder" href="#manual-modal"><i class="material-icons left" id="edit-options-tutorial-info-icon">help_outline</i></a></h6>
|
||||
</div>
|
||||
<p></p>
|
||||
<div class="row">
|
||||
<div id="input-options" class="col s5 m5 l5 xl4">
|
||||
<a id="wildcard-char" class="btn-small waves-effect waves-light tooltipped" data-position="top" data-tooltip="Look for a variable character (also called wildcard character)">Wildcard character</a>
|
||||
<a id="option-group" class="btn-small waves-effect waves-light tooltipped" data-position="top" data-tooltip="Find character sequences from a list of options">Option Group</a>
|
||||
</div>
|
||||
<div class="col s3 m3 l3 xl3" id="incidence-modifiers-button">
|
||||
<a class="dropdown-trigger btn-small waves-effect waves-light" href="#" data-target="incidence-modifiers" data-position="top" data-tooltip="Incidence Modifiers are special characters or patterns, <br>which determine how often a character represented previously should occur.">incidence modifiers</a>
|
||||
</div>
|
||||
|
||||
<ul id="incidence-modifiers" class="dropdown-content">
|
||||
<li><a id="one-or-more" data-token="+" class="tooltipped" data-position ="top" data-tooltip="...occurrences of the character/token before">one or more (+)</a></li>
|
||||
<li><a id="zero-or-more" data-token="*" class="tooltipped" data-position ="top" data-tooltip="...occurrences of the character/token before">zero or more (*)</a></li>
|
||||
<li><a id="zero-or-one" data-token="?" class="tooltipped" data-position ="top" data-tooltip="...occurrences of the character/token before">zero or one (?)</a></li>
|
||||
<li><a id="exactly-n" class="modal-trigger tooltipped" href="#exactlyN" data-token="{n}" class="" data-position ="top" data-tooltip="...occurrences of the character/token before">exactly n ({n})</a></li>
|
||||
<li><a id="between-n-m" class="modal-trigger tooltipped" href="#betweenNM" data-token="{n,m}" class="" data-position ="top" data-tooltip="...occurrences of the character/token before">between n and m ({n,m})</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="ignore-case-checkbox" class="col s2 m2 l2 xl2">
|
||||
<p id="ignore-case">
|
||||
<label>
|
||||
<input type="checkbox" class="filled-in" />
|
||||
<span>Ignore Case</span>
|
||||
</label>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col s2 m2 l2 xl2" id="condition-container">
|
||||
<a class="btn-small tooltipped waves-effect waves-light" id="or" data-position="bottom" data-tooltip="You can add another condition to your token. <br>At least one must be fulfilled">or</a>
|
||||
<a class="btn-small tooltipped waves-effect waves-light" id="and" data-position="bottom" data-tooltip="You can add another condition to your token. <br>Both must be fulfilled">and</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="exactlyN" class="modal">
|
||||
<div class="row modal-content">
|
||||
<div class="input-field col s10">
|
||||
<i class="material-icons prefix">mode_edit</i>
|
||||
<input placeholder="type in a number for 'n'" type="text" id="n-input">
|
||||
</div>
|
||||
<div class="col s2">
|
||||
<p class="btn-floating waves-effect waves-light" id="n-submit">
|
||||
<i class="material-icons right">send</i>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="betweenNM" class="modal">
|
||||
<div class="row modal-content">
|
||||
<div class= "input-field col s5">
|
||||
<i class="material-icons prefix">mode_edit</i>
|
||||
<input placeholder="number for 'n'" type="text" id="n-m-input">
|
||||
</div>
|
||||
<div class= "input-field col s5">
|
||||
<i class="material-icons prefix">mode_edit</i>
|
||||
<input placeholder="number for 'm'" type="text" id="m-input">
|
||||
</div>
|
||||
<div class="col s2">
|
||||
<p class="btn-floating waves-effect waves-light" id="n-m-submit">
|
||||
<i class="material-icons right">send</i>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock modals %}
|
||||
|
||||
{% block scripts %}
|
||||
|
@ -152,11 +152,16 @@
|
||||
<script>
|
||||
let jobDisplay = new JobDisplay(document.querySelector('#job-display'));
|
||||
let deleteJobRequestElement = document.querySelector('#delete-job-request');
|
||||
let jobLogButtonElement = document.querySelector('#job-log-button');
|
||||
let restartJobRequestElement = document.querySelector('#restart-job-request');
|
||||
deleteJobRequestElement.addEventListener('click', (event) => {
|
||||
Requests.jobs.entity.delete({{ job.hashid|tojson }});
|
||||
});
|
||||
restartJobRequestElement.addEventListener('click', (event) => {
|
||||
Requests.jobs.entity.restart({{ job.hashid|tojson }});
|
||||
});
|
||||
|
||||
if ({{ current_user.is_administrator()|tojson }}) {
|
||||
let jobLogButtonElement = document.querySelector('#job-log-button');
|
||||
jobLogButtonElement.addEventListener('click', (event) => {
|
||||
Requests.jobs.entity.log({{ job.hashid|tojson }})
|
||||
.then(
|
||||
@ -168,8 +173,6 @@
|
||||
});
|
||||
});
|
||||
});
|
||||
restartJobRequestElement.addEventListener('click', (event) => {
|
||||
Requests.jobs.entity.restart({{ job.hashid|tojson }});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock scripts %}
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<h1 id="title">{{ title }}</h1>
|
||||
<h1 id="title">{{ service_manifest.name }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="col s12 m3 push-m9">
|
||||
@ -52,7 +52,14 @@
|
||||
{{ wtf.render_field(form.images, accept='image/jpeg, image/png, image/tiff', placeholder='Choose JPEG, PNG or TIFF files') }}
|
||||
</div>
|
||||
<div class="col s12 l3">
|
||||
{{ wtf.render_field(form.version, material_icon='apps') }}
|
||||
<div class="input-field">
|
||||
<i class="material-icons prefix">apps</i>
|
||||
{{ form.version() }}
|
||||
{{ form.version.label }}
|
||||
<span class="helper-text">
|
||||
<a class="modal-trigger tooltipped" href="#versions-modal" data-position="bottom" data-tooltip="See more information about versions"><i class="material-icons service-color-text text-darken" data-service="file-setup-pipeline">help_outline</i></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -65,3 +72,26 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endblock page_content %}
|
||||
|
||||
{% block modals %}
|
||||
{{ super() }}
|
||||
<div id="versions-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>File Setup Pipeline versions</h4>
|
||||
<ul class="collapsible popout" id="file-setup-pipeline-versions">
|
||||
{% for version, version_info in service_manifest.versions.items() %}
|
||||
<li id="file-setup-pipeline-version-{{ version }}">
|
||||
<div class="collapsible-header"><i class="material-icons">widgets</i>{{ service_manifest.publisher }} ({{ version_info.publishing_year }}), {{ service_manifest.name }} {{ version }}</div>
|
||||
<div class="collapsible-body">
|
||||
<p><b>Release</b>: <a href="{{ version_info.url }}">{{ version_info.url }}</a></p>
|
||||
<p><b>Code</b>: <a href="{{ version_info.code_url }}">{{ version_info.code_url }}</a></p>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class="modal-close waves-effect waves-light btn">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock modals %}
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<h1 id="title">{{ title }}</h1>
|
||||
<h1 id="title">{{ service_manifest.name }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="col s12 m3 push-m9">
|
||||
@ -81,7 +81,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col s12 l3">
|
||||
{{ wtf.render_field(form.version, material_icon='apps') }}
|
||||
<div class="input-field">
|
||||
<i class="material-icons prefix">apps</i>
|
||||
{{ form.version() }}
|
||||
{{ form.version.label }}
|
||||
<span class="helper-text">
|
||||
<a class="modal-trigger tooltipped" href="#versions-modal" data-position="bottom" data-tooltip="See more information about versions"><i class="material-icons" style="color:#0064A3;">help_outline</i></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col s12">
|
||||
<span class="card-title">Preprocessing</span>
|
||||
@ -120,18 +127,6 @@
|
||||
|
||||
{% block modals %}
|
||||
{{ super() }}
|
||||
<div id="progress-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4><i class="material-icons prefix">file_upload</i> Uploading files...</h4>
|
||||
<div class="progress">
|
||||
<div class="determinate" style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="models-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>spaCy NLP Pipeline models</h4>
|
||||
@ -162,6 +157,26 @@
|
||||
<a href="#!" class="modal-close waves-effect waves-light btn">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="versions-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>SpaCy NLP Pipeline versions</h4>
|
||||
<ul class="collapsible popout" id="spacy-nlp-pipeline-versions">
|
||||
{% for version, version_info in service_manifest.versions.items() %}
|
||||
<li id="spacy-nlp-pipeline-version-{{ version }}">
|
||||
<div class="collapsible-header"><i class="material-icons">widgets</i>{{ service_manifest.publisher }} ({{ version_info.publishing_year }}), {{ service_manifest.name }} {{ version }}</div>
|
||||
<div class="collapsible-body">
|
||||
<p><b>Release</b>: <a href="{{ version_info.url }}">{{ version_info.url }}</a></p>
|
||||
<p><b>Code</b>: <a href="{{ version_info.code_url }}">{{ version_info.code_url }}</a></p>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class="modal-close waves-effect waves-light btn">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock modals %}
|
||||
|
||||
{% block scripts %}
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<h1 id="title">{{ title }}</h1>
|
||||
<h1 id="title">{{ service_manifest.name }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="col s12 m3 push-m9">
|
||||
@ -66,7 +66,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col s12 l3">
|
||||
{{ wtf.render_field(form.version, material_icon='apps') }}
|
||||
<div class="input-field">
|
||||
<i class="material-icons prefix">apps</i>
|
||||
{{ form.version() }}
|
||||
{{ form.version.label }}
|
||||
<span class="helper-text">
|
||||
<a class="modal-trigger tooltipped" href="#versions-modal" data-position="bottom" data-tooltip="See more information about versions"><i class="material-icons" style="color:#00A58B;">help_outline</i></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col s12">
|
||||
<span class="card-title">Preprocessing</span>
|
||||
@ -142,6 +149,26 @@
|
||||
<a href="#!" class="modal-close waves-effect waves-light btn">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="versions-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Tesseract OCR Pipeline versions</h4>
|
||||
<ul class="collapsible popout" id="tesseract-ocr-pipeline-versions">
|
||||
{% for version, version_info in service_manifest.versions.items() %}
|
||||
<li id="tesseract-ocr-pipeline-version-{{ version }}">
|
||||
<div class="collapsible-header"><i class="material-icons">widgets</i>{{ service_manifest.publisher }} ({{ version_info.publishing_year }}), {{ service_manifest.name }} {{ version }}</div>
|
||||
<div class="collapsible-body">
|
||||
<p><b>Release</b>: <a href="{{ version_info.url }}">{{ version_info.url }}</a></p>
|
||||
<p><b>Code</b>: <a href="{{ version_info.code_url }}">{{ version_info.code_url }}</a></p>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class="modal-close waves-effect waves-light btn">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock modals %}
|
||||
|
||||
{% block scripts %}
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<h1 id="title">{{ title }}</h1>
|
||||
<h1 id="title">{{ service_manifest.name }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="col s12 m3 push-m9">
|
||||
@ -62,7 +62,7 @@
|
||||
{{ form.model() }}
|
||||
{{ form.model.label }}
|
||||
<span class="helper-text">
|
||||
<a class="modal-trigger" href="#models-modal">More details about models</a>
|
||||
<a class="modal-trigger tooltipped" href="#models-modal" data-position="bottom" data-tooltip="See more information about models"><i class="material-icons service-color-text text-darken" data-service="transkribus-htr-pipeline">help_outline</i></a>
|
||||
</span>
|
||||
{% for error in form.model.errors %}
|
||||
<span class="helper-text error-color-text">{{ error }}</span>
|
||||
@ -70,7 +70,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col s12 l3">
|
||||
{{ wtf.render_field(form.version, material_icon='apps') }}
|
||||
<div class="input-field">
|
||||
<i class="material-icons prefix">apps</i>
|
||||
{{ form.version() }}
|
||||
{{ form.version.label }}
|
||||
<span class="helper-text">
|
||||
<a class="modal-trigger tooltipped" href="#versions-modal" data-position="bottom" data-tooltip="See more information about versions"><i class="material-icons service-color-text text-darken" data-service="transkribus-htr-pipeline">help_outline</i></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col s12">
|
||||
<span class="card-title">Preprocessing</span>
|
||||
@ -128,15 +135,23 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="progress-modal" class="modal">
|
||||
<div id="versions-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4><i class="material-icons left">file_upload</i>Uploading files...</h4>
|
||||
<div class="progress">
|
||||
<div class="determinate" style="width: 0%"></div>
|
||||
<h4>SpaCy NLP Pipeline versions</h4>
|
||||
<ul class="collapsible popout" id="spacy-nlp-pipeline-versions">
|
||||
{% for version, version_info in service_manifest.versions.items() %}
|
||||
<li id="spacy-nlp-pipeline-version-{{ version }}">
|
||||
<div class="collapsible-header"><i class="material-icons">widgets</i>{{ service_manifest.publisher }} ({{ version_info.publishing_year }}), {{ service_manifest.name }} {{ version }}</div>
|
||||
<div class="collapsible-body">
|
||||
<p><b>Release</b>: <a href="{{ version_info.url }}">{{ version_info.url }}</a></p>
|
||||
<p><b>Code</b>: <a href="{{ version_info.code_url }}">{{ version_info.code_url }}</a></p>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a>
|
||||
<a href="#!" class="modal-close waves-effect waves-light btn">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock modals %}
|
||||
|
@ -0,0 +1,273 @@
|
||||
<h2>Workshop Aufgaben</h2>
|
||||
|
||||
<h3>Aufgabenblock 1</h3>
|
||||
<p>
|
||||
1. Ich möchte alle Ergebnisse für den Begriff "jüdisch" finden. Groß- und
|
||||
Kleinschreibung soll dabei nicht berücksichtigt werden. Bei der richtigen
|
||||
Abfrage gibt es 5 Ergebnisse.
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col s2">
|
||||
<span class="btn waves-effect waves-light solution-button">Lösung</span>
|
||||
</div>
|
||||
<div class="col s10 solution-field hide">
|
||||
<pre style="margin-top: 7px;"><code>[word="jüdisch" %c];</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
2. Ich möchte jetzt in einer einzigen Suchabfrage alle Ergebnisse für die
|
||||
Begriffe "jüdisch", aber auch "Juden" und "jüdischer" usw. finden. Bei der
|
||||
richtigen Abfrage müsste es dafür 118 Ergebnisse geben.
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col s2">
|
||||
<span class="btn waves-effect waves-light solution-button">Lösung</span>
|
||||
</div>
|
||||
<div class="col s10 solution-field hide">
|
||||
<pre style="margin-top: 7px;"><code>[word="j(u|ü)d.*" %c];</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
3. Ich möchte in einer einzigen Suchabfrage alle Ergebnisse für den Begriff
|
||||
"judisch" (in sämtlichen Ableitungen s.o.) im Zusammenhang mit dem Begriff
|
||||
(ebenfalls sämtliche Ableitungen) "Freund" herausfiltern. Dazwischen sollen
|
||||
0 bis 10 Wörter auftauchen. Es gibt 1 Ergebnis bei der richtigen Abfrage.
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col s2">
|
||||
<span class="btn waves-effect waves-light solution-button">Lösung</span>
|
||||
</div>
|
||||
<div class="col s10 solution-field hide">
|
||||
<pre style="margin-top: 7px;"><code>[word="j(u|ü)d.*" %c] []{0,10} [word="freund.*" %c];</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
4. Ich möchte zuletzt in einer einzigen Suchanfrage alle Ergebnisse für
|
||||
entweder "jüdisch" oder "deutsch" (in sämtlichen Ableitungen) und "Freund"
|
||||
herausfiltern. Dazwischen sollen wieder 0 bis 10 Wörter auftauchen.
|
||||
Es gibt wieder ein Ergebnis.
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col s2">
|
||||
<span class="btn waves-effect waves-light solution-button">Lösung</span>
|
||||
</div>
|
||||
<div class="col s10 solution-field hide">
|
||||
<pre style="margin-top: 7px;"><code>[word="j(u|ü)d.*" %c | word="deutsch.*" %c] []{0,10} [word="freund.*" %c];</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="collapsible">
|
||||
<li>
|
||||
<div class="collapsible-header">Tipp 1</div>
|
||||
<div class="collapsible-body">
|
||||
<p>
|
||||
Wörter können über den Query Builder > "Add new Token to your Query" hinzugefügt werden. Unten kann der Haken bei "Ignore Case" gesetzt werden um Groß- und Kleinschreibung zu ignorieren.
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header">Tipp 2</div>
|
||||
<div class="collapsible-body">
|
||||
<p>
|
||||
Über die Option Group lassen sich auch Buchstaben in der Suche definieren. So könnte als erste Option "u" und als zweite Option "ü" definiert werden. Die Suche würde dann nach beiden Varianten suchen.
|
||||
Um beliebig viele Buchstaben zu finden, kann ein Wildcard-Charakter (".") verwendet werden, gefolgt von dem Incidence Modifier "zero or more" ("*"). Damit sind beliebig viele Buchstaben jeglicher Art möglich.
|
||||
<pre><code>[word="l(o|u)r.*"];</code></pre> würde z.B. nach "lora", "lura", "lurum" usw. suchen.
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header">Tipp 3</div>
|
||||
<div class="collapsible-body">
|
||||
<p>
|
||||
Um eine bestimmte Anzahl Wörter anzeigen zu lassen, die einen beliebigen
|
||||
Inhalt haben dürfen, kann mit einem Empty Token (also einem nicht definiertem Token)
|
||||
gerarbeitet werden. Den kann man über das Dropdown "Which kind of token are you looking for?"
|
||||
hinzugefügen. Dem leeren Token kann dann ein Incidence Modifier zugewiesen werden, der
|
||||
die Anzahl der Wörter auf 0 bis 10 begrenzt (between n and m).
|
||||
<pre><code>[]{0,10};</code></pre>
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header">Tipp 4</div>
|
||||
<div class="collapsible-body">
|
||||
<p>
|
||||
Wenn entweder das eine oder das andere Wort auftauchen soll, kann der "OR"-Operator in der unteren Options-Leiste verwendet werden.
|
||||
Dann kann ein zweiter Wert eingetragen werden. Einer von beiden muss dann auftauchen.
|
||||
<pre><code>[word="lorem" %c | word="ipsum" %c];</code></pre>
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Aufgabenblock 2</h3>
|
||||
<p>
|
||||
1. Ich möchte in einer Suchanfrage alle Ergebnisse für Wortfolgen, in denen
|
||||
das Wort "jüdisch" (mit sämtlichen Ableitungen) vorkommt. Vor dem Wort
|
||||
soll ein Adjektiv auftauchen auf das 0-5 Wörter folgen sollen. Die
|
||||
richtige Abfrage ergibt 36 Ergebnisse.
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col s2">
|
||||
<span class="btn waves-effect waves-light solution-button">Lösung</span>
|
||||
</div>
|
||||
<div class="col s10 solution-field hide">
|
||||
<pre style="margin-top: 7px;"><code>[simple_pos="ADJ"] []{0,5} [word="j(u|ü)d.*" %c];</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
2. Ich möchte in einer Suchanfrage alle Ergebnisse für Wortfolgen, in denen
|
||||
das Wort "jüdisch" (mit sämtlichen Ableitungen) ein Adjektiv ist und direkt
|
||||
von einem Nomen gefolgt wird. Die richtige Abfrage ergibt 27 Ergebnisse.
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col s2">
|
||||
<span class="btn waves-effect waves-light solution-button">Lösung</span>
|
||||
</div>
|
||||
<div class="col s10 solution-field hide">
|
||||
<pre style="margin-top: 7px;"><code>[word="j(u|ü)d.*" %c & simple_pos="ADJ"] [simple_pos="NOUN"];</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
3. Ich möchte eine Suchanfrage aller Ergebnisse für Wortfolgen, in denen das
|
||||
Wort "jüdisch" (mit sämtlichen Ableitungen) von dem Lemma "sein" gefolgt
|
||||
wird. Dazwischen dürfen 0-5 beliebige Wörter vorkommen. Die richtige Abfrage
|
||||
ergibt 16 Ergebnisse.
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col s2">
|
||||
<span class="btn waves-effect waves-light solution-button">Lösung</span>
|
||||
</div>
|
||||
<div class="col s10 solution-field hide">
|
||||
<pre style="margin-top: 7px;"><code>[word="J(u|ü)d.*" %c] []{0,5} [lemma="sein" %c];</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="collapsible">
|
||||
<li>
|
||||
<div class="collapsible-header">Tipp 1</div>
|
||||
<div class="collapsible-body">
|
||||
<p>
|
||||
Über die Token-Suchauswahl kann "simple_pos" ausgewählt werden. Darüber
|
||||
findet man sämtliche Werte, zum Beispiel "ADJ" für Adjektive oder "NOUN" für Nomen.
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header">Tipp 2</div>
|
||||
<div class="collapsible-body">
|
||||
<p>
|
||||
Dem Wort kann eine zweite Token-Eingrenzung hinzugefügt werden. Dafür nutzen wir den
|
||||
"AND"-Operator. Dort können wir über die Token-Suchauswahl "simple_pos" auswählen und
|
||||
dann einen Wert hinzufügen. Somit muss das gesuchte Wort
|
||||
ebenfalls den simple_pos-Wert haben, also zum Beispiel ein Adjektiv sein.
|
||||
<pre><code>[word="lorem" & simple_pos="NOUN"];</code></pre>
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header">Tipp 3</div>
|
||||
<div class="collapsible-body">
|
||||
<p>
|
||||
Ich kann ebenfalls nach der Grundform (Lemma) eines Wortes suchen. Dafür
|
||||
muss ich in der Token-Suchauswahl "lemma" auswählen und dann den Wert - genau wie beim "word" -
|
||||
eintragen.
|
||||
<pre><code>[lemma="lorem" %c];</code></pre>
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Aufgabenblock 3</h3>
|
||||
<p>
|
||||
1. Ich möchte in einer Suchanfrage alle Ergebnisse für "jüdisch"
|
||||
(in sämtlichen Ableitungen) im Zusammenhang mit dem Lemma "sprechen"
|
||||
(in sämtlichen Ableitungen, also auch "besprechen", "versprechen" usw.)
|
||||
erhalten. Dabei möchte ich nur Ergebnisse innerhalb eines Satzes berücksichtigen.
|
||||
Vor, zwischen und nach den Begriffen dürfen beliebig viele Wörter auftauchen.
|
||||
Die richtige Abfrage ergibt 2 Treffer.
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col s2">
|
||||
<span class="btn waves-effect waves-light solution-button">Lösung</span>
|
||||
</div>
|
||||
<div class="col s10 solution-field hide">
|
||||
<pre style="margin-top: 7px;"><code><s> []* [word="j(u|ü)d.*" %c] []* [lemma=".*sprechen.*" %c] []* </s></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
2. Ich möchte in einer Suchanfrage alle Ergebnisse für Sätze, in denen eine
|
||||
Person im Zusammenhang mit dem Lemma "helfen" (in sämtlichen Schreibweisen,
|
||||
also auch "verhelfen" etc.) vorkommt. Vor, zwischen und nach den gesuchten
|
||||
Werten dürfen beliebig viele Wörter vorkommen. Der als Person deklarierte
|
||||
Wert darf ebenfalls beliebig lang sein. Die richtige Abfrage ergibt 6 Treffer.
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col s2">
|
||||
<span class="btn waves-effect waves-light solution-button">Lösung</span>
|
||||
</div>
|
||||
<div class="col s10 solution-field hide">
|
||||
<pre style="margin-top: 7px;"><code><s>[]* <ent_type="PER"> []* </ent_type> []* [lemma=".*helfen.*" %c] []* </s>;</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
3. Ich möchte in einer Suchabfrage alle Ergebnisse für Sätzen in denen der
|
||||
Begriff "jüdisch" (in sämtlichen Ableitungen) im Zusammenhang mit einer
|
||||
Organisation auftaucht. Vor, zwischen und nach den gesuchten Werten dürfen
|
||||
beliebig viele Wörter vorkommen. Der als Organisation deklarierte Wert darf
|
||||
ebenfalls beliebig lang sein. Die richtige Abfrage ergibt 4 Treffer.
|
||||
Test
|
||||
<b>Schaffen Sie das auch ohne Query Builder?</b> (Tipp: Die Tagsets helfen beim Spezifizieren des ent_type-Wertes.)
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col s2">
|
||||
<span class="btn waves-effect waves-light solution-button">Lösung</span>
|
||||
</div>
|
||||
<div class="col s10 solution-field hide">
|
||||
<pre style="margin-top: 7px;"><code><s>[]* [word="j(u|ü)d.*" %c][]* <ent_type="ORG"> []* </ent_type> []*</s>;</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="collapsible">
|
||||
<li>
|
||||
<div class="collapsible-header">Tipp 1</div>
|
||||
<div class="collapsible-body">
|
||||
<p>
|
||||
Ich kann über den Button "Add structural attributes to your query" umschließende
|
||||
Satz-Tags setzen. Dafür muss ich auf den Button "Sentence" klicken und nachdem ich meine Anfrage
|
||||
erstellt habe wieder auf "End Sentence" an der gleichen Stelle.
|
||||
</p>
|
||||
<p>
|
||||
Wenn ich mit Sätzen arbeite, darf ich nicht die Platzhalter-Token ("<code>[]*</code>") vergessen, da sonst
|
||||
ausschließlich Sätze mit genau den gesuchten Wörtern gefunden werden.
|
||||
</p>
|
||||
<p>
|
||||
Wir haben bisher nur mit beliebigen Endungen eines Wortes in Form von
|
||||
<code>[word="lore.*"]</code> gearbeitet. Das gleiche funktioniert auch am
|
||||
Anfang eines Wortes, indem ich beliebig viele Wildcard-Character an den Anfang
|
||||
der Wortes setze: <code>[word=".*rem"]</code>.
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header">Tipp 2</div>
|
||||
<div class="collapsible-body">
|
||||
<p>
|
||||
Über den Button "Add structural attributes to your query" kann ich auch Entitäten bestimmen.
|
||||
Für unser Beispiel arbeiten wir ausschließlich mit den german ent_types. Deren Definitionen kann ich
|
||||
mir in den Tagset-Listen anschauen. Hier kann ich dann die gewünschte Entität auswählen. Wenn
|
||||
der gesuchte Wert beliebig sein darf, muss ich zwischen den öffnenden und schließenden ent-tag ein
|
||||
Platzhalter-Token setzen, das beliebig lang sein darf ("<code>[]*</code>").
|
||||
<pre><code><ent_type="LOC"> []* </ent_type></code></pre>
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<script>
|
||||
let solutionButtons = document.querySelectorAll('.solution-button');
|
||||
solutionButtons.forEach((button) => {
|
||||
button.addEventListener('click', (event) => {
|
||||
let solutionField = event.target.parentElement.parentElement.querySelector('.solution-field');
|
||||
solutionField.classList.toggle('hide');
|
||||
});
|
||||
});
|
||||
</script>
|
@ -0,0 +1,82 @@
|
||||
<h2>Vorbereitungen</h2>
|
||||
<div class="row">
|
||||
<div class="col s12 m5">
|
||||
<img class="materialboxed responsive-img" alt="Dashboard" src="{{ url_for('static', filename='images/workshops/fgho_sommerschule_2023/dashboard.png') }}">
|
||||
</div>
|
||||
<div class="col s12 m7">
|
||||
<p>
|
||||
Navigiere zum Abschnitt "<a href="{{ url_for('main.dashboard', _anchor='corpora') }}">My Corpora</a>"
|
||||
auf der <a href="{{ url_for('main.dashboard') }}">Dashboard</a> Seite.
|
||||
</p>
|
||||
<p>
|
||||
Nutze dort den "<a href="{{ url_for('corpora.create_corpus') }}">Create corpus +</a>"
|
||||
Button um einen neuen Korpus zu erstellen.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col s12 m5">
|
||||
<img class="materialboxed responsive-img" alt="Dashboard" src="{{ url_for('static', filename='images/workshops/fgho_sommerschule_2023/create_corpus.png') }}">
|
||||
</div>
|
||||
<div class="col s12 m7">
|
||||
<p>
|
||||
Trage in dem Formular einen <b>Titel</b> und eine <b>Beschreibung</b> ein, die Felder
|
||||
können frei befüllt werden. Die Angaben sollen dir in Zukunft helfen den
|
||||
Korpus wiederzufinden, wenn deine Korpusliste sich füllt.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col s12 m5">
|
||||
<img class="materialboxed responsive-img" alt="Dashboard" src="{{ url_for('static', filename='images/workshops/fgho_sommerschule_2023/empty_corpus.png') }}">
|
||||
</div>
|
||||
<div class="col s12 m7">
|
||||
<p>
|
||||
Nachdem du den Korpus erstellt hast, wirst du zur Korpusübersicht
|
||||
weitergeleitet. Diese zeigt einen leeren Korpus, in dem noch keine
|
||||
Korpusdateien hinterlegt sind. Um den Korpus mit Texten zu füllen,
|
||||
wird der „<b>+ Add corpus file</b>“ Button benutzt.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col s12 m5">
|
||||
<img class="materialboxed responsive-img" alt="Dashboard" src="{{ url_for('static', filename='images/workshops/fgho_sommerschule_2023/add_corpus_file.png') }}">
|
||||
</div>
|
||||
<div class="col s12 m7">
|
||||
<p>
|
||||
In dem folgenden Formular werden nun Metadaten zu dem Text, den wir
|
||||
hinzufügen wollen, hinterlegt. Diese Daten sollten sorgfältig eingetragen
|
||||
werden, da sie in der Analyse mit einbezogen werden. Mit dem „File“-Feld
|
||||
muss eine Textdatei im „.vrt“ Format ausgewählt werden.
|
||||
</p>
|
||||
<p>
|
||||
Füge deinem neu erstellten Korpus so die zwei, <b>im Workshop zur Verfügung
|
||||
gestellten</b>, Texte hinzu.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col s12 m5">
|
||||
<img class="materialboxed responsive-img" alt="Dashboard" src="{{ url_for('static', filename='images/workshops/fgho_sommerschule_2023/corpus.png') }}">
|
||||
</div>
|
||||
<div class="col s12 m7">
|
||||
<p>
|
||||
Nachdem die Texte dem Korpus hinzugefügt wurden, sollte deine
|
||||
Korpusübersicht wie in dem Bild aussehen. Nutze nun die „<b>Build</b>“-Aktion,
|
||||
um den Korpus für eine Analyse vorzubereiten.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
23
app/templates/workshops/fgho_sommerschule_2023.html.j2
Normal file
23
app/templates/workshops/fgho_sommerschule_2023.html.j2
Normal file
@ -0,0 +1,23 @@
|
||||
{% extends "base.html.j2" %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<h1 id="title">{{ title }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="col s12">
|
||||
<a class="btn waves-effect waves-light" href="#fgho-sommerschule-2023-workshop-aufgaben">Hier geht es zu den Aufgaben<i class="material-icons right">send</i></a>
|
||||
</div>
|
||||
|
||||
<div class="col s12" id="fgho-sommerschule-2023-vorbereitungen">
|
||||
{% include "workshops/_fgho_sommerschule_2023/_vorbereitungen.html.j2" %}
|
||||
</div>
|
||||
|
||||
<div class="col s12" id="fgho-sommerschule-2023-workshop-aufgaben">
|
||||
{% include "workshops/_fgho_sommerschule_2023/_aufgaben.html.j2" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock page_content %}
|
@ -7,7 +7,7 @@ from app.models import User
|
||||
|
||||
@socketio.on('GET /users/<user_id>')
|
||||
@socketio_login_required
|
||||
def get_user(user_hashid, backrefs=False, relationships=False):
|
||||
def get_user(user_hashid):
|
||||
user_id = hashids.decode(user_hashid)
|
||||
user = User.query.get(user_id)
|
||||
if user is None:
|
||||
@ -15,12 +15,9 @@ def get_user(user_hashid, backrefs=False, relationships=False):
|
||||
if not (user == current_user or current_user.is_administrator()):
|
||||
return {'status': 403, 'statusText': 'Forbidden'}
|
||||
return {
|
||||
'body': user.to_json_serializeable(
|
||||
backrefs=backrefs,
|
||||
relationships=relationships
|
||||
),
|
||||
'body': user.to_json_serializeable(backrefs=True, relationships=True),
|
||||
'status': 200,
|
||||
'statusText': 'OK',
|
||||
'statusText': 'OK'
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,29 +7,29 @@ from app.models import Avatar, User
|
||||
from . import bp
|
||||
|
||||
|
||||
# @bp.route('/<hashid:user_id>', methods=['DELETE'])
|
||||
# @content_negotiation(produces='application/json')
|
||||
# def delete_user(user_id):
|
||||
# def _delete_user(app, user_id):
|
||||
# with app.app_context():
|
||||
# user = User.query.get(user_id)
|
||||
# user.delete()
|
||||
# db.session.commit()
|
||||
@bp.route('/<hashid:user_id>', methods=['DELETE'])
|
||||
@content_negotiation(produces='application/json')
|
||||
def delete_user(user_id):
|
||||
def _delete_user(app, user_id):
|
||||
with app.app_context():
|
||||
user = User.query.get(user_id)
|
||||
user.delete()
|
||||
db.session.commit()
|
||||
|
||||
# user = User.query.get_or_404(user_id)
|
||||
# if not (user == current_user or current_user.is_administrator()):
|
||||
# abort(403)
|
||||
# thread = Thread(
|
||||
# target=_delete_user,
|
||||
# args=(current_app._get_current_object(), user.id)
|
||||
# )
|
||||
# if user == current_user:
|
||||
# logout_user()
|
||||
# thread.start()
|
||||
# response_data = {
|
||||
# 'message': f'User "{user.username}" marked for deletion'
|
||||
# }
|
||||
# return response_data, 202
|
||||
user = User.query.get_or_404(user_id)
|
||||
if not (user == current_user or current_user.is_administrator()):
|
||||
abort(403)
|
||||
thread = Thread(
|
||||
target=_delete_user,
|
||||
args=(current_app._get_current_object(), user.id)
|
||||
)
|
||||
if user == current_user:
|
||||
logout_user()
|
||||
thread.start()
|
||||
response_data = {
|
||||
'message': f'User "{user.username}" marked for deletion'
|
||||
}
|
||||
return response_data, 202
|
||||
|
||||
|
||||
# @bp.route('/<hashid:user_id>/avatar', methods=['DELETE'])
|
||||
|
5
app/workshops/__init__.py
Normal file
5
app/workshops/__init__.py
Normal file
@ -0,0 +1,5 @@
|
||||
from flask import Blueprint
|
||||
|
||||
|
||||
bp = Blueprint('workshops', __name__)
|
||||
from . import routes
|
18
app/workshops/routes.py
Normal file
18
app/workshops/routes.py
Normal file
@ -0,0 +1,18 @@
|
||||
from flask import redirect, render_template, url_for
|
||||
from flask_breadcrumbs import register_breadcrumb
|
||||
from . import bp
|
||||
|
||||
|
||||
@bp.route('')
|
||||
@register_breadcrumb(bp, '.', '<i class="material-icons left">business_center</i>Workshops')
|
||||
def workshops():
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
|
||||
@bp.route('/fgho_sommerschule_2023')
|
||||
@register_breadcrumb(bp, '.fgho_sommerschule_2023', 'FGHO Sommerschule 2023')
|
||||
def fgho_sommerschule_2023():
|
||||
return render_template(
|
||||
'workshops/fgho_sommerschule_2023.html.j2',
|
||||
title='FGHO Sommerschule 2023',
|
||||
)
|
@ -1,5 +1,5 @@
|
||||
apifairy
|
||||
cqi>=0.1.4
|
||||
cqi>=0.1.5
|
||||
dnspython==2.2.1
|
||||
docker
|
||||
eventlet
|
||||
@ -7,7 +7,7 @@ Flask==2.1.3
|
||||
Flask-APScheduler
|
||||
Flask-Assets
|
||||
Flask-Breadcrumbs
|
||||
Flask-Hashids==1.0.1
|
||||
Flask-Hashids>=1.0.1
|
||||
Flask-HTTPAuth
|
||||
Flask-Login
|
||||
Flask-Mail
|
||||
|
Loading…
x
Reference in New Issue
Block a user