diff --git a/templates/Individuals/index.php b/templates/Individuals/index.php
index 4930899..84ed353 100644
--- a/templates/Individuals/index.php
+++ b/templates/Individuals/index.php
@@ -25,6 +25,10 @@ echo $this->element('genericElements/IndexTable/index_table', [
'data' => '',
'searchKey' => 'value',
'allowFilering' => true
+ ],
+ [
+ 'type' => 'table_action',
+ 'table_setting_id' => 'individual_index',
]
]
],
@@ -90,4 +94,4 @@ echo $this->element('genericElements/IndexTable/index_table', [
]
]);
echo '';
-?>
+?>
\ No newline at end of file
diff --git a/templates/Organisations/index.php b/templates/Organisations/index.php
index 4a98718..0448c77 100644
--- a/templates/Organisations/index.php
+++ b/templates/Organisations/index.php
@@ -26,6 +26,10 @@ echo $this->element('genericElements/IndexTable/index_table', [
'data' => '',
'searchKey' => 'value',
'allowFilering' => true
+ ],
+ [
+ 'type' => 'table_action',
+ 'table_setting_id' => 'organisation_index',
]
]
],
diff --git a/templates/element/genericElements/IndexTable/headers.php b/templates/element/genericElements/IndexTable/headers.php
index e38714a..8366449 100644
--- a/templates/element/genericElements/IndexTable/headers.php
+++ b/templates/element/genericElements/IndexTable/headers.php
@@ -22,7 +22,8 @@
}
$headersHtml .= sprintf(
- '
%s | ',
+ '%s | ',
+ h(\Cake\Utility\Inflector::variable(!empty($header['name']) ? $header['name'] : \Cake\Utility\Inflector::humanize($header['data_path']))),
$header_data
);
}
diff --git a/templates/element/genericElements/IndexTable/index_table.php b/templates/element/genericElements/IndexTable/index_table.php
index fc2a066..a893b90 100644
--- a/templates/element/genericElements/IndexTable/index_table.php
+++ b/templates/element/genericElements/IndexTable/index_table.php
@@ -59,6 +59,7 @@
'/genericElements/ListTopBar/scaffold',
[
'data' => $data['top_bar'],
+ 'table_data' => $data,
'tableRandomValue' => $tableRandomValue
]
);
diff --git a/templates/element/genericElements/IndexTable/row.php b/templates/element/genericElements/IndexTable/row.php
index c019110..b426534 100644
--- a/templates/element/genericElements/IndexTable/row.php
+++ b/templates/element/genericElements/IndexTable/row.php
@@ -31,7 +31,7 @@
);
}
$rowHtml .= sprintf(
- '%s | ',
+ '%s | ',
(empty($field['id'])) ? '' : sprintf('id="%s"', $field['id']),
(empty($field['class'])) ? '' : sprintf(' class="%s"', $field['class']),
(empty($field['style'])) ? '' : sprintf(' style="%s"', $field['style']),
@@ -42,6 +42,10 @@
h(implode(', ', $field['data_path'])) :
(h($field['data_path']))
),
+ sprintf(
+ ' data-columnname="%s"',
+ h(\Cake\Utility\Inflector::variable(!empty($field['name']) ? $field['name'] : \Cake\Utility\Inflector::humanize($field['data_path'])))
+ ),
(empty($field['encode_raw_value']) || empty($field['data_path'])) ? '' : sprintf(' data-value="%s"', (h($this->Hash->extract($row, $field['data_path'])[0]))),
(empty($field['ondblclick'])) ? '' : sprintf(' ondblclick="%s"', $field['ondblclick']),
$valueField
diff --git a/templates/element/genericElements/ListTopBar/group_table_action.php b/templates/element/genericElements/ListTopBar/group_table_action.php
new file mode 100644
index 0000000..a50184c
--- /dev/null
+++ b/templates/element/genericElements/ListTopBar/group_table_action.php
@@ -0,0 +1,57 @@
+user_settings_by_name['ui.table_setting']['value']) ? json_decode($loggedUser->user_settings_by_name['ui.table_setting']['value'], true) : [];
+$tableSettings = !empty($tableSettings[$data['table_setting_id']]) ? $tableSettings[$data['table_setting_id']] : [];
+
+$availableColumnsHtml = $this->element('/genericElements/ListTopBar/group_table_action/hiddenColumns', [
+ 'table_data' => $table_data,
+ 'tableSettings' => $tableSettings,
+ 'table_setting_id' => $data['table_setting_id'],
+]);
+?>
+
+ Bootstrap->dropdownMenu([
+ 'dropdown-class' => 'ms-1',
+ 'alignment' => 'end',
+ 'direction' => 'down',
+ 'toggle-button' => [
+ 'icon' => 'sliders-h',
+ 'variant' => 'primary',
+ ],
+ 'submenu_alignment' => 'end',
+ 'submenu_direction' => 'start',
+ 'params' => [
+ 'data-table-random-value' => $tableRandomValue,
+ 'data-table_setting_id' => $data['table_setting_id'],
+ ],
+ 'menu' => [
+ [
+ 'text' => __('Group by'),
+ 'icon' => 'layer-group',
+ 'menu' => [
+ [
+ 'text' => 'fields to be grouped by',
+ ]
+ ],
+ ],
+ [
+ 'text' => __('Show/hide columns'),
+ 'icon' => 'eye-slash',
+ 'keepOpen' => true,
+ 'menu' => [
+ [
+ 'html' => $availableColumnsHtml,
+ ]
+ ],
+ ],
+ [
+ 'text' => __('Compact display'),
+ 'icon' => 'text-height'
+ ],
+ ]
+ ]);
+ ?>
+
diff --git a/templates/element/genericElements/ListTopBar/group_table_action/hiddenColumns.php b/templates/element/genericElements/ListTopBar/group_table_action/hiddenColumns.php
new file mode 100644
index 0000000..a6647a4
--- /dev/null
+++ b/templates/element/genericElements/ListTopBar/group_table_action/hiddenColumns.php
@@ -0,0 +1,100 @@
+
+
+
+ ',
+ h(\Cake\Utility\Inflector::variable($fieldName)),
+ h(\Cake\Utility\Inflector::variable($fieldName)),
+ $isVisible ? 'checked' : '',
+ h(\Cake\Utility\Inflector::variable($fieldName)),
+ h($fieldName)
+ );
+}
+
+$availableColumnsHtml = $this->Bootstrap->genNode('form', [
+ 'class' => ['visible-column-form', 'px-2 py-1'],
+], $availableColumnsHtml);
+echo $availableColumnsHtml;
+?>
+
+
\ No newline at end of file
diff --git a/templates/element/genericElements/ListTopBar/scaffold.php b/templates/element/genericElements/ListTopBar/scaffold.php
index 675a660..8bd056b 100644
--- a/templates/element/genericElements/ListTopBar/scaffold.php
+++ b/templates/element/genericElements/ListTopBar/scaffold.php
@@ -1,8 +1,13 @@
element('/genericElements/ListTopBar/group_' . (empty($group['type']) ? 'simple' : h($group['type'])), array('data' => $group, 'tableRandomValue' => $tableRandomValue));
+ $groups .= $this->element('/genericElements/ListTopBar/group_' . (empty($group['type']) ? 'simple' : h($group['type'])), array(
+ 'data' => $group,
+ 'tableRandomValue' => $tableRandomValue,
+ 'table_data' => $table_data,
+ ));
$hasGroupSearch = $hasGroupSearch || (!empty($group['type']) && $group['type'] == 'search');
}
$tempClass = "btn-toolbar";
diff --git a/webroot/js/main.js b/webroot/js/main.js
index 3fb2fa8..a1584a5 100644
--- a/webroot/js/main.js
+++ b/webroot/js/main.js
@@ -152,6 +152,18 @@ function focusSearchResults(evt) {
}
}
+function saveUserSetting(statusNode, settingName, settingValue) {
+ const url = window.saveSettingURL
+ const data = {
+ name: settingName,
+ value: settingValue,
+ }
+ const APIOptions = {
+ statusNode: statusNode,
+ }
+ return AJAXApi.quickFetchAndPostForm(url, data, APIOptions)
+}
+
function openSaveBookmarkModal(bookmark_url = '') {
const url = '/user-settings/saveBookmark';
UI.submissionModal(url).then(([modalFactory, ajaxApi]) => {
@@ -195,11 +207,70 @@ function deleteBookmark(bookmark, forSidebar=false) {
}).catch((e) => { })
}
+function overloadBSDropdown() {
+ // Inspired from https://jsfiddle.net/dallaslu/mvk4uhzL/
+ (function ($bs) {
+ const CLASS_NAME_HAS_CHILD = 'has-child-dropdown-show';
+ const CLASS_NAME_KEEP_OPEN = 'keep-dropdown-show';
+
+ $bs.Dropdown.prototype.toggle = function (_orginal) {
+ return function () {
+ document.querySelectorAll('.' + CLASS_NAME_HAS_CHILD).forEach(function (e) {
+ e.classList.remove(CLASS_NAME_HAS_CHILD);
+ });
+ let dd = this._element.closest('.dropdown')
+ if (dd !== null) {
+ dd = dd.parentNode.closest('.dropdown');
+ for (; dd && dd !== document; dd = dd.parentNode.closest('.dropdown')) {
+ dd.classList.add(CLASS_NAME_HAS_CHILD);
+ }
+
+ if (this._element.classList.contains('open-form')) {
+ const openFormId = this._element.getAttribute('data-open-form-id')
+ document.querySelectorAll('.' + CLASS_NAME_KEEP_OPEN).forEach(function (e) {
+ e.classList.remove(CLASS_NAME_KEEP_OPEN);
+ });
+ let dd = this._element.closest('.dropdown')
+ dd.classList.add(CLASS_NAME_KEEP_OPEN);
+ dd.setAttribute('data-open-form-id', openFormId)
+ dd = dd.parentNode.closest('.dropdown');
+ for (; dd && dd !== document; dd = dd.parentNode.closest('.dropdown')) {
+ dd.setAttribute('data-open-form-id', openFormId)
+ dd.classList.add(CLASS_NAME_KEEP_OPEN);
+ }
+ }
+ }
+ return _orginal.call(this);
+ }
+ }($bs.Dropdown.prototype.toggle);
+
+ document.querySelectorAll('.dropdown').forEach(function (dd) {
+ dd.addEventListener('hide.bs.dropdown', function (e) {
+ if (this.classList.contains(CLASS_NAME_HAS_CHILD)) {
+ this.classList.remove(CLASS_NAME_HAS_CHILD);
+ e.preventDefault();
+ }
+
+ if (e.clickEvent !== undefined) {
+ let dd = e.clickEvent.target.closest('.dropdown')
+ if (dd !== null) {
+ if (dd.classList.contains('keep-dropdown-show')) {
+ e.preventDefault();
+ }
+ }
+ }
+ e.stopPropagation(); // do not need pop in multi level mode
+ });
+ });
+ })(bootstrap);
+}
+
var UI
$(document).ready(() => {
if (typeof UIFactory !== "undefined") {
UI = new UIFactory()
}
+ overloadBSDropdown();
const debouncedGlobalSearch = debounce(performGlobalSearch, 400)
$('#globalSearch')
diff --git a/webroot/js/settings.js b/webroot/js/settings.js
index e8b4808..2530740 100644
--- a/webroot/js/settings.js
+++ b/webroot/js/settings.js
@@ -60,15 +60,7 @@ $(document).ready(function () {
})
function saveSetting(statusNode, $input, settingName, settingValue) {
- const url = window.saveSettingURL
- const data = {
- name: settingName,
- value: settingValue,
- }
- const APIOptions = {
- statusNode: statusNode,
- }
- AJAXApi.quickFetchAndPostForm(url, data, APIOptions).then((result) => {
+ saveUserSetting(statusNode, settingName, settingValue).then((result) => {
window.settingsFlattened[settingName] = result.data
if ($input.attr('type') == 'checkbox') {
$input.prop('checked', result.data.value == true)