diff --git a/app/class/Optlist.php b/app/class/Optlist.php index 79c17693..cbea2afe 100644 --- a/app/class/Optlist.php +++ b/app/class/Optlist.php @@ -17,7 +17,7 @@ class Optlist extends Optcode protected bool $time = false; protected bool $author = false; protected bool $hidecurrent = false; - protected bool $tags = false; + protected bool $tagcheck = false; protected string $style = self::LIST; public const LIST = 'list'; @@ -27,6 +27,9 @@ class Optlist extends Optcode self::CARD => self::CARD, ]; + /** @var array $usefulltags */ + protected array $usefulltags = []; + /** * @param array $datas */ @@ -52,6 +55,9 @@ public function getcode(): string */ public function listhtml(array $pagelist, Page $currentpage): string { + $pagecount = count($pagelist); + $html = ''; + if ($this->hidecurrent && key_exists($currentpage->id(), $pagelist)) { unset($pagelist[$currentpage->id()]); } @@ -137,16 +143,69 @@ public function listhtml(array $pagelist, Page $currentpage): string $thumbnail->setAttribute('alt', htmlspecialchars($page->title())); $parent->appendChild($thumbnail); } + if ($this->tagcheck) { + $tags = $page->tag(); + $this->addusefulltags($tags); + foreach ($tags as $tag) { + $parent->setAttribute("data-tag_$tag", '1'); + } + } } - $dom->appendChild($ul); - return $dom->saveHTML($dom->documentElement); + if ($this->tagcheck) { + $hash = crc32(serialize($this)); + $domform = new DOMDocument('1.0', 'UTF-8'); + $form = $domform->createElement('form'); + $form->setAttribute('class', 'tagcheck'); + $form->setAttribute('id', "tagcheck-$hash"); + foreach ($this->usefulltags as $tag => $count) { + if ($count === $pagecount) { + continue; // skip this tag as it's used by all pages + } + $span = $domform->createElement('span'); + $span->setAttribute('class', "tag_$tag"); + $id = "tagcheck-$hash-tag_$tag"; + $input = $domform->createElement('input'); + $input->setAttribute('id', $id); + $input->setAttribute('value', $tag); + $input->setAttribute('type', 'checkbox'); + $label = $domform->createElement('label', $tag); + $label->setAttribute('for', $id); + $span->appendChild($input); + $span->appendChild($label); + $form->appendChild($span); + } + $domform->appendChild($form); + $html .= $domform->saveHTML($domform->documentElement); + $html .= "\n"; + } + + $html .= $dom->saveHTML($dom->documentElement); + + return $html; } catch (DOMException $e) { throw new LogicException('bad DOM node used', 0, $e); } } + /** + * merge list of tags within the list of usefull tags. + * Tag name is key and value count the time it's used. + * + * @param string[] $tags + */ + private function addusefulltags(array $tags): void + { + foreach ($tags as $tag) { + if (key_exists($tag, $this->usefulltags)) { + $this->usefulltags[$tag] ++; + } else { + $this->usefulltags[$tag] = 1; + } + } + } + @@ -188,6 +247,11 @@ public function hidecurrent(): bool return $this->hidecurrent; } + public function tagcheck(): bool + { + return $this->tagcheck; + } + public function style(): string { return $this->style; @@ -231,6 +295,11 @@ public function sethidecurrent(bool $hidecurrent): void $this->hidecurrent = $hidecurrent; } + public function settagcheck(bool $tagcheck): void + { + $this->tagcheck = $tagcheck; + } + public function setstyle(string $style): void { if (key_exists($style, self::STYLES)) { diff --git a/app/class/Servicerender.php b/app/class/Servicerender.php index 897a1358..dd74afaf 100644 --- a/app/class/Servicerender.php +++ b/app/class/Servicerender.php @@ -49,6 +49,9 @@ abstract class Servicerender /** @var bool True if the page need post process */ protected bool $postprocessaction = false; + /** @var bool True if the page need to join a JS checkbox file */ + protected bool $checkboxjs = false; + /** * @var Bookmark[] Associative array of Bookmarks using fullmatch as key * */ @@ -260,6 +263,10 @@ protected function gethead(): string } catch (RuntimeException $e) { Logger::warningex($e); } + if ($this->checkboxjs) { + $checkboxjs = Model::jspath() . 'pagecheckbox.bundle.js'; + $head .= "\n"; + } if (!empty($this->page->javascript())) { $head .= "\n"; } @@ -707,6 +714,10 @@ protected function pageoptlist(string $text): string $optlist->hydrate($options); + if ($optlist->tagcheck()) { + $this->checkboxjs = true; + } + $pagetable = $this->pagemanager->pagetable($this->pagemanager->pagelist(), $optlist); $content = $optlist->listhtml($pagetable, $this->page); $text = str_replace($match->fullmatch(), $content, $text); diff --git a/src/pagecheckbox.js b/src/pagecheckbox.js new file mode 100644 index 00000000..30af56f3 --- /dev/null +++ b/src/pagecheckbox.js @@ -0,0 +1,39 @@ +const formFilters = document.querySelectorAll('form'); + +function filterpagelist(id) { + let idSelector = '#' + id; + let tagCheckboxesChecked = document.querySelectorAll( + 'form' + idSelector + ' input[type="checkbox"]:checked' + ); + + let pages = document.querySelectorAll( + 'form' + idSelector + ' + .pagelist li' + ); + let tagCount = tagCheckboxesChecked.length; + + for (var li of pages) { + li.classList.remove('w_filter-or-out'); + li.classList.remove('w_filter-and-out'); + if (tagCount > 0) { + let counter = 0; + for (var tag of tagCheckboxesChecked) { + let dataAttr = 'data-tag_' + tag.value; + if (li.hasAttribute(dataAttr)) { + counter++; + } + } + if (counter < 1) { + li.classList.add('w_filter-or-out'); + } + if (counter !== tagCount) { + li.classList.add('w_filter-and-out'); + } + } + } +} + +for (let formFilter of formFilters) { + formFilter.addEventListener('click', () => { + filterpagelist(formFilter.id); + }); +}