From 91d656ff60fceff533033aad245eddd06eff3e9a Mon Sep 17 00:00:00 2001 From: chfhtw Date: Wed, 25 Mar 2026 16:11:52 +0100 Subject: [PATCH 001/107] remove unnecessary function --- application/libraries/dashboard/DashboardLib.php | 4 +++- application/models/dashboard/Dashboard_model.php | 11 ----------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/application/libraries/dashboard/DashboardLib.php b/application/libraries/dashboard/DashboardLib.php index 9b5306d94..72c7307e5 100644 --- a/application/libraries/dashboard/DashboardLib.php +++ b/application/libraries/dashboard/DashboardLib.php @@ -37,7 +37,9 @@ class DashboardLib public function getDashboardByKurzbz($dashboard_kurzbz) { - $result = $this->_ci->DashboardModel->getDashboardByKurzbz($dashboard_kurzbz); + $result = $this->_ci->DashboardModel->loadWhere([ + 'dashboard_kurzbz' => $dashboard_kurzbz + ]); if (hasData($result)) { diff --git a/application/models/dashboard/Dashboard_model.php b/application/models/dashboard/Dashboard_model.php index 88946ed83..78f6b1100 100644 --- a/application/models/dashboard/Dashboard_model.php +++ b/application/models/dashboard/Dashboard_model.php @@ -11,15 +11,4 @@ class Dashboard_model extends DB_Model $this->dbTable = 'dashboard.tbl_dashboard'; $this->pk = 'dashboard_id'; } - - - /** - * Get Dashboard by kurzbz. - * @param string dashboard_kurzbz - * @return array - */ - public function getDashboardByKurzbz($dashboard_kurzbz) - { - return $this->loadWhere(array('dashboard_kurzbz' => $dashboard_kurzbz)); - } } From d37fac0ff74b91c9351818c07694c6b7e5af99bd Mon Sep 17 00:00:00 2001 From: chfhtw Date: Wed, 25 Mar 2026 16:12:17 +0100 Subject: [PATCH 002/107] cleanup api calls to dashboard board --- .../api/frontend/v1/dashboard/Board.php | 17 ++++++++++--- public/js/components/Dashboard/Admin.js | 25 +++++-------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/application/controllers/api/frontend/v1/dashboard/Board.php b/application/controllers/api/frontend/v1/dashboard/Board.php index c50fec128..2c8c72107 100644 --- a/application/controllers/api/frontend/v1/dashboard/Board.php +++ b/application/controllers/api/frontend/v1/dashboard/Board.php @@ -40,11 +40,22 @@ class Board extends FHCAPI_Controller public function list() { + $this->DashboardModel->addSelect('dashboard_id'); + $this->DashboardModel->addSelect('dashboard_kurzbz'); + $this->DashboardModel->addSelect('tbl_dashboard.beschreibung'); + $this->DashboardModel->addSelect("( + SELECT json_agg(w.*) + FROM dashboard.tbl_widget w + JOIN dashboard.tbl_dashboard_widget dw + USING(widget_id) + WHERE dw.dashboard_id=tbl_dashboard.dashboard_id + ) AS \"widgetSetup\""); + $result = $this->DashboardModel->load(); $data = $this->getDataOrTerminateWithError($result); - $this->terminateWithSuccess($result); + $this->terminateWithSuccess($data); } public function create() @@ -82,7 +93,7 @@ class Board extends FHCAPI_Controller $data = $this->getDataOrTerminateWithError($result); - $this->terminateWithSuccess($result); + $this->terminateWithSuccess($data); } public function delete() @@ -116,6 +127,6 @@ class Board extends FHCAPI_Controller $data = $this->getDataOrTerminateWithError($result); - $this->terminateWithSuccess($result); + $this->terminateWithSuccess($data); } } diff --git a/public/js/components/Dashboard/Admin.js b/public/js/components/Dashboard/Admin.js index ff117a956..5222b9673 100644 --- a/public/js/components/Dashboard/Admin.js +++ b/public/js/components/Dashboard/Admin.js @@ -4,7 +4,6 @@ import DashboardAdminWidgets from "./Admin/Widgets.js"; import DashboardAdminPresets from "./Admin/Presets.js"; import ApiDashboardBoard from "../../api/factory/dashboard/board.js"; -import ApiDashboardWidget from "../../api/factory/dashboard/widget.js"; export default { name: 'DashboardAdmin', @@ -16,7 +15,7 @@ export default { provide() { return { adminMode: true, - widgetsSetup: Vue.computed(() => this.dashboards[this.current] ? this.dashboards[this.current].widgetSetup : null) + widgetsSetup: Vue.computed(() => this.dashboard ? this.dashboard.widgetSetup : null) }; }, data() { @@ -59,7 +58,7 @@ export default { dashboardUpdate(dashboard) { return this.$api .call(ApiDashboardBoard.update(dashboard)) - .then(response =>{ + .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); @@ -74,34 +73,22 @@ export default { .call(ApiDashboardBoard.delete(dashboard_id)) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); - - }) - .catch(this.$fhcAlert.handleSystemError) - .finally(() => { this.current = -1; this.dashboards = this.dashboards.filter(el => el.dashboard_id != dashboard_id); - }); + }) + .catch(this.$fhcAlert.handleSystemError); }, assignWidgets(widgets) { this.widgets = widgets; - /*while (this.widgets.length) - this.widgets.pop(); - for (var i in widgets) - this.widgets.push(widgets[i]);*/ } }, created() { this.$api .call(ApiDashboardBoard.list()) .then(result => { - this.dashboards = result.data.retval; + this.dashboards = result.data; for (const dashboard of this.dashboards) { - this.$api - .call(ApiDashboardWidget.list(dashboard.dashboard_id)) - .then(res => { - dashboard.widgetSetup = res.data; - }) - .catch(this.$fhcAlert.handleSystemError); + dashboard.widgetSetup = JSON.parse(dashboard.widgetSetup); } }) .catch(this.$fhcAlert.handleSystemError); From 00e019d6fef6e5839e9bc7ff40cf4c1b0558b61f Mon Sep 17 00:00:00 2001 From: chfhtw Date: Thu, 26 Mar 2026 15:21:41 +0100 Subject: [PATCH 003/107] cleanup db data --- .../api/frontend/v1/dashboard/Preset.php | 11 +-- .../api/frontend/v1/dashboard/User.php | 54 ++--------- .../libraries/dashboard/DashboardLib.php | 67 ++++---------- public/js/components/Dashboard/Dashboard.js | 4 +- system/dbupdate_3.4.php | 1 + .../dbupdate_3.4/68530_Dashboard_Cleanup.php | 91 +++++++++++++++++++ 6 files changed, 124 insertions(+), 104 deletions(-) create mode 100644 system/dbupdate_3.4/68530_Dashboard_Cleanup.php diff --git a/application/controllers/api/frontend/v1/dashboard/Preset.php b/application/controllers/api/frontend/v1/dashboard/Preset.php index 5983d9660..d9be307cf 100644 --- a/application/controllers/api/frontend/v1/dashboard/Preset.php +++ b/application/controllers/api/frontend/v1/dashboard/Preset.php @@ -120,10 +120,7 @@ class Preset extends FHCAPI_Controller $conf = $this->dashboardlib->getPreset($db, $funktion); if ($conf) { $preset = json_decode($conf->preset, true); - if (!isset($preset[$funktion]) || !isset($preset[$funktion]['widgets'])) - $result[$funktion] = []; - else - $result[$funktion] = $preset[$funktion]['widgets']; + $result[$funktion] = $preset; } else { $result[$funktion] = []; } @@ -154,7 +151,7 @@ class Preset extends FHCAPI_Controller $preset_decoded = json_decode($preset->preset, true); - $this->dashboardlib->addWidgetsToWidgets($preset_decoded, $dashboard_kurzbz, $funktion_kurzbz, [$widget]); + $preset_decoded[$widget['widgetid']] = $widget; $preset->preset = json_encode($preset_decoded); @@ -186,8 +183,10 @@ class Preset extends FHCAPI_Controller $preset_decoded = json_decode($preset->preset, true); - if (!$this->dashboardlib->removeWidgetFromWidgets($preset_decoded, $funktion_kurzbz, $widgetid)) + if (!isset($preset_decoded[$widgetid])) show_404(); + + unset($preset_decoded[$widgetid]); $preset->preset = json_encode($preset_decoded); diff --git a/application/controllers/api/frontend/v1/dashboard/User.php b/application/controllers/api/frontend/v1/dashboard/User.php index 9d020649e..0dee430d7 100644 --- a/application/controllers/api/frontend/v1/dashboard/User.php +++ b/application/controllers/api/frontend/v1/dashboard/User.php @@ -48,25 +48,9 @@ class User extends FHCAPI_Controller $uid = $this->authlib->getAuthObj()->username; - /*$mergedconfig = $this->dashboardlib->getMergedConfig($dashboard->dashboard_id, $uid); + $mergedconfig = $this->dashboardlib->getMergedUserConfig($dashboard->dashboard_id, $uid); - $this->terminateWithSuccess([ - 'general' => call_user_func_array( - 'array_merge_recursive', - $mergedconfig - ) - ]);*/ - $defaultconfig = $this->dashboardlib->getDefaultConfig($dashboard->dashboard_id); - $userconfig = $this->dashboardlib->getUserConfig($dashboard->dashboard_id, $uid); - - $defaultconfig_squashed = $defaultconfig ? call_user_func_array('array_replace_recursive', $defaultconfig) : []; - $userconfig_squashed = $userconfig ? call_user_func_array('array_replace_recursive', $userconfig) : []; - - $mergedconfig = array_replace_recursive($defaultconfig_squashed, $userconfig_squashed); - - $this->terminateWithSuccess([ - DashboardLib::SECTION_IF_FUNKTION_KURZBZ_IS_NULL => $mergedconfig - ]); + $this->terminateWithSuccess($mergedconfig); } public function addWidget() @@ -87,25 +71,11 @@ class User extends FHCAPI_Controller $widget['widgetid'] = $this->dashboardlib->generateWidgetId($dashboard_kurzbz); $override = $this->dashboardlib->getOverrideOrCreateEmptyOverride($dashboard_kurzbz, $uid); - + $override_decoded = json_decode($override->override, true); - if (!isset($override_decoded['general']) || !is_array($override_decoded['general'])) - $override_decoded['general'] = []; + $override_decoded[$widget['widgetid']] = $widget; - if (!isset($override_decoded['general']['widgets'])) - $override_decoded['general']['widgets'] = []; - - $override_decoded['general']['widgets'][$widget['widgetid']] = $widget; - - // NOTE(chris): remove doubles in other funktionen - foreach ($override_decoded as $funktion => $array) { - if ($funktion == 'general') - continue; - if (isset($array['widgets']) && isset($array['widgets'][$widget['widgetid']])) - unset($override_decoded[$funktion]['widgets'][$widget['widgetid']]); - } - $override->override = json_encode($override_decoded); $result = $this->dashboardlib->insertOrUpdateOverride($override); @@ -135,18 +105,10 @@ class User extends FHCAPI_Controller $override_decoded = json_decode($override->override, true); - foreach (array_keys($override_decoded) as $k) { - if (!isset($override_decoded[$k]["widgets"])) { - unset($override_decoded[$k]); - continue; - } - if (isset($override_decoded[$k]["widgets"][$widget_id])) { - unset($override_decoded[$k]["widgets"][$widget_id]); - } - if (!$override_decoded[$k]["widgets"]) { - unset($override_decoded[$k]); - } - } + if (!isset($override_decoded[$widget_id])) + show_404(); + + unset($override_decoded[$widget_id]); $override->override = json_encode($override_decoded); diff --git a/application/libraries/dashboard/DashboardLib.php b/application/libraries/dashboard/DashboardLib.php index 7bd85867d..c9838f0e7 100644 --- a/application/libraries/dashboard/DashboardLib.php +++ b/application/libraries/dashboard/DashboardLib.php @@ -49,17 +49,21 @@ class DashboardLib return null; } - public function getMergedConfig($dashboard_id, $uid) + public function getMergedUserConfig($dashboard_id, $uid) { - $defaultconfig = $this->getDefaultConfig($dashboard_id); - $userconfig = $this->getUserConfig($dashboard_id, $uid); + $defaultconfig = $this->getUserBaseConfig($dashboard_id); + $userconfig = $this->getUserOverrideConfig($dashboard_id, $uid); - $mergedconfig = array_replace_recursive($defaultconfig, $userconfig); + $sourceconfig = array_map(function ($value) { + return ['source' => $value['source']]; + }, $defaultconfig); + + $mergedconfig = array_replace_recursive($defaultconfig, $userconfig, $sourceconfig); return $mergedconfig; } - public function getDefaultConfig($dashboard_id) + protected function getUserBaseConfig($dashboard_id) { $funktion_kurzbzs = []; $rights = $this->_ci->permissionlib->getAccessRights(); @@ -89,7 +93,11 @@ class DashboardLib $preset = json_decode($presetobj->preset, true); if (null !== $preset) { - $defaultconfig = array_replace_recursive($defaultconfig, $preset); + $preset = array_map(function ($value) use ($presetobj) { + $value['source'] = $presetobj->funktion_kurzbz ?: self::SECTION_IF_FUNKTION_KURZBZ_IS_NULL; + return $value; + }, $preset); + $defaultconfig = array_merge_recursive($defaultconfig, $preset); } } } @@ -97,7 +105,7 @@ class DashboardLib return $defaultconfig; } - public function getUserConfig($dashboard_id, $uid) + protected function getUserOverrideConfig($dashboard_id, $uid) { $res_userconfig = $this->_ci->DashboardOverrideModel->getOverride($dashboard_id, $uid); @@ -126,7 +134,7 @@ class DashboardLib $emptyoverride = new stdClass(); $emptyoverride->dashboard_id = $dashboard->dashboard_id; $emptyoverride->uid = $uid; - $emptyoverride->override = '{"' . self::USEROVERRIDE_SECTION . '": {"widgets":{}}, "custom": { "widgets" : {}}}'; + $emptyoverride->override = '[]'; return $emptyoverride; } @@ -145,8 +153,7 @@ class DashboardLib $emptypreset = new stdClass(); $emptypreset->dashboard_id = $dashboard->dashboard_id; $emptypreset->funktion_kurzbz = $funktion_kurzbz; - $section = ($funktion_kurzbz !== null) ? $funktion_kurzbz : self::SECTION_IF_FUNKTION_KURZBZ_IS_NULL; - $emptypreset->preset = '{"' . $section . '": { "widgets" : {}},"custom": { "widgets" : {}}}'; + $emptypreset->preset = '[]'; return $emptypreset; } @@ -211,44 +218,4 @@ class DashboardLib return $result; } - - public function addWidgetsToWidgets(&$widgets, $dashboard_kurzbz, $section, $addwigets) - { - foreach ($addwigets as $widget) - { - if(!isset($widget['widgetid'])) - { - $widget['widgetid'] = $this->generateWidgetId($dashboard_kurzbz); - } - $this->addWidgetToWidgets($widgets, $section, $widget, $widget['widgetid']); - } - } - - public function addWidgetToWidgets(&$widgets, $section, $widget, $widgetid) - { - $section = ($section !== null) ? $section : self::SECTION_IF_FUNKTION_KURZBZ_IS_NULL; - if (!isset($widgets[$section]) || !isset($widgets[$section]["widgets"]) || !is_array($widgets[$section])) - { - $widgets[$section] = array(); - $widgets[$section]["widgets"] = array(); - } - - $widgets[$section]["widgets"][$widgetid] = $widget; - } - - public function removeWidgetFromWidgets(&$widgets, $section, $widgetid) - { - $section = ($section !== null) ? $section : self::SECTION_IF_FUNKTION_KURZBZ_IS_NULL; - if (isset($widgets[$section]) && isset($widgets[$section]["widgets"][$widgetid])) - { - unset($widgets[$section]["widgets"][$widgetid]); - if(empty($widgets[$section]["widgets"]) && $section !== self::USEROVERRIDE_SECTION) { - unset($widgets[$section]); - } - return true; - } - else { - return false; - } - } } diff --git a/public/js/components/Dashboard/Dashboard.js b/public/js/components/Dashboard/Dashboard.js index e92e34f29..c7a45c2a8 100644 --- a/public/js/components/Dashboard/Dashboard.js +++ b/public/js/components/Dashboard/Dashboard.js @@ -138,8 +138,8 @@ export default { const widgets = []; const remove = []; - for (var wid in res.data.general.widgets) { - let widget = res.data.general.widgets[wid]; + for (var wid in res.data) { + let widget = res.data[wid]; widget.id = wid; if (widget.custom || widget.preset) { widgets.push(widget); diff --git a/system/dbupdate_3.4.php b/system/dbupdate_3.4.php index 4ddb38203..5fd66506b 100644 --- a/system/dbupdate_3.4.php +++ b/system/dbupdate_3.4.php @@ -92,6 +92,7 @@ require_once('dbupdate_3.4/68744_StV_settings.php'); require_once('dbupdate_3.4/62889_reihungstest_ueberwachung_mit_constructor.php'); require_once('dbupdate_3.4/71399_dashboard_update_widget_paths.php'); require_once('dbupdate_3.4/71645_studvw_messagetab_ladezeit.php'); +require_once('dbupdate_3.4/68530_Dashboard_Cleanup.php'); // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen echo '

