From d7dbe7fee362d587dfc334135d9581b6216a4295 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 23 Nov 2025 04:13:56 +0000
Subject: [PATCH] =Timeline block, and feed block updated. DataStore.js refactored to not block rendering

---
 inc/managers/CRUDManager.php |  174 ++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 140 insertions(+), 34 deletions(-)

diff --git a/inc/managers/CRUDManager.php b/inc/managers/CRUDManager.php
index aa4293d..e05a0e5 100644
--- a/inc/managers/CRUDManager.php
+++ b/inc/managers/CRUDManager.php
@@ -58,6 +58,10 @@
 		];
 
 		$this->init();
+
+		if ($this->isTimeline) {
+			$this->stuck[] = 'post_thumbnail';
+		}
 		add_filter('jvbAdditionalActions', [$this, 'createItem']);
 	}
 
@@ -89,6 +93,7 @@
 		}));
 		array_unshift($this->timelineSharedFields, 'post_thumbnail');
 		array_unshift($this->timelineSharedFields, 'post_title');
+		array_unshift($this->timelineSharedFields, 'post_status');
 
 		$this->timelineUniqueFields = array_keys(array_filter($this->fields, function ($field) {
 			if (array_key_exists('for_all', $field) && $field['for_all'] === true) {
@@ -192,7 +197,7 @@
 	{
 		ob_start();
 		?>
-		<div class="dashboard-page <?= esc_attr($this->content) ?>">
+		<div class="dashboard-page <?= esc_attr($this->content) ?>"<?=($this->isTimeline) ? ' data-timeline' : ''?>>
 			<?php
 			$this->renderHeader();
 			$this->renderContent();
@@ -331,7 +336,7 @@
 			<?php
 				$order = [
 					'orderby' => [
-						'calendar' => 'Order by date created',
+						'date' => 'Order by date created',
 						'alphabetical' => 'Order alphabetically'
 					],
 					'order' => [
@@ -347,10 +352,11 @@
 					<?php
 					$i = 0;
 					foreach ($option as $opt => $label) {
+						$icon = $opt === 'date' ? 'calendar' : $opt;
 						?>
 						<input id="<?=$opt?>" class="btn" type="radio" name="<?=$o?>" data-filter="<?=$o?>" value="<?=$opt?>"<?=$i===0 ? ' checked':''?>>
 
-						<label for="<?=$opt?>" title="<?=$label?>"><?=jvbIcon($opt)?></label>
+						<label for="<?=$opt?>" title="<?=$label?>"><?=jvbIcon($icon)?></label>
 						<?php
 						$i++;
 					}
@@ -736,36 +742,6 @@
 	}
 
 
-	protected function renderTimelineFields():string
-	{
-		ob_start();
-
-
-		?>
-		<div class="repeater-field timeline-repeater" data-timeline data-field="fields">
-			<div class="repeater-rows" data-repeater-container>
-				<!-- Parent row (non-draggable) -->
-				<div class="repeater-row parent-row" data-row-index="0" data-id="">
-					<div class="row-header">
-						<h4>Before (Starting Point)</h4>
-					</div>
-					<div class="row-fields">
-						<?php $this->renderRowFields(); ?>
-					</div>
-				</div>
-
-				<!-- Child rows will be added dynamically -->
-			</div>
-
-			<button type="button" class="add-repeater-row btn secondary">
-				<?= jvbIcon('plus-square') ?>
-				<span>Add Progress Step</span>
-			</button>
-		</div>
-		<?php
-		return ob_get_clean();
-	}
-
 	protected function renderRowFields():void
 	{
 		$fields = $this->fields;
@@ -1010,6 +986,10 @@
 
 	protected function renderTableView():void
 	{
+		if ($this->isTimeline) {
+			$this->renderTimelineTableView();
+			return;
+		}
 		?>
 		<template class="contentTable">
 			<form class="table"
@@ -1038,13 +1018,17 @@
 	 * Render table row template
 	 */
 	protected function renderTableRow(): void {
+		if ($this->isTimeline) {
+			$this->renderTimelineTableGroup();
+			return;
+		}
 		?>
 		<template class="tableView">
 			<tr class="item">
 				<td class="select">
 					<?= $this->renderItemSelect() ?>
 				</td>
-				<td class="status">
+				<td class="status" data-field="post_status">
 					<?= $this->renderStatusRadios() ?>
 				</td>
 				<?php
@@ -1070,6 +1054,102 @@
 		</template>
 		<?php
 	}
+
+	protected function renderTimelineTableView():void
+	{
+		?>
+		<template class="contentTable">
+			<form class="table"
+				  data-save="content"
+				  data-content="<?= esc_attr($this->content) ?>"
+				  data-form-id="content-table-<?= esc_attr($this->content) ?>">
+				<?= jvbFormStatus() ?>
+				<?= $this->renderTableActions() ?>
+
+				<table>
+					<thead>
+					<?= $this->renderTimelineTableHeader() ?>
+					</thead>
+					<!-- Rows are inserted as tbody groups -->
+					<tfoot>
+					<?= $this->renderTimelineTableHeader() ?>
+					</tfoot>
+				</table>
+			</form>
+		</template>
+		<?php
+	}
+
+	protected function renderTimelineTableGroup():void
+	{
+		$makeDetails = [
+			'group',
+			'repeater',
+			'checkbox',
+			'radio'
+		];
+		?>
+		<template class="tableView">
+			<tbody class="item">
+				<tr class="shared">
+					<td class="select">
+						<?= $this->renderItemSelect() ?>
+					</td>
+					<td class="show-post_status field" data-field="post_status">
+						<?= $this->renderStatusRadios() ?>
+					</td>
+					<?php
+					foreach ($this->fields as $name => $config) {
+						if(array_key_exists('hidden', $config) || $name === 'post_status') {
+							continue;
+						}
+						if (!in_array($name, $this->timelineSharedFields)) {
+							echo '<td></td>';
+							continue;
+						}
+							$makeThisDetailed = (in_array($config['type'], $makeDetails));
+						?>
+						<td class="field show-<?= esc_attr($name) ?>" data-field="<?= esc_attr($name) ?>" data-field-type="<?=$config['type']?>"<?=(in_array($name, $this->stuck)) ? ' data-stuck':''?>>
+							<?= $makeThisDetailed ? '<details><summary class="row btw">See Value</summary>' : '' ?>
+							<?php $this->meta->render('form', $name, $config); ?>
+							<?= $makeThisDetailed ? '</details>' : '' ?>
+						</td>
+						<?php
+					}
+
+					?>
+				</tr>
+				<tr class="timeline-point">
+					<td class="select">
+						<button class="drag-handle" title="Drag to reorder" aria-label="Drag to reorder this timeline point"><?= jvbIcon('dots-six') ?></button>
+					</td>
+					<td class="show-post_status field" data-field="post_status">
+						<?= $this->renderStatusRadios() ?>
+					</td>
+					<?php
+					foreach ($this->fields as $name => $config) {
+						if(array_key_exists('hidden', $config) || $name === 'post_status') {
+							continue;
+						}
+						if (!in_array($name, $this->timelineUniqueFields)) {
+							echo '<td></td>';
+							continue;
+						}
+						$makeThisDetailed = (in_array($config['type'], $makeDetails));
+						?>
+						<td class="field show-<?= esc_attr($name) ?>" data-field="<?= esc_attr($name) ?>" data-field-type="<?=$config['type']?>"<?=(in_array($name, $this->stuck)) ? ' data-stuck':''?>>
+							<?= $makeThisDetailed ? '<details><summary class="row btw">See Value</summary>' : '' ?>
+							<?php $this->meta->render('form', $name, $config); ?>
+							<?= $makeThisDetailed ? '</details>' : '' ?>
+						</td>
+						<?php
+					}
+					?>
+				</tr>
+			</tbody>
+		</template>
+		<?php
+	}
 	/**
 	 * Render status radio buttons
 	 */
@@ -1131,6 +1211,32 @@
 		return ob_get_clean();
 	}
 
+	protected function renderTimelineTableHeader(): string {
+		ob_start();
+
+		?>
+		<tr>
+			<th scope="col" class="select-header">
+				<input type="checkbox" id="select-all" name="select-all">
+				<label for="select-all">All</label>
+			</th>
+			<th scope="col" class="show-post_status">
+				Status
+			</th>
+			<?php foreach ($this->fields as $name => $config):
+				if (array_key_exists('hidden', $config) || $name === 'post_status'){
+					continue;
+				}
+				?>
+				<th scope="col" class="show-<?= esc_attr($name) ?>"<?= (in_array($name, $this->stuck)) ? ' data-stuck':''?>>
+					<?= esc_html($config['label']) ?>
+				</th>
+			<?php endforeach; ?>
+		</tr>
+		<?php
+		return ob_get_clean();
+	}
+
 	/**
 	 * Render table action controls
 	 */

--
Gitblit v1.10.0