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