xref: /plugin/combo/ComboStrap/Bootstrap.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
137748cd8SNickeau<?php
237748cd8SNickeau/**
337748cd8SNickeau * Copyright (c) 2021. ComboStrap, Inc. and its affiliates. All Rights Reserved.
437748cd8SNickeau *
537748cd8SNickeau * This source code is licensed under the GPL license found in the
637748cd8SNickeau * COPYING  file in the root directory of this source tree.
737748cd8SNickeau *
837748cd8SNickeau * @license  GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html)
937748cd8SNickeau * @author   ComboStrap <support@combostrap.com>
1037748cd8SNickeau *
1137748cd8SNickeau */
1237748cd8SNickeau
1337748cd8SNickeaunamespace ComboStrap;
1437748cd8SNickeau
15*04fd306cSNickeauuse action_plugin_combo_snippetsbootstrap;
16*04fd306cSNickeauuse ComboStrap\Web\Url;
17*04fd306cSNickeauuse Exception;
18*04fd306cSNickeau
1937748cd8SNickeauclass Bootstrap
2037748cd8SNickeau{
21*04fd306cSNickeau    const DEFAULT_STYLESHEET_NAME = "bootstrap";
22*04fd306cSNickeau    const TAG = self::CANONICAL;
23*04fd306cSNickeau    public const DEFAULT_MAJOR = 5;
24*04fd306cSNickeau    public const VERSION_501 = self::DEFAULT_MAJOR . ".0.1";
25*04fd306cSNickeau    public const DEFAULT_BOOTSTRAP_4_VERSION = "4.5.0";
26*04fd306cSNickeau    public const DEFAULT_BOOTSTRAP_5_VERSION = self::VERSION_501;
27*04fd306cSNickeau    public const DEFAULT_BOOTSTRAP_STYLESHEET_4_VERSION = self::DEFAULT_BOOTSTRAP_4_VERSION . " - " . self::DEFAULT_STYLESHEET_NAME;
28*04fd306cSNickeau    public const DEFAULT_BOOTSTRAP_STYLESHEET_5_VERSION = self::DEFAULT_BOOTSTRAP_5_VERSION . " - " . self::DEFAULT_STYLESHEET_NAME;
2937748cd8SNickeau
30*04fd306cSNickeau    private Snippet $jquerySnippet;
31*04fd306cSNickeau    private Snippet $jsSnippet;
32*04fd306cSNickeau    private Snippet $popperSnippet;
33*04fd306cSNickeau    private Snippet $cssSnippet;
3437748cd8SNickeau
35*04fd306cSNickeau    /**
36*04fd306cSNickeau     * @param string $qualifiedVersion - the bootstrap version separated by the stylesheet
37*04fd306cSNickeau     */
38*04fd306cSNickeau    public function __construct(string $qualifiedVersion)
39*04fd306cSNickeau    {
40*04fd306cSNickeau        $bootstrapStyleSheetArray = explode(Bootstrap::BOOTSTRAP_VERSION_STYLESHEET_SEPARATOR, $qualifiedVersion);
41*04fd306cSNickeau        $this->version = $bootstrapStyleSheetArray[0];
42*04fd306cSNickeau        /**
43*04fd306cSNickeau         * In case the input is just the major version
44*04fd306cSNickeau         */
45*04fd306cSNickeau        switch ($this->version) {
46*04fd306cSNickeau            case "4":
47*04fd306cSNickeau                $this->version = self::DEFAULT_BOOTSTRAP_4_VERSION;
48*04fd306cSNickeau                break;
49*04fd306cSNickeau            case "5":
50*04fd306cSNickeau                $this->version = self::DEFAULT_BOOTSTRAP_5_VERSION;
51*04fd306cSNickeau                break;
52*04fd306cSNickeau        }
53*04fd306cSNickeau
54*04fd306cSNickeau        /**
55*04fd306cSNickeau         * Stylesheet
56*04fd306cSNickeau         */
57*04fd306cSNickeau        if (isset($bootstrapStyleSheetArray[1])) {
58*04fd306cSNickeau            $this->styleSheetName = $bootstrapStyleSheetArray[1];
59*04fd306cSNickeau        } else {
60*04fd306cSNickeau            $this->styleSheetName = self::DEFAULT_STYLESHEET_NAME;
61*04fd306cSNickeau        }
62*04fd306cSNickeau
63*04fd306cSNickeau        $this->build();
64*04fd306cSNickeau
65*04fd306cSNickeau    }
66*04fd306cSNickeau
67*04fd306cSNickeau
68*04fd306cSNickeau    const BootStrapFiveMajorVersion = 5;
69*04fd306cSNickeau    const BootStrapFourMajorVersion = 4;
7037748cd8SNickeau    const CANONICAL = "bootstrap";
71*04fd306cSNickeau    /**
72*04fd306cSNickeau     * Stylesheet and Boostrap should have the same version
73*04fd306cSNickeau     * This conf is a mix between the version and the stylesheet
74*04fd306cSNickeau     *
75*04fd306cSNickeau     * majorVersion.0.0 - stylesheetname
76*04fd306cSNickeau     */
77*04fd306cSNickeau    public const CONF_BOOTSTRAP_VERSION_STYLESHEET = "bootstrapVersionStylesheet";
78*04fd306cSNickeau    /**
79*04fd306cSNickeau     * The separator in {@link Bootstrap::CONF_BOOTSTRAP_VERSION_STYLESHEET}
80*04fd306cSNickeau     */
81*04fd306cSNickeau    public const BOOTSTRAP_VERSION_STYLESHEET_SEPARATOR = " - ";
82*04fd306cSNickeau    public const DEFAULT_BOOTSTRAP_VERSION_STYLESHEET = "5.0.1" . Bootstrap::BOOTSTRAP_VERSION_STYLESHEET_SEPARATOR . "bootstrap";
83*04fd306cSNickeau
84*04fd306cSNickeau    /**
85*04fd306cSNickeau     * @var mixed|string
86*04fd306cSNickeau     */
87*04fd306cSNickeau    private $version;
88*04fd306cSNickeau    /**
89*04fd306cSNickeau     * @var string - the stylesheet name
90*04fd306cSNickeau     */
91*04fd306cSNickeau    private $styleSheetName;
9237748cd8SNickeau
9337748cd8SNickeau    public static function getDataNamespace()
9437748cd8SNickeau    {
9537748cd8SNickeau        $dataToggleNamespace = "";
9637748cd8SNickeau        if (self::getBootStrapMajorVersion() == self::BootStrapFiveMajorVersion) {
9737748cd8SNickeau            $dataToggleNamespace = "-bs";
9837748cd8SNickeau        }
9937748cd8SNickeau        return $dataToggleNamespace;
10037748cd8SNickeau    }
10137748cd8SNickeau
102*04fd306cSNickeau    public function getMajorVersion(): int
10337748cd8SNickeau    {
104*04fd306cSNickeau        $bootstrapMajorVersion = $this->getVersion()[0];
1054cadd4f8SNickeau        try {
106*04fd306cSNickeau            return DataType::toInteger($bootstrapMajorVersion);
107*04fd306cSNickeau        } catch (ExceptionBadArgument $e) {
108*04fd306cSNickeau            LogUtility::internalError("The bootstrap major version ($bootstrapMajorVersion) is not an integer, default taken");
109*04fd306cSNickeau            return self::DEFAULT_MAJOR;
1104cadd4f8SNickeau        }
111*04fd306cSNickeau
11237748cd8SNickeau    }
113*04fd306cSNickeau
114*04fd306cSNickeau    /**
115*04fd306cSNickeau     * Utility function that returns the major version
116*04fd306cSNickeau     * because this is really common in code
117*04fd306cSNickeau     * @return int - the major version
118*04fd306cSNickeau     */
119*04fd306cSNickeau    public static function getBootStrapMajorVersion(): int
120*04fd306cSNickeau    {
121*04fd306cSNickeau        return Bootstrap::getFromContext()->getMajorVersion();
122*04fd306cSNickeau    }
12337748cd8SNickeau
12437748cd8SNickeau
125*04fd306cSNickeau    public function getVersion(): string
126*04fd306cSNickeau    {
127*04fd306cSNickeau        return $this->version;
128*04fd306cSNickeau    }
129*04fd306cSNickeau
130*04fd306cSNickeau    public static function createFromQualifiedVersion(string $boostrapVersion): Bootstrap
131*04fd306cSNickeau    {
132*04fd306cSNickeau        return new Bootstrap($boostrapVersion);
133*04fd306cSNickeau    }
134*04fd306cSNickeau
135*04fd306cSNickeau
136*04fd306cSNickeau    public function getStyleSheetName(): string
137*04fd306cSNickeau    {
138*04fd306cSNickeau        return $this->styleSheetName;
139*04fd306cSNickeau    }
140*04fd306cSNickeau
141*04fd306cSNickeau    /**
142*04fd306cSNickeau     *
143*04fd306cSNickeau     * @return array - an array of stylesheet tag
144*04fd306cSNickeau     */
145*04fd306cSNickeau    public static function getStyleSheetMetas(): array
146*04fd306cSNickeau    {
147*04fd306cSNickeau
148*04fd306cSNickeau        /**
149*04fd306cSNickeau         * Standard stylesheet
150*04fd306cSNickeau         */
151*04fd306cSNickeau        $stylesheetsFile = WikiPath::createComboResource(':library:bootstrap:bootstrapStylesheet.json');
152*04fd306cSNickeau        try {
153*04fd306cSNickeau            $styleSheets = Json::createFromPath($stylesheetsFile)->toArray();
154*04fd306cSNickeau        } catch (ExceptionNotFound|ExceptionBadSyntax $e) {
155*04fd306cSNickeau            LogUtility::internalError("An error has occurred reading the file ($stylesheetsFile). Error:{$e->getMessage()}", self::CANONICAL);
156*04fd306cSNickeau            return [];
157*04fd306cSNickeau        }
158*04fd306cSNickeau
159*04fd306cSNickeau        /**
160*04fd306cSNickeau         * User defined stylesheet
161*04fd306cSNickeau         */
162*04fd306cSNickeau        $localStyleSheetsFile = WikiPath::createComboResource(':library:bootstrap:bootstrapLocal.json');
163*04fd306cSNickeau        try {
164*04fd306cSNickeau            $localStyleSheets = Json::createFromPath($localStyleSheetsFile)->toArray();
165*04fd306cSNickeau            foreach ($localStyleSheets as $bootstrapVersion => &$localStyleSheetData) {
166*04fd306cSNickeau                $actualStyleSheet = $styleSheets[$bootstrapVersion];
167*04fd306cSNickeau                if (isset($actualStyleSheet)) {
168*04fd306cSNickeau                    $styleSheets[$bootstrapVersion] = array_merge($actualStyleSheet, $localStyleSheetData);
169*04fd306cSNickeau                } else {
170*04fd306cSNickeau                    $styleSheets[$bootstrapVersion] = $localStyleSheetData;
171*04fd306cSNickeau                }
172*04fd306cSNickeau            }
173*04fd306cSNickeau        } catch (ExceptionBadSyntax|ExceptionNotFound $e) {
174*04fd306cSNickeau            // user file does not exists and that's okay
175*04fd306cSNickeau        }
176*04fd306cSNickeau        return $styleSheets;
177*04fd306cSNickeau
178*04fd306cSNickeau
179*04fd306cSNickeau    }
180*04fd306cSNickeau
181*04fd306cSNickeau
182*04fd306cSNickeau    /**
183*04fd306cSNickeau     * @return array - A list of all available stylesheets
184*04fd306cSNickeau     * This function is used to build the configuration as a list of files
185*04fd306cSNickeau     */
186*04fd306cSNickeau    public static function getQualifiedVersions(): array
187*04fd306cSNickeau    {
188*04fd306cSNickeau        $cssVersionsMetas = Bootstrap::getStyleSheetMetas();
189*04fd306cSNickeau        $listVersionStylesheetMeta = array();
190*04fd306cSNickeau        foreach ($cssVersionsMetas as $bootstrapVersion => $cssVersionMeta) {
191*04fd306cSNickeau            foreach ($cssVersionMeta as $fileName => $values) {
192*04fd306cSNickeau                $listVersionStylesheetMeta[] = $bootstrapVersion . Bootstrap::BOOTSTRAP_VERSION_STYLESHEET_SEPARATOR . $fileName;
193*04fd306cSNickeau            }
194*04fd306cSNickeau        }
195*04fd306cSNickeau        return $listVersionStylesheetMeta;
196*04fd306cSNickeau    }
197*04fd306cSNickeau
198*04fd306cSNickeau
199*04fd306cSNickeau    /**
200*04fd306cSNickeau     * @return Bootstrap
201*04fd306cSNickeau     */
202*04fd306cSNickeau    public static function getFromContext(): Bootstrap
203*04fd306cSNickeau    {
204*04fd306cSNickeau        $executionContext = ExecutionContext::getActualOrCreateFromEnv();
205*04fd306cSNickeau        try {
206*04fd306cSNickeau            return $executionContext->getRuntimeObject(self::CANONICAL);
207*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
208*04fd306cSNickeau            $bootstrapStyleSheetVersion = ExecutionContext::getActualOrCreateFromEnv()
209*04fd306cSNickeau                ->getConfValue(Bootstrap::CONF_BOOTSTRAP_VERSION_STYLESHEET, Bootstrap::DEFAULT_BOOTSTRAP_VERSION_STYLESHEET);
210*04fd306cSNickeau            $bootstrap = new Bootstrap($bootstrapStyleSheetVersion);
211*04fd306cSNickeau            $executionContext->setRuntimeObject(self::CANONICAL, $bootstrap);
212*04fd306cSNickeau            return $bootstrap;
213*04fd306cSNickeau        }
214*04fd306cSNickeau
215*04fd306cSNickeau    }
216*04fd306cSNickeau
217*04fd306cSNickeau
218*04fd306cSNickeau    /**
219*04fd306cSNickeau     * @throws ExceptionNotFound
220*04fd306cSNickeau     */
221*04fd306cSNickeau    public function getCssSnippet(): Snippet
222*04fd306cSNickeau    {
223*04fd306cSNickeau        if (isset($this->cssSnippet)) {
224*04fd306cSNickeau            return $this->cssSnippet;
225*04fd306cSNickeau        }
226*04fd306cSNickeau        throw new ExceptionNotFound("No css snippet");
227*04fd306cSNickeau    }
228*04fd306cSNickeau
229*04fd306cSNickeau    /**
230*04fd306cSNickeau     * @return Snippet[] the js snippets in order
231*04fd306cSNickeau     */
232*04fd306cSNickeau    public function getJsSnippets(): array
233*04fd306cSNickeau    {
234*04fd306cSNickeau
235*04fd306cSNickeau        /**
236*04fd306cSNickeau         * The javascript snippet order is important
237*04fd306cSNickeau         */
238*04fd306cSNickeau        $snippets = [];
239*04fd306cSNickeau        try {
240*04fd306cSNickeau            $snippets[] = $this->getJquerySnippet();
241*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
242*04fd306cSNickeau            // error already send at build time
243*04fd306cSNickeau            // or just not present
244*04fd306cSNickeau        }
245*04fd306cSNickeau        try {
246*04fd306cSNickeau            $snippets[] = $this->getPopperSnippet();
247*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
248*04fd306cSNickeau            // error already send at build time
249*04fd306cSNickeau        }
250*04fd306cSNickeau        try {
251*04fd306cSNickeau            $snippets[] = $this->getBootstrapJsSnippet();
252*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
253*04fd306cSNickeau            // error already send at build time
254*04fd306cSNickeau        }
255*04fd306cSNickeau        return $snippets;
256*04fd306cSNickeau
257*04fd306cSNickeau    }
258*04fd306cSNickeau
259*04fd306cSNickeau    /**
260*04fd306cSNickeau     *
261*04fd306cSNickeau     */
262*04fd306cSNickeau    private function build(): void
263*04fd306cSNickeau    {
264*04fd306cSNickeau
265*04fd306cSNickeau
266*04fd306cSNickeau        $version = $this->getVersion();
267*04fd306cSNickeau
268*04fd306cSNickeau        // Javascript
269*04fd306cSNickeau        $bootstrapJsonFile = WikiPath::createComboResource(Snippet::LIBRARY_BASE . ":bootstrap:bootstrapJavascript.json");
270*04fd306cSNickeau        try {
271*04fd306cSNickeau            $bootstrapJsonMetas = Json::createFromPath($bootstrapJsonFile)->toArray();
272*04fd306cSNickeau        } catch (ExceptionBadSyntax|ExceptionNotFound $e) {
273*04fd306cSNickeau            // should not happen, no need to advertise it
274*04fd306cSNickeau            throw new ExceptionRuntimeInternal("Unable to read the file {$bootstrapJsonFile} as json.", self::CANONICAL, 1, $e);
275*04fd306cSNickeau        }
276*04fd306cSNickeau        if (!isset($bootstrapJsonMetas[$version])) {
277*04fd306cSNickeau            throw new ExceptionRuntimeInternal("The bootstrap version ($version) could not be found in the file $bootstrapJsonFile");
278*04fd306cSNickeau        }
279*04fd306cSNickeau        $bootstrapMetas = $bootstrapJsonMetas[$version];
280*04fd306cSNickeau
281*04fd306cSNickeau        // Css
282*04fd306cSNickeau        $bootstrapMetas["stylesheet"] = $this->getStyleSheetMeta();
283*04fd306cSNickeau
284*04fd306cSNickeau
285*04fd306cSNickeau        foreach ($bootstrapMetas as $key => $script) {
286*04fd306cSNickeau            $fileNameWithExtension = $script["file"];
287*04fd306cSNickeau            $file = LocalPath::createFromPathString($fileNameWithExtension);
288*04fd306cSNickeau
289*04fd306cSNickeau            $path = WikiPath::createComboResource(":library:bootstrap:$version:$fileNameWithExtension");
290*04fd306cSNickeau            $snippet = Snippet::createSnippet($path)
291*04fd306cSNickeau                ->setComponentId(self::TAG);
292*04fd306cSNickeau            $url = $script["url"];
293*04fd306cSNickeau            if (!empty($url)) {
294*04fd306cSNickeau                try {
295*04fd306cSNickeau                    $url = Url::createFromString($url);
296*04fd306cSNickeau                    $snippet->setRemoteUrl($url);
297*04fd306cSNickeau                    if (isset($script['integrity'])) {
298*04fd306cSNickeau                        $snippet->setIntegrity($script['integrity']);
299*04fd306cSNickeau                    }
300*04fd306cSNickeau                } catch (ExceptionBadArgument|ExceptionBadSyntax $e) {
301*04fd306cSNickeau                    LogUtility::internalError("The url ($url) for the bootstrap metadata ($fileNameWithExtension) from the bootstrap dictionary is not valid. Error:{$e->getMessage()}", self::CANONICAL);
302*04fd306cSNickeau                }
303*04fd306cSNickeau            }
304*04fd306cSNickeau
305*04fd306cSNickeau            try {
306*04fd306cSNickeau                $extension = $file->getExtension();
307*04fd306cSNickeau            } catch (ExceptionNotFound $e) {
308*04fd306cSNickeau                LogUtility::internalError("No extension was found on the file metadata ($fileNameWithExtension) from the bootstrap dictionary", self::CANONICAL);
309*04fd306cSNickeau                continue;
310*04fd306cSNickeau            }
311*04fd306cSNickeau            switch ($extension) {
312*04fd306cSNickeau                case Snippet::EXTENSION_JS:
313*04fd306cSNickeau                    $snippet->setCritical(false);
314*04fd306cSNickeau                    switch ($key) {
315*04fd306cSNickeau                        case "jquery":
316*04fd306cSNickeau                            $this->jquerySnippet = $snippet;
317*04fd306cSNickeau                            break;
318*04fd306cSNickeau                        case "js":
319*04fd306cSNickeau                            $this->jsSnippet = $snippet;
320*04fd306cSNickeau                            break;
321*04fd306cSNickeau                        case "popper":
322*04fd306cSNickeau                            $this->popperSnippet = $snippet;
323*04fd306cSNickeau                            break;
324*04fd306cSNickeau                        default:
325*04fd306cSNickeau                            LogUtility::internalError("The snippet key ($key) is unknown for bootstrap", self::CANONICAL);
326*04fd306cSNickeau                            break;
327*04fd306cSNickeau                    }
328*04fd306cSNickeau                    break;
329*04fd306cSNickeau                case Snippet::EXTENSION_CSS:
330*04fd306cSNickeau                    switch ($key) {
331*04fd306cSNickeau                        case "stylesheet":
332*04fd306cSNickeau                            $this->cssSnippet = $snippet;
333*04fd306cSNickeau                            break;
334*04fd306cSNickeau                        default:
335*04fd306cSNickeau                            LogUtility::internalError("The snippet key ($key) is unknown for bootstrap");
336*04fd306cSNickeau                            break;
337*04fd306cSNickeau                    }
338*04fd306cSNickeau            }
339*04fd306cSNickeau        }
340*04fd306cSNickeau
341*04fd306cSNickeau
342*04fd306cSNickeau    }
343*04fd306cSNickeau
344*04fd306cSNickeau    public function getSnippets(): array
345*04fd306cSNickeau    {
346*04fd306cSNickeau
347*04fd306cSNickeau        $snippets = [];
348*04fd306cSNickeau        try {
349*04fd306cSNickeau            $snippets[] = $this->getCssSnippet();
350*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
351*04fd306cSNickeau            // error already send at build time
352*04fd306cSNickeau        }
353*04fd306cSNickeau
354*04fd306cSNickeau        /**
355*04fd306cSNickeau         * The javascript snippet
356*04fd306cSNickeau         */
357*04fd306cSNickeau        return array_merge($snippets, $this->getJsSnippets());
358*04fd306cSNickeau    }
359*04fd306cSNickeau
360*04fd306cSNickeau    /**
361*04fd306cSNickeau     * @throws ExceptionNotFound
362*04fd306cSNickeau     */
363*04fd306cSNickeau    public function getPopperSnippet(): Snippet
364*04fd306cSNickeau    {
365*04fd306cSNickeau        if (isset($this->popperSnippet)) {
366*04fd306cSNickeau            return $this->popperSnippet;
367*04fd306cSNickeau        }
368*04fd306cSNickeau        throw new ExceptionNotFound("No popper snippet");
369*04fd306cSNickeau    }
370*04fd306cSNickeau
371*04fd306cSNickeau    /**
372*04fd306cSNickeau     * @throws ExceptionNotFound
373*04fd306cSNickeau     */
374*04fd306cSNickeau    public function getBootstrapJsSnippet(): Snippet
375*04fd306cSNickeau    {
376*04fd306cSNickeau        if (isset($this->jsSnippet)) {
377*04fd306cSNickeau            return $this->jsSnippet;
378*04fd306cSNickeau        }
379*04fd306cSNickeau        throw new ExceptionNotFound("No js snippet");
380*04fd306cSNickeau    }
381*04fd306cSNickeau
382*04fd306cSNickeau    /**
383*04fd306cSNickeau     * @throws ExceptionNotFound
384*04fd306cSNickeau     */
385*04fd306cSNickeau    private function getJquerySnippet(): Snippet
386*04fd306cSNickeau    {
387*04fd306cSNickeau        if (isset($this->jquerySnippet)) {
388*04fd306cSNickeau            return $this->jquerySnippet;
389*04fd306cSNickeau        }
390*04fd306cSNickeau        throw new ExceptionNotFound("No jquery snippet");
391*04fd306cSNickeau    }
392*04fd306cSNickeau
393*04fd306cSNickeau    /**
394*04fd306cSNickeau     * @return array - the stylesheet meta (file, url, ...) for the version
395*04fd306cSNickeau     */
396*04fd306cSNickeau    private function getStyleSheetMeta(): array
397*04fd306cSNickeau    {
398*04fd306cSNickeau
399*04fd306cSNickeau        $styleSheets = self::getStyleSheetMetas();
400*04fd306cSNickeau
401*04fd306cSNickeau        $version = $this->getVersion();
402*04fd306cSNickeau        if (!isset($styleSheets[$version])) {
403*04fd306cSNickeau            LogUtility::internalError("The bootstrap version ($version) could not be found");
404*04fd306cSNickeau            return [];
405*04fd306cSNickeau        }
406*04fd306cSNickeau        $styleSheetsForVersion = $styleSheets[$version];
407*04fd306cSNickeau
408*04fd306cSNickeau        $styleSheetName = $this->getStyleSheetName();
409*04fd306cSNickeau        if (!isset($styleSheetsForVersion[$styleSheetName])) {
410*04fd306cSNickeau            LogUtility::internalError("The bootstrap stylesheet ($styleSheetName) could not be found for the version ($version) in the distribution or custom configuration files");
411*04fd306cSNickeau            return [];
412*04fd306cSNickeau        }
413*04fd306cSNickeau        $styleSheetForVersionAndName = $styleSheetsForVersion[$styleSheetName];
414*04fd306cSNickeau
415*04fd306cSNickeau        /**
416*04fd306cSNickeau         * Select Rtl or Ltr
417*04fd306cSNickeau         * Stylesheet name may have another level
418*04fd306cSNickeau         * with direction property of the language
419*04fd306cSNickeau         *
420*04fd306cSNickeau         * Bootstrap needs another stylesheet
421*04fd306cSNickeau         * See https://getbootstrap.com/docs/5.0/getting-started/rtl/
422*04fd306cSNickeau         */
423*04fd306cSNickeau        try {
424*04fd306cSNickeau            $direction = Lang::createFromRequestedMarkup()->getDirection();
425*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
426*04fd306cSNickeau            $direction = Site::getLangObject()->getDirection();
427*04fd306cSNickeau        }
428*04fd306cSNickeau        if (isset($styleSheetForVersionAndName[$direction])) {
429*04fd306cSNickeau            return $styleSheetForVersionAndName[$direction];
430*04fd306cSNickeau        }
431*04fd306cSNickeau        if (!isset($styleSheetForVersionAndName['file'])) {
432*04fd306cSNickeau            LogUtility::internalError('The file stylesheet attribute is unknown (' . DataType::toString($styleSheetForVersionAndName) . ')');
433*04fd306cSNickeau        }
434*04fd306cSNickeau        return $styleSheetForVersionAndName;
43537748cd8SNickeau    }
43637748cd8SNickeau}
437