We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * (c) Kitodo. Key to digital objects e.V. <[email protected]> |
||
5 | * |
||
6 | * This file is part of the Kitodo and TYPO3 projects. |
||
7 | * |
||
8 | * @license GNU General Public License version 3 or later. |
||
9 | * For the full copyright and license information, please read the |
||
10 | * LICENSE.txt file that was distributed with this source code. |
||
11 | */ |
||
12 | |||
13 | namespace Kitodo\Dlf\Plugin; |
||
14 | |||
15 | use Kitodo\Dlf\Common\Helper; |
||
16 | use Kitodo\Dlf\Common\IiifManifest; |
||
17 | use Ubl\Iiif\Presentation\Common\Model\Resources\ManifestInterface; |
||
18 | use Ubl\Iiif\Presentation\Common\Vocabulary\Motivation; |
||
19 | |||
20 | /** |
||
21 | * Plugin 'Page View' for the 'dlf' extension |
||
22 | * |
||
23 | * @author Sebastian Meyer <[email protected]> |
||
24 | * @package TYPO3 |
||
25 | * @subpackage dlf |
||
26 | * @access public |
||
27 | */ |
||
28 | class PageView extends \Kitodo\Dlf\Common\AbstractPlugin |
||
29 | { |
||
30 | public $scriptRelPath = 'Classes/Plugin/PageView.php'; |
||
31 | |||
32 | /** |
||
33 | * Holds the controls to add to the map |
||
34 | * |
||
35 | * @var array |
||
36 | * @access protected |
||
37 | */ |
||
38 | protected $controls = []; |
||
39 | |||
40 | /** |
||
41 | * Holds the current images' URLs and MIME types |
||
42 | * |
||
43 | * @var array |
||
44 | * @access protected |
||
45 | */ |
||
46 | protected $images = []; |
||
47 | |||
48 | /** |
||
49 | * Holds the current fulltexts' URLs |
||
50 | * |
||
51 | * @var array |
||
52 | * @access protected |
||
53 | */ |
||
54 | protected $fulltexts = []; |
||
55 | |||
56 | /** |
||
57 | * Holds the current AnnotationLists / AnnotationPages |
||
58 | * |
||
59 | * @var array |
||
60 | * @access protected |
||
61 | */ |
||
62 | protected $annotationContainers = []; |
||
63 | |||
64 | /** |
||
65 | * Adds Viewer javascript |
||
66 | * |
||
67 | * @access protected |
||
68 | * |
||
69 | * @return string The output string for the ###JAVASCRIPT### template marker |
||
70 | */ |
||
71 | protected function addViewerJS() |
||
72 | { |
||
73 | $markerArray = ''; |
||
74 | // CSS files. |
||
75 | $cssFiles = [ |
||
76 | 'Resources/Public/Javascript/OpenLayers/ol3.css' |
||
77 | ]; |
||
78 | // Javascript files. |
||
79 | $jsFiles = [ |
||
80 | // OpenLayers |
||
81 | 'Resources/Public/Javascript/OpenLayers/glif.min.js', |
||
82 | 'Resources/Public/Javascript/OpenLayers/ol3-dlf.js', |
||
83 | // Viewer |
||
84 | 'Resources/Public/Javascript/PageView/Utility.js', |
||
85 | 'Resources/Public/Javascript/PageView/OL3.js', |
||
86 | 'Resources/Public/Javascript/PageView/OL3Styles.js', |
||
87 | 'Resources/Public/Javascript/PageView/OL3Sources.js', |
||
88 | 'Resources/Public/Javascript/PageView/AltoParser.js', |
||
89 | 'Resources/Public/Javascript/PageView/AnnotationParser.js', |
||
90 | 'Resources/Public/Javascript/PageView/AnnotationControl.js', |
||
91 | 'Resources/Public/Javascript/PageView/ImageManipulationControl.js', |
||
92 | 'Resources/Public/Javascript/PageView/FulltextDownloadControl.js', |
||
93 | 'Resources/Public/Javascript/PageView/FulltextControl.js', |
||
94 | 'Resources/Public/Javascript/PageView/FullTextUtility.js', |
||
95 | 'Resources/Public/Javascript/PageView/PageView.js' |
||
96 | ]; |
||
97 | // Viewer configuration. |
||
98 | $viewerConfiguration = ' |
||
99 | $(document).ready(function() { |
||
100 | if (dlfUtils.exists(dlfViewer)) { |
||
101 | tx_dlf_viewer = new dlfViewer({ |
||
102 | controls: ["' . implode('", "', $this->controls) . '"], |
||
103 | div: "' . $this->conf['elementId'] . '", |
||
104 | images: ' . json_encode($this->images) . ', |
||
105 | fulltexts: ' . json_encode($this->fulltexts) . ', |
||
106 | annotationContainers: ' . json_encode($this->annotationContainers) . ', |
||
107 | useInternalProxy: ' . ($this->conf['useInternalProxy'] ? 1 : 0) . ' |
||
108 | }); |
||
109 | } |
||
110 | }); |
||
111 | '; |
||
112 | // Add Javascript to page footer if not configured otherwise. |
||
113 | if (empty($this->conf['addJStoBody'])) { |
||
114 | $pageRenderer = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Page\PageRenderer::class); |
||
115 | foreach ($cssFiles as $cssFile) { |
||
116 | $pageRenderer->addCssFile(\TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($this->extKey)) . $cssFile); |
||
117 | } |
||
118 | foreach ($jsFiles as $jsFile) { |
||
119 | $pageRenderer->addJsFooterFile(\TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($this->extKey)) . $jsFile); |
||
120 | } |
||
121 | $pageRenderer->addJsFooterInlineCode('kitodo-pageview-configuration', $viewerConfiguration); |
||
122 | } else { |
||
123 | foreach ($jsFiles as $jsFile) { |
||
124 | $markerArray .= '<script type="text/javascript" src="' . \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($this->extKey)) . $jsFile . '"></script>' . "\n"; |
||
125 | } |
||
126 | $markerArray .= ' |
||
127 | <script type="text/javascript"> |
||
128 | /*<![CDATA[*/ |
||
129 | /*kitodo-pageview-configuration*/ |
||
130 | ' . $viewerConfiguration . ' |
||
131 | /*]]>*/ |
||
132 | </script>'; |
||
133 | } |
||
134 | return $markerArray; |
||
135 | } |
||
136 | |||
137 | /** |
||
138 | * Adds pageview interaction (crop, magnifier and rotation) |
||
139 | * |
||
140 | * @access protected |
||
141 | * |
||
142 | * @return array Marker array |
||
143 | */ |
||
144 | protected function addInteraction() |
||
145 | { |
||
146 | $markerArray = []; |
||
147 | if ($this->piVars['id']) { |
||
148 | if ($this->conf['crop']) { |
||
149 | $markerArray['###EDITBUTTON###'] = '<a href="javascript: tx_dlf_viewer.activateSelection();" title="' . htmlspecialchars($this->pi_getLL('editMode', '')) . '">' . htmlspecialchars($this->pi_getLL('editMode', '')) . '</a>'; |
||
150 | $markerArray['###EDITREMOVE###'] = '<a href="javascript: tx_dlf_viewer.resetCropSelection();" title="' . htmlspecialchars($this->pi_getLL('editRemove', '')) . '">' . htmlspecialchars($this->pi_getLL('editRemove', '')) . '</a>'; |
||
151 | } else { |
||
152 | $markerArray['###EDITBUTTON###'] = ''; |
||
153 | $markerArray['###EDITREMOVE###'] = ''; |
||
154 | } |
||
155 | if ($this->conf['magnifier']) { |
||
156 | $markerArray['###MAGNIFIER###'] = '<a href="javascript: tx_dlf_viewer.activateMagnifier();" title="' . htmlspecialchars($this->pi_getLL('magnifier', '')) . '">' . htmlspecialchars($this->pi_getLL('magnifier', '')) . '</a>'; |
||
157 | } else { |
||
158 | $markerArray['###MAGNIFIER###'] = ''; |
||
159 | } |
||
160 | } |
||
161 | return $markerArray; |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Adds form to save cropping data to basket |
||
166 | * |
||
167 | * @access protected |
||
168 | * |
||
169 | * @return array Marker array |
||
170 | */ |
||
171 | protected function addBasketForm() |
||
172 | { |
||
173 | $markerArray = []; |
||
174 | // Add basket button |
||
175 | if ($this->conf['basketButton'] && $this->conf['targetBasket'] && $this->piVars['id']) { |
||
176 | $label = htmlspecialchars($this->pi_getLL('addBasket', '')); |
||
177 | $params = [ |
||
178 | 'id' => $this->piVars['id'], |
||
179 | 'addToBasket' => true |
||
180 | ]; |
||
181 | if (empty($this->piVars['page'])) { |
||
182 | $params['page'] = 1; |
||
183 | } |
||
184 | $basketConf = [ |
||
185 | 'parameter' => $this->conf['targetBasket'], |
||
186 | 'forceAbsoluteUrl' => !empty($this->conf['forceAbsoluteUrl']) ? 1 : 0, |
||
187 | 'forceAbsoluteUrl.' => ['scheme' => !empty($this->conf['forceAbsoluteUrl']) && !empty($this->conf['forceAbsoluteUrlHttps']) ? 'https' : 'http'], |
||
188 | 'additionalParams' => \TYPO3\CMS\Core\Utility\GeneralUtility::implodeArrayForUrl($this->prefixId, $params, '', true, false), |
||
189 | 'title' => $label |
||
190 | ]; |
||
191 | $output = '<form id="addToBasketForm" action="' . $this->cObj->typoLink_URL($basketConf) . '" method="post">'; |
||
192 | $output .= '<input type="hidden" name="tx_dlf[startpage]" id="startpage" value="' . htmlspecialchars($this->piVars['page']) . '">'; |
||
193 | $output .= '<input type="hidden" name="tx_dlf[endpage]" id="endpage" value="' . htmlspecialchars($this->piVars['page']) . '">'; |
||
194 | $output .= '<input type="hidden" name="tx_dlf[startX]" id="startX">'; |
||
195 | $output .= '<input type="hidden" name="tx_dlf[startY]" id="startY">'; |
||
196 | $output .= '<input type="hidden" name="tx_dlf[endX]" id="endX">'; |
||
197 | $output .= '<input type="hidden" name="tx_dlf[endY]" id="endY">'; |
||
198 | $output .= '<input type="hidden" name="tx_dlf[rotation]" id="rotation">'; |
||
199 | $output .= '<button id="submitBasketForm" onclick="this.form.submit()">' . $label . '</button>'; |
||
200 | $output .= '</form>'; |
||
201 | $output .= '<script>'; |
||
202 | $output .= '$(document).ready(function() { $("#submitBasketForm").click(function() { $("#addToBasketForm").submit(); }); });'; |
||
203 | $output .= '</script>'; |
||
204 | $markerArray['###BASKETBUTTON###'] = $output; |
||
205 | } else { |
||
206 | $markerArray['###BASKETBUTTON###'] = ''; |
||
207 | } |
||
208 | return $markerArray; |
||
209 | } |
||
210 | |||
211 | /** |
||
212 | * Get image's URL and MIME type |
||
213 | * |
||
214 | * @access protected |
||
215 | * |
||
216 | * @param int $page: Page number |
||
217 | * |
||
218 | * @return array URL and MIME type of image file |
||
219 | */ |
||
220 | protected function getImage($page) |
||
221 | { |
||
222 | $image = []; |
||
223 | // Get @USE value of METS fileGrp. |
||
224 | $fileGrps = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->conf['fileGrps']); |
||
225 | while ($fileGrp = @array_pop($fileGrps)) { |
||
226 | // Get image link. |
||
227 | if (!empty($this->doc->physicalStructureInfo[$this->doc->physicalStructure[$page]]['files'][$fileGrp])) { |
||
228 | $image['url'] = $this->doc->getFileLocation($this->doc->physicalStructureInfo[$this->doc->physicalStructure[$page]]['files'][$fileGrp]); |
||
229 | if ($this->conf['useInternalProxy']) { |
||
230 | // Configure @action URL for form. |
||
231 | $linkConf = [ |
||
232 | 'parameter' => $GLOBALS['TSFE']->id, |
||
233 | 'forceAbsoluteUrl' => !empty($this->conf['forceAbsoluteUrl']) ? 1 : 0, |
||
234 | 'forceAbsoluteUrl.' => ['scheme' => !empty($this->conf['forceAbsoluteUrl']) && !empty($this->conf['forceAbsoluteUrlHttps']) ? 'https' : 'http'], |
||
235 | 'additionalParams' => '&eID=tx_dlf_pageview_proxy&url=' . urlencode($image['url']), |
||
236 | ]; |
||
237 | $image['url'] = $this->cObj->typoLink_URL($linkConf); |
||
238 | } |
||
239 | $image['mimetype'] = $this->doc->getFileMimeType($this->doc->physicalStructureInfo[$this->doc->physicalStructure[$page]]['files'][$fileGrp]); |
||
240 | break; |
||
241 | } else { |
||
242 | Helper::devLog('File not found in fileGrp "' . $fileGrp . '"', DEVLOG_SEVERITY_WARNING); |
||
243 | } |
||
244 | } |
||
245 | return $image; |
||
246 | } |
||
247 | |||
248 | /** |
||
249 | * Get fulltext URL and MIME type |
||
250 | * |
||
251 | * @access protected |
||
252 | * |
||
253 | * @param int $page: Page number |
||
254 | * |
||
255 | * @return array URL and MIME type of fulltext file |
||
256 | */ |
||
257 | protected function getFulltext($page) |
||
258 | { |
||
259 | $fulltext = []; |
||
260 | // Get fulltext link. |
||
261 | if (!empty($this->doc->physicalStructureInfo[$this->doc->physicalStructure[$page]]['files'][$this->conf['fileGrpFulltext']])) { |
||
262 | $fulltext['url'] = $this->doc->getFileLocation($this->doc->physicalStructureInfo[$this->doc->physicalStructure[$page]]['files'][$this->conf['fileGrpFulltext']]); |
||
263 | if ($this->conf['useInternalProxy']) { |
||
264 | // Configure @action URL for form. |
||
265 | $linkConf = [ |
||
266 | 'parameter' => $GLOBALS['TSFE']->id, |
||
267 | 'forceAbsoluteUrl' => !empty($this->conf['forceAbsoluteUrl']) ? 1 : 0, |
||
268 | 'forceAbsoluteUrl.' => ['scheme' => !empty($this->conf['forceAbsoluteUrl']) && !empty($this->conf['forceAbsoluteUrlHttps']) ? 'https' : 'http'], |
||
269 | 'additionalParams' => '&eID=tx_dlf_pageview_proxy&url=' . urlencode($fulltext['url']), |
||
270 | ]; |
||
271 | $fulltext['url'] = $this->cObj->typoLink_URL($linkConf); |
||
272 | } |
||
273 | $fulltext['mimetype'] = $this->doc->getFileMimeType($this->doc->physicalStructureInfo[$this->doc->physicalStructure[$page]]['files'][$this->conf['fileGrpFulltext']]); |
||
274 | } else { |
||
275 | Helper::devLog('File not found in fileGrp "' . $this->conf['fileGrpFulltext'] . '"', DEVLOG_SEVERITY_WARNING); |
||
276 | } |
||
277 | return $fulltext; |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Get all AnnotationPages / AnnotationLists that contain text Annotations with motivation "painting" |
||
282 | * |
||
283 | * @access protected |
||
284 | * |
||
285 | * @param int $page: Page number |
||
286 | * @return array An array containing the IRIs of the AnnotationLists / AnnotationPages as well as |
||
287 | * some information about the canvas. |
||
288 | */ |
||
289 | protected function getAnnotationContainers($page) |
||
290 | { |
||
291 | if ($this->doc instanceof IiifManifest) { |
||
292 | $canvasId = $this->doc->physicalStructure[$page]; |
||
293 | $iiif = $this->doc->getIiif(); |
||
294 | if ($iiif instanceof ManifestInterface) { |
||
295 | $canvas = $iiif->getContainedResourceById($canvasId); |
||
296 | /* @var $canvas \Ubl\Iiif\Presentation\Common\Model\Resources\CanvasInterface */ |
||
297 | if ($canvas != null && !empty($canvas->getPossibleTextAnnotationContainers(Motivation::PAINTING))) { |
||
298 | $annotationContainers = []; |
||
299 | /* |
||
300 | * TODO Analyzing the annotations on the server side requires loading the annotation lists / pages |
||
301 | * just to determine wether they contain text annotations for painting. This will take time and lead to a bad user experience. |
||
302 | * It would be better to link every annotation and analyze the data on the client side. |
||
303 | * |
||
304 | * On the other hand, server connections are potentially better than client connections. Downloading annotation lists |
||
305 | */ |
||
306 | foreach ($canvas->getPossibleTextAnnotationContainers(Motivation::PAINTING) as $annotationContainer) { |
||
307 | if (($textAnnotations = $annotationContainer->getTextAnnotations(Motivation::PAINTING)) != null) { |
||
308 | foreach ($textAnnotations as $annotation) { |
||
309 | if ( |
||
310 | $annotation->getBody()->getFormat() == 'text/plain' |
||
311 | && $annotation->getBody()->getChars() != null |
||
312 | ) { |
||
313 | $annotationListData = []; |
||
314 | $annotationListData['uri'] = $annotationContainer->getId(); |
||
315 | $annotationListData['label'] = $annotationContainer->getLabelForDisplay(); |
||
316 | $annotationContainers[] = $annotationListData; |
||
317 | break; |
||
318 | } |
||
319 | } |
||
320 | } |
||
321 | } |
||
322 | $result = [ |
||
323 | 'canvas' => [ |
||
324 | 'id' => $canvas->getId(), |
||
325 | 'width' => $canvas->getWidth(), |
||
326 | 'height' => $canvas->getHeight(), |
||
327 | ], |
||
328 | 'annotationContainers' => $annotationContainers |
||
329 | ]; |
||
330 | return $result; |
||
331 | } |
||
332 | } |
||
333 | } |
||
334 | return []; |
||
335 | } |
||
336 | |||
337 | /** |
||
338 | * The main method of the PlugIn |
||
339 | * |
||
340 | * @access public |
||
341 | * |
||
342 | * @param string $content: The PlugIn content |
||
343 | * @param array $conf: The PlugIn configuration |
||
344 | * |
||
345 | * @return string The content that is displayed on the website |
||
346 | */ |
||
347 | public function main($content, $conf) |
||
348 | { |
||
349 | $this->init($conf); |
||
350 | // Load current document. |
||
351 | $this->loadDocument(); |
||
352 | if ( |
||
353 | $this->doc === null |
||
354 | || $this->doc->numPages < 1 |
||
355 | ) { |
||
356 | // Quit without doing anything if required variables are not set. |
||
357 | return $content; |
||
358 | } else { |
||
359 | if (!empty($this->piVars['logicalPage'])) { |
||
360 | $this->piVars['page'] = $this->doc->getPhysicalPage($this->piVars['logicalPage']); |
||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
Loading history...
|
|||
361 | // The logical page parameter should not appear again |
||
362 | unset($this->piVars['logicalPage']); |
||
363 | } |
||
364 | // Set default values if not set. |
||
365 | // $this->piVars['page'] may be integer or string (physical structure @ID) |
||
366 | if ((int) $this->piVars['page'] > 0 || empty($this->piVars['page'])) { |
||
367 | $this->piVars['page'] = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange((int) $this->piVars['page'], 1, $this->doc->numPages, 1); |
||
368 | } else { |
||
369 | $this->piVars['page'] = array_search($this->piVars['page'], $this->doc->physicalStructure); |
||
370 | } |
||
371 | $this->piVars['double'] = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->piVars['double'], 0, 1, 0); |
||
372 | } |
||
373 | // Load template file. |
||
374 | $this->getTemplate(); |
||
375 | // Get image data. |
||
376 | $this->images[0] = $this->getImage($this->piVars['page']); |
||
377 | $this->fulltexts[0] = $this->getFulltext($this->piVars['page']); |
||
378 | $this->annotationContainers[0] = $this->getAnnotationContainers($this->piVars['page']); |
||
379 | if ($this->piVars['double'] && $this->piVars['page'] < $this->doc->numPages) { |
||
380 | $this->images[1] = $this->getImage($this->piVars['page'] + 1); |
||
381 | $this->fulltexts[1] = $this->getFulltext($this->piVars['page'] + 1); |
||
382 | $this->annotationContainers[1] = $this->getAnnotationContainers($this->piVars['page'] + 1); |
||
383 | } |
||
384 | // Get the controls for the map. |
||
385 | $this->controls = explode(',', $this->conf['features']); |
||
386 | // Fill in the template markers. |
||
387 | $markerArray = array_merge($this->addInteraction(), $this->addBasketForm()); |
||
388 | $markerArray['###JAVASCRIPT###'] = $this->addViewerJS(); |
||
389 | $content .= $this->templateService->substituteMarkerArray($this->template, $markerArray); |
||
390 | return $this->pi_wrapInBaseClass($content); |
||
391 | } |
||
392 | } |
||
393 |