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:
commit
1d734f8d77
22
frontend/src/lib/tooltips/frontend-tooltips.js
Normal file
22
frontend/src/lib/tooltips/frontend-tooltips.js
Normal 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
17
frontend/src/messages.js
Normal 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -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
|
||||
|
||||
125
frontend/src/utils/inputs/checkrange.js
Normal file
125
frontend/src/utils/inputs/checkrange.js
Normal 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));
|
||||
}
|
||||
}
|
||||
5
frontend/src/utils/inputs/checkrange.md
Normal file
5
frontend/src/utils/inputs/checkrange.md
Normal 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)
|
||||
@ -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,
|
||||
];
|
||||
|
||||
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user