Skip to content
Snippets Groups Projects
Select Git revision
  • 1ad0adedc541bfb27ab5808f9e0f8a3bce81ba5a
  • 11.x default protected
  • 10.5.x protected
  • 11.2.x protected
  • 10.6.x protected
  • 11.1.x protected
  • 10.4.x protected
  • 11.0.x protected
  • 10.3.x protected
  • 7.x protected
  • 10.2.x protected
  • 10.1.x protected
  • 9.5.x protected
  • 10.0.x protected
  • 9.4.x protected
  • 9.3.x protected
  • 9.2.x protected
  • 9.1.x protected
  • 8.9.x protected
  • 9.0.x protected
  • 8.8.x protected
  • 10.5.1 protected
  • 11.2.2 protected
  • 11.2.1 protected
  • 11.2.0 protected
  • 10.5.0 protected
  • 11.2.0-rc2 protected
  • 10.5.0-rc1 protected
  • 11.2.0-rc1 protected
  • 10.4.8 protected
  • 11.1.8 protected
  • 10.5.0-beta1 protected
  • 11.2.0-beta1 protected
  • 11.2.0-alpha1 protected
  • 10.4.7 protected
  • 11.1.7 protected
  • 10.4.6 protected
  • 11.1.6 protected
  • 10.3.14 protected
  • 10.4.5 protected
  • 11.0.13 protected
41 results

toolbar.module