Pruefe Tabellen und Attribute!

'; diff --git a/system/dbupdate_3.4/68530_Dashboard_Cleanup.php b/system/dbupdate_3.4/68530_Dashboard_Cleanup.php new file mode 100644 index 000000000..918711211 --- /dev/null +++ b/system/dbupdate_3.4/68530_Dashboard_Cleanup.php @@ -0,0 +1,91 @@ +, + * + * Description: + * Cleanup Dashboard DB data + */ +if (! defined('DB_NAME')) exit('No direct script access allowed'); + +// Cleanup presets +if ($result = @$db->db_query(" + SELECT 1 + FROM dashboard.tbl_dashboard_preset + WHERE preset ? COALESCE(funktion_kurzbz, 'general') + OR preset ? 'custom' + LIMIT 1 +")) { + if ($db->db_num_rows($result)) { + $qry = " + UPDATE dashboard.tbl_dashboard_preset + SET preset = COALESCE(preset->COALESCE(funktion_kurzbz, 'general'), preset->'custom')->'widgets' + WHERE preset ? COALESCE(funktion_kurzbz, 'general') + OR preset ? 'custom' + "; + + $result = $db->db_query($qry); + + if (!$result) { + echo 'dashboard.tbl_dashboard_preset '.$db->db_last_error().'
'; + } else { + $affected_rows = $db->db_affected_rows($result); + echo 'dashboard.tbl_dashboard_preset: ' . $affected_rows . ' rows migrated
'; + } + } +} + +// Cleanup user overrides +if ($result = @$db->db_query(" + SELECT 1 + FROM dashboard.tbl_dashboard_benutzer_override + WHERE EXISTS ( + SELECT 1 + FROM jsonb_each(override) + WHERE value ? 'widgets' + LIMIT 1 + ) AND override <> '[]'::jsonb + LIMIT 1 +")) { + if ($db->db_num_rows($result)) { + $qry = " + UPDATE dashboard.tbl_dashboard_benutzer_override + SET override = COALESCE(( + SELECT json_object_agg(key, value) FROM ( + SELECT value->'widgets' AS widgets + FROM jsonb_each(override) + WHERE jsonb_typeof(value->'widgets') = 'object' + ) x, jsonb_each(widgets) + ), '[]') + WHERE EXISTS ( + SELECT 1 + FROM jsonb_each(override) + WHERE value ? 'widgets' + LIMIT 1 + ) AND override <> '[]'::jsonb + "; + + $result = $db->db_query($qry); + + if (!$result) { + echo 'dashboard.tbl_dashboard_benutzer_override '.$db->db_last_error().'
'; + } else { + $affected_rows = $db->db_affected_rows($result); + echo 'dashboard.tbl_dashboard_benutzer_override: ' . $affected_rows . ' rows migrated
'; + } + } +} From d421b1ccb81bf5f5c0adf343e0458ad3895b6c22 Mon Sep 17 00:00:00 2001 From: chfhtw Date: Mon, 30 Mar 2026 09:29:05 +0200 Subject: [PATCH 004/107] cleanup dropgrid code --- public/js/components/Drop/Grid.js | 145 ++++++++++--------------- public/js/components/Drop/Grid/Item.js | 39 +++---- 2 files changed, 74 insertions(+), 110 deletions(-) diff --git a/public/js/components/Drop/Grid.js b/public/js/components/Drop/Grid.js index a7bea64e3..c4720781d 100644 --- a/public/js/components/Drop/Grid.js +++ b/public/js/components/Drop/Grid.js @@ -1,5 +1,3 @@ -// TODO(chris): Comments - import GridItem from './Grid/Item.js'; import GridLogic from '../../composables/GridLogic.js'; @@ -13,6 +11,12 @@ export default { components: { GridItem, }, + inject: { + sectionName: { + type: String, + default: '', + } + }, props: { cols: Number, items: Array, @@ -26,7 +30,7 @@ export default { type: Number, default: 0 }, - additionalRow:{ + additionalRow: { type: Boolean, default: false, } @@ -50,18 +54,12 @@ export default { permUpdates: [], positionUpdates: null, fixedPositionUpdates: null, - draggedOffset: [0,0], + draggedOffset: [0, 0], draggedItem: null, draggedNode: null, reorderedItems:[], clonedWidget:null, - } - }, - inject:{ - sectionName: { - type: String, - default: '', - }, + }; }, computed: { additionalRowComputed: { @@ -86,7 +84,7 @@ export default { }); return items }, - items_placeholders(){ + items_placeholders() { let placeholders = []; let col_max = this.cols; let rows_max = this.rows; @@ -133,7 +131,6 @@ export default { return this.grid ? (this.grid.h+1) : 1; } return this.grid ? this.grid.h : 1; - }, gridStyle() { const addH = this.active ? this.marginForExtraRow : 0; @@ -218,14 +215,12 @@ export default { return false; return this.grid.isFreeSlot(this.x, this.y); }, - widgetSetup(){ - if (!this.widgetsSetup) - return; - return this.widgetsSetup.reduce((acc, ele) => { - acc[ele.widget_id] =ele; - return acc; - } ,{}); - }, + currentItems() { + if (this.mode != 1 && this.mode != 2 && this.active) + return this.placedItems_withPlaceholders; + + return this.placedItems; + } }, watch: { active(active) { @@ -256,22 +251,22 @@ export default { } }, methods: { - needsReordering(item){ + needsReordering(item) { if (!item?.data?.place[this.cols]){ return true; } return false; }, - toggleDraggedItemOverlay(condition){ - if(!this.draggedNode) + toggleDraggedItemOverlay(condition) { + if (!this.draggedNode) return; - if(condition){ + if (condition) { this.draggedNode.firstElementChild.classList.add("dashboard-item-overlay"); - }else{ + } else { this.draggedNode.firstElementChild.classList.remove("dashboard-item-overlay"); } }, - dragging(event){ + dragging(event) { if(this.mode == MODE_MOVE){ this.toggleDraggedItemOverlay(true); @@ -313,7 +308,7 @@ export default { sortedItems.forEach(item => { let freeSlots = this.grid.getFreeSlots(); - if(this.needsReordering(item)){ + if (this.needsReordering(item)) { let firstFreeSlot = freeSlots.shift(); if (!firstFreeSlot) { item.x = 0; @@ -354,7 +349,6 @@ export default { return result; }, convertGridResultToUpdate(input, output, baseArray) { - if (!input) return; if (!baseArray) @@ -374,13 +368,6 @@ export default { output[item.index] = result; }); }, - mouseLeave() { - /* if (this.mode == MODE_IDLE) { - this.x = -1; - this.y = -1; - - } */ - }, updateCursor(evt) { if (!this.active) { this.x = this.y = -1; @@ -415,7 +402,6 @@ export default { } }, startMove(evt, item) { - if (!this.active) return; @@ -458,7 +444,7 @@ export default { if (!this.active) return this.dragCancel(); this.checkPinnedWidgetAnimation(); - if(this.mode == MODE_RESIZE){ + if (this.mode == MODE_RESIZE) { this.checkWidgetSizeLimitAnimation(); } if (this.updateCursor(evt)) { @@ -505,7 +491,6 @@ export default { this.draggedItem = null; this.$emit('draggedItem',null); this.draggedNode = null; - }, dragEnd() { this.removeWidgetClones(); @@ -554,14 +539,14 @@ export default { this.additionalRowComputed = false; this.$emit('newItem', this.x, this.y); }, - updateCursorOnMouseMove(evt){ - if(this.mode == MODE_IDLE){ + updateCursorOnMouseMove(evt) { + if(this.mode == MODE_IDLE) { this.updateCursor(evt); } }, - checkPinnedWidgetAnimation(){ - let itemAtPosition=[]; - switch(this.mode){ + checkPinnedWidgetAnimation() { + let itemAtPosition = []; + switch (this.mode) { case MODE_RESIZE: for (let x = this.draggedItem.x; x <= this.x; x++) { for (let y = this.draggedItem.y; y <= this.y; y++) { @@ -580,9 +565,9 @@ export default { Array.from(document.getElementsByClassName("denied-dragging-animation"))?.forEach(ele => { ele.classList.remove("denied-dragging-animation"); - }) + }); - itemAtPosition.forEach(item=>{ + itemAtPosition.forEach(item => { if (item.place[this.cols] && item.place[this.cols].pinned) { let pinnedWidget = document.getElementById(item.widgetid); let pinNode = pinnedWidget.querySelector("[pinned='true']"); @@ -590,10 +575,9 @@ export default { pinNode.classList.add("denied-dragging-animation"); } } - }) + }); }, checkWidgetSizeLimitAnimation() { - let draggedItemSetup = this.itemsSetup[this.draggedItem.data.widget]; let draggedItemMaxWidth = draggedItemSetup.width.max ?? draggedItemSetup.width; let draggedItemMinWidth = draggedItemSetup.width.min ?? draggedItemSetup.width; @@ -603,7 +587,7 @@ export default { let width_after_resize = this.x - this.draggedItem.x + 1; let height_after_resize = this.y - this.draggedItem.y + 1; - if( + if ( (width_after_resize > 0 && (width_after_resize > draggedItemMaxWidth || width_after_resize < draggedItemMinWidth) ) @@ -611,26 +595,26 @@ export default { (height_after_resize > 0 && (height_after_resize > draggedItemMaxHeight || height_after_resize < draggedItemMinHeight) ) - ){ + ) { draggedItemNode.classList.add("border-danger"); - }else{ + } else { draggedItemNode.classList.remove("border-danger"); } }, - removeWidgetClones(){ + removeWidgetClones() { let widgetClones = Array.from(document.getElementsByClassName("widgetClone")); for (let i = 0; i < widgetClones.length; i++) { this.$refs.container.removeChild(widgetClones[i]); } }, - mouseDown(){ + mouseDown() { this.mode = MODE_MOUSE_DOWN; }, mouseUp() { this.mode = MODE_IDLE; }, }, - template: ` + template: /* html */` ` } - -/* -OLD VERSION - ON HOVER -
- -
-*/ \ No newline at end of file diff --git a/public/js/components/Drop/Grid/Item.js b/public/js/components/Drop/Grid/Item.js index bd256a1fb..49f2bbbcf 100644 --- a/public/js/components/Drop/Grid/Item.js +++ b/public/js/components/Drop/Grid/Item.js @@ -1,9 +1,5 @@ export default { name:'GridItem', - components: { - }, - inject: { - }, props: { item: Object, active: Boolean @@ -15,18 +11,14 @@ export default { "startResize", "dragging", "endDrag", - "dropDrag", - "item", "touchStart", - "touchEnd", + "touchEnd" ], data() { return { dragAction: '', dragging: false - } - }, - computed: { + }; }, methods: { registerDragAction(evt) { @@ -42,16 +34,15 @@ export default { } } }, - tryDragStart(evt, item) { + tryDragStart(evt) { let dragAction = this.dragAction || evt.target.getAttribute('drag-action'); if (dragAction) { this.dragging = true; if (dragAction == 'move') - return this.$emit('startMove', evt, item); + return this.$emit('startMove', evt, this.item); else if (dragAction == 'resize') - return this.$emit('startResize', evt, item); + return this.$emit('startResize', evt, this.item); } - //evt.preventDefault(); }, touchDragEnd(evt) { if (!this.dragging) @@ -59,30 +50,32 @@ export default { this.dragging = false; this.$emit('touchEnd', evt); }, - touchStart(event){ + touchStart(event) { this.$emit('touchStart', event); this.registerDragAction(event); - this.tryDragStart(event, this.item); + this.tryDragStart(event); }, - touchMove(event){ - if(this.dragging){ + touchMove(event) { + if (this.dragging){ event.preventDefault(); this.$emit('dragging', event); } } }, - template: ` -
+ >
` } From 2354746d4f224283c2ba6531577876aa8eca9b42 Mon Sep 17 00:00:00 2001 From: chfhtw Date: Mon, 30 Mar 2026 13:34:34 +0200 Subject: [PATCH 005/107] more cleanup of dropgrid code & cleanup of dashboard item code --- public/js/components/Dashboard/Item.js | 230 ++++++++++++++----------- public/js/components/Drop/Grid.js | 29 ++-- public/js/components/Drop/Grid/Item.js | 2 +- 3 files changed, 139 insertions(+), 122 deletions(-) diff --git a/public/js/components/Dashboard/Item.js b/public/js/components/Dashboard/Item.js index 79e61293d..956ff5ddf 100644 --- a/public/js/components/Dashboard/Item.js +++ b/public/js/components/Dashboard/Item.js @@ -11,18 +11,15 @@ export default { data: () => ({ component: "", arguments: null, - target: false, widget: null, tmpConfig: {}, isLoading: false, hasConfig: false, - sharedData: null, + sharedData: null }), emits: [ "change", "remove", - "dragstart", - "resizestart", "configOpened", "configClosed", "pinItem", @@ -42,29 +39,25 @@ export default { "place", "setup", "dragstate", - "resizeOverlay", - "additionalRow" + "resizeOverlay" ], computed: { - maxHeight(){ + maxHeight() { + if (Object.prototype.toString.call(this.setup?.height) == "[object Number]") { + return this.setup?.height; + } return this.setup?.height?.max; }, - maxWidth(){ - if (Object.prototype.toString.call(this.setup?.width) == "[object Number]"){ + maxWidth() { + if (Object.prototype.toString.call(this.setup?.width) == "[object Number]") { return this.setup?.width; } return this.setup?.width?.max; }, - minHeight() { - return this.setup?.height?.min; + isResizeable() { + return this.maxWidth > 1 || this.maxHeight > 1; }, - minWidth() { - return this.setup?.width?.min; - }, - isResizeable(){ - return this.maxWidth >1 || this.maxHeight >1; - }, - isPinned(){ + isPinned() { return this.place?.pinned ? true : false; }, ready() { @@ -80,16 +73,16 @@ export default { } }, methods: { - unpin(){ + unpin() { // Unpinning is only possible in edit mode - if(!this.editMode) + if (!this.editMode) return; let result = { item: this.item_data, x: this.item_data.x, y: this.item_data.y }; this.$emit('unPinItem', [result]); }, - pinItem(){ - let result = { item: this.item_data, x: this.item_data.x, y: this.item_data.y}; - this.$emit('pinItem',[result]); + pinItem() { + let result = { item: this.item_data, x: this.item_data.x, y: this.item_data.y }; + this.$emit('pinItem', [result]); }, getWidgetC4Link(widget) { return (FHC_JS_DATA_STORAGE_OBJECT.app_root + @@ -101,22 +94,6 @@ export default { handleHideBsModal() { this.$emit('configClosed') }, - mouseDown(e) { - this.target = e.target; - }, - startDrag(e) { - if (this.$refs.dragHandle.contains(this.target)) { - this.$emit("dragstart", e); - } else if ( - this.isResizeable && - this.$refs.resizeHandle.contains(this.target) - ) { - if (this.isResizeable) this.$emit("resizestart", e); - else e.preventDefault(); - } else { - e.preventDefault(); - } - }, openConfig() { this.tmpConfig = { ...this.arguments }; this.$refs.config.show(); @@ -136,11 +113,11 @@ export default { sendChangeConfig(config) { for (var k in config) { if (this.widget.arguments[k] == config[k]) { - delete config[k]; + delete config[k]; } } this.$emit("change", config); - }, + } }, watch: { config() { @@ -170,75 +147,118 @@ export default { -
-
-
- - - - {{ widget.setup.name }} - - - - - - - - - - -
- -
-
-
-
- -
-
- - - - - - - ` } From 8a53c438e3a55089b76336b2c1af3eb347bc6119 Mon Sep 17 00:00:00 2001 From: chfhtw Date: Mon, 30 Mar 2026 15:01:03 +0200 Subject: [PATCH 008/107] more cleanup of dropgrid code --- public/js/components/Drop/Grid.js | 33 ++++++------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/public/js/components/Drop/Grid.js b/public/js/components/Drop/Grid.js index 8f048de94..75fdefda6 100644 --- a/public/js/components/Drop/Grid.js +++ b/public/js/components/Drop/Grid.js @@ -11,12 +11,6 @@ export default { components: { GridItem, }, - inject: { - sectionName: { - type: String, - default: '', - } - }, props: { cols: Number, items: Array, @@ -37,7 +31,6 @@ export default { }, emits: [ "rearrangeItems", - "newItem", "gridHeight", "draggedItem", "update:additionalRow" @@ -51,7 +44,6 @@ export default { mode: MODE_IDLE, grid: null, dragGrid: null, - permUpdates: [], positionUpdates: null, fixedPositionUpdates: null, draggedOffset: [0, 0], @@ -123,8 +115,11 @@ export default { } return placeholders; }, - placedItems_withPlaceholders() { - return [...this.placedItems, ...this.items_placeholders]; + currentItems() { + if (this.mode != 1 && this.mode != 2 && this.active) + return [ ...this.placedItems, ...this.items_placeholders ]; + + return this.placedItems; }, rows() { if (this.additionalRowComputed) { @@ -209,17 +204,6 @@ export default { } }) return [...mappedPlacedItems, ...temporaryResizeItems]; - }, - showEmptyTileHover() { - if (!this.active || !this.grid || this.mode != MODE_IDLE || this.x < 0 || this.y < 0 || this.x >= this.cols || this.y >= this.rows) - return false; - return this.grid.isFreeSlot(this.x, this.y); - }, - currentItems() { - if (this.mode != 1 && this.mode != 2 && this.active) - return this.placedItems_withPlaceholders; - - return this.placedItems; } }, watch: { @@ -436,7 +420,6 @@ export default { dragOver(evt) { if ((this.y + 1) > this.rows && (this.mode == MODE_MOVE || this.mode == MODE_RESIZE)) { this.dragCancel(); - } if (!this.active) return this.dragCancel(); @@ -532,10 +515,6 @@ export default { } return updated; }, - emptyTileClicked() { - this.additionalRowComputed = false; - this.$emit('newItem', this.x, this.y); - }, updateCursorOnMouseMove(evt) { if (this.mode == MODE_IDLE) { this.updateCursor(evt); @@ -609,7 +588,7 @@ export default { }, mouseUp() { this.mode = MODE_IDLE; - }, + } }, template: /* html */`
Date: Mon, 30 Mar 2026 16:49:21 +0200 Subject: [PATCH 009/107] stabilize workaround for chrome by adding more code into the workaround and get rid of updateCursorOnMouseMove in the process --- public/js/components/Drop/Grid.js | 36 ++++++++++++++++--------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/public/js/components/Drop/Grid.js b/public/js/components/Drop/Grid.js index 75fdefda6..d766492ad 100644 --- a/public/js/components/Drop/Grid.js +++ b/public/js/components/Drop/Grid.js @@ -386,13 +386,14 @@ export default { if (!this.active) return; - this.mode = MODE_MOVE; - - this.draggedItem = item; - - this.$emit('draggedItem', item); // workaround for chrome fireing event dragend when styles are manipulated during dragging setTimeout(() => { + this.mode = MODE_MOVE; + this.updateCursor(evt); + this.draggedItem = item; + + this.$emit('draggedItem', item); + this.draggedNode = evt.target.closest(".drop-grid-item"); //clones the widget for the drag Image @@ -402,19 +403,26 @@ export default { clone.classList.add("widgetClone"); this.$refs.container.appendChild(clone); const hiddenWidget = clone.querySelector("[style='display: none;']"); - hiddenWidget.style.removeProperty("display"); + if (hiddenWidget) + hiddenWidget.style.removeProperty("display"); this.clonedWidget = clone; + + this.draggedOffset = [item.x - this.x, item.y - this.y]; }, 0); - this.draggedOffset = [item.x - this.x, item.y - this.y]; this._dragStart(evt, item); }, startResize(evt, item) { if (!this.active) return; - this.mode = MODE_RESIZE; - this.draggedItem = item; - this.$emit('draggedItem', item); + + // workaround for chrome fireing event dragend when styles are manipulated during dragging + setTimeout(() => { + this.mode = MODE_RESIZE; + this.draggedItem = item; + this.$emit('draggedItem', item); + }, 0); + this._dragStart(evt); }, dragOver(evt) { @@ -515,11 +523,6 @@ export default { } return updated; }, - updateCursorOnMouseMove(evt) { - if (this.mode == MODE_IDLE) { - this.updateCursor(evt); - } - }, checkPinnedWidgetAnimation() { let itemAtPosition = []; switch (this.mode) { @@ -599,7 +602,6 @@ export default { @touchend="dragCancel" @dragover.prevent="dragOver" @drop="dragEnd" - @mousemove="updateCursorOnMouseMove" >