aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorThomas Hackl <hackl@data-quest.de>2022-12-12 15:20:27 +0000
committerDavid Siegfried <david.siegfried@uni-vechta.de>2022-12-12 15:20:27 +0000
commit936d1c00ea05bb0a5c56f441ff2eece6ccefada6 (patch)
tree10c4b9a4a1d02780112f7ddc99f9a88b37a1ad20 /lib
parent54dbf11a35cac0de6fed1c50114c9583d210a40e (diff)
Resolve "StEP00348: Responsive Navigation Stud.IP 5.x"
Closes #32 Merge request studip/studip!65
Diffstat (limited to 'lib')
-rw-r--r--lib/classes/ContentBar.php34
-rw-r--r--lib/classes/ResponsiveHelper.php173
-rw-r--r--lib/classes/SkipLinks.php24
-rw-r--r--lib/classes/WidgetContainer.php20
-rw-r--r--lib/classes/sidebar/Sidebar.php6
-rw-r--r--lib/include/html_head.inc.php6
-rw-r--r--lib/modules/ConsultationModule.class.php8
-rw-r--r--lib/modules/CoursewareModule.class.php1
-rw-r--r--lib/navigation/FooterNavigation.php6
-rw-r--r--lib/wiki.inc.php20
10 files changed, 242 insertions, 56 deletions
diff --git a/lib/classes/ContentBar.php b/lib/classes/ContentBar.php
index 043fe18..53b3dfc 100644
--- a/lib/classes/ContentBar.php
+++ b/lib/classes/ContentBar.php
@@ -15,25 +15,41 @@ class ContentBar
public $infoText = '';
public $icon = '';
public $toc = null;
+ public $actionMenu = null;
+
/**
- * ContentBar constructor.
- *
- * Note: An icon for consumer mode is always shown, this would have to be changed via template.
+ * The singleton instance of the container
+ */
+ protected static $instance = null;
+
+ /**
+ * Returns the instance of this container to ensure there is only one
+ * instance.
*
* @param TOCItem $toc Table of contents object.
* @param string $info Some information to show, like creation date, author etc.
* @param Icon|null $icon An icon to show in content bar.
* @param ActionMenu|null $actionMenu Optional action menu for page actions.
+ * @return ContentBar
+ * @static
*/
- public function __construct(TOCItem $toc, string $info = '', Icon $icon = null, ActionMenu $actionMenu = null)
+ public static function get(): ContentBar
{
- $this->infoText = $info;
- $this->icon = $icon;
- $this->toc = $toc;
- $this->actionMenu = $actionMenu;
+ if (static::$instance === null) {
+ static::$instance = new static;
+ }
+ return static::$instance;
}
- public $actionMenu = null;
+ /**
+ * Private constructor to ensure that the singleton Get() method is always
+ * used.
+ *
+ * @see ContentBar::get
+ */
+ protected function __construct()
+ {
+ }
/**
* Provide some info text.
diff --git a/lib/classes/ResponsiveHelper.php b/lib/classes/ResponsiveHelper.php
index eb7f41c..c2b201e 100644
--- a/lib/classes/ResponsiveHelper.php
+++ b/lib/classes/ResponsiveHelper.php
@@ -24,27 +24,54 @@ class ResponsiveHelper
$link_params = array_fill_keys(array_keys(URLHelper::getLinkParams()), null);
foreach (Navigation::getItem('/')->getSubNavigation() as $path => $nav) {
- if (!$nav->isVisible(true)) {
- continue;
+ $image = $nav->getImage();
+
+ $forceVisibility = false;
+ /*
+ * Special treatment for "browse" navigation which is normally hidden
+ * when we are inside a course.
+ */
+ if ($path === 'browse' && !$image) {
+ $image = Icon::create('seminar');
+ $forceVisibility = true;
+ }
+ /*
+ * Special treatment for "footer" navigation because
+ * the real footer is hidden in responsive view.
+ */
+ if ($path === 'footer' && !$image) {
+ $image = Icon::create('info');
+ $nav->setTitle(_('Impressum & Information'));
+ $forceVisibility = true;
}
- $image = $nav->getImage();
$image_src = $image ? $image->copyWithRole('info_alt')->asImagePath() : false;
$item = [
- 'icon' => $image_src ? self::getAssetsURL($image_src) : false,
- 'title' => (string) $nav->getTitle(),
- 'url' => self::getURL($nav->getURL(), $link_params),
+ 'icon' => $image_src ? self::getAssetsURL($image_src) : false,
+ 'title' => (string) $nav->getTitle(),
+ 'url' => URLHelper::getURL($nav->getURL(), $link_params, true),
+ 'parent' => '/',
+ 'path' => $path,
+ 'visible' => $forceVisibility ? true : $nav->isVisible(true),
+ 'active' => $nav->isActive()
];
if ($nav->isActive()) {
- $activated[] = $path;
+ // course navigation is integrated in course sub-navigation items
+ if ($path === 'course') {
+ $activated[] = 'browse/my_courses/' . (Context::get()->getId());
+ } else {
+ $activated[] = $path;
+ }
}
- if ($nav->getSubnavigation() && $path != 'start') {
+ if ($nav->getSubnavigation() && $path != 'start') {
$item['children'] = self::getChildren($nav, $path, $activated);
}
- $navigation[$path] = $item;
+ if ($path !== 'course') {
+ $navigation[$path] = $item;
+ }
}
return [$navigation, $activated];
@@ -54,35 +81,50 @@ class ResponsiveHelper
* Recursively build a navigation array from the subnavigation/children
* of a navigation object.
*
- * @param Navigation $navigation The navigation object
- * @param String $path Current path segment
- * @param array $activated Activated items
+ * @param Navigation $navigation The navigation object
+ * @param String $path Current path segment
+ * @param array $activated Activated items
+ * @param String|null $cid Optional context ID
* @return Array containing the children (+ grandchildren...)
*/
- protected static function getChildren(Navigation $navigation, $path, &$activated = [])
+ protected static function getChildren(Navigation $navigation, $path, &$activated = [], string $cid = null)
{
$children = [];
foreach ($navigation->getSubNavigation() as $subpath => $subnav) {
- if (!$subnav->isVisible()) {
+ /*if (!$subnav->isVisible()) {
continue;
- }
+ }*/
+ $originalSubpath = $subpath;
$subpath = "{$path}/{$subpath}";
$item = [
- 'title' => (string) $subnav->getTitle(),
- 'url' => self::getURL($subnav->getURL()),
+ 'title' => (string) $subnav->getTitle(),
+ 'url' => URLHelper::getURL($subnav->getURL(), $cid ? ['cid' => $cid] : []),
+ 'parent' => $path,
+ 'path' => $subpath,
+ 'visible' => $subnav->isVisible(),
+ 'active' => $subnav->isActive()
];
if ($subnav->isActive()) {
- $activated[] = $subpath;
+ // course navigation is integrated in course sub-navigation items
+ if ($path === 'course') {
+ $activated[] = 'browse/my_courses/' . Context::get()->getId() . '/' . $originalSubpath;
+ } else {
+ $activated[] = $subpath;
+ }
}
if ($subnav->getSubNavigation()) {
$item['children'] = self::getChildren($subnav, $subpath);
}
+ if ($subpath === 'browse/my_courses') {
+ $item['children'] = array_merge($item['children'] ?? [], static::getMyCoursesNavigation($activated));
+ }
+
$children[$subpath] = $item;
}
@@ -113,4 +155,99 @@ class ResponsiveHelper
{
return str_replace($GLOBALS['ASSETS_URL'], '', $url);
}
+
+ /**
+ * Specialty for responsive navigation: build navigation items
+ * for my courses in current semester.
+ *
+ * @return array
+ */
+ protected static function getMyCoursesNavigation($activated): array
+ {
+ if (!$GLOBALS['perm']->have_perm('admin')) {
+ $sem_data = Semester::getAllAsArray();
+
+ $currentIndex = -1;
+
+ foreach ($sem_data as $index => $semester) {
+ if ($semester['current']) {
+ $currentIndex = $index;
+ break;
+ }
+ }
+
+ $params = [
+ 'deputies_enabled' => Config::get()->DEPUTIES_ENABLE
+ ];
+
+ $courses = MyRealmModel::getCourses($currentIndex, $currentIndex, $params);
+ } else {
+ $courses = [];
+ }
+
+ $items = [];
+
+ $standardIcon = Icon::create('seminar', Icon::ROLE_INFO_ALT)->asImagePath();
+
+ // Add current course to list.
+ if (Context::get() && Context::isCourse()) {
+ $courses[] = Context::get();
+ }
+
+ foreach ($courses as $course) {
+ $avatar = CourseAvatar::getAvatar($course->id);
+ if ($avatar->is_customized()) {
+ $icon = $avatar->getURL(Avatar::SMALL);
+ } else {
+ $icon = $standardIcon;
+ }
+
+ $cnav = [
+ 'icon' => $icon,
+ 'title' => $course->getFullname(),
+ 'url' => URLHelper::getURL('dispatch.php/course/details', ['cid' => $course->id]),
+ 'parent' => 'browse/my_courses',
+ 'path' => 'browse/my_courses/' . $course->id,
+ 'visible' => true,
+ 'active' => Course::findCurrent() ? Course::findCurrent()->id === $course->id : false,
+ 'children' => []
+ ];
+
+ foreach ($course->tools as $tool) {
+ if (Seminar_Perm::get()->have_studip_perm($tool->getVisibilityPermission(), $course->id)) {
+
+ $path = 'browse/my_courses/' . $course->id;
+
+ $studip_module = $tool->getStudipModule();
+ if ($studip_module instanceof StudipModule) {
+ $tool_nav = $studip_module->getTabNavigation($course->id) ?: [];
+ foreach ($tool_nav as $nav_name => $navigation) {
+ if ($nav_name && is_a($navigation, 'Navigation')) {
+ $cnav['children'][$path . '/' . $nav_name] = [
+ 'icon' => $navigation->getImage() ? $navigation->getImage()->asImagePath() : '',
+ 'title' => $tool->getDisplayname(),
+ 'url' => URLHelper::getURL($navigation->getURL(), ['cid' => $course->id]),
+ 'parent' => 'browse/my_courses/' . $course->id,
+ 'path' => 'browse/my_courses/' . $course->id . '/' . $nav_name,
+ 'visible' => true,
+ 'active' => $navigation->isActive(),
+ 'children' => static::getChildren(
+ $navigation,
+ 'browse/my_courses/' . $course->id . '/' . $nav_name,
+ $activated,
+ $course->id
+ ),
+ ];
+ }
+ }
+ }
+ }
+ }
+
+ $items['browse/my_courses/' . $course->id] = $cnav;
+
+ }
+
+ return $items;
+ }
}
diff --git a/lib/classes/SkipLinks.php b/lib/classes/SkipLinks.php
index 684ae42..796206d 100644
--- a/lib/classes/SkipLinks.php
+++ b/lib/classes/SkipLinks.php
@@ -60,27 +60,29 @@ class SkipLinks
* @param string $url the url of the links
* @param integer $position the position of the link in the list
*/
- public static function addLink(string $name, string $url, $position = null)
+ public static function addLink(string $name, string $url, $position = null, bool $inFullscreen = true)
{
$position = (!$position || $position < 1) ? count(self::$links) + 100 : (int) $position;
self::$links[$url] = [
- 'name' => $name,
- 'url' => $url,
- 'position' => $position,
+ 'name' => $name,
+ 'url' => $url,
+ 'position' => $position,
+ 'fullscreen' => $inFullscreen
];
}
/**
* Adds a link to an anker on the same page to the list of skip links.
*
- * @param string $name the displayed name of the links
- * @param string $id the id of the anker
- * @param integer $position the position of the link in the list
+ * @param string $name the displayed name of the links
+ * @param string $id the id of the anker
+ * @param integer $position the position of the link in the list
+ * @param bool $inFullscreen is this link relevant in fullscreen mode?
*/
- public static function addIndex($name, $id, $position = null)
+ public static function addIndex($name, $id, $position = null, bool $inFullscreen = true)
{
$url = '#' . $id;
- self::addLink($name, $url, $position);
+ self::addLink($name, $url, $position, $inFullscreen);
}
/**
@@ -99,12 +101,14 @@ class SkipLinks
});
$navigation = new Navigation('');
+ $fullscreen = [];
foreach (array_values(self::$links) as $index => $link) {
$navigation->addSubNavigation(
"/skiplinks/link-{$index}",
new Navigation($link['name'], $link['url'])
);
+ $fullscreen['/skiplinks/link-' . $index] = $link['fullscreen'];
}
- return $GLOBALS['template_factory']->render('skiplinks', compact('navigation'));
+ return $GLOBALS['template_factory']->render('skiplinks', compact('navigation', 'fullscreen'));
}
}
diff --git a/lib/classes/WidgetContainer.php b/lib/classes/WidgetContainer.php
index 108477a..c702d06 100644
--- a/lib/classes/WidgetContainer.php
+++ b/lib/classes/WidgetContainer.php
@@ -160,6 +160,24 @@ abstract class WidgetContainer
}
/**
+ * Returns the number of widgets in this container. Optionally constrained
+ * to widgets of a specific class.
+ *
+ * @param string|null $widget_class
+ * @return int
+ */
+ public function countWidgets(string $widget_class = null): int
+ {
+ $widgets = $this->widgets;
+ if ($widget_class !== null) {
+ $widgets = array_filter($widgets, function (Widget $widget) use ($widget_class) {
+ return is_a($widget, $widget_class);
+ });
+ }
+ return count($widgets);
+ }
+
+ /**
* Returns whether this container has any widget.
*
* @return bool True if the container has at least one widget, false
@@ -167,7 +185,7 @@ abstract class WidgetContainer
*/
public function hasWidgets()
{
- return count($this->widgets) > 0;
+ return $this->countWidgets() > 0;
}
/**
diff --git a/lib/classes/sidebar/Sidebar.php b/lib/classes/sidebar/Sidebar.php
index 7536a7f..00c3b8f 100644
--- a/lib/classes/sidebar/Sidebar.php
+++ b/lib/classes/sidebar/Sidebar.php
@@ -224,7 +224,8 @@ class Sidebar extends WidgetContainer
SkipLinks::addIndex(
_('Dritte Navigationsebene'),
$widget->getId(),
- 20
+ 20,
+ false
);
$navigation_widget_added = true;
@@ -237,7 +238,8 @@ class Sidebar extends WidgetContainer
SkipLinks::addIndex(
_('Aktionen'),
$widget->getId(),
- 21
+ 21,
+ false
);
$actions_widget_added = true;
diff --git a/lib/include/html_head.inc.php b/lib/include/html_head.inc.php
index 4ab1c0e..a7f2c21 100644
--- a/lib/include/html_head.inc.php
+++ b/lib/include/html_head.inc.php
@@ -32,12 +32,6 @@ $lang_attr = str_replace('_', '-', $_SESSION['_language']);
String.locale = "<?= htmlReady(strtr($_SESSION['_language'], '_', '-')) ?>";
document.querySelector('html').className = 'js';
- setTimeout(() => {
- // This needs to be put in a timeout since otherwise it will not match
- if (window.matchMedia('(max-width: 767px)').matches) {
- document.querySelector('html').classList.add('responsive-display');
- }
- }, 0);
window.STUDIP = {
ABSOLUTE_URI_STUDIP: "<?= $GLOBALS['ABSOLUTE_URI_STUDIP'] ?>",
diff --git a/lib/modules/ConsultationModule.class.php b/lib/modules/ConsultationModule.class.php
index acc2cb4..5671776 100644
--- a/lib/modules/ConsultationModule.class.php
+++ b/lib/modules/ConsultationModule.class.php
@@ -103,11 +103,13 @@ class ConsultationModule extends CorePlugin implements StudipModule, SystemPlugi
*/
public function getTabNavigation($course_id)
{
- if ($GLOBALS['user']->id === 'nobody') {
- return [];
+ if ($GLOBALS['user']->id !== 'nobody') {
+ $navigation = new ConsultationNavigation(RangeFactory::find($course_id));
+ $navigation->setImage(Icon::create('consultation', Icon::ROLE_INFO_ALT));
+ return ['consultation' => $navigation];
}
- return ['consultation' => new ConsultationNavigation(RangeFactory::find($course_id))];
+ return [];
}
/**
diff --git a/lib/modules/CoursewareModule.class.php b/lib/modules/CoursewareModule.class.php
index 0d8dfe8..e07d5d2 100644
--- a/lib/modules/CoursewareModule.class.php
+++ b/lib/modules/CoursewareModule.class.php
@@ -39,6 +39,7 @@ class CoursewareModule extends CorePlugin implements SystemPlugin, StudipModule,
_('Courseware'),
URLHelper::getURL('dispatch.php/course/courseware/?cid='.$courseId)
);
+ $navigation->setImage(Icon::create('courseware', Icon::ROLE_INFO_ALT));
$navigation->addSubNavigation(
'content',
new Navigation(_('Inhalt'), 'dispatch.php/course/courseware/?cid='.$courseId)
diff --git a/lib/navigation/FooterNavigation.php b/lib/navigation/FooterNavigation.php
index d3f8b83..a24dc11 100644
--- a/lib/navigation/FooterNavigation.php
+++ b/lib/navigation/FooterNavigation.php
@@ -27,6 +27,9 @@ class FooterNavigation extends Navigation
{
parent::initSubNavigation();
+ // imprint
+ $this->addSubNavigation('siteinfo', new Navigation(_('Impressum'), 'dispatch.php/siteinfo/show?cancel_login=1'));
+
// sitemap
if (is_object($GLOBALS['user']) && $GLOBALS['user']->id !== 'nobody') {
$this->addSubNavigation('sitemap', new Navigation(_('Sitemap'), 'dispatch.php/sitemap/'));
@@ -35,9 +38,6 @@ class FooterNavigation extends Navigation
//studip
$this->addSubNavigation('studip', new Navigation(_('Stud.IP'), 'http://www.studip.de/'));
- // imprint
- $this->addSubNavigation('siteinfo', new Navigation(_('Impressum'), 'dispatch.php/siteinfo/show?cancel_login=1'));
-
// Datenschutzerklärung
//Check if the privacy url is one of the Stud.IP pages:
diff --git a/lib/wiki.inc.php b/lib/wiki.inc.php
index 29e50e4..6d37e54 100644
--- a/lib/wiki.inc.php
+++ b/lib/wiki.inc.php
@@ -1031,8 +1031,14 @@ function wikiEdit($keyword, $wikiData, $user_id, $backpage=NULL, $ancestor=NULL)
}
// Create content bar.
- $contentBar = new ContentBar($toc,
- $page_string, Icon::create('wiki'), $actionMenu);
+ $contentBar = ContentBar::get()
+ ->setTOC(CoreWiki::getTOC(WikiPage::getStartPage(Context::getId())))
+ ->setInfo($page_string)
+ ->setIcon(Icon::create('wiki'));
+
+ if ($actionMenu) {
+ $contentBar->setActionMenu($actionMenu);
+ }
$template = $GLOBALS['template_factory']->open('wiki/edit.php');
$template->keyword = $keyword;
@@ -1590,8 +1596,14 @@ function showWikiPage($keyword, $version, $special="", $show_comments="icon", $h
}
// Create content bar.
- $contentBar = new ContentBar($toc,
- $page_string, Icon::create('wiki'), $actionMenu);
+ $contentBar = ContentBar::get()
+ ->setTOC(CoreWiki::getTOC(WikiPage::getStartPage(Context::getId())))
+ ->setInfo($page_string)
+ ->setIcon(Icon::create('wiki'));
+
+ if ($actionMenu) {
+ $contentBar->setActionMenu($actionMenu);
+ }
if ($hilight) {
// Highlighting must only take place outside HTML tags, so