[BUGFIX] Quickedit mode: RTE has no user CSS
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / Classes / Extension / MicroDataSchema.php
1 <?php
2 namespace TYPO3\CMS\Rtehtmlarea\Extension;
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 TYPO3\CMS\Core\Utility\GeneralUtility;
18
19 /**
20 * Microdata Schema extension for htmlArea RTE
21 *
22 * @author Stanislas Rolland <typo3(arobas)sjbr.ca>
23 */
24 class MicroDataSchema extends \TYPO3\CMS\Rtehtmlarea\RteHtmlAreaApi {
25
26 // The key of the TYPO3 extension that is extending htmlArea RTE
27 protected $extensionKey = 'rtehtmlarea';
28
29 // The name of the plugin registered by the extension
30 protected $pluginName = 'MicrodataSchema';
31
32 // Path to this main locallang file of the extension relative to the extension dir.
33 protected $relativePathToLocallangFile = 'extensions/MicrodataSchema/locallang.xlf';
34
35 // Path to the skin (css) file relative to the extension dir
36 protected $relativePathToSkin = 'extensions/MicrodataSchema/skin/htmlarea.css';
37
38 protected $htmlAreaRTE;
39
40 // Reference to the invoking object
41 protected $thisConfig;
42
43 // Reference to RTE PageTSConfig
44 protected $toolbar;
45
46 // Reference to RTE toolbar array
47 protected $LOCAL_LANG;
48
49 // Frontend language array
50 protected $pluginButtons = 'showmicrodata';
51
52 protected $convertToolbarForHtmlAreaArray = array(
53 'showmicrodata' => 'ShowMicrodata'
54 );
55
56 /**
57 * Return JS configuration of the htmlArea plugins registered by the extension
58 *
59 * @param int Relative id of the RTE editing area in the form
60 * @return string JS configuration for registered plugins
61 */
62 public function buildJavascriptConfiguration($RTEcounter) {
63 $registerRTEinJavascriptString = '';
64 $schema = array(
65 'types' => array(),
66 'properties' => array()
67 );
68 // Parse configured schemas
69 if (is_array($this->thisConfig['schema.']) && is_array($this->thisConfig['schema.']['sources.'])) {
70 foreach ($this->thisConfig['schema.']['sources.'] as $source) {
71 $fileName = trim($source);
72 $absolutePath = GeneralUtility::getFileAbsFileName($fileName);
73 // Fallback to default schema file if configured file does not exists or is of zero size
74 if (!$fileName || !file_exists($absolutePath) || !filesize($absolutePath)) {
75 $fileName = 'EXT:' . $this->ID . '/extensions/MicrodataSchema/res/schemaOrgAll.rdf';
76 }
77 $fileName = $this->htmlAreaRTE->getFullFileName($fileName);
78 $rdf = GeneralUtility::getUrl($fileName);
79 if ($rdf) {
80 $this->parseSchema($rdf, $schema);
81 }
82 }
83 }
84 uasort($schema['types'], array($this, 'compareLabels'));
85 uasort($schema['properties'], array($this, 'compareLabels'));
86 // Insert no type and no property entries
87 if ($this->htmlAreaRTE->is_FE()) {
88 $noSchema = $GLOBALS['TSFE']->getLLL('No type', $this->LOCAL_LANG);
89 $noProperty = $GLOBALS['TSFE']->getLLL('No property', $this->LOCAL_LANG);
90 } else {
91 $noSchema = $GLOBALS['LANG']->getLL('No type');
92 $noProperty = $GLOBALS['LANG']->getLL('No property');
93 }
94 array_unshift($schema['types'], array('name' => 'none', 'label' => $noSchema));
95 array_unshift($schema['properties'], array('name' => 'none', 'label' => $noProperty));
96 // Convert character set
97 if ($this->htmlAreaRTE->is_FE()) {
98 $GLOBALS['TSFE']->csConvObj->convArray($schema, $this->htmlAreaRTE->outputCharset, 'utf-8');
99 }
100 // Store json encoded array in temporary file
101 $registerRTEinJavascriptString = LF . TAB . 'RTEarea[editornumber].schemaUrl = "' . ($this->htmlAreaRTE->is_FE() && $GLOBALS['TSFE']->absRefPrefix ? $GLOBALS['TSFE']->absRefPrefix : '') . $this->htmlAreaRTE->writeTemporaryFile('', ('schema_' . $this->htmlAreaRTE->language), 'js', json_encode($schema), TRUE) . '";';
102 return $registerRTEinJavascriptString;
103 }
104
105 /**
106 * Compare the labels of two schema types or properties for localized sort purposes
107 *
108 * @param array $a: first type/property definition array
109 * @param array $b: second type/property definition array
110 * @return int
111 */
112 protected function compareLabels($a, $b) {
113 return strcoll($a['label'], $b['label']);
114 }
115
116 /**
117 * Convert the xml rdf schema into an array
118 *
119 * @param string $string XML rdf schema to convert into an array
120 * @param array $schema: reference to the array to be filled
121 * @return void
122 */
123 protected function parseSchema($string, &$schema) {
124 $resources = array();
125 $types = array();
126 $properties = array();
127 // Load the document
128 $document = new \DOMDocument();
129 $document->loadXML($string);
130 if ($document) {
131 // Scan resource descriptions
132 $items = $document->getElementsByTagName('Description');
133 $itemsCount = $items->length;
134 foreach ($items as $item) {
135 $name = $item->getAttribute('rdf:about');
136 $type = $item->getElementsByTagName('type');
137 if ($name && $type->length) {
138 $type = $type->item(0)->getAttribute('rdf:resource');
139 $resource = array();
140 $resource['name'] = $name;
141 $labels = $item->getElementsByTagName('label');
142 if ($labels->length) {
143 foreach ($labels as $label) {
144 $language = $label->getAttribute('xml:lang');
145 if ($language === $this->language) {
146 $resource['label'] = $label->nodeValue;
147 } elseif ($language === 'en') {
148 $defaultLabel = $label->nodeValue;
149 }
150 }
151 if (!$resource['label']) {
152 $resource['label'] = $defaultLabel;
153 }
154 }
155 $comments = $item->getElementsByTagName('comment');
156 if ($comments->length) {
157 foreach ($comments as $comment) {
158 $language = $comment->getAttribute('xml:lang');
159 if ($language === $this->language) {
160 $resource['comment'] = $comment->nodeValue;
161 } elseif ($language === 'en') {
162 $defaultComment = $comment->nodeValue;
163 }
164 }
165 if (!$resource['comment']) {
166 $resource['comment'] = $defaultComment;
167 }
168 }
169 switch ($type) {
170 case 'http://www.w3.org/2000/01/rdf-schema#Class':
171 $subClassOfs = $item->getElementsByTagName('subClassOf');
172 if ($subClassOfs->length) {
173 foreach ($subClassOfs as $subClassOf) {
174 $resource['subClassOf'] = $subClassOf->getAttribute('rdf:resource');
175 }
176 }
177 // schema.rdfs.org/all.rdf may contain duplicates!!
178 if (!in_array($resource['name'], $types)) {
179 $schema['types'][] = $resource;
180 $types[] = $resource['name'];
181 }
182 break;
183 case 'http://www.w3.org/1999/02/22-rdf-syntax-ns#Property':
184 // Keep only the last level of the name
185 // This is the value we want in the itemprop attribute
186 $pos = strrpos($resource['name'], '/');
187 if ($pos) {
188 $resource['name'] = substr($resource['name'], $pos + 1);
189 }
190 $domains = $item->getElementsByTagName('domain');
191 if ($domains->length) {
192 foreach ($domains as $domain) {
193 $resource['domain'] = $domain->getAttribute('rdf:resource');
194 }
195 }
196 $ranges = $item->getElementsByTagName('range');
197 if ($ranges->length) {
198 foreach ($ranges as $range) {
199 $resource['range'] = $range->getAttribute('rdf:resource');
200 }
201 }
202 // schema.rdfs.org/all.rdf may contain duplicates!!
203 if (!in_array($resource['name'], $properties)) {
204 $schema['properties'][] = $resource;
205 $properties[] = $resource['name'];
206 }
207 break;
208 default:
209 // Do nothing
210 }
211 }
212 }
213 }
214 }
215
216 }