This is an automated email from the ASF dual-hosted git repository.

gstein pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/steve.git

commit 932ec2465f9fd0664d1187ad63c3b0ddc7a0ba70
Author: Greg Stein <[email protected]>
AuthorDate: Mon Dec 22 19:30:49 2025 -0600

    copy of manage.ezt; will revise to manage an STV vote
---
 v3/server/templates/manage-stv.ezt | 292 +++++++++++++++++++++++++++++++++++++
 1 file changed, 292 insertions(+)

diff --git a/v3/server/templates/manage-stv.ezt 
b/v3/server/templates/manage-stv.ezt
new file mode 100644
index 0000000..2a0821b
--- /dev/null
+++ b/v3/server/templates/manage-stv.ezt
@@ -0,0 +1,292 @@
+[include "header.ezt"]
+    <div class="container">
+        <h1>[title]</h1>
+        [include "flashes.ezt"]
+
+        <div class="sticky-top">
+            <h2>[e_title]</h2>
+        </div>
+
+    <div class="state-diagram">
+        <div id="state-editing"
+           class="state [is e_state "editable"]current[end]">Editing</div>
+        <div id="arrow1" class="arrow">→</div>
+        <div id="state-open"
+           class="state [is e_state "open"]current[end]">Open for Voting</div>
+        <div id="arrow2" class="arrow">→</div>
+        <div id="state-closed"
+           class="state [is e_state "closed"]current[end]">Closed</div>
+
+        [is e_state "editable"]
+            <button id="open-btn" class="btn btn-success action-button 
open-button">
+                <i class="bi bi-unlock me-1"></i>Open
+            </button>
+        [end]
+        [is e_state "open"]
+            <button id="close-btn" class="btn btn-danger action-button 
close-button">
+                <i class="bi bi-lock me-1"></i>Close
+            </button>
+        [end]
+    </div>
+
+    <!-- Open Confirmation Modal -->
+    <div class="modal fade" id="openConfirmModal" tabindex="-1" 
aria-labelledby="openConfirmModalLabel" aria-hidden="true">
+        <div class="modal-dialog">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title" id="openConfirmModalLabel">Confirm 
Open Election</h5>
+                    <button type="button" class="btn-close" 
data-bs-dismiss="modal" aria-label="Close"></button>
+                </div>
+                <div class="modal-body">
+                    Opening this election will allow voting and is 
irreversible. Are you sure?
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" 
data-bs-dismiss="modal">Cancel</button>
+                    <button type="button" class="btn btn-success" 
id="confirm-open">Confirm</button>
+                </div>
+            </div>
+        </div>
+    </div>[# id=openConfirmModal ]
+
+    <!-- Close Confirmation Modal -->
+    <div class="modal fade" id="closeConfirmModal" tabindex="-1" 
aria-labelledby="closeConfirmModalLabel" aria-hidden="true">
+        <div class="modal-dialog">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title" 
id="closeConfirmModalLabel">Confirm Close Election</h5>
+                    <button type="button" class="btn-close" 
data-bs-dismiss="modal" aria-label="Close"></button>
+                </div>
+                <div class="modal-body">
+                    Closing this election will end voting permanently. Are you 
sure?
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" 
data-bs-dismiss="modal">Cancel</button>
+                    <button type="button" class="btn btn-danger" 
id="confirm-close">Confirm</button>
+                </div>
+            </div>
+        </div>
+    </div>[# id=closeConfirmModal ]
+
+    <!-- Edit/Add Issue Modal -->
+    <div class="modal fade" id="issueModal" tabindex="-1" 
aria-labelledby="issueModalLabel" aria-hidden="true">
+        <div class="modal-dialog">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title" id="issueModalLabel">Edit 
Issue</h5>
+                    <button type="button" class="btn-close" 
data-bs-dismiss="modal" aria-label="Close"></button>
+                </div>
+                <div class="modal-body">
+                    <form id="issueForm" method="POST" action="">
+                        <input type="hidden" name="csrf_token" 
value="[csrf_token]">
+                        <input type="hidden" id="issueId" name="issueId" 
value="">
+                        <div class="mb-3">
+                            <label for="issueTitle" 
class="form-label">Title</label>
+                            <input type="text" class="form-control" 
id="issueTitle" name="title" required
+                                   aria-describedby="issueTitleHelp">
+                            <div id="issueTitleHelp" class="form-text">
+                                A brief title for this issue or ballot item.
+                            </div>
+                            <div class="invalid-feedback">Title is 
required.</div>
+                        </div>
+                        <div class="mb-3">
+                            <label for="issueDescription" 
class="form-label">Description</label>
+                            <textarea class="form-control" 
id="issueDescription" name="description" rows="4"
+                                      
aria-describedby="issueDescriptionHelp"></textarea>
+                            <div id="issueDescriptionHelp" class="form-text">
+                                Optional details about this issue for voters.
+                            </div>
+                        </div>
+                    </form>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" 
data-bs-dismiss="modal">Cancel</button>
+                    <button type="button" class="btn btn-primary" 
id="saveIssueBtn" onclick="saveIssue()">Save</button>
+                </div>
+            </div>[# modal-content ]
+        </div>[# modal-dialog ]
+    </div>[# id=issueModal ]
+
+    <!-- Delete Issue Confirmation Modal -->
+    <div class="modal fade" id="deleteIssueModal" tabindex="-1" 
aria-labelledby="deleteIssueModalLabel" aria-hidden="true">
+        <div class="modal-dialog">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title" id="deleteIssueModalLabel">Confirm 
Delete</h5>
+                    <button type="button" class="btn-close" 
data-bs-dismiss="modal" aria-label="Close"></button>
+                </div>
+                <div class="modal-body">
+                    <p id="deleteIssueMessage">Are you sure you want to delete 
this issue?</p>
+                    <form id="deleteIssueForm" method="POST" action="">
+                        <input type="hidden" name="csrf_token" 
value="[csrf_token]">
+                        <input type="hidden" id="deleteIssueId" name="issueId" 
value="">
+                    </form>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" 
data-bs-dismiss="modal">Cancel</button>
+                    <button type="submit" class="btn btn-danger" 
form="deleteIssueForm" id="deleteIssueBtn">
+                        <i class="bi bi-trash me-1"></i>Delete
+                    </button>
+                </div>
+            </div>[# modal-content ]
+        </div>[# modal-dialog ]
+    </div>[# id=deleteIssueModal ]
+
+        <div>
+            State: [e_state]
+        </div>
+        <div>
+            Estimate to open: <input type="date">
+        </div>
+        <div class="mb-3">
+            Estimate to close: <input type="date">
+        </div>
+
+        <div class="mb-4">
+            <button type="button" class="btn btn-primary" 
onclick="openAddIssueModal()">
+                <i class="bi bi-plus-circle me-1"></i>Add Issue
+            </button>
+            <button type="button" class="btn btn-outline-secondary ms-2" 
onclick="toggleAllDescriptions()">
+                <i class="bi bi-arrows-expand me-1"></i>
+                <span id="toggle-all-text">Expand All</span>
+            </button>
+        </div>
+
+        <div id="issues-list" class="list-group">
+            [for issues]
+            <div class="list-group-item issue-item">
+                <div class="d-flex justify-content-between align-items-center">
+                    <div>
+                        <span class="twiddle bi bi-caret-right-fill me-2" 
onclick="toggleDescription('[issues.iid]')"></span>
+                        <strong>[issues.title]</strong>
+                    </div>
+                    <div class="action-buttons">
+                        <button type="button" class="btn btn-outline-primary 
btn-sm me-1"
+                              onclick="openEditIssueModal('[issues.iid]',
+                                                          '[format 
"js,html"][issues.title][end]',
+                                                          '[format 
"js,html"][issues.description][end]')"
+                              aria-label="Edit Issue">
+                            <i class="bi bi-pencil"></i>
+                        </button>
+                        <button type="button" class="btn btn-outline-danger 
btn-sm"
+                              onclick="openDeleteIssueModal('[issues.iid]',
+                                                            '[format 
"js,html"][issues.title][end]')"
+                              aria-label="Delete Issue">
+                            <i class="bi bi-trash"></i>
+                        </button>
+                    </div>
+               </div>
+               <div id="description-[issues.iid]" class="description 
mt-2">[issues.description]</div>
+           </div>
+           [end]
+       </div>
+
+    </div>
+
+[include "footer.ezt"]
+
+<script>
+    const openModal = new 
bootstrap.Modal(document.getElementById('openConfirmModal'));
+    const closeModal = new 
bootstrap.Modal(document.getElementById('closeConfirmModal'));
+
+    [is e_state "editable"]
+        const openBtn = document.getElementById('open-btn');
+        openBtn.addEventListener('click', () => {
+            openModal.show();
+        });
+    [end]
+    const confirmOpen = document.getElementById('confirm-open');
+    confirmOpen.addEventListener('click', () => {
+        openModal.hide();
+        window.location.href = '/do-open/[eid]';
+    });
+
+    [is e_state "open"]
+        const closeBtn = document.getElementById('close-btn');
+        closeBtn.addEventListener('click', () => {
+            closeModal.show();
+        });
+    [end]
+    const confirmClose = document.getElementById('confirm-close');
+    confirmClose.addEventListener('click', () => {
+        closeModal.hide();
+        window.location.href = '/do-close/[eid]';
+    });
+
+    // Toggle individual description
+    function toggleDescription(issueId) {
+      const desc = document.getElementById(`description-${issueId}`);
+      const twiddle = desc.previousElementSibling.querySelector('.twiddle');
+      if (desc && twiddle) {
+        desc.classList.toggle('show');
+        twiddle.classList.toggle('bi-caret-right-fill');
+        twiddle.classList.toggle('bi-caret-down-fill');
+      }
+    }
+
+    // Expand/Collapse All descriptions
+    let allExpanded = false;
+    function toggleAllDescriptions() {
+      allExpanded = !allExpanded;
+      document.querySelectorAll('.description').forEach(desc => {
+        desc.classList.toggle('show', allExpanded);
+      });
+      document.querySelectorAll('.twiddle').forEach(twiddle => {
+        twiddle.classList.toggle('bi-caret-right-fill', !allExpanded);
+        twiddle.classList.toggle('bi-caret-down-fill', allExpanded);
+      });
+      const toggleBtn = document.querySelector('.btn-outline-secondary');
+      const toggleIcon = toggleBtn.querySelector('i');
+      const toggleText = document.getElementById('toggle-all-text');
+      
+      if (allExpanded) {
+        toggleIcon.className = 'bi bi-arrows-collapse me-1';
+        toggleText.textContent = 'Collapse All';
+      } else {
+        toggleIcon.className = 'bi bi-arrows-expand me-1';
+        toggleText.textContent = 'Expand All';
+      }
+    }
+
+    // Open modal for adding issue
+    function openAddIssueModal() {
+      const form = document.getElementById('issueForm');
+      form.action = '/do-add-issue/[eid]';
+      document.getElementById('issueModalLabel').textContent = 'Add Issue';
+      document.getElementById('issueId').value = '';
+      document.getElementById('issueTitle').value = '';
+      document.getElementById('issueDescription').value = '';
+      document.getElementById('issueTitle').classList.remove('is-invalid');
+      showModal('issueModal');
+    }
+
+    // Open modal for editing issue
+    function openEditIssueModal(issueId, title, description) {
+      const form = document.getElementById('issueForm');
+      form.action = `/do-edit-issue/[eid]/${issueId}`;
+      document.getElementById('issueModalLabel').textContent = 'Edit Issue';
+      document.getElementById('issueId').value = issueId;
+      document.getElementById('issueTitle').value = title;
+      document.getElementById('issueDescription').value = description;
+      document.getElementById('issueTitle').classList.remove('is-invalid');
+      showModal('issueModal');
+    }
+
+    // Open modal for deleting issue
+    function openDeleteIssueModal(issueId, title) {
+      const form = document.getElementById('deleteIssueForm');
+      form.action = `/do-delete-issue/[eid]/${issueId}`;
+      document.getElementById('deleteIssueId').value = issueId;
+      document.getElementById('deleteIssueMessage').textContent = `Are you 
sure you want to delete "${title}"?`;
+      showModal('deleteIssueModal');
+    }
+
+    // Save issue (add or edit)
+    function saveIssue() {
+      if (!validateRequiredField('issueTitle')) {
+        return;
+      }
+
+      submitFormWithLoading('issueForm', 'saveIssueBtn', 'Saving...');
+    }
+
+</script>

Reply via email to