* */ namespace ComboStrap; use Exception; class Site { const STRAP_TEMPLATE_NAME = "strap"; const SVG_LOGO_IDS = array( ':wiki:logo.svg', ':logo.svg' ); const PNG_LOGO_IDS = array( ':logo.png', ':wiki:logo.png', ':favicon-32×32.png', ':favicon-16×16.png', ':apple-touch-icon.png', ':android-chrome-192x192.png' ); /** * @return Image[] */ public static function getLogoImages(): array { $logosPaths = PluginUtility::mergeAttributes(self::PNG_LOGO_IDS, self::SVG_LOGO_IDS); $logos = []; foreach ($logosPaths as $logoPath) { $dokuPath = DokuPath::createMediaPathFromId($logoPath); if (FileSystems::exists($dokuPath)) { try { $logos[] = Image::createImageFromPath($dokuPath); } catch (Exception $e) { // The image is not valid LogUtility::msg("The logo ($logoPath) is not a valid image. {$e->getMessage()}"); } } } return $logos; } /** * @return string|null */ public static function getLogoUrlAsSvg(): ?string { $url = null; foreach (self::SVG_LOGO_IDS as $svgLogo) { $svgLogoFN = mediaFN($svgLogo); if (file_exists($svgLogoFN)) { $url = ml($svgLogo, '', true, '', true); break; } } return $url; } public static function getLogoAsSvgImage(): ?ImageSvg { foreach (self::SVG_LOGO_IDS as $svgLogo) { try { $image = ImageSvg::createImageFromId($svgLogo); } catch (ExceptionCombo $e) { LogUtility::msg("The svg ($svgLogo) returns an error. {$e->getMessage()}"); continue; } if ($image->exists()) { return $image; } } return null; } public static function getLogoUrlAsPng() { $url = null; foreach (self::PNG_LOGO_IDS as $svgLogo) { $svgLogoFN = mediaFN($svgLogo); if (file_exists($svgLogoFN)) { $url = ml($svgLogo, '', true, '', true); break; }; } return $url; } /** * @return mixed * @deprecated use {@link Site::getName()} instead * https://www.dokuwiki.org/config:title */ public static function getTitle() { global $conf; return $conf['title']; } /** * https://www.dokuwiki.org/config:title */ public static function setName($name) { global $conf; $conf['title'] = $name; } /** * @param string $sep - the separator - generally ("-") but not always * @return string * * Locale always canonicalizes to upper case. */ public static function getLocale(string $sep = "-"): ?string { $locale = null; $lang = self::getLang(); if ($lang != null) { $country = self::getLanguageRegion(); if ($country != null) { $locale = strtolower($lang) . $sep . strtoupper($country); } } return $locale; } /** * * ISO 3166 alpha-2 country code * */ public static function getLanguageRegion() { $region = PluginUtility::getConfValue(Region::CONF_SITE_LANGUAGE_REGION); if (!empty($region)) { return $region; } else { if (extension_loaded("intl")) { $locale = locale_get_default(); $localeParts = preg_split("/_/", $locale, 2); if (sizeof($localeParts) === 2) { return $localeParts[1]; } } return null; } } /** * @return mixed|null * Wrapper around https://www.dokuwiki.org/config:lang */ public static function getLang() { global $conf; $lang = $conf['lang']; return ($lang ?: null); } public static function getBaseUrl(): string { /** * In a {@link PluginUtility::isDevOrTest()} dev environment, * don't set the * https://www.dokuwiki.org/config:baseurl * to be able to test the metadata / social integration * via a tunnel * * Same as {@link getBaseURL()} ?? * Same as {@link wl()} without nothing */ return DOKU_URL; } public static function getTag() { global $conf; $tag = $conf['tag']; return ($tag ? $tag : null); } /** * @return string - the name of the sidebar page */ public static function getSidebarName() { global $conf; return $conf["sidebar"]; } public static function setTemplate($template) { global $conf; $conf['template'] = $template; } public static function setCacheXhtmlOn() { // ensure the value is not -1, which disables caching // https://www.dokuwiki.org/config:cachetime global $conf; $conf['cachetime'] = 60 * 60; } public static function debugIsOn() { global $conf; return $conf['allowdebug']; } public static function setTemplateToStrap() { global $conf; $conf['template'] = self::STRAP_TEMPLATE_NAME; } public static function setTemplateToDefault() { global $conf; $conf['template'] = 'dokuwiki'; } public static function setCacheDefault() { // The value is -1, which disables caching // https://www.dokuwiki.org/config:cachetime global $conf; $conf['cachetime'] = -1; } public static function useHeadingAsTitle() { // https://www.dokuwiki.org/config:useheading global $conf; $conf['useheading'] = 1; } public static function useHeadingDefault() { // https://www.dokuwiki.org/config:useheading global $conf; $conf['useheading'] = 0; } public static function getTemplate() { global $conf; return $conf['template']; } public static function isStrapTemplate() { global $conf; return $conf['template'] == self::STRAP_TEMPLATE_NAME; } public static function getAjaxUrl(): string { return self::getBaseUrl() . "lib/exe/ajax.php"; } public static function getPageDirectory() { global $conf; /** * Data dir is the pages dir (savedir is the data dir) */ $pageDirectory = $conf['datadir']; if ($pageDirectory === null) { throw new ExceptionComboRuntime("The page directory ($pageDirectory) is null"); } return LocalPath::createFromPath($pageDirectory); } public static function disableHeadingSectionEditing() { global $conf; $conf['maxseclevel'] = 0; } public static function setBreadCrumbOn() { global $conf; $conf['youarehere'] = 1; } public static function isHtmlRenderCacheOn(): bool { global $conf; return $conf['cachetime'] !== -1; } public static function getDataDirectory(): LocalPath { global $conf; $dataDirectory = $conf['savedir']; if ($dataDirectory === null) { throw new ExceptionComboRuntime("The data directory ($dataDirectory) is null"); } return LocalPath::createFromPath($dataDirectory); } public static function isLowQualityProtectionEnable(): bool { return PluginUtility::getConfValue(LowQualityPage::CONF_LOW_QUALITY_PAGE_PROTECTION_ENABLE) === 1; } public static function getHomePageName() { global $conf; return $conf["start"]; } /** * @return mixed - Application / Website name */ public static function getName() { return self::getTitle(); } public static function getTagLine() { global $conf; return $conf['tagline']; } /** * @return int|null */ public static function getCacheTime(): ?int { global $conf; $cacheTime = $conf['cachetime']; if ($cacheTime === null) { return null; } if (is_numeric($cacheTime)) { return intval($cacheTime); } return null; } /** * Absolute vs Relative URL * https://www.dokuwiki.org/config:canonical */ public static function shouldUrlBeAbsolute(): bool { global $conf; $value = $conf['canonical']; if ($value === 1) { return true; } return false; } /** * @param string $description * Same as {@link Site::setDescription()} */ public static function setTagLine(string $description) { global $conf; $conf['tagline'] = $description; } /** * @param string $description * */ public static function setDescription(string $description) { self::setTagLine($description); } public static function setPrimaryColor(string $primaryColorValue) { PluginUtility::setConf(ColorRgb::PRIMARY_COLOR_CONF, $primaryColorValue); } public static function getPrimaryColor($default = null): ?ColorRgb { $value = self::getPrimaryColorValue($default); if ( $value === null || (trim($value) === "")) { return null; } try { return ColorRgb::createFromString($value); } catch (ExceptionCombo $e) { LogUtility::msg("The primary color value configuration ($value) is not valid. Error: {$e->getMessage()}"); return null; } } public static function getSecondaryColor($default = null): ?ColorRgb { $value = Site::getSecondaryColorValue($default); if ($value === null) { return null; } try { return ColorRgb::createFromString($value); } catch (ExceptionCombo $e) { LogUtility::msg("The secondary color value configuration ($value) is not valid. Error: {$e->getMessage()}"); return null; } } public static function setSecondaryColor(string $secondaryColorValue) { PluginUtility::setConf(ColorRgb::SECONDARY_COLOR_CONF, $secondaryColorValue); } public static function unsetPrimaryColor() { PluginUtility::setConf(ColorRgb::PRIMARY_COLOR_CONF, null); } public static function isBrandingColorInheritanceEnabled(): bool { return PluginUtility::getConfValue(ColorRgb::BRANDING_COLOR_INHERITANCE_ENABLE_CONF, ColorRgb::BRANDING_COLOR_INHERITANCE_ENABLE_CONF_DEFAULT) === 1; } public static function getRem(): int { $defaultRem = 16; if (Site::getTemplate() === self::STRAP_TEMPLATE_NAME) { $loaded = self::loadStrapUtilityTemplateIfPresentAndSameVersion(); if ($loaded) { $value = TplUtility::getRem(); if ($value === null) { return $defaultRem; } try { return DataType::toInteger($value); } catch (ExceptionCombo $e) { LogUtility::msg("The rem configuration value ($value) is not a integer. Error: {$e->getMessage()}"); } } } return $defaultRem; } public static function enableBrandingColorInheritance() { PluginUtility::setConf(ColorRgb::BRANDING_COLOR_INHERITANCE_ENABLE_CONF, 1); } public static function setBrandingColorInheritanceToDefault() { PluginUtility::setConf(ColorRgb::BRANDING_COLOR_INHERITANCE_ENABLE_CONF, ColorRgb::BRANDING_COLOR_INHERITANCE_ENABLE_CONF_DEFAULT); } public static function getPrimaryColorForText(string $default = null): ?ColorRgb { $primaryColor = self::getPrimaryColor($default); if ($primaryColor === null) { return null; } try { return $primaryColor ->toHsl() ->setSaturation(30) ->setLightness(40) ->toRgb() ->toMinimumContrastRatioAgainstWhite(); } catch (ExceptionCombo $e) { LogUtility::msg("Error while calculating the primary text color. {$e->getMessage()}"); return null; } } /** * More lightness than the text * @return ColorRgb|null */ public static function getPrimaryColorTextHover(): ?ColorRgb { $primaryColor = self::getPrimaryColor(); if ($primaryColor === null) { return null; } try { return $primaryColor ->toHsl() ->setSaturation(88) ->setLightness(53) ->toRgb() ->toMinimumContrastRatioAgainstWhite(); } catch (ExceptionCombo $e) { LogUtility::msg("Error while calculating the secondary text color. {$e->getMessage()}"); return null; } } public static function getSecondarySlotNames(): array { try { return [ Site::getSidebarName(), Site::getHeaderSlotPageName(), Site::getFooterSlotPageName(), Site::getMainHeaderSlotName(), Site::getMainFooterSlotName() ]; } catch (ExceptionCombo $e) { // We known at least this one return [Site::getSidebarName()]; } } /** * @throws ExceptionCombo if the strap template is not installed or could not be loaded */ public static function getMainHeaderSlotName(): ?string { self::loadStrapUtilityTemplateIfPresentAndSameVersion(); return TplUtility::getMainHeaderSlotName(); } /** * Strap is loaded only if this is the same version * to avoid function, class, or members that does not exist * @throws ExceptionCombo if strap template utility class could not be loaded */ public static function loadStrapUtilityTemplateIfPresentAndSameVersion(): void { if (class_exists("ComboStrap\TplUtility")) { return; } $templateUtilityFile = __DIR__ . '/../../../tpl/strap/class/TplUtility.php'; if (file_exists($templateUtilityFile)) { /** * Check the version */ $templateInfo = confToHash(__DIR__ . '/../../../tpl/strap/template.info.txt'); $templateVersion = $templateInfo['version']; $comboVersion = PluginUtility::$INFO_PLUGIN['version']; if ($templateVersion != $comboVersion) { $strapName = "Strap"; $comboName = "Combo"; $strapLink = "$strapName"; $comboLink = "$comboName"; if ($comboVersion > $templateVersion) { $upgradeTarget = $strapName; } else { $upgradeTarget = $comboName; } $upgradeLink = "upgrade $upgradeTarget via the extension manager"; $message = "You should $upgradeLink to the latest version to get a fully functional experience. The version of $comboLink is ($comboVersion) while the version of $strapLink is ($templateVersion)."; LogUtility::msg($message); throw new ExceptionCombo($message); } else { /** @noinspection PhpIncludeInspection */ require_once($templateUtilityFile); } } if (Site::getTemplate() !== self::STRAP_TEMPLATE_NAME) { $message = "The strap template is not installed"; } else { $message = "The file ($templateUtilityFile) was not found"; } throw new ExceptionCombo($message); } /** * @throws ExceptionCombo */ public static function getSideKickSlotPageName() { Site::loadStrapUtilityTemplateIfPresentAndSameVersion(); return TplUtility::getSideKickSlotPageName(); } /** * @throws ExceptionCombo */ public static function getFooterSlotPageName() { Site::loadStrapUtilityTemplateIfPresentAndSameVersion(); return TplUtility::getFooterSlotPageName(); } /** * @throws ExceptionCombo */ public static function getHeaderSlotPageName() { Site::loadStrapUtilityTemplateIfPresentAndSameVersion(); return TplUtility::getHeaderSlotPageName(); } /** * @throws ExceptionCombo */ public static function setConfStrapTemplate($name, $value) { Site::loadStrapUtilityTemplateIfPresentAndSameVersion(); TplUtility::setConf($name, $value); } /** * @throws ExceptionCombo */ public static function getMainFooterSlotName(): string { self::loadStrapUtilityTemplateIfPresentAndSameVersion(); return TplUtility::getMainFooterSlotName(); } public static function getPrimaryColorValue($default = null) { $value = PluginUtility::getConfValue(ColorRgb::PRIMARY_COLOR_CONF, $default); if ($value !== null && trim($value) !== "") { return $value; } if (PluginUtility::isTest()) { // too much trouble // the load of styles is not consistent return null; } $styles = ColorRgb::getDokuWikiStyles(); return $styles["replacements"]["__theme_color__"]; } public static function getSecondaryColorValue($default = null) { $value = PluginUtility::getConfValue(ColorRgb::SECONDARY_COLOR_CONF, $default); if ($value === null || trim($value) === "") { return null; } return $value; } public static function setCanonicalUrlType(string $value) { PluginUtility::setConf(PageUrlType::CONF_CANONICAL_URL_TYPE, $value); } public static function setCanonicalUrlTypeToDefault() { PluginUtility::setConf(PageUrlType::CONF_CANONICAL_URL_TYPE, null); } public static function isBrandingColorInheritanceFunctional(): bool { return self::isBrandingColorInheritanceEnabled() && Site::getPrimaryColorValue() !== null; } public static function getMediaDirectory(): LocalPath { global $conf; $mediaDirectory = $conf['mediadir']; if ($mediaDirectory === null) { throw new ExceptionComboRuntime("The media directory ($mediaDirectory) is null"); } return LocalPath::createFromPath($mediaDirectory); } public static function getCacheDirectory(): LocalPath { global $conf; $cacheDirectory = $conf['cachedir']; if ($cacheDirectory === null) { throw new ExceptionComboRuntime("The cache directory ($cacheDirectory) is null"); } return LocalPath::createFromPath($cacheDirectory); } public static function getComboHome(): LocalPath { return LocalPath::create(DOKU_PLUGIN . PluginUtility::PLUGIN_BASE_NAME); } public static function getComboImagesDirectory(): LocalPath { return self::getComboResourcesDirectory()->resolve("images"); } public static function getComboResourcesDirectory(): LocalPath { return Site::getComboHome()->resolve("resources"); } public static function getComboDictionaryDirectory(): LocalPath { return Site::getComboResourcesDirectory()->resolve("dictionary"); } public static function getComboResourceSnippetDirectory(): LocalPath { return Site::getComboResourcesDirectory()->resolve("snippet"); } public static function getLogoHtml(): ?string { $tagAttributes = TagAttributes::createEmpty("identity"); $tagAttributes->addComponentAttributeValue(Dimension::WIDTH_KEY, "72"); $tagAttributes->addComponentAttributeValue(Dimension::HEIGHT_KEY, "72"); $tagAttributes->addComponentAttributeValue(TagAttributes::TYPE_KEY, SvgDocument::ICON_TYPE); $tagAttributes->addClassName("logo"); /** * Logo */ $logoImages = Site::getLogoImages(); foreach ($logoImages as $logoImage) { $path = $logoImage->getPath(); $mediaLink = MediaLink::createMediaLinkFromPath($path, $tagAttributes) ->setLazyLoad(false); try { return $mediaLink->renderMediaTag(); } catch (ExceptionCombo $e) { LogUtility::msg("Error while rendering the logo $logoImage"); } } return null; } }