Blame
  • Alex Pott's avatar
    Issue #1957148 by damiankloip | Berdir: Replace entity_query() with Drupal::entityQuery().
    Alex Pott authored
    bea3588b
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    toolbar.module 20.39 KiB
    <?php
    
    /**
     * @file
     * Administration toolbar for quick access to top level administration items.
     */
    
    use Symfony\Component\HttpFoundation\JsonResponse;
    use Drupal\Core\Template\Attribute;
    
    /**
     * Implements hook_help().
     */
    function toolbar_help($path, $arg) {
      switch ($path) {
        case 'admin/help#toolbar':
          $output = '<h3>' . t('About') . '</h3>';
          $output .= '<p>' . t('The Toolbar module displays links to top-level administration menu items and links from other modules at the top of the screen. For more information, see the online handbook entry for <a href="@toolbar">Toolbar module</a>.', array('@toolbar' => 'http://drupal.org/documentation/modules/toolbar')) . '</p>';
          $output .= '<h3>' . t('Uses') . '</h3>';
          $output .= '<dl>';
          $output .= '<dt>' . t('Displaying administrative links') . '</dt>';
          $output .= '<dd>' . t('The Toolbar module displays a bar containing top-level administrative components across the top of the screen. Below that, the Toolbar module has a <em>drawer</em> section where it displays links provided by other modules, such as the core <a href="@shortcuts-help">Shortcut module</a>. The drawer can be hidden/shown by clicking on its corresponding tab.', array('@shortcuts-help' => url('admin/help/shortcut'))) . '</dd>';
          $output .= '</dl>';
          return $output;
      }
    }
    
    /**
     * Implements hook_permission().
     */
    function toolbar_permission() {
      return array(
        'access toolbar' => array(
          'title' => t('Use the administration toolbar'),
        ),
      );
    }
    
    /**
     * Implements hook_theme().
     */
    function toolbar_theme($existing, $type, $theme, $path) {
      $items['toolbar'] = array(
        'render element' => 'element',
      );
      $items['toolbar_item'] = array(
        'render element' => 'element',
      );
      $items['toolbar_tab_wrapper'] = array(
        'render element' => 'element',
      );
      $items['toolbar_tray_wrapper'] = array(
        'render element' => 'element',
      );
      $items['toolbar_tray_heading_wrapper'] = array(
        'render element' => 'element',
      );
      return $items;
    }
    
    /**
     * Implements hook_menu().
     */
    function toolbar_menu() {
      $items['toolbar/subtrees/%'] = array(
        'page callback' => 'toolbar_subtrees_jsonp',
        'page arguments' => array(2),
        'access callback' => '_toolbar_subtrees_access',
        'access arguments' => array(2),
        'type' => MENU_CALLBACK,
      );
      return $items;
    }
    
    /**
     * Implements hook_element_info().
     */
    function toolbar_element_info() {
      $elements = array();
    
      $elements['toolbar'] = array(
        '#pre_render' => array('toolbar_pre_render'),
        '#theme' => 'toolbar',
        '#attached' => array(
          'library' => array(
            array('toolbar', 'toolbar'),
          ),
        ),
        // Metadata for the toolbar wrapping element.
        '#attributes' => array(
          // The id cannot be simply "toolbar" or it will clash with the simpletest
          // tests listing which produces a checkbox with attribute id="toolbar"
          'id' => 'toolbar-administration',
          // The 'overlay-displace-top' class pushes the overlay down, so it appears
          // below the toolbar.
          'class' => array('toolbar',),
          'role' => 'navigation',
        ),
        // Metadata for the administration bar.
        '#bar' => array(
          '#heading' => t('Toolbar items'),
          '#attributes' => array(
            'id' => 'toolbar-bar',
            'class' => array('bar', 'clearfix',),
            'data-offset-top' => array(),
          ),
        ),
      );
    
      // A toolbar item is wrapped in markup for common styling.  The 'tray'
      // property contains a renderable array. theme_toolbar_tab() is a light
      // wrapper around the l() function. The contents of tray are rendered in
      // theme_toolbar_tab().
      $elements['toolbar_item'] = array(
        '#pre_render' => array('toolbar_pre_render_item'),
        '#theme' => 'toolbar_item',
        '#theme_wrappers' => array('toolbar_tab_wrapper'),
        'tab' => array(
          '#type' => 'link',
          '#title' => NULL,
          '#href' => '',
        ),
      );
      return $elements;
    }
    
    /**
     * Access callback: Returns if the user has access to the rendered subtree requested by the hash.
     *
     * @see toolbar_menu().
     */
    function _toolbar_subtrees_access($hash) {
      return user_access('access toolbar') && ($hash == _toolbar_get_subtree_hash());
    }
    
    /**
     * Page callback: Returns the rendered subtree of each top-level toolbar link.
     *
     * @see toolbar_menu().
     */
    function toolbar_subtrees_jsonp($hash) {
      _toolbar_initialize_page_cache();
      $subtrees = toolbar_get_rendered_subtrees();
      $response = new JsonResponse($subtrees);
      $response->setCallback('Drupal.toolbar.setSubtrees');
      return $response;
    }
    
    /**
     * Use Drupal's page cache for toolbar/subtrees/*, even for authenticated users.
     *
     * This gets invoked after full bootstrap, so must duplicate some of what's
     * done by _drupal_bootstrap_page_cache().
     *
     * @todo Replace this hack with something better integrated with DrupalKernel
     *   once Drupal's page caching itself is properly integrated.
     */
    function _toolbar_initialize_page_cache() {
      $GLOBALS['conf']['system.performance']['cache']['page']['enabled'] = TRUE;
      drupal_page_is_cacheable(TRUE);
    
      // If we have a cache, serve it.
      // @see _drupal_bootstrap_page_cache()
      $cache = drupal_page_get_cache();
      if (is_object($cache)) {
        header('X-Drupal-Cache: HIT');
        // Restore the metadata cached with the page.
        $_GET['q'] = $cache->data['path'];
        date_default_timezone_set(drupal_get_user_timezone());
    
        drupal_serve_page_from_cache($cache);
    
        // We are done.
        exit;
      }
    
      // Otherwise, create a new page response (that will be cached).
      header('X-Drupal-Cache: MISS');
    
      // The Expires HTTP header is the heart of the client-side HTTP caching. The
      // additional server-side page cache only takes effect when the client
      // accesses the callback URL again (e.g., after clearing the browser cache or
      // when force-reloading a Drupal page).
      $max_age = 3600 * 24 * 365;
      drupal_add_http_header('Expires', gmdate(DATE_RFC1123, REQUEST_TIME + $max_age));
      drupal_add_http_header('Cache-Control', 'private, max-age=' . $max_age);
    }
    
    /**
     * Implements hook_page_build().
     *
     * Add admin toolbar to the page_top region automatically.
     */
    function toolbar_page_build(&$page) {
      $page['page_top']['toolbar'] = array(
        '#type' => 'toolbar',
        '#access' => user_access('access toolbar'),
      );
    }
    
    /**
     * Builds the Toolbar as a structured array ready for drupal_render().
     *
     * Since building the toolbar takes some time, it is done just prior to
     * rendering to ensure that it is built only if it will be displayed.
     *
     * @param array $element
     *  A renderable array.
     *
     * @return
     *  A renderable array.
     *
     * @see toolbar_page_build().
     */
    function toolbar_pre_render($element) {
    
      // Get the configured breakpoints to switch from vertical to horizontal
      // toolbar presentation.
      $breakpoints = entity_load('breakpoint_group', 'module.toolbar.toolbar');
      if (!empty($breakpoints)) {
        $media_queries = array();
        $media_queries['toolbar']['breakpoints'] = array_map(
          function ($object) {
            return $object->mediaQuery;
          },
          $breakpoints->breakpoints
        );
    
        $element['#attached']['js'][] = array(
          'data' => $media_queries,
          'type' => 'setting',
        );
      }
    
      // Get toolbar items from all modules that implement hook_toolbar().
      $items = module_invoke_all('toolbar');
      // Allow for altering of hook_toolbar().
      drupal_alter('toolbar', $items);
      // Sort the children.
      uasort($items, 'element_sort');
    
      // Merge in the original toolbar values.
      $element = array_merge($element, $items);
    
      // Render the children.
      $element['#children'] = drupal_render_children($element);
    
      return $element;
    }
    
    /**
     * Returns HTML that wraps the administration toolbar.
     *
     * @param array $variables
     *   An associative array containing:
     *   - element: An associative array containing the properties and children of
     *     the tray. Properties used: #children, #attributes and #bar.
     */
    function theme_toolbar(&$variables) {
      if (!empty($variables['element']['#children'])) {
        $element = $variables['element'];
        $trays = '';
        foreach (element_children($element) as $key) {
          $trays .= drupal_render($element[$key]['tray']);
        }
        return '<nav' . new Attribute($element['#attributes']) . '>'
          . '<div' . new Attribute($element['#bar']['#attributes']) . '>'
          . '<h2 class="element-invisible">' . $element['#bar']['#heading'] . '</h2>'
          . $element['#children'] . '</div>' . $trays . '</nav>';
      }
    }
    
    /**
     * Provides markup for associating a tray trigger with a tray element.
     *
     * A tray is a responsive container that wraps renderable content. Trays present
     * content well on small and large screens alike.
     *
     * @param array $element
     *   A renderable array.
     *
     * @return
     *   A renderable array.
     */
    function toolbar_pre_render_item($element) {
    
      // If tray content is present, markup the tray and its associated trigger.
      if (!empty($element['tray'])) {
    
        // Trays are associated with their trigger by a unique ID.
        $id = drupal_html_id('toolbar-tray');
        $element['tab']['#tray_id'] = $id;
    
        // Provide attributes for a tray trigger.
        $attributes = array(
          'id' => 'toolbar-tab-' . $id,
          'data-toolbar-tray' => $id,
          'aria-owns' => $id,
          'role' => 'button',
          'aria-pressed' => 'false',
        );
        // Merge in module-provided attributes.
        $element['tab'] += array('#attributes' => array());
        $element['tab']['#attributes'] += $attributes;
        $element['tab']['#attributes']['class'][] = 'trigger';
    
        // Provide attributes for the tray theme wrapper.
        $attributes = array(
          'id' => $id,
          'data-toolbar-tray' => $id,
          'aria-owned-by' => 'toolbar-tab-' . $id,
        );
        // Merge in module-provided attributes.
        if (!isset($element['tray']['#wrapper_attributes'])) {
          $element['tray']['#wrapper_attributes'] = array();
        }
        $element['tray']['#wrapper_attributes'] += $attributes;
        $element['tray']['#wrapper_attributes']['class'][] = 'tray';
    
        if (!isset($element['tray']['#theme_wrappers'])) {
          $element['tray']['#theme_wrappers'] = array();
        }
        // Add the standard theme_wrapper for trays.
        array_unshift($element['tray']['#theme_wrappers'], 'toolbar_tray_wrapper');
        // If a #heading is provided for the tray, provided a #theme_wrapper
        // function to append it.
        if (!empty($element['tray']['#heading'])) {
          array_unshift($element['tray']['#theme_wrappers'], 'toolbar_tray_heading_wrapper');
        }
      }
    
      return $element;
    }
    
    /**
     * Implements template_preprocess_HOOK().
     */
    function template_preprocess_toolbar_tab_wrapper(&$variables) {
      if (!isset($variables['element']['#wrapper_attributes'])) {
        $variables['element']['#wrapper_attributes'] = array();
      }
      $variables['element']['#wrapper_attributes']['class'][] = 'tab';
    }
    
    /**
     * Returns HTML for a toolbar item.
     *
     * This theme function only renders the tab portion of the toolbar item. The
     * tray portion will be rendered later.
     *
     * @param array $variables
     *   An associative array containing:
     *   - element: An associative array containing the properties and children of
     *     the tray. Property used: tab.
     *
     * @see toolbar_pre_render_item().
     * @see theme_toolbar().
     */
    function theme_toolbar_item(&$variables) {
      return drupal_render($variables['element']['tab']);
    }
    
    /**
     * Returns HTML for wrapping a toolbar tab.
     *
     * Toolbar tabs have a common styling and placement with the toolbar's bar area.
     *
     * @param array $variables
     *   An associative array containing:
     *   - element: An associative array containing the properties and children of
     *     the tray. Properties used: #children and #attributes.
     */
    function theme_toolbar_tab_wrapper(&$variables) {
      if (!empty($variables['element']['#children'])) {
        $element = $variables['element'];
        return '<div' . new Attribute($element['#wrapper_attributes']) . '>' . $element['#children'] . '</div>';
      }
    }
    
    /**
     * Returns HTML for wrapping a toolbar tray.
     *
     * Used in combination with theme_toolbar_tab() to create an
     * association between a link tag in the administration bar and a tray.
     *
     * @param array $variables
     *   An associative array containing:
     *   - element: An associative array containing the properties and children of
     *     the tray. Properties used: #children, #toolbar_identifier and
     *     #attributes.
     */
    function theme_toolbar_tray_wrapper(&$variables) {
      if (!empty($variables['element']['#children'])) {
        $element = $variables['element'];
        return '<div' . new Attribute($element['#wrapper_attributes']) . '><div class="lining clearfix">' . $element['#children'] . '</div></div>';
      }
    }
    
    /**
     * Returns HTML for prepending a heading to a toolbar tray.
     *
     * @param array $variables
     *   An associative array containing:
     *   - element: An associative array containing the properties and children of
     *     the tray. Properties used: #children and #heading.
     */
    function theme_toolbar_tray_heading_wrapper(&$variables) {
      if (!empty($variables['element']['#children'])) {
        $element = $variables['element'];
        return '<h3 class="element-invisible">' . $element['#heading'] . '</h3>' . $element['#children'];
      }
    }
    
    /**
     * Implements hook_system_info_alter().
     *
     * Indicate that the 'page_top' region (in which the toolbar will be displayed)
     * is an overlay supplemental region that should be refreshed whenever its
     * content is updated.
     *
     * This information is provided for any module that might need to use it, not
     * just the core Overlay module.
     */
    function toolbar_system_info_alter(&$info, $file, $type) {
      if ($type == 'theme') {
        $info['overlay_supplemental_regions'][] = 'page_top';
      }
    }
    
    /**
     * Implements hook_toolbar().
     */
    function toolbar_toolbar() {
      $items = array();
    
      // The 'Home' tab is a simple link, with no corresponding tray.
      $items['home'] = array(
        '#type' => 'toolbar_item',
        'tab' => array(
          '#type' => 'link',
          '#title' => t('Home'),
          '#href' => '<front>',
          '#options' => array(
            'attributes' => array(
              'title' => t('Home page'),
              'class' => array('icon', 'icon-home'),
            ),
          ),
        ),
        '#weight' => -20,
      );
    
      // Retrieve the administration menu from the database.
      $tree = toolbar_get_menu_tree();
    
      // Add attributes to the links before rendering.
      toolbar_menu_navigation_links($tree);
    
      $menu = array(
        '#heading' => t('Administration menu'),
        'toolbar_administration' => array(
          '#type' => 'container',
          '#attributes' => array(
            'class' => array('toolbar-menu-administration'),
          ),
          'administration_menu' => menu_tree_output($tree),
        ),
      );
    
      // To conserve bandwidth, we only include the top-level links in the HTML.
      // The subtrees are included in a JSONP script, cached by the browser. Here we
      // add that JSONP script. We add it as an external script, because it's a
      // Drupal path, not a file available via a stream wrapper.
      // @see toolbar_subtrees_jsonp()
      $menu['toolbar_administration']['#attached']['js'][url('toolbar/subtrees/' . _toolbar_get_subtree_hash())] = array('type' => 'external');
    
      // The administration element has a link that is themed to correspond to
      // a toolbar tray. The tray contains the full administrative menu of the site.
      $items['administration'] = array(
        '#type' => 'toolbar_item',
        'tab' => array(
          '#type' => 'link',
          '#title' => t('Menu'),
          '#href' => 'admin',
          '#options' => array(
            'attributes' => array(
              'title' => t('Admin menu'),
              'class' => array('icon', 'icon-menu'),
            ),
          ),
        ),
        'tray' => $menu,
        '#weight' => -15,
      );
    
      return $items;
    }
    
    /**
     * Gets only the top level items below the 'admin' path.
     *
     * @return
     *   An array containing a menu tree of top level items below the 'admin' path.
     */
    function toolbar_get_menu_tree() {
      $tree = array();
      $query = Drupal::entityQuery('menu_link')
        ->condition('menu_name', 'admin')
        ->condition('module', 'system')
        ->condition('link_path', 'admin');
      $result = $query->execute();
      if (!empty($result)) {
        $admin_link = menu_link_load(reset($result));
        $tree = menu_build_tree('admin', array(
          'expanded' => array($admin_link['mlid']),
          'min_depth' => $admin_link['depth'] + 1,
          'max_depth' => $admin_link['depth'] + 1,
        ));
      }
    
      return $tree;
    }
    
    /**
     * Generates an array of links from a menu tree array.
     *
     * Based on menu_navigation_links(). Adds path based IDs and icon placeholders
     * to the links.
     *
     * @return
     *   An array of links as defined above.
     */
    function toolbar_menu_navigation_links(&$tree) {
      foreach ($tree as $key => $item) {
        // Configure sub-items.
        if (!empty($item['below'])) {
          toolbar_menu_navigation_links($tree[$key]['below']);
        }
        // Make sure we have a path specific ID in place, so we can attach icons
        // and behaviors to the items.
        $tree[$key]['link']['localized_options']['attributes'] = array(
          'id' => 'toolbar-link-' . str_replace(array('/', '<', '>'), array('-', '', ''), $item['link']['link_path']),
          'class' => array(
            'icon',
            'icon-' . strtolower(str_replace(' ', '-', $item['link']['link_title'])),
          ),
        );
      }
    }
    
    /**
     * Returns the rendered subtree of each top-level toolbar link.
     */
    function toolbar_get_rendered_subtrees() {
      $subtrees = array();
      $tree = toolbar_get_menu_tree();
      foreach ($tree as $tree_item) {
        $item = $tree_item['link'];
        if (!$item['hidden'] && $item['access']) {
          if ($item['has_children']) {
            $query = db_select('menu_links');
            $query->addField('menu_links', 'mlid');
            $query->condition('has_children', 1);
            for ($i=1; $i <= $item['depth']; $i++) {
              $query->condition('p' . $i, $item['p' . $i]);
            }
            $parents = $query->execute()->fetchCol();
            $subtree = menu_build_tree($item['menu_name'], array('expanded' => $parents, 'min_depth' => $item['depth']+1));
            toolbar_menu_navigation_links($subtree);
            $subtree = menu_tree_output($subtree);
            $subtree = drupal_render($subtree);
          }
          else {
            $subtree = '';
          }
    
          $id = str_replace(array('/', '<', '>'), array('-', '', ''), $item['href']);
          $subtrees[$id] = $subtree;
        }
      }
      return $subtrees;
    }
    
    /**
     * Checks whether an item is in the active trail.
     *
     * Useful when using a menu generated by menu_tree_all_data() which does
     * not set the 'in_active_trail' flag on items.
     *
     * @return
     *   TRUE when path is in the active trail, FALSE if not.
     *
     * @todo
     *   Look at migrating to a menu system level function.
     */
    function toolbar_in_active_trail($path) {
      $active_paths = &drupal_static(__FUNCTION__);
    
      // Gather active paths.
      if (!isset($active_paths)) {
        $active_paths = array();
        $trail = menu_get_active_trail();
        foreach ($trail as $item) {
          if (!empty($item['href'])) {
            $active_paths[] = $item['href'];
          }
        }
      }
      return in_array($path, $active_paths);
    }
    
    /**
     * Implements hook_library_info().
     */
    function toolbar_library_info() {
      $libraries['toolbar'] = array(
        'title' => 'Toolbar',
        'version' => VERSION,
        'js' => array(
          drupal_get_path('module', 'toolbar') . '/js/toolbar.js' => array(),
        ),
        'css' => array(
          drupal_get_path('module', 'toolbar') . '/css/toolbar.base.css',
          drupal_get_path('module', 'toolbar') . '/css/toolbar.theme.css',
          drupal_get_path('module', 'toolbar') . '/css/toolbar.icons.css',
        ),
        'dependencies' => array(
          array('system', 'jquery'),
          array('system', 'drupal'),
          array('system', 'drupalSettings'),
          array('system', 'matchmedia'),
          array('system', 'jquery.once'),
          array('system', 'drupal.debounce'),
          array('system', 'drupal.displace'),
          array('toolbar', 'toolbar.menu'),
        ),
      );
    
      $libraries['toolbar.menu'] = array(
        'title' => 'Toolbar nested accordion menus.',
        'version' => VERSION,
        'js' => array(
          drupal_get_path('module', 'toolbar') . '/js/toolbar.menu.js' => array(),
        ),
        'css' => array(
          drupal_get_path('module', 'toolbar') . '/css/toolbar.menu.css',
        ),
        'dependencies' => array(
          array('system', 'jquery'),
          array('system', 'drupal'),
          array('system', 'jquery.once'),
        ),
      );
    
      return $libraries;
    }
    
    /**
     * Returns the hash of the per-user rendered toolbar subtrees.
     */
    function _toolbar_get_subtree_hash() {
      global $user;
      $cid = $user->uid . ':' . language(LANGUAGE_TYPE_INTERFACE)->langcode;
      if ($cache = cache('toolbar')->get($cid)) {
        $hash = $cache->data;
      }
      else {
        $subtrees = toolbar_get_rendered_subtrees();
        $hash = drupal_hash_base64(serialize($subtrees));
        cache('toolbar')->set($cid, $hash);
      }
      return $hash;
    }