Merge branch '735-modal-dom-wird-beim-schliessen-in-hauptseite-eingehangt' of gitlab2.rz.ifi.lmu.de:uni2work/uni2work into 735-modal-dom-wird-beim-schliessen-in-hauptseite-eingehangt

This commit is contained in:
Sarah Vaupel 2021-12-03 00:23:13 +01:00
commit 1d734f8d77
7 changed files with 188 additions and 1 deletions

View File

@ -0,0 +1,22 @@
export class FrontendTooltips {
static addToolTip(element, text) {
let tooltipWrap = document.createElement('span');
tooltipWrap.className = 'tooltip';
let tooltipContent = document.createElement('span');
tooltipContent.className = 'tooltip__content';
tooltipContent.appendChild(document.createTextNode(text));
tooltipWrap.append(tooltipContent);
let tooltipHandle = document.createElement('span');
tooltipHandle.className = 'tooltip__handle';
let icon = document.createElement('i');
icon.classList.add('fas');
icon.classList.add('fa-question-circle');
tooltipHandle.append(icon);
tooltipWrap.append(tooltipHandle);
element.append(tooltipWrap);
}
}

17
frontend/src/messages.js Normal file
View File

@ -0,0 +1,17 @@
export class Translations {
static translations = {
'checkrangeTooltip' : {
'de' : 'Shift-Klick, um mehrere Zellen zu markieren.',
'en' : 'Shift-click to mark multiple cells.',
},
};
static getTranslation(key, language) {
let json = Translations.translations[key];
if(language === 'en') {
return json.en;
} else {
return json.de;
}
}
};

View File

