diff --git a/acptemplates/faqQuestionAdd.tpl b/acptemplates/faqQuestionAdd.tpl index bb32bcf..268c56b 100644 --- a/acptemplates/faqQuestionAdd.tpl +++ b/acptemplates/faqQuestionAdd.tpl @@ -14,6 +14,10 @@ -{unsafe:$form->getHtml()} +{if $categories|count} + {unsafe:$form->getHtml()} +{else} + {lang}wcf.acp.faq.question.error.noCategory{/lang} +{/if} {include file='footer'} \ No newline at end of file diff --git a/files/lib/acp/form/FaqCategoryAddForm.class.php b/files/lib/acp/form/FaqCategoryAddForm.class.php index 2089bd0..b994f85 100644 --- a/files/lib/acp/form/FaqCategoryAddForm.class.php +++ b/files/lib/acp/form/FaqCategoryAddForm.class.php @@ -39,8 +39,6 @@ protected function createForm() #[Override] protected function finalizeForm() { - parent::finalizeForm(); - $this->form->getDataHandler()->addProcessor( new CustomFormDataProcessor( 'icon', @@ -59,5 +57,7 @@ function (IFormDocument $document, array $data, IStorableObject $object) { } ) ); + + parent::finalizeForm(); } } diff --git a/files/lib/acp/form/FaqQuestionAddForm.class.php b/files/lib/acp/form/FaqQuestionAddForm.class.php index ea2f4a5..eb1cd23 100644 --- a/files/lib/acp/form/FaqQuestionAddForm.class.php +++ b/files/lib/acp/form/FaqQuestionAddForm.class.php @@ -11,7 +11,6 @@ use wcf\data\IStorableObject; use wcf\data\language\item\LanguageItemList; use wcf\form\AbstractFormBuilderForm; -use wcf\system\exception\NamedUserException; use wcf\system\form\builder\container\FormContainer; use wcf\system\form\builder\container\TabFormContainer; use wcf\system\form\builder\container\TabMenuFormContainer; @@ -60,6 +59,8 @@ class FaqQuestionAddForm extends AbstractFormBuilderForm protected array $multiLingualAnswers = []; + protected array $categories; + #[Override] public function readParameters() { @@ -102,31 +103,6 @@ protected function createForm() { parent::createForm(); - $categoryTree = new FaqCategoryNodeTree('dev.tkirch.wsc.faq.category'); - $categoryTree->setMaxDepth(0); - $categoryList = $categoryTree->getIterator(); - - $categories = []; - foreach ($categoryList as $category) { - $categories[$category->categoryID] = $category; - - $childCategories = $category->getAllChildCategories(); - if (!\count($childCategories)) { - continue; - } - - foreach ($childCategories as $childCategory) { - $childCategory->setPrefix(); - $categories[$childCategory->categoryID] = $childCategory; - } - } - - if (!\count($categories)) { - throw new NamedUserException( - WCF::getLanguage()->getDynamicVariable('wcf.acp.faq.question.error.noCategory') - ); - } - $tabContent = []; if ($this->isMultilingual) { foreach ($this->availableLanguages as $language) { @@ -137,6 +113,7 @@ protected function createForm() ->label('wcf.acp.faq.question.answer') ->messageObjectType('dev.tkirch.wsc.faq.question') ->attachmentData('dev.tkirch.wsc.faq.question') + ->supportSmilies(true) ->required(), ]); } @@ -148,7 +125,7 @@ protected function createForm() ->appendChildren([ SingleSelectionFormField::create('categoryID') ->label('wcf.acp.faq.category') - ->options($categories) + ->options($this->getCategories()) ->required(), TextFormField::create('question') ->label('wcf.acp.faq.question.question') @@ -163,8 +140,8 @@ protected function createForm() : WysiwygFormContainer::create('answer') ->label('wcf.acp.faq.question.answer') ->messageObjectType('dev.tkirch.wsc.faq.question') - // ->messageLanguageItemPattern('wcf.faq.question.answer\d+') ->attachmentData('dev.tkirch.wsc.faq.question') + ->supportSmilies(true) ->required() ), FormContainer::create('position') @@ -239,4 +216,40 @@ protected function setFormAction() $this->form->action(LinkHandler::getInstance()->getControllerLink(static::class, $parameters)); } + + #[Override] + public function assignVariables() + { + parent::assignVariables(); + + WCF::getTPL()->assign([ + 'categories' => $this->getCategories(), + ]); + } + + protected function getCategories(): array + { + if (!isset($this->categories)) { + $categoryTree = new FaqCategoryNodeTree('dev.tkirch.wsc.faq.category'); + $categoryTree->setMaxDepth(0); + $categoryList = $categoryTree->getIterator(); + + $this->categories = []; + foreach ($categoryList as $category) { + $this->categories[$category->categoryID] = $category; + + $childCategories = $category->getAllChildCategories(); + if (!\count($childCategories)) { + continue; + } + + foreach ($childCategories as $childCategory) { + $childCategory->setPrefix(); + $this->categories[$childCategory->categoryID] = $childCategory; + } + } + } + + return $this->categories; + } } diff --git a/files/lib/data/faq/QuestionEditor.class.php b/files/lib/data/faq/QuestionEditor.class.php index 8f19153..c6dedc9 100644 --- a/files/lib/data/faq/QuestionEditor.class.php +++ b/files/lib/data/faq/QuestionEditor.class.php @@ -2,7 +2,10 @@ namespace wcf\data\faq; +use Override; use wcf\data\DatabaseObjectEditor; +use wcf\data\IEditableCachedObject; +use wcf\system\cache\builder\FaqQuestionListCacheBuilder; use wcf\system\WCF; /** @@ -10,13 +13,19 @@ * @method Question getDecoratedObject() * @mixin Question */ -final class QuestionEditor extends DatabaseObjectEditor +final class QuestionEditor extends DatabaseObjectEditor implements IEditableCachedObject { /** * @inheritDoc */ protected static $baseClass = Question::class; + #[Override] + public static function resetCache() + { + FaqQuestionListCacheBuilder::getInstance()->reset(); + } + /** * Returns the new show order for a object */ diff --git a/files/lib/data/faq/QuestionList.class.php b/files/lib/data/faq/QuestionList.class.php index 30afecc..f35f243 100644 --- a/files/lib/data/faq/QuestionList.class.php +++ b/files/lib/data/faq/QuestionList.class.php @@ -2,7 +2,6 @@ namespace wcf\data\faq; -use wcf\data\attachment\GroupedAttachmentList; use wcf\data\DatabaseObjectList; /** @@ -18,24 +17,4 @@ final class QuestionList extends DatabaseObjectList * @inheritDoc */ public $sqlOrderBy = 'showOrder, questionID'; - - private GroupedAttachmentList $attachmentList; - - public function readAttachments() - { - if (!empty($this->objectIDs)) { - $this->attachmentList = new GroupedAttachmentList('dev.tkirch.wsc.faq.question'); - $this->attachmentList->getConditionBuilder()->add('attachment.objectID IN (?)', [$this->objectIDs]); - $this->attachmentList->readObjects(); - } - } - - public function getAttachmentList() - { - if (!isset($this->attachmentList)) { - $this->readAttachments(); - } - - return $this->attachmentList; - } } diff --git a/files/lib/data/faq/category/FaqCategory.class.php b/files/lib/data/faq/category/FaqCategory.class.php index 2c79195..02a2ac7 100644 --- a/files/lib/data/faq/category/FaqCategory.class.php +++ b/files/lib/data/faq/category/FaqCategory.class.php @@ -13,6 +13,7 @@ use wcf\system\request\LinkHandler; use wcf\system\style\FontAwesomeIcon; use wcf\system\WCF; +use wcf\util\StringUtil; /** * @method FaqCategory[] getChildCategories() @@ -86,7 +87,17 @@ public function getLink(): string ]); } - public function getIcon(int $size = 24): string + public function getDescription(): string + { + return WCF::getLanguage()->get($this->description); + } + + public function getDescriptionHtml(): string + { + return $this->descriptionUseHtml ? $this->getDescription() : StringUtil::encodeHTML($this->getDescription()); + } + + public function getIcon(int $size = 24, bool $defaultIcon = false): string { if ( isset($this->additionalData['faqIcon']) @@ -95,6 +106,10 @@ public function getIcon(int $size = 24): string return FontAwesomeIcon::fromString($this->additionalData['faqIcon'])->toHtml($size); } + if ($defaultIcon) { + return FontAwesomeIcon::fromString('circle-question;false')->toHtml($size); + } + return ''; } } diff --git a/files/lib/page/FaqQuestionListPage.class.php b/files/lib/page/FaqQuestionListPage.class.php index 6bc2cb1..38a6d1c 100644 --- a/files/lib/page/FaqQuestionListPage.class.php +++ b/files/lib/page/FaqQuestionListPage.class.php @@ -4,10 +4,11 @@ use CuyZ\Valinor\Mapper\MappingError; use Override; +use wcf\data\attachment\GroupedAttachmentList; use wcf\data\faq\category\FaqCategory; use wcf\data\faq\category\FaqCategoryNodeTree; -use wcf\data\faq\QuestionList; use wcf\http\Helper; +use wcf\system\cache\builder\FaqQuestionListCacheBuilder; use wcf\system\exception\IllegalLinkException; use wcf\system\message\embedded\object\MessageEmbeddedObjectManager; use wcf\system\WCF; @@ -19,6 +20,8 @@ class FaqQuestionListPage extends AbstractPage */ public $neededPermissions = ['user.faq.canViewFAQ']; + protected array $faqs = []; + protected int $showFaqAddDialog = 0; protected ?FaqCategory $category; @@ -49,14 +52,15 @@ public function readParameters() } #[Override] - public function assignVariables() + public function readData() { - parent::assignVariables(); + parent::readData(); //get categories - $faqs = []; $embedObjectIDs = []; $categoryTree = new FaqCategoryNodeTree('dev.tkirch.wsc.faq.category'); + [$questionList, $questionIDs] = FaqQuestionListCacheBuilder::getInstance()->getData(); + $attachmentList = $this->getAttachmentList($questionIDs); foreach ($categoryTree->getIterator() as $category) { if (!$category->isAccessible()) { continue; @@ -69,23 +73,14 @@ public function assignVariables() continue; } - $questionList = new QuestionList(); - $questionList->getConditionBuilder()->add('categoryID = ?', [$category->categoryID]); - $questionList->readObjects(); - - if (!\count($questionList)) { - continue; - } - $faq = [ - 'id' => $category->categoryID, - 'title' => WCF::getLanguage()->get($category->title), - 'attachments' => $questionList->getAttachmentList(), - 'icon24' => $category->getIcon(24), - 'icon64' => $category->getIcon(64), + 'category' => $category, + 'attachments' => $attachmentList, + 'questions' => [], ]; - foreach ($questionList->getObjects() as $question) { + $questions = $questionList[$category->categoryID] ?? []; + foreach ($questions as $question) { if ($question->isAccessible()) { $faq['questions'][] = $question; if ($question->hasEmbeddedObjects) { @@ -95,22 +90,41 @@ public function assignVariables() } if ($category->getParentNode() && $category->getParentNode()->categoryID) { - $faqs[$category->getParentNode()->categoryID]['sub'][$category->categoryID] = $faq; + $this->faqs[$category->getParentNode()->categoryID]['sub'][$category->categoryID] = $faq; } else { - $faqs[$category->categoryID] = $faq; + $this->faqs[$category->categoryID] = $faq; } } - if (\count($embedObjectIDs)) { + if ($embedObjectIDs !== []) { MessageEmbeddedObjectManager::getInstance()->loadObjects( 'dev.tkirch.wsc.faq.question', $embedObjectIDs ); } + } + + #[Override] + public function assignVariables() + { + parent::assignVariables(); WCF::getTPL()->assign([ - 'faqs' => $faqs, + 'faqs' => $this->faqs, 'showFaqAddDialog' => $this->showFaqAddDialog, ]); } + + protected function getAttachmentList(array $questionIDs): array|GroupedAttachmentList + { + if ($questionIDs === []) { + return []; + } + + $attachmentList = new GroupedAttachmentList('dev.tkirch.wsc.faq.question'); + $attachmentList->getConditionBuilder()->add('attachment.objectID IN (?)', [$questionIDs]); + $attachmentList->readObjects(); + + return $attachmentList; + } } diff --git a/files/lib/system/box/FaqCategoriesBoxController.class.php b/files/lib/system/box/FaqCategoriesBoxController.class.php index 9b282f5..13eb871 100644 --- a/files/lib/system/box/FaqCategoriesBoxController.class.php +++ b/files/lib/system/box/FaqCategoriesBoxController.class.php @@ -46,6 +46,9 @@ protected function getResetFilterLink(): string #[Override] public function hasContent() { - return SIMPLE_FAQ_VIEW !== 'gallery'; + $categoryTree = $this->getNodeTree(); + $categoryList = $categoryTree->getIterator(); + + return SIMPLE_FAQ_VIEW !== 'gallery' && \iterator_count($categoryList); } } diff --git a/files/lib/system/cache/builder/FaqQuestionListCacheBuilder.class.php b/files/lib/system/cache/builder/FaqQuestionListCacheBuilder.class.php new file mode 100644 index 0000000..bc23312 --- /dev/null +++ b/files/lib/system/cache/builder/FaqQuestionListCacheBuilder.class.php @@ -0,0 +1,23 @@ +readObjects(); + + $questions = []; + foreach ($questionList as $question) { + $questions[$question->categoryID][] = $question; + } + + return [$questions, $questionList->getObjectIDs()]; + } +} diff --git a/files/lib/system/category/FaqCategoryType.class.php b/files/lib/system/category/FaqCategoryType.class.php index fb663c4..dcb924d 100644 --- a/files/lib/system/category/FaqCategoryType.class.php +++ b/files/lib/system/category/FaqCategoryType.class.php @@ -14,7 +14,7 @@ final class FaqCategoryType extends AbstractCategoryType /** * @inheritDoc */ - protected $hasDescription = false; + protected $hasDescription = true; /** * @inheritDoc @@ -42,7 +42,14 @@ final class FaqCategoryType extends AbstractCategoryType protected function init() { $this->maximumNestingLevel = SIMPLE_FAQ_VIEW === 'gallery' ? 0 : 1; + $this->hasDescription = SIMPLE_FAQ_VIEW === 'gallery' ? false : true; parent::init(); } + + #[Override] + public function supportsHtmlDescription() + { + return SIMPLE_FAQ_VIEW === 'gallery' ? false : true; + } } diff --git a/files/style/faq.scss b/files/style/faq.scss index 926fd7a..0572943 100644 --- a/files/style/faq.scss +++ b/files/style/faq.scss @@ -43,18 +43,22 @@ } .faq { - > h2 { - font-size: 1.5rem; - border-bottom: 1px solid currentColor; - padding-bottom: 10px + > .sectionHeader { + h2 { + font-size: 1.5rem !important; + } + border-bottom: 1px solid currentColor !important; + padding-bottom: 10px; } > .sub { margin-top: 16px; margin-bottom: 8px; margin-left: 16px; - > h2 { - font-size: 1.3rem; - border-bottom: 1px solid currentColor; + .sectionHeader { + h2 { + font-size: 1.3rem !important; + } + border-bottom: 1px solid currentColor !important; padding-bottom: 10px; } } diff --git a/package.xml b/package.xml index 88ae5c1..55c3573 100644 --- a/package.xml +++ b/package.xml @@ -6,8 +6,8 @@ Simple FAQ A simple and powerful FAQ for your WSC. Ein simples und leistungsstarkes FAQ für Ihr WSC. - 2.2.4 - 2024-10-29 + 2.2.5 + 2024-11-03 Hanashi Development, Titus Kirch @@ -36,8 +36,10 @@ acp/database/install_dev.tkirch.wsc.faq.php - - + + + + diff --git a/templates/faqQuestionAdd.tpl b/templates/faqQuestionAdd.tpl index 67ac013..4ac3e8d 100644 --- a/templates/faqQuestionAdd.tpl +++ b/templates/faqQuestionAdd.tpl @@ -18,6 +18,10 @@ {include file='header' contentHeader=$__contentHeader} -{unsafe:$form->getHtml()} +{if $categories|count} + {unsafe:$form->getHtml()} +{else} + {lang}wcf.acp.faq.question.error.noCategory{/lang} +{/if} {include file='footer'} diff --git a/templates/faqQuestionList.tpl b/templates/faqQuestionList.tpl index 98555db..9538d0d 100644 --- a/templates/faqQuestionList.tpl +++ b/templates/faqQuestionList.tpl @@ -23,13 +23,9 @@
{foreach from=$faqs item=faq} {if ($faq['questions']|isset && $faq['questions']|count)} - {/if} {/foreach} @@ -46,8 +42,8 @@ {if ($faq['questions']|isset && $faq['questions']|count)} {assign var='attachmentList' value=$faq['attachments']} -