1<?php 2 3use Fisharebest\Webtrees\Http\RequestHandlers\ControlPanel; 4use Fisharebest\Webtrees\Http\RequestHandlers\DataFixData; 5use Fisharebest\Webtrees\Http\RequestHandlers\DataFixPage; 6use Fisharebest\Webtrees\Http\RequestHandlers\DataFixUpdateAll; 7use Fisharebest\Webtrees\Http\RequestHandlers\HelpText; 8use Fisharebest\Webtrees\Http\RequestHandlers\ManageTrees; 9use Fisharebest\Webtrees\I18N; 10use Fisharebest\Webtrees\Module\ModuleDataFixInterface; 11use Fisharebest\Webtrees\Tree; 12use Fisharebest\Webtrees\View; 13 14/** 15 * @var ModuleDataFixInterface $data_fix 16 * @var string $latest_version 17 * @var string $title 18 * @var Tree $tree 19 * @var string $pending_url 20 */ 21 22?> 23 24<?= view('components/breadcrumbs', ['links' => [route(ControlPanel::class) => I18N::translate('Control panel'), route(ManageTrees::class, ['tree' => $tree->name()]) => I18N::translate('Manage family trees'), route(DataFixPage::class, ['tree' => $tree->name()]) => view('icons/data-fix') . I18N::translate('Data fixes'), $title]]) ?> 25 26<h1><?= $title ?></h1> 27 28<form action="#" id="data-fix-options"> 29 <p> 30 <?= $data_fix->description() ?> 31 </p> 32 33 <?= $data_fix->fixOptions($tree) ?> 34 35 <div class="row mb-3"> 36 <div class="col-sm-3"> 37 </div> 38 39 <div class="col-sm-9"> 40 <button class="btn btn-primary" type="button" id="btn-search"> 41 <?= view('icons/search') ?> 42 <?= I18N::translate('Search') ?> 43 </button> 44 45 <button class="btn btn-primary" type="button" id="btn-update-all"> 46 <?= view('icons/data-fix') ?> 47 <?= I18N::translate('Update all') ?> 48 </button> 49 </div> 50 </div> 51</form> 52 53<div id="data-fix-table-container" class="d-none"> 54 <table 55 id="data-fix-table" 56 class="table table-bordered table-sm table-hover wt-data-fix-table" 57 <?= view('lists/datatables-attributes') ?> 58 data-server-side="true" 59 data-filter="false" 60 data-processing="true" 61 data-sort="false" 62 > 63 <thead> 64 <tr> 65 <th class="w-75"> 66 <?= I18N::translate('Record') ?> 67 </th> 68 <th class="w-25"> 69 <?= view('icons/data-fix') ?> 70 <?= I18N::translate('Data fix') ?> 71 </th> 72 </tr> 73 </thead> 74 <tbody> 75 </tbody> 76 </table> 77 78 <hr> 79 80 <a href="#" data-bs-toggle="modal" data-bs-backdrop="static" data-bs-target="#wt-ajax-modal" data-wt-href="<?= e(route(HelpText::class, ['topic' => 'data-fixes'])) ?>"> 81 <?= view('icons/help') ?> 82 <?= I18N::translate('Why does this list include records that do not need to be updated?') ?> 83 </a> 84</div> 85 86<div id="data-fix-progress" class="d-none"> 87 <div class="progress"> 88 <div class="progress-bar" role="progressbar"></div> 89 </div> 90</div> 91 92<?= view('modals/ajax') ?> 93 94<?php View::push('javascript') ?> 95<script> 96 (function () { 97 let form = document.getElementById('data-fix-options'); 98 let container = document.getElementById('data-fix-table-container'); 99 let table = document.getElementById('data-fix-table'); 100 let progress = document.getElementById('data-fix-progress'); 101 let progressbar = progress.querySelector('.progress-bar'); 102 let queue = []; 103 104 function getParams () { 105 let formData = new FormData(form); 106 let params = {}; 107 formData.forEach(function (value, key) { 108 params[key] = value; 109 }); 110 111 return params; 112 } 113 114 function addParamsToUrl (u) { 115 let url = new URL(u); 116 let formData = new FormData(form); 117 formData.forEach(function (value, key) { 118 url.searchParams.append(key, value); 119 }); 120 121 return url.toString(); 122 123 } 124 125 form.addEventListener('submit', function (event) { 126 event.preventDefault(); 127 }); 128 129 container.addEventListener('click', function (event) { 130 if ('updateUrl' in event.target.dataset) { 131 event.preventDefault(); 132 133 webtrees.httpPost(event.target.dataset.updateUrl) 134 .then(function (response) { 135 $(table).DataTable().ajax.reload(null, false); 136 }) 137 .catch(function (error) { 138 alert(error); 139 }); 140 } 141 }); 142 143 document.getElementById('btn-search').addEventListener('click', function (event) { 144 event.preventDefault(); 145 146 // If we were in the middle of doing "update all", stop processing. 147 queue = []; 148 149 progress.classList.add('d-none'); 150 151 if ($.fn.dataTable.isDataTable(table)) { 152 $(table).DataTable().ajax.reload(); 153 } else { 154 $(table).DataTable({ 155 'ajax': { 156 'url': <?= json_encode(route(DataFixData::class, ['tree' => $tree->name(), 'data_fix' => $data_fix->name()]), JSON_THROW_ON_ERROR) ?>, 157 'data': function (data) { 158 $.extend(data, getParams()); 159 } 160 } 161 }); 162 } 163 164 container.classList.remove('d-none'); 165 }); 166 167 document.getElementById('btn-update-all').addEventListener('click', function (event) { 168 event.preventDefault(); 169 170 progressbar.innerHTML = ''; 171 progressbar.style.width = '0%'; 172 173 container.classList.add('d-none'); 174 progress.classList.remove('d-none'); 175 176 let url = addParamsToUrl(<?= json_encode(route(DataFixUpdateAll::class, ['tree' => $tree->name(), 'data_fix' => $data_fix->name()]), JSON_THROW_ON_ERROR) ?>); 177 178 webtrees.httpPost(url) 179 .then(function (response) { 180 return response.json(); 181 }) 182 .then(async function (data) { 183 queue = data; 184 while (queue.length > 0) { 185 let datum = queue.shift(); 186 await webtrees.httpPost(datum.url) 187 .then(function () { 188 let progressbar = progress.querySelector('.progress-bar'); 189 progressbar.innerHTML = datum.progress; 190 progressbar.style.width = datum.percent; 191 }); 192 } 193 }) 194 .catch(function (error) { 195 progress.innerHTML = error; 196 }); 197 }); 198 })(); 199</script> 200<?php View::endpush() ?> 201