summaryrefslogtreecommitdiffstats
path: root/core/modules/toolbar/toolbar.module
blob: 5151966c1f92569f672a88e9d62b806b78a513f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
<?php

/**
 * @file
 * Administration toolbar for quick access to top level administration items.
 */

/**
 * 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/handbook/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 links 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 using the show/hide shortcuts link at the end of the toolbar.', 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' => 'toolbar',
    'template' => 'toolbar',
    'path' => drupal_get_path('module', 'toolbar'),
  );
  $items['toolbar_toggle'] = array(
    'variables' => array(
      'collapsed' => NULL,
      'attributes' => array(),
    ),
  );
  return $items;
}

/**
 * Implements hook_menu().
 */
function toolbar_menu() {
  $items['toolbar/toggle'] = array(
    'title' => 'Toggle drawer visibility',
    'type' => MENU_CALLBACK,
    'page callback' => 'toolbar_toggle_page',
    'access arguments' => array('access toolbar'),
  );
  return $items;
}

/**
 * Page callback: Toggles the visibility of the toolbar drawer.
 *
 * Path: toolbar/toggle
 *
 * @see toolbar_menu().
 */
function toolbar_toggle_page() {
  global $base_path;
  // Toggle the value in the cookie.
  setcookie('Drupal.toolbar.collapsed', !_toolbar_is_collapsed(), NULL, $base_path);
  // Redirect the user from where he used the toggle element.
  drupal_goto();
}

/**
 * Formats an element used to toggle the toolbar drawer's visibility.
 *
 * @param $variables
 *   An associative array containing:
 *   - collapsed: A boolean value representing the toolbar drawer's visibility.
 *   - attributes: An associative array of HTML attributes.
 *
 * @return
 *   An HTML string representing the element for toggling.
 *
 * @ingroup themable
 */
function theme_toolbar_toggle($variables) {
  if ($variables['collapsed']) {
    $toggle_text = t('Show shortcuts');
  }
  else {
    $toggle_text = t('Hide shortcuts');
    $variables['attributes']['class'][] = 'toggle-active';
  }
  return l($toggle_text, 'toolbar/toggle', array('query' => drupal_get_destination(), 'attributes' => array('title' => $toggle_text) + $variables['attributes']));
}

/**
 * Determines the current state of the toolbar drawer's visibility.
 *
 * @return
 *   TRUE when drawer is collapsed, FALSE when it is expanded.
 */
function _toolbar_is_collapsed() {
  // PHP converts dots into underscores in cookie names to avoid problems with
  // its parser, so we use a converted cookie name.
  return isset($_COOKIE['Drupal_toolbar_collapsed']) ? $_COOKIE['Drupal_toolbar_collapsed'] : 0;
}

/**
 * Implements hook_page_build().
 *
 * Add admin toolbar to the page_top region automatically.
 */
function toolbar_page_build(&$page) {
  $page['page_top']['toolbar'] = array(
    '#pre_render' => array('toolbar_pre_render'),
    '#access' => user_access('access toolbar'),
    'toolbar_drawer' => array(),
  );
}

/**
 * Provides pre_render function for the toolbar.
 *
 * 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.
 *
 * @see toolbar_page_build().
 */
function toolbar_pre_render($toolbar) {
  $toolbar = array_merge($toolbar, toolbar_view());
  return $toolbar;
}

/**
 * Implements hook_preprocess_html().
 *
 * Add some page classes, so global page theming can adjust to the toolbar.
 */
function toolbar_preprocess_html(&$vars) {
  if (isset($vars['page']['page_top']['toolbar']) && user_access('access toolbar')) {
    $vars['classes_array'][] = 'toolbar';
    if (!_toolbar_is_collapsed()) {
      $vars['classes_array'][] = 'toolbar-drawer';
    }
  }
}

/**
 * Implements hook_preprocess_toolbar().
 *
 * Adding the 'overlay-displace-top' class to the toolbar pushes the overlay
 * down, so it appears below the toolbar.
 */
function toolbar_preprocess_toolbar(&$variables) {
  $variables['classes_array'][] = "overlay-displace-top";
}

/**
 * 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';
  }
}

/**
 * Builds the admin menu as a structured array ready for drupal_render().
 *
 * @return
 *   Array of links and settings relating to the admin menu.
 */
