From fa0216f1a65f6961711f74d708957c44665fab98 Mon Sep 17 00:00:00 2001 From: Tim Fry Date: Tue, 3 Dec 2024 18:25:25 -0400 Subject: [PATCH] fully functional but missing permissions --- app/phrases/phrase_edit.php | 95 ++++-- .../resources/javascript/phrase_edit.js | 300 +++++++++++------- 2 files changed, 252 insertions(+), 143 deletions(-) diff --git a/app/phrases/phrase_edit.php b/app/phrases/phrase_edit.php index d85b7beb41..e8ba79f0af 100644 --- a/app/phrases/phrase_edit.php +++ b/app/phrases/phrase_edit.php @@ -65,40 +65,68 @@ function build_data_array_from_post(settings $settings) { // Create two arrays - one for rows to delete and one for new/updated rows // for ($i = 0; $i < count($_POST['phrase_detail_function']); $i++) { - //check for the empty rows to delete - if (empty($_POST['phrase_detail_data'][$i]) && !empty($_POST['phrase_detail_uuid'][$i])) { + //check for function to perform + $phrase_detail_function = $_POST['phrase_detail_function'][$i]; + $phrase_detail_data = null; + $recording_uuid_or_file = ''; + $phrase_detail_uuid = ''; + //check for the empty rows to delete -- 0,false,null is valid + if (strlen($_POST['phrase_detail_data'][$i]) === 0 + && !empty($_POST['phrase_detail_uuid'][$i]) + && empty($_POST['slider'][$i]) + && empty($_POST['phrase_detail_text'][$i])) { $drop_rows['phrase_details'][$drop_row_count++]['phrase_detail_uuid'] = $_POST['phrase_detail_uuid'][$i]; continue; } - //only save rows with data - if (!empty($_POST['phrase_detail_data'][$i])) { - $recording_uuid_or_file = $_POST['phrase_detail_data'][$i]; - //check for valid recordings and files - if (is_uuid($recording_uuid_or_file)) { - //recording UUID - $phrase_detail_data = $recording_files[$recording_uuid_or_file]; - } else { - //not a recording so must be valid path inside the switch recording files - if (in_array($recording_uuid_or_file, $sound_files)) { - //valid switch audio file - $phrase_detail_data = $recording_uuid_or_file; - } else { - //ignore an invalid audio file - continue; + switch ($phrase_detail_function) { + case 'play-file': + //only save rows with data + if (!empty($_POST['phrase_detail_data'][$i])) { + $recording_uuid_or_file = $_POST['phrase_detail_data'][$i]; + //check for valid recordings and files + if (is_uuid($recording_uuid_or_file)) { + //recording UUID + $phrase_detail_data = $recording_files[$recording_uuid_or_file]; + } else { + //not a recording so must be valid path inside the switch recording files + if (in_array($recording_uuid_or_file, $sound_files)) { + //valid switch audio file + $phrase_detail_data = $recording_uuid_or_file; + } else { + //ignore an invalid audio file + continue(2); + } + } + //build data array + if ($_POST['phrase_detail_function'][$i] == 'execute' && substr($_POST['phrase_detail_data'][$i], 0,5) != "sleep" && !permission_exists("phrase_execute")) { + header("Location: phrase_edit.php?id=".$phrase_uuid); + exit; + } } - } - //build data array - if ($_POST['phrase_detail_function'][$i] == 'execute' && substr($_POST['phrase_detail_data'][$i], 0,5) != "sleep" && !permission_exists("phrase_execute")) { - header("Location: phrase_edit.php?id=".$phrase_uuid); - exit; - } - $_POST['phrase_detail_tag'] = 'action'; // default, for now - $_POST['phrase_detail_group'] = "0"; // one group, for now + break; + case 'pause': + //check for value + $phrase_detail_data = $_POST['slider'][$i]; + break; + case 'execute': + //check for the empty rows to delete + if (empty($_POST['phrase_detail_text'][$i]) && !empty($_POST['phrase_detail_uuid'][$i])) { + $drop_rows['phrase_details'][$drop_row_count++]['phrase_detail_uuid'] = $_POST['phrase_detail_uuid'][$i]; + continue(2); + } + $phrase_detail_data = $_POST['phrase_detail_text'][$i]; + break; + } - //update existing records in the database + $_POST['phrase_detail_tag'] = 'action'; // default, for now + $_POST['phrase_detail_group'] = "0"; // one group, for now + + if ($phrase_detail_data !== null) { if (!empty($_POST['phrase_detail_uuid'][$i])) { + //update existing records in the database $phrase_detail_uuid = $_POST['phrase_detail_uuid'][$i]; } else { + //new record $phrase_detail_uuid = uuid(); } $array['phrase_details'][$i]['phrase_detail_uuid'] = $phrase_detail_uuid; @@ -107,7 +135,7 @@ function build_data_array_from_post(settings $settings) { $array['phrase_details'][$i]['phrase_detail_order'] = $i; $array['phrase_details'][$i]['phrase_detail_tag'] = $_POST['phrase_detail_tag']; $array['phrase_details'][$i]['phrase_detail_pattern'] = $_POST['phrase_detail_pattern'] ?? null; - $array['phrase_details'][$i]['phrase_detail_function'] = $_POST['phrase_detail_function'][$i]; + $array['phrase_details'][$i]['phrase_detail_function'] = $phrase_detail_function; $array['phrase_details'][$i]['phrase_detail_data'] = $phrase_detail_data; //path and filename of recording $array['phrase_details'][$i]['phrase_detail_method'] = $_POST['phrase_detail_method'] ?? null; $array['phrase_details'][$i]['phrase_detail_type'] = $_POST['phrase_detail_type'] ?? null; @@ -481,12 +509,12 @@ if (count($_POST) > 0) { echo ""; //cloning row and buttons created outside of 'structure' table body echo ""; - echo "\n"; + echo "\n"; echo "
"; echo " \n"; echo " \n"; // } - echo " "; + echo " "; + echo " "; + echo " "; + echo " "; + echo " "; + echo " "; echo " \n"; - echo " \n"; + echo "\n"; echo ""; echo " "; echo "
"; diff --git a/app/phrases/resources/javascript/phrase_edit.js b/app/phrases/resources/javascript/phrase_edit.js index 2b8fbcc856..1385f5a769 100644 --- a/app/phrases/resources/javascript/phrase_edit.js +++ b/app/phrases/resources/javascript/phrase_edit.js @@ -31,75 +31,37 @@ document.addEventListener("DOMContentLoaded", function () { add_draggable_rows(); }); -// -// Switch to a text input box when 'Execute' is selected instead of dropdown -// -function add_switch_to_text_input(select_action) { - if (window.permission_execute) { - const row = select_action.parentNode.parentNode; - const row_index = document.getElementById('structure').rows.length; - //get the select boxes - const select_list = row.querySelectorAll('td select'); //action and recording select dropdown boxes - const select_data = select_list[1]; - - // Create a new text input to replace the select when execute is chosen - const textInput = document.createElement('input'); - textInput.type = 'text'; - textInput.className = 'formfld'; - textInput.id = 'phrase_detail_data_input[' + row_index + ']'; - textInput.name = 'phrase_detail_data_input[' + row_index + ']'; - //match style - textInput.style.width = select_data.style.width; - textInput.style.height = select_data.style.height; - //set to hide - textInput.style.display = 'none'; - select_data.parentNode.appendChild(textInput); - - select_action.addEventListener('change', function () { - if (select_action.value === 'execute') { - //show text box - select_data.style.display = 'none'; - textInput.style.display = 'block'; - } else { - //hide text box - select_data.style.display = 'block'; - textInput.style.display = 'none'; - } - }); - } -} - // // Inserts all existing records before the empty one // function add_existing() { const tbody = document.getElementById('structure'); - for (let i=0; i < window.phrase_details.length; i++) { - const newRow = document.getElementById('empty_row').cloneNode(true); - - //un-hide the row - newRow.style.display = ''; - - //get the select boxes - const select_list = newRow.querySelectorAll('td select'); //action and recording select dropdown boxes - //play, pause, execute select box - const select_action = select_list[0]; - add_switch_to_text_input(select_action); - select_by_value(select_action, 'play-file'); - - //recording select box - const select_recording = select_list[1]; - select_by_text(select_recording, window.phrase_details[i]['display_name']); - - const input_fields = newRow.querySelectorAll('td input'); - const uuid_field = input_fields[0]; - uuid_field.setAttribute('id' , 'phrase_detail_uuid[' + i +']'); - uuid_field.setAttribute('name', 'phrase_detail_uuid[' + i +']'); - uuid_field.value = window.phrase_details[i]['phrase_detail_uuid']; - - //add the row to the table body - tbody.appendChild(newRow); + for (let index=0; index < window.phrase_details.length; index++) { + add_row(); + const select_action = document.getElementById('phrase_detail_function[' + index + ']'); + select_by_value(select_action, window.phrase_details[index].phrase_detail_function); + const select_data = document.getElementById('phrase_detail_data[' + index + ']'); + select_by_text(select_data, window.phrase_details[index]['display_name']); + const uuid_field = document.getElementById('phrase_detail_uuid[' +index+']'); + uuid_field.value = window.phrase_details[index]['phrase_detail_uuid']; + const slider = document.getElementById('slider['+index+']'); + const sleep = document.getElementById('sleep['+index+']'); + const phrase_detail_text = document.getElementById('phrase_detail_text['+index+']'); + //update the sleep data + if (window.phrase_details[index].phrase_detail_function === 'pause') { + sleep.value = window.phrase_details[index].phrase_detail_data; + slider.value = window.phrase_details[index].phrase_detail_data; + } + //update the execute text + if (window.phrase_details[index].phrase_detail_function === 'execute') { + phrase_detail_text.value = window.phrase_details[index].phrase_detail_data; + } + // Manually trigger the change event to select the proper display + if (window.phrase_details[index].phrase_detail_function !== 'play-file') { + const changeEvent = new Event('change', { bubbles: true }); + select_action.dispatchEvent(changeEvent); + } } } @@ -107,27 +69,27 @@ function add_existing() { // Set the selected index on a dropdown box based on the value (key) // function select_by_value(selectElement, valueToFind) { - // Loop through the options of the select element - for (let i = 0; i < selectElement.options.length; i++) { - if (selectElement.options[i].value === valueToFind) { - selectElement.selectedIndex = i; // Set the selected index - return; // Exit the loop once found - } - } - console.warn('Value not found in select options'); + // Loop through the options of the select element + for (let i = 0; i < selectElement.options.length; i++) { + if (selectElement.options[i].value === valueToFind) { + selectElement.selectedIndex = i; // Set the selected index + return; // Exit the loop once found + } + } + console.warn('Value not found in select options'); } // // Set the selected index on a dropdown box based on the text // function select_by_text(selectElement, textToFind) { - for (let i = 0; i < selectElement.options.length; i++) { - if (selectElement.options[i].text === textToFind) { - selectElement.selectedIndex = i; - return; - } - } - console.warn('Text not found in select options'); + for (let i = 0; i < selectElement.options.length; i++) { + if (selectElement.options[i].text === textToFind) { + selectElement.selectedIndex = i; + return; + } + } + console.warn('Text not found in select options'); } // @@ -137,29 +99,47 @@ function add_draggable_rows() { const tableBody = document.getElementById('structure'); let draggedRow = null; - // Add drag-and-drop functionality - tableBody.addEventListener('dragstart', (e) => { - draggedRow = e.target; - e.target.classList.add('dragging'); - }); + // Add drag listeners only to the leftmost cell on the row + tableBody.querySelectorAll('tr').forEach(row => { + const dragHandleCell = row.cells[0]; // Assuming the first cell is the one left to the dropdown - tableBody.addEventListener('dragover', (e) => { - e.preventDefault(); - const targetRow = e.target.closest('tr'); - if (targetRow && targetRow !== draggedRow) { - const bounding = targetRow.getBoundingClientRect(); - const offset = e.clientY - bounding.top; - if (offset > bounding.height / 2) { - targetRow.parentNode.insertBefore(draggedRow, targetRow.nextSibling); - } else { - targetRow.parentNode.insertBefore(draggedRow, targetRow); + if (!dragHandleCell) return; + + // Enable dragging from this cell + dragHandleCell.setAttribute('draggable', 'true'); + + dragHandleCell.addEventListener('dragstart', (e) => { + draggedRow = row; + row.classList.add('dragging'); + }); + + dragHandleCell.addEventListener('dragend', () => { + if (draggedRow) { + draggedRow.classList.remove('dragging'); + draggedRow = null; } - } - }); + }); - tableBody.addEventListener('dragend', () => { - draggedRow.classList.remove('dragging'); - draggedRow = null; + dragHandleCell.addEventListener('dragover', (e) => { + e.preventDefault(); + const targetRow = e.target.closest('tr'); + if (targetRow && targetRow !== draggedRow) { + const bounding = targetRow.getBoundingClientRect(); + const offset = e.clientY - bounding.top; + if (offset > bounding.height / 2) { + targetRow.parentNode.insertBefore(draggedRow, targetRow.nextSibling); + } else { + targetRow.parentNode.insertBefore(draggedRow, targetRow); + } + } + }); + dragHandleCell.addEventListener('dragend', () => { + if (draggedRow) { + draggedRow.classList.remove('dragging'); + draggedRow = null; + update_order(); + } + }); }); } @@ -180,18 +160,47 @@ function update_order() { //get the select boxes const select_list = row.querySelectorAll('td select'); //action and recording select dropdown boxes + //get the input boxes + const input_boxes = row.querySelectorAll('td input'); + console.log(input_boxes); + //uuid + const phrase_detail_uuid = input_boxes[0]; + phrase_detail_uuid.removeAttribute('id'); + phrase_detail_uuid.id = 'phrase_detail_uuid[' + index + ']'; + phrase_detail_uuid.name = phrase_detail_uuid.id; + //execute action + const phrase_detail_text = input_boxes[1]; + temp_value = phrase_detail_text.value; + console.log('phrase_detail_text', temp_value); + phrase_detail_text.removeAttribute('id'); + phrase_detail_text.id = 'phrase_detail_text[' + index + ']'; + phrase_detail_text.name = phrase_detail_text.id; + phrase_detail_text.value = temp_value; + //slider + const slider = input_boxes[2]; + slider.removeAttribute('id'); + slider.id = 'slider[' + index + ']'; + slider.name = slider.id; + //sleep value + const sleep = input_boxes[3]; + temp_value = sleep.value; + sleep.removeAttribute('id'); + sleep.id = 'sleep[' + index + ']'; + sleep.name = sleep.id; + sleep.value = temp_value; + //play, pause, execute select box - const select_action = select_list[0]; + const select_function = select_list[0]; + select_function.removeAttribute('id'); + select_function.id = 'phrase_detail_function[' + index + ']' + select_function.name = select_function.id; //recording select box - const select_recording = select_list[1]; + const select_data = select_list[1]; + select_data.removeAttribute('id'); + select_data.id = 'phrase_detail_data[' + index + ']' + select_data.name = select_data.id; - //set the new id and name for action - select_action.id = 'phrase_detail_function[' + index + ']' - select_action.setAttribute('name', 'phrase_detail_function[' + index + ']'); - //set the new id and name for recording - select_recording.id = 'phrase_detail_data[' + index + ']' - select_recording.setAttribute('name', 'phrase_detail_data[' + index + ']'); }); } @@ -210,16 +219,18 @@ function submit_phrase() { // function add_row() { const tbody = document.getElementById('structure'); - const newRow = document.getElementById('empty_row').cloneNode(true); // current index is the count subtract the hidden row - const index = tbody.childElementCount - 1; + const index = tbody.childElementCount; + + const newRow = document.getElementById('empty_row').cloneNode(true); + //reset id + newRow.removeAttribute('id'); + newRow.id = 'row_' + index; //un-hide row newRow.style.display = ''; - //reset id - newRow.id = 'row_' + index; //reset 'name' attribute newRow.setAttribute('name', 'recording_' + index); @@ -227,17 +238,82 @@ function add_row() { const select_list = newRow.querySelectorAll('td select'); //action and recording select dropdown boxes //play, pause, execute select box const select_action = select_list[0]; + select_action.removeAttribute('id'); + select_action.id = 'phrase_detail_function[' + index + ']'; + select_action.name = 'phrase_detail_function[' + index + ']'; //recording select box - const select_recording = select_list[1]; + const select_data = select_list[1]; + select_data.removeAttribute('id'); + select_data.id = 'phrase_detail_data[' + index + ']'; + select_data.name = 'phrase_detail_data[' + index + ']'; + //uuid field + const uuid_field = newRow.querySelector('input[name="empty_uuid"]'); + uuid_field.removeAttribute('id'); + uuid_field.id = 'phrase_detail_uuid[' + index +']'; + uuid_field.name = 'phrase_detail_uuid[' + index +']'; + const phrase_detail_text = newRow.querySelector('input[name="empty_phrase_detail_text"]'); + phrase_detail_text.removeAttribute('id'); + phrase_detail_text.id = 'phrase_detail_text[' + index + ']'; + phrase_detail_text.name = 'phrase_detail_text[' + index + ']'; + //slider + const slider = newRow.querySelector('input[name="range"]'); + slider.removeAttribute('id'); + slider.id = 'slider[' + index + ']'; + slider.name = 'slider[' + index + ']'; + //sleep + const sleep = newRow.querySelector('input[name="sleep"]'); + sleep.removeAttribute('id'); + sleep.id = 'sleep[' + index + ']'; + sleep.name = 'sleep[' + index + ']'; + sleep.value = slider.value; + + let changing = false; + + slider.addEventListener('mousemove', function () { + changing = true; + sleep.value = slider.value; + changing = false; + }); + + sleep.addEventListener('keyup', function() { + if (!changing) { + if (sleep.value.length > 0) + slider.value = sleep.value; + else { + slider.value = 0; + } + } + }) //add switchable select box to text input box - add_switch_to_text_input(select_action); + select_action.addEventListener('change', function () { + if (select_action.value === 'execute') { + //show text box + select_data.style.display = 'none'; + slider.style.display = 'none'; + sleep.style.display = 'none'; + phrase_detail_text.style.display = 'block'; + } else if (select_action.value === 'pause') { + //show the range bar + select_data.style.display = 'none'; + phrase_detail_text.style.display = 'none'; + slider.style.display = 'block'; + sleep.style.display = 'block'; + } else { + //show drop down + phrase_detail_text.style.display = 'none'; + slider.style.display = 'none'; + sleep.style.display = 'none'; + select_data.style.display = 'block'; + } + }); //add the row to the table body tbody.appendChild(newRow); //reinitialize draggable functionality on the row add_draggable_rows(); + return index; } //