1146 lines
61 KiB
PHP
1146 lines
61 KiB
PHP
<?php
|
|
/**
|
|
* Excel-Style Planning View
|
|
* Table-based planning interface - both channels side by side
|
|
*/
|
|
|
|
ini_set('display_errors', 1);
|
|
ini_set('display_startup_errors', 1);
|
|
error_reporting(E_ALL);
|
|
|
|
require_once __DIR__ . '/vendor/autoload.php';
|
|
require_once __DIR__ . '/helpers.php';
|
|
require_once __DIR__ . '/auth/auth_functions.php';
|
|
|
|
use Dotenv\Dotenv;
|
|
$dotenv = Dotenv::createImmutable(__DIR__);
|
|
$dotenv->load();
|
|
|
|
// Require login
|
|
requireLogin();
|
|
|
|
$db = getDbConnection();
|
|
|
|
// Handle adding transmission to block - Admin only
|
|
if (isset($_POST['add_to_block']) && canCreate()) {
|
|
$commercialId = $_POST['infomercial_id'];
|
|
$channel = $_POST['channel'];
|
|
$date = $_POST['date'];
|
|
$blockId = $_POST['block_id'] ?? null;
|
|
|
|
// Get infomercial duration
|
|
$stmt = $db->prepare("SELECT duration FROM infomercials WHERE id = ?");
|
|
$stmt->execute([$commercialId]);
|
|
$duration = $stmt->fetchColumn();
|
|
|
|
// Calculate next start time for this specific block
|
|
$nextStartTime = calculateNextStartTimeForBlock($db, $date, $channel, $blockId);
|
|
|
|
// Insert transmission
|
|
$stmt = $db->prepare("
|
|
INSERT INTO transmissions
|
|
(infomercial_id, channel, template, start_date, start_time, duration, api_status)
|
|
VALUES (?, ?, 'HOME030', ?, ?, ?, 'pending')
|
|
");
|
|
$stmt->execute([$commercialId, $channel, $date, $nextStartTime, $duration]);
|
|
|
|
header("Location: planner.php?date=$date&success=added");
|
|
exit;
|
|
}
|
|
|
|
// Handle remove transmission - REMOVED: Now handled via AJAX to delete_transmission.php API
|
|
// This ensures proper Talpa API deletion
|
|
|
|
// Handle reorder (move up/down) - Admin only
|
|
if (isset($_POST['reorder']) && canEdit()) {
|
|
$transmissionId = $_POST['transmission_id'];
|
|
$direction = $_POST['direction']; // 'up' or 'down'
|
|
$date = $_POST['date'];
|
|
$channel = $_POST['channel'];
|
|
$blockId = $_POST['block_id'];
|
|
|
|
// Get block info including end time
|
|
$stmt = $db->prepare("SELECT actual_start_time, actual_end_time FROM daily_blocks WHERE id = ?");
|
|
$stmt->execute([$blockId]);
|
|
$blockInfo = $stmt->fetch();
|
|
$blockStartTime = $blockInfo['actual_start_time'];
|
|
$blockEndTime = $blockInfo['actual_end_time'] ?? '23:59:59';
|
|
|
|
// Get all transmissions for THIS SPECIFIC block only
|
|
$stmt = $db->prepare("
|
|
SELECT t.id, t.start_time, c.duration
|
|
FROM transmissions t
|
|
JOIN infomercials c ON t.infomercial_id = c.id
|
|
WHERE t.start_date = ? AND t.channel = ?
|
|
AND t.start_time >= ? AND t.start_time < ?
|
|
ORDER BY t.start_time ASC
|
|
");
|
|
$stmt->execute([$date, $channel, $blockStartTime, $blockEndTime]);
|
|
$transmissions = $stmt->fetchAll();
|
|
|
|
// Find current position
|
|
$currentIndex = array_search($transmissionId, array_column($transmissions, 'id'));
|
|
|
|
if ($currentIndex !== false) {
|
|
if ($direction === 'up' && $currentIndex > 0) {
|
|
// Swap with previous
|
|
$temp = $transmissions[$currentIndex];
|
|
$transmissions[$currentIndex] = $transmissions[$currentIndex - 1];
|
|
$transmissions[$currentIndex - 1] = $temp;
|
|
} elseif ($direction === 'down' && $currentIndex < count($transmissions) - 1) {
|
|
// Swap with next
|
|
$temp = $transmissions[$currentIndex];
|
|
$transmissions[$currentIndex] = $transmissions[$currentIndex + 1];
|
|
$transmissions[$currentIndex + 1] = $temp;
|
|
}
|
|
|
|
// Recalculate all start times
|
|
$currentTime = $blockStartTime;
|
|
|
|
foreach ($transmissions as $tx) {
|
|
$stmt = $db->prepare("UPDATE transmissions SET start_time = ?, api_status = 'pending' WHERE id = ?");
|
|
$stmt->execute([$currentTime, $tx['id']]);
|
|
|
|
$currentTime = addTimeToTime($currentTime, $tx['duration']);
|
|
}
|
|
}
|
|
|
|
header("Location: planner.php?date=$date");
|
|
exit;
|
|
}
|
|
|
|
// Handle block time update - Admin only
|
|
if (isset($_POST['update_block_time']) && canEdit()) {
|
|
$blockId = $_POST['block_id'];
|
|
$newStartTime = $_POST['new_start_time'];
|
|
$recalculate = isset($_POST['recalculate']);
|
|
|
|
// Update block time
|
|
$stmt = $db->prepare("UPDATE daily_blocks SET actual_start_time = ? WHERE id = ?");
|
|
$stmt->execute([$newStartTime, $blockId]);
|
|
|
|
// Optionally recalculate transmissions
|
|
if ($recalculate) {
|
|
$stmt = $db->prepare("SELECT block_date, channel FROM daily_blocks WHERE id = ?");
|
|
$stmt->execute([$blockId]);
|
|
$blockInfo = $stmt->fetch();
|
|
|
|
$stmt = $db->prepare("
|
|
SELECT t.id, c.duration
|
|
FROM transmissions t
|
|
JOIN infomercials c ON t.infomercial_id = c.id
|
|
WHERE t.start_date = ? AND t.channel = ? AND t.start_time >= ?
|
|
ORDER BY t.start_time ASC
|
|
");
|
|
$stmt->execute([$blockInfo['block_date'], $blockInfo['channel'], $newStartTime]);
|
|
$transmissions = $stmt->fetchAll();
|
|
|
|
$currentTime = $newStartTime;
|
|
foreach ($transmissions as $tx) {
|
|
$stmt = $db->prepare("UPDATE transmissions SET start_time = ?, api_status = 'pending' WHERE id = ?");
|
|
$stmt->execute([$currentTime, $tx['id']]);
|
|
$currentTime = addTimeToTime($currentTime, $tx['duration']);
|
|
}
|
|
}
|
|
|
|
header("Location: planner.php?date={$blockInfo['block_date']}&success=block_updated");
|
|
exit;
|
|
}
|
|
|
|
// Get selected date
|
|
$selectedDate = $_GET['date'] ?? date('Y-m-d');
|
|
|
|
// Ensure daily blocks exist
|
|
ensureDailyBlocks($db, $selectedDate, $selectedDate);
|
|
|
|
// Get all blocks for this date (both channels, all blocks)
|
|
$stmt = $db->prepare("
|
|
SELECT db.*, bt.name as template_name, bt.channel
|
|
FROM daily_blocks db
|
|
LEFT JOIN block_templates bt ON db.template_id = bt.id
|
|
WHERE db.block_date = ?
|
|
ORDER BY db.channel, db.actual_start_time
|
|
");
|
|
$stmt->execute([$selectedDate]);
|
|
$allBlocks = $stmt->fetchAll();
|
|
|
|
// Group blocks by channel
|
|
$blocksByChannel = [];
|
|
foreach ($allBlocks as $block) {
|
|
$blocksByChannel[$block['channel']][] = $block;
|
|
}
|
|
|
|
// Get all infomercials (including pending status - they can be used in planner)
|
|
$infomercials = $db->query("
|
|
SELECT * FROM infomercials
|
|
ORDER BY title ASC
|
|
")->fetchAll();
|
|
|
|
// Helper function to calculate next start time for a specific block
|
|
function calculateNextStartTimeForBlock($db, $date, $channel, $blockId) {
|
|
if ($blockId) {
|
|
$stmt = $db->prepare("SELECT actual_start_time, actual_end_time FROM daily_blocks WHERE id = ?");
|
|
$stmt->execute([$blockId]);
|
|
$blockInfo = $stmt->fetch();
|
|
$blockStartTime = $blockInfo['actual_start_time'];
|
|
$blockEndTime = $blockInfo['actual_end_time'] ?? '23:59:59';
|
|
} else {
|
|
$blockStartTime = '07:00:00'; // Default
|
|
$blockEndTime = '23:59:59';
|
|
}
|
|
|
|
// Get all transmissions in THIS SPECIFIC block only
|
|
$stmt = $db->prepare("
|
|
SELECT start_time, duration
|
|
FROM transmissions
|
|
WHERE start_date = ? AND channel = ?
|
|
AND start_time >= ? AND start_time < ?
|
|
ORDER BY start_time DESC
|
|
LIMIT 1
|
|
");
|
|
$stmt->execute([$date, $channel, $blockStartTime, $blockEndTime]);
|
|
$lastTx = $stmt->fetch();
|
|
|
|
if ($lastTx) {
|
|
return addTimeToTime($lastTx['start_time'], $lastTx['duration']);
|
|
}
|
|
|
|
return $blockStartTime;
|
|
}
|
|
?>
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="nl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Excel Planning - Telvero Talpa</title>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
|
<link rel="stylesheet" href="assets/css/custom.css">
|
|
<style>
|
|
.planning-table {
|
|
font-size: 0.85em;
|
|
}
|
|
.planning-table td {
|
|
vertical-align: middle;
|
|
padding: 6px;
|
|
}
|
|
.color-indicator {
|
|
width: 25px;
|
|
height: 25px;
|
|
border-radius: 3px;
|
|
display: inline-block;
|
|
}
|
|
.time-cell {
|
|
font-family: 'Courier New', monospace;
|
|
font-weight: 600;
|
|
font-size: 0.9em;
|
|
}
|
|
.duration-cell {
|
|
text-align: center;
|
|
font-weight: 600;
|
|
}
|
|
.remaining-time {
|
|
font-size: 0.85em;
|
|
color: #6c757d;
|
|
}
|
|
.block-section {
|
|
background: #f8f9fa;
|
|
border-left: 4px solid;
|
|
margin-bottom: 20px;
|
|
}
|
|
.block-header {
|
|
background: #e9ecef;
|
|
padding: 8px 12px;
|
|
font-weight: 600;
|
|
border-bottom: 2px solid #dee2e6;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="bg-light">
|
|
<?php $activePage = 'planner'; include __DIR__ . '/includes/nav.php'; ?>
|
|
|
|
<div class="container-fluid mt-4">
|
|
<?php if (isset($_GET['success'])): ?>
|
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
|
<?php
|
|
$messages = [
|
|
'added' => 'Uitzending toegevoegd!',
|
|
'removed' => 'Uitzending verwijderd!'
|
|
];
|
|
echo $messages[$_GET['success']] ?? 'Actie succesvol!';
|
|
?>
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Date Selector -->
|
|
<div class="row mb-3">
|
|
<div class="col-md-12">
|
|
<div class="card shadow-sm">
|
|
<div class="card-body">
|
|
<form method="GET" class="row g-3 align-items-end">
|
|
<div class="col-md-1">
|
|
<a href="?date=<?= date('Y-m-d', strtotime($selectedDate . ' -1 day')) ?>"
|
|
class="btn btn-outline-primary w-100"
|
|
title="Vorige dag">
|
|
<i class="bi bi-chevron-left"></i>
|
|
</a>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<input type="date" name="date" class="form-control" value="<?= $selectedDate ?>" required>
|
|
</div>
|
|
<div class="col-md-1">
|
|
<a href="?date=<?= date('Y-m-d', strtotime($selectedDate . ' +1 day')) ?>"
|
|
class="btn btn-outline-primary w-100"
|
|
title="Volgende dag">
|
|
<i class="bi bi-chevron-right"></i>
|
|
</a>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<button type="submit" class="btn btn-primary w-100">
|
|
<i class="bi bi-search"></i> Toon Planning
|
|
</button>
|
|
</div>
|
|
<div class="col-md-5 text-end">
|
|
<a href="calendar.php" class="btn btn-outline-secondary">
|
|
<i class="bi bi-calendar-week"></i> Kalender View
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="mb-3"><?= formatDateDutch($selectedDate) ?></h3>
|
|
|
|
<!-- Both Channels Side by Side -->
|
|
<div class="row">
|
|
<!-- Infomercial Sidebar -->
|
|
<div class="col-md-2">
|
|
<div class="card shadow-sm sticky-top" style="top: 20px;">
|
|
<div class="card-header bg-success text-white">
|
|
<h6 class="mb-0">
|
|
<i class="bi bi-collection-play"></i> Infomercials
|
|
</h6>
|
|
</div>
|
|
<div class="card-body p-2">
|
|
<!-- Search -->
|
|
<div class="mb-2">
|
|
<input type="text"
|
|
class="form-control form-control-sm"
|
|
id="commercialSearch"
|
|
placeholder="🔍 Zoeken..."
|
|
onkeyup="filterPlannerCommercials(this.value)">
|
|
</div>
|
|
|
|
<!-- Infomercial List -->
|
|
<div class="infomercial-sidebar" style="max-height: 70vh;">
|
|
<?php if (empty($infomercials)): ?>
|
|
<div class="text-center text-muted p-2">
|
|
<i class="bi bi-inbox"></i>
|
|
<p class="small mt-2">Geen infomercials</p>
|
|
</div>
|
|
<?php else: ?>
|
|
<?php foreach ($infomercials as $infomercial): ?>
|
|
<div class="infomercial-item draggable-infomercial"
|
|
style="border-left-color: <?= htmlspecialchars($infomercial['color_code']) ?>; padding: 8px; margin-bottom: 8px;"
|
|
draggable="true"
|
|
data-infomercial-id="<?= $infomercial['id'] ?>"
|
|
data-title="<?= htmlspecialchars($infomercial['title']) ?>"
|
|
data-duration="<?= $infomercial['duration'] ?>"
|
|
data-color="<?= htmlspecialchars($infomercial['color_code']) ?>"
|
|
data-series-code="<?= htmlspecialchars($infomercial['series_code'] ?? '') ?>">
|
|
|
|
<div class="d-flex align-items-center">
|
|
<div style="background-color: <?= htmlspecialchars($infomercial['color_code']) ?>; width: 15px; height: 15px; border-radius: 2px; margin-right: 6px;">
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<div style="font-weight: 600; font-size: 0.8em;">
|
|
<?= htmlspecialchars($infomercial['title']) ?>
|
|
</div>
|
|
<div style="font-size: 0.7em; color: #6c757d;">
|
|
<?= round(timeToSeconds($infomercial['duration']) / 60) ?> min
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<i class="bi bi-grip-vertical text-muted"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-10">
|
|
<div class="row">
|
|
<?php foreach (['SBS9', 'NET5'] as $channel): ?>
|
|
<div class="col-md-6">
|
|
<div class="card shadow-sm mb-4">
|
|
<div class="card-header <?= $channel == 'SBS9' ? 'bg-primary' : 'bg-danger' ?> text-white">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-tv"></i> <?= $channel ?>
|
|
</h5>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<?php
|
|
$channelBlocks = $blocksByChannel[$channel] ?? [];
|
|
|
|
if (empty($channelBlocks)): ?>
|
|
<div class="p-4 text-center text-muted">
|
|
<i class="bi bi-inbox"></i>
|
|
<p>Geen blokken voor deze dag</p>
|
|
</div>
|
|
<?php else: ?>
|
|
<?php foreach ($channelBlocks as $block):
|
|
// Get transmissions for this block
|
|
$blockStart = $block['actual_start_time'];
|
|
$blockEnd = $block['actual_end_time'] ?? '23:59:59';
|
|
|
|
$stmt = $db->prepare("
|
|
SELECT t.*, c.title, c.color_code, c.series_code,
|
|
t.api_status, t.talpa_transmission_id
|
|
FROM transmissions t
|
|
JOIN infomercials c ON t.infomercial_id = c.id
|
|
WHERE t.start_date = ? AND t.channel = ?
|
|
AND t.start_time >= ? AND t.start_time < ?
|
|
ORDER BY t.start_time ASC
|
|
");
|
|
$stmt->execute([$selectedDate, $channel, $blockStart, $blockEnd]);
|
|
$blockTransmissions = $stmt->fetchAll();
|
|
|
|
// Calculate block stats
|
|
$totalBlockMinutes = (timeToSeconds($blockEnd) - timeToSeconds($blockStart)) / 60;
|
|
$usedMinutes = 0;
|
|
foreach ($blockTransmissions as $tx) {
|
|
$usedMinutes += timeToSeconds($tx['duration']) / 60;
|
|
}
|
|
$remainingMinutes = $totalBlockMinutes - $usedMinutes;
|
|
|
|
// Calculate block sync status
|
|
$totalTransmissions = count($blockTransmissions);
|
|
$syncedTransmissions = 0;
|
|
foreach ($blockTransmissions as $tx) {
|
|
if ($tx['api_status'] === 'synced' && !empty($tx['talpa_transmission_id'])) {
|
|
$syncedTransmissions++;
|
|
}
|
|
}
|
|
|
|
// Determine block sync status
|
|
$blockSyncClass = 'block-sync-empty';
|
|
$blockSyncLabel = 'Leeg';
|
|
$blockSyncIcon = 'bi-inbox';
|
|
|
|
if ($totalTransmissions > 0) {
|
|
if ($syncedTransmissions == $totalTransmissions) {
|
|
$blockSyncClass = 'block-sync-complete';
|
|
$blockSyncLabel = 'Gepland';
|
|
$blockSyncIcon = 'bi-check-circle-fill';
|
|
} elseif ($syncedTransmissions > 0) {
|
|
$blockSyncClass = 'block-sync-partial';
|
|
$blockSyncLabel = "Deels ({$syncedTransmissions}/{$totalTransmissions})";
|
|
$blockSyncIcon = 'bi-exclamation-triangle-fill';
|
|
} else {
|
|
$blockSyncClass = 'block-sync-none';
|
|
$blockSyncLabel = 'Niet Gepland';
|
|
$blockSyncIcon = 'bi-x-circle-fill';
|
|
}
|
|
}
|
|
?>
|
|
<div class="block-section" style="border-left-color: <?= $channel == 'SBS9' ? '#3498db' : '#e74c3c' ?>;">
|
|
<div class="block-header">
|
|
<div class="block-header-left">
|
|
<h6 class="block-title"><?= htmlspecialchars($block['template_name'] ?? 'Blok') ?></h6>
|
|
|
|
<!-- Block Sync Status Badge -->
|
|
<span class="badge-sync <?= str_replace('block-sync-', 'badge-sync-', $blockSyncClass) ?>">
|
|
<i class="bi <?= $blockSyncIcon ?>"></i>
|
|
<?= $blockSyncLabel ?>
|
|
</span>
|
|
</div>
|
|
|
|
<div class="block-header-actions">
|
|
<?php if (canEdit()): ?>
|
|
<button type="button" class="btn-icon btn-icon-sm btn-icon-secondary"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#blockTimeModal<?= $block['id'] ?>">
|
|
<i class="bi bi-clock"></i>
|
|
</button>
|
|
<button type="button" class="btn-icon btn-icon-sm btn-icon-info"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#copyBlockModal<?= $block['id'] ?>">
|
|
<i class="bi bi-files"></i>
|
|
</button>
|
|
<?php endif; ?>
|
|
<?php if (canSync()): ?>
|
|
<button type="button" class="btn-icon btn-icon-sm btn-icon-success"
|
|
onclick="syncBlockPlanner('<?= $selectedDate ?>', '<?= $channel ?>')">
|
|
<i class="bi bi-cloud-upload"></i>
|
|
</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="block-header-time">
|
|
<?= substr($blockStart, 0, 5) ?> - <?= substr($blockEnd, 0, 5) ?> | <strong><?= round($remainingMinutes) ?> min</strong>
|
|
</div>
|
|
</div>
|
|
|
|
<table class="table table-sm table-hover planning-table mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th style="width: 40px;"></th>
|
|
<th>Product</th>
|
|
<th style="width: 80px;">Duur</th>
|
|
<th style="width: 70px;">Start</th>
|
|
<th style="width: 70px;">Eind</th>
|
|
<th style="width: 80px;">Restant</th>
|
|
<th style="width: 50px;" class="text-center">Talpa</th>
|
|
<th style="width: 100px;">Acties</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody data-block-id="<?= $block['id'] ?>" data-channel="<?= $channel ?>" data-date="<?= $selectedDate ?>">
|
|
<?php if (empty($blockTransmissions)): ?>
|
|
<tr>
|
|
<td colspan="7" class="text-center text-muted py-3">
|
|
<small>Nog geen uitzendingen in dit blok</small>
|
|
</td>
|
|
</tr>
|
|
<?php else: ?>
|
|
<?php foreach ($blockTransmissions as $index => $tx):
|
|
$durationMinutes = round(timeToSeconds($tx['duration']) / 60);
|
|
$endTime = addTimeToTime($tx['start_time'], $tx['duration']);
|
|
|
|
// Calculate remaining time in block after this transmission
|
|
$remainingSeconds = timeToSeconds($blockEnd) - timeToSeconds($endTime);
|
|
$txRemainingMinutes = round($remainingSeconds / 60);
|
|
?>
|
|
<tr style="background-color: <?= $tx['color_code'] ?>15;">
|
|
<td>
|
|
<div class="color-indicator" style="background-color: <?= htmlspecialchars($tx['color_code']) ?>;"></div>
|
|
</td>
|
|
<td>
|
|
<strong><?= htmlspecialchars($tx['title']) ?></strong>
|
|
</td>
|
|
<td class="duration-cell">
|
|
<?= $durationMinutes ?> min
|
|
</td>
|
|
<td class="time-cell text-success">
|
|
<?= substr($tx['start_time'], 0, 5) ?>
|
|
</td>
|
|
<td class="time-cell text-danger">
|
|
<?= substr($endTime, 0, 5) ?>
|
|
</td>
|
|
<td class="text-center remaining-time">
|
|
<?= $txRemainingMinutes ?> min
|
|
</td>
|
|
<td class="text-center">
|
|
<?php
|
|
$syncClass = 'sync-pending';
|
|
$syncIcon = 'bi-circle-fill';
|
|
$syncTitle = 'Nog niet gesynchroniseerd';
|
|
|
|
if ($tx['api_status'] === 'synced' && !empty($tx['talpa_transmission_id'])) {
|
|
$syncClass = 'sync-success';
|
|
$syncTitle = 'Gesynchroniseerd met Talpa ID: ' . $tx['talpa_transmission_id'];
|
|
} elseif ($tx['api_status'] === 'error') {
|
|
$syncClass = 'sync-error';
|
|
$syncIcon = 'bi-exclamation-circle-fill';
|
|
$syncTitle = 'Sync fout - klik voor details';
|
|
}
|
|
?>
|
|
<span class="sync-indicator <?= $syncClass ?>"
|
|
title="<?= htmlspecialchars($syncTitle) ?>"
|
|
data-bs-toggle="tooltip"
|
|
data-bs-placement="left"
|
|
data-bs-html="true">
|
|
<i class="bi <?= $syncIcon ?>"></i>
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<div class="action-buttons">
|
|
<?php if (canEdit() && $index > 0): ?>
|
|
<form method="POST" style="display:inline;">
|
|
<input type="hidden" name="transmission_id" value="<?= $tx['id'] ?>">
|
|
<input type="hidden" name="direction" value="up">
|
|
<input type="hidden" name="date" value="<?= $selectedDate ?>">
|
|
<input type="hidden" name="channel" value="<?= $channel ?>">
|
|
<input type="hidden" name="block_id" value="<?= $block['id'] ?>">
|
|
<button type="submit" name="reorder" class="btn-icon btn-icon-xs btn-icon-secondary">
|
|
<i class="bi bi-arrow-up"></i>
|
|
</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
|
|
<?php if (canEdit() && $index < count($blockTransmissions) - 1): ?>
|
|
<form method="POST" style="display:inline;">
|
|
<input type="hidden" name="transmission_id" value="<?= $tx['id'] ?>">
|
|
<input type="hidden" name="direction" value="down">
|
|
<input type="hidden" name="date" value="<?= $selectedDate ?>">
|
|
<input type="hidden" name="channel" value="<?= $channel ?>">
|
|
<input type="hidden" name="block_id" value="<?= $block['id'] ?>">
|
|
<button type="submit" name="reorder" class="btn-icon btn-icon-xs btn-icon-secondary">
|
|
<i class="bi bi-arrow-down"></i>
|
|
</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
|
|
<?php if (canDelete()): ?>
|
|
<button type="button"
|
|
class="btn-icon btn-icon-xs btn-icon-danger"
|
|
onclick="deleteTransmissionPlanner(<?= $tx['id'] ?>, '<?= $selectedDate ?>')">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
|
|
<?php if (canCreate()): ?>
|
|
<!-- Add Infomercial Row (also a drop zone) -->
|
|
<tr class="table-success drop-zone-end"
|
|
data-block-id="<?= $block['id'] ?>"
|
|
data-channel="<?= $channel ?>"
|
|
data-date="<?= $selectedDate ?>">
|
|
<td colspan="7">
|
|
<form method="POST" class="row g-2 align-items-center">
|
|
<input type="hidden" name="date" value="<?= $selectedDate ?>">
|
|
<input type="hidden" name="channel" value="<?= $channel ?>">
|
|
<input type="hidden" name="block_id" value="<?= $block['id'] ?>">
|
|
|
|
<div class="col-md-8">
|
|
<select name="infomercial_id" class="form-select form-select-sm" required>
|
|
<option value="">+ Voeg infomercial toe...</option>
|
|
<?php foreach ($infomercials as $c): ?>
|
|
<option value="<?= $c['id'] ?>">
|
|
<?= htmlspecialchars($c['title']) ?>
|
|
(<?= round(timeToSeconds($c['duration']) / 60) ?> min)
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<button type="submit" name="add_to_block" class="btn btn-success btn-sm w-100">
|
|
<i class="bi bi-plus-circle"></i> Toevoegen
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Block Time Edit Modals -->
|
|
<?php foreach ($allBlocks as $block): ?>
|
|
<div class="modal fade" id="blockTimeModal<?= $block['id'] ?>" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<form method="POST">
|
|
<input type="hidden" name="block_id" value="<?= $block['id'] ?>">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">
|
|
<i class="bi bi-clock"></i> Starttijd Aanpassen
|
|
</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="alert alert-info">
|
|
<strong><?= htmlspecialchars($block['template_name'] ?? 'Blok') ?></strong><br>
|
|
<?= htmlspecialchars($block['channel']) ?> - <?= formatDateDutch($selectedDate) ?>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Nieuwe Starttijd</label>
|
|
<input type="time" name="new_start_time" class="form-control"
|
|
value="<?= $block['actual_start_time'] ?>" required>
|
|
</div>
|
|
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="recalculate"
|
|
id="recalc<?= $block['id'] ?>" checked>
|
|
<label class="form-check-label" for="recalc<?= $block['id'] ?>">
|
|
Herbereken alle uitzendingen in dit blok
|
|
</label>
|
|
</div>
|
|
|
|
<div class="alert alert-warning mt-3 small">
|
|
<i class="bi bi-exclamation-triangle"></i>
|
|
Als je "herbereken" aanvinkt, worden alle uitzendingen in dit blok opnieuw getimed vanaf de nieuwe starttijd.
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuleren</button>
|
|
<button type="submit" name="update_block_time" class="btn btn-primary">
|
|
<i class="bi bi-check-circle"></i> Opslaan
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
|
|
<!-- Copy Block Modals -->
|
|
<?php foreach ($allBlocks as $block): ?>
|
|
<div class="modal fade" id="copyBlockModal<?= $block['id'] ?>" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<form id="copyBlockForm<?= $block['id'] ?>">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">
|
|
<i class="bi bi-files"></i> Kopieer Blok
|
|
</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="alert alert-info">
|
|
<strong>Doelblok:</strong><br>
|
|
<?= htmlspecialchars($block['template_name'] ?? 'Blok') ?><br>
|
|
<?= htmlspecialchars($block['channel']) ?> - <?= formatDateDutch($selectedDate) ?>
|
|
</div>
|
|
|
|
<div class="alert alert-warning">
|
|
<i class="bi bi-exclamation-triangle"></i>
|
|
<strong>Let op:</strong> Alle bestaande uitzendingen in dit blok worden overschreven!
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Brondag</label>
|
|
<input type="date"
|
|
class="form-control"
|
|
id="sourceDate<?= $block['id'] ?>"
|
|
required
|
|
onchange="loadSourceBlocks(<?= $block['id'] ?>, '<?= $block['channel'] ?>', <?= $block['template_id'] ?>)">
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Bronblok</label>
|
|
<select class="form-select"
|
|
id="sourceBlock<?= $block['id'] ?>"
|
|
required
|
|
onchange="showSourceBlockPreview(<?= $block['id'] ?>)">
|
|
<option value="">Selecteer eerst een brondag...</option>
|
|
</select>
|
|
<small class="text-muted">
|
|
Alleen blokken van hetzelfde type (<?= htmlspecialchars($block['template_name'] ?? 'Blok') ?>) worden getoond
|
|
</small>
|
|
</div>
|
|
|
|
<div id="sourceBlockPreview<?= $block['id'] ?>" class="mt-3" style="display: none;">
|
|
<h6>Preview Bronblok:</h6>
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div id="sourceBlockInfo<?= $block['id'] ?>"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
|
Annuleren
|
|
</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bi bi-files"></i> Kopieer Blok
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
|
|
<script>
|
|
// Initialize Bootstrap tooltips
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
|
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
|
return new bootstrap.Tooltip(tooltipTriggerEl);
|
|
});
|
|
});
|
|
|
|
// Filter infomercials in sidebar
|
|
function filterPlannerCommercials(searchTerm) {
|
|
const items = document.querySelectorAll('.draggable-infomercial');
|
|
const term = searchTerm.toLowerCase();
|
|
|
|
items.forEach(item => {
|
|
const title = item.dataset.title.toLowerCase();
|
|
const seriesCode = (item.dataset.seriesCode || '').toLowerCase();
|
|
|
|
if (title.includes(term) || seriesCode.includes(term)) {
|
|
item.style.display = 'block';
|
|
} else {
|
|
item.style.display = 'none';
|
|
}
|
|
});
|
|
}
|
|
|
|
// Make infomercial items draggable
|
|
document.querySelectorAll('.draggable-infomercial').forEach(item => {
|
|
item.addEventListener('dragstart', function(e) {
|
|
e.dataTransfer.setData('infomercial_id', this.dataset.infomercialId);
|
|
e.dataTransfer.setData('title', this.dataset.title);
|
|
e.dataTransfer.setData('duration', this.dataset.duration);
|
|
this.style.opacity = '0.5';
|
|
});
|
|
|
|
item.addEventListener('dragend', function(e) {
|
|
this.style.opacity = '1';
|
|
});
|
|
});
|
|
|
|
// Make table rows drop targets
|
|
document.querySelectorAll('.planning-table tbody').forEach(tbody => {
|
|
const blockId = tbody.dataset.blockId;
|
|
const channel = tbody.dataset.channel;
|
|
const date = tbody.dataset.date;
|
|
|
|
// Make each row a drop zone
|
|
tbody.querySelectorAll('tr:not(.table-success)').forEach((row, index) => {
|
|
row.addEventListener('dragover', function(e) {
|
|
e.preventDefault();
|
|
this.style.borderTop = '3px solid #28a745';
|
|
});
|
|
|
|
row.addEventListener('dragleave', function(e) {
|
|
this.style.borderTop = '';
|
|
});
|
|
|
|
row.addEventListener('drop', function(e) {
|
|
e.preventDefault();
|
|
this.style.borderTop = '';
|
|
|
|
const commercialId = e.dataTransfer.getData('infomercial_id');
|
|
|
|
// Insert at this position
|
|
fetch('api/insert_transmission_at_position.php', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
infomercial_id: commercialId,
|
|
channel: channel,
|
|
date: date,
|
|
block_id: blockId,
|
|
position: index
|
|
})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
window.location.reload();
|
|
} else {
|
|
alert('Fout: ' + data.error);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
// Make "Add Infomercial" rows also drop zones (for adding at end)
|
|
document.querySelectorAll('.drop-zone-end').forEach(row => {
|
|
const blockId = row.dataset.blockId;
|
|
const channel = row.dataset.channel;
|
|
const date = row.dataset.date;
|
|
|
|
row.addEventListener('dragover', function(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
this.style.backgroundColor = '#d4edda';
|
|
});
|
|
|
|
row.addEventListener('dragleave', function(e) {
|
|
this.style.backgroundColor = '';
|
|
});
|
|
|
|
row.addEventListener('drop', function(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
this.style.backgroundColor = '';
|
|
|
|
const commercialId = e.dataTransfer.getData('infomercial_id');
|
|
|
|
if (!commercialId) return;
|
|
|
|
// Add at end (use existing add_to_block logic)
|
|
const form = this.querySelector('form');
|
|
if (form) {
|
|
const select = form.querySelector('select[name="infomercial_id"]');
|
|
if (select) {
|
|
select.value = commercialId;
|
|
form.submit();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Delete transmission via API (calls Talpa API)
|
|
function deleteTransmissionPlanner(transmissionId, date) {
|
|
if (!confirm('Weet je zeker dat je deze uitzending wilt verwijderen?\n\nDit verwijdert ook de uitzending uit Talpa.')) {
|
|
return;
|
|
}
|
|
|
|
// Show loading indicator
|
|
const btn = event.target.closest('button');
|
|
const originalHTML = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status"></span>';
|
|
|
|
fetch('api/delete_transmission.php', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ id: transmissionId })
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
// Reload page to show updated list
|
|
window.location.href = `planner.php?date=${date}&success=removed`;
|
|
} else {
|
|
alert('✗ Fout bij verwijderen: ' + (data.error || 'Onbekende fout'));
|
|
btn.disabled = false;
|
|
btn.innerHTML = originalHTML;
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
alert('✗ Netwerkfout bij verwijderen');
|
|
btn.disabled = false;
|
|
btn.innerHTML = originalHTML;
|
|
});
|
|
}
|
|
|
|
// Sync block to Talpa
|
|
function syncBlockPlanner(date, channel) {
|
|
if (!confirm(`Wilt u alle uitzendingen in dit blok synchroniseren naar Talpa?\n\nDatum: ${date}\nZender: ${channel}`)) {
|
|
return;
|
|
}
|
|
|
|
// Show loading indicator
|
|
const btn = event.target.closest('button');
|
|
const originalHTML = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status"></span> Synchroniseren...';
|
|
|
|
fetch('api/sync_block.php', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
date: date,
|
|
channel: channel
|
|
})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
btn.disabled = false;
|
|
btn.innerHTML = originalHTML;
|
|
|
|
// Log debug information to console
|
|
console.group('🔍 Sync Block Debug Info');
|
|
console.log('Full Response:', data);
|
|
if (data.debug) {
|
|
console.log('Debug Log:', data.debug);
|
|
}
|
|
if (data.api_calls) {
|
|
console.log('API Calls:', data.api_calls);
|
|
}
|
|
if (data.errors) {
|
|
console.log('Errors:', data.errors);
|
|
}
|
|
console.groupEnd();
|
|
|
|
if (data.success) {
|
|
let message = `✓ Synchronisatie voltooid!\n\nGeslaagd: ${data.synced}\nMislukt: ${data.failed}`;
|
|
|
|
if (data.errors && data.errors.length > 0) {
|
|
message += '\n\nFouten:\n';
|
|
data.errors.forEach(err => {
|
|
message += `- ${err.title} (${err.time}): ${err.error}\n`;
|
|
});
|
|
message += '\n\nZie console (F12) voor gedetailleerde debug informatie.';
|
|
}
|
|
|
|
alert(message);
|
|
|
|
// Reload page to show updated status
|
|
window.location.reload();
|
|
} else {
|
|
alert('✗ Fout bij synchroniseren: ' + (data.error || 'Onbekende fout') + '\n\nZie console (F12) voor debug informatie.');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
btn.disabled = false;
|
|
btn.innerHTML = originalHTML;
|
|
console.error('Error:', error);
|
|
alert('✗ Netwerkfout bij synchroniseren');
|
|
});
|
|
}
|
|
|
|
// Load available source blocks when date is selected
|
|
function loadSourceBlocks(targetBlockId, channel, templateId) {
|
|
const sourceDate = document.getElementById(`sourceDate${targetBlockId}`).value;
|
|
const sourceBlockSelect = document.getElementById(`sourceBlock${targetBlockId}`);
|
|
|
|
if (!sourceDate) {
|
|
sourceBlockSelect.innerHTML = '<option value="">Selecteer eerst een brondag...</option>';
|
|
return;
|
|
}
|
|
|
|
// Show loading
|
|
sourceBlockSelect.innerHTML = '<option value="">Laden...</option>';
|
|
|
|
fetch(`api/get_available_source_blocks.php?date=${sourceDate}&channel=${channel}&template_id=${templateId}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success && data.blocks.length > 0) {
|
|
let options = '<option value="">Selecteer bronblok...</option>';
|
|
data.blocks.forEach(block => {
|
|
const transmissionCount = block.transmission_count || 0;
|
|
const startTime = block.actual_start_time ? block.actual_start_time.substring(0,5) : '??:??';
|
|
const endTime = block.actual_end_time ? block.actual_end_time.substring(0,5) : '∞';
|
|
options += `<option value="${block.id}">
|
|
${block.template_name} (${startTime} - ${endTime}) - ${transmissionCount} uitzendingen
|
|
</option>`;
|
|
});
|
|
sourceBlockSelect.innerHTML = options;
|
|
} else {
|
|
sourceBlockSelect.innerHTML = '<option value="">Geen blokken beschikbaar op deze dag</option>';
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error loading source blocks:', error);
|
|
sourceBlockSelect.innerHTML = '<option value="">Fout bij laden</option>';
|
|
});
|
|
}
|
|
|
|
// Show preview of source block when selected
|
|
function showSourceBlockPreview(targetBlockId) {
|
|
const sourceBlockId = document.getElementById(`sourceBlock${targetBlockId}`).value;
|
|
const previewDiv = document.getElementById(`sourceBlockPreview${targetBlockId}`);
|
|
const infoDiv = document.getElementById(`sourceBlockInfo${targetBlockId}`);
|
|
|
|
if (!sourceBlockId) {
|
|
previewDiv.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
// Load block details
|
|
fetch(`api/get_block_details.php?block_id=${sourceBlockId}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
const startTime = data.block.actual_start_time ? data.block.actual_start_time.substring(0,5) : '??:??';
|
|
const endTime = data.block.actual_end_time ? data.block.actual_end_time.substring(0,5) : '∞';
|
|
|
|
let html = `
|
|
<p><strong>Starttijd:</strong> ${startTime}</p>
|
|
<p><strong>Eindtijd:</strong> ${endTime}</p>
|
|
<p><strong>Aantal uitzendingen:</strong> ${data.transmissions.length}</p>
|
|
`;
|
|
|
|
if (data.transmissions.length > 0) {
|
|
html += '<hr><p><strong>Uitzendingen:</strong></p><ul class="small">';
|
|
data.transmissions.forEach(tx => {
|
|
const txTime = tx.start_time ? tx.start_time.substring(0,5) : '??:??';
|
|
html += `<li>${txTime} - ${tx.title}</li>`;
|
|
});
|
|
html += '</ul>';
|
|
}
|
|
|
|
infoDiv.innerHTML = html;
|
|
previewDiv.style.display = 'block';
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error loading block details:', error);
|
|
infoDiv.innerHTML = '<p class="text-danger">Fout bij laden van preview</p>';
|
|
previewDiv.style.display = 'block';
|
|
});
|
|
}
|
|
|
|
// Handle copy block form submission
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
document.querySelectorAll('[id^="copyBlockForm"]').forEach(form => {
|
|
form.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
const blockId = this.id.replace('copyBlockForm', '');
|
|
const sourceDate = document.getElementById(`sourceDate${blockId}`).value;
|
|
const sourceBlockId = document.getElementById(`sourceBlock${blockId}`).value;
|
|
|
|
if (!sourceDate || !sourceBlockId) {
|
|
alert('Selecteer een brondag en bronblok');
|
|
return;
|
|
}
|
|
|
|
if (!confirm('Weet je zeker dat je dit blok wilt kopiëren? Alle bestaande uitzendingen worden overschreven!')) {
|
|
return;
|
|
}
|
|
|
|
// Show loading
|
|
const submitBtn = this.querySelector('button[type="submit"]');
|
|
const originalHTML = submitBtn.innerHTML;
|
|
submitBtn.disabled = true;
|
|
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Kopiëren...';
|
|
|
|
// Call API
|
|
fetch('api/copy_block.php', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
source_block_id: sourceBlockId,
|
|
target_block_id: blockId,
|
|
target_date: '<?= $selectedDate ?>'
|
|
})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
alert(`✓ Blok succesvol gekopieerd!\n\nGekopieerd: ${data.copied_count} uitzendingen\nVerwijderd: ${data.deleted_count} uitzendingen`);
|
|
window.location.reload();
|
|
} else {
|
|
alert('✗ Fout bij kopiëren: ' + (data.error || 'Onbekende fout'));
|
|
submitBtn.disabled = false;
|
|
submitBtn.innerHTML = originalHTML;
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
alert('✗ Netwerkfout bij kopiëren');
|
|
submitBtn.disabled = false;
|
|
submitBtn.innerHTML = originalHTML;
|
|
});
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|