/
FaqHelper.php
250 lines (217 loc) · 7.58 KB
/
FaqHelper.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
<?php
/**
* Helper class for phpMyFAQ FAQs.
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*
* @package phpMyFAQ\Helper
* @author Thorsten Rinne <thorsten@phpmyfaq.de>
* @copyright 2010-2023 phpMyFAQ Team
* @license https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
* @link https://www.phpmyfaq.de
* @since 2010-11-12
*/
namespace phpMyFAQ\Helper;
use DOMDocument;
use Exception;
use ParsedownExtra;
use phpMyFAQ\Category;
use phpMyFAQ\Configuration;
use phpMyFAQ\Date;
use phpMyFAQ\Entity\FaqEntity;
use phpMyFAQ\Faq;
use phpMyFAQ\Helper;
use phpMyFAQ\Language\LanguageCodes;
use phpMyFAQ\Link;
use phpMyFAQ\Strings;
use phpMyFAQ\Translation;
use phpMyFAQ\Utils;
/**
* Class FaqHelper
*
* @package phpMyFAQ\Helper
*/
class FaqHelper extends Helper
{
/**
* Constructor.
*/
public function __construct(Configuration $config)
{
$this->config = $config;
}
/**
* Rewrites the CSS class generated by TinyMCE for HighlightJS.
*/
public function renderMarkupContent(string $answer): string
{
return str_replace('class="language-markup"', 'class="language-html"', $answer);
}
/**
* Extends URL fragments (e.g. <a href="#foo">) with the full default URL.
*/
public function rewriteUrlFragments(string $answer, string $currentUrl): string
{
return str_replace('href="#', 'href="' . $currentUrl . '#', $answer);
}
/**
* Renders a Share on Twitter link.
*/
public function renderTwitterShareLink(string $url): string
{
if (empty($url) || $this->config->get('socialnetworks.disableAll')) {
return '';
}
return sprintf(
'<i aria-hidden="true" class="fa fa-twitter"></i>' .
'<a rel="nofollow" href="%s" target="_blank" class="text-decoration-none">Twitter</a>',
$url
);
}
/**
* Renders a "Send to friend" HTML snippet.
*/
public function renderSendToFriend(string $url): string
{
if (empty($url) || !$this->config->get('main.enableSendToFriend')) {
return '';
}
return sprintf(
'<i aria-hidden="true" class="fa fa-envelope"></i>' .
'<a rel="nofollow" href="%s" class="text-decoration-none">%s</a>',
$url,
Translation::get('msgSend2Friend')
);
}
/**
* Renders a select box with all translations of a FAQ.
*/
public function renderChangeLanguageSelector(Faq $faq, int $categoryId): string
{
$html = '';
$faqUrl = sprintf(
'?action=faq&cat=%d&id=%d&artlang=%%s',
$categoryId,
$faq->faqRecord['id']
);
$oLink = new Link($this->config->getDefaultUrl() . $faqUrl, $this->config);
$oLink->itemTitle = $faq->faqRecord['title'];
$availableLanguages = $this->config->getLanguage()->isLanguageAvailable($faq->faqRecord['id']);
if ((is_countable($availableLanguages) ? count($availableLanguages) : 0) > 1) {
$html = '<form method="post">';
$html .= '<select name="language" onchange="top.location.href = this.options[this.selectedIndex].value;">';
foreach ($availableLanguages as $language) {
$html .= sprintf('<option value="%s"', sprintf($oLink->toString(), $language));
$html .= ($faq->faqRecord['lang'] === $language ? ' selected' : '');
$html .= sprintf('>%s</option>', LanguageCodes::get($language));
}
$html .= '</select></form>';
}
return $html;
}
/**
* Renders a preview of the answer.
*
* @throws Exception
*/
public function renderAnswerPreview(string $answer, int $numWords): string
{
if ($this->config->get('main.enableMarkdownEditor')) {
$parseDown = new ParsedownExtra();
return Utils::chopString(strip_tags((string) $parseDown->text($answer)), $numWords);
} else {
return Utils::chopString(strip_tags($answer), $numWords);
}
}
/**
* Creates an overview with all categories with their FAQs.
*
* @throws Exception
*/
public function createOverview(Category $category, Faq $faq, string $language = ''): string
{
$output = '';
// Initialize categories
$category->transform(0);
// Get all FAQs
$faq->getAllRecords(FAQ_SORTING_TYPE_CATID_FAQID, ['lang' => $language]);
$date = new Date($this->config);
if (count($faq->faqRecords)) {
$lastCategory = 0;
foreach ($faq->faqRecords as $data) {
if ($data['category_id'] !== $lastCategory) {
$output .= sprintf('<h3>%s</h3>', $category->getPath($data['category_id'], ' » '));
}
$output .= sprintf('<h4>%s</h4>', Strings::htmlentities($data['title']));
$output .= sprintf('<article>%s</article>', $data['content']);
$output .= sprintf(
'<p>%s: %s<br>%s',
Translation::get('msgAuthor'),
Strings::htmlentities($data['author']),
Translation::get('msgLastUpdateArticle') . $date->format($data['updated'])
);
$output .= '<hr>';
$lastCategory = $data['category_id'];
}
}
return $output;
}
/**
* Creates a list of links with available languages to edit a FAQ
* in the admin backend.
*/
public function createFaqTranslationLinkList(int $faqId, int $categoryId, string $faqLang): string
{
$output = '';
$availableLanguages = $this->config->getLanguage()->isLanguageAvailable($categoryId, 'faqcategories');
foreach ($availableLanguages as $languageCode) {
if ($languageCode !== $faqLang) {
$output .= sprintf(
'<a class="dropdown-item" href="?action=editentry&id=%d&cat=%d&translateTo=%s">%s %s</a>',
$faqId,
$categoryId,
$languageCode,
'Translate to',
LanguageCodes::get($languageCode)
);
} else {
$output .= '<a class="dropdown-item">n/a</a>';
}
}
return $output;
}
/**
* Returns the URL for a given FAQ Entity and category ID.
* @param FaqEntity $faqEntity
* @param int $categoryId
* @return string
*/
public function createFaqUrl(FaqEntity $faqEntity, int $categoryId): string
{
return sprintf(
'%s?action=faq&cat=%d&id=%d&artlang=%s',
$this->config->getDefaultUrl() . 'index.php',
$categoryId,
$faqEntity->getId(),
$faqEntity->getLanguage()
);
}
/**
* Remove <script> tags, we don't need them
*
* @param string $content
* @return string
*/
public function cleanUpContent(string $content): string
{
$document = new DOMDocument();
$document->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$scriptTags = $document->getElementsByTagName('script');
for ($i = 0; $i < $scriptTags->length; $i++) {
$scriptTags->item($i)->parentNode->removeChild($scriptTags->item($i));
}
return preg_replace(['/\r/', '/\n/'], '', $document->saveHTML());
}
}