Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

render.js

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 9.30 KiB


001  var MSXML = (typeof DOMParser === 'undefined' || typeof XSLTProcessor === 'undefined');
002  var xslt = {
003      /**
004      * @param {string} xsl
005      */
006      init: function(xsl)
007      {
008          var stylesheet = xslt.loadXML(xsl);
009          if (MSXML)
010          {
011              var generator = new ActiveXObject('MSXML2.XSLTemplate.6.0');
012              generator['stylesheet'] = stylesheet;
013              xslt.proc = generator['createProcessor']();
014          }
015          else
016          {
017              xslt.proc = new XSLTProcessor;
018              xslt.proc['importStylesheet'](stylesheet);
019          }
020      },
021   
022      /**
023      * @param  {string} xml
024      * @return {!Document}
025      */
026      loadXML: function(xml)
027      {
028          var dom;
029          if (MSXML)
030          {
031              dom = new ActiveXObject('MSXML2.FreeThreadedDOMDocument.6.0');
032              dom['async'] = false;
033              dom['validateOnParse'] = false;
034              dom['loadXML'](xml);
035          }
036          else
037          {
038              dom = (new DOMParser).parseFromString(xml, 'text/xml');
039          }
040   
041          if (!dom)
042          {
043              throw 'Cannot parse ' + xml;
044          }
045   
046          return dom;
047      },
048   
049      /**
050      * @param {string} paramName  Parameter name
051      * @param {string} paramValue Parameter's value
052      */
053      setParameter: function(paramName, paramValue)
054      {
055          if (MSXML)
056          {
057              xslt.proc['addParameter'](paramName, paramValue, '');
058          }
059          else
060          {
061              xslt.proc['setParameter'](null, paramName, paramValue);
062          }
063      },
064   
065      /**
066      * @param  {string}    xml
067      * @param  {!Document} targetDoc
068      * @return {!DocumentFragment}
069      */
070      transformToFragment: function(xml, targetDoc)
071      {
072          if (MSXML)
073          {
074              var div = targetDoc.createElement('div'),
075                  fragment = targetDoc.createDocumentFragment();
076   
077              xslt.proc['input'] = xslt.loadXML(xml);
078              xslt.proc['transform']();
079              div.innerHTML = xslt.proc['output'];
080              while (div.firstChild)
081              {
082                  fragment.appendChild(div.firstChild);
083              }
084   
085              return fragment;
086          }
087   
088          return xslt.proc['transformToFragment'](xslt.loadXML(xml), targetDoc);
089      }
090  };
091  xslt.init(xsl);
092   
093  /**
094  * Parse a given text and render it into given HTML element
095  *
096  * @param  {string} text
097  * @param  {!HTMLElement} target
098  * @return {!Node}
099  */
100  function preview(text, target)
101  {
102      var targetDoc = target.ownerDocument;
103      if (!targetDoc)
104      {
105          throw 'Target does not have a ownerDocument';
106      }
107   
108      var resultFragment = xslt.transformToFragment(parse(text).replace(/<[eis]>[^<]*<\/[eis]>/g, ''), targetDoc),
109          lastUpdated    = target;
110   
111      // https://bugs.chromium.org/p/chromium/issues/detail?id=266305
112      if (typeof window !== 'undefined' && 'chrome' in window)
113      {
114          resultFragment.querySelectorAll('script').forEach(
115              function (oldScript)
116              {
117                  let newScript = document.createElement('script');
118                  for (let attribute of oldScript['attributes'])
119                  {
120                      newScript['setAttribute'](attribute.name, attribute.value);
121                  }
122                  newScript.textContent = oldScript.textContent;
123   
124                  oldScript.parentNode.replaceChild(newScript, oldScript);
125              }
126          );
127      }
128   
129      // Compute and refresh hashes
130      if (HINT.hash)
131      {
132          computeHashes(resultFragment);
133      }
134   
135      // Apply post-processing
136      if (HINT.onRender)
137      {
138          executeEvents(resultFragment, 'render');
139      }
140   
141      /**
142      * Compute and set all hashes in given document fragment
143      *
144      * @param {!DocumentFragment} fragment
145      */
146      function computeHashes(fragment)
147      {
148          var nodes = fragment.querySelectorAll('[data-s9e-livepreview-hash]'),
149              i     = nodes.length;
150          while (--i >= 0)
151          {
152              nodes[i]['setAttribute']('data-s9e-livepreview-hash', hash(nodes[i].outerHTML));
153          }
154      }
155   
156      /**
157      * Execute an event's code on a given node
158      *
159      * @param {!Element} node
160      * @param {string}   eventName
161      */
162      function executeEvent(node, eventName)
163      {
164          /** @type {string} */
165          var code = node.getAttribute('data-s9e-livepreview-on' + eventName);
166          if (!functionCache[code])
167          {
168              functionCache[code] = new Function(code);
169          }
170   
171          functionCache[code]['call'](node);
172      }
173   
174      /**
175      * Locate and execute an event on given document fragment or element
176      *
177      * @param {!DocumentFragment|!Element} root
178      * @param {string}                     eventName
179      */
180      function executeEvents(root, eventName)
181      {
182          // Execute the event on the root node, as there is no self-or-descendant selector in CSS
183          if (root instanceof Element && root['hasAttribute']('data-s9e-livepreview-on' + eventName))
184          {
185              executeEvent(root, eventName);
186          }
187   
188          var nodes = root.querySelectorAll('[data-s9e-livepreview-on' + eventName + ']'),
189              i     = nodes.length;
190          while (--i >= 0)
191          {
192              executeEvent(nodes[i], eventName);
193          }
194      }
195   
196      /**
197      * Update the content of given node oldParent to match node newParent
198      *
199      * @param {!Node} oldParent
200      * @param {!Node} newParent
201      */
202      function refreshElementContent(oldParent, newParent)
203      {
204          var oldNodes = oldParent.childNodes,
205              newNodes = newParent.childNodes,
206              oldCnt   = oldNodes.length,
207              newCnt   = newNodes.length,
208              oldNode,
209              newNode,
210              left     = 0,
211              right    = 0;
212   
213          // Skip the leftmost matching nodes
214          while (left < oldCnt && left < newCnt)
215          {
216              oldNode = oldNodes[left];
217              newNode = newNodes[left];
218              if (!refreshNode(oldNode, newNode))
219              {
220                  break;
221              }
222   
223              ++left;
224          }
225   
226          // Skip the rightmost matching nodes
227          var maxRight = Math.min(oldCnt - left, newCnt - left);
228          while (right < maxRight)
229          {
230              oldNode = oldNodes[oldCnt - (right + 1)];
231              newNode = newNodes[newCnt - (right + 1)];
232              if (!refreshNode(oldNode, newNode))
233              {
234                  break;
235              }
236   
237              ++right;
238          }
239   
240          // Remove the old dirty nodes in the middle of the tree
241          var i = oldCnt - right;
242          while (--i >= left)
243          {
244              oldParent.removeChild(oldNodes[i]);
245              lastUpdated = oldParent;
246          }
247   
248          // Test whether there are any nodes in the new tree between the matching nodes at the left
249          // and the matching nodes at the right
250          var rightBoundary = newCnt - right;
251          if (left >= rightBoundary)
252          {
253              return;
254          }
255   
256          // Clone the new nodes
257          var newNodesFragment = targetDoc.createDocumentFragment();
258          i = left;
259          do
260          {
261              newNode = newNodes[i];
262              if (HINT.onUpdate && newNode instanceof Element)
263              {
264                  executeEvents(newNode, 'update');
265              }
266              lastUpdated = newNodesFragment.appendChild(newNode);
267          }
268          while (i < --rightBoundary);
269   
270          // If we haven't skipped any nodes to the right, we can just append the fragment
271          if (!right)
272          {
273              oldParent.appendChild(newNodesFragment);
274          }
275          else
276          {
277              oldParent.insertBefore(newNodesFragment, oldParent.childNodes[left]);
278          }
279      }
280   
281      /**
282      * Update given node oldNode to make it match newNode
283      *
284      * @param {!Node} oldNode
285      * @param {!Node} newNode
286      * @return {boolean} Whether the node can be skipped
287      */
288      function refreshNode(oldNode, newNode)
289      {
290          if (oldNode.nodeName !== newNode.nodeName || oldNode.nodeType !== newNode.nodeType)
291          {
292              return false;
293          }
294   
295          if (oldNode instanceof HTMLElement && newNode instanceof HTMLElement)
296          {
297              if (!oldNode.isEqualNode(newNode) && !elementHashesMatch(oldNode, newNode))
298              {
299                  if (HINT.onUpdate && newNode['hasAttribute']('data-s9e-livepreview-onupdate'))
300                  {
301                      executeEvent(newNode, 'update');
302                  }
303                  syncElementAttributes(oldNode, newNode);
304                  refreshElementContent(oldNode, newNode);
305              }
306          }
307          // Node.TEXT_NODE || Node.COMMENT_NODE
308          else if (oldNode.nodeType === 3 || oldNode.nodeType === 8)
309          {
310              if (oldNode.nodeValue !== newNode.nodeValue)
311              {
312                  oldNode.nodeValue = newNode.nodeValue;
313                  lastUpdated = oldNode;
314              }
315          }
316   
317          return true;
318      }
319   
320      /**
321      * Test whether both given elements have a hash value and both match
322      *
323      * @param  {!HTMLElement} oldEl
324      * @param  {!HTMLElement} newEl
325      * @return {boolean}
326      */
327      function elementHashesMatch(oldEl, newEl)
328      {
329          if (!HINT.hash)
330          {
331              // Hashes can never match if there are no hashes in any template
332              return false;
333          }
334          const attrName = 'data-s9e-livepreview-hash';
335   
336          return oldEl['hasAttribute'](attrName) && newEl['hasAttribute'](attrName) && oldEl['getAttribute'](attrName) === newEl['getAttribute'](attrName);
337      }
338   
339      /**
340      * Hash given string
341      *
342      * @param  {string} text
343      * @return {number}
344      */
345      function hash(text)
346      {
347          var pos = text.length, s1 = 0, s2 = 0;
348          while (--pos >= 0)
349          {
350              s1 = (s1 + text.charCodeAt(pos)) % 0xFFFF;
351              s2 = (s1 + s2) % 0xFFFF;
352          }
353   
354          return (s2 << 16) | s1;
355      }
356   
357      /**
358      * Make the set of attributes of given element oldEl match newEl's
359      *
360      * @param {!HTMLElement} oldEl
361      * @param {!HTMLElement} newEl
362      */
363      function syncElementAttributes(oldEl, newEl)
364      {
365          var oldAttributes = oldEl['attributes'],
366              newAttributes = newEl['attributes'],
367              oldCnt        = oldAttributes.length,
368              newCnt        = newAttributes.length,
369              i             = oldCnt,
370              ignoreAttrs   = ' ' + oldEl.getAttribute('data-s9e-livepreview-ignore-attrs') + ' ';
371   
372          while (--i >= 0)
373          {
374              var oldAttr      = oldAttributes[i],
375                  namespaceURI = oldAttr['namespaceURI'],
376                  attrName     = oldAttr['name'];
377   
378              if (HINT.ignoreAttrs && ignoreAttrs.indexOf(' ' + attrName + ' ') > -1)
379              {
380                  continue;
381              }
382              if (!newEl.hasAttributeNS(namespaceURI, attrName))
383              {
384                  oldEl.removeAttributeNS(namespaceURI, attrName);
385                  lastUpdated = oldEl;
386              }
387          }
388   
389          i = newCnt;
390          while (--i >= 0)
391          {
392              var newAttr      = newAttributes[i],
393                  namespaceURI = newAttr['namespaceURI'],
394                  attrName     = newAttr['name'],
395                  attrValue    = newAttr['value'];
396   
397              if (HINT.ignoreAttrs && ignoreAttrs.indexOf(' ' + attrName + ' ') > -1)
398              {
399                  continue;
400              }
401              if (attrValue !== oldEl.getAttributeNS(namespaceURI, attrName))
402              {
403                  oldEl.setAttributeNS(namespaceURI, attrName, attrValue);
404                  lastUpdated = oldEl;
405              }
406          }
407      }
408   
409      refreshElementContent(target, resultFragment);
410   
411      return lastUpdated;
412  }
413   
414  /**
415  * Set the value of a stylesheet parameter
416  *
417  * @param {string} paramName  Parameter name
418  * @param {string} paramValue Parameter's value
419  */
420  function setParameter(paramName, paramValue)
421  {
422      xslt.setParameter(paramName, paramValue);
423  }