Add parent widget drag handle (#7792)
* Add parent widget drag handle * Update parent.php * Update css.php
This commit is contained in:
+85
-45
@@ -310,7 +310,7 @@ div.hud_chart {
|
|||||||
padding-top: 7px;
|
padding-top: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dashboard settings */
|
/* Dashboard Settings */
|
||||||
<?php
|
<?php
|
||||||
foreach ($widgets as $row) {
|
foreach ($widgets as $row) {
|
||||||
$widget_id = 'id_'.md5(preg_replace('/[^-A-Fa-f0-9]/', '', $row['dashboard_widget_uuid']));
|
$widget_id = 'id_'.md5(preg_replace('/[^-A-Fa-f0-9]/', '', $row['dashboard_widget_uuid']));
|
||||||
@@ -484,7 +484,7 @@ foreach ($widgets as $row) {
|
|||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
/* Screen smaller than 575px? 1 columns */
|
/* Screen smaller than 575px? 1 column */
|
||||||
@media (max-width: 575px) {
|
@media (max-width: 575px) {
|
||||||
.widgets { grid-template-columns: repeat(1, minmax(100px, 1fr)); }
|
.widgets { grid-template-columns: repeat(1, minmax(100px, 1fr)); }
|
||||||
.col-num { grid-column: span 1; }
|
.col-num { grid-column: span 1; }
|
||||||
@@ -558,6 +558,7 @@ foreach ($widgets as $row) {
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
// Widget details expand button
|
||||||
document.addEventListener('click', function(event) {
|
document.addEventListener('click', function(event) {
|
||||||
let hud_content = event.target.closest('.hud_content');
|
let hud_content = event.target.closest('.hud_content');
|
||||||
let hud_expander = event.target.closest('.hud_expander');
|
let hud_expander = event.target.closest('.hud_expander');
|
||||||
@@ -589,7 +590,7 @@ function toggle_grid_row_span(widget_id) {
|
|||||||
let first_toggle = false;
|
let first_toggle = false;
|
||||||
|
|
||||||
function toggle_grid_row_span_all() {
|
function toggle_grid_row_span_all() {
|
||||||
const widgets = document.querySelectorAll('div.widget, div.child_widget');
|
const widgets = document.querySelectorAll('div.widget');
|
||||||
|
|
||||||
widgets.forEach(widget => {
|
widgets.forEach(widget => {
|
||||||
if (widget.classList.contains('details_disabled')) {
|
if (widget.classList.contains('details_disabled')) {
|
||||||
@@ -613,14 +614,15 @@ function toggle_grid_row_span_all() {
|
|||||||
first_toggle = true;
|
first_toggle = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Automatically update parent widget height and row span based on content and window size
|
||||||
function update_parent_height() {
|
function update_parent_height() {
|
||||||
const parent_widgets = document.querySelectorAll('.parent_widget');
|
const parent_widgets = document.querySelectorAll('.parent_widget > .hud_box > .hud_content');
|
||||||
|
|
||||||
parent_widgets.forEach(parent_widget => {
|
parent_widgets.forEach(parent_widget => {
|
||||||
if (!parent_widget.dataset.originalHeight) {
|
if (!parent_widget.dataset.originalHeight) {
|
||||||
parent_widget.dataset.originalHeight = parseFloat(window.getComputedStyle(parent_widget).height.replace('px', ''));
|
parent_widget.dataset.originalHeight = parseFloat(window.getComputedStyle(parent_widget).height.replace('px', ''));
|
||||||
}
|
}
|
||||||
const widget = parent_widget.closest('.widget');
|
const widget = parent_widget.closest('.parent_widget');
|
||||||
const row_gap = parseInt(window.getComputedStyle(document.documentElement).getPropertyValue('--grid-gap').replace('px', ''));
|
const row_gap = parseInt(window.getComputedStyle(document.documentElement).getPropertyValue('--grid-gap').replace('px', ''));
|
||||||
const row_height = parseInt(window.getComputedStyle(document.documentElement).getPropertyValue('--row-height').replace('px', ''));
|
const row_height = parseInt(window.getComputedStyle(document.documentElement).getPropertyValue('--row-height').replace('px', ''));
|
||||||
const original_row_span = parseInt(window.getComputedStyle(widget).getPropertyValue('--row-span').replace('span ', ''));
|
const original_row_span = parseInt(window.getComputedStyle(widget).getPropertyValue('--row-span').replace('span ', ''));
|
||||||
@@ -647,7 +649,7 @@ window.addEventListener('resize', update_parent_height);
|
|||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
//include the dashboards
|
//include the widgets
|
||||||
echo "<div class='widgets' id='widgets' style='padding: 0 5px;'>\n";
|
echo "<div class='widgets' id='widgets' style='padding: 0 5px;'>\n";
|
||||||
$x = 0;
|
$x = 0;
|
||||||
foreach ($widgets as $row) {
|
foreach ($widgets as $row) {
|
||||||
@@ -707,7 +709,10 @@ window.addEventListener('resize', update_parent_height);
|
|||||||
$widget_path_name = $widget_path_array[1];
|
$widget_path_name = $widget_path_array[1];
|
||||||
$path_array = glob(dirname(__DIR__, 2).'/*/'.$application_name.'/resources/dashboard/'.$widget_path_name.'.php');
|
$path_array = glob(dirname(__DIR__, 2).'/*/'.$application_name.'/resources/dashboard/'.$widget_path_name.'.php');
|
||||||
|
|
||||||
echo "<div class='widget details_".$widget_details_state."' id='".$widget_id."' ".($widget_path == 'dashboard/parent' ? "data-is-parent='true'" : null)." draggable='false'>\n";
|
// Widget class
|
||||||
|
$widget_class = ($widget_path == 'dashboard/parent' ? 'parent_widget' : 'widget');
|
||||||
|
|
||||||
|
echo "<div class='".$widget_class." details_".$widget_details_state." draggable' id='".$widget_id."' draggable='false'>\n";
|
||||||
if (file_exists($path_array[0])) {
|
if (file_exists($path_array[0])) {
|
||||||
include $path_array[0];
|
include $path_array[0];
|
||||||
}
|
}
|
||||||
@@ -730,22 +735,26 @@ window.addEventListener('resize', update_parent_height);
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.widget.editable {
|
.editable {
|
||||||
cursor: move;
|
position: relative;
|
||||||
|
cursor: grab;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hud_box.editable {
|
.hud_box.editable {
|
||||||
transition: 0.2s;
|
transition: 0.2s;
|
||||||
border: 1px dashed rgba(0,0,0,0.4);
|
border: 1px dashed rgba(0,0,0,0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hud_box.editable:hover {
|
.hud_box.editable:hover {
|
||||||
box-shadow: 0 5px 10px rgba(0,0,0,0.2);
|
box-shadow: 0 5px 10px rgba(0,0,0,0.2);
|
||||||
border: 1px dashed rgba(0,0,0,0.4);
|
border: 1px dashed rgba(0,0,0,0.3);
|
||||||
transform: scale(1.03, 1.03);
|
|
||||||
transition: 0.2s;
|
transition: 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.widget > .hud_box.editable:hover {
|
||||||
|
transform: scale(1.03, 1.03);
|
||||||
|
}
|
||||||
|
|
||||||
.hud_box .hud_box.editable:hover {
|
.hud_box .hud_box.editable:hover {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
transform: none;
|
transform: none;
|
||||||
@@ -760,57 +769,63 @@ window.addEventListener('resize', update_parent_height);
|
|||||||
<?php unset($br); ?>
|
<?php unset($br); ?>
|
||||||
opacity: 0.2;
|
opacity: 0.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.widget_edit_actions {
|
||||||
|
z-index: 999;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
background: #ffffff75;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
border-bottom-left-radius: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #000000aa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget_edit_actions i {
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: #00000020;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const widgets = document.getElementById('widgets');
|
const widgets = document.getElementById('widgets');
|
||||||
let sortable;
|
let sortable;
|
||||||
|
|
||||||
//make widgets draggable
|
|
||||||
function edit_mode(state) {
|
function edit_mode(state) {
|
||||||
|
|
||||||
if (state == 'on') {
|
if (state == 'on') {
|
||||||
$('span#expand_contract, #btn_edit, #btn_add').hide();
|
$('span#expand_contract, #btn_edit, #btn_add').hide();
|
||||||
$('.hud_box').addClass('editable');
|
$('.hud_box').addClass('editable');
|
||||||
$('#btn_back, #btn_save').show();
|
$('#btn_back, #btn_save').show();
|
||||||
$('div.widget').attr('draggable',true).addClass('editable');
|
$('div.widget, div.parent_widget').attr('draggable',true).addClass('editable');
|
||||||
$('div.child_widget').attr('draggable',true).addClass('editable');
|
$('div.child_widget').attr('draggable',true).addClass('editable');
|
||||||
|
|
||||||
function update_widget_order() {
|
// Widget edit actions
|
||||||
let widget_ids_list = [];
|
document.querySelectorAll('.parent_widget > .hud_box').forEach(widget => {
|
||||||
let order = 10;
|
const container = document.createElement('div');
|
||||||
|
container.className = 'widget_edit_actions';
|
||||||
|
|
||||||
widgets.querySelectorAll(':scope > div.widget[id]').forEach(widget => {
|
// Drag handle
|
||||||
const widget_id = widget.id;
|
const grip_icon = document.createElement('i');
|
||||||
|
grip_icon.className = 'fa-solid fa-grip-lines';
|
||||||
|
|
||||||
//add the widgets to the list
|
container.appendChild(grip_icon);
|
||||||
widget_ids_list.push(`${widget_id}|null|${order}`);
|
widget.prepend(container);
|
||||||
order += 10;
|
});
|
||||||
|
|
||||||
//add the nested widgets to the list
|
|
||||||
const nested_container = widget.querySelector('.parent_widget');
|
|
||||||
if (nested_container) {
|
|
||||||
nested_container.querySelectorAll(':scope > div.child_widget[id]').forEach(nested => {
|
|
||||||
const child_id = nested.id;
|
|
||||||
widget_ids_list.push(`${child_id}|${widget_id}|${order}`);
|
|
||||||
order += 10;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('widget_order').value = widget_ids_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Make widgets draggable
|
||||||
sortable = Sortable.create(widgets, {
|
sortable = Sortable.create(widgets, {
|
||||||
group: {
|
group: {
|
||||||
name: 'shared',
|
name: 'shared',
|
||||||
pull: function(to, from, dragEl) {
|
pull: function(to, from, dragEl) {
|
||||||
return !dragEl.hasAttribute('data-is-parent');
|
return !dragEl.classList.contains('parent_widget');
|
||||||
},
|
},
|
||||||
put: true,
|
put: true,
|
||||||
},
|
},
|
||||||
animation: 150,
|
animation: 150,
|
||||||
draggable: '.widget',
|
draggable: '.draggable',
|
||||||
preventOnFilter: true,
|
preventOnFilter: true,
|
||||||
ghostClass: 'ghost',
|
ghostClass: 'ghost',
|
||||||
onSort: update_widget_order,
|
onSort: update_widget_order,
|
||||||
@@ -831,7 +846,7 @@ window.addEventListener('resize', update_parent_height);
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelectorAll('.parent_widget').forEach(function(container) {
|
document.querySelectorAll('.parent_widget > .hud_box > .hud_content').forEach(function(container) {
|
||||||
Sortable.create(container, {
|
Sortable.create(container, {
|
||||||
group: {
|
group: {
|
||||||
name: 'shared',
|
name: 'shared',
|
||||||
@@ -839,7 +854,7 @@ window.addEventListener('resize', update_parent_height);
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
put: function(to, from, dragEl) {
|
put: function(to, from, dragEl) {
|
||||||
return !dragEl.hasAttribute('data-is-parent');
|
return !dragEl.classList.contains('parent_widget');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
animation: 150,
|
animation: 150,
|
||||||
@@ -870,18 +885,43 @@ window.addEventListener('resize', update_parent_height);
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function update_widget_order() {
|
||||||
|
let widget_ids_list = [];
|
||||||
|
let order = 10;
|
||||||
|
|
||||||
|
widgets.querySelectorAll(':scope > div.widget[id]').forEach(widget => {
|
||||||
|
const widget_id = widget.id;
|
||||||
|
|
||||||
|
//add the widgets to the list
|
||||||
|
widget_ids_list.push(`${widget_id}|null|${order}`);
|
||||||
|
order += 10;
|
||||||
|
|
||||||
|
//add the nested widgets to the list
|
||||||
|
const nested_container = widget.querySelector('.parent_widget > .hud_box > .hud_content');
|
||||||
|
if (nested_container) {
|
||||||
|
nested_container.querySelectorAll(':scope > div.child_widget[id]').forEach(nested => {
|
||||||
|
const child_id = nested.id;
|
||||||
|
widget_ids_list.push(`${child_id}|${widget_id}|${order}`);
|
||||||
|
order += 10;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('widget_order').value = widget_ids_list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else { // off
|
else { // off
|
||||||
|
$('div.widget, div.parent_widget, div.child_widget').attr('draggable',false).removeClass('editable');
|
||||||
$('div.widget').attr('draggable',false).removeClass('editable');
|
|
||||||
$('div.child_widget').attr('draggable',false).removeClass('editable');
|
|
||||||
$('.hud_box').removeClass('editable');
|
$('.hud_box').removeClass('editable');
|
||||||
$('#btn_back, #btn_save').hide();
|
$('#btn_back, #btn_save').hide();
|
||||||
$('span#expand_contract, #btn_edit, #btn_add').show();
|
$('span#expand_contract, #btn_edit, #btn_add').show();
|
||||||
|
|
||||||
|
document.querySelectorAll('.widget_edit_actions').forEach(element => element.remove());
|
||||||
|
|
||||||
sortable.option('disabled', true);
|
sortable.option('disabled', true);
|
||||||
document.querySelectorAll('.parent_widget').forEach(el => {
|
document.querySelectorAll('.parent_widget > .hud_box > .hud_content').forEach(element => {
|
||||||
const nested_sortable = Sortable.get(el);
|
const nested_sortable = Sortable.get(element);
|
||||||
|
|
||||||
if (nested_sortable) {
|
if (nested_sortable) {
|
||||||
nested_sortable.option('disabled', true);
|
nested_sortable.option('disabled', true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
div.parent_widget {
|
.parent_widget > .hud_box > .hud_content {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -124,9 +124,9 @@ foreach ($child_widgets as $row) {
|
|||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
//include the dashboards
|
//include the widgets
|
||||||
echo "<div class='hud_box'>\n";
|
echo "<div class='hud_box'>\n";
|
||||||
echo " <div class='hud_content parent_widget'>\n";
|
echo " <div class='hud_content'>\n";
|
||||||
|
|
||||||
$x = 0;
|
$x = 0;
|
||||||
foreach ($child_widgets as $row) {
|
foreach ($child_widgets as $row) {
|
||||||
|
|||||||
@@ -3004,7 +3004,8 @@ else { //default: white
|
|||||||
border: 1px solid <?=$dashboard_border_color_hover?>;
|
border: 1px solid <?=$dashboard_border_color_hover?>;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.widget div.hud_box:first-of-type {
|
div.widget div.hud_box:first-of-type,
|
||||||
|
div.parent_widget div.hud_box:first-of-type {
|
||||||
<?php
|
<?php
|
||||||
echo "background: ".($dashboard_background_color[0] ?? '#ffffff').";\n";
|
echo "background: ".($dashboard_background_color[0] ?? '#ffffff').";\n";
|
||||||
if (!empty($dashboard_background_color) && is_array($dashboard_background_color) && sizeof($dashboard_background_color) > 1) {
|
if (!empty($dashboard_background_color) && is_array($dashboard_background_color) && sizeof($dashboard_background_color) > 1) {
|
||||||
|
|||||||
Reference in New Issue
Block a user