function toolbar_view() {
  global $user;

  $module_path = drupal_get_path('module', 'toolbar');
  $build = array(
    '#theme' => 'toolbar',
    '#attached'=> array(
      'js' => array(
        $module_path . '/toolbar.js',
        array(
          'data' => array('tableHeaderOffset' => 'Drupal.toolbar.height'),
          'type' => 'setting'
        ),
      ),
      'css' => array(
        $module_path . '/toolbar.css',
      ),
      'library' => array(array('system', 'jquery.cookie')),
    ),
  );

  // Retrieve the admin menu from the database.
  $links = toolbar_menu_navigation_links(toolbar_get_menu_tree());
  $build['toolbar_menu'] = array(
    '#theme' => 'links__toolbar_menu',
    '#links' => $links,
    '#attributes' => array('id' => 'toolbar-menu'),
    '#heading' => array('text' => t('Administrative toolbar'), 'level' => 'h2', 'class' => 'element-invisible'),
  );

  // Add logout & user account links or login link.
  if ($user->uid) {
    $links = array(
      'account' => array(
        'title' => t('Hello <strong>@username</strong>', array('@username' => format_username($user))),
        'href' => 'user',
        'html' => TRUE,
        'attributes' => array('title' => t('User account')),
      ),
      'logout' => array(
        'title' => t('Log out'),
        'href' => 'user/logout',
      ),
    );
  }
  else {
     $links = array(
      'login' => array(
        'title' => t('Log in'),
        'href' => 'user',
      ),
    );
  }
  $build['toolbar_user'] = array(
    '#theme' => 'links__toolbar_user',
    '#links' => $links,
    '#attributes' => array('id' => 'toolbar-user'),
  );

  // Add a "home" link.
  $link = array(
    'home' => array(
      'title' => '<span class="home-link">Home</span>',
      'href' => '<front>',
      'html' => TRUE,
      'attributes' => array('title' => t('Home')),
    ),
  );
  $build['toolbar_home'] = array(
    '#theme' => 'links',
    '#links' => $link,
    '#attributes' => array('id' => 'toolbar-home'),
  );

  // Add an anchor to be able to toggle the visibility of the drawer.
  $build['toolbar_toggle'] = array(
    '#theme' => 'toolbar_toggle',
    '#collapsed' => _toolbar_is_collapsed(),
    '#attributes' => array('class' => array('toggle')),
  );

  // Prepare the drawer links CSS classes.
  $toolbar_drawer_classes = array(
    'toolbar-drawer',
    'clearfix',
  );
  if (_toolbar_is_collapsed()) {
    $toolbar_drawer_classes[] = 'collapsed';
  }
  $build['toolbar_drawer']['#type'] = 'container';
  $build['toolbar_drawer']['#attributes']['class'] = $toolbar_drawer_classes;

  return $build;
}

/**
 * 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();
  $admin_link = db_query('SELECT * FROM {menu_links} WHERE menu_name = :menu_name AND module = :module AND link_path = :path', array(':menu_name' => 'management', ':module' => 'system', ':path' => 'admin'))->fetchAssoc();
  if ($admin_link) {
    $tree = menu_build_tree('management', 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) {
  $links = array();
  foreach ($tree as $item) {
    if (!$item['link']['hidden'] && $item['link']['access']) {
      // Make sure we have a path specific ID in place, so we can attach icons
      // and behaviors to the items.
      $id = str_replace(array('/', '<', '>'), array('-', '', ''), $item['link']['href']);

      $link = $item['link']['localized_options'];
      $link['href'] = $item['link']['href'];
      // Add icon placeholder.
      $link['title'] = '<span class="icon"></span>' . check_plain($item['link']['title']);
      // Add admin link ID.
      $link['attributes'] = array('id' => 'toolbar-link-' . $id);
      if (!empty($item['link']['description'])) {
        $link['title'] .= ' <span class="element-invisible">(' . $item['link']['description'] . ')</span>';
        $link['attributes']['title'] = $item['link']['description'];
      }
      $link['html'] = TRUE;

      $class = ' path-' . $id;
      if (toolbar_in_active_trail($item['link']['href'])) {
        $class .= ' active-trail';
      }
      $links['menu-' . $item['link']['mlid'] . $class] = $link;
    }
  }
  return $links;
}

/**
 * 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);
}