mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-10-12 15:04:04 +00:00
Merge branch 'feature-77588/AnwesenheitenSprint252' into demo
This commit is contained in:
@@ -7,6 +7,7 @@ use \DateTime as DateTime;
|
||||
use \DateTimeZone as DateTimeZone;
|
||||
use \DateInterval as DateInterval;
|
||||
use \DatePeriod as DatePeriod;
|
||||
use CI3_Events as Events;
|
||||
|
||||
class StundenplanLib
|
||||
{
|
||||
@@ -143,7 +144,7 @@ class StundenplanLib
|
||||
return $stundenplan_data;
|
||||
$stundenplan_data = getData($stundenplan_data) ?? [];
|
||||
|
||||
$function_error = $this->expandObjectInformation($stundenplan_data);
|
||||
$function_error = $this->expandObjectInformation($stundenplan_data, true);
|
||||
if ($function_error)
|
||||
return $function_error;
|
||||
|
||||
@@ -303,7 +304,7 @@ class StundenplanLib
|
||||
return success($lektoren);
|
||||
}
|
||||
|
||||
public function expandObjectInformation($data)
|
||||
public function expandObjectInformation($data, $callExtensionsEvent = false)
|
||||
{
|
||||
$this->_ci =& get_instance();
|
||||
|
||||
@@ -392,6 +393,20 @@ class StundenplanLib
|
||||
$item->lektor = $lektor_obj_array;
|
||||
|
||||
}
|
||||
|
||||
// info retrieved from extensions might not be necessary for some stundenplan use cases so the event
|
||||
// will be gated behind this flag
|
||||
|
||||
if($callExtensionsEvent) {
|
||||
Events::trigger(
|
||||
'extendStundenplanData',
|
||||
function & () use (&$data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function fetchFerienTageEvents($start_date, $end_date, $studiengang_kz)
|
||||
|
||||
@@ -840,8 +840,11 @@ html {
|
||||
color: var(--fhc-light);
|
||||
}
|
||||
|
||||
/* the bootstrap opacity 0.5 reaches 2.9:1 on the blue header, 0.75 reaches 4.5:1 (WCAG 1.4.11) */
|
||||
#cis-main .modal-header .btn-close{
|
||||
filter: invert(1);
|
||||
--bs-btn-close-opacity: 0.75;
|
||||
--bs-btn-close-hover-opacity: 1;
|
||||
}
|
||||
|
||||
#cis-main .modal-footer {
|
||||
|
||||
@@ -121,8 +121,9 @@
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
/* contrast: #777 reaches 4.48:1 on the odd and 4:1 on the even rows (#f2f2f2), #6c6c6c 5.3:1 and 4.7:1 */
|
||||
.tabulator-row.tabulator-unselectable:not(.tabulator-calcs) {
|
||||
color: #777 !important;
|
||||
color: #6c6c6c !important;
|
||||
}
|
||||
|
||||
.tabulator-cell .btn {
|
||||
@@ -156,3 +157,23 @@
|
||||
color: #fff;
|
||||
background: #1d68cd;
|
||||
}
|
||||
|
||||
/* contrast (WCAG 1.4.11): tabulator_simple draws the inactive sort arrow in #bbb (1.9:1) and the
|
||||
* placeholder in #ccc (1.6:1). #8f8f8f (3.2:1) is close to the grey of the active arrow, so the
|
||||
* active arrow gets the primary color (6.8:1) */
|
||||
.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter .tabulator-arrow,
|
||||
.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="none"] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow {
|
||||
border-bottom-color: #8f8f8f;
|
||||
}
|
||||
|
||||
.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="ascending"] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow {
|
||||
border-bottom-color: var(--fhc-primary, #006095);
|
||||
}
|
||||
|
||||
.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="descending"] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow {
|
||||
border-top-color: var(--fhc-primary, #006095);
|
||||
}
|
||||
|
||||
.tabulator .tabulator-tableholder .tabulator-placeholder .tabulator-placeholder-contents {
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
@@ -188,6 +188,9 @@
|
||||
--fhc-light: var(--fhc-white-50);
|
||||
|
||||
--fhc-cis-menu-lvl-1-color: var(--fhc-white-50);
|
||||
|
||||
/* input borders, 3:1 against the background and the tinted card headers (#f8f8f9) */
|
||||
--fhc-input-border: #868e96;
|
||||
}
|
||||
|
||||
:root.dark {
|
||||
@@ -233,6 +236,8 @@
|
||||
--fhc-dark: var(--fhc-black-50);
|
||||
--fhc-light: var(--fhc-white-70);
|
||||
|
||||
/* input borders, 3:1 against the background */
|
||||
--fhc-input-border: #7c8791;
|
||||
}
|
||||
|
||||
:root.purple {
|
||||
@@ -313,12 +318,13 @@ html.dark .border-primary {
|
||||
border-color: var(--fhc-primary) !important;
|
||||
}
|
||||
|
||||
/* fhc danger*/
|
||||
/* fhc danger: --fhc-danger is a light red for text and borders on the dark background. White text
|
||||
* on it reaches 1.2:1, the backgrounds use the dark red (6.5:1) */
|
||||
html.dark .bg-danger,
|
||||
html.dark .btn-danger,
|
||||
html.dark .btn-outline-danger {
|
||||
background-color: var(--fhc-danger) !important;
|
||||
border-color: var(--fhc-danger) !important;
|
||||
background-color: var(--fhc-red-60) !important;
|
||||
border-color: var(--fhc-red-60) !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
@@ -335,6 +341,29 @@ html.dark .border-danger {
|
||||
border-color: var(--fhc-danger) !important;
|
||||
}
|
||||
|
||||
/* bootstrap draws btn-outline-secondary in #6c757d: 4.3:1 on the light dialog footer (#f6f6f6).
|
||||
* --fhc-gray-30 reaches 5.4:1 there, the white hover text 5.9:1 */
|
||||
html.light .btn-outline-secondary {
|
||||
--bs-btn-color: var(--fhc-gray-30);
|
||||
--bs-btn-border-color: var(--fhc-gray-30);
|
||||
--bs-btn-hover-bg: var(--fhc-gray-30);
|
||||
--bs-btn-hover-border-color: var(--fhc-gray-30);
|
||||
--bs-btn-active-bg: var(--fhc-gray-30);
|
||||
--bs-btn-active-border-color: var(--fhc-gray-30);
|
||||
}
|
||||
|
||||
/* bootstrap keeps #6c757d for btn-outline-secondary in the dark theme: 2.4:1 on the dark tables and dialogs */
|
||||
html.dark .btn-outline-secondary {
|
||||
--bs-btn-color: var(--fhc-white-90);
|
||||
--bs-btn-border-color: var(--fhc-white-90);
|
||||
--bs-btn-hover-color: var(--fhc-black-30);
|
||||
--bs-btn-hover-bg: var(--fhc-white-90);
|
||||
--bs-btn-hover-border-color: var(--fhc-white-90);
|
||||
--bs-btn-active-color: var(--fhc-black-30);
|
||||
--bs-btn-active-bg: var(--fhc-white-90);
|
||||
--bs-btn-active-border-color: var(--fhc-white-90);
|
||||
}
|
||||
|
||||
|
||||
html.dark .tabulator,
|
||||
html.dark .tabulator .tabulator-header,
|
||||
@@ -355,6 +384,52 @@ html.dark .tabulator .tabulator-header .tabulator-col:hover {
|
||||
background-color: var(--fhc-tertiary) !important;
|
||||
}
|
||||
|
||||
/* the active sort arrow of tabulator_simple (#666) reaches 2:1 on the dark header */
|
||||
html.dark .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="ascending"] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow {
|
||||
border-bottom-color: var(--fhc-text);
|
||||
}
|
||||
|
||||
html.dark .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="descending"] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow {
|
||||
border-top-color: var(--fhc-text);
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
html.dark .tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover {
|
||||
border-bottom-color: var(--fhc-text);
|
||||
border-top-color: var(--fhc-text);
|
||||
}
|
||||
}
|
||||
|
||||
/* the group toggle arrow of tabulator_simple (#666) reaches 2:1 on the dark rows */
|
||||
html.dark .tabulator .tabulator-row.tabulator-group:not(.tabulator-group-visible) .tabulator-arrow {
|
||||
border-left-color: var(--fhc-text);
|
||||
}
|
||||
|
||||
html.dark .tabulator .tabulator-row.tabulator-group.tabulator-group-visible .tabulator-arrow {
|
||||
border-top-color: var(--fhc-text);
|
||||
}
|
||||
|
||||
/* the footer stays white otherwise: the page buttons get the white button text of the dark color scheme */
|
||||
html.dark .tabulator .tabulator-footer {
|
||||
background-color: var(--fhc-tertiary);
|
||||
border-top-color: var(--fhc-border);
|
||||
color: var(--fhc-text);
|
||||
}
|
||||
|
||||
html.dark .tabulator .tabulator-footer .tabulator-page {
|
||||
background: transparent;
|
||||
border-color: var(--fhc-white-90);
|
||||
color: var(--fhc-text);
|
||||
}
|
||||
|
||||
html.dark .tabulator .tabulator-footer .tabulator-page.active {
|
||||
color: var(--fhc-red-30);
|
||||
}
|
||||
|
||||
html.dark .tabulator .tabulator-tableholder .tabulator-placeholder .tabulator-placeholder-contents {
|
||||
color: var(--fhc-white-90);
|
||||
}
|
||||
|
||||
.p-paginator{
|
||||
background-color: var(--fhc-background) !important;
|
||||
}
|
||||
@@ -376,4 +451,35 @@ html.dark .tabulator .tabulator-header .tabulator-col:hover {
|
||||
|
||||
.p-link:focus {
|
||||
box-shadow: 0 0 0 0.2rem rgba(var(--fhc-primary), 0.5) !important;
|
||||
}
|
||||
|
||||
/* input borders: 3:1 against the background (WCAG 1.4.11), the bootstrap, primevue and datepicker defaults
|
||||
* reach 1.3 - 1.9:1. Focus and checked states of the libraries stay */
|
||||
.form-control,
|
||||
.form-select,
|
||||
.form-check-input,
|
||||
.p-inputtext,
|
||||
.p-inputtext:enabled:hover:not(:focus),
|
||||
.p-dropdown,
|
||||
.p-dropdown:not(.p-disabled):hover:not(.p-focus),
|
||||
.p-multiselect,
|
||||
.p-multiselect:not(.p-disabled):hover:not(.p-focus),
|
||||
.p-checkbox .p-checkbox-box,
|
||||
.p-radiobutton .p-radiobutton-box {
|
||||
border-color: var(--fhc-input-border, #868e96);
|
||||
}
|
||||
|
||||
/* the datepicker css loads after the theme, html raises the specificity */
|
||||
html .dp__theme_light,
|
||||
html .dp__theme_dark {
|
||||
--dp-border-color: var(--fhc-input-border, #868e96);
|
||||
--dp-border-color-hover: var(--fhc-border-highlight, #495057);
|
||||
}
|
||||
|
||||
/* the light datepicker (also in the dark cis4 theme) draws the days of other months in #c0c4cc (1.8:1),
|
||||
* the icons in #959595 (3:1) and the selected day in #f8f5f5 on #1976d2 (4.2:1) */
|
||||
html .dp__theme_light {
|
||||
--dp-secondary-color: #6c6c6c;
|
||||
--dp-icon-color: #6c757d;
|
||||
--dp-primary-text-color: #fff;
|
||||
}
|
||||
@@ -73,6 +73,7 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// opacity 0.5 reaches 2.4:1 on the blue cis4 modal header, 0.75 reaches 3.6:1 (WCAG 1.4.11)
|
||||
getExpandButtonStyles() {
|
||||
const hovered = this.expandBtnHovered;
|
||||
const focused = this.expandBtnFocused;
|
||||
@@ -85,12 +86,11 @@ export default {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
font-size: 1em;
|
||||
opacity: 0.5;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
transition: opacity 0.15s ease;
|
||||
opacity: ${focused ? '1' : hovered ? '0.75' : '0.5'};
|
||||
opacity: ${focused || hovered ? '1' : '0.75'};
|
||||
outline: ${focused ? '1px solid currentColor' : 'none'};
|
||||
outline-offset: 2px;`
|
||||
}
|
||||
|
||||
@@ -66,6 +66,24 @@ export default {
|
||||
return "d-none d-xl-grid";
|
||||
}
|
||||
},
|
||||
// link into the FHC-Core-Anwesenheiten tool
|
||||
// digi_anw_data is attached per event by the extension's `extendStundenplanData` listener
|
||||
anwLink() {
|
||||
const d = this.event && this.event.digi_anw_data;
|
||||
if (!d || !d.stg_kz || !d.lv_id || !d.sem_kurzbz)
|
||||
return null;
|
||||
const base = FHC_JS_DATA_STORAGE_OBJECT.app_root
|
||||
+ FHC_JS_DATA_STORAGE_OBJECT.ci_router
|
||||
+ '/extensions/FHC-Core-Anwesenheiten/';
|
||||
return base
|
||||
+ `?stg_kz=${encodeURIComponent(d.stg_kz)}`
|
||||
+ `&sem=${encodeURIComponent(d.sem ?? '')}`
|
||||
+ `&lvid=${encodeURIComponent(d.lv_id)}`
|
||||
+ `&sem_kurzbz=${encodeURIComponent(d.sem_kurzbz)}`;
|
||||
},
|
||||
anwLinkTitle() {
|
||||
return this.$p.t('global/anwKontrolleOeffnen');
|
||||
},
|
||||
},
|
||||
template: /*html*/`
|
||||
<div
|
||||
@@ -96,6 +114,21 @@ export default {
|
||||
... +{{ event.lektor.length - 3 }}
|
||||
</span>
|
||||
</div>
|
||||
<a
|
||||
v-if="anwLink"
|
||||
:href="anwLink"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
class="d-flex align-items-center flex-shrink-0"
|
||||
style="margin-right: 4px"
|
||||
:title="anwLinkTitle"
|
||||
:aria-label="anwLinkTitle"
|
||||
draggable="false"
|
||||
@click.stop
|
||||
@mousedown.stop
|
||||
>
|
||||
<i class="fa fa-arrow-up-right-from-square fs-5" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
`,
|
||||
}
|
||||
|
||||
@@ -49,6 +49,20 @@ export default {
|
||||
return this.event.ende;
|
||||
}
|
||||
return numberPadding(this.event.ende.getHours()) + ":" + numberPadding(this.event.ende.getMinutes());
|
||||
},
|
||||
// Deep link into the attendance tool; only present when the anw extension wrote into digi_anw_data
|
||||
anwLink: function () {
|
||||
const d = this.event && this.event.digi_anw_data;
|
||||
if (!d || !d.stg_kz || !d.lv_id || !d.sem_kurzbz)
|
||||
return null;
|
||||
const base = FHC_JS_DATA_STORAGE_OBJECT.app_root
|
||||
+ FHC_JS_DATA_STORAGE_OBJECT.ci_router
|
||||
+ '/extensions/FHC-Core-Anwesenheiten/';
|
||||
return base
|
||||
+ `?stg_kz=${encodeURIComponent(d.stg_kz)}`
|
||||
+ `&sem=${encodeURIComponent(d.sem ?? '')}`
|
||||
+ `&lvid=${encodeURIComponent(d.lv_id)}`
|
||||
+ `&sem_kurzbz=${encodeURIComponent(d.sem_kurzbz)}`;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -160,6 +174,16 @@ export default {
|
||||
}}</th>
|
||||
<td>{{event.organisationseinheit}}</td>
|
||||
</tr>
|
||||
<tr v-if="anwLink">
|
||||
<th>{{
|
||||
$p.t('global','anwKontrolle')?
|
||||
$p.t('global','anwKontrolle')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>
|
||||
<a :href="anwLink" target="_blank" rel="noopener" :aria-label="$p.t('global','anwKontrolleOeffnen')" :title="$p.t('global','anwKontrolleOeffnen')"><i class="fa fa-arrow-up-right-from-square me-1" style="color:#00649C" aria-hidden="true"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<lv-menu v-if="lvMenu.length && $route.name === 'MyLvPlan'" :containerStyles="['p-0']" :rowStyles="['m-0']" :menu="lvMenu" />
|
||||
|
||||
@@ -106,6 +106,13 @@ export const CoreFilterCmpt = {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
// fields of the columns a preset is allowed to handle. Give the constant
|
||||
// columns here if the table builds dynamic columns at runtime. An empty
|
||||
// array gives the preset every column of the table.
|
||||
presetColumns: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
@@ -942,6 +949,10 @@ export const CoreFilterCmpt = {
|
||||
return res;
|
||||
}, {});
|
||||
},
|
||||
isColumnInPresetScope(columnField) {
|
||||
if (!this.$props.presetColumns.length) return true;
|
||||
return this.$props.presetColumns.includes(columnField);
|
||||
},
|
||||
afterTablePresetApplied(preset) {
|
||||
this.selectedFields = [...preset.displayedColumns];
|
||||
this.appliedPreset = { ...preset };
|
||||
@@ -973,6 +984,7 @@ export const CoreFilterCmpt = {
|
||||
|
||||
const displayedColumns = this.tabulator.columnManager.columns
|
||||
.filter((column) => column.field !== "collapse")
|
||||
.filter((column) => this.isColumnInPresetScope(column.field))
|
||||
.filter((column) => column.visible)
|
||||
.map((column) => column.field);
|
||||
|
||||
@@ -1029,12 +1041,13 @@ export const CoreFilterCmpt = {
|
||||
});
|
||||
|
||||
const activeSort = this.tabulator.getSorters()[0];
|
||||
const sort = activeSort
|
||||
? {
|
||||
column: activeSort.field,
|
||||
direction: activeSort.dir,
|
||||
}
|
||||
: null;
|
||||
const sort =
|
||||
activeSort && this.isColumnInPresetScope(activeSort.field)
|
||||
? {
|
||||
column: activeSort.field,
|
||||
direction: activeSort.dir,
|
||||
}
|
||||
: null;
|
||||
if (
|
||||
sort?.column !== this.appliedPreset.sort?.column ||
|
||||
sort?.direction !== this.appliedPreset.sort?.direction
|
||||
@@ -1148,6 +1161,7 @@ export const CoreFilterCmpt = {
|
||||
:presetsId="$props.presetsId"
|
||||
:tabulator="tabulator"
|
||||
:generalPresets="$props.generalPresets"
|
||||
:presetColumns="$props.presetColumns"
|
||||
ref="tablePresets"
|
||||
class="card-body collapse"
|
||||
></table-presets>
|
||||
|
||||
@@ -26,6 +26,9 @@ export default {
|
||||
presetsId: { type: String },
|
||||
tabulator: { type: Object },
|
||||
generalPresets: { type: Array, default: [] },
|
||||
// fields of the columns the preset is allowed to handle. An empty array
|
||||
// gives the preset every column of the table.
|
||||
presetColumns: { type: Array, default: [] },
|
||||
},
|
||||
emits: ["tablePresetApplied"],
|
||||
data: function () {
|
||||
@@ -162,6 +165,10 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isInPresetScope(columnField) {
|
||||
if (!this.$props.presetColumns.length) return true;
|
||||
return this.$props.presetColumns.includes(columnField);
|
||||
},
|
||||
getPresetIndex() {
|
||||
return this.presetIndexBeingApplied;
|
||||
},
|
||||
@@ -227,9 +234,9 @@ export default {
|
||||
}
|
||||
},
|
||||
generateNewPreset() {
|
||||
const columns = this.tabulator.columnManager.columns.filter(
|
||||
(column) => column.field !== "collapse",
|
||||
);
|
||||
const columns = this.tabulator.columnManager.columns
|
||||
.filter((column) => column.field !== "collapse")
|
||||
.filter((column) => this.isInPresetScope(column.field));
|
||||
|
||||
const displayedColumns = columns
|
||||
.filter((column) => column.visible)
|
||||
@@ -251,12 +258,13 @@ export default {
|
||||
);
|
||||
|
||||
const activeSort = this.tabulator.getSorters()[0];
|
||||
const sort = activeSort
|
||||
? {
|
||||
column: activeSort.field,
|
||||
direction: activeSort.dir,
|
||||
}
|
||||
: null;
|
||||
const sort =
|
||||
activeSort && this.isInPresetScope(activeSort.field)
|
||||
? {
|
||||
column: activeSort.field,
|
||||
direction: activeSort.dir,
|
||||
}
|
||||
: null;
|
||||
|
||||
this.newPreset = {
|
||||
displayedColumns,
|
||||
@@ -325,8 +333,11 @@ export default {
|
||||
preset.displayedColumns.length;
|
||||
preset.displayedColumns = preset.displayedColumns.filter(
|
||||
(columnField) => {
|
||||
return validColumns.some(
|
||||
(column) => column.field === columnField,
|
||||
return (
|
||||
this.isInPresetScope(columnField) &&
|
||||
validColumns.some(
|
||||
(column) => column.field === columnField,
|
||||
)
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -365,10 +376,11 @@ export default {
|
||||
|
||||
if (preset.sort) {
|
||||
if (
|
||||
!this.isInPresetScope(preset.sort.column) ||
|
||||
!validColumns.some(
|
||||
(column) =>
|
||||
column.field === preset.sort.column &&
|
||||
column.headerSort,
|
||||
column.headerSort !== false,
|
||||
)
|
||||
) {
|
||||
preset.sort = null;
|
||||
@@ -407,7 +419,10 @@ export default {
|
||||
window.localStorage["tabulatorPreset-" + this.$props.presetsId] =
|
||||
preset.id ? "custom:" + preset.id : "general:" + preset.name;
|
||||
|
||||
this.$props.tabulator.modules.tablePresets.applyPreset(preset);
|
||||
this.$props.tabulator.modules.tablePresets.applyPreset(
|
||||
preset,
|
||||
this.$props.presetColumns,
|
||||
);
|
||||
|
||||
this.$emit("tablePresetApplied", { preset });
|
||||
|
||||
|
||||
@@ -8,27 +8,36 @@ export default class TablePresetsModule extends Module {
|
||||
super(table);
|
||||
}
|
||||
|
||||
applyPreset(preset) {
|
||||
let columnsConfig = this.table.options.columns;
|
||||
let reorderedColumnsConfig = [];
|
||||
preset.displayedColumns.forEach((columnField) => {
|
||||
let columnConfig = columnsConfig.find(
|
||||
(column) => column.field === columnField,
|
||||
);
|
||||
if (!columnConfig) return;
|
||||
columnConfig.visible = true;
|
||||
reorderedColumnsConfig.push(columnConfig);
|
||||
});
|
||||
|
||||
let hiddenColumnsConfig = columnsConfig
|
||||
.filter((column) => !preset.displayedColumns.includes(column.field))
|
||||
.map((column) => {
|
||||
column.visible = false;
|
||||
return column;
|
||||
// presetColumns limits the preset to the given column fields. A table with dynamic
|
||||
// columns gives the fields of its constant columns here.
|
||||
applyPreset(preset, presetColumns = []) {
|
||||
if (presetColumns.length) {
|
||||
this.applyColumnsInScope(preset, presetColumns);
|
||||
} else {
|
||||
let columnsConfig = this.table.options.columns;
|
||||
let reorderedColumnsConfig = [];
|
||||
preset.displayedColumns.forEach((columnField) => {
|
||||
let columnConfig = columnsConfig.find(
|
||||
(column) => column.field === columnField,
|
||||
);
|
||||
if (!columnConfig) return;
|
||||
columnConfig.visible = true;
|
||||
reorderedColumnsConfig.push(columnConfig);
|
||||
});
|
||||
this.table.setColumns(
|
||||
reorderedColumnsConfig.concat(hiddenColumnsConfig),
|
||||
);
|
||||
|
||||
let hiddenColumnsConfig = columnsConfig
|
||||
.filter(
|
||||
(column) =>
|
||||
!preset.displayedColumns.includes(column.field),
|
||||
)
|
||||
.map((column) => {
|
||||
column.visible = false;
|
||||
return column;
|
||||
});
|
||||
this.table.setColumns(
|
||||
reorderedColumnsConfig.concat(hiddenColumnsConfig),
|
||||
);
|
||||
}
|
||||
|
||||
this.table.clearHeaderFilter();
|
||||
if (preset.headerFilters) {
|
||||
@@ -61,4 +70,44 @@ export default class TablePresetsModule extends Module {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// The preset orders and hides the columns of the scope only. A column outside the
|
||||
// scope keeps its position, because the table does not show it in every state.
|
||||
applyColumnsInScope(preset, presetColumns) {
|
||||
const displayedColumns = preset.displayedColumns ?? [];
|
||||
|
||||
// a displayed column takes the rank of the preset. A column that the preset
|
||||
// hides has no rank and keeps the current order at the end of its block.
|
||||
const rank = (columnConfig) => {
|
||||
const index = displayedColumns.indexOf(columnConfig.field);
|
||||
return index === -1 ? displayedColumns.length : index;
|
||||
};
|
||||
|
||||
let columnsConfig = [];
|
||||
let scopeBlock = [];
|
||||
|
||||
// the sort runs for each block of neighbouring scope columns. This way a scope
|
||||
// column never moves over a column outside the scope.
|
||||
const addScopeBlock = () => {
|
||||
scopeBlock.sort((a, b) => rank(a) - rank(b));
|
||||
columnsConfig = columnsConfig.concat(scopeBlock);
|
||||
scopeBlock = [];
|
||||
};
|
||||
|
||||
this.table.getColumnDefinitions().forEach((columnConfig) => {
|
||||
if (!presetColumns.includes(columnConfig.field)) {
|
||||
addScopeBlock();
|
||||
columnsConfig.push(columnConfig);
|
||||
return;
|
||||
}
|
||||
|
||||
columnConfig.visible = displayedColumns.includes(
|
||||
columnConfig.field,
|
||||
);
|
||||
scopeBlock.push(columnConfig);
|
||||
});
|
||||
addScopeBlock();
|
||||
|
||||
this.table.setColumns(columnsConfig);
|
||||
}
|
||||
}
|
||||
|
||||
+1462
-60
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user