@ -21,6 +21,8 @@ export class CheckAll {
_tableIndices;
_lastCheckedCell = null;
constructor(element, app) {
if (!element) {
throw new Error('Check All utility cannot be setup without an element!');
@ -41,7 +43,9 @@ export class CheckAll {
if (DEBUG_MODE > 0)
console.log(this._columns);
this._findCheckboxColumns().forEach(columnId => this._checkAllColumns.push(new CheckAllColumn(this._element, app, this._columns[columnId], this._eventManager)));
let checkboxColumns = this._findCheckboxColumns();
checkboxColumns.forEach(columnId => this._checkAllColumns.push(new CheckAllColumn(this._element, app, this._columns[columnId])));
// mark initialized
this._element.classList.add(CHECK_ALL_INITIALIZED_CLASS);
@ -116,6 +120,7 @@ class CheckAllColumn {
this._checkAllCheckbox = document.createElement('input');
this._checkAllCheckbox.setAttribute('type', 'checkbox');
this._checkAllCheckbox.setAttribute('id', this._checkboxId);
th.insertBefore(this._checkAllCheckbox, th.firstChild);
// set up new checkbox

View File

@ -0,0 +1,125 @@
import { Utility } from '../../core/utility';
import { TableIndices } from '../../lib/table/table';
import { FrontendTooltips } from '../../lib/tooltips/frontend-tooltips';
import { Translations } from '../../messages';
const CHECKRANGE_INITIALIZED_CLASS = 'checkrange--initialized';
const CHECKBOX_SELECTOR = '[type="checkbox"]';
@Utility({
selector: 'table:not([uw-no-check-all])',
})
export class CheckRange {
_lastCheckedCell = null;
_element;
_tableIndices
_columns = new Array();
constructor(element) {
if(!element) {
throw new Error('Check Range Utility cannot be setup without an element');
}
this._element = element;
if (this._element.classList.contains(CHECKRANGE_INITIALIZED_CLASS))
return false;
this._tableIndices = new TableIndices(this._element);
this._gatherColumns();
let checkboxColumns = this._findCheckboxColumns();
checkboxColumns.forEach(columnId => this._setUpShiftClickOnColumn(columnId));
this._element.classList.add(CHECKRANGE_INITIALIZED_CLASS);
}
_setUpShiftClickOnColumn(columnId) {
if (!this._columns || columnId < 0 || columnId >= this._columns.length) return;
let column = this._columns[columnId];
let language = document.documentElement.lang;
let toolTipMessage = Translations.getTranslation('checkrangeTooltip', language);
FrontendTooltips.addToolTip(column[0], toolTipMessage);
column.forEach(el => el.addEventListener('click', (ev) => {
if(ev.shiftKey && this.lastCheckedCell !== null) {
let lastClickedIndex = this._tableIndices.rowIndex(this._lastCheckedCell);
let currentCellIndex = this._tableIndices.rowIndex(el);
let cell = this._columns[columnId][currentCellIndex];
if(currentCellIndex > lastClickedIndex)
this._handleCellsInBetween(cell, lastClickedIndex, currentCellIndex, columnId);
else
this._handleCellsInBetween(cell, currentCellIndex, lastClickedIndex, columnId);
} else {
this._lastCheckedCell = el;
}
}));
}
_handleCellsInBetween(cell, firstRowIndex, lastRowIndex, columnId) {
if(this._isChecked(cell)) {
this._uncheckMultipleCells(firstRowIndex, lastRowIndex, columnId);
} else {
this._checkMultipleCells(firstRowIndex, lastRowIndex, columnId);
}
}
_checkMultipleCells(firstRowIndex, lastRowIndex, columnId) {
for(let i=firstRowIndex; i<=lastRowIndex; i++) {
let cell = this._columns[columnId][i];
if (cell.tagName !== 'TH') {
cell.querySelector(CHECKBOX_SELECTOR).checked = true;
}
}
}
_uncheckMultipleCells(firstRowIndex, lastRowIndex, columnId) {
for(let i=firstRowIndex; i<=lastRowIndex; i++) {
let cell = this._columns[columnId][i];
if (cell.tagName !== 'TH') {
cell.querySelector(CHECKBOX_SELECTOR).checked = false;
}
}
}
_isChecked(cell) {
return cell.querySelector(CHECKBOX_SELECTOR).checked;
}
_gatherColumns() {
for (const rowIndex of Array(this._tableIndices.maxRow + 1).keys()) {
for (const colIndex of Array(this._tableIndices.maxCol + 1).keys()) {
const cell = this._tableIndices.getCell(rowIndex, colIndex);
if (!cell)
continue;
if (!this._columns[colIndex])
this._columns[colIndex] = new Array();
this._columns[colIndex][rowIndex] = cell;
}
}
}
_findCheckboxColumns() {
let checkboxColumnIds = new Array();
this._columns.forEach((col, i) => {
if (this._isCheckboxColumn(col)) {
checkboxColumnIds.push(i);
}
});
return checkboxColumnIds;
}
_isCheckboxColumn(col) {
return col.every(cell => cell.tagName == 'TH' || cell.querySelector(CHECKBOX_SELECTOR))
&& col.some(cell => cell.querySelector(CHECKBOX_SELECTOR));
}
}

View File

@ -0,0 +1,5 @@
# Checkrange Utility
Is set on the table header of a specific row. Remembers the last checked checkbox. When the users shift-clicks another checkbox in the same row, all checkboxes in between are also checked.
# Attribute: table:not([uw-no-check-all]
(will be setup on all tables which use the util check-all)

View File

@ -2,6 +2,7 @@ import { Checkbox } from './checkbox';
import { FileInput } from './file-input';
import { FileMaxSize } from './file-max-size';
import { Password } from './password';
import { CheckRange } from './checkrange';
import './inputs.sass';
import './radio-group.sass';
@ -11,4 +12,5 @@ export const InputUtils = [
FileInput,
FileMaxSize,
Password,
CheckRange,
];

View File

@ -167,6 +167,15 @@ postUsersR = do
-- Set.foldr (\needle acc -> acc E.||. (user E.^. UserDisplayName) `E.hasInfix` needle) eFalse (criterion :: Set.Set Text)
E.any (\c -> user E.^. UserDisplayName `E.hasInfix` E.val c) criteria
)
, ( "user-ident", FilterColumn $ \user criterion -> case getLast (criterion :: Last Text) of
Nothing -> E.val True :: E.SqlExpr (E.Value Bool)
Just needle -> (E.castString (user E.^. UserIdent) `E.ilike` (E.%) E.++. E.val needle E.++. (E.%))
)
, ( "user-email", FilterColumn $ \user criterion -> case getLast (criterion :: Last Text) of
Nothing -> E.val True :: E.SqlExpr (E.Value Bool)
Just needle -> (E.castString (user E.^. UserEmail) `E.ilike` (E.%) E.++. E.val needle E.++. (E.%))
E.||. (E.castString (user E.^. UserDisplayEmail) `E.ilike` (E.%) E.++. E.val needle E.++. (E.%))
)
, ( "matriculation", FilterColumn $ \user (criteria :: Set.Set Text) -> if
| Set.null criteria -> E.true -- TODO: why can this be eFalse and work still?
| otherwise -> E.any (\c -> user E.^. UserMatrikelnummer `E.hasInfix` E.val c) criteria
@ -192,6 +201,8 @@ postUsersR = do
]
, dbtFilterUI = \mPrev -> mconcat
[ prismAForm (singletonFilter "user-search") mPrev $ aopt textField (fslI MsgName)
, prismAForm (singletonFilter "user-ident") mPrev $ aopt textField (fslI MsgAdminUserIdent)
, prismAForm (singletonFilter "user-email") mPrev $ aopt textField (fslI MsgAdminUserEmail)
-- , prismAForm (singletonFilter "matriculation" ) mPrev $ aopt textField (fslI MsgTableMatrikelNr)
, prismAForm (singletonFilter "matriculation") mPrev $ aopt matriculationField (fslI MsgTableMatrikelNr)
, prismAForm (singletonFilter "auth-ldap" . maybePrism _PathPiece) mPrev $ aopt (lift `hoistField` selectFieldList [(MsgAuthPWHash "", False), (MsgAuthLDAP, True)]) (fslI MsgAuthMode)