4a0e8540eeef2ef8c96974ae03a8a105b65cdacd
[Packages/TYPO3.CMS.git] / typo3 / sysext / opendocs / Classes / Backend / ToolbarItems / OpendocsToolbarItem.php
1 <?php
2 namespace TYPO3\CMS\Opendocs\Backend\ToolbarItems;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
21 use TYPO3\CMS\Core\Imaging\Icon;
22 use TYPO3\CMS\Core\Imaging\IconFactory;
23 use TYPO3\CMS\Core\Page\PageRenderer;
24 use TYPO3\CMS\Core\Utility\GeneralUtility;
25
26 /**
27 * Alist of all open documents
28 */
29 class OpendocsToolbarItem implements ToolbarItemInterface
30 {
31 /**
32 * @var array
33 */
34 protected $openDocs;
35
36 /**
37 * @var array
38 */
39 protected $recentDocs;
40
41 /**
42 * @var IconFactory
43 */
44 protected $iconFactory;
45
46 /**
47 * Constructor
48 */
49 public function __construct()
50 {
51 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
52 $this->getLanguageService()->includeLLFile('EXT:opendocs/Resources/Private/Language/locallang.xlf');
53 $this->loadDocsFromUserSession();
54 $pageRenderer = $this->getPageRenderer();
55 $pageRenderer->loadRequireJsModule('TYPO3/CMS/Opendocs/Toolbar/OpendocsMenu');
56 }
57
58 /**
59 * Checks whether the user has access to this toolbar item
60 *
61 * @return bool TRUE if user has access, FALSE if not
62 */
63 public function checkAccess()
64 {
65 $conf = $this->getBackendUser()->getTSConfig('backendToolbarItem.tx_opendocs.disabled');
66 return $conf['value'] != 1;
67 }
68
69 /**
70 * Loads the opened and recently opened documents from the user
71 *
72 * @return void
73 */
74 public function loadDocsFromUserSession()
75 {
76 $backendUser = $this->getBackendUser();
77 list($this->openDocs, ) = $backendUser->getModuleData('FormEngine', 'ses');
78 $this->recentDocs = $backendUser->getModuleData('opendocs::recent');
79 }
80
81 /**
82 * Render toolbar icon
83 *
84 * @return string HTML
85 */
86 public function getItem()
87 {
88 $numDocs = count($this->openDocs);
89 $title = htmlspecialchars($this->getLanguageService()->getLL('toolbaritem'));
90 $icon = $this->iconFactory->getIcon('apps-toolbar-menu-opendocs', Icon::SIZE_SMALL)->render('inline');
91 return '
92 <span class="toolbar-item-icon" title="' . $title . '">' . $icon . '</span>
93 <span class="toolbar-item-title">' . $title . '</span>
94 <span class="toolbar-item-badge badge" id="tx-opendocs-counter">' . $numDocs . '</span>
95 ';
96 }
97
98 /**
99 * Render drop down
100 *
101 * @return string HTML
102 */
103 public function getDropDown()
104 {
105 $languageService = $this->getLanguageService();
106 $openDocuments = $this->openDocs;
107 $recentDocuments = $this->recentDocs;
108 $entries = [];
109
110 $entries[] = '<h3 class="dropdown-headline">';
111 $entries[] = htmlspecialchars($this->getLanguageService()->getLL('toolbaritem'));
112 $entries[] = '</h3>';
113 $entries[] = '<hr>';
114
115 if (!empty($openDocuments)) {
116 $entries[] = '<h3 class="dropdown-headline">';
117 $entries[] = htmlspecialchars($languageService->getLL('open_docs'));
118 $entries[] = '</h3>';
119 $entries[] = '<div class="dropdown-table">';
120 $i = 0;
121 foreach ($openDocuments as $md5sum => $openDocument) {
122 $i++;
123 $entries[] = $this->renderMenuEntry($openDocument, $md5sum, false, $i == 1);
124 }
125 $entries[] = '</div>';
126 $entries[] = '<hr>';
127 }
128 // If there are "recent documents" in the list, add them
129 if (!empty($recentDocuments)) {
130 $entries[] = '<h3 class="dropdown-headline">';
131 $entries[] = htmlspecialchars($languageService->getLL('recent_docs'));
132 $entries[] = '</h3>';
133 $entries[] = '<div class="dropdown-table">';
134 $i = 0;
135 foreach ($recentDocuments as $md5sum => $recentDocument) {
136 $i++;
137 $entries[] = $this->renderMenuEntry($recentDocument, $md5sum, true, $i == 1);
138 }
139 $entries[] = '</div>';
140 }
141 if (!empty($entries)) {
142 $content = implode('', $entries);
143 } else {
144 $content = '<p>' . htmlspecialchars($languageService->getLL('no_docs')) . '</p>';
145 }
146 return $content;
147 }
148
149 /**
150 * Returns the recent documents list as an array
151 *
152 * @param array $document
153 * @param string $md5sum
154 * @param bool $isRecentDoc
155 * @param bool $isFirstDoc
156 * @return array All recent documents as list-items
157 */
158 protected function renderMenuEntry($document, $md5sum, $isRecentDoc = false, $isFirstDoc = false)
159 {
160 $table = $document[3]['table'];
161 $uid = $document[3]['uid'];
162 $record = BackendUtility::getRecordWSOL($table, $uid);
163 if (!is_array($record)) {
164 // Record seems to be deleted
165 return '';
166 }
167 $label = htmlspecialchars(strip_tags(htmlspecialchars_decode($document[0])));
168 $icon = $this->iconFactory->getIconForRecord($table, $record, Icon::SIZE_SMALL)->render();
169 $link = BackendUtility::getModuleUrl('record_edit') . '&' . $document[2];
170 $pageId = (int)$document[3]['uid'];
171 if ($document[3]['table'] !== 'pages') {
172 $pageId = (int)$document[3]['pid'];
173 }
174 $onClickCode = 'jump(' . GeneralUtility::quoteJSvalue($link) . ', \'web_list\', \'web\', ' . $pageId . '); TYPO3.OpendocsMenu.toggleMenu(); return false;';
175 if (!$isRecentDoc) {
176 $title = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.closeDoc'));
177 // Open document
178 $entry = '<div class="dropdown-table-row t3js-topbar-opendocs-item">';
179 $entry .= '<div class="dropdown-table-column dropdown-table-icon">';
180 $entry .= $icon;
181 $entry .= '</div>';
182 $entry .= '<div class="dropdown-table-column dropdown-table-title">';
183 $entry .= '<a class="dropdown-table-title-ellipsis" href="#" onclick="' . htmlspecialchars($onClickCode) . '" target="contentIframe">';
184 $entry .= $label;
185 $entry .= '</a>';
186 $entry .= '</div>';
187 $entry .= '<div class="dropdown-table-column dropdown-table-actions">';
188 $entry .= '<a href="#" class="dropdown-table-actions-btn dropdown-table-actions-btn-close t3js-topbar-opendocs-close" data-opendocsidentifier="' . $md5sum . '" title="' . $title . '">';
189 $entry .= $this->iconFactory->getIcon('actions-close', Icon::SIZE_SMALL)->render('inline');
190 $entry .= '</a>';
191 $entry .= '</div>';
192 $entry .= '</div>';
193 } else {
194 // Recently used document
195 $entry = '<div class="dropdown-table-row t3js-topbar-recentdoc">';
196 $entry .= '<div class="dropdown-table-column dropdown-table-icon">';
197 $entry .= $icon;
198 $entry .= '</div>';
199 $entry .= '<div class="dropdown-table-column dropdown-table-title">';
200 $entry .= '<a class="dropdown-table-title-ellipsis" href="#" onclick="' . htmlspecialchars($onClickCode) . '" target="contentIframe">';
201 $entry .= $label;
202 $entry .= '</a>';
203 $entry .= '</div>';
204 $entry .= '</div>';
205 }
206 return $entry;
207 }
208
209 /**
210 * No additional attributes
211 *
212 * @return string List item HTML attibutes
213 */
214 public function getAdditionalAttributes()
215 {
216 return [];
217 }
218
219 /**
220 * This item has a drop down
221 *
222 * @return bool
223 */
224 public function hasDropDown()
225 {
226 return true;
227 }
228
229 /*******************
230 *** HOOKS ***
231 *******************/
232 /**
233 * Called as a hook in \TYPO3\CMS\Backend\Utility\BackendUtility::setUpdateSignal, calls a JS function to change
234 * the number of opened documents
235 *
236 * @param array $params
237 * @param unknown_type $ref
238 * @return string list item HTML attributes
239 */
240 public function updateNumberOfOpenDocsHook(&$params, $ref)
241 {
242 $params['JScode'] = '
243 if (top && top.TYPO3.OpendocsMenu) {
244 top.TYPO3.OpendocsMenu.updateMenu();
245 }
246 ';
247 }
248
249 /******************
250 *** AJAX CALLS ***
251 ******************/
252 /**
253 * Closes a document in the session and
254 *
255 * @param ServerRequestInterface $request
256 * @param ResponseInterface $response
257 * @return ResponseInterface
258 */
259 public function closeDocument(ServerRequestInterface $request, ResponseInterface $response)
260 {
261 $backendUser = $this->getBackendUser();
262 $md5sum = isset($request->getParsedBody()['md5sum']) ? $request->getParsedBody()['md5sum'] : $request->getQueryParams()['md5sum'];
263 if ($md5sum && isset($this->openDocs[$md5sum])) {
264 // Add the document to be closed to the recent documents
265 $this->recentDocs = array_merge([$md5sum => $this->openDocs[$md5sum]], $this->recentDocs);
266 // Allow a maximum of 8 recent documents
267 if (count($this->recentDocs) > 8) {
268 $this->recentDocs = array_slice($this->recentDocs, 0, 8);
269 }
270 // Remove it from the list of the open documents, and store the status
271 unset($this->openDocs[$md5sum]);
272 list(, $docDat) = $backendUser->getModuleData('FormEngine', 'ses');
273 $backendUser->pushModuleData('FormEngine', [$this->openDocs, $docDat]);
274 $backendUser->pushModuleData('opendocs::recent', $this->recentDocs);
275 }
276 return $this->renderMenu($request, $response);
277 }
278
279 /**
280 * Renders the menu so that it can be returned as response to an AJAX call
281 *
282 * @param ServerRequestInterface $request
283 * @param ResponseInterface $response
284 * @return ResponseInterface
285 */
286 public function renderMenu(ServerRequestInterface $request, ResponseInterface $response)
287 {
288 $response->getBody()->write($this->getDropDown());
289 $response = $response->withHeader('Content-Type', 'html');
290 return $response;
291 }
292
293 /**
294 * Position relative to others
295 *
296 * @return int
297 */
298 public function getIndex()
299 {
300 return 30;
301 }
302
303 /**
304 * Returns the current BE user.
305 *
306 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
307 */
308 protected function getBackendUser()
309 {
310 return $GLOBALS['BE_USER'];
311 }
312
313 /**
314 * Returns current PageRenderer
315 *
316 * @return PageRenderer
317 */
318 protected function getPageRenderer()
319 {
320 return GeneralUtility::makeInstance(PageRenderer::class);
321 }
322
323 /**
324 * Returns LanguageService
325 *
326 * @return \TYPO3\CMS\Lang\LanguageService
327 */
328 protected function getLanguageService()
329 {
330 return $GLOBALS['LANG'];
331 }
332 }