Chris@0: ' . t('About') . ''; Chris@0: $output .= '
' . t('The Shortcut module allows users to create sets of shortcut links to commonly-visited pages of the site. Shortcuts are contained within sets. Each user with Select any shortcut set permission can select a shortcut set created by anyone at the site. For more information, see the online documentation for the Shortcut module.', [':shortcut' => 'https://www.drupal.org/documentation/modules/shortcut']) . '
'; Chris@0: $output .= '' . t('Define which shortcut set you are using on the Shortcuts tab of your account page.', [':shortcut-link' => Url::fromRoute('shortcut.set_switch', ['user' => $user->id()])->toString()]) . '
'; Chris@0: return $output; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Access callback for editing a shortcut set. Chris@0: * Chris@0: * @param Drupal\shortcut\ShortcutSetInterface $shortcut_set Chris@0: * (optional) The shortcut set to be edited. If not set, the current user's Chris@0: * shortcut set will be used. Chris@0: * Chris@0: * @return \Drupal\Core\Access\AccessResultInterface Chris@0: * The access result. Chris@0: */ Chris@0: function shortcut_set_edit_access(ShortcutSetInterface $shortcut_set = NULL) { Chris@0: $account = \Drupal::currentUser(); Chris@0: Chris@0: // Shortcut administrators can edit any set. Chris@0: if ($account->hasPermission('administer shortcuts')) { Chris@0: return AccessResult::allowed()->cachePerPermissions(); Chris@0: } Chris@0: Chris@0: // Sufficiently-privileged users can edit their currently displayed shortcut Chris@0: // set, but not other sets. They must also be able to access shortcuts. Chris@0: $may_edit_current_shortcut_set = $account->hasPermission('customize shortcut links') && (!isset($shortcut_set) || $shortcut_set == shortcut_current_displayed_set()) && $account->hasPermission('access shortcuts'); Chris@0: $result = AccessResult::allowedIf($may_edit_current_shortcut_set)->cachePerPermissions(); Chris@0: if (!$result->isAllowed()) { Chris@0: $result->setReason("The shortcut set must be the currently displayed set for the user and the user must have 'access shortcuts' AND 'customize shortcut links' permissions."); Chris@0: } Chris@0: return $result; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Access callback for switching the shortcut set assigned to a user account. Chris@0: * Chris@0: * @param object $account Chris@0: * (optional) The user account whose shortcuts will be switched. If not set, Chris@0: * permissions will be checked for switching the logged-in user's own Chris@0: * shortcut set. Chris@0: * Chris@0: * @return \Drupal\Core\Access\AccessResultInterface Chris@0: * The access result. Chris@0: */ Chris@0: function shortcut_set_switch_access($account = NULL) { Chris@0: $user = \Drupal::currentUser(); Chris@0: Chris@0: if ($user->hasPermission('administer shortcuts')) { Chris@0: // Administrators can switch anyone's shortcut set. Chris@0: return AccessResult::allowed()->cachePerPermissions(); Chris@0: } Chris@0: Chris@0: if (!$user->hasPermission('access shortcuts')) { Chris@0: // The user has no permission to use shortcuts. Chris@0: return AccessResult::neutral()->cachePerPermissions(); Chris@0: } Chris@0: Chris@0: if (!$user->hasPermission('switch shortcut sets')) { Chris@0: // The user has no permission to switch anyone's shortcut set. Chris@0: return AccessResult::neutral()->cachePerPermissions(); Chris@0: } Chris@0: Chris@0: // Users with the 'switch shortcut sets' permission can switch their own Chris@0: // shortcuts sets. Chris@0: if (!isset($account)) { Chris@0: return AccessResult::allowed()->cachePerPermissions(); Chris@0: } Chris@0: elseif ($user->id() == $account->id()) { Chris@0: return AccessResult::allowed()->cachePerPermissions()->cachePerUser(); Chris@0: } Chris@0: Chris@0: // No opinion. Chris@0: return AccessResult::neutral()->cachePerPermissions(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Assigns a user to a particular shortcut set. Chris@0: * Chris@0: * @param $shortcut_set Drupal\shortcut\Entity\Shortcut Chris@0: * An object representing the shortcut set. Chris@0: * @param $account Chris@0: * A user account that will be assigned to use the set. Chris@0: * Chris@0: * @deprecated in Drupal 8.x, will be removed before Drupal 9.0. Chris@0: * Use \Drupal::entityManager()->getStorage('shortcut_set')->assignUser(). Chris@0: */ Chris@0: function shortcut_set_assign_user($shortcut_set, $account) { Chris@0: \Drupal::entityManager() Chris@0: ->getStorage('shortcut_set') Chris@0: ->assignUser($shortcut_set, $account); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Unassigns a user from any shortcut set they may have been assigned to. Chris@0: * Chris@0: * The user will go back to using whatever default set applies. Chris@0: * Chris@0: * @param $account Chris@0: * A user account that will be removed from the shortcut set assignment. Chris@0: * Chris@0: * @return Chris@0: * TRUE if the user was previously assigned to a shortcut set and has been Chris@0: * successfully removed from it. FALSE if the user was already not assigned Chris@0: * to any set. Chris@0: * Chris@0: * @deprecated in Drupal 8.x, will be removed before Drupal 9.0. Chris@0: * Use \Drupal::entityManager()->getStorage('shortcut_set')->unassignUser(). Chris@0: */ Chris@0: function shortcut_set_unassign_user($account) { Chris@0: return (bool) \Drupal::entityManager() Chris@0: ->getStorage('shortcut_set') Chris@0: ->unassignUser($account); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the current displayed shortcut set for the provided user account. Chris@0: * Chris@0: * @param $account Chris@0: * (optional) The user account whose shortcuts will be returned. Defaults to Chris@0: * the currently logged-in user. Chris@0: * Chris@0: * @return Chris@0: * An object representing the shortcut set that should be displayed to the Chris@0: * current user. If the user does not have an explicit shortcut set defined, Chris@0: * the default set is returned. Chris@0: */ Chris@0: function shortcut_current_displayed_set($account = NULL) { Chris@0: $shortcut_sets = &drupal_static(__FUNCTION__, []); Chris@0: $user = \Drupal::currentUser(); Chris@0: if (!isset($account)) { Chris@0: $account = $user; Chris@0: } Chris@0: // Try to return a shortcut set from the static cache. Chris@0: if (isset($shortcut_sets[$account->id()])) { Chris@0: return $shortcut_sets[$account->id()]; Chris@0: } Chris@0: // If none was found, try to find a shortcut set that is explicitly assigned Chris@0: // to this user. Chris@0: $shortcut_set_name = \Drupal::entityManager() Chris@0: ->getStorage('shortcut_set') Chris@0: ->getAssignedToUser($account); Chris@0: if ($shortcut_set_name) { Chris@0: $shortcut_set = ShortcutSet::load($shortcut_set_name); Chris@0: } Chris@0: // Otherwise, use the default set. Chris@0: else { Chris@0: $shortcut_set = shortcut_default_set($account); Chris@0: } Chris@0: Chris@0: $shortcut_sets[$account->id()] = $shortcut_set; Chris@0: return $shortcut_set; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the default shortcut set for a given user account. Chris@0: * Chris@0: * @param object $account Chris@0: * (optional) The user account whose default shortcut set will be returned. Chris@0: * If not provided, the function will return the currently logged-in user's Chris@0: * default shortcut set. Chris@0: * Chris@0: * @return Chris@0: * An object representing the default shortcut set. Chris@0: */ Chris@0: function shortcut_default_set($account = NULL) { Chris@0: $user = \Drupal::currentUser(); Chris@0: if (!isset($account)) { Chris@0: $account = $user; Chris@0: } Chris@0: Chris@0: // Allow modules to return a default shortcut set name. Since we can only Chris@0: // have one, we allow the last module which returns a valid result to take Chris@0: // precedence. If no module returns a valid set, fall back on the site-wide Chris@0: // default, which is the lowest-numbered shortcut set. Chris@0: $suggestions = array_reverse(\Drupal::moduleHandler()->invokeAll('shortcut_default_set', [$account])); Chris@0: $suggestions[] = 'default'; Chris@0: foreach ($suggestions as $name) { Chris@0: if ($shortcut_set = ShortcutSet::load($name)) { Chris@0: break; Chris@0: } Chris@0: } Chris@0: Chris@0: return $shortcut_set; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Check to see if a shortcut set with the given title already exists. Chris@0: * Chris@0: * @param $title Chris@0: * Human-readable name of the shortcut set to check. Chris@0: * Chris@0: * @return Chris@0: * TRUE if a shortcut set with that title exists; FALSE otherwise. Chris@0: * Chris@0: * @deprecated in Drupal 8.x, will be removed before Drupal 9.0. Chris@0: */ Chris@0: function shortcut_set_title_exists($title) { Chris@0: $sets = ShortcutSet::loadMultiple(); Chris@0: foreach ($sets as $set) { Chris@0: if ($set->label() == $title) { Chris@0: return TRUE; Chris@0: } Chris@0: } Chris@0: return FALSE; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns an array of shortcut links, suitable for rendering. Chris@0: * Chris@0: * @param \Drupal\shortcut\ShortcutSetInterface $shortcut_set Chris@0: * (optional) An object representing the set whose links will be displayed. Chris@0: * If not provided, the user's current set will be displayed. Chris@0: * Chris@0: * @return \Drupal\shortcut\ShortcutInterface[] Chris@0: * An array of shortcut links, in the format returned by the menu system. Chris@0: */ Chris@0: function shortcut_renderable_links($shortcut_set = NULL) { Chris@0: $shortcut_links = []; Chris@0: Chris@0: if (!isset($shortcut_set)) { Chris@0: $shortcut_set = shortcut_current_displayed_set(); Chris@0: } Chris@0: Chris@0: $cache_tags = []; Chris@0: foreach ($shortcut_set->getShortcuts() as $shortcut) { Chris@18: $shortcut = \Drupal::service('entity.repository')->getTranslationFromContext($shortcut); Chris@0: $url = $shortcut->getUrl(); Chris@0: if ($url->access()) { Chris@0: $links[$shortcut->id()] = [ Chris@0: 'type' => 'link', Chris@0: 'title' => $shortcut->label(), Chris@0: 'url' => $shortcut->getUrl(), Chris@0: ]; Chris@0: $cache_tags = Cache::mergeTags($cache_tags, $shortcut->getCacheTags()); Chris@0: } Chris@0: } Chris@0: Chris@0: if (!empty($links)) { Chris@0: $shortcut_links = [ Chris@0: '#theme' => 'links__toolbar_shortcuts', Chris@0: '#links' => $links, Chris@0: '#attributes' => [ Chris@0: 'class' => ['toolbar-menu'], Chris@0: ], Chris@0: '#cache' => [ Chris@0: 'tags' => $cache_tags, Chris@0: ], Chris@0: ]; Chris@0: } Chris@0: Chris@0: return $shortcut_links; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Implements hook_preprocess_HOOK() for block templates. Chris@0: */ Chris@0: function shortcut_preprocess_block(&$variables) { Chris@0: if ($variables['configuration']['provider'] == 'shortcut') { Chris@0: $variables['attributes']['role'] = 'navigation'; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Implements hook_preprocess_HOOK() for page title templates. Chris@0: */ Chris@0: function shortcut_preprocess_page_title(&$variables) { Chris@0: // Only display the shortcut link if the user has the ability to edit Chris@0: // shortcuts and if the page's actual content is being shown (for example, Chris@0: // we do not want to display it on "access denied" or "page not found" Chris@0: // pages). Chris@0: if (shortcut_set_edit_access()->isAllowed() && !\Drupal::request()->attributes->has('exception')) { Chris@0: $link = Url::fromRouteMatch(\Drupal::routeMatch())->getInternalPath(); Chris@0: $route_match = \Drupal::routeMatch(); Chris@0: Chris@0: // Replicate template_preprocess_html()'s processing to get the title in Chris@0: // string form, so we can set the default name for the shortcut. Chris@0: // Strip HTML tags from the title. Chris@0: $name = trim(strip_tags(render($variables['title']))); Chris@0: $query = [ Chris@0: 'link' => $link, Chris@0: 'name' => $name, Chris@0: ]; Chris@0: Chris@0: $shortcut_set = shortcut_current_displayed_set(); Chris@0: Chris@0: // Check if $link is already a shortcut and set $link_mode accordingly. Chris@0: $shortcuts = \Drupal::entityManager()->getStorage('shortcut')->loadByProperties(['shortcut_set' => $shortcut_set->id()]); Chris@0: /** @var \Drupal\shortcut\ShortcutInterface $shortcut */ Chris@0: foreach ($shortcuts as $shortcut) { Chris@0: if (($shortcut_url = $shortcut->getUrl()) && $shortcut_url->isRouted() && $shortcut_url->getRouteName() == $route_match->getRouteName() && $shortcut_url->getRouteParameters() == $route_match->getRawParameters()->all()) { Chris@0: $shortcut_id = $shortcut->id(); Chris@0: break; Chris@0: } Chris@0: } Chris@0: $link_mode = isset($shortcut_id) ? "remove" : "add"; Chris@0: Chris@0: if ($link_mode == "add") { Chris@0: $link_text = shortcut_set_switch_access()->isAllowed() ? t('Add to %shortcut_set shortcuts', ['%shortcut_set' => $shortcut_set->label()]) : t('Add to shortcuts'); Chris@0: $route_name = 'shortcut.link_add_inline'; Chris@0: $route_parameters = ['shortcut_set' => $shortcut_set->id()]; Chris@0: } Chris@0: else { Chris@0: $query['id'] = $shortcut_id; Chris@0: $link_text = shortcut_set_switch_access()->isAllowed() ? t('Remove from %shortcut_set shortcuts', ['%shortcut_set' => $shortcut_set->label()]) : t('Remove from shortcuts'); Chris@0: $route_name = 'entity.shortcut.link_delete_inline'; Chris@0: $route_parameters = ['shortcut' => $shortcut_id]; Chris@0: } Chris@0: Chris@0: if (theme_get_setting('third_party_settings.shortcut.module_link')) { Chris@0: $query += \Drupal::destination()->getAsArray(); Chris@0: $variables['title_suffix']['add_or_remove_shortcut'] = [ Chris@0: '#attached' => [ Chris@0: 'library' => [ Chris@0: 'shortcut/drupal.shortcut', Chris@0: ], Chris@0: ], Chris@0: '#type' => 'link', Chris@17: '#title' => new FormattableMarkup(' ', ['@text' => $link_text]), Chris@0: '#url' => Url::fromRoute($route_name, $route_parameters), Chris@0: '#options' => ['query' => $query], Chris@0: '#attributes' => [ Chris@0: 'class' => [ Chris@0: 'shortcut-action', Chris@0: 'shortcut-action--' . $link_mode, Chris@0: ], Chris@0: ], Chris@0: ]; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Implements hook_toolbar(). Chris@0: */ Chris@0: function shortcut_toolbar() { Chris@0: $user = \Drupal::currentUser(); Chris@0: Chris@0: $items = []; Chris@0: $items['shortcuts'] = [ Chris@0: '#cache' => [ Chris@0: 'contexts' => [ Chris@0: // Cacheable per user, because each user can have their own shortcut Chris@0: // set, even if they cannot create or select a shortcut set, because Chris@0: // an administrator may have assigned a non-default shortcut set. Chris@0: 'user', Chris@0: ], Chris@0: ], Chris@0: ]; Chris@0: Chris@0: if ($user->hasPermission('access shortcuts')) { Chris@0: $links = shortcut_renderable_links(); Chris@0: $shortcut_set = shortcut_current_displayed_set(); Chris@0: \Drupal::service('renderer')->addCacheableDependency($items['shortcuts'], $shortcut_set); Chris@0: $configure_link = NULL; Chris@0: if (shortcut_set_edit_access($shortcut_set)->isAllowed()) { Chris@0: $configure_link = [ Chris@0: '#type' => 'link', Chris@0: '#title' => t('Edit shortcuts'), Chris@0: '#url' => Url::fromRoute('entity.shortcut_set.customize_form', ['shortcut_set' => $shortcut_set->id()]), Chris@0: '#options' => ['attributes' => ['class' => ['edit-shortcuts']]], Chris@0: ]; Chris@0: } Chris@0: if (!empty($links) || !empty($configure_link)) { Chris@0: $items['shortcuts'] += [ Chris@0: '#type' => 'toolbar_item', Chris@0: 'tab' => [ Chris@0: '#type' => 'link', Chris@0: '#title' => t('Shortcuts'), Chris@18: '#url' => $shortcut_set->toUrl('collection'), Chris@0: '#attributes' => [ Chris@0: 'title' => t('Shortcuts'), Chris@0: 'class' => ['toolbar-icon', 'toolbar-icon-shortcut'], Chris@0: ], Chris@0: ], Chris@0: 'tray' => [ Chris@0: '#heading' => t('User-defined shortcuts'), Chris@0: 'shortcuts' => $links, Chris@0: 'configure' => $configure_link, Chris@0: ], Chris@0: '#weight' => -10, Chris@0: '#attached' => [ Chris@0: 'library' => [ Chris@0: 'shortcut/drupal.shortcut', Chris@0: ], Chris@0: ], Chris@0: ]; Chris@0: } Chris@0: } Chris@0: Chris@0: return $items; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Implements hook_themes_installed(). Chris@0: */ Chris@0: function shortcut_themes_installed($theme_list) { Chris@0: if (in_array('seven', $theme_list)) { Chris@0: // Theme settings are not configuration entities and cannot depend on modules Chris@0: // so to set a module-specific setting, we need to set it with logic. Chris@0: if (\Drupal::moduleHandler()->moduleExists('shortcut')) { Chris@0: \Drupal::configFactory()->getEditable('seven.settings')->set('third_party_settings.shortcut.module_link', TRUE)->save(TRUE); Chris@0: } Chris@0: } Chris@0: }