getLang('menu'); } // --------------------------------------------------------------------- // Request handling (clear actions) // --------------------------------------------------------------------- /** * Process a submitted clear action, then Post/Redirect/Get back to the * overview so a reload does not repeat it. DokuWiki's admin dispatcher * enforces forAdminOnly() before this runs; the CSRF token and the helper's * canClear() rule are still checked. * * @return void */ public function handle() { global $INPUT, $ID; $action = $INPUT->post->str('annotations_action'); if ($action === '') { return; } if (!checkSecurityToken()) { return; } /** @var helper_plugin_annotations $helper */ $helper = $this->loadHelper('annotations', false); if (!$helper || !$helper->canClear(auth_isadmin())) { return; } if ($action === 'clear_orphaned') { $page = cleanID($INPUT->post->str('clearpage')); if ($page !== '') { $count = $helper->clearOrphaned($page); if ($count === false) { msg($this->getLang('clear_fail'), -1); } else { msg(sprintf($this->getLang('cleared_page'), $count, hsc($page)), 1); } } } elseif ($action === 'clear_orphaned_all') { $count = $helper->clearOrphanedAll(); msg(sprintf($this->getLang('cleared_all'), $count), 1); } send_redirect(wl($ID, $this->standingParams(), true, '&')); } // --------------------------------------------------------------------- // Output // --------------------------------------------------------------------- /** * Render the overview: a wiki-wide "clear all orphaned" button, then a * sortable/filterable/paginated table of annotated pages. * * @return void */ public function html() { global $INPUT, $ID; echo '
' . hsc($this->getLang('none')) . '
'; echo ''; return; } $totalOrphaned = 0; foreach ($rows as $r) { $totalOrphaned += $r['orphaned']; } // request parameters $sort = $INPUT->str('sort', 'page'); if (!in_array($sort, $this->sortable, true)) { $sort = 'page'; } $dir = ($INPUT->str('dir') === 'desc') ? 'desc' : 'asc'; $filters = $this->activeFilters(); $shown = $this->applyFilters($rows, $filters); $shown = $this->sortRows($shown, $sort, $dir); $total = count($shown); [$pageRows, $page, $totalPages, $from, $to] = $this->paginate($shown, (int) $this->getConf('entries_per_page')); echo '' . hsc($this->getLang('intro')) . '
'; // wiki-wide clear-all (counts all annotated pages, not just the filtered // view); the button targets the POST form rendered at the end via form= echo ''; $cols = ['page', 'normal', 'orphaned', 'actions']; $labels = [ 'page' => $this->getLang('th_page'), 'normal' => $this->getLang('th_normal'), 'orphaned' => $this->getLang('th_orphaned'), 'actions' => $this->getLang('th_actions'), ]; // GET form so the filter combines with the sort links and bookmarks // cleanly; the action URL's query string is dropped on submit, so the // standing parameters travel as hidden fields. echo ''; echo $this->renderPager($page, $totalPages); if ($total > 0) { echo '' . hsc(sprintf($this->getLang('shown'), $from, $to, $total)) . '
'; } // POST forms targeted by the clear buttons (siblings of the GET form, so // no illegal nested '; $all = ''; return $single . $all; } /** * The standing sort/filter/page state as hidden inputs, so a clear action's * redirect (which rebuilds the URL from $INPUT) preserves the current view. * * @return string */ protected function standingHiddenFields() { global $INPUT; $html = ''; $sort = $INPUT->str('sort'); if (in_array($sort, $this->sortable, true)) { $html .= ''; } if ($INPUT->str('dir') === 'desc') { $html .= ''; } $filters = $this->activeFilters(); if (isset($filters['page'])) { $html .= ''; } $pg = $INPUT->int('pg', 0); if ($pg > 1) { $html .= ''; } return $html; } /** * An onclick attribute that confirms before submitting, escaped safely for * both the HTML-attribute and the JS-string layers (json_encode escapes the * quotes inside the message, hsc escapes the attribute). * * @param string $key lang key of the confirmation message * @return string e.g. ' onclick="return confirm("…")"' */ protected function confirmAttr($key) { $js = 'return confirm(' . json_encode($this->getLang($key), JSON_HEX_APOS | JSON_HEX_QUOT | JSON_UNESCAPED_UNICODE) . ');'; return ' onclick="' . hsc($js) . '"'; } }