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