+
+ ${prettyQueryText}
+ close
+
`
);
- buttonElement.addEventListener('click', () => {this.deleteAttr(buttonElement);});
+ queryChipElement.addEventListener('click', () => {this.deleteAttr(queryChipElement);});
+ queryChipElement.addEventListener('dragstart', (event) => {
+ // selects all nodes without target class
+ let queryChips = this.elements.yourQuery.querySelectorAll('.query-component');
+
+ // Adds a target chip in front of all draggable childnodes
+ setTimeout(() => {
+ let targetChipElement = Utils.HTMLToElement('Drop here');
+ for (let element of queryChips) {
+ if (element === queryChipElement.nextSibling) {continue;}
+ let targetChipClone = targetChipElement.cloneNode(true);
+ if (element === queryChipElement) {
+ // If the dragged element is not at the very end, a target chip is also inserted at the end
+ if (queryChips[queryChips.length - 1] !== element) {
+ queryChips[queryChips.length - 1].insertAdjacentElement('afterend', targetChipClone);
+ }
+ } else {
+ element.insertAdjacentElement('beforebegin', targetChipClone);
+ }
+ targetChipClone.addEventListener('dragover', (event) => {
+ event.preventDefault();
+ });
+ targetChipClone.addEventListener('dragenter', (event) => {
+ event.preventDefault();
+ event.target.style.borderStyle = 'solid dotted';
+ });
+ targetChipClone.addEventListener('dragleave', (event) => {
+ event.preventDefault();
+ event.target.style.borderStyle = 'hidden';
+ });
+ targetChipClone.addEventListener('drop', (event) => {
+ let dropzone = event.target;
+ dropzone.parentElement.replaceChild(queryChipElement, dropzone);
+ this.queryPreviewBuilder();
+ });
+ }
+ }, 0);
+ });
+
+ queryChipElement.addEventListener('dragend', (event) => {
+ let targets = document.querySelectorAll('.drop-target');
+ for (let target of targets) {
+ target.remove();
+ }
+ });
// Ensures that metadata is always at the end of the query:
if (this.elements.yourQuery.lastChild === null || this.elements.yourQuery.lastChild.dataset.type !== 'text-annotation') {
- this.elements.yourQuery.appendChild(buttonElement);
+ this.elements.yourQuery.appendChild(queryChipElement);
} else if (this.elements.yourQuery.lastChild.dataset.type === 'text-annotation') {
- this.elements.yourQuery.insertBefore(buttonElement, this.elements.yourQuery.lastChild);
+ this.elements.yourQuery.insertBefore(queryChipElement, this.elements.yourQuery.lastChild);
}
this.elements.queryContainer.classList.remove('hide');
this.queryPreviewBuilder();
@@ -234,73 +280,11 @@ class ConcordanceQueryBuilder {
}
}
- //#region Drag&Drop Events
- dragStartHandler(event) {
- // Creates element with the class 'target' and all necessary drop functions, in which drop content can be released
- this.elements.dropButton = event.target;
- let targetChip = `
-
- Drop here
-
- `.trim();
- // selects all nodes without target class
- let childNodes = this.elements.yourQuery.querySelectorAll('div:not(.target)');
-
- // Adds a target chip in front of all draggable childnodes
- setTimeout(() => {
- for (let element of childNodes) {
- if (element === this.elements.dropButton) {
- // If the dragged element is not at the very end, a target chip is also inserted at the end
- if (childNodes[childNodes.length - 1] !== element) {
- childNodes[childNodes.length - 1].insertAdjacentHTML('afterend', targetChip);
- }
- } else if (element === this.elements.dropButton.nextSibling) {
- continue;
- } else {
- element.insertAdjacentHTML('beforebegin', targetChip)
- }
- }
- },0);
- }
-
- dragOverHandler(event) {
- event.preventDefault();
- }
-
- dragEnterHandler(event) {
- event.preventDefault();
- event.target.style.borderStyle = 'solid dotted';
- }
-
- dragLeaveHandler(event) {
- event.preventDefault();
- event.target.style.borderStyle = 'hidden';
- }
-
- dragEndHandler(event) {
- let targets = document.querySelectorAll('.target');
- for (let target of targets) {
- target.remove();
- }
- }
-
- dropHandler(event) {
- let dropzone = event.target;
- dropzone.parentElement.replaceChild(this.elements.dropButton, dropzone);
- this.queryPreviewBuilder();
- }
- //#endregion Drag&Drop Events
-
queryPreviewBuilder() {
this.elements.yourQueryContent = [];
for (let element of this.elements.yourQuery.childNodes) {
let queryElement = decodeURI(element.dataset.query);
- if (queryElement.includes('<')) {
- queryElement = queryElement.replace('<', '<');
- }
- if (queryElement.includes('>')) {
- queryElement = queryElement.replace('>', '>');
- }
+ queryElement = Utils.escape(queryElement);
if (queryElement !== 'undefined') {
this.elements.yourQueryContent.push(queryElement);
}
@@ -380,7 +364,7 @@ class ConcordanceQueryBuilder {
}
clearAll() {
- // Everything is reset. After 5 seconds for 5 seconds (with 'instance'), a message is displayed indicating that further information can be obtained via the question mark icon
+ // Everything is reset.
let instance = M.Tooltip.getInstance(this.elements.queryBuilderTutorialInfoIcon);
this.hideEverything();
@@ -393,16 +377,20 @@ class ConcordanceQueryBuilder {
this.elements.entity.innerHTML = 'Entity';
this.elements.sentence.innerHTML = 'Sentence';
+ // If the Modal is open after 5 seconds for 5 seconds (with 'instance'), a message is displayed indicating that further information can be obtained via the question mark icon
instance.tooltipEl.style.background = '#98ACD2';
instance.tooltipEl.style.borderTop = 'solid 4px #0064A3';
instance.tooltipEl.style.padding = '10px';
instance.tooltipEl.style.color = 'black';
setTimeout(() => {
- instance.open();
- setTimeout(() => {
- instance.close();
- }, 5000);
+ let modalInstance = M.Modal.getInstance(this.elements.concordanceQueryBuilder);
+ if (modalInstance.isOpen) {
+ instance.open();
+ setTimeout(() => {
+ instance.close();
+ }, 5000);
+ }
}, 5000);
}
@@ -467,19 +455,19 @@ class ConcordanceQueryBuilder {
}
- tokenButtonfactory(prettyText, tokenText) {
+ tokenChipFactory(prettyQueryText, tokenText) {
tokenText = encodeURI(tokenText);
let builderElement;
- let buttonElement;
+ let queryChipElement;
builderElement = document.createElement('div');
builderElement.innerHTML = `
- ${prettyText}
+ ${prettyQueryText}
close
`;
- buttonElement = builderElement.firstElementChild;
- buttonElement.addEventListener('click', () => {this.deleteTokenAttr(buttonElement);});
- this.elements.tokenQuery.appendChild(buttonElement);
+ queryChipElement = builderElement.firstElementChild;
+ queryChipElement.addEventListener('click', () => {this.deleteTokenAttr(queryChipElement);});
+ this.elements.tokenQuery.appendChild(queryChipElement);
}
deleteTokenAttr(attr) {
@@ -492,12 +480,12 @@ class ConcordanceQueryBuilder {
}
- addToken() {
+ addTokenToQuery() {
let c;
- let tokenQueryContent = ''; //for ButtonFactory(prettyText)
+ let tokenQueryContent = ''; //for ButtonFactory(prettyQueryText)
let tokenQueryText = ''; //for ButtonFactory(queryText)
this.elements.cancelBool = false;
- let emptyTokenCheck = false;
+ let tokenIsEmpty = false;
if (this.elements.ignoreCase.checked) {
c = ' %c';
@@ -510,7 +498,7 @@ class ConcordanceQueryBuilder {
tokenQueryContent += ' ' + element.firstChild.data + ' ';
tokenQueryText += decodeURI(element.dataset.tokentext);
if (element.innerText.indexOf('empty token') !== -1) {
- emptyTokenCheck = true;
+ tokenIsEmpty = true;
}
}
@@ -570,10 +558,11 @@ class ConcordanceQueryBuilder {
// cancelBool looks in disableTokenSubmit() whether a value is passed. If the input fields/dropdowns are empty (cancelBool === true), no token is added.
if (this.elements.cancelBool === false) {
// Square brackets are added only if it is not an empty token (where they are already present).
- if (emptyTokenCheck === false) {
+ if (tokenIsEmpty === false) {
tokenQueryText = '[' + tokenQueryText + ']';
}
- this.buttonfactory('token', tokenQueryContent, tokenQueryText);
+ console.log(tokenQueryText);
+ this.queryChipFactory('token', tokenQueryContent, tokenQueryText);
this.hideEverything();
this.elements.positionalAttrArea.classList.add('hide');
this.elements.tokenQuery.innerHTML = '';
@@ -659,7 +648,7 @@ class ConcordanceQueryBuilder {
}
emptyTokenHandler() {
- this.tokenButtonfactory('empty token', '[]');
+ this.tokenChipFactory('empty token', '[]');
this.elements.tokenQueryFilled = true;
this.hideEverything();
this.elements.incidenceModifiersButton.classList.remove('hide');
@@ -701,27 +690,27 @@ class ConcordanceQueryBuilder {
break;
case 'english-pos':
this.elements.tokenQueryFilled = true;
- this.tokenButtonfactory(`pos=${this.elements.englishPos.value}`, `pos="${this.elements.englishPos.value}"`);
- this.tokenButtonfactory('{' + this.elements.nInput.value + '}', '{' + this.elements.nInput.value + '}');
+ this.tokenChipFactory(`pos=${this.elements.englishPos.value}`, `pos="${this.elements.englishPos.value}"`);
+ this.tokenChipFactory('{' + this.elements.nInput.value + '}', '{' + this.elements.nInput.value + '}');
this.elements.englishPosBuilder.classList.add('hide');
this.elements.incidenceModifiersButton.classList.add('hide');
break;
case 'german-pos':
this.elements.tokenQueryFilled = true;
- this.tokenButtonfactory(`pos=${this.elements.germanPos.value}`, `pos="${this.elements.germanPos.value}"`);
- this.tokenButtonfactory('{' + this.elements.nInput.value + '}', '{' + this.elements.nInput.value + '}');
+ this.tokenChipFactory(`pos=${this.elements.germanPos.value}`, `pos="${this.elements.germanPos.value}"`);
+ this.tokenChipFactory('{' + this.elements.nInput.value + '}', '{' + this.elements.nInput.value + '}');
this.elements.germanPosBuilder.classList.add('hide');
this.elements.incidenceModifiersButton.classList.add('hide');
break;
case 'simple-pos-button':
this.elements.tokenQueryFilled = true;
- this.tokenButtonfactory(`simple_pos=${this.elements.simplePos.value}`, `simple_pos="${this.elements.simplePos.value}"`);
- this.tokenButtonfactory('{' + this.elements.nInput.value + '}', '{' + this.elements.nInput.value + '}');
+ this.tokenChipFactory(`simple_pos=${this.elements.simplePos.value}`, `simple_pos="${this.elements.simplePos.value}"`);
+ this.tokenChipFactory('{' + this.elements.nInput.value + '}', '{' + this.elements.nInput.value + '}');
this.elements.simplePosBuilder.classList.add('hide');
this.elements.incidenceModifiersButton.classList.add('hide');
break;
case 'empty-token':
- this.tokenButtonfactory('{' + this.elements.nInput.value + '}', '{' + this.elements.nInput.value + '}');
+ this.tokenChipFactory('{' + this.elements.nInput.value + '}', '{' + this.elements.nInput.value + '}');
break;
default:
break;
@@ -742,27 +731,27 @@ class ConcordanceQueryBuilder {
break;
case 'english-pos':
this.elements.tokenQueryFilled = true;
- this.tokenButtonfactory(`pos=${this.elements.englishPos.value}`, `pos="${this.elements.englishPos.value}"`);
- this.tokenButtonfactory(`{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`, `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`);
+ this.tokenChipFactory(`pos=${this.elements.englishPos.value}`, `pos="${this.elements.englishPos.value}"`);
+ this.tokenChipFactory(`{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`, `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`);
this.elements.englishPosBuilder.classList.add('hide');
this.elements.incidenceModifiersButton.classList.add('hide');
break;
case 'german-pos':
this.elements.tokenQueryFilled = true;
- this.tokenButtonfactory(`pos=${this.elements.germanPos.value}`, `pos="${this.elements.germanPos.value}"`);
- this.tokenButtonfactory(`{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`, `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`);
+ this.tokenChipFactory(`pos=${this.elements.germanPos.value}`, `pos="${this.elements.germanPos.value}"`);
+ this.tokenChipFactory(`{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`, `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`);
this.elements.germanPosBuilder.classList.add('hide');
this.elements.incidenceModifiersButton.classList.add('hide');
break;
case 'simple-pos-button':
this.elements.tokenQueryFilled = true;
- this.tokenButtonfactory(`simple_pos=${this.elements.simplePos.value}`, `simple_pos="${this.elements.simplePos.value}"`);
- this.tokenButtonfactory(`{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`, `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`);
+ this.tokenChipFactory(`simple_pos=${this.elements.simplePos.value}`, `simple_pos="${this.elements.simplePos.value}"`);
+ this.tokenChipFactory(`{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`, `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`);
this.elements.simplePosBuilder.classList.add('hide');
this.elements.incidenceModifiersButton.classList.add('hide');
break;
case 'empty-token':
- this.tokenButtonfactory(`{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`, `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`);
+ this.tokenChipFactory(`{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`, `{${this.elements.nmInput.value}, ${this.elements.mInput.value}}`);
break;
default:
break;
@@ -772,22 +761,22 @@ class ConcordanceQueryBuilder {
incidenceModifiersHandler(elem) {
// For word and lemma, the incidence modifiers are inserted in the input field. For the others, one or two chips are created which contain the respective value of the token and the incidence modifier.
if (this.elements.positionalAttr.value === 'empty-token') {
- this.tokenButtonfactory(elem.innerText, elem.dataset.token);
+ this.tokenChipFactory(elem.innerText, elem.dataset.token);
} else if (this.elements.positionalAttr.value === 'english-pos') {
- this.tokenButtonfactory(`pos=${this.elements.englishPos.value}`, `pos="${this.elements.englishPos.value}"`);
- this.tokenButtonfactory(elem.innerText, elem.dataset.token);
+ this.tokenChipFactory(`pos=${this.elements.englishPos.value}`, `pos="${this.elements.englishPos.value}"`);
+ this.tokenChipFactory(elem.innerText, elem.dataset.token);
this.elements.englishPosBuilder.classList.add('hide');
this.elements.incidenceModifiersButton.classList.add('hide');
this.elements.tokenQueryFilled = true;
} else if (this.elements.positionalAttr.value === 'german-pos') {
- this.tokenButtonfactory(`pos=${this.elements.germanPos.value}`, `pos="${this.elements.germanPos.value}"`);
- this.tokenButtonfactory(elem.innerText, elem.dataset.token);
+ this.tokenChipFactory(`pos=${this.elements.germanPos.value}`, `pos="${this.elements.germanPos.value}"`);
+ this.tokenChipFactory(elem.innerText, elem.dataset.token);
this.elements.germanPosBuilder.classList.add('hide');
this.elements.incidenceModifiersButton.classList.add('hide');
this.elements.tokenQueryFilled = true;
} else if (this.elements.positionalAttr.value === 'simple-pos-button') {
- this.tokenButtonfactory(`simple_pos=${this.elements.simplePos.value}`, `simple_pos="${this.elements.simplePos.value}"`);
- this.tokenButtonfactory(elem.innerText, elem.dataset.token);
+ this.tokenChipFactory(`simple_pos=${this.elements.simplePos.value}`, `simple_pos="${this.elements.simplePos.value}"`);
+ this.tokenChipFactory(elem.innerText, elem.dataset.token);
this.elements.simplePosBuilder.classList.add('hide');
this.elements.incidenceModifiersButton.classList.add('hide');
this.elements.tokenQueryFilled = true;
@@ -856,8 +845,8 @@ class ConcordanceQueryBuilder {
break;
}
- this.tokenButtonfactory(tokenQueryContent, tokenQueryText);
- this.tokenButtonfactory(conditionText, conditionQueryContent);
+ this.tokenChipFactory(tokenQueryContent, tokenQueryText);
+ this.tokenChipFactory(conditionText, conditionQueryContent);
this.wordBuilder();
}
@@ -874,10 +863,10 @@ class ConcordanceQueryBuilder {
addSentence() {
this.hideEverything();
if (this.elements.sentence.text === 'End Sentence') {
- this.buttonfactory('end-sentence', 'Sentence End', '');
+ this.queryChipFactory('end-sentence', 'Sentence End', '');
this.elements.sentence.innerHTML = 'Sentence';
} else {
- this.buttonfactory('start-sentence', 'Sentence Start', '');
+ this.queryChipFactory('start-sentence', 'Sentence Start', '');
this.elements.queryContent.push('sentence');
this.elements.sentence.innerHTML = 'End Sentence';
}
@@ -891,7 +880,7 @@ class ConcordanceQueryBuilder {
} else {
queryText = '';
}
- this.buttonfactory('end-entity', 'Entity End', queryText);
+ this.queryChipFactory('end-entity', 'Entity End', queryText);
this.elements.entity.innerHTML = 'Entity';
} else {
this.hideEverything();
@@ -901,7 +890,7 @@ class ConcordanceQueryBuilder {
}
englishEntTypeHandler() {
- this.buttonfactory('start-entity', 'Entity Type=' + this.elements.englishEntType.value, '');
+ this.queryChipFactory('start-entity', 'Entity Type=' + this.elements.englishEntType.value, '');
this.elements.entity.innerHTML = 'End Entity';
this.hideEverything();
this.elements.entityAnyType = false;
@@ -913,7 +902,7 @@ class ConcordanceQueryBuilder {
}
germanEntTypeHandler() {
- this.buttonfactory('start-entity', 'Entity Type=' + this.elements.germanEntType.value, '');
+ this.queryChipFactory('start-entity', 'Entity Type=' + this.elements.germanEntType.value, '');
this.elements.entity.innerHTML = 'End Entity';
this.hideEverything();
this.elements.entityAnyType = false;
@@ -925,7 +914,7 @@ class ConcordanceQueryBuilder {
}
emptyEntityButton() {
- this.buttonfactory('start-empty-entity', 'Entity Start', '');
+ this.queryChipFactory('start-empty-entity', 'Entity Start', '');
this.elements.entity.innerHTML = 'End Entity';
this.hideEverything();
this.elements.entityAnyType = true;
@@ -955,7 +944,7 @@ class ConcordanceQueryBuilder {
}, 3000);
} else {
let queryText = `:: match.text_${this.elements.textAnnotationOptions.value}="${this.elements.textAnnotationInput.value}"`;
- this.buttonfactory('text-annotation', `${this.elements.textAnnotationOptions.value}=${this.elements.textAnnotationInput.value}`, queryText);
+ this.queryChipFactory('text-annotation', `${this.elements.textAnnotationOptions.value}=${this.elements.textAnnotationInput.value}`, queryText);
this.hideEverything();
}
}
diff --git a/app/static/js/Forms/Form.js b/app/static/js/Forms/Form.js
index d93f3e2c..a9604c69 100644
--- a/app/static/js/Forms/Form.js
+++ b/app/static/js/Forms/Form.js
@@ -32,7 +32,7 @@ class Form {
submit(event) {
let request = new XMLHttpRequest();
- let modalElement = Utils.elementFromString(
+ let modalElement = Utils.HTMLToElement(
`
@@ -71,7 +71,7 @@ class Form {
for (let selectElement of this.formElement.querySelectorAll('select')) {
if (selectElement.value === '') {
let inputFieldElement = selectElement.closest('.input-field');
- let errorHelperTextElement = Utils.elementFromString(
+ let errorHelperTextElement = Utils.HTMLToElement(
'Please select an option.'
);
inputFieldElement.appendChild(errorHelperTextElement);
@@ -98,7 +98,7 @@ class Form {
.querySelector(`input[name$="${inputName}"], select[name$="${inputName}"]`)
.closest('.input-field');
for (let inputError of inputErrors) {
- let errorHelperTextElement = Utils.elementFromString(
+ let errorHelperTextElement = Utils.HTMLToElement(
`${inputError}`
);
inputFieldElement.appendChild(errorHelperTextElement);
diff --git a/app/static/js/ResourceLists/AdminUserList.js b/app/static/js/ResourceLists/AdminUserList.js
new file mode 100644
index 00000000..0307bbdc
--- /dev/null
+++ b/app/static/js/ResourceLists/AdminUserList.js
@@ -0,0 +1,112 @@
+class AdminUserList extends ResourceList {
+ static autoInit() {
+ for (let adminUserListElement of document.querySelectorAll('.admin-user-list:not(.no-autoinit)')) {
+ new AdminUserList(adminUserListElement);
+ }
+ }
+
+ constructor(listContainerElement, options = {}) {
+ super(listContainerElement, options);
+ this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
+ }
+
+ get item() {
+ return `
+