buildOriginalPathFromTagAttributes($tagAttributes); /** * Capture the view port */ $viewPortWidth = $tagAttributes->getValueAndRemoveIfPresent(self::VIEWPORT_WIDTH); if ($viewPortWidth !== null) { try { $this->setRequestedViewPort(DataType::toInteger($viewPortWidth)); } catch (ExceptionBadArgument $e) { throw new ExceptionBadArgument("The viewport width is not a valid integer. Error:{$e->getMessage()}", self::CANONICAL); } } /** * Capture the layout */ $layout = $tagAttributes->getValueAndRemoveIfPresent(self::LAYOUT_ATTRIBUTE); if ($layout !== null) { try { $this->setRequestedLayout($layout); } catch (ExceptionBadArgument $e) { throw new ExceptionBadArgument("The layout is not a valid. Error:{$e->getMessage()}", self::CANONICAL); } } return parent::buildFromTagAttributes($tagAttributes); } function getFetchPath(): Path { throw new ExceptionRuntimeInternal("No fetch path: Railbar is not a file but a dynamic HTML document"); } function getFetchString(): string { if (!$this->shouldBePrinted()) { return ""; } $localWikiRequest = null; $localWikiId = null; try { ExecutionContext::getExecutionContext(); } catch (ExceptionNotFound $e) { /** * No actual request (called via ajax) */ $localWikiId = $this->getSourcePath()->getWikiId(); $localWikiRequest = ExecutionContext::getOrCreateFromRequestedWikiId($localWikiId); /** * page info is needed and used by all other plugins * in all hooks (should be first) */ global $INFO; $INFO = pageinfo(); /** * Uses by {@link action_plugin_move_rename} to set * if it will add the button */ $tmp = array(); \dokuwiki\Extension\Event::createAndTrigger('DOKUWIKI_STARTED', $tmp); } try { $snippetManager = SnippetSystem::getFromContext(); $railBarHtmlListItems = $this->getRailBarHtmlListItems(); $railBarLayout = $this->getLayoutTypeToApply(); switch ($railBarLayout) { case self::FIXED_LAYOUT: $railBar = $this->toFixedLayout($railBarHtmlListItems); $snippetManager->attachCssInternalStylesheet("railbar-$railBarLayout"); break; case self::OFFCANVAS_LAYOUT: $railBar = $this->toOffCanvasLayout($railBarHtmlListItems); $snippetManager->attachCssInternalStylesheet("railbar-$railBarLayout"); break; case self::BOTH_LAYOUT: default: $snippetManager->attachCssInternalStylesheet("railbar-" . self::FIXED_LAYOUT); $snippetManager->attachCssInternalStylesheet("railbar-" . self::OFFCANVAS_LAYOUT); $breakpoint = $this->getBreakPointConfiguration(); $railBar = $this->toFixedLayout($railBarHtmlListItems, $breakpoint) . $this->toOffCanvasLayout($railBarHtmlListItems, $breakpoint); break; } $snippetManager->attachCssInternalStylesheet("railbar"); if ($localWikiRequest !== null) { $snippets = $snippetManager->toHtmlForAllSnippets(); $snippetClass = self::getSnippetClass(); /** * Snippets should be after the html because they works * on the added HTML */ $railBar = << $snippets EOF; } return $railBar; } finally { if ($localWikiRequest !== null) { $localWikiRequest->close($localWikiId); } } } function getBuster(): string { return ""; } public function getMime(): Mime { return Mime::getHtml(); } public function getFetcherName(): string { return self::NAME; } public function setRequestedPageWikiId(string $wikiId): FetcherRailBar { $path = WikiPath::createMarkupPathFromId($wikiId); return $this->setRequestedPath($path); } public static function getSnippetClass(): string { return Snippet::getClassFromComponentId(self::CANONICAL); } private function getRailBarHtmlListItems(): string { $liUserTools = (new UserMenu())->getListItems('action'); $pageMenu = new PageMenu(); $liPageTools = $pageMenu->getListItems(); $liSiteTools = (new SiteMenu())->getListItems('action'); // FYI: The below code outputs all menu in mobile (in another HTML layout) // echo (new \dokuwiki\Menu\MobileMenu())->getDropdown($lang['tools']); $componentClass = self::getComponentClass(); return <<
  • User
  • $liUserTools
  • Page
  • $liPageTools
  • Website
  • $liSiteTools EOF; } private function toOffCanvasLayout(string $railBarHtmlListItems, Breakpoint $hideFromBreakpoint = null): string { $breakpointHiding = ""; if ($hideFromBreakpoint !== null) { $breakpointHiding = "d-{$hideFromBreakpoint->getShortName()}-none"; } $railBarOffCanvasPrefix = "railbar-offcanvas"; $railBarClass = StyleAttribute::addComboStrapSuffix(self::NAME); $railBarOffCanvasClassAndId = StyleAttribute::addComboStrapSuffix($railBarOffCanvasPrefix); $railBarOffCanvasWrapperId = StyleAttribute::addComboStrapSuffix("{$railBarOffCanvasPrefix}-wrapper"); $railBarOffCanvasLabelId = StyleAttribute::addComboStrapSuffix("{$railBarOffCanvasPrefix}-label"); $railBarOffcanvasBodyId = StyleAttribute::addComboStrapSuffix("{$railBarOffCanvasPrefix}-body"); $railBarOffCanvasCloseId = StyleAttribute::addComboStrapSuffix("{$railBarOffCanvasPrefix}-close"); $railBarOffCanvasOpenId = StyleAttribute::addComboStrapSuffix("{$railBarOffCanvasPrefix}-open"); return << EOF; } public function getLayoutTypeToApply(): string { if (isset($this->requestedLayout)) { return $this->requestedLayout; } $bootstrapVersion = Bootstrap::getBootStrapMajorVersion(); if ($bootstrapVersion === Bootstrap::BootStrapFourMajorVersion) { return self::FIXED_LAYOUT; } try { $breakPointConfigurationInPixel = $this->getBreakPointConfiguration()->getWidth(); } catch (ExceptionInfinite $e) { // no breakpoint return self::OFFCANVAS_LAYOUT; } try { if ($this->getRequestedViewPort() > $breakPointConfigurationInPixel) { return self::FIXED_LAYOUT; } else { return self::OFFCANVAS_LAYOUT; } } catch (ExceptionNotFound $e) { // no known target view port // we send them both then return self::BOTH_LAYOUT; } } public function setRequestedViewPort(int $viewPort): FetcherRailBar { $this->requestedViewPort = $viewPort; return $this; } /** * The call may indicate the view port that the railbar will be used for * (ie breakpoint) * @return int * @throws ExceptionNotFound */ public function getRequestedViewPort(): int { if (!isset($this->requestedViewPort)) { throw new ExceptionNotFound("No requested view port"); } return $this->requestedViewPort; } private function shouldBePrinted(): bool { if ( SiteConfig::getConfValue(self::CONF_PRIVATE_RAIL_BAR, 0) === 1 && !Identity::isLoggedIn() ) { return false; } return true; } private function getBreakPointConfiguration(): Breakpoint { $name = SiteConfig::getConfValue(self::CONF_BREAKPOINT_RAIL_BAR, Breakpoint::BREAKPOINT_LARGE_NAME); return Breakpoint::createFromLongName($name); } /** * @param string $railBarHtmlListItems * @param Breakpoint|null $showFromBreakpoint * @return string */ private function toFixedLayout(string $railBarHtmlListItems, Breakpoint $showFromBreakpoint = null): string { $showFromBreakpointClasses = ""; if ($showFromBreakpoint !== null) { $showFromBreakpointClasses = "d-none d-{$showFromBreakpoint->getShortName()}-flex"; } $railBarClass = StyleAttribute::addComboStrapSuffix(self::NAME); $railBarFixedClassOrId = StyleAttribute::addComboStrapSuffix(self::NAME . "-fixed"); $zIndexRailbar = 1000; // A navigation bar (below the drop down because we use it in the search box for auto-completion) return <<
    $railBarHtmlListItems
    EOF; } /** * The layout may be requested (example in a landing page where you don't want to see it) * @param string $layout * @return FetcherRailBar * @throws ExceptionBadArgument */ public function setRequestedLayout(string $layout): FetcherRailBar { if (!in_array($layout, self::KNOWN_LAYOUT)) { throw new ExceptionBadArgument("The layout ($layout) is not valid. The known-layout are : ".ArrayUtility::formatAsString(self::KNOWN_LAYOUT)); } $this->requestedLayout = $layout; return $this; } public function setRequestedPath(WikiPath $requestedPath): FetcherRailBar { $this->setSourcePath($requestedPath); return $this; } public function getLabel(): string { return self::NAME; } }