summaryrefslogtreecommitdiffstats
path: root/helpcontent2/help3xsl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /helpcontent2/help3xsl
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'helpcontent2/help3xsl')
-rw-r--r--helpcontent2/help3xsl/README.prism.js.txt56
-rw-r--r--helpcontent2/help3xsl/README.txt78
-rw-r--r--helpcontent2/help3xsl/a11y-toggle.js100
-rw-r--r--helpcontent2/help3xsl/brand.xsl81
-rw-r--r--helpcontent2/help3xsl/default.css994
-rw-r--r--helpcontent2/help3xsl/flexsearch.debug.js963
-rw-r--r--helpcontent2/help3xsl/generate_hid2file.xsl58
-rw-r--r--helpcontent2/help3xsl/get_bookmark.xsl132
-rw-r--r--helpcontent2/help3xsl/get_tree.xsl84
-rw-r--r--helpcontent2/help3xsl/help.html46
-rw-r--r--helpcontent2/help3xsl/help.js261
-rw-r--r--helpcontent2/help3xsl/help2.js267
-rw-r--r--helpcontent2/help3xsl/index.html19
-rw-r--r--helpcontent2/help3xsl/index2.html74
-rw-r--r--helpcontent2/help3xsl/normalize.css341
-rw-r--r--helpcontent2/help3xsl/noscript.xsl35
-rw-r--r--helpcontent2/help3xsl/online_transform.xsl1544
-rw-r--r--helpcontent2/help3xsl/paginathing.js243
-rw-r--r--helpcontent2/help3xsl/polyfills.js122
-rw-r--r--helpcontent2/help3xsl/prism.css263
-rw-r--r--helpcontent2/help3xsl/prism.js2304
-rw-r--r--helpcontent2/help3xsl/xap_templ_query.xsl295
22 files changed, 8360 insertions, 0 deletions
diff --git a/helpcontent2/help3xsl/README.prism.js.txt b/helpcontent2/help3xsl/README.prism.js.txt
new file mode 100644
index 000000000..96a42aa13
--- /dev/null
+++ b/helpcontent2/help3xsl/README.prism.js.txt
@@ -0,0 +1,56 @@
+Latest download version
+
+PrismJS 1.28.0
+
+Using prism.js for Basic code highlight
+
+http://prismjs.com
+
+License MIT (see prism.js)
+
+Download page http://prismjs.com/download
+
+Theme: Coy
+
+Languages to download:
+Visual Basic +
+Python +
+SQL +
+defaults Prism pre-sets
+
+Plugins:
+line numbers,
+normalize-whitespace: configure after https://prismjs.com/plugins/normalize-whitespace/
+
+Prism.plugins.NormalizeWhitespace = new NormalizeWhitespace({
+'remove-trailing': true,
+'remove-indent': true,
+'left-trim': true,
+'right-trim': true,
+/*'break-lines': 80,
+'indent': 2,*/
+'remove-initial-line-feed': true,
+/*'tabs-to-spaces': 4,
+'spaces-to-tabs': 4*/
+});
+
+
+Usage:
+
+Add prism.js and prism.css to html page,
+
+Add class 'language-visual-basic' and 'line-numbers' to <code> as in
+
+<xsl:template match="bascode">
+ <div class="bascode" itemscope="true" itemtype="http://schema.org/SoftwareSourceCode" itemprop="codeSampleType" content="snippet">
+ <xsl:attribute name="data-tooltip"><xsl:value-of select="$ui_copyclip"/></xsl:attribute>
+ <pre><code class="language-visual-basic line-numbers"><xsl:apply-templates /></code></pre>
+ </div>
+</xsl:template>
+
+<xsl:template match="pycode">
+ <div class="pycode" itemscope="true" itemtype="http://schema.org/SoftwareSourceCode" itemprop="codeSampleType" content="snippet">
+ <xsl:attribute name="data-tooltip"><xsl:value-of select="$ui_copyclip"/></xsl:attribute>
+ <pre><code class="language-python line-numbers"><xsl:apply-templates /></code></pre>
+ </div>
+</xsl:template>
diff --git a/helpcontent2/help3xsl/README.txt b/helpcontent2/help3xsl/README.txt
new file mode 100644
index 000000000..ea5335a57
--- /dev/null
+++ b/helpcontent2/help3xsl/README.txt
@@ -0,0 +1,78 @@
+Helpcontent displayed in a browser
+==================================
+
+This directory contains files needed to convert the XHP files to html, and
+also the html and css files needed for the actual rendering in the web
+browser.
+
+Building and translation of the XHP files is now integrated into the
+LibreOffice build process based on gbuild. If you want to use it, configure
+LibreOffice with one of the:
+
+ --with-help=html (for the local html files)
+ --with-help=online (for the html files that can be uploaded to a webserver)
+
+Using the online version
+------------------------
+
+When you have configured with --with-help=online, the result of the build is
+in
+
+ instdir/help
+
+You want to upload to your webserver like:
+
+ rsync -avz instdir/help/ username@webserver:/srv/www/htdocs/
+
+Then you also need to setup a link 'latest' on the server, like
+
+ ln -s 6.1 latest
+
+and make sure that symlinks are allowed in the webserver configuration.
+
+File descriptions
+-----------------
+
+index2.html:
+
+This is the starting point for help when F1 is pressed. The control 'target' is passed in
+and then the javascript here does the lookup of the hid2file.js map. If the target is found then that
+HTML file is given to the browser with the module and other parameters added, otherwise it substitutes
+a default, which is the modules main page.
+
+* default.css:
+
+ the cascading style sheet for HTML formatting.
+
+* online_transform.xsl:
+
+ the XSL transform file. Transform XHP files into HTML files.
+
+ This file is a modification of xmlhelp/util/main_transform.xsl, which was designed for xmlhelp XSL processor.
+
+* help.js
+
+ This javascript file:
+
+ 1. modifies href attributes in <a> of #DisplayArea to handle &DbPAR and &System params
+ 2. picks the bookmarks file and displays in #BottomLeft <div> area.
+ 3. Reads URL params.
+
+New ‘Object’ tag
+----------------
+
+The filter online_transform.xsl now support the <object> tag defined for XHP files to allow a generic object in the browser. The <object> tag now maps to the following HTML5 tags:
+Maps to HTML5 <video> tag:
+
+<section id="video">
+ <object id="1232312" type ="video/ogg" data="movies/testvideo.ogv" height="480px" width="640px"/>
+</section>
+
+Maps to HTML5 <audio> tag:
+<section id="audio">
+ <object id="1232312" type ="audio/ogg" data="audio/testaudio.wav" height="" width=""/>
+</section>
+
+Maps to HTML5 <object> tag:
+
+ <object id="1232312" type ="{mimetype}" data="object/testobject.swf" height="" width=""/>
diff --git a/helpcontent2/help3xsl/a11y-toggle.js b/helpcontent2/help3xsl/a11y-toggle.js
new file mode 100644
index 000000000..821a8e027
--- /dev/null
+++ b/helpcontent2/help3xsl/a11y-toggle.js
@@ -0,0 +1,100 @@
+/*
+MIT License
+
+Copyright (c) 2016 Edenspiekermann
+
+*/
+
+(function () {
+ 'use strict';
+
+ var internalId = 0;
+ var togglesMap = {};
+ var targetsMap = {};
+
+ function $ (selector, context) {
+ return Array.prototype.slice.call(
+ (context || document).querySelectorAll(selector)
+ );
+ }
+
+ function getClosestToggle (element) {
+ if (element.closest) {
+ return element.closest('[data-a11y-toggle]');
+ }
+
+ while (element) {
+ if (element.nodeType === 1 && element.hasAttribute('data-a11y-toggle')) {
+ return element;
+ }
+
+ element = element.parentNode;
+ }
+
+ return null;
+ }
+
+ function handleToggle (toggle) {
+ var target = toggle && targetsMap[toggle.getAttribute('aria-controls')];
+
+ if (!target) {
+ return false;
+ }
+
+ var toggles = togglesMap['#' + target.id];
+ var isExpanded = target.getAttribute('aria-hidden') === 'false';
+
+ target.setAttribute('aria-hidden', isExpanded);
+ toggles.forEach(function (toggle) {
+ toggle.setAttribute('aria-expanded', !isExpanded);
+ });
+ }
+
+ var initA11yToggle = function (context) {
+ togglesMap = $('[data-a11y-toggle]', context).reduce(function (acc, toggle) {
+ var selector = '#' + toggle.getAttribute('data-a11y-toggle');
+ acc[selector] = acc[selector] || [];
+ acc[selector].push(toggle);
+ return acc;
+ }, togglesMap);
+
+ var targets = Object.keys(togglesMap);
+ targets.length && $(targets).forEach(function (target) {
+ var toggles = togglesMap['#' + target.id];
+ var isExpanded = target.hasAttribute('data-a11y-toggle-open');
+ var labelledby = [];
+
+ toggles.forEach(function (toggle) {
+ toggle.id || toggle.setAttribute('id', 'a11y-toggle-' + internalId++);
+ toggle.setAttribute('aria-controls', target.id);
+ toggle.setAttribute('aria-expanded', isExpanded);
+ labelledby.push(toggle.id);
+ });
+
+ target.setAttribute('aria-hidden', !isExpanded);
+ target.hasAttribute('aria-labelledby') || target.setAttribute('aria-labelledby', labelledby.join(' '));
+
+ targetsMap[target.id] = target;
+ });
+ };
+
+ document.addEventListener('DOMContentLoaded', function () {
+ initA11yToggle();
+ });
+
+ document.addEventListener('click', function (event) {
+ var toggle = getClosestToggle(event.target);
+ handleToggle(toggle);
+ });
+
+ document.addEventListener('keyup', function (event) {
+ if (event.which === 13 || event.which === 32) {
+ var toggle = getClosestToggle(event.target);
+ if (toggle && toggle.getAttribute('role') === 'button') {
+ handleToggle(toggle);
+ }
+ }
+ });
+
+ window && (window.a11yToggle = initA11yToggle);
+})();
diff --git a/helpcontent2/help3xsl/brand.xsl b/helpcontent2/help3xsl/brand.xsl
new file mode 100644
index 000000000..af9bc0c01
--- /dev/null
+++ b/helpcontent2/help3xsl/brand.xsl
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<!-- Product brand variables used in the help files -->
+<xsl:variable name="brand1" select="'$[officename]'"/>
+<xsl:variable name="brand2" select="'$[officeversion]'"/>
+<xsl:variable name="brand3" select="'%PRODUCTNAME'"/>
+<xsl:variable name="brand4" select="'%PRODUCTVERSION'"/>
+
+<!-- Branding -->
+<xsl:template name="brand" >
+ <xsl:param name="string"/>
+ <xsl:choose>
+ <xsl:when test="contains($string,$brand1)">
+ <xsl:variable name="newstr">
+ <xsl:value-of select="substring-before($string,$brand1)"/>
+ <xsl:value-of select="$productname"/>
+ <xsl:value-of select="substring-after($string,$brand1)"/>
+ </xsl:variable>
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string" select="$newstr"/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:when test="contains($string,$brand2)">
+ <xsl:variable name="newstr">
+ <xsl:value-of select="substring-before($string,$brand2)"/>
+ <xsl:value-of select="$pversion"/>
+ <xsl:value-of select="substring-after($string,$brand2)"/>
+ </xsl:variable>
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string" select="$newstr"/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:when test="contains($string,$brand3)">
+ <xsl:variable name="newstr">
+ <xsl:value-of select="substring-before($string,$brand3)"/>
+ <xsl:value-of select="$productname"/>
+ <xsl:value-of select="substring-after($string,$brand3)"/>
+ </xsl:variable>
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string" select="$newstr"/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:when test="contains($string,$brand4)">
+ <xsl:variable name="newstr">
+ <xsl:value-of select="substring-before($string,$brand4)"/>
+ <xsl:value-of select="$pversion"/>
+ <xsl:value-of select="substring-after($string,$brand4)"/>
+ </xsl:variable>
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string" select="$newstr"/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:value-of select="$string"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/helpcontent2/help3xsl/default.css b/helpcontent2/help3xsl/default.css
new file mode 100644
index 000000000..374050472
--- /dev/null
+++ b/helpcontent2/help3xsl/default.css
@@ -0,0 +1,994 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+/*
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++ LIBREOFFICE HELP IN BROWSER +
++ DEFAULT STYLESHEET +
++ WESTERN LANGUAGES +
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+We use px as the unit for navigation elements and fonts because we do
+not want them to scale with browser-set font size.
+We use rem as the unit for article and footer contents because they
+do not break anything related to layout by scaling.
+
+*/
+:root {
+ --font_mono: Menlo, "Cascadia Mono", "Cascadia Code", Consolas, "DejaVu Sans Mono", monospace;
+ --font_body: Ubuntu, Cantarell, "Segoe UI Variable", "Segoe UI", "Noto Sans", "DejaVu Sans", "Lucida Grande", sans-serif, FreeSerif, NanumGothic, "Noto Sans Tibetan", Taprom;
+}
+
+body,
+p,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.listitem,
+.listitemintable,
+.tablecontent {
+ font-family: var(--font_body);
+}
+.input {
+ background-color: rgba(0,0,0,0.04);
+ transition-property: background-color;
+ transition-duration: 150ms;
+ border-bottom: 1px dashed rgba(0,0,0,0.1);
+ font-family: var(--font_mono);
+}
+[data-tooltip]{
+ position:relative;
+}
+[data-tooltip]::before {
+ content: "";
+ position: absolute;
+ top:-6px;
+ left:50%;
+ transform: translateX(-50%);
+ border-width: 4px 6px 0 6px;
+ border-style: solid;
+ border-color: rgba(0,0,0,0.7) transparent transparent transparent;
+ z-index: 100;
+ opacity: 0;
+ pointer-events: none;
+}
+[data-tooltip]::after {
+ content: attr(data-tooltip);
+ position: absolute;
+ left:50%;
+ top:-6px;
+ transform: translateX(-50%) translateY(-100%);
+ background: rgba(0,0,0,0.7);
+ text-align: center;
+ color: #fff;
+ padding:4px 2px;
+ font-size: 12px;
+ min-width: 80px;
+ border-radius: 5px;
+ opacity: 0;
+ pointer-events: none;
+}
+[data-tooltip]:hover:before, [data-tooltip]:hover:after {
+ opacity: 1;
+ pointer-events: auto;
+}
+body {
+ background-color: #F7F8F7;
+ margin: 0;
+ line-height: normal;
+}
+::selection {
+ background: #FFEB9F;
+}
+a {
+ text-decoration-color: rgba(0,0,0,0.15);
+ color: #0461e0;
+}
+a:hover {
+ text-decoration: underline;
+ color: #023a86;
+}
+a:visited {
+ color: #633363;
+}
+pre,
+.code,
+.codeintable,
+.example,
+.exampleintable,
+.literal,
+.literalintable,
+.path,
+.pathintable {
+ background-color: rgba(0,0,0,0.04);
+ border-radius: 2px;
+ display: inline;
+ padding: 1px 3px;
+ font-family: var(--font_mono);
+ word-wrap: anywhere;
+}
+.smathcode {
+ border-radius: 2px;
+ padding: 1px 3px;
+ font-family: var(--font_mono);
+}
+.acronym {
+ font-weight: bold;
+}
+.related {
+ font-weight: bold;
+ margin-top: 1.67rem;
+ border-top: 1px solid black;
+}
+.emph,
+.menuitem {
+ font-weight: bold;
+}
+.keycode {
+ font-family: var(--font_mono);
+}
+.widget{
+ padding: 1px 10px;
+ background: #f0f0f0;
+ background: linear-gradient(to bottom,#f0f0f0,#fcfcfc);
+ border-radius: 3px;
+ color: #303030;
+ border: 1px solid #a0a0a0;
+ border-bottom-width: 2px;
+ white-space: nowrap;
+}
+/* div's for warning, tip and note */
+.note,
+.tip,
+.warning {
+ display:flex;
+ align-items: center;
+ border-radius: 2px;
+ box-shadow: 0 2px 5px -3px rgb(0 0 0 / 10%);
+ padding: 0.2em;
+ margin-top: 15px;
+}
+.note {
+ border-left: 2px solid #309048;
+ background-color: #d9f1dd;
+}
+.tip {
+ border-left: 2px solid #0063b1;
+ background-color: #cde5f7;
+}
+.warning {
+ border-left: 2px solid #ed8733;
+ background-color: #f6f1d2;
+}
+.noteicon, .notetext {
+ padding:0.3em;
+}
+/* Override some Prism.js styles */
+code[class*="language-"], pre[class*="language-"] {
+ white-space: pre-wrap;
+}
+
+/* Table related classes */
+
+/* Special case of table with one cell*/
+.onecell{
+ box-shadow: rgba(0,0,0,0.1) 0px 1px 3px 0px;
+ border-bottom: 1px solid #E8E8E8;
+}
+/* Special case of icon table*/
+.icontable {
+ display:flex;
+ align-items:center;
+}
+.iconcell {
+ padding:0.3em;
+}
+
+table {
+ background: #FEFEFE;
+ box-shadow: rgba(0,0,0,0.08) 0 1px 5px 0;
+ border-collapse: collapse;
+}
+table, th, td {
+ border-top: 0;
+ border-bottom: 1px solid #E8E8E8;
+ border-left: 0;
+ border-right: 0;
+ padding: 0.3em;
+}
+html[dir=ltr] th {
+ text-align: left;
+}
+.tablehead,
+.tableheadintable {
+ font-weight: bold;
+ margin-top: 0px;
+}
+.tableheadcell {
+ color: white;
+ vertical-align:top;
+}
+
+.table_font_small {
+ font-size: 0.98rem;
+}
+
+/* ScriptForge service tables */
+.sf_table {
+ min-width: 100%;
+}
+.sf_table thead {
+ display: none;
+}
+.sf_table tr, .sf_table td {
+ display: block;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ margin-bottom: 0.67rem;
+ color: #148603;
+}
+p,
+ol,
+td {
+ font-size: 1.15rem;
+ margin: 2px 0 10px 0;
+}
+h1 {
+ font-size: 1.83rem;
+ font-weight: 300;
+ border-bottom: 2px solid #148603;
+ margin-bottom: 1.67rem;
+}
+h1 a {
+ text-decoration: none;
+}
+h2 {
+ font-size: 1.55rem;
+}
+h3 {
+ font-size: 1.33rem;
+}
+h4,
+h5,
+h6 {
+ font-size: 1.17rem;
+}
+.relatedtopics {
+ font-weight: normal;
+}
+.howtoget {
+ background: #EBE7E9;
+ border-left: 2px solid #4E4B55;
+ border-radius: 2px;
+ box-shadow: 0 2px 5px -3px rgb(0 0 0 / 10%);
+ padding: 0.2em;
+ display: flex;
+ flex-direction: column;
+}
+.howtogetheader {
+ background: #FFF;
+ border-radius: 2px;
+ box-shadow: 0 2px 2px -2px rgba(0,0,0,0.2);
+ display: inline-block;
+ font-weight: bold;
+ padding: 0.1em 0.3em;
+}
+.howtogetbody {
+ padding: 0 0.3em;
+}
+.samplefilesection{
+}
+.wide {
+ width: 100%;
+}
+.bug {
+ color: red;
+}
+.debug {
+ border: 1px solid black;
+ padding: 3px;
+ display: none;
+ background-color: #222;
+ color: red;
+ text-align: left;
+}
+.sqlcode,
+.pycode,
+.bascode {
+ border: solid 5px transparent;
+ margin-top: 15px;
+ margin-bottom: 15px;
+}
+
+#DisplayArea {
+ background-color: #FCFCFC;
+ overflow: auto;
+ padding: 10px 10px 40px 10px;
+ grid-area: main;
+}
+
+.mediabutton {
+ background-color: cyan;
+}
+.mediadiv{
+ padding-bottom:5%;
+ height:0;
+ display:inline-block;
+ border:none;
+}
+.screenshot, .genericimage {
+ border: .5px solid rgba(0,0,0,.1);
+ border-radius: 3px;
+ margin-left: auto;
+ margin-right: auto;
+ margin-top: 2em;
+ margin-bottom: 2em;
+ display:block;
+ box-shadow: rgba(0,0,0,0.08) 0 1px 5px 0;
+}
+.iconimage {}
+
+.switch,
+.switchinline {}
+
+.embedded {}
+#TopLeftHeader {
+ grid-area: header;
+ position: sticky;
+ top: 0px;
+ color: #fff;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-start;
+ z-index: 100;
+}
+.dropdowns {
+ /* allow for scrolling */
+ overflow-x: auto;
+ overflow-y: hidden;
+ /* make it smooth on iOS */
+ -webkit-overflow-scrolling: touch;
+ grid-area: dropdowns;
+ display: flex;
+ justify-content: space-between;
+ flex-direction: column;
+}
+.symbol, .logo, .logo:hover, .logo:visited {
+ color: #fff;
+ text-decoration: none;
+}
+.logo p {
+ font-size: 24px;
+}
+.symbol {
+ grid-area: symbol;
+ padding: 8px 8px 8px 20px;
+}
+.symbol div {
+ background-image: url(media/navigation/libo-symbol-white.svg);
+ background-repeat: no-repeat;
+ background-size: contain;
+ width: 52px;
+ height: 60px;
+}
+
+[data-a11y-toggle]:not([aria-controls]) {
+ display: none;
+}
+/* You Tube matters */
+.youtube_placeholder{
+ border: 1px solid #eee;
+ max-width:700px;
+ padding: 10px;
+ background-color: #eee;
+ text-align: center;
+}
+.youtube_button {
+ appearance: none;
+ backface-visibility: hidden;
+ background-color: #27ae60;
+ border-radius: 8px;
+ border-style: none;
+ box-shadow: rgba(39, 174, 96, .15) 0 4px 9px;
+ box-sizing: border-box;
+ color: #fff;
+ cursor: pointer;
+ display: inline-block;
+ font-size: 16px;
+ font-weight: 600;
+ letter-spacing: normal;
+ line-height: 1.5;
+ outline: none;
+ overflow: hidden;
+ padding: 13px 20px;
+ position: relative;
+ text-align: center;
+ text-decoration: none;
+ transform: translate3d(0, 0, 0);
+ transition: all .3s;
+ user-select: none;
+ -webkit-user-select: none;
+ touch-action: manipulation;
+ vertical-align: top;
+ white-space: nowrap;
+}
+.youtube_button:hover {
+ background-color: #1e8449;
+ opacity: 1;
+ transform: translateY(0);
+ transition-duration: .35s;
+ box-shadow: rgba(39, 174, 96, .2) 0 6px 12px;
+}
+.youtube_button:active {
+ transform: translateY(2px);
+ transition-duration: .35s;
+}
+
+#langs-nav:not([aria-hidden='true']), #modules-nav:not([aria-hidden='true']) {
+ z-index: 100;
+ /* line them up horizontally */
+ display: flex;
+ flex-direction: row;
+ /* allow for scrolling */
+ overflow-x: auto;
+ overflow-y: hidden;
+ /* make it smooth on iOS */
+ -webkit-overflow-scrolling: touch;
+}
+#langs-nav a, #modules-nav a {
+ color: #fff;
+ background-color: #233336;
+ display: block;
+ line-height: 1.5;
+ padding: 3px 6px;
+ text-decoration: none;
+ font-size: 24px;
+ flex-shrink: 0;
+ z-index: 100;
+ white-space: nowrap;
+}
+footer {
+ padding: 30px 20px;
+}
+footer p {
+ font-size: 0.98rem;
+}
+.contents-treeview input[type=checkbox], aside input[type=checkbox] {
+ /* from .visuallyhidden class of html5-boilerplate */
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+ white-space: nowrap;
+}
+label[for=accordion-1] {
+ color: #233336;
+ display: block;
+ padding: 10px 0 10px 20px;
+ font-size: 22px;
+ line-height: .6;
+}
+label[for=accordion-1]:after {
+ font-size: 44px;
+ content:"⌄";
+}
+aside input[type=checkbox] ~ .contents-treeview {
+ display: none;
+}
+aside input[type=checkbox]:checked ~ .contents-treeview {
+ color: #333;
+ z-index: 6;
+ display: block;
+ margin: 0 20px 0 20px;
+}
+.index-label {
+ font-size: 22px;
+ color: #233336;
+ padding-left: 20px;
+ margin: 20px 0 0 0;
+}
+#Index, .index {
+ margin-top: 10px;
+}
+.index {
+ padding-left: 15px;
+}
+.index a {
+ font-size: 15px;
+ display: block;
+}
+.index .hidden {
+ display: none;
+}
+#Bookmarks {
+ padding: 0 20px;
+}
+#Bookmarks p {
+ font-size: 22px;
+ font-weight: bold;
+ color: #148603;
+}
+#WRITER::before {
+ content: "Writer";
+ display: block;
+ font-size: 22px;
+ font-weight: bold;
+ color: #0369a3;
+}
+#CALC::before {
+ content: "Calc";
+ display: block;
+ font-size: 22px;
+ font-weight: bold;
+ color: #43c330;
+}
+#IMPRESS::before {
+ content: "Impress";
+ display: block;
+ font-size: 22px;
+ font-weight: bold;
+ color: #a33e03;
+}
+#DRAW::before {
+ content: "Draw";
+ display: block;
+ font-size: 22px;
+ font-weight: bold;
+ color: #c99c00;
+}
+#BASE::before {
+ content: "Base";
+ display: block;
+ font-size: 22px;
+ font-weight: bold;
+ color: #8e03a3;
+}
+#MATH::before {
+ content: "Math";
+ display: block;
+ font-size: 22px;
+ font-weight: bold;
+ color: darkslategray;
+}
+#CHART::before {
+ content: "Chart";
+ display: block;
+ font-size: 22px;
+ font-weight: bold;
+ color: darkcyan;
+}
+#BASIC::before {
+ content: "Basic";
+ display: block;
+ font-size: 22px;
+ font-weight: bold;
+ color: black;
+}
+#SHARED::before {
+ content: "%PRODUCTNAME";
+ display: block;
+ font-size: 22px;
+ font-weight: bold;
+ color: gray;
+}
+.pagination-container {
+ text-align: center;
+ margin-left: -40px; /* The normalizer fails to account for this */
+}
+.pagination li {
+ display: inline-block;
+ padding: 0 5px;
+}
+.pagination a {
+ text-decoration: none;
+}
+li.active {
+ background-color: #023a86;
+}
+li.active a {
+ color: #fff;
+}
+li.disabled a {
+ opacity: 0.4;
+ pointer-events: none;
+}
+#search-bar, input {
+ border: 1px solid #CCC;
+ box-shadow: inset 0 1px 1px rgba(0,0,0,0.1);
+ box-sizing: border-box;
+ line-height: 1.5em;
+ margin-top: 10px;
+ outline: none;
+ padding: 0 .25em;
+ transition: all 0.30s ease-in-out;
+}
+#search-bar:focus, input:focus {
+ border: 1px solid #0EA5FB;
+}
+#search-bar {
+ width: 100%;
+}
+#search-bar::placeholder {
+ font-style: italic;
+}
+.xapian-donation {
+ border-top: 2px solid #148603;
+ background-color: #FCFCFC;
+ box-shadow: 0 2px 8px 0 rgba(0,0,0,.05);
+}
+#DonationFrame {
+ background: #18A303;
+ position: sticky;
+ top: 0px;
+}
+.donation{
+ border: 1px solid #f1c62a;
+ border-radius: 2px;
+ padding: 5px 10px;
+ margin: auto;
+ max-width: 200px;
+ color: #ffffff;
+}
+.donation:hover {
+ background: linear-gradient(90deg, #1c71d8 0%, #30c877 100%);
+}
+.donation a {
+ color: white;
+ text-decoration: none;
+}
+.donation p {
+ font-size:1rem;
+ text-align: center;
+}
+#SearchFrame {
+ background: #18A303;
+ top: 0px;
+ position: sticky;
+ z-index: 100;
+}
+.xapian-omega-search {
+ margin: auto;
+}
+.modules {
+ border-bottom: 2px solid #f3f3f3;
+ background-color: #233336;
+ z-index: 100;
+}
+#modules:after, #langs:after {
+ font-size: 30px;
+ color: #fff;
+ content:"⌄";
+}
+.lang {
+ background-color: #233336;
+}
+#langs, #modules {
+ display: none;
+}
+#modules-nav div {
+ background-repeat: no-repeat;
+ background-size: contain;
+ float: left;
+ display: none;
+}
+
+.office-icon,
+.calc-icon,
+.chart-icon,
+.writer-icon,
+.impress-icon,
+.draw-icon,
+.math-icon,
+.basic-icon,
+.base-icon {
+ width: 21.5px;
+ height: 26px;
+ position: relative;
+ margin-right: 5px;
+}
+.office-icon {
+ background-image: url(media/navigation/libo-symbol-black.svg);
+}
+.calc-icon {
+ background-image: url(media/navigation/libo-calc.svg);
+}
+.writer-icon {
+ background-image: url(media/navigation/libo-writer.svg);
+}
+.impress-icon {
+ background-image: url(media/navigation/libo-impress.svg);
+}
+.draw-icon {
+ background-image: url(media/navigation/libo-draw.svg);
+}
+.math-icon {
+ background-image: url(media/navigation/libo-math.svg);
+}
+.base-icon {
+ background-image: url(media/navigation/libo-base.svg);
+}
+.chart-icon {
+ background-image: url(media/navigation/libo-chart.svg);
+}
+.basic-icon {
+ background-image: url(media/navigation/libo-basic.svg);
+}
+/* tree view */
+
+.contents-treeview ul,
+.contents-treeview li {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+ font-size: 15px;
+}
+.contents-treeview {
+ -moz-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+}
+.contents-treeview a, .index a {
+ text-decoration: none;
+ line-height: 1.4;
+}
+.contents-treeview a:hover, .index a:hover {
+ border-left: 2px solid rgba(0,0,0,0.05);
+ margin-left: -12px;
+ padding-left: 10px;
+}
+.contents-treeview input + label + ul {
+ margin: 0 0 0 22px;
+}
+.contents-treeview input ~ ul {
+ display: none;
+}
+.contents-treeview label,
+.contents-treeview label:before {
+ cursor: pointer;
+ color: #111;
+}
+.contents-treeview input:disabled + label {
+ cursor: default;
+ opacity: .6;
+}
+.contents-treeview input:checked:not(:disabled) ~ ul {
+ display: block;
+}
+.contents-treeview label,
+.contents-treeview a,
+.contents-treeview label::before {
+ display: block;
+ vertical-align: middle;
+}
+.contents-treeview label:before {
+ content: "⊞";
+ color: #0461e0;
+ width: 16px;
+ margin: 0 5px 0 0;
+ display: inline-block;
+}
+.contents-treeview input:checked + label::before {
+ content: "⊟";
+}
+.contents-current {
+ background: rgba(0,0,0,0.1);
+ border-left: 2px solid #6E7487;
+ margin-left: -12px;
+ padding-left: 10px;
+}
+/* webkit adjacent element selector bugfix */
+
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+ .contents-treeview {
+ -webkit-animation: webkit-adjacent-element-selector-bugfix infinite 1s;
+ }
+ @-webkit-keyframes webkit-adjacent-element-selector-bugfix {
+ from {
+ padding: 0;
+ }
+ to {
+ padding: 0;
+ }
+ }
+}
+@media screen and (min-width: 960px) {
+ .dropdowns {
+ flex-direction: row;
+ overflow-y: auto;
+ overflow-x: hidden;
+ }
+ #langs-nav, #modules-nav {
+ display: none;
+ }
+ #langs-nav a {
+ font-size: 19px;
+ white-space: normal;
+ }
+ /* these are buttons, so also reset some default stylings */
+ #langs, #modules {
+ cursor: pointer;
+ color: #fff;
+ font-size: 19px;
+ display: block;
+ background: transparent;
+ border: none;
+ text-transform: none;
+ padding: 0;
+ line-height: normal;
+ }
+
+ /* change the menu direction to stacked */
+ #langs-nav:not([aria-hidden='true']), #modules-nav:not([aria-hidden='true']) {
+ display: flex;
+ flex-direction: column;
+ overflow-y: auto;
+ max-height: 480px;
+ position: absolute;
+ }
+ #modules-nav {
+ background-color: #101820;
+ text-align: left;
+ }
+ #modules-nav div {
+ display: block;
+ }
+ #modules-nav a {
+ font-size: 19px;
+ }
+ aside {
+ float: left;
+ width: 320px;
+ }
+ .leftside {
+ grid-area: leftside;
+ }
+ .rightside {
+ grid-area: rightside;
+ }
+ #DonationFrame {
+ grid-area: donation;
+ }
+ #SearchFrame {
+ grid-area: search;
+ }
+ footer {
+ grid-area: footer;
+ }
+ .lang {
+ background-color: transparent;
+ }
+ .modules {
+ border: none;
+ background-color: transparent;
+ }
+ #DisplayArea {
+ box-shadow: 0 2px 8px 0 rgba(0,0,0,.05);
+ padding: 10px 50px 40px 50px;
+ }
+ .xapian-omega-search {
+ width: 100%;
+ }
+ .xapian-omega-search form {
+ display: flex;
+ justify-content: center;
+ }
+ .omega-autofocus {
+ max-width: 200px;
+ width: 100%
+ }
+ /* ScriptForge service tables */
+ .sf_table {
+ min-width: auto;
+ }
+ .sf_table thead {
+ display: table-header-group;
+ }
+ .sf_table tr {
+ display: table-row;
+ }
+ .sf_table td {
+ display: table-cell;
+ }
+}
+@media screen and (min-width: 1440px) {
+ #Contents {
+ color: #333;
+ z-index: 6;
+ display: block;
+ margin: 0 20px 0 20px;
+ }
+ label[for=accordion-1] {
+ background-color: transparent;
+ text-decoration: none;
+ }
+ label[for=accordion-1]:hover {
+ background-color: transparent;
+ }
+ label[for=accordion-1]:after {
+ content: "";
+ }
+ .omega-autofocus {
+ max-width: 400px;
+ }
+}
+/* Use @supports to sneak these rules past IE */
+@supports (grid-area: auto) {
+ @media screen and (min-width: 960px) {
+ #TopLeftHeader {
+ display: grid;
+ align-items: end;
+ grid-template-columns: auto auto;
+ grid-template-rows: auto auto;
+ grid-template-areas: "symbol logo"
+ "symbol dropdowns"
+ }
+ #SearchFrame {
+ grid-area: search;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+ #DonationFrame {
+ grid-area: donation;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+ body {
+ display: grid;
+ grid-template-columns: 320px 100px 300px 1fr;
+ grid-template-rows: minmax(1em, auto) minmax(1em, auto) 1fr minmax(1em, auto);
+ grid-template-areas: "header header search donation"
+ "rightside main main main"
+ "leftside main main main"
+ ". footer footer footer"
+ }
+ html {
+ scroll-padding-top: 64px;
+ }
+ }
+ @media screen and (min-width: 1440px) {
+ body {
+ display: grid;
+ grid-template-columns: 360px 100px 400px 400px 1fr;
+ grid-template-rows: 1fr minmax(1em, auto) minmax(1em, auto);
+ grid-template-areas: "header header search search donation"
+ "leftside main main main rightside"
+ ". footer footer footer ."
+ }
+ .donation {
+ max-width: 300px;
+ }
+ .rightside {
+ width: auto;
+ border-right: none;
+ }
+ }
+}
diff --git a/helpcontent2/help3xsl/flexsearch.debug.js b/helpcontent2/help3xsl/flexsearch.debug.js
new file mode 100644
index 000000000..98e658130
--- /dev/null
+++ b/helpcontent2/help3xsl/flexsearch.debug.js
@@ -0,0 +1,963 @@
+/**!
+ * FlexSearch.js v0.7.2 (Debug)
+ * Copyright 2018-2021 Nextapps GmbH
+ * Author: Thomas Wilkerling
+ * Licence: Apache-2.0
+ * https://github.com/nextapps-de/flexsearch
+ */
+(function(self){'use strict';
+function r(a, b) {
+ return "undefined" !== typeof a ? a : b;
+}
+function v(a) {
+ const b = Array(a);
+ for (let c = 0; c < a; c++) {
+ b[c] = w();
+ }
+ return b;
+}
+function w() {
+ return Object.create(null);
+}
+function aa(a, b) {
+ return b.length - a.length;
+}
+function x(a) {
+ return "string" === typeof a;
+}
+function z(a) {
+ return "object" === typeof a;
+}
+function D(a) {
+ return "function" === typeof a;
+}
+;function ba(a, b, c, d) {
+ if (a && (b && (a = E(a, b)), this.matcher && (a = E(a, this.matcher)), this.stemmer && 1 < a.length && (a = E(a, this.stemmer)), d && 1 < a.length && (a = F(a)), c || "" === c)) {
+ a = a.split(c);
+ if (this.filter) {
+ b = this.filter;
+ c = a.length;
+ d = [];
+ for (let e = 0, f = 0; e < c; e++) {
+ const g = a[e];
+ g && !b[g] && (d[f++] = g);
+ }
+ a = d;
+ }
+ return a;
+ }
+ return a;
+}
+const ca = /[\p{Z}\p{S}\p{P}\p{C}]+/u, da = /[\u0300-\u036f]/g;
+function ea(a, b) {
+ const c = Object.keys(a), d = c.length, e = [];
+ let f = "", g = 0;
+ for (let h = 0, k, m; h < d; h++) {
+ k = c[h], (m = a[k]) ? (e[g++] = G(b ? "(?!\\b)" + k + "(\\b|_)" : k), e[g++] = m) : f += (f ? "|" : "") + k;
+ }
+ f && (e[g++] = G(b ? "(?!\\b)(" + f + ")(\\b|_)" : "(" + f + ")"), e[g] = "");
+ return e;
+}
+function E(a, b) {
+ for (let c = 0, d = b.length; c < d && (a = a.replace(b[c], b[c + 1]), a); c += 2) {
+ }
+ return a;
+}
+function G(a) {
+ return new RegExp(a, "g");
+}
+function F(a) {
+ let b = "", c = "";
+ for (let d = 0, e = a.length, f; d < e; d++) {
+ (f = a[d]) !== c && (b += c = f);
+ }
+ return b;
+}
+;var ha = {encode:fa, rtl:!1, tokenize:""};
+function fa(a) {
+ return ba.call(this, a.toLowerCase(), !1, ca, !1);
+}
+;const ia = {}, I = {};
+function ja(a) {
+ J(a, "add");
+ J(a, "append");
+ J(a, "search");
+ J(a, "update");
+ J(a, "remove");
+}
+function J(a, b) {
+ a[b + "Async"] = function() {
+ const c = this, d = arguments;
+ var e = d[d.length - 1];
+ let f;
+ D(e) && (f = e, delete d[d.length - 1]);
+ e = new Promise(function(g) {
+ setTimeout(function() {
+ c.async = !0;
+ const h = c[b].apply(c, d);
+ c.async = !1;
+ g(h);
+ });
+ });
+ return f ? (e.then(f), this) : e;
+ };
+}
+;function ka(a, b, c, d) {
+ const e = a.length;
+ let f = [], g, h, k = 0;
+ d && (d = []);
+ for (let m = e - 1; 0 <= m; m--) {
+ const p = a[m], u = p.length, q = w();
+ let n = !g;
+ for (let l = 0; l < u; l++) {
+ const t = p[l], y = t.length;
+ if (y) {
+ for (let C = 0, B, A; C < y; C++) {
+ if (A = t[C], g) {
+ if (g[A]) {
+ if (!m) {
+ if (c) {
+ c--;
+ } else {
+ if (f[k++] = A, k === b) {
+ return f;
+ }
+ }
+ }
+ if (m || d) {
+ q[A] = 1;
+ }
+ n = !0;
+ }
+ if (d && (h[A] = (B = h[A]) ? ++B : B = 1, B < e)) {
+ const H = d[B - 2] || (d[B - 2] = []);
+ H[H.length] = A;
+ }
+ } else {
+ q[A] = 1;
+ }
+ }
+ }
+ }
+ if (d) {
+ g || (h = q);
+ } else {
+ if (!n) {
+ return [];
+ }
+ }
+ g = q;
+ }
+ if (d) {
+ for (let m = d.length - 1, p, u; 0 <= m; m--) {
+ p = d[m];
+ u = p.length;
+ for (let q = 0, n; q < u; q++) {
+ if (n = p[q], !g[n]) {
+ if (c) {
+ c--;
+ } else {
+ if (f[k++] = n, k === b) {
+ return f;
+ }
+ }
+ g[n] = 1;
+ }
+ }
+ }
+ }
+ return f;
+}
+function la(a, b) {
+ const c = w(), d = w(), e = [];
+ for (let f = 0; f < a.length; f++) {
+ c[a[f]] = 1;
+ }
+ for (let f = 0, g; f < b.length; f++) {
+ g = b[f];
+ for (let h = 0, k; h < g.length; h++) {
+ k = g[h], c[k] && !d[k] && (d[k] = 1, e[e.length] = k);
+ }
+ }
+ return e;
+}
+;function K(a) {
+ this.limit = !0 !== a && a;
+ this.cache = w();
+ this.queue = [];
+}
+function ma(a, b, c) {
+ z(a) && (a = a.query);
+ let d = this.cache.get(a);
+ d || (d = this.search(a, b, c), this.cache.set(a, d));
+ return d;
+}
+K.prototype.set = function(a, b) {
+ if (!this.cache[a]) {
+ var c = this.queue.length;
+ c === this.limit ? delete this.cache[this.queue[c - 1]] : c++;
+ for (--c; 0 < c; c--) {
+ this.queue[c] = this.queue[c - 1];
+ }
+ this.queue[0] = a;
+ }
+ this.cache[a] = b;
+};
+K.prototype.get = function(a) {
+ const b = this.cache[a];
+ if (this.limit && b && (a = this.queue.indexOf(a))) {
+ const c = this.queue[a - 1];
+ this.queue[a - 1] = this.queue[a];
+ this.queue[a] = c;
+ }
+ return b;
+};
+K.prototype.del = function(a) {
+ for (let b = 0, c, d; b < this.queue.length; b++) {
+ d = this.queue[b], c = this.cache[d], -1 !== c.indexOf(a) && (this.queue.splice(b--, 1), delete this.cache[d]);
+ }
+};
+const na = {memory:{charset:"latin:extra", resolution:3, minlength:4, fastupdate:!1}, performance:{resolution:3, minlength:3, optimize:!1, context:{depth:2, resolution:1}}, match:{charset:"latin:extra", tokenize:"reverse", }, score:{charset:"latin:advanced", resolution:20, minlength:3, context:{depth:3, resolution:9, }}, "default":{}, };
+function pa(a, b, c, d, e, f) {
+ setTimeout(function() {
+ const g = a(c, JSON.stringify(f));
+ g && g.then ? g.then(function() {
+ b.export(a, b, c, d, e + 1);
+ }) : b.export(a, b, c, d, e + 1);
+ });
+}
+;function L(a, b) {
+ if (!(this instanceof L)) {
+ return new L(a);
+ }
+ var c;
+ if (a) {
+ if (x(a)) {
+ na[a] || console.warn("Preset not found: " + a), a = na[a];
+ } else {
+ if (c = a.preset) {
+ c[c] || console.warn("Preset not found: " + c), a = Object.assign({}, c[c], a);
+ }
+ }
+ c = a.charset;
+ var d = a.lang;
+ x(c) && (-1 === c.indexOf(":") && (c += ":default"), c = I[c]);
+ x(d) && (d = ia[d]);
+ } else {
+ a = {};
+ }
+ let e, f, g = a.context || {};
+ this.encode = a.encode || c && c.encode || fa;
+ this.register = b || w();
+ this.resolution = e = a.resolution || 9;
+ this.tokenize = b = c && c.tokenize || a.tokenize || "strict";
+ this.depth = "strict" === b && g.depth;
+ this.bidirectional = r(g.bidirectional, !0);
+ this.optimize = f = r(a.optimize, !0);
+ this.fastupdate = r(a.fastupdate, !0);
+ this.minlength = a.minlength || 1;
+ this.boost = a.boost;
+ this.map = f ? v(e) : w();
+ this.resolution_ctx = e = g.resolution || 1;
+ this.ctx = f ? v(e) : w();
+ this.rtl = c && c.rtl || a.rtl;
+ this.matcher = (b = a.matcher || d && d.matcher) && ea(b, !1);
+ this.stemmer = (b = a.stemmer || d && d.stemmer) && ea(b, !0);
+ if (c = b = a.filter || d && d.filter) {
+ c = b;
+ d = w();
+ for (let h = 0, k = c.length; h < k; h++) {
+ d[c[h]] = 1;
+ }
+ c = d;
+ }
+ this.filter = c;
+ this.cache = (b = a.cache) && new K(b);
+}
+L.prototype.append = function(a, b) {
+ return this.add(a, b, !0);
+};
+L.prototype.add = function(a, b, c, d) {
+ if (b && (a || 0 === a)) {
+ if (!d && !c && this.register[a]) {
+ return this.update(a, b);
+ }
+ b = this.encode(b);
+ if (d = b.length) {
+ const m = w(), p = w(), u = this.depth, q = this.resolution;
+ for (let n = 0; n < d; n++) {
+ let l = b[this.rtl ? d - 1 - n : n];
+ var e = l.length;
+ if (l && e >= this.minlength && (u || !p[l])) {
+ var f = M(q, d, n), g = "";
+ switch(this.tokenize) {
+ case "full":
+ if (3 < e) {
+ for (f = 0; f < e; f++) {
+ for (var h = e; h > f; h--) {
+ if (h - f >= this.minlength) {
+ var k = M(q, d, n, e, f);
+ g = l.substring(f, h);
+ this.push_index(p, g, k, a, c);
+ }
+ }
+ }
+ break;
+ }
+ case "reverse":
+ if (2 < e) {
+ for (h = e - 1; 0 < h; h--) {
+ g = l[h] + g, g.length >= this.minlength && (k = M(q, d, n, e, h), this.push_index(p, g, k, a, c));
+ }
+ g = "";
+ }
+ case "forward":
+ if (1 < e) {
+ for (h = 0; h < e; h++) {
+ g += l[h], g.length >= this.minlength && this.push_index(p, g, f, a, c);
+ }
+ break;
+ }
+ default:
+ if (this.boost && (f = Math.min(f / this.boost(b, l, n) | 0, q - 1)), this.push_index(p, l, f, a, c), u && 1 < d && n < d - 1) {
+ for (e = w(), g = this.resolution_ctx, f = l, h = Math.min(u + 1, d - n), e[f] = 1, k = 1; k < h; k++) {
+ if ((l = b[this.rtl ? d - 1 - n - k : n + k]) && l.length >= this.minlength && !e[l]) {
+ e[l] = 1;
+ const t = M(g + (d / 2 > g ? 0 : 1), d, n, h - 1, k - 1), y = this.bidirectional && l > f;
+ this.push_index(m, y ? f : l, t, a, c, y ? l : f);
+ }
+ }
+ }
+ }
+ }
+ }
+ this.fastupdate || (this.register[a] = 1);
+ }
+ }
+ return this;
+};
+function M(a, b, c, d, e) {
+ return c && 1 < a ? b + (d || 0) <= a ? c + (e || 0) : (a - 1) / (b + (d || 0)) * (c + (e || 0)) + 1 | 0 : 0;
+}
+L.prototype.push_index = function(a, b, c, d, e, f) {
+ let g = f ? this.ctx : this.map;
+ if (!a[b] || f && !a[b][f]) {
+ this.optimize && (g = g[c]), f ? (a = a[b] || (a[b] = w()), a[f] = 1, g = g[f] || (g[f] = w())) : a[b] = 1, g = g[b] || (g[b] = []), this.optimize || (g = g[c] || (g[c] = [])), e && -1 !== g.indexOf(d) || (g[g.length] = d, this.fastupdate && (a = this.register[d] || (this.register[d] = []), a[a.length] = g));
+ }
+};
+L.prototype.search = function(a, b, c) {
+ c || (!b && z(a) ? (c = a, a = c.query) : z(b) && (c = b));
+ let d = [], e;
+ let f, g = 0;
+ if (c) {
+ b = c.limit;
+ g = c.offset || 0;
+ var h = c.context;
+ f = c.suggest;
+ }
+ if (a && (a = this.encode(a), e = a.length, 1 < e)) {
+ c = w();
+ var k = [];
+ for (let p = 0, u = 0, q; p < e; p++) {
+ if ((q = a[p]) && q.length >= this.minlength && !c[q]) {
+ if (this.optimize || f || this.map[q]) {
+ k[u++] = q, c[q] = 1;
+ } else {
+ return d;
+ }
+ }
+ }
+ a = k;
+ e = a.length;
+ }
+ if (!e) {
+ return d;
+ }
+ b || (b = 100);
+ h = this.depth && 1 < e && !1 !== h;
+ c = 0;
+ let m;
+ h ? (m = a[0], c = 1) : 1 < e && a.sort(aa);
+ for (let p, u; c < e; c++) {
+ u = a[c];
+ h ? (p = this.add_result(d, f, b, g, 2 === e, u, m), f && !1 === p && d.length || (m = u)) : p = this.add_result(d, f, b, g, 1 === e, u);
+ if (p) {
+ return p;
+ }
+ if (f && c === e - 1) {
+ k = d.length;
+ if (!k) {
+ if (h) {
+ h = 0;
+ c = -1;
+ continue;
+ }
+ return d;
+ }
+ if (1 === k) {
+ return qa(d[0], b, g);
+ }
+ }
+ }
+ return ka(d, b, g, f);
+};
+L.prototype.add_result = function(a, b, c, d, e, f, g) {
+ let h = [], k = g ? this.ctx : this.map;
+ this.optimize || (k = ra(k, f, g, this.bidirectional));
+ if (k) {
+ let m = 0;
+ const p = Math.min(k.length, g ? this.resolution_ctx : this.resolution);
+ for (let u = 0, q = 0, n, l; u < p; u++) {
+ if (n = k[u]) {
+ if (this.optimize && (n = ra(n, f, g, this.bidirectional)), d && n && e && (l = n.length, l <= d ? (d -= l, n = null) : (n = n.slice(d), d = 0)), n && (h[m++] = n, e && (q += n.length, q >= c))) {
+ break;
+ }
+ }
+ }
+ if (m) {
+ if (e) {
+ return qa(h, c, 0);
+ }
+ a[a.length] = h;
+ return;
+ }
+ }
+ return !b && h;
+};
+function qa(a, b, c) {
+ a = 1 === a.length ? a[0] : [].concat.apply([], a);
+ return c || a.length > b ? a.slice(c, c + b) : a;
+}
+function ra(a, b, c, d) {
+ c ? (d = d && b > c, a = (a = a[d ? b : c]) && a[d ? c : b]) : a = a[b];
+ return a;
+}
+L.prototype.contain = function(a) {
+ return !!this.register[a];
+};
+L.prototype.update = function(a, b) {
+ return this.remove(a).add(a, b);
+};
+L.prototype.remove = function(a, b) {
+ const c = this.register[a];
+ if (c) {
+ if (this.fastupdate) {
+ for (let d = 0, e; d < c.length; d++) {
+ e = c[d], e.splice(e.indexOf(a), 1);
+ }
+ } else {
+ N(this.map, a, this.resolution, this.optimize), this.depth && N(this.ctx, a, this.resolution_ctx, this.optimize);
+ }
+ b || delete this.register[a];
+ this.cache && this.cache.del(a);
+ }
+ return this;
+};
+function N(a, b, c, d, e) {
+ let f = 0;
+ if (a.constructor === Array) {
+ if (e) {
+ b = a.indexOf(b), -1 !== b ? 1 < a.length && (a.splice(b, 1), f++) : f++;
+ } else {
+ e = Math.min(a.length, c);
+ for (let g = 0, h; g < e; g++) {
+ if (h = a[g]) {
+ f = N(h, b, c, d, e), d || f || delete a[g];
+ }
+ }
+ }
+ } else {
+ for (let g in a) {
+ (f = N(a[g], b, c, d, e)) || delete a[g];
+ }
+ }
+ return f;
+}
+L.prototype.searchCache = ma;
+L.prototype.export = function(a, b, c, d, e) {
+ let f, g;
+ switch(e || (e = 0)) {
+ case 0:
+ f = "reg";
+ if (this.fastupdate) {
+ g = w();
+ for (let h in this.register) {
+ g[h] = 1;
+ }
+ } else {
+ g = this.register;
+ }
+ break;
+ case 1:
+ f = "cfg";
+ g = {doc:0, opt:this.optimize ? 1 : 0};
+ break;
+ case 2:
+ f = "map";
+ g = this.map;
+ break;
+ case 3:
+ f = "ctx";
+ g = this.ctx;
+ break;
+ default:
+ return;
+ }
+ pa(a, b || this, c ? c + "." + f : f, d, e, g);
+ return !0;
+};
+L.prototype.import = function(a, b) {
+ if (b) {
+ switch(x(b) && (b = JSON.parse(b)), a) {
+ case "cfg":
+ this.optimize = !!b.opt;
+ break;
+ case "reg":
+ this.fastupdate = !1;
+ this.register = b;
+ break;
+ case "map":
+ this.map = b;
+ break;
+ case "ctx":
+ this.ctx = b;
+ }
+ }
+};
+ja(L.prototype);
+function sa(a) {
+ a = a.data;
+ var b = self._index;
+ const c = a.args;
+ var d = a.task;
+ switch(d) {
+ case "init":
+ d = a.options || {};
+ a = a.factory;
+ b = d.encode;
+ d.cache = !1;
+ b && 0 === b.indexOf("function") && (d.encode = Function("return " + b)());
+ a ? (Function("return " + a)()(self), self._index = new self.FlexSearch.Index(d), delete self.FlexSearch) : self._index = new L(d);
+ break;
+ default:
+ a = a.id, b = b[d].apply(b, c), postMessage("search" === d ? {id:a, msg:b} : {id:a});
+ }
+}
+;let ta = 0;
+function O(a) {
+ if (!(this instanceof O)) {
+ return new O(a);
+ }
+ var b;
+ a ? D(b = a.encode) && (a.encode = b.toString()) : a = {};
+ (b = (self || window)._factory) && (b = b.toString());
+ const c = self.exports, d = this;
+ this.worker = ua(b, c, a.worker);
+ this.resolver = w();
+ if (this.worker) {
+ if (c) {
+ this.worker.on("message", function(e) {
+ d.resolver[e.id](e.msg);
+ delete d.resolver[e.id];
+ });
+ } else {
+ this.worker.onmessage = function(e) {
+ e = e.data;
+ d.resolver[e.id](e.msg);
+ delete d.resolver[e.id];
+ };
+ }
+ this.worker.postMessage({task:"init", factory:b, options:a});
+ }
+}
+Q("add");
+Q("append");
+Q("search");
+Q("update");
+Q("remove");
+function Q(a) {
+ O.prototype[a] = O.prototype[a + "Async"] = function() {
+ const b = this, c = [].slice.call(arguments);
+ var d = c[c.length - 1];
+ let e;
+ D(d) && (e = d, c.splice(c.length - 1, 1));
+ d = new Promise(function(f) {
+ setTimeout(function() {
+ b.resolver[++ta] = f;
+ b.worker.postMessage({task:a, id:ta, args:c});
+ });
+ });
+ return e ? (d.then(e), this) : d;
+ };
+}
+function ua(a, b, c) {
+ let d;
+ try {
+ d = b ? eval('new (require("worker_threads")["Worker"])("../dist/node/node.js")') : a ? new Worker(URL.createObjectURL(new Blob(["onmessage=" + sa.toString()], {type:"text/javascript"}))) : new Worker(x(c) ? c : "worker/worker.js", {type:"module"});
+ } catch (e) {
+ }
+ return d;
+}
+;function R(a) {
+ if (!(this instanceof R)) {
+ return new R(a);
+ }
+ var b = a.document || a.doc || a, c;
+ this.tree = [];
+ this.field = [];
+ this.marker = [];
+ this.register = w();
+ this.key = (c = b.key || b.id) && S(c, this.marker) || "id";
+ this.fastupdate = r(a.fastupdate, !0);
+ this.storetree = (c = b.store) && !0 !== c && [];
+ this.store = c && w();
+ this.tag = (c = b.tag) && S(c, this.marker);
+ this.tagindex = c && w();
+ this.cache = (c = a.cache) && new K(c);
+ a.cache = !1;
+ this.worker = a.worker;
+ this.async = !1;
+ c = w();
+ let d = b.index || b.field || b;
+ x(d) && (d = [d]);
+ for (let e = 0, f, g; e < d.length; e++) {
+ f = d[e], x(f) || (g = f, f = f.field), g = z(g) ? Object.assign({}, a, g) : a, this.worker && (c[f] = new O(g), c[f].worker || (this.worker = !1)), this.worker || (c[f] = new L(g, this.register)), this.tree[e] = S(f, this.marker), this.field[e] = f;
+ }
+ if (this.storetree) {
+ for (a = b.store, x(a) && (a = [a]), b = 0; b < a.length; b++) {
+ this.storetree[b] = S(a[b], this.marker);
+ }
+ }
+ this.index = c;
+}
+function S(a, b) {
+ const c = a.split(":");
+ let d = 0;
+ for (let e = 0; e < c.length; e++) {
+ a = c[e], 0 <= a.indexOf("[]") && (a = a.substring(0, a.length - 2)) && (b[d] = !0), a && (c[d++] = a);
+ }
+ d < c.length && (c.length = d);
+ return 1 < d ? c : c[0];
+}
+function T(a, b) {
+ if (x(b)) {
+ a = a[b];
+ } else {
+ for (let c = 0; a && c < b.length; c++) {
+ a = a[b[c]];
+ }
+ }
+ return a;
+}
+function U(a, b, c, d, e) {
+ a = a[e];
+ if (d === c.length - 1) {
+ b[e] = a;
+ } else {
+ if (a) {
+ if (a.constructor === Array) {
+ for (b = b[e] = Array(a.length), e = 0; e < a.length; e++) {
+ U(a, b, c, d, e);
+ }
+ } else {
+ b = b[e] || (b[e] = w()), e = c[++d], U(a, b, c, d, e);
+ }
+ }
+ }
+}
+function V(a, b, c, d, e, f, g, h) {
+ if (a = a[g]) {
+ if (d === b.length - 1) {
+ if (a.constructor === Array) {
+ if (c[d]) {
+ for (b = 0; b < a.length; b++) {
+ e.add(f, a[b], !0, !0);
+ }
+ return;
+ }
+ a = a.join(" ");
+ }
+ e.add(f, a, h, !0);
+ } else {
+ if (a.constructor === Array) {
+ for (g = 0; g < a.length; g++) {
+ V(a, b, c, d, e, f, g, h);
+ }
+ } else {
+ g = b[++d], V(a, b, c, d, e, f, g, h);
+ }
+ }
+ }
+}
+R.prototype.add = function(a, b, c) {
+ z(a) && (b = a, a = T(b, this.key));
+ if (b && (a || 0 === a)) {
+ if (!c && this.register[a]) {
+ return this.update(a, b);
+ }
+ for (let d = 0, e, f; d < this.field.length; d++) {
+ f = this.field[d], e = this.tree[d], x(e) && (e = [e]), V(b, e, this.marker, 0, this.index[f], a, e[0], c);
+ }
+ if (this.tag) {
+ let d = T(b, this.tag), e = w();
+ x(d) && (d = [d]);
+ for (let f = 0, g, h; f < d.length; f++) {
+ if (g = d[f], !e[g] && (e[g] = 1, h = this.tagindex[g] || (this.tagindex[g] = []), !c || -1 === h.indexOf(a))) {
+ if (h[h.length] = a, this.fastupdate) {
+ const k = this.register[a] || (this.register[a] = []);
+ k[k.length] = h;
+ }
+ }
+ }
+ }
+ if (this.store && (!c || !this.store[a])) {
+ let d;
+ if (this.storetree) {
+ d = w();
+ for (let e = 0, f; e < this.storetree.length; e++) {
+ f = this.storetree[e], x(f) ? d[f] = b[f] : U(b, d, f, 0, f[0]);
+ }
+ }
+ this.store[a] = d || b;
+ }
+ }
+ return this;
+};
+R.prototype.append = function(a, b) {
+ return this.add(a, b, !0);
+};
+R.prototype.update = function(a, b) {
+ return this.remove(a).add(a, b);
+};
+R.prototype.remove = function(a) {
+ z(a) && (a = T(a, this.key));
+ if (this.register[a]) {
+ for (var b = 0; b < this.field.length && (this.index[this.field[b]].remove(a, !this.worker), !this.fastupdate); b++) {
+ }
+ if (this.tag && !this.fastupdate) {
+ for (let c in this.tagindex) {
+ b = this.tagindex[c];
+ const d = b.indexOf(a);
+ -1 !== d && (1 < b.length ? b.splice(d, 1) : delete this.tagindex[c]);
+ }
+ }
+ this.store && delete this.store[a];
+ delete this.register[a];
+ }
+ return this;
+};
+R.prototype.search = function(a, b, c, d) {
+ c || (!b && z(a) ? (c = a, a = c.query) : z(b) && (c = b, b = 0));
+ let e = [], f = [], g, h, k, m, p, u, q = 0;
+ if (c) {
+ if (c.constructor === Array) {
+ k = c, c = null;
+ } else {
+ k = (g = c.pluck) || c.index || c.field;
+ m = c.tag;
+ h = this.store && c.enrich;
+ p = "and" === c.bool;
+ b = c.limit || 100;
+ u = c.offset || 0;
+ if (m && (x(m) && (m = [m]), !a)) {
+ for (let l = 0, t; l < m.length; l++) {
+ if (t = va.call(this, m[l], b, u, h)) {
+ e[e.length] = t, q++;
+ }
+ }
+ return q ? e : [];
+ }
+ x(k) && (k = [k]);
+ }
+ }
+ k || (k = this.field);
+ p = p && (1 < k.length || m && 1 < m.length);
+ const n = !d && (this.worker || this.async) && [];
+ for (let l = 0, t, y, C; l < k.length; l++) {
+ let B;
+ y = k[l];
+ x(y) || (B = y, y = y.field);
+ if (n) {
+ n[l] = this.index[y].searchAsync(a, b, B || c);
+ } else {
+ C = (t = d ? d[l] : this.index[y].search(a, b, B || c)) && t.length;
+ if (m && C) {
+ const A = [];
+ let H = 0;
+ p && (A[0] = [t]);
+ for (let W = 0, oa, P; W < m.length; W++) {
+ if (oa = m[W], C = (P = this.tagindex[oa]) && P.length) {
+ H++, A[A.length] = p ? [P] : P;
+ }
+ }
+ H && (t = p ? ka(A, b || 100, u || 0) : la(t, A), C = t.length);
+ }
+ if (C) {
+ f[q] = y, e[q++] = t;
+ } else {
+ if (p) {
+ return [];
+ }
+ }
+ }
+ }
+ if (n) {
+ const l = this;
+ return new Promise(function(t) {
+ Promise.all(n).then(function(y) {
+ t(l.search(a, b, c, y));
+ });
+ });
+ }
+ if (!q) {
+ return [];
+ }
+ if (g && (!h || !this.store)) {
+ return e[0];
+ }
+ for (let l = 0, t; l < f.length; l++) {
+ t = e[l];
+ t.length && h && (t = wa.call(this, t));
+ if (g) {
+ return t;
+ }
+ e[l] = {field:f[l], result:t};
+ }
+ return e;
+};
+function va(a, b, c, d) {
+ let e = this.tagindex[a], f = e && e.length - c;
+ if (f && 0 < f) {
+ if (f > b || c) {
+ e = e.slice(c, c + b);
+ }
+ d && (e = wa.call(this, e));
+ return {tag:a, result:e};
+ }
+}
+function wa(a) {
+ const b = Array(a.length);
+ for (let c = 0, d; c < a.length; c++) {
+ d = a[c], b[c] = {id:d, doc:this.store[d]};
+ }
+ return b;
+}
+R.prototype.contain = function(a) {
+ return !!this.register[a];
+};
+R.prototype.get = function(a) {
+ return this.store[a];
+};
+R.prototype.set = function(a, b) {
+ this.store[a] = b;
+ return this;
+};
+R.prototype.searchCache = ma;
+R.prototype.export = function(a, b, c, d, e) {
+ e || (e = 0);
+ d || (d = 0);
+ if (d < this.field.length) {
+ const f = this.field[d], g = this.index[f];
+ b = this;
+ setTimeout(function() {
+ g.export(a, b, e ? f.replace(":", "-") : "", d, e++) || (d++, e = 1, b.export(a, b, f, d, e));
+ });
+ } else {
+ let f;
+ switch(e) {
+ case 1:
+ c = "tag";
+ f = this.tagindex;
+ break;
+ case 2:
+ c = "store";
+ f = this.store;
+ break;
+ default:
+ return;
+ }
+ pa(a, this, c, d, e, f);
+ }
+};
+R.prototype.import = function(a, b) {
+ if (b) {
+ switch(x(b) && (b = JSON.parse(b)), a) {
+ case "tag":
+ this.tagindex = b;
+ break;
+ case "reg":
+ this.fastupdate = !1;
+ this.register = b;
+ for (let d = 0, e; d < this.field.length; d++) {
+ e = this.index[this.field[d]], e.register = b, e.fastupdate = !1;
+ }
+ break;
+ case "store":
+ this.store = b;
+ break;
+ default:
+ a = a.split(".");
+ const c = a[0];
+ a = a[1];
+ c && a && this.index[c].import(a, b);
+ }
+ }
+};
+ja(R.prototype);
+var ya = {encode:xa, rtl:!1, tokenize:""};
+const za = G("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"), Aa = G("[\u00e8\u00e9\u00ea\u00eb]"), Ba = G("[\u00ec\u00ed\u00ee\u00ef]"), Ca = G("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"), Da = G("[\u00f9\u00fa\u00fb\u00fc\u0171]"), Ea = G("[\u00fd\u0177\u00ff]"), Fa = G("\u00f1"), Ga = G("[\u00e7c]"), Ha = G("\u00df"), Ia = G(" & "), Ja = [za, "a", Aa, "e", Ba, "i", Ca, "o", Da, "u", Ea, "y", Fa, "n", Ga, "k", Ha, "s", Ia, " and "];
+function xa(a) {
+ var b = a = "" + a;
+ b.normalize && (b = b.normalize("NFD").replace(da, ""));
+ return ba.call(this, b.toLowerCase(), !a.normalize && Ja, ca, !1);
+}
+;var La = {encode:Ka, rtl:!1, tokenize:"strict"};
+const Ma = /[^a-z0-9]+/, Na = {b:"p", v:"f", w:"f", z:"s", x:"s", "\u00df":"s", d:"t", n:"m", c:"k", g:"k", j:"k", q:"k", i:"e", y:"e", u:"o"};
+function Ka(a) {
+ a = xa.call(this, a).join(" ");
+ const b = [];
+ if (a) {
+ const c = a.split(Ma), d = c.length;
+ for (let e = 0, f, g = 0; e < d; e++) {
+ if ((a = c[e]) && (!this.filter || !this.filter[a])) {
+ f = a[0];
+ let h = Na[f] || f, k = h;
+ for (let m = 1; m < a.length; m++) {
+ f = a[m];
+ const p = Na[f] || f;
+ p && p !== k && (h += p, k = p);
+ }
+ b[g++] = h;
+ }
+ }
+ }
+ return b;
+}
+;var Pa = {encode:Oa, rtl:!1, tokenize:""};
+const Qa = G("ae"), Ra = G("oe"), Sa = G("sh"), Ta = G("th"), Ua = G("ph"), Va = G("pf"), Wa = [Qa, "a", Ra, "o", Sa, "s", Ta, "t", Ua, "f", Va, "f", G("(?![aeo])h(?![aeo])"), "", G("(?!^[aeo])h(?!^[aeo])"), ""];
+function Oa(a, b) {
+ a && (a = Ka.call(this, a).join(" "), 2 < a.length && (a = E(a, Wa)), b || (1 < a.length && (a = F(a)), a && (a = a.split(" "))));
+ return a;
+}
+;var Ya = {encode:Xa, rtl:!1, tokenize:""};
+const Za = G("(?!\\b)[aeo]");
+function Xa(a) {
+ a && (a = Oa.call(this, a, !0), 1 < a.length && (a = a.replace(Za, "")), 1 < a.length && (a = F(a)), a && (a = a.split(" ")));
+ return a;
+}
+;I["latin:default"] = ha;
+I["latin:simple"] = ya;
+I["latin:balance"] = La;
+I["latin:advanced"] = Pa;
+I["latin:extra"] = Ya;
+const X = self;
+let Y;
+const Z = {Index:L, Document:R, Worker:O, registerCharset:function(a, b) {
+ I[a] = b;
+}, registerLanguage:function(a, b) {
+ ia[a] = b;
+}};
+(Y = X.define) && Y.amd ? Y([], function() {
+ return Z;
+}) : X.exports ? X.exports = Z : X.FlexSearch = Z;
+}(this));
diff --git a/helpcontent2/help3xsl/generate_hid2file.xsl b/helpcontent2/help3xsl/generate_hid2file.xsl
new file mode 100644
index 000000000..59e2e4edd
--- /dev/null
+++ b/helpcontent2/help3xsl/generate_hid2file.xsl
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+-->
+<!--
+Stylesheet to extract index bookmarks from xhp files and output a link to
+the xhp file.
+Usage:
+xsltproc get_bookmark.xsl <file.xhp>
+-->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:output indent="yes" method="text"/>
+
+<!--
+############################
+# Variables and Parameters #
+############################
+//-->
+<xsl:variable name="fname" select="/helpdocument/meta/topic/filename"/>
+<xsl:variable name="filename">
+ <xsl:choose>
+ <xsl:when test="starts-with($fname, '/')">
+ <xsl:value-of select="substring($fname, 2)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$fname"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:variable>
+<!--
+#############
+# Templates #
+#############
+//-->
+
+<!-- Extract the bookmarks branches x filename-->
+<!--Special case for questions marks chars, that interferes in passing
+parameters in URLS-->
+<xsl:template match="/">
+ <xsl:variable name="href" select="concat(substring-before($filename,'xhp'),'html')"/>
+ <xsl:for-each select="//bookmark[@branch!='index']">
+ <xsl:variable name="aux" select="substring-after(@branch,'hid/')"/>
+ <xsl:text>'</xsl:text>
+ <xsl:choose>
+ <xsl:when test="not(contains($aux,'?'))"><xsl:value-of select="$aux"/></xsl:when>
+ <xsl:otherwise><xsl:value-of select="concat(substring-before($aux,'?'),'%3F',substring-after($aux,'?'))"/></xsl:otherwise>
+ </xsl:choose>
+ <xsl:text>':'</xsl:text>
+ <xsl:value-of select="concat($href,'#',@id)"/><xsl:text>',&#xA;</xsl:text>
+ </xsl:for-each>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/helpcontent2/help3xsl/get_bookmark.xsl b/helpcontent2/help3xsl/get_bookmark.xsl
new file mode 100644
index 000000000..9700e4d57
--- /dev/null
+++ b/helpcontent2/help3xsl/get_bookmark.xsl
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+-->
+<!--
+Stylesheet to extract index bookmarks from xhp files and output a link to
+the xhp file.
+Usage:
+xsltproc get_bookmark.xsl <file.xhp>
+-->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:include href="brand.xsl"/>
+<xsl:param name="app"/>
+<xsl:param name="local"/>
+<xsl:param name="Language"/>
+<xsl:param name="productname"/>
+<xsl:param name="productversion"/>
+
+<xsl:output indent="yes" method="text"/>
+
+<!--
+############################
+# Variables and Parameters #
+############################
+//-->
+<xsl:variable name="fname" select="/helpdocument/meta/topic/filename"/>
+<xsl:variable name="filename">
+ <xsl:choose>
+ <xsl:when test="starts-with($fname, '/')">
+ <xsl:value-of select="substring($fname, 2)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$fname"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:variable>
+<!--
+#############
+# Templates #
+#############
+//-->
+
+<!-- Extract the bookmarks-->
+<xsl:template match="/">
+ <xsl:for-each select="//bookmark[@branch='index']">
+ <xsl:variable name="hrefhtml" select="substring-before($filename,'xhp')"/>
+ <xsl:variable name="href" select="concat($Language,'/',$hrefhtml,'html?DbPAR=',$app,'#',@id)"/>
+ <xsl:for-each select="bookmark_value">
+ <xsl:text disable-output-escaping="yes"><![CDATA[{url:"]]></xsl:text>
+ <xsl:value-of select="$href"/>
+ <xsl:text disable-output-escaping="yes"><![CDATA[", app:"]]></xsl:text>
+ <xsl:value-of select="$app"/>
+ <xsl:text disable-output-escaping="yes"><![CDATA[", text:"]]></xsl:text>
+ <xsl:call-template name="replace"><xsl:with-param name="text" select="normalize-space(.)"/></xsl:call-template>
+ <xsl:text disable-output-escaping="yes"><![CDATA["},]]>&#xA;</xsl:text>
+ </xsl:for-each>
+ </xsl:for-each>
+</xsl:template>
+
+<xsl:template name="replace">
+ <xsl:param name="text"/>
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string">
+ <xsl:call-template name="apostrophe">
+ <xsl:with-param name="string">
+ <xsl:call-template name="doublequote">
+ <xsl:with-param name="string">
+ <xsl:choose>
+ <xsl:when test="contains($text,';')">
+ <xsl:value-of select="substring-before($text,';')"/>
+ <xsl:text disable-output-escaping="yes"><![CDATA[ -- ]]></xsl:text>
+ <xsl:value-of select="substring-after($text,';')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$text"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+</xsl:template>
+
+<!-- weird characters inside bookmarks, replace by HTML entities-->
+<xsl:template name="apostrophe">
+ <xsl:param name="string"/>
+ <xsl:variable name="apost">&apos;</xsl:variable><!-- apostrophe -->
+ <xsl:choose>
+ <xsl:when test="contains($string,$apost)">
+ <xsl:variable name="newstr">
+ <xsl:value-of select="substring-before($string,$apost)"/>
+ <xsl:text disable-output-escaping="yes"><![CDATA[&]]>#39;</xsl:text>
+ <xsl:value-of select="substring-after($string,$apost)"/>
+ </xsl:variable>
+ <xsl:call-template name="apostrophe">
+ <xsl:with-param name="string" select="$newstr"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$string"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="doublequote">
+ <xsl:param name="string"/>
+ <xsl:variable name="dq">&quot;</xsl:variable><!-- double quote -->
+ <xsl:choose>
+ <xsl:when test="contains($string,$dq)">
+ <xsl:variable name="newstr">
+ <xsl:value-of select="substring-before($string,$dq)"/>
+ <xsl:text disable-output-escaping="yes"><![CDATA[&]]>#34;</xsl:text>
+ <xsl:value-of select="substring-after($string,$dq)"/>
+ </xsl:variable>
+ <xsl:call-template name="doublequote">
+ <xsl:with-param name="string" select="$newstr"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$string"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/helpcontent2/help3xsl/get_tree.xsl b/helpcontent2/help3xsl/get_tree.xsl
new file mode 100644
index 000000000..1dd4a6489
--- /dev/null
+++ b/helpcontent2/help3xsl/get_tree.xsl
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+-->
+<!--
+Stylesheet to extract tree context and generate a nested list
+Usage:
+xsltproc get_tree.xsl <file.tree>
+-->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:include href="brand.xsl"/>
+<xsl:param name="lang"/>
+<xsl:param name="local"/>
+<xsl:param name="productversion"/>
+<xsl:param name="productname"/>
+<xsl:param name="module"/>
+<xsl:output indent="no" method="text"/>
+
+<!--
+#############
+# Templates #
+#############
+//-->
+<!-- Extract the tree and generate a nested UL-->
+<xsl:template match="/">
+ <xsl:apply-templates/>
+</xsl:template>
+<xsl:template match="help_section">
+ <![CDATA[<ul><li><input type="checkbox" id="]]><xsl:value-of select="@id"/><![CDATA["><label for="]]><xsl:value-of select="@id"/><![CDATA[">]]><xsl:call-template name="replace"><xsl:with-param name="text"><xsl:value-of select="@title"/></xsl:with-param></xsl:call-template><![CDATA[</label><ul>\]]><xsl:apply-templates/><![CDATA[</ul></li></ul>\]]>
+</xsl:template>
+
+<xsl:template match="node">
+ <![CDATA[<li><input type="checkbox" id="]]><xsl:value-of select="@id"/><![CDATA["><label for="]]><xsl:value-of select="@id"/><![CDATA[">]]><xsl:call-template name="replace"><xsl:with-param name="text"><xsl:value-of select="@title"/></xsl:with-param></xsl:call-template><![CDATA[</label><ul>\]]><xsl:apply-templates/><![CDATA[</ul></li>\]]>
+</xsl:template>
+
+<xsl:template match="topic">
+ <xsl:variable name="pagetarget">
+ <xsl:value-of select="substring-after(@id,'xhp')"/>
+ </xsl:variable>
+ <xsl:variable name="htmlpage">
+ <xsl:value-of select="concat($lang,'/',substring-before(substring-after(@id,'/'),'.xhp'),'.html','?DbPAR=',$module,$pagetarget)" />
+ </xsl:variable>
+ <![CDATA[<li><a target="_top" href="]]><xsl:value-of select="$htmlpage"/><![CDATA[">]]><xsl:call-template name="replace"><xsl:with-param name="text"><xsl:value-of select="."/></xsl:with-param></xsl:call-template><![CDATA[</a></li>\]]>
+</xsl:template>
+
+<xsl:template name="replace">
+ <xsl:param name="text"/>
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string">
+ <xsl:call-template name="apostrophe">
+ <xsl:with-param name="string">
+ <xsl:value-of select="$text"/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:with-param>
+ </xsl:call-template>
+</xsl:template>
+
+<!-- weird characters inside bookmarks, replace by HTML entities-->
+<xsl:template name="apostrophe">
+ <xsl:param name="string"/>
+ <xsl:variable name="apost">&apos;</xsl:variable><!-- apostrophe -->
+ <xsl:choose>
+ <xsl:when test="contains($string,$apost)">
+ <xsl:variable name="newstr">
+ <xsl:value-of select="substring-before($string,$apost)"/>
+ <xsl:text disable-output-escaping="yes"><![CDATA[&#39;]]></xsl:text>
+ <xsl:value-of select="substring-after($string,$apost)"/>
+ </xsl:variable>
+ <xsl:call-template name="apostrophe">
+ <xsl:with-param name="string" select="$newstr"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$string"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/helpcontent2/help3xsl/help.html b/helpcontent2/help3xsl/help.html
new file mode 100644
index 000000000..8ee3510cf
--- /dev/null
+++ b/helpcontent2/help3xsl/help.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<!--
+* This file is part of the LibreOffice project.
+*
+* 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 http://mozilla.org/MPL/2.0/.
+-->
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline' 'unsafe-eval' piwik.documentfoundation.org"/>
+</head>
+<body>
+<script type="text/javascript">
+ function getParameterByName(name, url) {
+ if (!url) {
+ url = window.location.href;
+ }
+ name = name.replace(/[\[\]]/g, "\\$&");
+ var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)");
+ var results = regex.exec(url);
+ if (!results) {
+ return null;
+ }
+ if (!results[2]) {
+ return '';
+ }
+ return decodeURIComponent(results[2].replace(/\+/g, " "));
+ }
+
+ var url = window.location.href;
+ var n = url.indexOf('?');
+ if (n != -1) {
+ // the URL came from LibreOffice help (F1)
+ var version = getParameterByName("Version", url);
+ var query = url.substr(n + 1, url.length);
+ var newURL = version + '/index.html?' + query;
+ window.location.replace(newURL);
+ } else {
+ window.location.replace('latest/index.html');
+ }
+</script>
+</body>
+</html>
+
diff --git a/helpcontent2/help3xsl/help.js b/helpcontent2/help3xsl/help.js
new file mode 100644
index 000000000..3e9c0fe11
--- /dev/null
+++ b/helpcontent2/help3xsl/help.js
@@ -0,0 +1,261 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+ */
+
+// Pagination and bookmark search
+var url = window.location.pathname;
+var moduleRegex = new RegExp('text\\/(\\w+)\\/');
+var regexArray = moduleRegex.exec(url);
+var userModule = currentModule();
+var modules = ['CALC', 'WRITER', 'IMPRESS', 'DRAW', 'BASE', 'MATH', 'CHART', 'BASIC', 'SHARED'];
+var indexEl = document.getElementsByClassName("index")[0];
+var fullLinks = fullLinkify(indexEl, bookmarks, modules, userModule);
+var search = document.getElementById('search-bar');
+search.addEventListener('keyup', debounce(filter, 100, indexEl));
+var flexIndex = new FlexSearch.Document({ document: {
+ // Only the text content gets indexed, the others get stored as-is
+ index: [{
+ field: 'text',
+ tokenize: 'full'
+ }],
+ store: ['url','app','text']
+ }
+});
+// Populate FlexSearch index
+loadSearch();
+// Render the unfiltered index list on page load
+fillIndex(indexEl, fullLinks, modules);
+// Preserve search input value during the session
+search.value = sessionStorage.getItem('searchsave');
+if (search.value !== undefined) {
+ filter(indexEl);
+}
+window.addEventListener('unload', function(event) {
+ sessionStorage.setItem('searchsave', search.value);
+});
+
+function getQuery(q) {
+ var pattern = new RegExp('[?&]' + q + '=([^&]+)');
+ var param = window.location.search.match(pattern);
+ if (param) {
+ return param[1];
+ }
+ return null;
+}
+
+function currentModule() {
+ // We need to know the module that the user is using when they call for help
+ let module = getQuery('DbPAR');
+ let moduleFromURL = regexArray[1].toUpperCase();
+ if (module == null) {
+ // first deal with snowflake Base
+ if(url.indexOf('/sdatabase/') !== -1) {
+ module = 'BASE';
+ } else {
+ if (null === regexArray || moduleFromURL === 'SHARED') {
+ // comes from search or elsewhere, no defined module in URL
+ module = 'SHARED'
+ } else {
+ // drop the 's' from the start
+ module = moduleFromURL.substring(1);
+ }
+ }
+ }
+ return module;
+};
+function fullLinkify(indexEl, bookmarks, modules, currentModule) {
+ var fullLinkified = '';
+ // if user is not on a shared category page, limit the index to the current module + shared
+ if(currentModule !== 'SHARED') {
+ bookmarks = bookmarks.filter(function(obj) {
+ return obj['app'] === currentModule || obj['app'] === 'SHARED';
+ });
+ }
+ bookmarks.forEach(function(obj) {
+ fullLinkified += '<a href="' + obj['url'] + '" class="' + obj['app'] + '" dir="auto">' + obj['text'] + '</a>';
+ });
+ return fullLinkified;
+}
+function loadSearch() {
+ bookmarks.forEach((el, i) => {
+ flexIndex.add(i, el);
+ });
+}
+function fillIndex(indexEl, content, modules) {
+ indexEl.innerHTML = content;
+ var indexKids = indexEl.children;
+ for (var i = 0, len = indexKids.length; i < len; i++) {
+ indexKids[i].removeAttribute("id");
+ }
+ modules.forEach(function(module) {
+ var moduleHeader = indexEl.getElementsByClassName(module)[0];
+ if (typeof moduleHeader !== 'undefined') {
+ // let's wrap the header in a span, so the ::before element will not become a link
+ moduleHeader.outerHTML = '<span id="' + module + '" class="' + module + '">' + moduleHeader.outerHTML + '</span>';
+ }
+ });
+ Paginator(indexEl);
+}
+// filter the index list based on search field input
+function filter(indexList) {
+ let group = [];
+ let target = search.value.trim();
+ let filtered = '';
+ if (target.length < 1) {
+ fillIndex(indexEl, fullLinks, modules);
+ return;
+ }
+ // Regex for highlighting the match
+ let regex = new RegExp(target.split(/\s+/).filter((i) => i?.length).join("|"), 'gi');
+ let results = flexIndex.search(target, { pluck: "text", enrich: true, limit: 1000 });
+
+ // Similarly to fullLinkify(), limit search results to the user's current module + shared
+ // unless they're somehow not coming from a module.
+ if(userModule !== 'SHARED') {
+ resultModules = [userModule, 'SHARED'];
+ } else {
+ resultModules = modules;
+ }
+
+ // tdf#123506 - Group the filtered list into module groups, keeping the ordering
+ modules.forEach(function(module) {
+ group[module] = '';
+ });
+ results.forEach(function(result) {
+ group[result.doc.app] += '<a href="' + result.doc.url + '" class="' + result.doc.app + '">' + result.doc.text.replace(regex, (match) => `<strong>${match}</strong>`) + '</a>';
+ });
+ resultModules.forEach(function(module) {
+ if (group[module].length > 0) {
+ filtered += group[module];
+ }
+ });
+
+ fillIndex(indexList, filtered, modules);
+};
+// delay the rendering of the filtered results while user is typing
+function debounce(fn, wait, indexList) {
+ var timeout;
+ return function() {
+ clearTimeout(timeout);
+ timeout = setTimeout(function() {
+ fn.call(this, indexList);
+ }, (wait || 150));
+ };
+}
+
+// copy pycode, sqlcode and bascode to clipboard on mouse click
+// Show border when copy is done
+divcopyable(document.getElementsByClassName("bascode"));
+divcopyable(document.getElementsByClassName("pycode"));
+divcopyable(document.getElementsByClassName("sqlcode"));
+
+function divcopyable(itemcopyable){
+for (var i = 0, len = itemcopyable.length; i < len; i++) {
+ (function() {
+ var item = itemcopyable[i];
+
+ function changeBorder(item, color) {
+ var saveBorder = item.style.border;
+ item.style.borderColor = color;
+
+ setTimeout(function() {
+ item.style.border = saveBorder;
+ }, 150);
+ }
+ item.onclick = function() {
+ document.execCommand("copy");
+ changeBorder(item, "#18A303");
+ };
+ item.addEventListener("copy", function(event) {
+ event.preventDefault();
+ if (event.clipboardData) {
+ event.clipboardData.setData("text/plain", item.textContent);
+ }
+ });
+ }());
+}
+}
+
+// copy useful content to clipboard on mouse click
+var copyable = document.getElementsByClassName("input");
+for (var i = 0, len = copyable.length; i < len; i++) {
+ (function() {
+ var item = copyable[i];
+
+ function changeColor(item, color, colorToChangeBackTo) {
+ item.style.backgroundColor = color;
+ setTimeout(function() {
+ item.style.backgroundColor = colorToChangeBackTo;
+ }, 150);
+ }
+ item.onclick = function() {
+ document.execCommand("copy");
+ changeColor(item, "#18A303", "transparent");
+ };
+ item.addEventListener("copy", function(event) {
+ event.preventDefault();
+ if (event.clipboardData) {
+ event.clipboardData.setData("text/plain", item.textContent);
+ }
+ });
+ }());
+}
+// auto-expand contents per subitem
+var pathname = window.location.pathname;
+var pathRegex = /text\/.*\.html$/;
+var linkIndex = 0;
+var contentMatch = pathname.match(pathRegex);
+function linksMatch(content) {
+ var linkMatch = new RegExp(content);
+ var links = document.getElementById("Contents").getElementsByTagName("a");
+ for (var i = 0, len = links.length; i < len; i++) {
+ if (links[i].href.match(linkMatch)) {
+ return i;
+ }
+ }
+}
+linkIndex = linksMatch(contentMatch);
+if (typeof linkIndex !== "undefined") {
+ var current = document.getElementById("Contents").getElementsByTagName("a")[linkIndex];
+ var cItem = current.parentElement;
+ var parents = [];
+ while (cItem.parentElement && !cItem.parentElement.matches("#Contents") && parents.indexOf(cItem.parentElement) == -1) {
+ parents.push(cItem = cItem.parentElement);
+ }
+ var liParents = [].filter.call(parents, function(item) {
+ return item.matches("li");
+ });
+ for (var i = 0, len = liParents.length; i < len; i++) {
+ var input = liParents[i].querySelectorAll(':scope > input');
+ document.getElementById(input[0].id).checked = true;
+ }
+ current.classList.add('contents-current');
+}
+// close navigation menus when clicking anywhere on the page
+// (ignoring menu button clicks and mobile browsing)
+document.addEventListener('click', function(event) {
+ let a11yButton = event.target.getAttribute("data-a11y-toggle");
+ let vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
+ if (!a11yButton && vw >= 960) {
+ document.querySelectorAll("[data-a11y-toggle] + nav").forEach((el) => {
+ el.setAttribute("aria-hidden", true);
+ });
+ }
+});
+// YouTube consent click. This only works for a single video.
+let youtubePlaceholder = document.querySelector(".youtube_placeholder");
+if (youtubePlaceholder) {
+ youtubePlaceholder.prepend(...document.querySelectorAll(".youtube_consent"));
+}
+function youtubeLoader(ytId, width, height) {
+ let iframeMarkup = `<iframe width="${width}" height="${height}" src="https://www.youtube-nocookie.com/embed/${ytId}?version=3" allowfullscreen="true" frameborder="0"></iframe>`;
+ let placeholder = document.getElementById(ytId);
+ placeholder.innerHTML = iframeMarkup;
+ placeholder.removeAttribute("style");
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/helpcontent2/help3xsl/help2.js b/helpcontent2/help3xsl/help2.js
new file mode 100644
index 000000000..5b9b2a970
--- /dev/null
+++ b/helpcontent2/help3xsl/help2.js
@@ -0,0 +1,267 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+ */
+// Used to set Application in caseinline=APP
+function setApplSpan(spanZ) {
+ var module = getParameterByName("DbPAR");
+ if (module === null) {
+ module = "WRITER";
+ }
+ var y = spanZ.getElementsByTagName("SPAN");
+ var n = y.length;
+ var foundAppl = false;
+ for (i = 0; i < n; i++) {
+ if (y[i].getAttribute("id") === null){
+ continue;
+ }
+ else if( y[i].getAttribute("id").startsWith(module)){
+ y[i].removeAttribute("hidden");
+ foundAppl=true;
+ }
+ }
+ for (i = 0; i < n; i++) {
+ if (y[i].getAttribute("id") === null){
+ continue;
+ }
+ else if( y[i].getAttribute("id").startsWith("default")){
+ if(!foundAppl){
+ y[i].removeAttribute("hidden");
+ }
+ }
+ }
+}
+// Used to set system in case, caseinline=SYSTEM
+function setSystemSpan(spanZ) {
+ // if no System in URL, get browser system
+ var system = getParameterByName("System");
+ if (system === null) {
+ system = getSystem();
+ }
+ var y = spanZ.getElementsByTagName("SPAN");
+ var n = y.length;
+ var foundSystem = false;
+ for (i = 0; i < n; i++) {
+ if (y[i].getAttribute("id") === null){
+ continue;
+ }
+ else if( y[i].getAttribute("id").startsWith(system)){
+ y[i].removeAttribute("hidden");
+ foundSystem=true;
+ }
+ }
+ for (i = 0; i < n; i++) {
+ if (y[i].getAttribute("id") === null){
+ continue;
+ }
+ else if( y[i].getAttribute("id").startsWith("default")){
+ if(!foundSystem){
+ y[i].removeAttribute("hidden");
+ }
+ }
+ }
+}
+
+// paint headers and headings with appl color
+
+function moduleColor (module) {
+ switch (module){
+ case "WRITER" : {color="#0369A3"; break;}
+ case "CALC" : {color="#43C330"; break;}
+ case "CHART" : {color="darkcyan"; break;}
+ case "IMPRESS": {color="#A33E03"; break;}
+ case "DRAW" : {color="#C99C00"; break;}
+ case "BASE" : {color="#8E03A3"; break;}
+ case "BASIC" : {color="black"; break;}
+ case "MATH" : {color="darkslategray"; break;}
+ case "SHARED" : {color="gray"; break;}
+ default : {color="#18A303"; break;}
+ }
+ document.getElementById("TopLeftHeader").style.background = color;
+ document.getElementById("SearchFrame").style.background = color;
+ document.getElementById("DonationFrame").style.background = color;
+ var cols = document.getElementsByClassName('tableheadcell');
+ for(i = 0; i < cols.length; i++) {cols[i].style.backgroundColor = color;};
+ for (j of [1,2,3,4,5,6]) {
+ var hh = document.getElementsByTagName("H" + j);
+ for(i = 0; i < hh.length; i++) {
+ hh[i].style.color = color;
+ hh[i].style.borderBottomColor = color;
+ }
+ }
+}
+
+// Find spans that need the switch treatment and give it to them
+var spans = document.querySelectorAll("[class^=switch]");
+var n = spans.length;
+for (z = 0; z < n; z++) {
+ var id = spans[z].getAttribute("id");
+ if (id === null) {
+ continue;
+ }
+ else if (id.startsWith("swlnsys")) {
+ setSystemSpan(spans[z]);
+ } else {
+ setApplSpan(spans[z]);
+ }
+}
+/* add &DbPAR= and &System= to the links in DisplayArea div */
+/* skip for object files */
+function fixURL(module, system) {
+ if ((DisplayArea = document.getElementById("DisplayArea")) === null) return;
+ var itemlink = DisplayArea.getElementsByTagName("a");
+ var pSystem = (system === null) ? getSystem() : system;
+ var pAppl = (module === null) ? "SHARED" : module;
+ var n = itemlink.length;
+ for (var i = 0; i < n; i++) {
+ if (itemlink[i].getAttribute("class") != "objectfiles") {
+ setURLParam(itemlink[i], pSystem, pAppl);
+ }
+ }
+}
+//Set the params inside URL
+function setURLParam(itemlink, pSystem, pAppl) {
+ var href = itemlink.getAttribute("href");
+ if (href !== null) {
+ // skip external links
+ if (!href.startsWith("http")) {
+ // handle bookmark.
+ if (href.lastIndexOf('#') != -1) {
+ var postf = href.substring(href.lastIndexOf('#'), href.length);
+ var pref = href.substring(0, href.lastIndexOf('#'));
+ itemlink.setAttribute("href", pref + "?" + '&DbPAR=' + pAppl + '&System=' + pSystem + postf);
+ } else {
+ itemlink.setAttribute("href", href + "?" + '&DbPAR=' + pAppl + '&System=' + pSystem);
+ }
+ }
+ }
+}
+
+function getSystem() {
+ var system = "Unknown OS";
+ if (navigator.appVersion.indexOf("Win") != -1) system = "WIN";
+ if (navigator.appVersion.indexOf("Mac") != -1) system = "MAC";
+ if (navigator.appVersion.indexOf("X11") != -1) system = "UNIX";
+ if (navigator.appVersion.indexOf("Linux") != -1) system = "UNIX";
+ return system;
+}
+
+function getParameterByName(name, url) {
+ if (!url) {
+ url = window.location.href;
+ }
+ name = name.replace(/[\[\]]/g, "\\$&");
+ var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)");
+ var results = regex.exec(url);
+ if (!results) {
+ return null;
+ }
+ if (!results[2]) {
+ return '';
+ }
+ return decodeURIComponent(results[2].replace(/\+/g, " "));
+}
+
+function existingLang(lang) {
+ if (lang === undefined) {
+ return 'en-US';
+ }
+
+ if (languagesSet.has(lang)) {
+ return lang;
+ }
+
+ lang = lang.replace(/[-_].*/, '');
+ if (languagesSet.has(lang)) {
+ return lang;
+ }
+
+ return 'en-US';
+}
+
+function setupModules(lang) {
+ var modulesNav = document.getElementById('modules-nav');
+ if (!modulesNav.classList.contains('loaded')) {
+ var html =
+ '<a href="' + lang + '/text/shared/05/new_help.html?DbPAR=SHARED"><div class="office-icon"></div>%PRODUCTNAME</a>' +
+ '<a href="' + lang + '/text/swriter/main0000.html?DbPAR=WRITER"><div class="writer-icon"></div>Writer</a>' +
+ '<a href="' + lang + '/text/scalc/main0000.html?DbPAR=CALC"><div class="calc-icon"></div>Calc</a>' +
+ '<a href="' + lang + '/text/simpress/main0000.html?DbPAR=IMPRESS"><div class="impress-icon"></div>Impress</a>' +
+ '<a href="' + lang + '/text/sdraw/main0000.html?DbPAR=DRAW"><div class="draw-icon"></div>Draw</a>' +
+ '<a href="' + lang + '/text/sdatabase/main.html?DbPAR=BASE"><div class="base-icon"></div>Base</a>' +
+ '<a href="' + lang + '/text/smath/main0000.html?DbPAR=MATH"><div class="math-icon"></div>Math</a>' +
+ '<a href="' + lang + '/text/schart/main0000.html?DbPAR=CHART"><div class="chart-icon"></div>Chart</a>' +
+ '<a href="' + lang + '/text/sbasic/shared/main0601.html?DbPAR=BASIC"><div class="basic-icon"></div>Basic</a>';
+ modulesNav.innerHTML = html;
+ modulesNav.classList.add('loaded');
+ }
+}
+
+function setupLanguages(page) {
+ var langNav = document.getElementById('langs-nav');
+ if (!langNav.classList.contains('loaded')) {
+ var html = '';
+ languagesSet.forEach(function(lang) {
+ html += '<a href="' + lang + page + '">' + ((lang in languageNames)? languageNames[lang]: lang) + '</a>';
+ });
+ langNav.innerHTML = html;
+ langNav.classList.add('loaded');
+ }
+}
+
+// Test, if we are online
+if (document.body.getElementsByTagName('meta')) {
+ var _paq = _paq || [];
+ /* tracker methods like "setCustomDimension" should be called before "trackPageView" */
+ _paq.push(['disableCookies']);
+ _paq.push(['trackPageView']);
+ _paq.push(['enableLinkTracking']);
+ (function() {
+ var u="//piwik.documentfoundation.org/";
+ _paq.push(['setTrackerUrl', u+'piwik.php']);
+ _paq.push(['setSiteId', '68']);
+ var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
+ g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
+ })();
+ var system = getParameterByName("System");
+} else {
+ var system = getSystem();
+}
+
+var module = getParameterByName("DbPAR");
+fixURL(module,system);
+moduleColor(module);
+var helpID = getParameterByName("HID");
+// only used in xhp pages with <help-id-missing/> tags
+var missingElement = document.getElementById("bm_HID2");
+if(missingElement != null){missingElement.innerHTML = helpID;}
+
+function debugInfo(dbg) {
+ if (dbg == null) return;
+ document.getElementById("DEBUG").style.display = "block";
+ document.getElementById("bm_module").innerHTML = "Module is: "+module;
+ document.getElementById("bm_system").innerHTML = "System is: "+system;
+ document.getElementById("bm_HID").innerHTML = "HID is: "+helpID;
+}
+
+debugInfo(getParameterByName("Debug"));
+
+// Mobile devices need the modules and langs on page load
+if (Math.max(document.documentElement.clientWidth, window.innerWidth || 0) < 960) {
+ var e = new Event('click');
+ var modulesBtn = document.getElementById('modules');
+ var langsBtn = document.getElementById('langs');
+ var modules = document.getElementById('modules-nav');
+ var langs = document.getElementById('langs-nav');
+ modules.setAttribute('data-a11y-toggle-open', '');
+ modulesBtn.dispatchEvent(e);
+ if (langs) {
+ langs.setAttribute('data-a11y-toggle-open', '');
+ langsBtn.dispatchEvent(e);
+ }
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/helpcontent2/help3xsl/index.html b/helpcontent2/help3xsl/index.html
new file mode 100644
index 000000000..69d7ee6af
--- /dev/null
+++ b/helpcontent2/help3xsl/index.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<!--
+* This file is part of the LibreOffice project.
+*
+* 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 http://mozilla.org/MPL/2.0/.
+-->
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline' 'unsafe-eval' piwik.documentfoundation.org"/>
+</head>
+<body>
+<script type="text/javascript">
+ window.location.href = 'latest/index.html';
+</script>
+</body>
+</html>
diff --git a/helpcontent2/help3xsl/index2.html b/helpcontent2/help3xsl/index2.html
new file mode 100644
index 000000000..c08335e08
--- /dev/null
+++ b/helpcontent2/help3xsl/index2.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<!--
+* This file is part of the LibreOffice project.
+*
+* 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 http://mozilla.org/MPL/2.0/.
+-->
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline' 'unsafe-eval' piwik.documentfoundation.org"/>
+ <script type="text/javascript" src="polyfills.js"></script>
+ <script type="text/javascript" src="hid2file.js"></script>
+ <script type="text/javascript" src="languages.js"></script>
+ <script type="text/javascript" src="help2.js" defer></script>
+</head>
+<body>
+<script type="text/javascript">
+ // We have to wait until both the deferred help2.js and the document have loaded
+ window.addEventListener('DOMContentLoaded', function() {
+ var url = window.location.href;
+ var n = url.indexOf('index.html?');
+ if (n != -1) {
+ // the URL came from LibreOffice help (F1)
+ var target = getParameterByName("Target",url);
+ var lang = existingLang(getParameterByName("Language", url));
+ var system = getParameterByName("System", url);
+ var module;
+ var defaultFile;
+ var smodule = target.substr(0, target.indexOf('/'));
+ switch (smodule) {
+ case "swriter": {defaultFile='text/swriter/main0000.html';module="WRITER";break;}
+ case "scalc": {defaultFile='text/scalc/main0000.html';module="CALC";break;}
+ case "schart": {defaultFile='text/schart/main0000.html';module="CHART";break;}
+ case "simpress": {defaultFile='text/simpress/main0000.html';module="IMPRESS";break;}
+ case "sdraw": {defaultFile='text/sdraw/main0000.html';module="DRAW";break;}
+ case "smath": {defaultFile='text/smath/main0000.html';module="MATH";break;}
+ case "sdatabase": {defaultFile='text/sdatabase/main.html';module="BASE";break;}
+ case "sbasic": {defaultFile='text/sbasic/shared/main0601.html';module="BASIC";break;}
+ default: {defaultFile='text/shared/05/new_help.html';module="SHARED";break;}
+ }
+ //Special case of application F1 or menu Help -> LibreOffice Help
+ if (target.indexOf('.uno:HelpIndex') != -1) {
+ window.location.replace(lang + '/' + defaultFile + '?System=' + system + '&DbPAR=' + module);
+ }
+ var bookmark = target.slice(target.indexOf('/') + 1, target.length);
+ var file = hid2fileMap[bookmark];
+ // check first if a root bookmark @@nowidget@@ can be used
+ if (file === undefined) {
+ var b2 = bookmark.substring(0, bookmark.lastIndexOf("/")) + '/@@nowidget@@';
+ file = hid2fileMap[b2];
+ }
+ // rebuild URL
+ if (file === undefined) {
+ var newURL = lang + '/text/shared/05/err_html.html?System=' + system + '&DbPAR=' + module + '&HID=' + bookmark ;
+ } else {
+ var indx = file.indexOf('#');
+ var bm = file.substr(indx,file.length);
+ file = file.substr(0,indx);
+ var newURL = lang + '/' + file + '?System=' + system + '&DbPAR=' + module + '&HID=' + bookmark + bm;
+ }
+ window.location.replace(newURL);
+ } else {
+ // URL came from elsewhere, direct access to webroot, we redirect to main Help page
+ var system = 'WIN';
+ if (navigator.userAgent.indexOf("Mac") != -1) system = 'MAC';
+ if (navigator.userAgent.indexOf("Linux") != -1) system = 'UNIX';
+ window.location.replace(existingLang(navigator.language) + '/text/shared/05/new_help.html?&DbPAR=SHARED&System=' + system);
+ }
+ });
+</script>
+</body>
+</html>
diff --git a/helpcontent2/help3xsl/normalize.css b/helpcontent2/help3xsl/normalize.css
new file mode 100644
index 000000000..47b010e47
--- /dev/null
+++ b/helpcontent2/help3xsl/normalize.css
@@ -0,0 +1,341 @@
+/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */
+
+/* Document
+ ========================================================================== */
+
+/**
+ * 1. Correct the line height in all browsers.
+ * 2. Prevent adjustments of font size after orientation changes in iOS.
+ */
+
+html {
+ line-height: 1.15; /* 1 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/* Sections
+ ========================================================================== */
+
+/**
+ * Remove the margin in all browsers.
+ */
+
+body {
+ margin: 0;
+}
+
+/**
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/* Grouping content
+ ========================================================================== */
+
+/**
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
+ */
+
+hr {
+ box-sizing: content-box; /* 1 */
+ height: 0; /* 1 */
+ overflow: visible; /* 2 */
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+pre {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/* Text-level semantics
+ ========================================================================== */
+
+/**
+ * Remove the gray background on active links in IE 10.
+ */
+
+a {
+ background-color: transparent;
+}
+
+/**
+ * 1. Remove the bottom border in Chrome 57-
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+ */
+
+abbr[title] {
+ border-bottom: none; /* 1 */
+ text-decoration: underline; /* 2 */
+ text-decoration: underline dotted; /* 2 */
+}
+
+/**
+ * Add the correct font weight in Chrome, Edge, and Safari.
+ */
+
+b,
+strong {
+ font-weight: bolder;
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+code,
+kbd,
+samp {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/**
+ * Add the correct font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+/* Embedded content
+ ========================================================================== */
+
+/**
+ * Remove the border on images inside links in IE 10.
+ */
+
+img {
+ border-style: none;
+}
+
+/* Forms
+ ========================================================================== */
+
+/**
+ * 1. Change the font styles in all browsers.
+ * 2. Remove the margin in Firefox and Safari.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 1 */
+ line-height: 1.15; /* 1 */
+ margin: 0; /* 2 */
+}
+
+/**
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
+ */
+
+button,
+input { /* 1 */
+ overflow: visible;
+}
+
+/**
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
+ */
+
+button,
+select { /* 1 */
+ text-transform: none;
+}
+
+/**
+ * Correct the inability to style clickable types in iOS and Safari.
+ */
+
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+ -webkit-appearance: button;
+}
+
+/**
+ * Remove the inner border and padding in Firefox.
+ */
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+ border-style: none;
+ padding: 0;
+}
+
+/**
+ * Restore the focus styles unset by the previous rule.
+ */
+
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+ outline: 1px dotted ButtonText;
+}
+
+/**
+ * Correct the padding in Firefox.
+ */
+
+fieldset {
+ padding: 0.35em 0.75em 0.625em;
+}
+
+/**
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ * `fieldset` elements in all browsers.
+ */
+
+legend {
+ box-sizing: border-box; /* 1 */
+ color: inherit; /* 2 */
+ display: table; /* 1 */
+ max-width: 100%; /* 1 */
+ padding: 0; /* 3 */
+ white-space: normal; /* 1 */
+}
+
+/**
+ * Add the correct vertical alignment in Chrome, Firefox, and Opera.
+ */
+
+progress {
+ vertical-align: baseline;
+}
+
+/**
+ * Remove the default vertical scrollbar in IE 10+.
+ */
+
+textarea {
+ overflow: auto;
+}
+
+/**
+ * 1. Add the correct box sizing in IE 10.
+ * 2. Remove the padding in IE 10.
+ */
+
+[type="checkbox"],
+[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Correct the cursor style of increment and decrement buttons in Chrome.
+ */
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
+ */
+
+[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ outline-offset: -2px; /* 2 */
+}
+
+/**
+ * Remove the inner padding in Chrome and Safari on macOS.
+ */
+
+[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
+ */
+
+::-webkit-file-upload-button {
+ -webkit-appearance: button; /* 1 */
+ font: inherit; /* 2 */
+}
+
+/* Interactive
+ ========================================================================== */
+
+/*
+ * Add the correct display in Edge, IE 10+, and Firefox.
+ */
+
+details {
+ display: block;
+}
+
+/*
+ * Add the correct display in all browsers.
+ */
+
+summary {
+ display: list-item;
+}
+
+/* Misc
+ ========================================================================== */
+
+/**
+ * Add the correct display in IE 10+.
+ */
+
+template {
+ display: none;
+}
+
+/**
+ * Add the correct display in IE 10.
+ */
+
+[hidden] {
+ display: none;
+}
diff --git a/helpcontent2/help3xsl/noscript.xsl b/helpcontent2/help3xsl/noscript.xsl
new file mode 100644
index 000000000..ed693867e
--- /dev/null
+++ b/helpcontent2/help3xsl/noscript.xsl
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+* This file is part of the LibreOffice project.
+*
+* 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 http://mozilla.org/MPL/2.0/.
+-->
+<!--
+Stylesheet to create the localized noscript error page.
+xsltproc noscript.xsl <browserhelp.xhp>
+-->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:include href="brand.xsl"/>
+<xsl:output indent="yes" method="html"/>
+ <xsl:param name="productname"/>
+ <xsl:param name="productversion"/>
+
+<xsl:template match="/">
+<html>
+<head>
+</head>
+<body>
+<div style="margin: 20px">
+<h1 style="color: red;">
+<xsl:call-template name="brand">
+<xsl:with-param name="string"><xsl:value-of select="//variable[@id='noscriptmsg']"/></xsl:with-param>
+</xsl:call-template>
+</h1>
+</div>
+</body>
+</html>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/helpcontent2/help3xsl/online_transform.xsl b/helpcontent2/help3xsl/online_transform.xsl
new file mode 100644
index 000000000..811abb0b4
--- /dev/null
+++ b/helpcontent2/help3xsl/online_transform.xsl
@@ -0,0 +1,1544 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:output indent="yes" method="html" doctype-system= "about:legacy-compat"/>
+
+<xsl:include href="links.txt.xsl"/>
+<!--
+############################
+# Variables and Parameters #
+############################
+//-->
+
+<xsl:param name="local" />
+<xsl:param name="root"/>
+<xsl:param name="Language"/>
+<xsl:param name="productname"/>
+<xsl:param name="productversion"/>
+<xsl:param name="xapian"/>
+
+<xsl:param name="System" select="'WIN'"/>
+<xsl:param name="imgtheme" select="''"/>
+<xsl:param name="Id" />
+
+<!-- General Usage -->
+<xsl:variable name="am" select="'&amp;'"/>
+<xsl:variable name="sl" select="'/'"/>
+<xsl:variable name="qt" select="'&quot;'"/>
+
+<!-- For calculating pixel sizes -->
+<xsl:variable name="dpi" select="'96'"/>
+<xsl:variable name="dpcm" select="'38'"/>
+<xsl:variable name="dpmm" select="'3.8'"/>
+
+<!-- Product brand variables used in the help files -->
+<xsl:variable name="brand1" select="'$[officename]'"/>
+<xsl:variable name="brand2" select="'$[officeversion]'"/>
+<xsl:variable name="brand3" select="'%PRODUCTNAME'"/>
+<xsl:variable name="brand4" select="'%PRODUCTVERSION'"/>
+
+<!-- Installation -->
+<xsl:variable name="online" select="$local!='yes'"/>
+
+<!-- meta data variables from the help file -->
+<xsl:variable name="filename" select="/helpdocument/meta/topic/filename"/>
+<xsl:variable name="title" select="/helpdocument/meta/topic/title"/>
+
+<!-- the other parameters given by the help caller -->
+
+<xsl:variable name="pversion">
+ <xsl:value-of select="translate($productversion,' ','')"/>
+</xsl:variable>
+<!-- this is were the images are -->
+
+<xsl:variable name="lang" select="$Language"/>
+<xsl:variable name="urlpre" select="$root"/>
+
+
+<!-- generic Icon alt text -->
+<xsl:variable name="alttext" select="concat($root,'text/shared/00/icon_alt.xhp')"/>
+
+ <!-- parts of help and image urls -->
+
+<xsl:variable name="img_url_prefix" select="concat('media',$imgtheme,'/')"/>
+
+<xsl:variable name="urlpost" select="concat('?Language=',$lang,$am,'System=',$System,$am,'UseDB=no')"/>
+
+<xsl:variable name="linkprefix" select="concat($lang,'/')"/>
+
+<!--<xsl:variable name="linkpostfix" select="$urlpost"/>-->
+<xsl:variable name="linkpostfix" select="''"/>
+
+<!-- images for notes, tips and warnings -->
+<xsl:variable name="iconsizestyle" select="'width:40px;height:40px;'"/>
+<xsl:variable name="note_img" select="concat($img_url_prefix,'icon-themes/res/helpimg/note.svg')"/>
+<xsl:variable name="tip_img" select="concat($img_url_prefix,'icon-themes/res/helpimg/tip.svg')"/>
+<xsl:variable name="warning_img" select="concat($img_url_prefix,'icon-themes/res/helpimg/warning.svg')"/>
+
+<!-- Strings for the help UI page -->
+<xsl:variable name="tmp_href_ui"><xsl:value-of select="concat($urlpre,'text/shared/help/browserhelp.xhp')"/></xsl:variable>
+<xsl:variable name="tmp_doc_ui" select="document($tmp_href_ui)"/>
+<xsl:variable name ="ui_contents"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='contents']"/></xsl:variable>
+<xsl:variable name ="ui_index"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='index']"/></xsl:variable>
+<xsl:variable name ="ui_pholderall"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='pholderall']"/></xsl:variable>
+<xsl:variable name ="ui_pholderchosen"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='pholderchosen']"/></xsl:variable>
+<xsl:variable name ="ui_module"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='module']"/></xsl:variable>
+<xsl:variable name ="ui_language"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='language']"/></xsl:variable>
+<xsl:variable name ="ui_donate"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='donate']"/></xsl:variable>
+<xsl:variable name ="ui_logo"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='LibreOfficeHelp']"/></xsl:variable>
+<xsl:variable name ="ui_selectmodule"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='selectmodule']"/></xsl:variable>
+<xsl:variable name ="ui_selectlang"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='selectlanguage']"/></xsl:variable>
+<xsl:variable name ="ui_search"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='searchhelpcontents']"/></xsl:variable>
+<xsl:variable name ="ui_copyclip"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='copyclip']"/></xsl:variable>
+<xsl:variable name ="ytvideobutton"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='ytbutton']"/></xsl:variable>
+<xsl:variable name ="ytaccept"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='ytaccept']"/></xsl:variable>
+<xsl:variable name ="ytpromovideoH2"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='externalvideo']"/></xsl:variable>
+<xsl:variable name ="ytprivacy"><xsl:apply-templates select="$tmp_doc_ui//variable[@id='ytprivacy']"/></xsl:variable>
+<!--
+#############
+# Templates #
+#############
+//-->
+
+<!-- Create the document skeleton -->
+<xsl:template match="/">
+ <xsl:variable name="htmlpage"><xsl:value-of select="concat(substring-before($filename,'.xhp'),'.html')"/></xsl:variable>
+ <xsl:variable name="titleL10N">
+ <xsl:call-template name="brand"><xsl:with-param name="string"><xsl:value-of select="$title"/></xsl:with-param></xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="install">
+ <xsl:call-template name="tokenize">
+ <xsl:with-param name="str" select="$filename"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="logoprodversion">
+ <xsl:choose>
+ <xsl:when test="$productversion='latest'"><xsl:value-of select="''"/></xsl:when>
+ <xsl:otherwise><xsl:value-of select="$productversion"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="direction">
+ <xsl:choose>
+ <xsl:when test="$lang='ar' or $lang='fa' or $lang='he' or $lang='sd' or $lang='ur'">
+ <xsl:value-of select="'rtl'"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="'ltr'"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+<html lang="{$lang}" dir="{$direction}">
+ <head>
+ <base href="{$install}"/>
+ <noscript><meta http-equiv="refresh" content="0; URL={$install}{$lang}/noscript.html"/></noscript>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <xsl:if test="$online">
+ <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline' 'unsafe-eval' piwik.documentfoundation.org"/>
+ </xsl:if>
+ <title><xsl:value-of disable-output-escaping="yes" select="$titleL10N"/></title>
+ <link rel="shortcut icon" href="media/navigation/favicon.ico"/>
+ <link type="text/css" href="normalize.css" rel="Stylesheet"/>
+ <link type="text/css" href="prism.css" rel="Stylesheet"/>
+ <link type="text/css" href="default.css" rel="Stylesheet"/>
+ <script type="text/javascript" src="polyfills.js"></script>
+ <script type="text/javascript" src="languages.js"></script>
+ <script type="text/javascript" src="{$lang}/langnames.js"></script>
+ <script type="text/javascript" src="flexsearch.debug.js"></script>
+ <script type="text/javascript" src="prism.js"></script>
+ <script type="text/javascript" src="help2.js" defer=""></script>
+ <script type="text/javascript" src="a11y-toggle.js" defer=""></script>
+ <script type="text/javascript" src="paginathing.js" defer=""></script>
+ <script type="text/javascript" src="{$lang}/bookmarks.js" defer=""></script>
+ <script type="text/javascript" src="{$lang}/contents.js" defer=""></script>
+ <script type="text/javascript" src="help.js" defer=""></script>
+ <meta name="viewport" content="width=device-width,initial-scale=1"/>
+ </head>
+ <body>
+
+ <header id="TopLeftHeader">
+ <a class="symbol" href="{$lang}/text/shared/05/new_help.html">
+ <div></div>
+ </a>
+ <a class="logo" href="{$lang}/text/shared/05/new_help.html">
+ <p dir="auto"><xsl:value-of disable-output-escaping="yes" select="$ui_logo"/></p>
+ </a>
+ <div class="dropdowns">
+ <div class="modules">
+ <button type="button" data-a11y-toggle="modules-nav" id="modules" onclick="setupModules('{$lang}');">
+ <xsl:value-of select="$ui_module"/>
+ </button>
+ <nav id="modules-nav"/><!-- is filled in via setupModules() on demand -->
+ </div>
+ <xsl:if test="$online">
+ <div class="lang">
+ <button type="button" data-a11y-toggle="langs-nav" id="langs" onclick="setupLanguages('{$htmlpage}');">
+ <xsl:value-of select="$ui_language"/>
+ </button>
+ <nav id="langs-nav"/><!-- is filled in via setupLanguages() on demand -->
+ </div>
+ </xsl:if>
+ </div>
+ </header>
+ <aside class="rightside">
+ <input id="accordion-1" name="accordion-menu" type="checkbox"/>
+ <label for="accordion-1" dir="auto"><xsl:value-of select="$ui_contents"/></label>
+ <div id="Contents" class="contents-treeview"></div>
+ </aside>
+ <aside class="leftside">
+ <div id="Index">
+ <div class="index-label" dir="auto"><xsl:value-of select="$ui_index"/> &#32;&#x1f50e;&#xfe0e;&#32;</div>
+ <div id="Bookmarks">
+ <xsl:variable name="pholder">
+ <xsl:choose>
+ <xsl:when test="contains($htmlpage, '/text/shared/')">
+ <xsl:value-of select="$ui_pholderall"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$ui_pholderchosen"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <input id="search-bar" type="search" class="search" placeholder="{$pholder}" dir="auto"/>
+ <nav class="index" dir="auto"></nav>
+ </div>
+ </div>
+ </aside>
+ <div id="DisplayArea" itemprop="softwareHelp" itemscope="true" itemtype="http://schema.org/SoftwareApplication">
+ <xsl:if test="$online">
+ <!-- help2.js checks, if meta elements exist in the body -->
+ <meta itemprop="applicationCategory" content="BusinessApplication"/>
+ <meta itemprop="applicationSuite" content="LibreOffice"/>
+ <meta itemprop="name" content="LibreOffice"/>
+ <meta itemprop="operatingsystem" content="Windows, Linux, MacOS"/>
+ <meta itemprop="author.name" content="The LibreOffice Documentation Team"/>
+ <meta itemprop="publisher.name" content="The Document Foundation"/>
+ <meta itemprop="softwareVersion" content="{$productversion}"/>
+ <meta itemprop="inLanguage" content="{$lang}"/>
+ <meta itemprop="datePublished" content="2020"/>
+ <meta itemprop="headline" content="{$titleL10N}"/>
+ <meta itemprop="license" content="https://www.libreoffice.org/download/license/"/>
+ <meta itemprop="image" content="media/navigation/libo-symbol-white.svg"/>
+ </xsl:if>
+ <xsl:apply-templates select="/helpdocument/body"/>
+ </div>
+ <div id="SearchFrame">
+ <xsl:if test="$online">
+ <xsl:if test="$xapian='yes'">
+ <div class="xapian-omega-search">
+ <form name="P" method="get" action="/{$productversion}/{$lang}/search" target="_top">
+ <input id="omega-autofocus" type="search" name="P" dir="auto"/>
+ <input type="submit" class="xapian-omega-search-button" value="&#x1f50d;"/>
+ </form>
+ </div>
+ </xsl:if>
+ </xsl:if>
+ </div>
+ <div id="DonationFrame">
+ <xsl:if test="$online">
+ <div class="donation">
+ <p dir="auto"><a href="https://www.libreoffice.org/donate/?pk_campaign=help" target ="_blank"><xsl:value-of select="$ui_donate"/></a></p>
+ </div>
+ </xsl:if>
+ </div>
+ <footer>
+ <xsl:if test="$online">
+ <p itemscope="true" itemtype="http://schema.org/Organization" dir="auto">
+ <meta itemprop="name" content="The Document Foundation"/>
+ <meta itemprop="legalName" content="The Document Foundation"/>
+ <meta itemprop="alternateName" content="TDF"/>
+ <meta itemprop="publishingPrinciples" content="https://www.libreoffice.org/imprint"/>
+ <a href="https://www.libreoffice.org/imprint" target="_blank">Impressum (Legal Info)</a> | <a href="https://www.libreoffice.org/privacy" target="_blank">Privacy Policy</a> | <a href="https://www.documentfoundation.org/statutes.pdf" target="_blank">Statutes (non-binding English translation)</a> - <a href="https://www.documentfoundation.org/satzung.pdf" target="_blank">Satzung (binding German version)</a> | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the <a href="https://www.libreoffice.org/download/license/" target="_blank">Mozilla Public License v2.0</a>. “LibreOffice” and “The Document Foundation” are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our <a href="https://wiki.documentfoundation.org/TradeMark_Policy" target="_blank">trademark policy</a>. LibreOffice was based on OpenOffice.org.</p>
+ </xsl:if>
+ <div id="DEBUG" class="debug">
+ <h3 class="bug">Help content debug info:</h3>
+ <p dir="auto">This page is: <a href="https://opengrok.libreoffice.org/xref/help/source{$filename}" target="_blank"><xsl:value-of select="$filename"/></a></p>
+ <p dir="auto">Title is: <xsl:value-of disable-output-escaping="yes" select="$title"/></p>
+ <p id="bm_module" dir="auto"></p>
+ <p id="bm_system" dir="auto"></p>
+ <p id="bm_HID" dir="auto"></p>
+ </div>
+ </footer>
+ </body>
+</html>
+</xsl:template>
+
+<!-- AHELP -->
+<xsl:template match="ahelp">
+ <xsl:if test="not(@visibility='hidden')"><span class="avis"><xsl:apply-templates /></span></xsl:if>
+</xsl:template>
+
+<!-- ALT -->
+<xsl:template match="alt"/>
+
+<!-- MATHML -->
+<xsl:template match="math">
+<div class="mathml"><xsl:apply-templates /></div>
+</xsl:template>
+
+<!-- BOOKMARK -->
+<xsl:template match="bookmark">
+ <a name="{@id}"></a>
+ <xsl:choose>
+ <xsl:when test="starts-with(@branch,'hid')" />
+ <xsl:otherwise><xsl:apply-templates /></xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+<xsl:template match="bookmark" mode="embedded" />
+
+<!-- BOOKMARK_VALUE -->
+<xsl:template match="bookmark_value">
+ <xsl:variable name="aux1">
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string" select="."/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:element name="meta">
+ <xsl:attribute name="itemprop">keywords</xsl:attribute>
+ <xsl:attribute name="content"><xsl:value-of select="translate($aux1,';',',')"/></xsl:attribute>
+ </xsl:element>
+</xsl:template>
+
+<!-- BR -->
+<xsl:template match="br"><br /></xsl:template>
+<xsl:template match="br" mode="embedded"><br /></xsl:template>
+
+<!-- CAPTION -->
+<xsl:template match="caption" />
+
+<!-- CASE -->
+<xsl:template match="case"><xsl:call-template name="insertcase" /></xsl:template>
+<xsl:template match="case" mode="embedded">
+ <xsl:call-template name="insertcase">
+ <xsl:with-param name="embedded" select="'yes'"/>
+ </xsl:call-template>
+</xsl:template>
+
+<!-- CASEINLINE -->
+<xsl:template match="caseinline"><xsl:call-template name="insertcase" /></xsl:template>
+<xsl:template match="caseinline" mode="embedded">
+ <xsl:call-template name="insertcase">
+ <xsl:with-param name="embedded" select="'yes'"/>
+ </xsl:call-template>
+</xsl:template>
+
+<!-- COMMENT -->
+<xsl:template match="comment" />
+<xsl:template match="comment" mode="embedded"/>
+
+<!-- CREATED -->
+<xsl:template match="created" />
+
+<!-- DEFAULT -->
+<xsl:template match="default"><xsl:call-template name="insertdefault" /></xsl:template>
+<xsl:template match="default" mode="embedded">
+ <xsl:call-template name="insertdefault">
+ <xsl:with-param name="embedded" select="'yes'"/>
+ </xsl:call-template>
+</xsl:template>
+
+<!-- DEFAULTINLINE -->
+<xsl:template match="defaultinline"><xsl:call-template name="insertdefault" /></xsl:template>
+<xsl:template match="defaultinline" mode="embedded">
+ <xsl:call-template name="insertdefault">
+ <xsl:with-param name="embedded" select="'yes'"/>
+ </xsl:call-template>
+</xsl:template>
+
+<!-- EMBED -->
+<xsl:template match="embed"><xsl:call-template name="resolveembed"/></xsl:template>
+<xsl:template match="embed" mode="embedded"><xsl:call-template name="resolveembed"/></xsl:template>
+
+<!-- EMBEDVAR -->
+<xsl:template match="embedvar"><xsl:call-template name="resolveembedvar"/></xsl:template>
+<xsl:template match="embedvar" mode="embedded"><xsl:call-template name="resolveembedvar"/></xsl:template>
+
+<!-- EMPH -->
+<xsl:template match="emph">
+ <span class="emph"><xsl:apply-templates /></span>
+</xsl:template>
+<xsl:template match="emph" mode="embedded">
+ <span class="emph"><xsl:apply-templates /></span>
+</xsl:template>
+
+<!-- SUB -->
+<xsl:template match="sub">
+ <sub><xsl:apply-templates /></sub>
+</xsl:template>
+<xsl:template match="sub" mode="embedded">
+ <sub><xsl:apply-templates /></sub>
+</xsl:template>
+
+<!-- SUP -->
+<xsl:template match="sup">
+ <sup><xsl:apply-templates /></sup>
+</xsl:template>
+<xsl:template match="sup" mode="embedded">
+ <sup><xsl:apply-templates /></sup>
+</xsl:template>
+
+<!-- FILENAME -->
+<xsl:template match="filename"/>
+
+<!-- HISTORY -->
+<xsl:template match="history" />
+
+<!-- IMAGE -->
+<xsl:template match="image"><xsl:call-template name="insertimage"/></xsl:template>
+<xsl:template match="image" mode="embedded"><xsl:call-template name="insertimage"/></xsl:template>
+
+<!-- ITEM -->
+<xsl:template match="item">
+ <span class="{@type}">
+<!-- Insert tooltip only to input classes and only if the content is longer than 3 characters -->
+ <xsl:if test="@type='input' and string-length(.)>3">
+ <xsl:attribute name="data-tooltip">
+ <xsl:value-of select="$ui_copyclip"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates />
+ </span>
+</xsl:template>
+<xsl:template match="item" mode="embedded">
+ <span class="{@type}">
+ <xsl:if test="@type='input' and string-length(.)>3">
+ <xsl:attribute name="data-tooltip">
+ <xsl:value-of select="$ui_copyclip"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates />
+ </span>
+</xsl:template>
+
+<!-- LINK -->
+<xsl:template match="link">
+ <xsl:choose> <!-- don't insert the heading link to itself -->
+ <xsl:when test="(concat('/',@href) = /helpdocument/meta/topic/filename) or (@href = /helpdocument/meta/topic/filename)">
+ <xsl:apply-templates />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="createlink" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+<xsl:template match="link" mode="embedded">
+ <xsl:call-template name="createlink"/>
+</xsl:template>
+
+<!-- LIST -->
+<xsl:template match="list">
+ <xsl:call-template name="insertlist"/>
+</xsl:template>
+
+<xsl:template match="list" mode="embedded">
+ <xsl:call-template name="insertlist"/>
+</xsl:template>
+
+<!-- LISTITEM -->
+<xsl:template match="listitem">
+ <xsl:call-template name="insertlistitem"/>
+</xsl:template>
+<xsl:template match="listitem" mode="embedded">
+ <xsl:call-template name="insertlistitem"/>
+</xsl:template>
+
+<!-- META, SEE HEADER -->
+<xsl:template match="meta" />
+
+<!-- OBJECT -->
+<xsl:template match="object">
+ <xsl:if test="$online">
+ <xsl:call-template name="insertobject"/>
+ </xsl:if>
+</xsl:template>
+<xsl:template match="object" mode="embedded">
+ <xsl:if test="$online">
+ <xsl:call-template name="insertobject"/>
+ </xsl:if>
+</xsl:template>
+
+<!-- PARAGRAPH -->
+<xsl:template match="paragraph">
+ <xsl:choose>
+
+ <xsl:when test="@role='heading'">
+ <xsl:call-template name="insertheading">
+ <xsl:with-param name="level" select="@level"/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:when test="@role='note' or @role='tip' or @role='warning'">
+ <xsl:call-template name="insertnote">
+ <xsl:with-param name="type" select="@role" />
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:when test="@role='bascode' or @role='pycode' or @role='sqlcode'">
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string" select="."/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:when test="@role='smathcode'">
+ <p id="{@id}" class="smathcode" dir="auto"><span class="input" data-tooltip="{$ui_copyclip}"><xsl:apply-templates /></span></p>
+ </xsl:when>
+
+ <xsl:when test="@role='logocode'">
+ <xsl:call-template name="insertlogocode" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:call-template name="insertpara" />
+ </xsl:otherwise>
+
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="paragraph" mode="embedded">
+ <xsl:choose>
+ <xsl:when test="@role='heading'"> <!-- increase the level of headings that are embedded -->
+ <xsl:variable name="newlevel">
+ <xsl:choose>
+ <xsl:when test="@level='1'"><xsl:value-of select="'2'"/></xsl:when>
+ <xsl:otherwise><xsl:value-of select="@level"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:call-template name="insertheading">
+ <xsl:with-param name="level" select="$newlevel"/>
+ <xsl:with-param name="embedded" select="'yes'"/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:when test="@role='note' or @role='tip' or @role='warning'">
+ <xsl:call-template name="insertnote">
+ <xsl:with-param name="type" select="@role" />
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:when test="@role='bascode' or @role='pycode' or @role='sqlcode'">
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string" select="."/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:when test="@role='smathcode'">
+ <p id="{@id}" class="smathcode" dir="auto"><span class="input" data-tooltip="{$ui_copyclip}"><xsl:apply-templates /></span></p>
+ </xsl:when>
+
+ <xsl:when test="@role='logocode'">
+ <xsl:call-template name="insertlogocode" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="insertpara" />
+ </xsl:otherwise>
+
+ </xsl:choose>
+</xsl:template>
+
+<!-- SECTION -->
+<xsl:template match="section">
+ <a name="{@id}"></a>
+ <xsl:choose>
+ <xsl:when test="@id='relatedtopics'">
+ <div class="relatedtopics">
+ <!--<xsl:variable name="href"><xsl:value-of select="concat($urlpre,'text/shared/00/00000004.xhp',$urlpost)"/></xsl:variable>-->
+ <xsl:variable name="href"><xsl:value-of select="concat($urlpre,'text/shared/00/00000004.xhp')"/></xsl:variable>
+ <xsl:variable name="anchor"><xsl:value-of select="'related'"/></xsl:variable>
+ <xsl:variable name="doc" select="document($href)"/>
+ <p class="related" itemprop="mentions" dir="auto">
+ <xsl:apply-templates select="$doc//variable[@id=$anchor]"/>
+ </p>
+ <div class="relatedbody" itemprop="mentions">
+ <xsl:apply-templates />
+ </div>
+ </div>
+ </xsl:when>
+ <xsl:when test="@id='howtoget'">
+ <xsl:call-template name="insert_howtoget" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- SECTION -->
+<xsl:template match="section" mode="embedded">
+ <a name="{@id}"></a>
+ <xsl:apply-templates mode="embedded"/>
+</xsl:template>
+
+<!-- SORT -->
+<xsl:template match="sort" >
+ <xsl:variable name="order1">
+ <xsl:choose>
+ <xsl:when test="string-length(@order) = 0"><xsl:value-of select="'ascending'"/></xsl:when>
+ <xsl:otherwise><xsl:value-of select="concat(@order,'ending')"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="string-length(@descendant)=0">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::paragraph"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:when test="@descendant='h1'">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::h1"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:when test="@descendant='h2'">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::h2"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:when test="@descendant='h3'">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::h3"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:when test="@descendant='h4'">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::h4"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:when test="@descendant='h5'">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::h5"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:when test="@descendant='h6'">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::h6"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::paragraph"/></xsl:apply-templates>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+<xsl:template match="sort" mode="embedded">
+ <xsl:variable name="order1">
+ <xsl:choose>
+ <xsl:when test="string-length(@order) = 0"><xsl:value-of select="'ascending'"/></xsl:when>
+ <xsl:otherwise><xsl:value-of select="concat(@order,'ending')"/></xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="string-length(@descendant)=0">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::paragraph"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:when test="@descendant='h1'">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::h1"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:when test="@descendant='h2'">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::h2"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:when test="@descendant='h3'">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::h3"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:when test="@descendant='h4'">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::h4"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:when test="@descendant='h5'">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::h5"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:when test="@descendant='h6'">
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::h6"/></xsl:apply-templates>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates><xsl:sort lang="{$lang}" order="{$order1}" select="descendant::paragraph"/></xsl:apply-templates>
+ </xsl:otherwise>
+ </xsl:choose>
+
+</xsl:template>
+
+<!-- SWITCH -->
+<xsl:template match="switch">
+ <xsl:variable name="idsw">
+ <xsl:value-of select="//meta/topic/@id" /><xsl:number level="any" count="switch|switchinline" format="_1"/>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test ="@select = 'sys'">
+ <span id="swlnsys{$idsw}" class="switch">
+ <xsl:apply-templates />
+ </span>
+ </xsl:when>
+ <xsl:when test ="@select = 'appl'">
+ <span id="swlnappl{$idsw}" class="switch">
+ <xsl:apply-templates />
+ </span>
+ </xsl:when>
+ <xsl:otherwise>
+ <p class="debug" dir="auto">Unsupported switch condition.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+<xsl:template match="switch" mode="embedded">
+ <xsl:variable name="idsw">
+ <xsl:value-of select="//meta/topic/@id" /><xsl:number level="any" count="switch|switchinline" format="_1"/>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test ="@select = 'sys'">
+ <span id="swlnsys{$idsw}" class="switch">
+ <xsl:apply-templates mode="embedded"/>
+ </span>
+ </xsl:when>
+ <xsl:when test ="@select = 'appl'">
+ <span id="swlnappl{$idsw}" class="switch">
+ <xsl:apply-templates mode="embedded"/>
+ </span>
+ </xsl:when>
+ <xsl:otherwise>
+ <p class="debug" dir="auto">Unsupported switch condition.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- SWITCHINLINE -->
+<xsl:template match="switchinline">
+ <xsl:variable name="idsw">
+ <xsl:value-of select="//meta/topic/@id" /><xsl:number level="any" count="switch|switchinline" format="_1"/>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test ="@select = 'sys'">
+ <span id="swlnsys{$idsw}" class="switchinline">
+ <xsl:apply-templates />
+ </span>
+ </xsl:when>
+ <xsl:when test ="@select = 'appl'">
+ <span id="swlnappl{$idsw}" class="switchinline">
+ <xsl:apply-templates />
+ </span>
+ </xsl:when>
+ <xsl:otherwise>
+ <p class="debug" dir="auto">Unsupported switch condition.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+<xsl:template match="switchinline" mode="embedded">
+ <xsl:variable name="idsw">
+ <xsl:value-of select="//meta/topic/@id" /><xsl:number level="any" count="switch|switchinline" format="_1"/>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test ="@select = 'sys'">
+ <span id="swlnsys{$idsw}" class="switchinline">
+ <xsl:apply-templates mode="embedded"/>
+ </span>
+ </xsl:when>
+ <xsl:when test ="@select = 'appl'">
+ <span id="swln{@select}_{$idsw}" class="switchinline">
+ <xsl:apply-templates mode="embedded"/>
+ </span>
+ </xsl:when>
+ <xsl:otherwise>
+ <p class="debug" dir="auto">Unsupported switch condition.</p>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- TABLE -->
+<xsl:template match="table"><xsl:call-template name="inserttable"/></xsl:template>
+<xsl:template match="table" mode="embedded"><xsl:call-template name="inserttable"/></xsl:template>
+
+<!-- TABLECELL -->
+<xsl:template match="tablecell">
+ <xsl:choose>
+ <xsl:when test="paragraph[@role='tablehead']">
+ <th rowspan="{@rowspan}" colspan="{@colspan}" class='tableheadcell' dir="auto"><xsl:apply-templates /></th>
+ </xsl:when>
+ <xsl:otherwise>
+ <td rowspan="{@rowspan}" colspan="{@colspan}" dir="auto"><xsl:apply-templates /></td>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+<xsl:template match="tablecell" mode="onecell"><xsl:apply-templates/></xsl:template>
+<xsl:template match="tablecell" mode="icontable"><div class="iconcell"><xsl:apply-templates/></div></xsl:template>
+<xsl:template match="tablecell" mode="embedded">
+ <xsl:choose>
+ <xsl:when test="paragraph[@role='tablehead']">
+ <th rowspan="{@rowspan}" colspan="{@colspan}" class='tableheadcell' dir="auto"><xsl:apply-templates mode="embedded"/></th>
+ </xsl:when>
+ <xsl:otherwise>
+ <td rowspan="{@rowspan}" colspan="{@colspan}" dir="auto"><xsl:apply-templates mode="embedded"/></td>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- TABLEROW -->
+<xsl:template match="tablerow"><tr><xsl:apply-templates /></tr></xsl:template>
+<xsl:template match="tablerow" mode="onecell"><xsl:apply-templates mode="onecell"/></xsl:template>
+<xsl:template match="tablerow" mode="icontable"><div class="icontable"><xsl:apply-templates mode="icontable"/></div></xsl:template>
+<xsl:template match="tablerow" mode="embedded"><tr><xsl:apply-templates mode="embedded"/></tr></xsl:template>
+
+<!-- TABLEHEAD -->
+<xsl:template match="tablehead"><thead><xsl:apply-templates /></thead></xsl:template>
+
+<!-- TITLE -->
+<xsl:template match="title"/>
+
+<!-- TOPIC -->
+<xsl:template match="topic"/>
+
+<!-- VARIABLE -->
+<xsl:template match="variable"><a name="{@id}"></a><xsl:apply-templates /></xsl:template>
+<xsl:template match="variable" mode="embedded"><a name="{@id}"></a><xsl:apply-templates mode="embedded"/></xsl:template>
+
+<xsl:template match="text()">
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string"><xsl:value-of select="."/></xsl:with-param>
+ </xsl:call-template>
+</xsl:template>
+
+<xsl:template match="text()" mode="embedded">
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string"><xsl:value-of select="."/></xsl:with-param>
+ </xsl:call-template>
+</xsl:template>
+
+<!-- XHP extensions (2018) -->
+<!-- H1-H6 -->
+<xsl:template match="h1 | h2 | h3 | h4 | h5 | h6">
+ <xsl:element name="{local-name()}">
+ <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
+ <xsl:attribute name="dir">auto</xsl:attribute>
+ <xsl:apply-templates />
+ </xsl:element>
+</xsl:template>
+<xsl:template match="h1 | h2 | h3 | h4 | h5 | h6" mode="embedded">
+ <xsl:element name="{concat('h',substring-after(local-name(),'h') + 1)}">
+ <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
+ <xsl:attribute name="dir">auto</xsl:attribute>
+ <xsl:apply-templates mode="embedded"/>
+ </xsl:element>
+</xsl:template>
+
+<!-- INPUT -->
+<xsl:template match="input">
+ <span class="input" data-tooltip="{$ui_copyclip}"><xsl:apply-templates /></span>
+</xsl:template>
+<xsl:template match="input" mode="embedded">
+ <span class="input" data-tooltip="{$ui_copyclip}"><xsl:apply-templates mode="embedded"/></span>
+</xsl:template>
+
+<!--MENUITEM, KEYCODE, LITERAL, WIDGET-->
+<xsl:template match="menuitem | keycode | literal | widget">
+ <span class="{local-name()}"><xsl:apply-templates /></span>
+</xsl:template>
+<xsl:template match="menuitem | input | keycode | literal" mode="embedded">
+ <span class="{local-name()}"><xsl:apply-templates mode="embedded"/></span>
+</xsl:template>
+
+<!--NOTE TIP AND WARNING-->
+<xsl:template match="tip | note | warning">
+ <xsl:variable name="imgsrc">
+ <xsl:choose>
+ <xsl:when test="local-name()='note'"><xsl:value-of select="$note_img"/></xsl:when>
+ <xsl:when test="local-name()='tip'"><xsl:value-of select="$tip_img"/></xsl:when>
+ <xsl:when test="local-name()='warning'"><xsl:value-of select="$warning_img"/></xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+ <div class="{local-name()}">
+ <div class="noteicon" dir="auto"><img src="{$imgsrc}" alt="{local-name()}" style="{$iconsizestyle}"/></div>
+ <div class="notetext"><p id="{@id}" dir="auto"><xsl:apply-templates /></p></div>
+ </div>
+ <br/>
+</xsl:template>
+<xsl:template match="tip | note | warning" mode="embedded">
+ <xsl:variable name="imgsrc">
+ <xsl:choose>
+ <xsl:when test="local-name()='note'"><xsl:value-of select="$note_img"/></xsl:when>
+ <xsl:when test="local-name()='tip'"><xsl:value-of select="$tip_img"/></xsl:when>
+ <xsl:when test="local-name()='warning'"><xsl:value-of select="$warning_img"/></xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+ <div class="{local-name()}">
+ <div class="noteicon" dir="auto"><img src="{$imgsrc}" alt="{local-name()}" style="{$iconsizestyle}"/></div>
+ <div class="notetext"><p id="{@id}" dir="auto"><xsl:apply-templates mode="embedded"/></p></div>
+ </div>
+ <br/>
+</xsl:template>
+
+<!--SQLCODE, BASCODE, PYCODE-->
+<xsl:template match="bascode | pycode | sqlcode">
+ <xsl:variable name="codelangclass">
+ <xsl:choose>
+ <xsl:when test="local-name()='bascode'"><xsl:text>language-visual-basic line-numbers</xsl:text></xsl:when>
+ <xsl:when test="local-name()='pycode'"><xsl:text>language-python line-numbers</xsl:text></xsl:when>
+ <xsl:when test="local-name()='sqlcode'"><xsl:text>language-sql</xsl:text></xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+ <div class="{local-name()}" itemscope="true" itemtype="http://schema.org/SoftwareSourceCode" itemprop="codeSampleType" content="snippet">
+ <xsl:attribute name="data-tooltip"><xsl:value-of select="$ui_copyclip"/></xsl:attribute>
+ <pre dir="auto"><code class="{$codelangclass}"><xsl:apply-templates /></code></pre>
+ </div>
+</xsl:template>
+<xsl:template match="bascode | pycode | sqlcode" mode="embedded">
+ <xsl:variable name="codelangclass">
+ <xsl:choose>
+ <xsl:when test="local-name()='bascode'"><xsl:text>language-visual-basic line-numbers</xsl:text></xsl:when>
+ <xsl:when test="local-name()='pycode'"><xsl:text>language-python line-numbers</xsl:text></xsl:when>
+ <xsl:when test="local-name()='sqlcode'"><xsl:text>language-sql</xsl:text></xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+ <div class="{local-name()}" itemscope="true" itemtype="http://schema.org/SoftwareSourceCode" itemprop="codeSampleType" content="snippet">
+ <xsl:attribute name="data-tooltip"><xsl:value-of select="$ui_copyclip"/></xsl:attribute>
+ <pre dir="auto"><code class="{$codelangclass}"><xsl:apply-templates /></code></pre>
+ </div>
+</xsl:template>
+<!-- In case of missing help files -->
+<xsl:template match="help-id-missing">
+<span id="bm_HID2"></span>
+</xsl:template>
+
+<!--
+###################
+# NAMED TEMPLATES #
+###################
+//-->
+
+<!-- Branding -->
+<xsl:template name="brand" >
+ <xsl:param name="string"/>
+
+ <xsl:choose>
+
+ <xsl:when test="contains($string,$brand1)">
+ <xsl:variable name="newstr">
+ <xsl:value-of select="substring-before($string,$brand1)"/>
+ <xsl:value-of select="$productname"/>
+ <xsl:value-of select="substring-after($string,$brand1)"/>
+ </xsl:variable>
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string" select="$newstr"/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:when test="contains($string,$brand2)">
+ <xsl:variable name="newstr">
+ <xsl:value-of select="substring-before($string,$brand2)"/>
+ <xsl:value-of select="$pversion"/>
+ <xsl:value-of select="substring-after($string,$brand2)"/>
+ </xsl:variable>
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string" select="$newstr"/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:when test="contains($string,$brand3)">
+ <xsl:variable name="newstr">
+ <xsl:value-of select="substring-before($string,$brand3)"/>
+ <xsl:value-of select="$productname"/>
+ <xsl:value-of select="substring-after($string,$brand3)"/>
+ </xsl:variable>
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string" select="$newstr"/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:when test="contains($string,$brand4)">
+ <xsl:variable name="newstr">
+ <xsl:value-of select="substring-before($string,$brand4)"/>
+ <xsl:value-of select="$pversion"/>
+ <xsl:value-of select="substring-after($string,$brand4)"/>
+ </xsl:variable>
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string" select="$newstr"/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:value-of select="$string"/>
+ </xsl:otherwise>
+ </xsl:choose>
+
+</xsl:template>
+
+<!-- Insert list item -->
+<xsl:template name="insertlistitem">
+ <xsl:choose>
+ <xsl:when test="ancestor::list[@type='ordered']">
+ <li itemprop="itemListElement" itemscope="true" itemtype="http://schema.org/HowToStep" dir="auto">
+ <xsl:apply-templates />
+ </li>
+ </xsl:when>
+ <xsl:otherwise>
+ <li itemprop="itemListElement" itemscope="true" itemtype="http://schema.org/ItemListUnordered" dir="auto">
+ <xsl:apply-templates />
+ </li>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- insert List -->
+<xsl:template name="insertlist">
+ <xsl:choose>
+ <xsl:when test="@type='ordered'">
+ <ol itemprop="HowTo" itemscope="true" itemtype="http://schema.org/HowToSection" dir="auto">
+ <xsl:if test="@startwith != ''">
+ <xsl:attribute name="start"><xsl:value-of select="@startwith"/></xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates />
+ </ol>
+ </xsl:when>
+ <xsl:otherwise>
+ <ul itemprop="Unordered" itemscope="true" itemtype="http://schema.org/ItemList" dir="auto">
+ <xsl:apply-templates />
+ </ul>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- Insert Paragraph -->
+<xsl:template name="insertpara">
+ <xsl:variable name="role">
+ <xsl:choose>
+ <xsl:when test="ancestor::table">
+ <xsl:value-of select="concat(@role,'intable')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@role"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <p id="{@id}" class="{$role}" dir="auto"><xsl:apply-templates /></p>
+</xsl:template>
+
+<!-- Insert Logo code snippet -->
+<xsl:template name="insertlogocode">
+ <pre dir="auto"><xsl:apply-templates /></pre>
+</xsl:template>
+
+<!-- Insert "How to get Link" -->
+<xsl:template name="insert_howtoget">
+ <xsl:param name="linkhref" />
+ <xsl:variable name="archive" select="'shared'"/>
+ <xsl:variable name="tmp_href"><xsl:value-of select="concat($urlpre,'text/shared/00/00000004.xhp')"/></xsl:variable>
+ <xsl:variable name="tmp_doc" select="document($tmp_href)"/>
+ <div class="howtoget">
+ <div>
+ <p class="howtogetheader" dir="auto"><xsl:apply-templates select="$tmp_doc//variable[@id='wie']"/></p>
+ </div>
+ <div class="howtogetbody">
+ <xsl:choose>
+ <xsl:when test="$linkhref = ''"> <!-- new style -->
+ <xsl:apply-templates/>
+ </xsl:when>
+ <xsl:otherwise> <!-- old style -->
+ <xsl:variable name="href"><xsl:value-of select="concat($urlpre,substring-before($linkhref,'#'))"/></xsl:variable>
+ <xsl:variable name="anc"><xsl:value-of select="substring-after($linkhref,'#')"/></xsl:variable>
+ <xsl:variable name="docum" select="document($href)"/>
+ <xsl:call-template name="insertembed">
+ <xsl:with-param name="doc" select="$docum" />
+ <xsl:with-param name="anchor" select="$anc" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </div>
+ </div>
+ <br/>
+</xsl:template>
+
+<!-- Create a link -->
+<xsl:template name="createlink">
+ <xsl:choose>
+ <xsl:when test="starts-with(@href,'http://') or starts-with(@href,'https://')"> <!-- web links -->
+ <a target ="_blank" href="{@href}"><xsl:apply-templates /></a>
+ </xsl:when>
+ <xsl:when test="contains(@href,'#')"> <!-- internal links with bookmark -->
+ <xsl:variable name="anchor"><xsl:value-of select="concat('#',substring-after(@href,'#'))"/></xsl:variable>
+ <xsl:variable name="href"><xsl:value-of select="concat($linkprefix,substring-before(@href, 'xhp'),'html',$anchor,$linkpostfix)"/></xsl:variable>
+ <a target ="_top" href="{$href}"><xsl:apply-templates /></a>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="href"><xsl:value-of select="concat($linkprefix,substring-before(@href, 'xhp'),'html',$linkpostfix)"/></xsl:variable>
+ <a target ="_top" href="{$href}"><xsl:apply-templates /></a>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- Insert Note, Warning, or Tip -->
+<xsl:template name="insertnote">
+ <xsl:param name="type" /> <!-- note, tip, or warning -->
+ <xsl:variable name="imgsrc">
+ <xsl:choose>
+ <xsl:when test="$type='note'"><xsl:value-of select="$note_img"/></xsl:when>
+ <xsl:when test="$type='tip'"><xsl:value-of select="$tip_img"/></xsl:when>
+ <xsl:when test="$type='warning'"><xsl:value-of select="$warning_img"/></xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="alt">
+ <xsl:variable name="href"><xsl:value-of select="$alttext"/></xsl:variable>
+ <xsl:variable name="anchor"><xsl:value-of select="concat('alt_',$type)"/></xsl:variable>
+ <xsl:variable name="doc" select="document($href)"/>
+ <xsl:apply-templates select="$doc//variable[@id=$anchor]" mode="embedded"/>
+ </xsl:variable>
+ <div class="{$type}">
+ <div class="noteicon" dir="auto"><img src="{$imgsrc}" alt="{$alt}" style="{$iconsizestyle}"/></div>
+ <div class="notetext"><p dir="auto"><xsl:apply-templates /></p></div>
+ </div>
+ <br/>
+</xsl:template>
+
+<!-- Insert a heading -->
+<xsl:template name="insertheading">
+ <xsl:param name="level" />
+ <xsl:param name="embedded" />
+ <xsl:element name="{concat('h',$level)}">
+ <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
+ <xsl:attribute name="dir">auto</xsl:attribute>
+ <xsl:choose>
+ <xsl:when test="$embedded = 'yes'">
+ <xsl:apply-templates mode="embedded"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:element>
+</xsl:template>
+
+<!-- Evaluate a case or caseinline switch -->
+<xsl:template name="insertcase">
+ <xsl:param name="embedded" />
+ <xsl:variable name="auxID">
+ <xsl:value-of select="//meta/topic/@id" /><xsl:number level="any" count="switch|switchinline" format="_1"/>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="$embedded = 'yes'">
+ <span hidden="true" id="{@select}{$auxID}" class="{@select}"><xsl:apply-templates mode="embedded"/></span>
+ </xsl:when>
+ <xsl:otherwise>
+ <span hidden="true" id="{@select}{$auxID}" class="{@select}"><xsl:apply-templates/></span>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- Evaluate a default or defaultinline switch -->
+<xsl:template name="insertdefault">
+ <xsl:param name="embedded" />
+ <xsl:variable name="auxID">
+ <xsl:value-of select="//meta/topic/@id" /><xsl:number level="any" count="switch|switchinline" format="_1"/>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="parent::switch[@select='sys'] or parent::switchinline[@select='sys']">
+ <xsl:choose>
+ <xsl:when test="$embedded = 'yes'">
+ <span hidden="true" id="default{$auxID}"><xsl:apply-templates mode="embedded"/></span>
+ </xsl:when>
+ <xsl:otherwise>
+ <span hidden="true" id="default{$auxID}"><xsl:apply-templates /></span>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:when test="parent::switch[@select='appl'] or parent::switchinline[@select='appl']">
+ <xsl:choose>
+ <xsl:when test="$embedded = 'yes'">
+ <span hidden="true" id="default{$auxID}"><xsl:apply-templates mode="embedded"/></span>
+ </xsl:when>
+ <xsl:otherwise>
+ <span hidden="true" id="default{$auxID}"><xsl:apply-templates /></span>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:when test="parent::switch[@select='distrib'] or parent::switchinline[@select='distrib']"><!--TODO: fix this distrib case if relevant-->
+ <xsl:if test="not(../child::case[@select=$distrib]) and not(../child::caseinline[@select=$distrib])">
+ <xsl:choose>
+ <xsl:when test="$embedded = 'yes'">
+ <span hidden="true" itemprop="distrib" value="DEFDIST"><xsl:apply-templates mode="embedded"/></span>
+ </xsl:when>
+ <xsl:otherwise>
+ <span hidden="true" itemprop="distrib" value="DEFDIST"><xsl:apply-templates /></span>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:when>
+ </xsl:choose>
+</xsl:template>
+
+<!-- evaluate embeds -->
+<xsl:template name="insertembed">
+ <xsl:param name="doc" />
+ <xsl:param name="anchor" />
+ <!-- different embed targets (also falsely used embed instead embedvar) -->
+ <xsl:choose>
+ <xsl:when test="$doc//section[@id=$anchor]"> <!-- first test for a section of that name -->
+ <xsl:apply-templates select="$doc//section[@id=$anchor]" mode="embedded"/>
+ </xsl:when>
+ <xsl:when test="$doc//paragraph[@id=$anchor]"> <!-- then test for a para of that name -->
+ <p class="embedded" dir="auto">
+ <xsl:apply-templates select="$doc//paragraph[@id=$anchor]" mode="embedded"/>
+ </p>
+ </xsl:when>
+ <xsl:when test="$doc//variable[@id=$anchor]"> <!-- then test for a variable of that name -->
+ <p class="embedded" dir="auto">
+ <xsl:apply-templates select="$doc//variable[@id=$anchor]" mode="embedded"/>
+ </p>
+ </xsl:when>
+ <xsl:otherwise> <!-- then give up -->
+ <p class="bug" dir="auto">D'oh! You found a bug (<xsl:value-of select="@href"/> not found).</p>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- Insert an image -->
+<xsl:template name="insertimage">
+ <xsl:variable name="src2">
+ <xsl:choose>
+ <xsl:when test="starts-with(@src,'media/screenshots/')">
+ <xsl:choose>
+ <xsl:when test="not(@localize=false) and not($lang='en-US')">
+ <xsl:variable name="tmp0" select="substring-before(@src, '/ui/')"/>
+ <xsl:variable name="tmp1" select="substring-after(@src, '/ui/')"/>
+ <xsl:variable name="tmp2" select="substring-before($tmp1,'/')"/>
+ <xsl:variable name="tmp3" select="substring-after($tmp1,'/')"/>
+ <xsl:value-of select="concat($tmp0,'/ui/', $tmp2, '/',$lang,'/',$tmp3)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@src"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <!-- generic media file -->
+ <xsl:when test="starts-with(@src,'media/')">
+ <xsl:value-of select="@src"/>
+ </xsl:when>
+ <!-- handle icons -->
+ <xsl:when test="not(starts-with(@src,'media/'))">
+ <xsl:variable name="linklist">
+ <xsl:call-template name="linktxt"><xsl:with-param name="src1" select="@src"/></xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="aux00">
+ <xsl:choose>
+ <xsl:when test="substring($linklist,string-length($linklist) - 3, 4)='.png'">
+ <xsl:value-of select="concat(substring-before($linklist,'.png'),'.svg')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$linklist"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:value-of select="concat('media/icon-themes/',$aux00)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@src"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="imagestyle">
+ <xsl:choose>
+ <xsl:when test="starts-with(@src,'media/screenshots/')">
+ <xsl:value-of select="'screenshot'"/>
+ </xsl:when>
+ <xsl:when test="starts-with(@src,'media/')">
+ <xsl:value-of select="'genericimage'"/>
+ </xsl:when>
+ <xsl:when test="not(starts-with(@src,'media/'))">
+ <xsl:value-of select="'iconimage'"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="'genericimage'"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="property">
+ <xsl:choose>
+ <xsl:when test="starts-with(@src,'media/screenshots/')">
+ <xsl:value-of select="'screenshot'"/>
+ </xsl:when>
+ <xsl:when test="starts-with(@src,'media/')">
+ <xsl:value-of select="'image'"/>
+ </xsl:when>
+ <xsl:when test="not(starts-with(@src,'media/'))">
+ <xsl:value-of select="'icon'"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="'image'"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="alt"><xsl:value-of select="./alt"/></xsl:variable>
+ <xsl:variable name="width">
+ <xsl:if test="string-length(@width)!=0">
+ <xsl:call-template name="convert2px"><xsl:with-param name="value" select="@width"/></xsl:call-template>
+ </xsl:if>
+ </xsl:variable>
+ <xsl:variable name="height">
+ <xsl:if test="string-length(@height)!=0">
+ <xsl:call-template name="convert2px"><xsl:with-param name="value" select="@height"/></xsl:call-template>
+ </xsl:if>
+ </xsl:variable>
+ <img src="{$src2}" class="{$imagestyle}" alt="{$alt}" style="{concat('width:',$width,';height:',$height)}" itemprop="{$property}" itemscope="true" itemtype="http://schema.org/ImageObject"/>
+</xsl:template>
+
+<!-- Insert an object -->
+<xsl:template name="insertobject">
+ <xsl:variable name="auxID">
+ <xsl:value-of select="//meta/topic/@id" /><xsl:number level="any" count="object" format="_1"/>
+ </xsl:variable>
+ <xsl:variable name="tmp_href"><xsl:value-of select="concat($urlpre,'text/shared/00/00000004.xhp')"/></xsl:variable>
+ <xsl:variable name="tmp_doc" select="document($tmp_href)"/>
+ <xsl:variable name="data">
+ <xsl:value-of select="concat($img_url_prefix,@data)"/>
+ </xsl:variable>
+ <xsl:variable name="type"><xsl:value-of select="@type"/></xsl:variable>
+ <xsl:variable name="width">
+ <xsl:call-template name="convert2px"><xsl:with-param name="value" select="@width"/></xsl:call-template>
+ </xsl:variable>
+ <xsl:variable name="height">
+ <xsl:call-template name="convert2px"><xsl:with-param name="value" select="@height"/></xsl:call-template>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="starts-with(@type,'video/youtube')">
+ <div id="{@id}" class="youtube_placeholder">
+ <h2 id="promovideoH2"><xsl:value-of select="$ytpromovideoH2"/></h2>
+ <p><xsl:value-of select="$ytaccept"/></p>
+ <p><a href="https://policies.google.com/privacy" target="_blank"><xsl:value-of select="$ytprivacy"/></a></p>
+ <button class="youtube_button" onClick="youtubeLoader('{@id}', 700, 394)" >
+ <xsl:value-of select="$ytvideobutton"/>
+ </button>
+ </div>
+ </xsl:when>
+ <xsl:when test="not(starts-with(@type,'video/youtube')) and starts-with(@type,'video')">
+ <div id="mediadiv">
+ <video src="{$data}" type="{@type}" width="{$width}" height="{$height}" controls="'1'"></video>
+ </div>
+ </xsl:when>
+ <xsl:when test="starts-with(@type,'audio')">
+ <div id="mediadiv">
+ <audio src="{$data}" type="{@type}" controls="'1'"></audio>
+ </div>
+ </xsl:when>
+ <xsl:when test="@type='application/vnd.oasis.opendocument.spreadsheet'">
+ <xsl:variable name="src">
+ <xsl:call-template name="addlang2path">
+ <xsl:with-param name="string" select="@data"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <div class="samplefilesection" id="obj{$auxID}">
+ <h3><xsl:apply-templates select="$tmp_doc//variable[@id='samplefile']"/></h3>
+ <a class="objectfiles" href="{$src}"><img src="media/navigation/libo-calc.svg" width="25px" height="30px"></img></a>
+ </div>
+ </xsl:when>
+ <xsl:when test="@type='application/vnd.oasis.opendocument.text'">
+ <xsl:variable name="src">
+ <xsl:call-template name="addlang2path">
+ <xsl:with-param name="string" select="@data"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <div class="samplefilesection" id="obj{$auxID}">
+ <h3><xsl:apply-templates select="$tmp_doc//variable[@id='samplefile']"/></h3>
+ <a class="objectfiles" href="{$src}"><img src="media/navigation/libo-writer.svg" width="25px" height="30px"></img></a>
+ </div>
+ </xsl:when>
+ <xsl:when test="@type='application/vnd.oasis.opendocument.presentation'">
+ <xsl:variable name="src">
+ <xsl:call-template name="addlang2path">
+ <xsl:with-param name="string" select="@data"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <div class="samplefilesection" id="obj{$auxID}">
+ <h3><xsl:apply-templates select="$tmp_doc//variable[@id='samplefile']"/></h3>
+ <a class="objectfiles" href="{$src}"><img src="media/navigation/libo-impress.svg" width="25px" height="30px"></img></a>
+ </div>
+ </xsl:when>
+ <xsl:when test="@type='application/vnd.oasis.opendocument.drawing'">
+ <xsl:variable name="src">
+ <xsl:call-template name="addlang2path">
+ <xsl:with-param name="string" select="@data"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <div class="samplefilesection" id="obj{$auxID}">
+ <h3><xsl:apply-templates select="$tmp_doc//variable[@id='samplefile']"/></h3>
+ <a class="objectfiles" href="{$src}"><img src="media/navigation/libo-draw.svg" width="25px" height="30px"></img></a>
+ </div>
+ </xsl:when>
+ <xsl:when test="@type='application/vnd.oasis.opendocument.formula'">
+ <xsl:variable name="src">
+ <xsl:call-template name="addlang2path">
+ <xsl:with-param name="string" select="@data"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <div class="samplefilesection" id="obj{$auxID}">
+ <h3><xsl:apply-templates select="$tmp_doc//variable[@id='samplefile']"/></h3>
+ <a class="objectfiles" href="{$src}"><img src="media/navigation/libo-math.svg" width="25px" height="30px"></img></a>
+ </div>
+ </xsl:when>
+ <xsl:when test="@type='application/vnd.oasis.opendocument.database'">
+ <xsl:variable name="src">
+ <xsl:call-template name="addlang2path">
+ <xsl:with-param name="string" select="@data"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <div class="samplefilesection" id="obj{$auxID}">
+ <h3><xsl:apply-templates select="$tmp_doc//variable[@id='samplefile']"/></h3>
+ <a class="objectfiles" href="{$src}"><img src="media/navigation/libo-base.svg" width="25px" height="30px"></img></a>
+ </div>
+ </xsl:when>
+ <xsl:otherwise>
+ <object width="{$width}" height="{$height}" data="{$data}" type="{@type}"></object>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- changing measure to pixel -->
+<xsl:template name="convert2px">
+ <xsl:param name="value"/>
+ <xsl:choose>
+ <xsl:when test="contains($value, 'cm')">
+ <xsl:value-of select="concat(round(number(substring-before($value, 'cm')) * $dpcm),'px')"/>
+ </xsl:when>
+ <xsl:when test="contains($value, 'mm')">
+ <xsl:value-of select="concat(round(number(substring-before($value, 'mm')) * $dpmm),'px')"/>
+ </xsl:when>
+ <xsl:when test="contains($value, 'in')">
+ <xsl:value-of select="concat(round(number(substring-before($value, 'in')) * $dpi),'px')"/>
+ </xsl:when>
+ <xsl:when test="contains($value, 'px')">
+ <xsl:value-of select="$value"/>
+ </xsl:when>
+ <xsl:otherwise>
+<!-- <xsl:message>measure_conversion.xsl: Find no conversion for <xsl:value-of select="$value"/> to 'px'!</xsl:message> -->
+ <xsl:value-of select="concat($value, 'px;')"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- Insert a Table -->
+<xsl:template name="inserttable">
+ <xsl:variable name="imgsrc"> <!-- see if we are in an image table -->
+ <xsl:value-of select="tablerow/tablecell[1]/paragraph[1]/image/@src"/>
+ </xsl:variable>
+
+ <xsl:choose>
+ <xsl:when test="count(descendant::tablecell)=1">
+ <div class="onecell"><xsl:apply-templates mode="onecell"/></div>
+ </xsl:when>
+
+ <xsl:when test="descendant::tablecell[1]/descendant::image">
+ <xsl:apply-templates mode="icontable"/>
+ </xsl:when>
+
+ <xsl:when test="@class='wide'">
+ <table border="1" class="{@class}" cellpadding="0" cellspacing="0" width="100%" >
+ <xsl:apply-templates />
+ </table>
+ <br/>
+ </xsl:when>
+
+ <xsl:when test="not(@class='')">
+ <table border="1" class="{@class}" cellpadding="0" cellspacing="0" >
+ <xsl:apply-templates />
+ </table>
+ <br/>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <table border="1" class="border" cellpadding="0" cellspacing="0" >
+ <xsl:apply-templates />
+ </table>
+ <br/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="resolveembed">
+ <div class="embedded">
+ <xsl:variable name="href"><xsl:value-of select="concat($urlpre,substring-before(@href,'#'))"/></xsl:variable>
+ <xsl:variable name="anc"><xsl:value-of select="substring-after(@href,'#')"/></xsl:variable>
+ <xsl:variable name="docum" select="document($href)"/>
+ <xsl:call-template name="insertembed">
+ <xsl:with-param name="doc" select="$docum" />
+ <xsl:with-param name="anchor" select="$anc" />
+ </xsl:call-template>
+ </div>
+</xsl:template>
+
+<xsl:template name="resolveembedvar">
+ <xsl:variable name="archive"><xsl:value-of select="concat(substring-before(substring-after(@href,'text/'),'/'),'/')"/></xsl:variable>
+ <xsl:variable name="href"><xsl:value-of select="concat($urlpre,substring-before(@href,'#'))"/></xsl:variable>
+ <xsl:variable name="anchor"><xsl:value-of select="substring-after(@href,'#')"/></xsl:variable>
+ <xsl:variable name="doc" select="document($href)"/>
+ <xsl:choose>
+ <xsl:when test="$doc//variable[@id=$anchor]"> <!-- test for a variable of that name -->
+ <xsl:apply-templates select="$doc//variable[@id=$anchor]" mode="embedded"/>
+ </xsl:when>
+ <xsl:otherwise> <!-- or give up -->
+ <span class="bug">[<xsl:value-of select="@href"/> not found].</span>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- Apply -->
+<xsl:template name="apply">
+ <xsl:param name="embedded" />
+ <xsl:choose>
+ <xsl:when test="$embedded = 'yes'">
+ <xsl:apply-templates mode="embedded"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="filehtml">
+ <xsl:param name="file"/>
+ <xsl:value-of select="concat(substring-before($file,'.xhp'),'.html')"/>
+</xsl:template>
+
+<!-- recursive named template -->
+<xsl:template name="tokenize">
+ <xsl:param name="str" />
+ <xsl:param name="result" select="''" />
+ <xsl:choose>
+ <xsl:when test="substring-after($str,'/')">
+ <xsl:call-template name="tokenize">
+ <xsl:with-param name="str" select="substring-after($str,'/')" />
+ <xsl:with-param name="result" select="concat($result,'../')" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$result" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+<!--Add language to path for file -->
+<xsl:template name="addlang2path">
+ <xsl:param name="string"/>
+ <xsl:choose>
+ <xsl:when test="not($lang='en-US')">
+ <xsl:variable name="tmpfn">
+ <xsl:call-template name="substring-after-last">
+ <xsl:with-param name="string" select="$string"/>
+ <xsl:with-param name="char" select="'/'"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of select="concat(substring-before($string, $tmpfn),$lang,'/',$tmpfn)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$string"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="substring-after-last">
+ <xsl:param name="string"/>
+ <xsl:param name="char"/>
+ <xsl:choose>
+ <xsl:when test="contains($string, $char)">
+ <xsl:call-template name="substring-after-last">
+ <xsl:with-param name="string" select="substring-after($string, $char)"/>
+ <xsl:with-param name="char" select="$char"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$string"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/helpcontent2/help3xsl/paginathing.js b/helpcontent2/help3xsl/paginathing.js
new file mode 100644
index 000000000..cd52b3637
--- /dev/null
+++ b/helpcontent2/help3xsl/paginathing.js
@@ -0,0 +1,243 @@
+/**
+ * Paginathing
+ * Paginate Everything
+ *
+ * Original author Alfred Crosby <https://github.com/alfredcrosby>
+ * Inspired from http://esimakin.github.io/twbs-pagination/
+ * Modified to pure JavaScript and specialised to LibreOffice Help by
+ * Ilmari Lauhakangas
+ *
+ * MIT License (Expat)
+ *
+ * Copyright (c) 2018 Alfred Crosby
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+var options = {
+ perPage: 20,
+ limitPagination: 6,
+ prevNext: true,
+ firstLast: true,
+ prevText: '←',
+ nextText: '→',
+ firstText: '⇤',
+ lastText: '⇥',
+ containerClass: 'pagination-container',
+ ulClass: 'pagination',
+ liClass: 'page',
+ activeClass: 'active',
+ disabledClass: 'disabled'
+};
+
+var Paginator = function(element) {
+ var el = element;
+ var startPage = 1;
+ var currentPage = 1;
+ var pageDivision = 0;
+ var totalItems = el.children.length;
+ var limitPagination = options.limitPagination;
+ pageDivision = Math.ceil(totalItems / options.perPage);
+ // let's not display pagination leading nowhere
+ function pagLimit() {
+ if (options.limitPagination >= pageDivision) {
+ limitPagination = pageDivision;
+ } else {
+ limitPagination = options.limitPagination;
+ }
+ return limitPagination;
+ }
+ var totalPages = Math.max(pageDivision, pagLimit());
+ var existingContainer = document.getElementsByClassName('pagination-container')[0];
+ if (existingContainer) {
+ parent = existingContainer.parentNode;
+ parent.removeChild(existingContainer);
+ }
+ var container = document.createElement('nav');
+ container.setAttribute('class', options.containerClass);
+ var ul = document.createElement('ul');
+ ul.setAttribute('class', options.ulClass);
+
+ function paginationFunc(type, page) {
+ var li = document.createElement('li');
+ var a = document.createElement('a');
+ a.setAttribute('href', '#');
+ var cssClass = type === 'number' ? options.liClass : type;
+ var text = document.createTextNode(type === 'number' ? page : paginationText(type));
+
+ li.classList.add(cssClass);
+ li.setAttribute('data-pagination-type', type);
+ li.setAttribute('data-page', page);
+ a.appendChild(text);
+ li.appendChild(a);
+
+ return li;
+ }
+
+ function paginationText(type) {
+ return options[type + 'Text'];
+ }
+
+ function buildPagination() {
+ var pagination = [];
+ var prev = currentPage - 1 < startPage ? startPage : currentPage - 1;
+ var next = currentPage + 1 > totalPages ? totalPages : currentPage + 1;
+
+ var start = 0;
+ var end = 0;
+ var limit = limitPagination;
+
+ if (limit) {
+ if (currentPage <= Math.ceil(limit / 2) + 1) {
+ start = 1;
+ end = limit;
+ } else if (currentPage + Math.floor(limit / 2) >= totalPages) {
+ start = totalPages + 1 - limit;
+ end = totalPages;
+ } else {
+ start = currentPage - Math.ceil(limit / 2);
+ end = currentPage + Math.floor(limit / 2);
+ }
+ } else {
+ start = startPage;
+ end = totalPages;
+ }
+
+
+ // "First" button
+ if (options.firstLast) {
+ pagination.push(paginationFunc('first', startPage));
+ }
+
+ // "Prev" button
+ if (options.prevNext) {
+ pagination.push(paginationFunc('prev', prev));
+ }
+
+ // Pagination
+ for (var i = start; i <= end; i++) {
+ pagination.push(paginationFunc('number', i));
+ }
+
+ // "Next" button
+ if (options.prevNext) {
+ pagination.push(paginationFunc('next', next));
+ }
+
+ // "Last" button
+ if (options.firstLast) {
+ pagination.push(paginationFunc('last', totalPages));
+ }
+ return pagination;
+ }
+
+ function render(page) {
+ // Remove children before re-render (prevent duplicate)
+ while (ul.hasChildNodes()) {
+ ul.removeChild(ul.lastChild);
+ }
+
+ var paginationBuild = buildPagination();
+
+ paginationBuild.forEach(function(item) {
+ ul.appendChild(item);
+ });
+
+ // Manage active DOM
+ var startAt = page === 1 ? 0 : (page - 1) * options.perPage;
+ var endAt = page * options.perPage;
+
+ var domLi = el.children;
+
+ for (var i = 0, len = domLi.length; i < len; i++) {
+ var item = domLi[i];
+
+ if (i >= startAt && i <= endAt) {
+ item.classList.remove('hidden');
+ } else {
+ item.classList.add('hidden');
+ }
+ }
+
+ // Manage active state
+ var ulKids = ul.getElementsByTagName("li");
+
+ for (var i = 0, len = ulKids.length; i < len; i++) {
+ var _li = ulKids[i];
+ var type = _li.getAttribute('data-pagination-type');
+
+ switch (type) {
+ case 'number':
+ if (parseInt(_li.getAttribute('data-page'), 10) === page) {
+ _li.classList.add(options.activeClass);
+ }
+ break;
+ case 'first':
+ page === startPage && _li.classList.toggle(options.disabledClass);
+ break;
+ case 'last':
+ page === totalPages && _li.classList.toggle(options.disabledClass);
+ break;
+ case 'prev':
+ (page - 1) < startPage && _li.classList.toggle(options.disabledClass);
+ break;
+ case 'next':
+ (page + 1) > totalPages && _li.classList.toggle(options.disabledClass);
+ break;
+ default:
+ break;
+ }
+ }
+
+ el.before(container);
+ container.appendChild(ul);
+ }
+
+ function handle() {
+ var pagLi = container.childNodes[0].childNodes;
+
+ for (var i = 0, len = pagLi.length; i < len; i++) {
+ (function() {
+ var item = pagLi[i];
+
+ item.addEventListener('click', function(e) {
+ e.preventDefault();
+ var page = parseInt(item.getAttribute('data-page'), 10);
+ currentPage = page;
+ // let's prevent the pagination from flowing to two rows
+ if (currentPage >= 98) {
+ limitPagination = 4;
+ } else {
+ limitPagination = pagLimit();
+ }
+ show(page);
+ });
+ }());
+ }
+ }
+
+ function show(page) {
+ render(page);
+ handle();
+ }
+
+ show(startPage);
+
+ return;
+};
diff --git a/helpcontent2/help3xsl/polyfills.js b/helpcontent2/help3xsl/polyfills.js
new file mode 100644
index 000000000..0c14764d7
--- /dev/null
+++ b/helpcontent2/help3xsl/polyfills.js
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+// This file can be removed, when we stop supporting IE11.
+// Polyfill for .before()
+// from: https://github.com/jserz/js_piece/blob/master/DOM/ChildNode/before()/before().md
+// Copyright (c) 2016-present, jszhou
+// MIT License
+(function (arr) {
+ arr.forEach(function (item) {
+ if (item.hasOwnProperty('before')) {
+ return;
+ }
+ Object.defineProperty(item, 'before', {
+ configurable: true,
+ enumerable: true,
+ writable: true,
+ value: function before() {
+ var argArr = Array.prototype.slice.call(arguments),
+ docFrag = document.createDocumentFragment();
+
+ argArr.forEach(function (argItem) {
+ var isNode = argItem instanceof Node;
+ docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
+ });
+
+ this.parentNode.insertBefore(docFrag, this);
+ }
+ });
+ });
+})([Element.prototype, CharacterData.prototype, DocumentType.prototype]);
+// Polyfill for .startsWith()
+// from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith#Polyfill
+if (!String.prototype.startsWith) {
+ Object.defineProperty(String.prototype, 'startsWith', {
+ value: function(search, pos) {
+ pos = !pos || pos < 0 ? 0 : +pos;
+ return this.substring(pos, pos + search.length) === search;
+ }
+ });
+}
+// Polyfill for .matches()
+// from: https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill
+if (!Element.prototype.matches) {
+ Element.prototype.matches = Element.prototype.msMatchesSelector ||
+ Element.prototype.webkitMatchesSelector;
+}
+// Polyfill for iterable Set (IE11)
+// from: https://stackoverflow.com/a/45686452/3057764
+if (new Set([0]).size === 0) {
+ //constructor doesn't take an iterable as an argument - thanks IE
+ const BuiltinSet = Set;
+ Set = function Set(iterable) {
+ const set = new BuiltinSet();
+ if (iterable) {
+ iterable.forEach(set.add, set);
+ }
+ return set;
+ };
+ Set.prototype = BuiltinSet.prototype;
+ Set.prototype.constructor = Set;
+}
+// Polyfill for using :scope in querySelector/querySelectorAll
+// from: https://github.com/lazd/scopedQuerySelectorShim
+// Copyright (C) 2015 Larry Davis
+// This software may be modified and distributed under the terms of the BSD license.
+(function() {
+ if (!HTMLElement.prototype.querySelectorAll) {
+ throw new Error("rootedQuerySelectorAll: This polyfill can only be used with browsers that support querySelectorAll");
+ }
+ // A temporary element to query against for elements not currently in the DOM
+ // We'll also use this element to test for :scope support
+ var container = document.createElement("div");
+ // Check if the browser supports :scope
+ try {
+ // Browser supports :scope, do nothing
+ container.querySelectorAll(":scope *");
+ } catch (e) {
+ // Match usage of scope
+ var scopeRE = /^\s*:scope/gi;
+ // Overrides
+ function overrideNodeMethod(prototype, methodName) {
+ // Store the old method for use later
+ var oldMethod = prototype[methodName];
+ // Override the method
+ prototype[methodName] = function(query) {
+ var nodeList, gaveId = false, gaveContainer = false;
+ if (query.match(scopeRE)) {
+ // Remove :scope
+ query = query.replace(scopeRE, "");
+ if (!this.parentNode) {
+ // Add to temporary container
+ container.appendChild(this);
+ gaveContainer = true;
+ }
+ parentNode = this.parentNode;
+ if (!this.id) {
+ // Give temporary ID
+ this.id = "rootedQuerySelector_id_" + new Date().getTime();
+ gaveId = true;
+ }
+ // Find elements against parent node
+ nodeList = oldMethod.call(parentNode, "#" + this.id + " " + query);
+ // Reset the ID
+ if (gaveId) {
+ this.id = "";
+ }
+ // Remove from temporary container
+ if (gaveContainer) {
+ container.removeChild(this);
+ }
+ return nodeList;
+ } else {
+ // No immediate child selector used
+ return oldMethod.call(this, query);
+ }
+ };
+ }
+ // Browser doesn't support :scope, add polyfill
+ overrideNodeMethod(HTMLElement.prototype, "querySelector");
+ overrideNodeMethod(HTMLElement.prototype, "querySelectorAll");
+ }
+})();
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/helpcontent2/help3xsl/prism.css b/helpcontent2/help3xsl/prism.css
new file mode 100644
index 000000000..461090981
--- /dev/null
+++ b/helpcontent2/help3xsl/prism.css
@@ -0,0 +1,263 @@
+/* PrismJS 1.28.0
+https://prismjs.com/download.html#themes=prism-coy&languages=markup+css+clike+javascript+python+sql+visual-basic&plugins=line-numbers+normalize-whitespace */
+/**
+ * prism.js Coy theme for JavaScript, CoffeeScript, CSS and HTML
+ * Based on https://github.com/tshedor/workshop-wp-theme (Example: http://workshop.kansan.com/category/sessions/basics or http://workshop.timshedor.com/category/sessions/basics);
+ * @author Tim Shedor
+ */
+
+code[class*="language-"],
+pre[class*="language-"] {
+ color: black;
+ background: none;
+ font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+ font-size: 1em;
+ text-align: left;
+ white-space: pre;
+ word-spacing: normal;
+ word-break: normal;
+ word-wrap: normal;
+ line-height: 1.5;
+
+ -moz-tab-size: 4;
+ -o-tab-size: 4;
+ tab-size: 4;
+
+ -webkit-hyphens: none;
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ hyphens: none;
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+ position: relative;
+ margin: .5em 0;
+ overflow: visible;
+ padding: 1px;
+}
+
+pre[class*="language-"] > code {
+ position: relative;
+ z-index: 1;
+ border-left: 10px solid #358ccb;
+ box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
+ background-color: #fdfdfd;
+ background-image: linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
+ background-size: 3em 3em;
+ background-origin: content-box;
+ background-attachment: local;
+}
+
+code[class*="language-"] {
+ max-height: inherit;
+ height: inherit;
+ padding: 0 1em;
+ display: block;
+ overflow: auto;
+}
+
+/* Margin bottom to accommodate shadow */
+:not(pre) > code[class*="language-"],
+pre[class*="language-"] {
+ background-color: #fdfdfd;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ margin-bottom: 1em;
+}
+
+/* Inline code */
+:not(pre) > code[class*="language-"] {
+ position: relative;
+ padding: .2em;
+ border-radius: 0.3em;
+ color: #c92c2c;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ display: inline;
+ white-space: normal;
+}
+
+pre[class*="language-"]:before,
+pre[class*="language-"]:after {
+ content: '';
+ display: block;
+ position: absolute;
+ bottom: 0.75em;
+ left: 0.18em;
+ width: 40%;
+ height: 20%;
+ max-height: 13em;
+ box-shadow: 0px 13px 8px #979797;
+ -webkit-transform: rotate(-2deg);
+ -moz-transform: rotate(-2deg);
+ -ms-transform: rotate(-2deg);
+ -o-transform: rotate(-2deg);
+ transform: rotate(-2deg);
+}
+
+pre[class*="language-"]:after {
+ right: 0.75em;
+ left: auto;
+ -webkit-transform: rotate(2deg);
+ -moz-transform: rotate(2deg);
+ -ms-transform: rotate(2deg);
+ -o-transform: rotate(2deg);
+ transform: rotate(2deg);
+}
+
+.token.comment,
+.token.block-comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+ color: #7D8B99;
+}
+
+.token.punctuation {
+ color: #5F6364;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.function-name,
+.token.constant,
+.token.symbol,
+.token.deleted {
+ color: #c92c2c;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.function,
+.token.builtin,
+.token.inserted {
+ color: #2f9c0a;
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.token.variable {
+ color: #a67f59;
+ background: rgba(255, 255, 255, 0.5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword,
+.token.class-name {
+ color: #1990b8;
+}
+
+.token.regex,
+.token.important {
+ color: #e90;
+}
+
+.language-css .token.string,
+.style .token.string {
+ color: #a67f59;
+ background: rgba(255, 255, 255, 0.5);
+}
+
+.token.important {
+ font-weight: normal;
+}
+
+.token.bold {
+ font-weight: bold;
+}
+.token.italic {
+ font-style: italic;
+}
+
+.token.entity {
+ cursor: help;
+}
+
+.token.namespace {
+ opacity: .7;
+}
+
+@media screen and (max-width: 767px) {
+ pre[class*="language-"]:before,
+ pre[class*="language-"]:after {
+ bottom: 14px;
+ box-shadow: none;
+ }
+
+}
+
+/* Plugin styles: Line Numbers */
+pre[class*="language-"].line-numbers.line-numbers {
+ padding-left: 0;
+}
+
+pre[class*="language-"].line-numbers.line-numbers code {
+ padding-left: 3.8em;
+}
+
+pre[class*="language-"].line-numbers.line-numbers .line-numbers-rows {
+ left: 0;
+}
+
+/* Plugin styles: Line Highlight */
+pre[class*="language-"][data-line] {
+ padding-top: 0;
+ padding-bottom: 0;
+ padding-left: 0;
+}
+pre[data-line] code {
+ position: relative;
+ padding-left: 4em;
+}
+pre .line-highlight {
+ margin-top: 0;
+}
+
+pre[class*="language-"].line-numbers {
+ position: relative;
+ padding-left: 3.8em;
+ counter-reset: linenumber;
+}
+
+pre[class*="language-"].line-numbers > code {
+ position: relative;
+ white-space: inherit;
+}
+
+.line-numbers .line-numbers-rows {
+ position: absolute;
+ pointer-events: none;
+ top: 0;
+ font-size: 100%;
+ left: -3.8em;
+ width: 3em; /* works for line-numbers below 1000 lines */
+ letter-spacing: -1px;
+ border-right: 1px solid #999;
+
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+}
+
+ .line-numbers-rows > span {
+ display: block;
+ counter-increment: linenumber;
+ }
+
+ .line-numbers-rows > span:before {
+ content: counter(linenumber);
+ color: #999;
+ display: block;
+ padding-right: 0.8em;
+ text-align: right;
+ }
+
diff --git a/helpcontent2/help3xsl/prism.js b/helpcontent2/help3xsl/prism.js
new file mode 100644
index 000000000..6ed382590
--- /dev/null
+++ b/helpcontent2/help3xsl/prism.js
@@ -0,0 +1,2304 @@
+/* PrismJS 1.28.0
+https://prismjs.com/download.html#themes=prism-coy&languages=markup+css+clike+javascript+python+sql+visual-basic&plugins=line-numbers+normalize-whitespace */
+/// <reference lib="WebWorker"/>
+
+var _self = (typeof window !== 'undefined')
+ ? window // if in browser
+ : (
+ (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)
+ ? self // if in worker
+ : {} // if in node js
+ );
+
+/**
+ * Prism: Lightweight, robust, elegant syntax highlighting
+ *
+ * @license MIT <https://opensource.org/licenses/MIT>
+ * @author Lea Verou <https://lea.verou.me>
+ * @namespace
+ * @public
+ */
+var Prism = (function (_self) {
+
+ // Private helper vars
+ var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i;
+ var uniqueId = 0;
+
+ // The grammar object for plaintext
+ var plainTextGrammar = {};
+
+
+ var _ = {
+ /**
+ * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the
+ * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load
+ * additional languages or plugins yourself.
+ *
+ * By setting this value to `true`, Prism will not automatically highlight all code elements on the page.
+ *
+ * You obviously have to change this value before the automatic highlighting started. To do this, you can add an
+ * empty Prism object into the global scope before loading the Prism script like this:
+ *
+ * ```js
+ * window.Prism = window.Prism || {};
+ * Prism.manual = true;
+ * // add a new <script> to load Prism's script
+ * ```
+ *
+ * @default false
+ * @type {boolean}
+ * @memberof Prism
+ * @public
+ */
+ manual: _self.Prism && _self.Prism.manual,
+ /**
+ * By default, if Prism is in a web worker, it assumes that it is in a worker it created itself, so it uses
+ * `addEventListener` to communicate with its parent instance. However, if you're using Prism manually in your
+ * own worker, you don't want it to do this.
+ *
+ * By setting this value to `true`, Prism will not add its own listeners to the worker.
+ *
+ * You obviously have to change this value before Prism executes. To do this, you can add an
+ * empty Prism object into the global scope before loading the Prism script like this:
+ *
+ * ```js
+ * window.Prism = window.Prism || {};
+ * Prism.disableWorkerMessageHandler = true;
+ * // Load Prism's script
+ * ```
+ *
+ * @default false
+ * @type {boolean}
+ * @memberof Prism
+ * @public
+ */
+ disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler,
+
+ /**
+ * A namespace for utility methods.
+ *
+ * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may
+ * change or disappear at any time.
+ *
+ * @namespace
+ * @memberof Prism
+ */
+ util: {
+ encode: function encode(tokens) {
+ if (tokens instanceof Token) {
+ return new Token(tokens.type, encode(tokens.content), tokens.alias);
+ } else if (Array.isArray(tokens)) {
+ return tokens.map(encode);
+ } else {
+ return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
+ }
+ },
+
+ /**
+ * Returns the name of the type of the given value.
+ *
+ * @param {any} o
+ * @returns {string}
+ * @example
+ * type(null) === 'Null'
+ * type(undefined) === 'Undefined'
+ * type(123) === 'Number'
+ * type('foo') === 'String'
+ * type(true) === 'Boolean'
+ * type([1, 2]) === 'Array'
+ * type({}) === 'Object'
+ * type(String) === 'Function'
+ * type(/abc+/) === 'RegExp'
+ */
+ type: function (o) {
+ return Object.prototype.toString.call(o).slice(8, -1);
+ },
+
+ /**
+ * Returns a unique number for the given object. Later calls will still return the same number.
+ *
+ * @param {Object} obj
+ * @returns {number}
+ */
+ objId: function (obj) {
+ if (!obj['__id']) {
+ Object.defineProperty(obj, '__id', { value: ++uniqueId });
+ }
+ return obj['__id'];
+ },
+
+ /**
+ * Creates a deep clone of the given object.
+ *
+ * The main intended use of this function is to clone language definitions.
+ *
+ * @param {T} o
+ * @param {Record<number, any>} [visited]
+ * @returns {T}
+ * @template T
+ */
+ clone: function deepClone(o, visited) {
+ visited = visited || {};
+
+ var clone; var id;
+ switch (_.util.type(o)) {
+ case 'Object':
+ id = _.util.objId(o);
+ if (visited[id]) {
+ return visited[id];
+ }
+ clone = /** @type {Record<string, any>} */ ({});
+ visited[id] = clone;
+
+ for (var key in o) {
+ if (o.hasOwnProperty(key)) {
+ clone[key] = deepClone(o[key], visited);
+ }
+ }
+
+ return /** @type {any} */ (clone);
+
+ case 'Array':
+ id = _.util.objId(o);
+ if (visited[id]) {
+ return visited[id];
+ }
+ clone = [];
+ visited[id] = clone;
+
+ (/** @type {Array} */(/** @type {any} */(o))).forEach(function (v, i) {
+ clone[i] = deepClone(v, visited);
+ });
+
+ return /** @type {any} */ (clone);
+
+ default:
+ return o;
+ }
+ },
+
+ /**
+ * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
+ *
+ * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
+ *
+ * @param {Element} element
+ * @returns {string}
+ */
+ getLanguage: function (element) {
+ while (element) {
+ var m = lang.exec(element.className);
+ if (m) {
+ return m[1].toLowerCase();
+ }
+ element = element.parentElement;
+ }
+ return 'none';
+ },
+
+ /**
+ * Sets the Prism `language-xxxx` class of the given element.
+ *
+ * @param {Element} element
+ * @param {string} language
+ * @returns {void}
+ */
+ setLanguage: function (element, language) {
+ // remove all `language-xxxx` classes
+ // (this might leave behind a leading space)
+ element.className = element.className.replace(RegExp(lang, 'gi'), '');
+
+ // add the new `language-xxxx` class
+ // (using `classList` will automatically clean up spaces for us)
+ element.classList.add('language-' + language);
+ },
+
+ /**
+ * Returns the script element that is currently executing.
+ *
+ * This does __not__ work for line script element.
+ *
+ * @returns {HTMLScriptElement | null}
+ */
+ currentScript: function () {
+ if (typeof document === 'undefined') {
+ return null;
+ }
+ if ('currentScript' in document && 1 < 2 /* hack to trip TS' flow analysis */) {
+ return /** @type {any} */ (document.currentScript);
+ }
+
+ // IE11 workaround
+ // we'll get the src of the current script by parsing IE11's error stack trace
+ // this will not work for inline scripts
+
+ try {
+ throw new Error();
+ } catch (err) {
+ // Get file src url from stack. Specifically works with the format of stack traces in IE.
+ // A stack will look like this:
+ //
+ // Error
+ // at _.util.currentScript (http://localhost/components/prism-core.js:119:5)
+ // at Global code (http://localhost/components/prism-core.js:606:1)
+
+ var src = (/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(err.stack) || [])[1];
+ if (src) {
+ var scripts = document.getElementsByTagName('script');
+ for (var i in scripts) {
+ if (scripts[i].src == src) {
+ return scripts[i];
+ }
+ }
+ }
+ return null;
+ }
+ },
+
+ /**
+ * Returns whether a given class is active for `element`.
+ *
+ * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated
+ * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the
+ * given class is just the given class with a `no-` prefix.
+ *
+ * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is
+ * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its
+ * ancestors have the given class or the negated version of it, then the default activation will be returned.
+ *
+ * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated
+ * version of it, the class is considered active.
+ *
+ * @param {Element} element
+ * @param {string} className
+ * @param {boolean} [defaultActivation=false]
+ * @returns {boolean}
+ */
+ isActive: function (element, className, defaultActivation) {
+ var no = 'no-' + className;
+
+ while (element) {
+ var classList = element.classList;
+ if (classList.contains(className)) {
+ return true;
+ }
+ if (classList.contains(no)) {
+ return false;
+ }
+ element = element.parentElement;
+ }
+ return !!defaultActivation;
+ }
+ },
+
+ /**
+ * This namespace contains all currently loaded languages and the some helper functions to create and modify languages.
+ *
+ * @namespace
+ * @memberof Prism
+ * @public
+ */
+ languages: {
+ /**
+ * The grammar for plain, unformatted text.
+ */
+ plain: plainTextGrammar,
+ plaintext: plainTextGrammar,
+ text: plainTextGrammar,
+ txt: plainTextGrammar,
+
+ /**
+ * Creates a deep copy of the language with the given id and appends the given tokens.
+ *
+ * If a token in `redef` also appears in the copied language, then the existing token in the copied language
+ * will be overwritten at its original position.
+ *
+ * ## Best practices
+ *
+ * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language)
+ * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to
+ * understand the language definition because, normally, the order of tokens matters in Prism grammars.
+ *
+ * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens.
+ * Furthermore, all non-overwriting tokens should be placed after the overwriting ones.
+ *
+ * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`.
+ * @param {Grammar} redef The new tokens to append.
+ * @returns {Grammar} The new language created.
+ * @public
+ * @example
+ * Prism.languages['css-with-colors'] = Prism.languages.extend('css', {
+ * // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token
+ * // at its original position
+ * 'comment': { ... },
+ * // CSS doesn't have a 'color' token, so this token will be appended
+ * 'color': /\b(?:red|green|blue)\b/
+ * });
+ */
+ extend: function (id, redef) {
+ var lang = _.util.clone(_.languages[id]);
+
+ for (var key in redef) {
+ lang[key] = redef[key];
+ }
+
+ return lang;
+ },
+
+ /**
+ * Inserts tokens _before_ another token in a language definition or any other grammar.
+ *
+ * ## Usage
+ *
+ * This helper method makes it easy to modify existing languages. For example, the CSS language definition
+ * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded
+ * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the
+ * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do
+ * this:
+ *
+ * ```js
+ * Prism.languages.markup.style = {
+ * // token
+ * };
+ * ```
+ *
+ * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens
+ * before existing tokens. For the CSS example above, you would use it like this:
+ *
+ * ```js
+ * Prism.languages.insertBefore('markup', 'cdata', {
+ * 'style': {
+ * // token
+ * }
+ * });
+ * ```
+ *
+ * ## Special cases
+ *
+ * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar
+ * will be ignored.
+ *
+ * This behavior can be used to insert tokens after `before`:
+ *
+ * ```js
+ * Prism.languages.insertBefore('markup', 'comment', {
+ * 'comment': Prism.languages.markup.comment,
+ * // tokens after 'comment'
+ * });
+ * ```
+ *
+ * ## Limitations
+ *
+ * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object
+ * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave
+ * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily
+ * deleting properties which is necessary to insert at arbitrary positions.
+ *
+ * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object.
+ * Instead, it will create a new object and replace all references to the target object with the new one. This
+ * can be done without temporarily deleting properties, so the iteration order is well-defined.
+ *
+ * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if
+ * you hold the target object in a variable, then the value of the variable will not change.
+ *
+ * ```js
+ * var oldMarkup = Prism.languages.markup;
+ * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... });
+ *
+ * assert(oldMarkup !== Prism.languages.markup);
+ * assert(newMarkup === Prism.languages.markup);
+ * ```
+ *
+ * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the
+ * object to be modified.
+ * @param {string} before The key to insert before.
+ * @param {Grammar} insert An object containing the key-value pairs to be inserted.
+ * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the
+ * object to be modified.
+ *
+ * Defaults to `Prism.languages`.
+ * @returns {Grammar} The new grammar object.
+ * @public
+ */
+ insertBefore: function (inside, before, insert, root) {
+ root = root || /** @type {any} */ (_.languages);
+ var grammar = root[inside];
+ /** @type {Grammar} */
+ var ret = {};
+
+ for (var token in grammar) {
+ if (grammar.hasOwnProperty(token)) {
+
+ if (token == before) {
+ for (var newToken in insert) {
+ if (insert.hasOwnProperty(newToken)) {
+ ret[newToken] = insert[newToken];
+ }
+ }
+ }
+
+ // Do not insert token which also occur in insert. See #1525
+ if (!insert.hasOwnProperty(token)) {
+ ret[token] = grammar[token];
+ }
+ }
+ }
+
+ var old = root[inside];
+ root[inside] = ret;
+
+ // Update references in other language definitions
+ _.languages.DFS(_.languages, function (key, value) {
+ if (value === old && key != inside) {
+ this[key] = ret;
+ }
+ });
+
+ return ret;
+ },
+
+ // Traverse a language definition with Depth First Search
+ DFS: function DFS(o, callback, type, visited) {
+ visited = visited || {};
+
+ var objId = _.util.objId;
+
+ for (var i in o) {
+ if (o.hasOwnProperty(i)) {
+ callback.call(o, i, o[i], type || i);
+
+ var property = o[i];
+ var propertyType = _.util.type(property);
+
+ if (propertyType === 'Object' && !visited[objId(property)]) {
+ visited[objId(property)] = true;
+ DFS(property, callback, null, visited);
+ } else if (propertyType === 'Array' && !visited[objId(property)]) {
+ visited[objId(property)] = true;
+ DFS(property, callback, i, visited);
+ }
+ }
+ }
+ }
+ },
+
+ plugins: {},
+
+ /**
+ * This is the most high-level function in Prism’s API.
+ * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on
+ * each one of them.
+ *
+ * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`.
+ *
+ * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}.
+ * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}.
+ * @memberof Prism
+ * @public
+ */
+ highlightAll: function (async, callback) {
+ _.highlightAllUnder(document, async, callback);
+ },
+
+ /**
+ * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls
+ * {@link Prism.highlightElement} on each one of them.
+ *
+ * The following hooks will be run:
+ * 1. `before-highlightall`
+ * 2. `before-all-elements-highlight`
+ * 3. All hooks of {@link Prism.highlightElement} for each element.
+ *
+ * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted.
+ * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers.
+ * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done.
+ * @memberof Prism
+ * @public
+ */
+ highlightAllUnder: function (container, async, callback) {
+ var env = {
+ callback: callback,
+ container: container,
+ selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
+ };
+
+ _.hooks.run('before-highlightall', env);
+
+ env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector));
+
+ _.hooks.run('before-all-elements-highlight', env);
+
+ for (var i = 0, element; (element = env.elements[i++]);) {
+ _.highlightElement(element, async === true, env.callback);
+ }
+ },
+
+ /**
+ * Highlights the code inside a single element.
+ *
+ * The following hooks will be run:
+ * 1. `before-sanity-check`
+ * 2. `before-highlight`
+ * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`.
+ * 4. `before-insert`
+ * 5. `after-highlight`
+ * 6. `complete`
+ *
+ * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for
+ * the element's language.
+ *
+ * @param {Element} element The element containing the code.
+ * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier.
+ * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers
+ * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is
+ * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default).
+ *
+ * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for
+ * asynchronous highlighting to work. You can build your own bundle on the
+ * [Download page](https://prismjs.com/download.html).
+ * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done.
+ * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously.
+ * @memberof Prism
+ * @public
+ */
+ highlightElement: function (element, async, callback) {
+ // Find language
+ var language = _.util.getLanguage(element);
+ var grammar = _.languages[language];
+
+ // Set language on the element, if not present
+ _.util.setLanguage(element, language);
+
+ // Set language on the parent, for styling
+ var parent = element.parentElement;
+ if (parent && parent.nodeName.toLowerCase() === 'pre') {
+ _.util.setLanguage(parent, language);
+ }
+
+ var code = element.textContent;
+
+ var env = {
+ element: element,
+ language: language,
+ grammar: grammar,
+ code: code
+ };
+
+ function insertHighlightedCode(highlightedCode) {
+ env.highlightedCode = highlightedCode;
+
+ _.hooks.run('before-insert', env);
+
+ env.element.innerHTML = env.highlightedCode;
+
+ _.hooks.run('after-highlight', env);
+ _.hooks.run('complete', env);
+ callback && callback.call(env.element);
+ }
+
+ _.hooks.run('before-sanity-check', env);
+
+ // plugins may change/add the parent/element
+ parent = env.element.parentElement;
+ if (parent && parent.nodeName.toLowerCase() === 'pre' && !parent.hasAttribute('tabindex')) {
+ parent.setAttribute('tabindex', '0');
+ }
+
+ if (!env.code) {
+ _.hooks.run('complete', env);
+ callback && callback.call(env.element);
+ return;
+ }
+
+ _.hooks.run('before-highlight', env);
+
+ if (!env.grammar) {
+ insertHighlightedCode(_.util.encode(env.code));
+ return;
+ }
+
+ if (async && _self.Worker) {
+ var worker = new Worker(_.filename);
+
+ worker.onmessage = function (evt) {
+ insertHighlightedCode(evt.data);
+ };
+
+ worker.postMessage(JSON.stringify({
+ language: env.language,
+ code: env.code,
+ immediateClose: true
+ }));
+ } else {
+ insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));
+ }
+ },
+
+ /**
+ * Low-level function, only use if you know what you’re doing. It accepts a string of text as input
+ * and the language definitions to use, and returns a string with the HTML produced.
+ *
+ * The following hooks will be run:
+ * 1. `before-tokenize`
+ * 2. `after-tokenize`
+ * 3. `wrap`: On each {@link Token}.
+ *
+ * @param {string} text A string with the code to be highlighted.
+ * @param {Grammar} grammar An object containing the tokens to use.
+ *
+ * Usually a language definition like `Prism.languages.markup`.
+ * @param {string} language The name of the language definition passed to `grammar`.
+ * @returns {string} The highlighted HTML.
+ * @memberof Prism
+ * @public
+ * @example
+ * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript');
+ */
+ highlight: function (text, grammar, language) {
+ var env = {
+ code: text,
+ grammar: grammar,
+ language: language
+ };
+ _.hooks.run('before-tokenize', env);
+ if (!env.grammar) {
+ throw new Error('The language "' + env.language + '" has no grammar.');
+ }
+ env.tokens = _.tokenize(env.code, env.grammar);
+ _.hooks.run('after-tokenize', env);
+ return Token.stringify(_.util.encode(env.tokens), env.language);
+ },
+
+ /**
+ * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input
+ * and the language definitions to use, and returns an array with the tokenized code.
+ *
+ * When the language definition includes nested tokens, the function is called recursively on each of these tokens.
+ *
+ * This method could be useful in other contexts as well, as a very crude parser.
+ *
+ * @param {string} text A string with the code to be highlighted.
+ * @param {Grammar} grammar An object containing the tokens to use.
+ *
+ * Usually a language definition like `Prism.languages.markup`.
+ * @returns {TokenStream} An array of strings and tokens, a token stream.
+ * @memberof Prism
+ * @public
+ * @example
+ * let code = `var foo = 0;`;
+ * let tokens = Prism.tokenize(code, Prism.languages.javascript);
+ * tokens.forEach(token => {
+ * if (token instanceof Prism.Token && token.type === 'number') {
+ * console.log(`Found numeric literal: ${token.content}`);
+ * }
+ * });
+ */
+ tokenize: function (text, grammar) {
+ var rest = grammar.rest;
+ if (rest) {
+ for (var token in rest) {
+ grammar[token] = rest[token];
+ }
+
+ delete grammar.rest;
+ }
+
+ var tokenList = new LinkedList();
+ addAfter(tokenList, tokenList.head, text);
+
+ matchGrammar(text, tokenList, grammar, tokenList.head, 0);
+
+ return toArray(tokenList);
+ },
+
+ /**
+ * @namespace
+ * @memberof Prism
+ * @public
+ */
+ hooks: {
+ all: {},
+
+ /**
+ * Adds the given callback to the list of callbacks for the given hook.
+ *
+ * The callback will be invoked when the hook it is registered for is run.
+ * Hooks are usually directly run by a highlight function but you can also run hooks yourself.
+ *
+ * One callback function can be registered to multiple hooks and the same hook multiple times.
+ *
+ * @param {string} name The name of the hook.
+ * @param {HookCallback} callback The callback function which is given environment variables.
+ * @public
+ */
+ add: function (name, callback) {
+ var hooks = _.hooks.all;
+
+ hooks[name] = hooks[name] || [];
+
+ hooks[name].push(callback);
+ },
+
+ /**
+ * Runs a hook invoking all registered callbacks with the given environment variables.
+ *
+ * Callbacks will be invoked synchronously and in the order in which they were registered.
+ *
+ * @param {string} name The name of the hook.
+ * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered.
+ * @public
+ */
+ run: function (name, env) {
+ var callbacks = _.hooks.all[name];
+
+ if (!callbacks || !callbacks.length) {
+ return;
+ }
+
+ for (var i = 0, callback; (callback = callbacks[i++]);) {
+ callback(env);
+ }
+ }
+ },
+
+ Token: Token
+ };
+ _self.Prism = _;
+
+
+ // Typescript note:
+ // The following can be used to import the Token type in JSDoc:
+ //
+ // @typedef {InstanceType<import("./prism-core")["Token"]>} Token
+
+ /**
+ * Creates a new token.
+ *
+ * @param {string} type See {@link Token#type type}
+ * @param {string | TokenStream} content See {@link Token#content content}
+ * @param {string|string[]} [alias] The alias(es) of the token.
+ * @param {string} [matchedStr=""] A copy of the full string this token was created from.
+ * @class
+ * @global
+ * @public
+ */
+ function Token(type, content, alias, matchedStr) {
+ /**
+ * The type of the token.
+ *
+ * This is usually the key of a pattern in a {@link Grammar}.
+ *
+ * @type {string}
+ * @see GrammarToken
+ * @public
+ */
+ this.type = type;
+ /**
+ * The strings or tokens contained by this token.
+ *
+ * This will be a token stream if the pattern matched also defined an `inside` grammar.
+ *
+ * @type {string | TokenStream}
+ * @public
+ */
+ this.content = content;
+ /**
+ * The alias(es) of the token.
+ *
+ * @type {string|string[]}
+ * @see GrammarToken
+ * @public
+ */
+ this.alias = alias;
+ // Copy of the full string this token was created from
+ this.length = (matchedStr || '').length | 0;
+ }
+
+ /**
+ * A token stream is an array of strings and {@link Token Token} objects.
+ *
+ * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process
+ * them.
+ *
+ * 1. No adjacent strings.
+ * 2. No empty strings.
+ *
+ * The only exception here is the token stream that only contains the empty string and nothing else.
+ *
+ * @typedef {Array<string | Token>} TokenStream
+ * @global
+ * @public
+ */
+
+ /**
+ * Converts the given token or token stream to an HTML representation.
+ *
+ * The following hooks will be run:
+ * 1. `wrap`: On each {@link Token}.
+ *
+ * @param {string | Token | TokenStream} o The token or token stream to be converted.
+ * @param {string} language The name of current language.
+ * @returns {string} The HTML representation of the token or token stream.
+ * @memberof Token
+ * @static
+ */
+ Token.stringify = function stringify(o, language) {
+ if (typeof o == 'string') {
+ return o;
+ }
+ if (Array.isArray(o)) {
+ var s = '';
+ o.forEach(function (e) {
+ s += stringify(e, language);
+ });
+ return s;
+ }
+
+ var env = {
+ type: o.type,
+ content: stringify(o.content, language),
+ tag: 'span',
+ classes: ['token', o.type],
+ attributes: {},
+ language: language
+ };
+
+ var aliases = o.alias;
+ if (aliases) {
+ if (Array.isArray(aliases)) {
+ Array.prototype.push.apply(env.classes, aliases);
+ } else {
+ env.classes.push(aliases);
+ }
+ }
+
+ _.hooks.run('wrap', env);
+
+ var attributes = '';
+ for (var name in env.attributes) {
+ attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '&quot;') + '"';
+ }
+
+ return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>';
+ };
+
+ /**
+ * @param {RegExp} pattern
+ * @param {number} pos
+ * @param {string} text
+ * @param {boolean} lookbehind
+ * @returns {RegExpExecArray | null}
+ */
+ function matchPattern(pattern, pos, text, lookbehind) {
+ pattern.lastIndex = pos;
+ var match = pattern.exec(text);
+ if (match && lookbehind && match[1]) {
+ // change the match to remove the text matched by the Prism lookbehind group
+ var lookbehindLength = match[1].length;
+ match.index += lookbehindLength;
+ match[0] = match[0].slice(lookbehindLength);
+ }
+ return match;
+ }
+
+ /**
+ * @param {string} text
+ * @param {LinkedList<string | Token>} tokenList
+ * @param {any} grammar
+ * @param {LinkedListNode<string | Token>} startNode
+ * @param {number} startPos
+ * @param {RematchOptions} [rematch]
+ * @returns {void}
+ * @private
+ *
+ * @typedef RematchOptions
+ * @property {string} cause
+ * @property {number} reach
+ */
+ function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) {
+ for (var token in grammar) {
+ if (!grammar.hasOwnProperty(token) || !grammar[token]) {
+ continue;
+ }
+
+ var patterns = grammar[token];
+ patterns = Array.isArray(patterns) ? patterns : [patterns];
+
+ for (var j = 0; j < patterns.length; ++j) {
+ if (rematch && rematch.cause == token + ',' + j) {
+ return;
+ }
+
+ var patternObj = patterns[j];
+ var inside = patternObj.inside;
+ var lookbehind = !!patternObj.lookbehind;
+ var greedy = !!patternObj.greedy;
+ var alias = patternObj.alias;
+
+ if (greedy && !patternObj.pattern.global) {
+ // Without the global flag, lastIndex won't work
+ var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0];
+ patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g');
+ }
+
+ /** @type {RegExp} */
+ var pattern = patternObj.pattern || patternObj;
+
+ for ( // iterate the token list and keep track of the current token/string position
+ var currentNode = startNode.next, pos = startPos;
+ currentNode !== tokenList.tail;
+ pos += currentNode.value.length, currentNode = currentNode.next
+ ) {
+
+ if (rematch && pos >= rematch.reach) {
+ break;
+ }
+
+ var str = currentNode.value;
+
+ if (tokenList.length > text.length) {
+ // Something went terribly wrong, ABORT, ABORT!
+ return;
+ }
+
+ if (str instanceof Token) {
+ continue;
+ }
+
+ var removeCount = 1; // this is the to parameter of removeBetween
+ var match;
+
+ if (greedy) {
+ match = matchPattern(pattern, pos, text, lookbehind);
+ if (!match || match.index >= text.length) {
+ break;
+ }
+
+ var from = match.index;
+ var to = match.index + match[0].length;
+ var p = pos;
+
+ // find the node that contains the match
+ p += currentNode.value.length;
+ while (from >= p) {
+ currentNode = currentNode.next;
+ p += currentNode.value.length;
+ }
+ // adjust pos (and p)
+ p -= currentNode.value.length;
+ pos = p;
+
+ // the current node is a Token, then the match starts inside another Token, which is invalid
+ if (currentNode.value instanceof Token) {
+ continue;
+ }
+
+ // find the last node which is affected by this match
+ for (
+ var k = currentNode;
+ k !== tokenList.tail && (p < to || typeof k.value === 'string');
+ k = k.next
+ ) {
+ removeCount++;
+ p += k.value.length;
+ }
+ removeCount--;
+
+ // replace with the new match
+ str = text.slice(pos, p);
+ match.index -= pos;
+ } else {
+ match = matchPattern(pattern, 0, str, lookbehind);
+ if (!match) {
+ continue;
+ }
+ }
+
+ // eslint-disable-next-line no-redeclare
+ var from = match.index;
+ var matchStr = match[0];
+ var before = str.slice(0, from);
+ var after = str.slice(from + matchStr.length);
+
+ var reach = pos + str.length;
+ if (rematch && reach > rematch.reach) {
+ rematch.reach = reach;
+ }
+
+ var removeFrom = currentNode.prev;
+
+ if (before) {
+ removeFrom = addAfter(tokenList, removeFrom, before);
+ pos += before.length;
+ }
+
+ removeRange(tokenList, removeFrom, removeCount);
+
+ var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr);
+ currentNode = addAfter(tokenList, removeFrom, wrapped);
+
+ if (after) {
+ addAfter(tokenList, currentNode, after);
+ }
+
+ if (removeCount > 1) {
+ // at least one Token object was removed, so we have to do some rematching
+ // this can only happen if the current pattern is greedy
+
+ /** @type {RematchOptions} */
+ var nestedRematch = {
+ cause: token + ',' + j,
+ reach: reach
+ };
+ matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch);
+
+ // the reach might have been extended because of the rematching
+ if (rematch && nestedRematch.reach > rematch.reach) {
+ rematch.reach = nestedRematch.reach;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @typedef LinkedListNode
+ * @property {T} value
+ * @property {LinkedListNode<T> | null} prev The previous node.
+ * @property {LinkedListNode<T> | null} next The next node.
+ * @template T
+ * @private
+ */
+
+ /**
+ * @template T
+ * @private
+ */
+ function LinkedList() {
+ /** @type {LinkedListNode<T>} */
+ var head = { value: null, prev: null, next: null };
+ /** @type {LinkedListNode<T>} */
+ var tail = { value: null, prev: head, next: null };
+ head.next = tail;
+
+ /** @type {LinkedListNode<T>} */
+ this.head = head;
+ /** @type {LinkedListNode<T>} */
+ this.tail = tail;
+ this.length = 0;
+ }
+
+ /**
+ * Adds a new node with the given value to the list.
+ *
+ * @param {LinkedList<T>} list
+ * @param {LinkedListNode<T>} node
+ * @param {T} value
+ * @returns {LinkedListNode<T>} The added node.
+ * @template T
+ */
+ function addAfter(list, node, value) {
+ // assumes that node != list.tail && values.length >= 0
+ var next = node.next;
+
+ var newNode = { value: value, prev: node, next: next };
+ node.next = newNode;
+ next.prev = newNode;
+ list.length++;
+
+ return newNode;
+ }
+ /**
+ * Removes `count` nodes after the given node. The given node will not be removed.
+ *
+ * @param {LinkedList<T>} list
+ * @param {LinkedListNode<T>} node
+ * @param {number} count
+ * @template T
+ */
+ function removeRange(list, node, count) {
+ var next = node.next;
+ for (var i = 0; i < count && next !== list.tail; i++) {
+ next = next.next;
+ }
+ node.next = next;
+ next.prev = node;
+ list.length -= i;
+ }
+ /**
+ * @param {LinkedList<T>} list
+ * @returns {T[]}
+ * @template T
+ */
+ function toArray(list) {
+ var array = [];
+ var node = list.head.next;
+ while (node !== list.tail) {
+ array.push(node.value);
+ node = node.next;
+ }
+ return array;
+ }
+
+
+ if (!_self.document) {
+ if (!_self.addEventListener) {
+ // in Node.js
+ return _;
+ }
+
+ if (!_.disableWorkerMessageHandler) {
+ // In worker
+ _self.addEventListener('message', function (evt) {
+ var message = JSON.parse(evt.data);
+ var lang = message.language;
+ var code = message.code;
+ var immediateClose = message.immediateClose;
+
+ _self.postMessage(_.highlight(code, _.languages[lang], lang));
+ if (immediateClose) {
+ _self.close();
+ }
+ }, false);
+ }
+
+ return _;
+ }
+
+ // Get current script and highlight
+ var script = _.util.currentScript();
+
+ if (script) {
+ _.filename = script.src;
+
+ if (script.hasAttribute('data-manual')) {
+ _.manual = true;
+ }
+ }
+
+ function highlightAutomaticallyCallback() {
+ if (!_.manual) {
+ _.highlightAll();
+ }
+ }
+
+ if (!_.manual) {
+ // If the document state is "loading", then we'll use DOMContentLoaded.
+ // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the
+ // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they
+ // might take longer one animation frame to execute which can create a race condition where only some plugins have
+ // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded.
+ // See https://github.com/PrismJS/prism/issues/2102
+ var readyState = document.readyState;
+ if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) {
+ document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback);
+ } else {
+ if (window.requestAnimationFrame) {
+ window.requestAnimationFrame(highlightAutomaticallyCallback);
+ } else {
+ window.setTimeout(highlightAutomaticallyCallback, 16);
+ }
+ }
+ }
+
+ return _;
+
+}(_self));
+
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = Prism;
+}
+
+// hack for components to work correctly in node.js
+if (typeof global !== 'undefined') {
+ global.Prism = Prism;
+}
+
+// some additional documentation/types
+
+/**
+ * The expansion of a simple `RegExp` literal to support additional properties.
+ *
+ * @typedef GrammarToken
+ * @property {RegExp} pattern The regular expression of the token.
+ * @property {boolean} [lookbehind=false] If `true`, then the first capturing group of `pattern` will (effectively)
+ * behave as a lookbehind group meaning that the captured text will not be part of the matched text of the new token.
+ * @property {boolean} [greedy=false] Whether the token is greedy.
+ * @property {string|string[]} [alias] An optional alias or list of aliases.
+ * @property {Grammar} [inside] The nested grammar of this token.
+ *
+ * The `inside` grammar will be used to tokenize the text value of each token of this kind.
+ *
+ * This can be used to make nested and even recursive language definitions.
+ *
+ * Note: This can cause infinite recursion. Be careful when you embed different languages or even the same language into
+ * each another.
+ * @global
+ * @public
+ */
+
+/**
+ * @typedef Grammar
+ * @type {Object<string, RegExp | GrammarToken | Array<RegExp | GrammarToken>>}
+ * @property {Grammar} [rest] An optional grammar object that will be appended to this grammar.
+ * @global
+ * @public
+ */
+
+/**
+ * A function which will invoked after an element was successfully highlighted.
+ *
+ * @callback HighlightCallback
+ * @param {Element} element The element successfully highlighted.
+ * @returns {void}
+ * @global
+ * @public
+ */
+
+/**
+ * @callback HookCallback
+ * @param {Object<string, any>} env The environment variables of the hook.
+ * @returns {void}
+ * @global
+ * @public
+ */
+;
+Prism.languages.markup = {
+ 'comment': {
+ pattern: /<!--(?:(?!<!--)[\s\S])*?-->/,
+ greedy: true
+ },
+ 'prolog': {
+ pattern: /<\?[\s\S]+?\?>/,
+ greedy: true
+ },
+ 'doctype': {
+ // https://www.w3.org/TR/xml/#NT-doctypedecl
+ pattern: /<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,
+ greedy: true,
+ inside: {
+ 'internal-subset': {
+ pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/,
+ lookbehind: true,
+ greedy: true,
+ inside: null // see below
+ },
+ 'string': {
+ pattern: /"[^"]*"|'[^']*'/,
+ greedy: true
+ },
+ 'punctuation': /^<!|>$|[[\]]/,
+ 'doctype-tag': /^DOCTYPE/i,
+ 'name': /[^\s<>'"]+/
+ }
+ },
+ 'cdata': {
+ pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i,
+ greedy: true
+ },
+ 'tag': {
+ pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,
+ greedy: true,
+ inside: {
+ 'tag': {
+ pattern: /^<\/?[^\s>\/]+/,
+ inside: {
+ 'punctuation': /^<\/?/,
+ 'namespace': /^[^\s>\/:]+:/
+ }
+ },
+ 'special-attr': [],
+ 'attr-value': {
+ pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
+ inside: {
+ 'punctuation': [
+ {
+ pattern: /^=/,
+ alias: 'attr-equals'
+ },
+ {
+ pattern: /^(\s*)["']|["']$/,
+ lookbehind: true
+ }
+ ]
+ }
+ },
+ 'punctuation': /\/?>/,
+ 'attr-name': {
+ pattern: /[^\s>\/]+/,
+ inside: {
+ 'namespace': /^[^\s>\/:]+:/
+ }
+ }
+
+ }
+ },
+ 'entity': [
+ {
+ pattern: /&[\da-z]{1,8};/i,
+ alias: 'named-entity'
+ },
+ /&#x?[\da-f]{1,8};/i
+ ]
+};
+
+Prism.languages.markup['tag'].inside['attr-value'].inside['entity'] =
+ Prism.languages.markup['entity'];
+Prism.languages.markup['doctype'].inside['internal-subset'].inside = Prism.languages.markup;
+
+// Plugin to make entity title show the real entity, idea by Roman Komarov
+Prism.hooks.add('wrap', function (env) {
+
+ if (env.type === 'entity') {
+ env.attributes['title'] = env.content.replace(/&amp;/, '&');
+ }
+});
+
+Object.defineProperty(Prism.languages.markup.tag, 'addInlined', {
+ /**
+ * Adds an inlined language to markup.
+ *
+ * An example of an inlined language is CSS with `<style>` tags.
+ *
+ * @param {string} tagName The name of the tag that contains the inlined language. This name will be treated as
+ * case insensitive.
+ * @param {string} lang The language key.
+ * @example
+ * addInlined('style', 'css');
+ */
+ value: function addInlined(tagName, lang) {
+ var includedCdataInside = {};
+ includedCdataInside['language-' + lang] = {
+ pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,
+ lookbehind: true,
+ inside: Prism.languages[lang]
+ };
+ includedCdataInside['cdata'] = /^<!\[CDATA\[|\]\]>$/i;
+
+ var inside = {
+ 'included-cdata': {
+ pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i,
+ inside: includedCdataInside
+ }
+ };
+ inside['language-' + lang] = {
+ pattern: /[\s\S]+/,
+ inside: Prism.languages[lang]
+ };
+
+ var def = {};
+ def[tagName] = {
+ pattern: RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g, function () { return tagName; }), 'i'),
+ lookbehind: true,
+ greedy: true,
+ inside: inside
+ };
+
+ Prism.languages.insertBefore('markup', 'cdata', def);
+ }
+});
+Object.defineProperty(Prism.languages.markup.tag, 'addAttribute', {
+ /**
+ * Adds an pattern to highlight languages embedded in HTML attributes.
+ *
+ * An example of an inlined language is CSS with `style` attributes.
+ *
+ * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as
+ * case insensitive.
+ * @param {string} lang The language key.
+ * @example
+ * addAttribute('style', 'css');
+ */
+ value: function (attrName, lang) {
+ Prism.languages.markup.tag.inside['special-attr'].push({
+ pattern: RegExp(
+ /(^|["'\s])/.source + '(?:' + attrName + ')' + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,
+ 'i'
+ ),
+ lookbehind: true,
+ inside: {
+ 'attr-name': /^[^\s=]+/,
+ 'attr-value': {
+ pattern: /=[\s\S]+/,
+ inside: {
+ 'value': {
+ pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,
+ lookbehind: true,
+ alias: [lang, 'language-' + lang],
+ inside: Prism.languages[lang]
+ },
+ 'punctuation': [
+ {
+ pattern: /^=/,
+ alias: 'attr-equals'
+ },
+ /"|'/
+ ]
+ }
+ }
+ }
+ });
+ }
+});
+
+Prism.languages.html = Prism.languages.markup;
+Prism.languages.mathml = Prism.languages.markup;
+Prism.languages.svg = Prism.languages.markup;
+
+Prism.languages.xml = Prism.languages.extend('markup', {});
+Prism.languages.ssml = Prism.languages.xml;
+Prism.languages.atom = Prism.languages.xml;
+Prism.languages.rss = Prism.languages.xml;
+
+(function (Prism) {
+
+ var string = /(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;
+
+ Prism.languages.css = {
+ 'comment': /\/\*[\s\S]*?\*\//,
+ 'atrule': {
+ pattern: RegExp('@[\\w-](?:' + /[^;{\s"']|\s+(?!\s)/.source + '|' + string.source + ')*?' + /(?:;|(?=\s*\{))/.source),
+ inside: {
+ 'rule': /^@[\w-]+/,
+ 'selector-function-argument': {
+ pattern: /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,
+ lookbehind: true,
+ alias: 'selector'
+ },
+ 'keyword': {
+ pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/,
+ lookbehind: true
+ }
+ // See rest below
+ }
+ },
+ 'url': {
+ // https://drafts.csswg.org/css-values-3/#urls
+ pattern: RegExp('\\burl\\((?:' + string.source + '|' + /(?:[^\\\r\n()"']|\\[\s\S])*/.source + ')\\)', 'i'),
+ greedy: true,
+ inside: {
+ 'function': /^url/i,
+ 'punctuation': /^\(|\)$/,
+ 'string': {
+ pattern: RegExp('^' + string.source + '$'),
+ alias: 'url'
+ }
+ }
+ },
+ 'selector': {
+ pattern: RegExp('(^|[{}\\s])[^{}\\s](?:[^{};"\'\\s]|\\s+(?![\\s{])|' + string.source + ')*(?=\\s*\\{)'),
+ lookbehind: true
+ },
+ 'string': {
+ pattern: string,
+ greedy: true
+ },
+ 'property': {
+ pattern: /(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,
+ lookbehind: true
+ },
+ 'important': /!important\b/i,
+ 'function': {
+ pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,
+ lookbehind: true
+ },
+ 'punctuation': /[(){};:,]/
+ };
+
+ Prism.languages.css['atrule'].inside.rest = Prism.languages.css;
+
+ var markup = Prism.languages.markup;
+ if (markup) {
+ markup.tag.addInlined('style', 'css');
+ markup.tag.addAttribute('style', 'css');
+ }
+
+}(Prism));
+
+Prism.languages.clike = {
+ 'comment': [
+ {
+ pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,
+ lookbehind: true,
+ greedy: true
+ },
+ {
+ pattern: /(^|[^\\:])\/\/.*/,
+ lookbehind: true,
+ greedy: true
+ }
+ ],
+ 'string': {
+ pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
+ greedy: true
+ },
+ 'class-name': {
+ pattern: /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,
+ lookbehind: true,
+ inside: {
+ 'punctuation': /[.\\]/
+ }
+ },
+ 'keyword': /\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,
+ 'boolean': /\b(?:false|true)\b/,
+ 'function': /\b\w+(?=\()/,
+ 'number': /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
+ 'operator': /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,
+ 'punctuation': /[{}[\];(),.:]/
+};
+
+Prism.languages.javascript = Prism.languages.extend('clike', {
+ 'class-name': [
+ Prism.languages.clike['class-name'],
+ {
+ pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,
+ lookbehind: true
+ }
+ ],
+ 'keyword': [
+ {
+ pattern: /((?:^|\})\s*)catch\b/,
+ lookbehind: true
+ },
+ {
+ pattern: /(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,
+ lookbehind: true
+ },
+ ],
+ // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444)
+ 'function': /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,
+ 'number': {
+ pattern: RegExp(
+ /(^|[^\w$])/.source +
+ '(?:' +
+ (
+ // constant
+ /NaN|Infinity/.source +
+ '|' +
+ // binary integer
+ /0[bB][01]+(?:_[01]+)*n?/.source +
+ '|' +
+ // octal integer
+ /0[oO][0-7]+(?:_[0-7]+)*n?/.source +
+ '|' +
+ // hexadecimal integer
+ /0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source +
+ '|' +
+ // decimal bigint
+ /\d+(?:_\d+)*n/.source +
+ '|' +
+ // decimal number (integer or float) but no bigint
+ /(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source
+ ) +
+ ')' +
+ /(?![\w$])/.source
+ ),
+ lookbehind: true
+ },
+ 'operator': /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/
+});
+
+Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/;
+
+Prism.languages.insertBefore('javascript', 'keyword', {
+ 'regex': {
+ pattern: RegExp(
+ // lookbehind
+ // eslint-disable-next-line regexp/no-dupe-characters-character-class
+ /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source +
+ // Regex pattern:
+ // There are 2 regex patterns here. The RegExp set notation proposal added support for nested character
+ // classes if the `v` flag is present. Unfortunately, nested CCs are both context-free and incompatible
+ // with the only syntax, so we have to define 2 different regex patterns.
+ /\//.source +
+ '(?:' +
+ /(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source +
+ '|' +
+ // `v` flag syntax. This supports 3 levels of nested character classes.
+ /(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source +
+ ')' +
+ // lookahead
+ /(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source
+ ),
+ lookbehind: true,
+ greedy: true,
+ inside: {
+ 'regex-source': {
+ pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/,
+ lookbehind: true,
+ alias: 'language-regex',
+ inside: Prism.languages.regex
+ },
+ 'regex-delimiter': /^\/|\/$/,
+ 'regex-flags': /^[a-z]+$/,
+ }
+ },
+ // This must be declared before keyword because we use "function" inside the look-forward
+ 'function-variable': {
+ pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,
+ alias: 'function'
+ },
+ 'parameter': [
+ {
+ pattern: /(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,
+ lookbehind: true,
+ inside: Prism.languages.javascript
+ },
+ {
+ pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,
+ lookbehind: true,
+ inside: Prism.languages.javascript
+ },
+ {
+ pattern: /(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,
+ lookbehind: true,
+ inside: Prism.languages.javascript
+ },
+ {
+ pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,
+ lookbehind: true,
+ inside: Prism.languages.javascript
+ }
+ ],
+ 'constant': /\b[A-Z](?:[A-Z_]|\dx?)*\b/
+});
+
+Prism.languages.insertBefore('javascript', 'string', {
+ 'hashbang': {
+ pattern: /^#!.*/,
+ greedy: true,
+ alias: 'comment'
+ },
+ 'template-string': {
+ pattern: /`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,
+ greedy: true,
+ inside: {
+ 'template-punctuation': {
+ pattern: /^`|`$/,
+ alias: 'string'
+ },
+ 'interpolation': {
+ pattern: /((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,
+ lookbehind: true,
+ inside: {
+ 'interpolation-punctuation': {
+ pattern: /^\$\{|\}$/,
+ alias: 'punctuation'
+ },
+ rest: Prism.languages.javascript
+ }
+ },
+ 'string': /[\s\S]+/
+ }
+ },
+ 'string-property': {
+ pattern: /((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,
+ lookbehind: true,
+ greedy: true,
+ alias: 'property'
+ }
+});
+
+Prism.languages.insertBefore('javascript', 'operator', {
+ 'literal-property': {
+ pattern: /((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,
+ lookbehind: true,
+ alias: 'property'
+ },
+});
+
+if (Prism.languages.markup) {
+ Prism.languages.markup.tag.addInlined('script', 'javascript');
+
+ // add attribute support for all DOM events.
+ // https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events
+ Prism.languages.markup.tag.addAttribute(
+ /on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,
+ 'javascript'
+ );
+}
+
+Prism.languages.js = Prism.languages.javascript;
+
+Prism.languages.python = {
+ 'comment': {
+ pattern: /(^|[^\\])#.*/,
+ lookbehind: true,
+ greedy: true
+ },
+ 'string-interpolation': {
+ pattern: /(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,
+ greedy: true,
+ inside: {
+ 'interpolation': {
+ // "{" <expression> <optional "!s", "!r", or "!a"> <optional ":" format specifier> "}"
+ pattern: /((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,
+ lookbehind: true,
+ inside: {
+ 'format-spec': {
+ pattern: /(:)[^:(){}]+(?=\}$)/,
+ lookbehind: true
+ },
+ 'conversion-option': {
+ pattern: /![sra](?=[:}]$)/,
+ alias: 'punctuation'
+ },
+ rest: null
+ }
+ },
+ 'string': /[\s\S]+/
+ }
+ },
+ 'triple-quoted-string': {
+ pattern: /(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,
+ greedy: true,
+ alias: 'string'
+ },
+ 'string': {
+ pattern: /(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,
+ greedy: true
+ },
+ 'function': {
+ pattern: /((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,
+ lookbehind: true
+ },
+ 'class-name': {
+ pattern: /(\bclass\s+)\w+/i,
+ lookbehind: true
+ },
+ 'decorator': {
+ pattern: /(^[\t ]*)@\w+(?:\.\w+)*/m,
+ lookbehind: true,
+ alias: ['annotation', 'punctuation'],
+ inside: {
+ 'punctuation': /\./
+ }
+ },
+ 'keyword': /\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,
+ 'builtin': /\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,
+ 'boolean': /\b(?:False|None|True)\b/,
+ 'number': /\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,
+ 'operator': /[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,
+ 'punctuation': /[{}[\];(),.:]/
+};
+
+Prism.languages.python['string-interpolation'].inside['interpolation'].inside.rest = Prism.languages.python;
+
+Prism.languages.py = Prism.languages.python;
+
+Prism.languages.sql = {
+ 'comment': {
+ pattern: /(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,
+ lookbehind: true
+ },
+ 'variable': [
+ {
+ pattern: /@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,
+ greedy: true
+ },
+ /@[\w.$]+/
+ ],
+ 'string': {
+ pattern: /(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,
+ greedy: true,
+ lookbehind: true
+ },
+ 'identifier': {
+ pattern: /(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,
+ greedy: true,
+ lookbehind: true,
+ inside: {
+ 'punctuation': /^`|`$/
+ }
+ },
+ 'function': /\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i, // Should we highlight user defined functions too?
+ 'keyword': /\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,
+ 'boolean': /\b(?:FALSE|NULL|TRUE)\b/i,
+ 'number': /\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,
+ 'operator': /[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,
+ 'punctuation': /[;[\]()`,.]/
+};
+
+Prism.languages['visual-basic'] = {
+ 'comment': {
+ pattern: /(?:['‘’]|REM\b)(?:[^\r\n_]|_(?:\r\n?|\n)?)*/i,
+ inside: {
+ 'keyword': /^REM/i
+ }
+ },
+ 'directive': {
+ pattern: /#(?:Const|Else|ElseIf|End|ExternalChecksum|ExternalSource|If|Region)(?:\b_[ \t]*(?:\r\n?|\n)|.)+/i,
+ alias: 'property',
+ greedy: true
+ },
+ 'string': {
+ pattern: /\$?["“”](?:["“”]{2}|[^"“”])*["“”]C?/i,
+ greedy: true
+ },
+ 'date': {
+ pattern: /#[ \t]*(?:\d+([/-])\d+\1\d+(?:[ \t]+(?:\d+[ \t]*(?:AM|PM)|\d+:\d+(?::\d+)?(?:[ \t]*(?:AM|PM))?))?|\d+[ \t]*(?:AM|PM)|\d+:\d+(?::\d+)?(?:[ \t]*(?:AM|PM))?)[ \t]*#/i,
+ alias: 'number'
+ },
+ 'number': /(?:(?:\b\d+(?:\.\d+)?|\.\d+)(?:E[+-]?\d+)?|&[HO][\dA-F]+)(?:[FRD]|U?[ILS])?/i,
+ 'boolean': /\b(?:False|Nothing|True)\b/i,
+ 'keyword': /\b(?:AddHandler|AddressOf|Alias|And(?:Also)?|As|Boolean|ByRef|Byte|ByVal|Call|Case|Catch|C(?:Bool|Byte|Char|Date|Dbl|Dec|Int|Lng|Obj|SByte|Short|Sng|Str|Type|UInt|ULng|UShort)|Char|Class|Const|Continue|Currency|Date|Decimal|Declare|Default|Delegate|Dim|DirectCast|Do|Double|Each|Else(?:If)?|End(?:If)?|Enum|Erase|Error|Event|Exit|Finally|For|Friend|Function|Get(?:Type|XMLNamespace)?|Global|GoSub|GoTo|Handles|If|Implements|Imports|In|Inherits|Integer|Interface|Is|IsNot|Let|Lib|Like|Long|Loop|Me|Mod|Module|Must(?:Inherit|Override)|My(?:Base|Class)|Namespace|Narrowing|New|Next|Not(?:Inheritable|Overridable)?|Object|Of|On|Operator|Option(?:al)?|Or(?:Else)?|Out|Overloads|Overridable|Overrides|ParamArray|Partial|Private|Property|Protected|Public|RaiseEvent|ReadOnly|ReDim|RemoveHandler|Resume|Return|SByte|Select|Set|Shadows|Shared|short|Single|Static|Step|Stop|String|Structure|Sub|SyncLock|Then|Throw|To|Try|TryCast|Type|TypeOf|U(?:Integer|Long|Short)|Until|Using|Variant|Wend|When|While|Widening|With(?:Events)?|WriteOnly|Xor)\b/i,
+ 'operator': /[+\-*/\\^<=>&#@$%!]|\b_(?=[ \t]*[\r\n])/,
+ 'punctuation': /[{}().,:?]/
+};
+
+Prism.languages.vb = Prism.languages['visual-basic'];
+Prism.languages.vba = Prism.languages['visual-basic'];
+
+(function () {
+
+ if (typeof Prism === 'undefined' || typeof document === 'undefined') {
+ return;
+ }
+
+ /**
+ * Plugin name which is used as a class name for <pre> which is activating the plugin
+ *
+ * @type {string}
+ */
+ var PLUGIN_NAME = 'line-numbers';
+
+ /**
+ * Regular expression used for determining line breaks
+ *
+ * @type {RegExp}
+ */
+ var NEW_LINE_EXP = /\n(?!$)/g;
+
+
+ /**
+ * Global exports
+ */
+ var config = Prism.plugins.lineNumbers = {
+ /**
+ * Get node for provided line number
+ *
+ * @param {Element} element pre element
+ * @param {number} number line number
+ * @returns {Element|undefined}
+ */
+ getLine: function (element, number) {
+ if (element.tagName !== 'PRE' || !element.classList.contains(PLUGIN_NAME)) {
+ return;
+ }
+
+ var lineNumberRows = element.querySelector('.line-numbers-rows');
+ if (!lineNumberRows) {
+ return;
+ }
+ var lineNumberStart = parseInt(element.getAttribute('data-start'), 10) || 1;
+ var lineNumberEnd = lineNumberStart + (lineNumberRows.children.length - 1);
+
+ if (number < lineNumberStart) {
+ number = lineNumberStart;
+ }
+ if (number > lineNumberEnd) {
+ number = lineNumberEnd;
+ }
+
+ var lineIndex = number - lineNumberStart;
+
+ return lineNumberRows.children[lineIndex];
+ },
+
+ /**
+ * Resizes the line numbers of the given element.
+ *
+ * This function will not add line numbers. It will only resize existing ones.
+ *
+ * @param {HTMLElement} element A `<pre>` element with line numbers.
+ * @returns {void}
+ */
+ resize: function (element) {
+ resizeElements([element]);
+ },
+
+ /**
+ * Whether the plugin can assume that the units font sizes and margins are not depended on the size of
+ * the current viewport.
+ *
+ * Setting this to `true` will allow the plugin to do certain optimizations for better performance.
+ *
+ * Set this to `false` if you use any of the following CSS units: `vh`, `vw`, `vmin`, `vmax`.
+ *
+ * @type {boolean}
+ */
+ assumeViewportIndependence: true
+ };
+
+ /**
+ * Resizes the given elements.
+ *
+ * @param {HTMLElement[]} elements
+ */
+ function resizeElements(elements) {
+ elements = elements.filter(function (e) {
+ var codeStyles = getStyles(e);
+ var whiteSpace = codeStyles['white-space'];
+ return whiteSpace === 'pre-wrap' || whiteSpace === 'pre-line';
+ });
+
+ if (elements.length == 0) {
+ return;
+ }
+
+ var infos = elements.map(function (element) {
+ var codeElement = element.querySelector('code');
+ var lineNumbersWrapper = element.querySelector('.line-numbers-rows');
+ if (!codeElement || !lineNumbersWrapper) {
+ return undefined;
+ }
+
+ /** @type {HTMLElement} */
+ var lineNumberSizer = element.querySelector('.line-numbers-sizer');
+ var codeLines = codeElement.textContent.split(NEW_LINE_EXP);
+
+ if (!lineNumberSizer) {
+ lineNumberSizer = document.createElement('span');
+ lineNumberSizer.className = 'line-numbers-sizer';
+
+ codeElement.appendChild(lineNumberSizer);
+ }
+
+ lineNumberSizer.innerHTML = '0';
+ lineNumberSizer.style.display = 'block';
+
+ var oneLinerHeight = lineNumberSizer.getBoundingClientRect().height;
+ lineNumberSizer.innerHTML = '';
+
+ return {
+ element: element,
+ lines: codeLines,
+ lineHeights: [],
+ oneLinerHeight: oneLinerHeight,
+ sizer: lineNumberSizer,
+ };
+ }).filter(Boolean);
+
+ infos.forEach(function (info) {
+ var lineNumberSizer = info.sizer;
+ var lines = info.lines;
+ var lineHeights = info.lineHeights;
+ var oneLinerHeight = info.oneLinerHeight;
+
+ lineHeights[lines.length - 1] = undefined;
+ lines.forEach(function (line, index) {
+ if (line && line.length > 1) {
+ var e = lineNumberSizer.appendChild(document.createElement('span'));
+ e.style.display = 'block';
+ e.textContent = line;
+ } else {
+ lineHeights[index] = oneLinerHeight;
+ }
+ });
+ });
+
+ infos.forEach(function (info) {
+ var lineNumberSizer = info.sizer;
+ var lineHeights = info.lineHeights;
+
+ var childIndex = 0;
+ for (var i = 0; i < lineHeights.length; i++) {
+ if (lineHeights[i] === undefined) {
+ lineHeights[i] = lineNumberSizer.children[childIndex++].getBoundingClientRect().height;
+ }
+ }
+ });
+
+ infos.forEach(function (info) {
+ var lineNumberSizer = info.sizer;
+ var wrapper = info.element.querySelector('.line-numbers-rows');
+
+ lineNumberSizer.style.display = 'none';
+ lineNumberSizer.innerHTML = '';
+
+ info.lineHeights.forEach(function (height, lineNumber) {
+ wrapper.children[lineNumber].style.height = height + 'px';
+ });
+ });
+ }
+
+ /**
+ * Returns style declarations for the element
+ *
+ * @param {Element} element
+ */
+ function getStyles(element) {
+ if (!element) {
+ return null;
+ }
+
+ return window.getComputedStyle ? getComputedStyle(element) : (element.currentStyle || null);
+ }
+
+ var lastWidth = undefined;
+ window.addEventListener('resize', function () {
+ if (config.assumeViewportIndependence && lastWidth === window.innerWidth) {
+ return;
+ }
+ lastWidth = window.innerWidth;
+
+ resizeElements(Array.prototype.slice.call(document.querySelectorAll('pre.' + PLUGIN_NAME)));
+ });
+
+ Prism.hooks.add('complete', function (env) {
+ if (!env.code) {
+ return;
+ }
+
+ var code = /** @type {Element} */ (env.element);
+ var pre = /** @type {HTMLElement} */ (code.parentNode);
+
+ // works only for <code> wrapped inside <pre> (not inline)
+ if (!pre || !/pre/i.test(pre.nodeName)) {
+ return;
+ }
+
+ // Abort if line numbers already exists
+ if (code.querySelector('.line-numbers-rows')) {
+ return;
+ }
+
+ // only add line numbers if <code> or one of its ancestors has the `line-numbers` class
+ if (!Prism.util.isActive(code, PLUGIN_NAME)) {
+ return;
+ }
+
+ // Remove the class 'line-numbers' from the <code>
+ code.classList.remove(PLUGIN_NAME);
+ // Add the class 'line-numbers' to the <pre>
+ pre.classList.add(PLUGIN_NAME);
+
+ var match = env.code.match(NEW_LINE_EXP);
+ var linesNum = match ? match.length + 1 : 1;
+ var lineNumbersWrapper;
+
+ var lines = new Array(linesNum + 1).join('<span></span>');
+
+ lineNumbersWrapper = document.createElement('span');
+ lineNumbersWrapper.setAttribute('aria-hidden', 'true');
+ lineNumbersWrapper.className = 'line-numbers-rows';
+ lineNumbersWrapper.innerHTML = lines;
+
+ if (pre.hasAttribute('data-start')) {
+ pre.style.counterReset = 'linenumber ' + (parseInt(pre.getAttribute('data-start'), 10) - 1);
+ }
+
+ env.element.appendChild(lineNumbersWrapper);
+
+ resizeElements([pre]);
+
+ Prism.hooks.run('line-numbers', env);
+ });
+
+ Prism.hooks.add('line-numbers', function (env) {
+ env.plugins = env.plugins || {};
+ env.plugins.lineNumbers = true;
+ });
+
+}());
+
+(function () {
+
+ if (typeof Prism === 'undefined') {
+ return;
+ }
+
+ var assign = Object.assign || function (obj1, obj2) {
+ for (var name in obj2) {
+ if (obj2.hasOwnProperty(name)) {
+ obj1[name] = obj2[name];
+ }
+ }
+ return obj1;
+ };
+
+ function NormalizeWhitespace(defaults) {
+ this.defaults = assign({}, defaults);
+ }
+
+ function toCamelCase(value) {
+ return value.replace(/-(\w)/g, function (match, firstChar) {
+ return firstChar.toUpperCase();
+ });
+ }
+
+ function tabLen(str) {
+ var res = 0;
+ for (var i = 0; i < str.length; ++i) {
+ if (str.charCodeAt(i) == '\t'.charCodeAt(0)) {
+ res += 3;
+ }
+ }
+ return str.length + res;
+ }
+
+ NormalizeWhitespace.prototype = {
+ setDefaults: function (defaults) {
+ this.defaults = assign(this.defaults, defaults);
+ },
+ normalize: function (input, settings) {
+ settings = assign(this.defaults, settings);
+
+ for (var name in settings) {
+ var methodName = toCamelCase(name);
+ if (name !== 'normalize' && methodName !== 'setDefaults' &&
+ settings[name] && this[methodName]) {
+ input = this[methodName].call(this, input, settings[name]);
+ }
+ }
+
+ return input;
+ },
+
+ /*
+ * Normalization methods
+ */
+ leftTrim: function (input) {
+ return input.replace(/^\s+/, '');
+ },
+ rightTrim: function (input) {
+ return input.replace(/\s+$/, '');
+ },
+ tabsToSpaces: function (input, spaces) {
+ spaces = spaces|0 || 4;
+ return input.replace(/\t/g, new Array(++spaces).join(' '));
+ },
+ spacesToTabs: function (input, spaces) {
+ spaces = spaces|0 || 4;
+ return input.replace(RegExp(' {' + spaces + '}', 'g'), '\t');
+ },
+ removeTrailing: function (input) {
+ return input.replace(/\s*?$/gm, '');
+ },
+ // Support for deprecated plugin remove-initial-line-feed
+ removeInitialLineFeed: function (input) {
+ return input.replace(/^(?:\r?\n|\r)/, '');
+ },
+ removeIndent: function (input) {
+ var indents = input.match(/^[^\S\n\r]*(?=\S)/gm);
+
+ if (!indents || !indents[0].length) {
+ return input;
+ }
+
+ indents.sort(function (a, b) { return a.length - b.length; });
+
+ if (!indents[0].length) {
+ return input;
+ }
+
+ return input.replace(RegExp('^' + indents[0], 'gm'), '');
+ },
+ indent: function (input, tabs) {
+ return input.replace(/^[^\S\n\r]*(?=\S)/gm, new Array(++tabs).join('\t') + '$&');
+ },
+ breakLines: function (input, characters) {
+ characters = (characters === true) ? 80 : characters|0 || 80;
+
+ var lines = input.split('\n');
+ for (var i = 0; i < lines.length; ++i) {
+ if (tabLen(lines[i]) <= characters) {
+ continue;
+ }
+
+ var line = lines[i].split(/(\s+)/g);
+ var len = 0;
+
+ for (var j = 0; j < line.length; ++j) {
+ var tl = tabLen(line[j]);
+ len += tl;
+ if (len > characters) {
+ line[j] = '\n' + line[j];
+ len = tl;
+ }
+ }
+ lines[i] = line.join('');
+ }
+ return lines.join('\n');
+ }
+ };
+
+ // Support node modules
+ if (typeof module !== 'undefined' && module.exports) {
+ module.exports = NormalizeWhitespace;
+ }
+
+ Prism.plugins.NormalizeWhitespace = new NormalizeWhitespace({
+ 'remove-trailing': true,
+ 'remove-indent': true,
+ 'left-trim': true,
+ 'right-trim': true,
+ /*'break-lines': 80,
+ 'indent': 2,
+ 'remove-initial-line-feed': false,
+ 'tabs-to-spaces': 4,
+ 'spaces-to-tabs': 4*/
+ });
+
+ Prism.hooks.add('before-sanity-check', function (env) {
+ var Normalizer = Prism.plugins.NormalizeWhitespace;
+
+ // Check settings
+ if (env.settings && env.settings['whitespace-normalization'] === false) {
+ return;
+ }
+
+ // Check classes
+ if (!Prism.util.isActive(env.element, 'whitespace-normalization', true)) {
+ return;
+ }
+
+ // Simple mode if there is no env.element
+ if ((!env.element || !env.element.parentNode) && env.code) {
+ env.code = Normalizer.normalize(env.code, env.settings);
+ return;
+ }
+
+ // Normal mode
+ var pre = env.element.parentNode;
+ if (!env.code || !pre || pre.nodeName.toLowerCase() !== 'pre') {
+ return;
+ }
+
+ var children = pre.childNodes;
+ var before = '';
+ var after = '';
+ var codeFound = false;
+
+ // Move surrounding whitespace from the <pre> tag into the <code> tag
+ for (var i = 0; i < children.length; ++i) {
+ var node = children[i];
+
+ if (node == env.element) {
+ codeFound = true;
+ } else if (node.nodeName === '#text') {
+ if (codeFound) {
+ after += node.nodeValue;
+ } else {
+ before += node.nodeValue;
+ }
+
+ pre.removeChild(node);
+ --i;
+ }
+ }
+
+ if (!env.element.children.length || !Prism.plugins.KeepMarkup) {
+ env.code = before + env.code + after;
+ env.code = Normalizer.normalize(env.code, env.settings);
+ } else {
+ // Preserve markup for keep-markup plugin
+ var html = before + env.element.innerHTML + after;
+ env.element.innerHTML = Normalizer.normalize(html, env.settings);
+ env.code = env.element.textContent;
+ }
+ });
+
+}());
+
diff --git a/helpcontent2/help3xsl/xap_templ_query.xsl b/helpcontent2/help3xsl/xap_templ_query.xsl
new file mode 100644
index 000000000..51f2fea3c
--- /dev/null
+++ b/helpcontent2/help3xsl/xap_templ_query.xsl
@@ -0,0 +1,295 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+* This file is part of the LibreOffice project.
+*
+* 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 http://mozilla.org/MPL/2.0/.
+-->
+<!--
+Stylesheet to create the localized xapian template.
+Based on the query template from xapian
+Usage:
+xsltproc xap_template_query.xsl <file.xhp>
+-->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:param name="lang"/>
+ <xsl:param name="productname"/>
+ <xsl:param name="productversion"/>
+ <xsl:output indent="yes" method="text"/>
+ <xsl:variable name="target" select="concat('/',$productversion,'/')"/>
+ <!-- Strings for the help UI page -->
+ <xsl:variable name ="ui_contents"><xsl:apply-templates select="//variable[@id='contents']"/></xsl:variable>
+ <xsl:variable name ="ui_index"><xsl:apply-templates select="//variable[@id='index']"/></xsl:variable>
+ <xsl:variable name ="ui_pholderall"><xsl:apply-templates select="//variable[@id='pholderall']"/></xsl:variable>
+ <xsl:variable name ="ui_pholderchosen"><xsl:apply-templates select="//variable[@id='pholderchosen']"/></xsl:variable>
+ <xsl:variable name ="ui_module"><xsl:apply-templates select="//variable[@id='module']"/></xsl:variable>
+ <xsl:variable name ="ui_language"><xsl:apply-templates select="//variable[@id='language']"/></xsl:variable>
+ <xsl:variable name ="ui_donate"><xsl:apply-templates select="//variable[@id='donate']"/></xsl:variable>
+ <xsl:variable name ="ui_logo"><xsl:apply-templates select="//variable[@id='LibreOfficeHelp']"/></xsl:variable>
+ <xsl:variable name ="ui_selectmodule"><xsl:apply-templates select="//variable[@id='selectmodule']"/></xsl:variable>
+ <xsl:variable name ="ui_selectlang"><xsl:apply-templates select="//variable[@id='selectlanguage']"/></xsl:variable>
+ <xsl:variable name ="ui_search"><xsl:apply-templates select="//variable[@id='searchhelpcontents']"/></xsl:variable>
+
+ <xsl:variable name="brand3" select="'%PRODUCTNAME'"/>
+ <xsl:variable name="brand4" select="'%PRODUCTVERSION'"/>
+
+
+<xsl:template match="/">
+<![CDATA[$httpheader{Content-Type,text/html; charset=utf-8}<!DOCTYPE html><html lang="]]><xsl:value-of select="$lang"/><![CDATA[">
+<base href="]]><xsl:value-of select="$target"/><![CDATA["/>
+$set{flag_spelling,$ne{$cgi{SPELL},0}}
+$set{stemmer,$if{$cgi{STEMMER},$cgi{STEMMER},none}}
+$set{flag_spelling_correction,true}
+$set{thousand,$.}$set{decimal,.}
+$setmap{prefix,,$split{ S B F},title,S,author,A,topic,B}
+${
+$def{PREV,
+$if{$ne{$topdoc,0},<input type=image name="&lt;" alt="&lt;"
+src="/images/xapian-omega/prev.png" height=30 width=30>,
+<img alt="" src="/images/xapian-omega/prevoff.png" height=30 width=30>}
+}
+
+$def{NEXT,
+$if{$ne{$last,$msize},<input type=image name="&gt;" alt="&gt;"
+src="/images/xapian-omega/next.png" height=30 width=30>,
+<img alt="" src="/images/xapian-omega/nextoff.png" height=30 width=30>}
+}
+
+$def{P,<input type=image name="$1" value="$1" src="/images/xapian-omega/page-$2.png" $opt{a} alt="$1">}
+$def{PAGE,$if{$gt{$1,9},$if{$gt{$1,99},$P{$1,$div{$1,100}}}$P{$1,$mod{$div{$1,10},10}}}$P{$1,$mod{$1,10}}}
+
+$def{S,<img src="/images/xapian-omega/page-$2s.png" $opt{a} alt=$1>}
+$def{SPAGE,$if{$gt{$1,9},$if{$gt{$1,99},$S{$1,$div{$1,100}}}$S{$1,$mod{$div{$1,10},10}}}$S{$1,$mod{$1,10}}}
+}
+
+$def{PREV,$if{$ne{$topdoc,0},<input type=submit name="&lt;" value="]]><xsl:apply-templates select="//variable[@id='xap_previous']"/><![CDATA[">}}
+
+$def{PAGE,<input type=submit name="[" value="$1">}
+
+$def{SPAGE,<input type=submit name="[" value="$1" disabled=disabled>}
+
+ $def{NEXT,$if{$ne{$last,$msize},<input type=submit name="&gt;" value="]]><xsl:apply-templates select="//variable[@id='xap_next']"/><![CDATA[">}}
+
+<head>
+<title>$if{$query,Omega Search: $html{$query},Omega Search}</title>
+<!--$if{$opt{topterms},$include{inc/toptermsjs}}-->
+<link rel="shortcut icon" href="media/navigation/favicon.ico"/>
+<link type="text/css" href="normalize.css" rel="Stylesheet"/>
+<link type="text/css" href="default.css" rel="Stylesheet"/>
+<link type="text/css" href="prism.css" rel="Stylesheet"/>
+<script type="text/javascript" src="polyfills.js"></script>
+<script type="text/javascript" src="languages.js"></script>
+<script type="text/javascript" src="]]><xsl:value-of select="$lang"/><![CDATA[/langnames.js"></script>
+<script type="text/javascript" src="flexsearch.debug.js"></script>
+<script type="text/javascript" src="prism.js"></script>
+<script type="text/javascript" src="help2.js" defer=""></script>
+<script type="text/javascript" src="a11y-toggle.js" defer=""></script>
+<script type="text/javascript" src="paginathing.js" defer=""></script>
+<script type="text/javascript" src="]]><xsl:value-of select="$lang"/><![CDATA[/bookmarks.js" defer=""></script>
+<script type="text/javascript" src="]]><xsl:value-of select="$lang"/><![CDATA[/contents.js" defer=""></script>
+<script type="text/javascript" src="help.js" defer=""></script>
+<meta name="viewport" content="width=device-width,initial-scale=1"/>
+<style>
+input[type=image] {
+ border: 0px;
+ }
+</style>
+<script type="text/javascript">
+function f2(n) {return (n>9?"":"0")+n;}
+function write_date(time_t) {
+var d=new Date();d.setTime(time_t*1000);
+var D=d.getFullYear()+"-"+f2(d.getMonth()+1)+"-"+f2(d.getDate());
+var T=f2(d.getHours())+":"+f2(d.getMinutes())+":"+f2(d.getSeconds());
+document.write("<span title=\""+D+" "+T+"\">]]><xsl:apply-templates select="//variable[@id='xap_modified']"/><![CDATA[<br><b>"+D+"</b></span>");
+}
+</script>
+</head>
+<body>
+<div id="TopLeftHeader">
+ <header>
+ <div class="logo-container">
+ <a class="logo" href="]]><xsl:value-of select="$lang"/><![CDATA[/text/shared/05/new_help.html">
+ <div class="symbol"></div>
+ <p>]]><xsl:value-of select="$ui_logo"/><![CDATA[</p>
+ </a>
+ </div>
+ </header>
+</div>
+<div class="modules">
+ <button type="button" data-a11y-toggle="modules-nav" id="modules" onclick="setupModules(']]><xsl:value-of select="$lang"/><![CDATA[');">]]><xsl:value-of select="$ui_module"/><![CDATA[
+ </button>
+ <nav id="modules-nav"/><!-- is filled in via setupModules() on demand -->
+</div>
+<aside class="rightside">
+ <input id="accordion-1" name="accordion-menu" type="checkbox"/>
+ <label for="accordion-1">]]><xsl:value-of select="$ui_contents"/><![CDATA[</label>
+ <div id="Contents" class="contents-treeview"></div>
+</aside>
+<aside class="leftside">
+ <div id="Index">
+ <div class="index-label">]]><xsl:value-of select="$ui_index"/><![CDATA[ &#32;&#x1f50e;&#xfe0e;&#32;</div>
+ <div id="Bookmarks">
+ <input id="search-bar" type="search" class="search" placeholder="]]><xsl:value-of select="$ui_pholderchosen"/><![CDATA["/>
+ <nav class="index"></nav>
+ </div>
+ </div>
+</aside>
+<div id="DonationFrame">
+ <div class="donation">
+ <p><a href="https://www.libreoffice.org/donate/?pk_campaign=help" target ="_blank">]]><xsl:value-of select="$ui_donate"/><![CDATA[</a></p>
+ </div>
+</div>
+<div id="SearchFrame">
+ <div class="xapian-omega-search">
+ </div>
+</div>
+<div id="DisplayArea">
+ <form name="P" method="get" action="]]><xsl:value-of select="$lang"/><![CDATA[/search" target="_top">
+<center>
+<input id="omega-autofocus" type=search name=P value="$html{$query}" size=40 autofocus>
+<script>
+if (!("autofocus" in document.createElement("input")))
+ document.getElementById("omega-autofocus").focus();
+</script>
+<input type="submit" class="xapian-omega-search-button" value="&#x1f50d;"/>
+<hr>
+<input type=radio name=DEFAULTOP value=and $if{$eq{$defaultop,and},checked}>]]><xsl:apply-templates select="//variable[@id='xap_match_all']"/><![CDATA[
+<input type=radio name=DEFAULTOP value=or $if{$eq{$defaultop,or},checked}>]]><xsl:apply-templates select="//variable[@id='xap_match_any']"/><![CDATA[
+$if{$opt{topterms},
+ <div title="Suggested terms to add to your query"
+ style="text-align:left;background:#cfc;border:1px solid green;padding:2px;font:11px verdana$. arial$. helvetica$. sans-serif;">
+ $map{$topterms,<span style="white-space:nowrap"><input type=checkbox name=X value="$html{$prettyterm{$_}}" onClick="C(this)">$html{$prettyterm{$_}}</span> }
+ <br><noscript><input type=hidden name=ADD value=1></noscript>
+ </div>
+}
+<br>
+$if{$suggestion,]]><xsl:apply-templates select="//variable[@id='xap_didyoumean']"/><![CDATA[ <a href="$html{$or{$env{SCRIPT_NAME},omega}?P=$url{$suggestion}$if{$ne{$hitsperpage,10},&HITSPERPAGE=$hitsperpage}$if{$cgi{COLLAPSE},&COLLAPSE=$url{$cgi{COLLAPSE}}}$map{$relevants,&R=$_}$if{$cgi{THRESHOLD},&THRESHOLD=$url{$cgi{THRESHOLD}}}$map{$cgilist{B},&B=$url{$_}}&SPELL=0}">$html{$suggestion}</a><br>}
+
+$or{$html{$error},
+$if{$eq{$msize,0},
+$if{$query,]]><xsl:apply-templates select="//variable[@id='xap_no_match']"/><![CDATA[,
+<hr>]]><xsl:apply-templates select="//variable[@id='xap_searching_doc']"/><![CDATA[
+},
+$if{$not{$msizeexact},
+$nice{$add{$topdoc,1}}-$nice{$last} ]]><xsl:apply-templates select="//variable[@id='xap_about']"/><![CDATA[,
+ $if{$and{$eq{$last,$msize},$eq{$topdoc,0}},
+ ]]><xsl:apply-templates select="//variable[@id='xap_allmatches']"/><![CDATA[ ,
+ $nice{$add{$topdoc,1}}$if{$ne{$add{$topdoc,1},$last},-$nice{$last}} ]]><xsl:apply-templates select="//variable[@id='xap_exactly']"/><![CDATA[}
+}
+<hr>
+
+</center>
+$if{$map{$queryterms,$set{U,$unstem{$_}}$set{F_$opt{U},$add{$opt{F_$opt{U}},$freq{$_}}}},$list{$unique{$map{$queryterms,$set{U,$unstem{$_}}$list{$html{$unique{$opt{U}}},<b>,</b>/<b>,</b>}:&nbsp;$nice{$opt{F_$opt{U}}}}},]]><xsl:apply-templates select="//variable[@id='xap_term_frequencies']"/><![CDATA[ ,$. ,}}
+<br><small>]]><xsl:apply-templates select="//variable[@id='xap_searchtimes']"/><![CDATA[</small>
+<table>
+$hitlist{<tr><td valign=top>
+${<img src="/images/xapian-omega/score-$div{$percentage,10}.png" alt="$percentage%" height=16 width=32>}
+<div title="$percentage%" style='float:left;width:60px;height:10px;border:1px solid black;margin-top:4px;'>
+<div style='width:$div{$mul{$percentage,6},10}px; height:10px; background-color: red;'>
+</div></div>
+<div style='float:left;margin-top:2px;font-size:x-small;'>
+$if{$and{$field{modtime},$ne{$field{modtime},-1}},
+<script type="text/javascript">write_date($add{$field{modtime}});</script>
+<noscript>
+<span title="$html{$date{$field{modtime},%Y-%m-%d %H:%M:%S}}">
+]]><xsl:apply-templates select="//variable[@id='xap_modified']"/><![CDATA[<br><b>$html{$date{$field{modtime},%Y-%m-%d}}</b></span>
+</noscript><br>
+}
+$if{$field{language},]]><xsl:apply-templates select="//variable[@id='xap_lang']"/><![CDATA[<b>$html{$field{language}}</b><br>}
+$if{$field{size},<span title="$html{$field{size}} bytes">]]><xsl:apply-templates select="//variable[@id='xap_size']"/><![CDATA[<b>$html{$filesize{$field{size}}}</b></span><br>}
+<div title="]]><xsl:apply-templates select="//variable[@id='xap_relevant']"/><![CDATA[" style="float:left;background-color:#cfc;border:1px solid green;margin-top:2px;">
+<input type=checkbox name=R value=$id$if{$relevant, checked}>
+</div>
+</div>
+</td>
+<td><b><a href="$html{$field{url}}">$html{$or{$field{caption},$field{title},$prettyurl{$field{url}},Untitled}}</a></b><br>
+<small>$snippet{$field{sample}}</small><br>
+<a href="$html{$field{url}}">$html{$prettyurl{$field{url}}}</a><br>
+<small>
+]]><xsl:apply-templates select="//variable[@id='xap_matching']"/><![CDATA[
+<i>$list{$map{$terms,$html{$prettyterm{$_}}},</i>$. <i>,</i> and <i>}</i></small>${for lynx:}<p></td></tr>}
+</table>
+
+<br><center>
+
+${suppress next, prev, and page links if there's only one page}
+$if{$ne{$lastpage,1},
+$set{a,$if{$opt{pagelink_height}, HEIGHT=$opt{pagelink_height}}$if{$opt{pagelink_width}, WIDTH=$opt{pagelink_width}}}
+
+${1-W ... X-(this)-Y ...}
+$set{w,$min{3,$add{$thispage,-1}}}
+$set{x,$max{$add{$opt{w},1},$add{$thispage,-3}}}
+$set{y,$min{$lastpage,$add{$thispage,8}}}
+$PREV
+$map{$range{1,$opt{w}},$PAGE{$_}}
+$if{$ne{$add{$opt{w},1},$opt{x}},...}
+$map{$range{$opt{x},$add{$thispage,-1}},$PAGE{$_}}
+$SPAGE{$thispage}
+$map{$range{$add{$thispage,1},$opt{y}},$PAGE{$_}}
+$if{$ne{$opt{y},$lastpage},...}
+$NEXT
+}
+}}
+</center><br>
+$if{$ne{$topdoc,0},<input type=hidden name=TOPDOC value=$topdoc>}
+$if{$ne{$hitsperpage,10},<input type=hidden name=HITSPERPAGE value=$hitsperpage>}
+$if{$cgi{COLLAPSE},<input type=hidden name=COLLAPSE value="$html{$cgi{COLLAPSE}}">}
+$if{$queryterms,<input type=hidden name=xP value="$html{$queryterms}">}
+<input type=hidden name=xFILTERS value="$html{$filters}">
+$list{$relevants,<input type=hidden name=R value=",.,">}
+$if{$cgi{THRESHOLD},<input type=hidden name=THRESHOLD value="$html{$cgi{THRESHOLD}}">}
+${Preserve any B filters used - this needs modifying if you modify this template
+ to have B on radio buttons, SELECT, etc}
+$map{$cgilist{B},<input type=hidden name=B value="$html{$_}">}
+</form>
+<hr><div align=right><i><small><a href="https://xapian.org/">$html{$version}</a></small></i></div>
+ <footer>
+ <p><a href="https://www.libreoffice.org/imprint" target="_blank">Impressum (Legal Info)</a> | <a href="https://www.libreoffice.org/privacy" target="_blank">Privacy Policy</a> | <a href="https://www.documentfoundation.org/statutes.pdf" target="_blank">Statutes (non-binding English translation)</a> - <a href="https://www.documentfoundation.org/satzung.pdf" target="_blank">Satzung (binding German version)</a> | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the <a href="https://www.libreoffice.org/download/license/" target="_blank">Mozilla Public License v2.0</a>. “LibreOffice” and “The Document Foundation” are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our <a href="https://wiki.documentfoundation.org/TradeMark_Policy" target="_blank">trademark policy</a>. LibreOffice was based on OpenOffice.org.</p>
+ </footer>
+</body>
+</html>
+$log{query.log}
+</div>
+]]>
+</xsl:template>
+
+<xsl:template match="text()">
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string"><xsl:value-of select="."/></xsl:with-param>
+ </xsl:call-template>
+</xsl:template>
+
+<!-- Branding -->
+<xsl:template name="brand" >
+ <xsl:param name="string"/>
+ <xsl:choose>
+ <xsl:when test="contains($string,$brand3)">
+ <xsl:variable name="newstr">
+ <xsl:value-of select="substring-before($string,$brand3)"/>
+ <xsl:value-of select="$productname"/>
+ <xsl:value-of select="substring-after($string,$brand3)"/>
+ </xsl:variable>
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string" select="$newstr"/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:when test="contains($string,$brand4)">
+ <xsl:variable name="newstr">
+ <xsl:value-of select="substring-before($string,$brand4)"/>
+ <xsl:value-of select="$productversion"/>
+ <xsl:value-of select="substring-after($string,$brand4)"/>
+ </xsl:variable>
+ <xsl:call-template name="brand">
+ <xsl:with-param name="string" select="$newstr"/>
+ </xsl:call-template>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:value-of select="$string"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+</xsl:stylesheet>