diff --git a/app/assets/javascripts/onboarding/boards_tour.js b/app/assets/javascripts/onboarding/boards_tour.js index 40c7bf97ce7..0222b5a5921 100644 --- a/app/assets/javascripts/onboarding/boards_tour.js +++ b/app/assets/javascripts/onboarding/boards_tour.js @@ -17,7 +17,7 @@ 'next .board-list--container': I18n.t('js.onboarding.steps.boards.lists'), 'showSkip': false, 'nextButton': {text: I18n.t('js.onboarding.buttons.next')}, - 'containerClass': '-dark', + 'containerClass': '-dark -hidden-arrow', 'timeout': function() { return new Promise(function(resolve) { waitForElement('.wp-card', '#content', function() { diff --git a/app/assets/javascripts/onboarding/onboarding_tour.js b/app/assets/javascripts/onboarding/onboarding_tour.js index 509c39ba2dc..ba640047b04 100644 --- a/app/assets/javascripts/onboarding/onboarding_tour.js +++ b/app/assets/javascripts/onboarding/onboarding_tour.js @@ -28,7 +28,7 @@ var url = new URL(window.location.href); var isMobile = document.body.classList.contains('-browser-mobile'); var demoProjectsAvailable = $('meta[name=demo_projects_available]').attr('content') === "true"; - var boardsDemoDataAvailable = $('meta[name=boards_demo_data_available]').attr('content') === "true" + var boardsDemoDataAvailable = $('meta[name=boards_demo_data_available]').attr('content') === "true"; var eeTokenAvailable = !$('body').hasClass('ee-banners-visible'); // ------------------------------- Initial start ------------------------------- diff --git a/config/locales/en.yml b/config/locales/en.yml index 11bd4fad8b2..8cccb00629a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -973,7 +973,7 @@ en: description_choose_project: "Projects" description_compare_from: "Compare from" description_compare_to: "Compare to" - description_current_position: "You are here:" + description_current_position: "You are here: " description_date_from: "Enter start date" description_date_range_interval: "Choose range by selecting start and end date" description_date_range_list: "Choose range from list" diff --git a/config/locales/js-en.yml b/config/locales/js-en.yml index 463a507b192..c42ef92672d 100644 --- a/config/locales/js-en.yml +++ b/config/locales/js-en.yml @@ -107,7 +107,7 @@ en: too_many: 'There are more work packages (%{count}) than can be displayed by the calendar (%{max}). Add filters to focus on the relevant ones.' description_available_columns: "Available Columns" - description_current_position: "You are here:" + description_current_position: "You are here: " description_select_work_package: "Select work package #%{id}" description_selected_columns: "Selected Columns" description_subwork_package: "Child of work package #%{id}" diff --git a/frontend/src/app/modules/boards/openproject-boards.module.ts b/frontend/src/app/modules/boards/openproject-boards.module.ts index 889d88351b5..d77280d639c 100644 --- a/frontend/src/app/modules/boards/openproject-boards.module.ts +++ b/frontend/src/app/modules/boards/openproject-boards.module.ts @@ -55,6 +55,8 @@ import {DragScrollModule} from "cdk-drag-scroll"; import {BoardListDropdownMenuDirective} from "core-app/modules/boards/board/board-list/board-list-dropdown.directive"; import {BoardListService} from "core-app/modules/boards/board/board-list/board-list.service"; +const menuItemClass = 'board-view-menu-item'; + export const BOARDS_ROUTES:Ng2StateDeclaration[] = [ { name: 'boards', @@ -62,6 +64,10 @@ export const BOARDS_ROUTES:Ng2StateDeclaration[] = [ // The trailing slash is important // cf., https://community.openproject.com/wp/29754 url: '/boards/?query_props', + data: { + bodyClasses: 'router--boards-view-base', + menuItem: menuItemClass + }, params: { // Use custom encoder/decoder that ensures validity of URL string query_props: { type: 'opQueryString', dynamic: true } @@ -74,7 +80,8 @@ export const BOARDS_ROUTES:Ng2StateDeclaration[] = [ component: BoardsIndexPageComponent, data: { parent: 'boards', - bodyClasses: 'router--boards-list-view' + bodyClasses: 'router--boards-list-view', + menuItem: menuItemClass } }, { @@ -88,7 +95,8 @@ export const BOARDS_ROUTES:Ng2StateDeclaration[] = [ component: BoardComponent, data: { parent: 'boards', - bodyClasses: 'router--boards-full-view' + bodyClasses: 'router--boards-full-view', + menuItem: menuItemClass } } ]; diff --git a/frontend/src/app/modules/calendar/openproject-calendar.module.ts b/frontend/src/app/modules/calendar/openproject-calendar.module.ts index 7e2b88d4b1a..80a2d40d4fa 100644 --- a/frontend/src/app/modules/calendar/openproject-calendar.module.ts +++ b/frontend/src/app/modules/calendar/openproject-calendar.module.ts @@ -37,6 +37,8 @@ import {Ng2StateDeclaration, UIRouterModule} from "@uirouter/angular"; require("fullcalendar/dist/locale-all.js"); +const menuItemClass = 'calendar-menu-item'; + export const CALENDAR_ROUTES:Ng2StateDeclaration[] = [ { name: 'work-packages.calendar', @@ -45,6 +47,7 @@ export const CALENDAR_ROUTES:Ng2StateDeclaration[] = [ reloadOnSearch: false, data: { bodyClasses: 'router--work-packages-calendar', + menuItem: menuItemClass, parent: 'work-packages' } } diff --git a/frontend/src/app/modules/router/openproject.routes.ts b/frontend/src/app/modules/router/openproject.routes.ts index 00c26c915cc..e96e67f7dfe 100644 --- a/frontend/src/app/modules/router/openproject.routes.ts +++ b/frontend/src/app/modules/router/openproject.routes.ts @@ -72,6 +72,22 @@ export function bodyClass(className:string|null|undefined, action:'add'|'remove' document.body.classList[action](className); } } +export function updateMenuItem(menuItemClass:string|undefined, action:'add'|'remove' = 'add') { + if (menuItemClass) { + let menuItem = jQuery('#main-menu .' + menuItemClass)[0]; + + // Update Class + menuItem.classList[action]('selected'); + + // Update accessibility label + let menuItemTitle = (menuItem.getAttribute('title') || '').split(':').slice(-1)[0]; + if (action === 'add') { + menuItemTitle = I18n.t('js.description_current_position') + menuItemTitle; + } + + menuItem.setAttribute('title', menuItemTitle); + } +} export function uiRouterConfiguration(uiRouter:UIRouter, injector:Injector, module:StatesModule) { // Allow optional trailing slashes @@ -113,11 +129,17 @@ export function initializeUiRouterListeners(injector:Injector) { $transitions.onEnter({}, function(transition:Transition, state:StateDeclaration) { // Add body class when entering this state bodyClass(_.get(state, 'data.bodyClasses'), 'add'); + if (transition.from().data && _.get(state, 'data.menuItem') !== transition.from().data.menuItem) { + updateMenuItem(_.get(state, 'data.menuItem'), 'add'); + } }); $transitions.onExit({}, function(transition:Transition, state:StateDeclaration) { // Remove body class when leaving this state bodyClass(_.get(state, 'data.bodyClasses'), 'remove'); + if (transition.to().data && _.get(state, 'data.menuItem') !== transition.to().data.menuItem) { + updateMenuItem(_.get(state, 'data.menuItem'), 'remove'); + } }); $transitions.onStart({}, function(transition:Transition) { diff --git a/frontend/src/app/modules/work_packages/routing/work-packages-routes.ts b/frontend/src/app/modules/work_packages/routing/work-packages-routes.ts index 1d395bf79bf..b82fce4c48a 100644 --- a/frontend/src/app/modules/work_packages/routing/work-packages-routes.ts +++ b/frontend/src/app/modules/work_packages/routing/work-packages-routes.ts @@ -40,6 +40,8 @@ import {WorkPackageSplitViewComponent} from "core-app/modules/work_packages/rout import {Ng2StateDeclaration} from "@uirouter/angular"; import {WorkPackagesBaseComponent} from "core-app/modules/work_packages/routing/wp-base/wp--base.component"; +const menuItemClass = 'work-packages-menu-item'; + export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ { name: 'work-packages', @@ -48,7 +50,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ url: '/work_packages?query_id&query_props&start_onboarding_tour', redirectTo: 'work-packages.list', data: { - bodyClasses: 'router--work-packages-base' + bodyClasses: 'router--work-packages-base', + menuItem: menuItemClass }, params: { query_id: { type: 'query', dynamic: true }, @@ -65,7 +68,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ reloadOnSearch: false, data: { allowMovingInEditMode: true, - bodyClasses: 'router--work-packages-full-create' + bodyClasses: 'router--work-packages-full-create', + menuItem: menuItemClass }, }, { @@ -75,7 +79,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ reloadOnSearch: false, data: { allowMovingInEditMode: true, - bodyClasses: 'router--work-packages-full-create' + bodyClasses: 'router--work-packages-full-create', + menuItem: menuItemClass }, }, { @@ -85,7 +90,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ redirectTo: 'work-packages.show.activity', component: WorkPackagesFullViewComponent, data: { - bodyClasses: 'router--work-packages-full-view' + bodyClasses: 'router--work-packages-full-view', + menuItem: menuItemClass } }, { @@ -93,7 +99,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ url: '/activity', component: WorkPackageActivityTabComponent, data: { - parent: 'work-packages.show' + parent: 'work-packages.show', + menuItem: menuItemClass } }, { @@ -101,7 +108,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ url: '/activity/details/#{activity_no:\d+}', component: WorkPackageActivityTabComponent, data: { - parent: 'work-packages.show' + parent: 'work-packages.show', + menuItem: menuItemClass } }, { @@ -109,7 +117,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ url: '/relations', component: WorkPackageRelationsTabComponent, data: { - parent: 'work-packages.show' + parent: 'work-packages.show', + menuItem: menuItemClass } }, { @@ -117,7 +126,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ url: '/watchers', component: WorkPackageWatchersTabComponent, data: { - parent: 'work-packages.show' + parent: 'work-packages.show', + menuItem: menuItemClass } }, { @@ -126,7 +136,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ component: WorkPackagesListComponent, reloadOnSearch: false, data: { - bodyClasses: 'router--work-packages-list-view' + bodyClasses: 'router--work-packages-list-view', + menuItem: menuItemClass } }, { @@ -137,6 +148,7 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ data: { allowMovingInEditMode: true, bodyClasses: 'router--work-packages-split-view-new', + menuItem: menuItemClass, parent: 'work-packages.list' }, }, @@ -148,6 +160,7 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ data: { allowMovingInEditMode: true, bodyClasses: 'router--work-packages-split-view', + menuItem: menuItemClass, parent: 'work-packages.list' }, }, @@ -164,7 +177,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ } }, data: { - bodyClasses: 'router--work-packages-split-view' + bodyClasses: 'router--work-packages-split-view', + menuItem: menuItemClass }, }, { @@ -172,7 +186,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ url: '/overview', component: WorkPackageOverviewTabComponent, data: { - parent: 'work-packages.list.details' + parent: 'work-packages.list.details', + menuItem: menuItemClass } }, { @@ -180,7 +195,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ url: '/activity', component: WorkPackageActivityTabComponent, data: { - parent: 'work-packages.list.details' + parent: 'work-packages.list.details', + menuItem: menuItemClass } }, { @@ -188,7 +204,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ url: '/activity/details/#{activity_no:\d+}', component: WorkPackageActivityTabComponent, data: { - parent: 'work-packages.list.details' + parent: 'work-packages.list.details', + menuItem: menuItemClass } }, { @@ -196,7 +213,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ url: '/relations', component: WorkPackageRelationsTabComponent, data: { - parent: 'work-packages.list.details' + parent: 'work-packages.list.details', + menuItem: menuItemClass } }, { @@ -204,7 +222,8 @@ export const WORK_PACKAGES_ROUTES:Ng2StateDeclaration[] = [ url: '/watchers', component: WorkPackageWatchersTabComponent, data: { - parent: 'work-packages.list.details' + parent: 'work-packages.list.details', + menuItem: menuItemClass } }, // Avoid lazy-loading the routes for now diff --git a/lib/redmine/menu_manager/menu_helper.rb b/lib/redmine/menu_manager/menu_helper.rb index 853539d57ec..3b42cc5eab3 100644 --- a/lib/redmine/menu_manager/menu_helper.rb +++ b/lib/redmine/menu_manager/menu_helper.rb @@ -186,7 +186,6 @@ module Redmine::MenuManager::MenuHelper def render_single_menu_node(item, caption, url, selected) link_text = ''.html_safe link_text << op_icon(item.icon) if item.icon.present? - link_text << you_are_here_info(selected) link_text << content_tag(:span, class: "menu-item--title ellipsis #{item.badge.present? ? '-has-badge' : ''}", lang: menu_item_locale(item)) do