558 lines
18 KiB
Plaintext
558 lines
18 KiB
Plaintext
<?php
|
|
// $Id$
|
|
|
|
/**
|
|
* @file
|
|
* Allows users to manage customizable lists of shortcut links.
|
|
*/
|
|
|
|
/**
|
|
* The name of the default shortcut set.
|
|
*
|
|
* This set will be displayed to any user that does not have another set
|
|
* assigned.
|
|
*/
|
|
define('SHORTCUT_DEFAULT_SET_NAME', 'shortcut-set-1');
|
|
|
|
/**
|
|
* Implement hook_permission().
|
|
*/
|
|
function shortcut_permission() {
|
|
return array(
|
|
'administer shortcuts' => array(
|
|
'title' => t('Administer shortcuts'),
|
|
'description' => t('Manage all shortcut and shortcut sets.'),
|
|
),
|
|
'customize shortcut links' => array(
|
|
'title' => t('Customize shortcut links'),
|
|
'description' => t("Edit, add and delete the links in shortcut set the user is using."),
|
|
),
|
|
'switch shortcut sets' => array(
|
|
'title' => t('Choose a different shortcut set'),
|
|
'description' => t('Choose which set of shortcuts are displayed for the user.')
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Implement hook_menu().
|
|
*/
|
|
function shortcut_menu() {
|
|
$items['admin/config/system/shortcut'] = array(
|
|
'title' => 'Shortcuts',
|
|
'description' => 'List the available shortcut sets and switch between them.',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('shortcut_set_switch'),
|
|
'access arguments' => array('administer shortcuts'),
|
|
'file' => 'shortcut.admin.inc',
|
|
);
|
|
$items['admin/config/system/shortcut/%shortcut_set'] = array(
|
|
'title' => 'Customize shortcuts',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('shortcut_set_customize', 4),
|
|
'access callback' => 'shortcut_set_edit_access',
|
|
'access arguments' => array(4),
|
|
'type' => MENU_CALLBACK,
|
|
'file' => 'shortcut.admin.inc',
|
|
);
|
|
$items['admin/config/system/shortcut/%shortcut_set/add-link'] = array(
|
|
'title' => 'Add shortcut',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('shortcut_link_add', 4),
|
|
'access callback' => 'shortcut_set_edit_access',
|
|
'access arguments' => array(4),
|
|
'type' => MENU_LOCAL_ACTION,
|
|
'file' => 'shortcut.admin.inc',
|
|
);
|
|
$items['admin/config/system/shortcut/%shortcut_set/add-link-inline'] = array(
|
|
'title' => 'Add shortcut',
|
|
'page callback' => 'shortcut_link_add_inline',
|
|
'page arguments' => array(4),
|
|
'access callback' => 'shortcut_set_edit_access',
|
|
'access arguments' => array(4),
|
|
'type' => MENU_CALLBACK,
|
|
'file' => 'shortcut.admin.inc',
|
|
);
|
|
$items['admin/config/system/shortcut/link/%menu_link'] = array(
|
|
'title' => 'Edit shortcut',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('shortcut_link_edit', 5),
|
|
'access callback' => 'shortcut_link_access',
|
|
'access arguments' => array(5),
|
|
'type' => MENU_CALLBACK,
|
|
'file' => 'shortcut.admin.inc',
|
|
);
|
|
$items['admin/config/system/shortcut/link/%menu_link/delete'] = array(
|
|
'title' => 'Delete shortcut',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('shortcut_link_delete', 5),
|
|
'access callback' => 'shortcut_link_access',
|
|
'access arguments' => array(5),
|
|
'type' => MENU_CALLBACK,
|
|
'file' => 'shortcut.admin.inc',
|
|
);
|
|
$items['user/%user/shortcuts'] = array(
|
|
'title' => 'Shortcuts',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('shortcut_set_switch', 1),
|
|
'access callback' => 'shortcut_set_switch_access',
|
|
'access arguments' => array(1),
|
|
'type' => MENU_LOCAL_TASK,
|
|
'file' => 'shortcut.admin.inc',
|
|
);
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* Implement hook_theme().
|
|
*/
|
|
function shortcut_theme() {
|
|
return array(
|
|
'shortcut_set_switch' => array(
|
|
'render element' => 'form',
|
|
'file' => 'shortcut.admin.inc',
|
|
),
|
|
'shortcut_set_customize' => array(
|
|
'render element' => 'form',
|
|
'file' => 'shortcut.admin.inc',
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Implement hook_block_info().
|
|
*/
|
|
function shortcut_block_info() {
|
|
$blocks['shortcuts']['info'] = t('Shortcuts');
|
|
// Shortcut blocks can't be cached because each menu item can have a custom
|
|
// access callback. menu.inc manages its own caching.
|
|
$blocks['shortcuts']['cache'] = DRUPAL_NO_CACHE;
|
|
return $blocks;
|
|
}
|
|
|
|
/**
|
|
* Implement hook_block_view().
|
|
*/
|
|
function shortcut_block_view($delta = '') {
|
|
if ($delta == 'shortcuts') {
|
|
$shortcut_set = shortcut_current_displayed_set();
|
|
$data['subject'] = t('@shortcut_set shortcuts', array('@shortcut_set' => $shortcut_set->title));
|
|
$data['content'] = shortcut_renderable_links($shortcut_set);
|
|
return $data;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Access callback for editing a shortcut set.
|
|
*
|
|
* @param $shortcut_set
|
|
* (optional) The shortcut set to be edited. If not set, the current
|
|
* displayed shortcut set will be assumed.
|
|
* @return
|
|
* TRUE if the current user has access to edit the shortcut set, FALSE
|
|
* otherwise.
|
|
*/
|
|
function shortcut_set_edit_access($shortcut_set = NULL) {
|
|
// Sufficiently-privileged users can edit their currently displayed shortcut
|
|
// set, but not other sets. Shortcut administrators can edit any set.
|
|
if (user_access('administer shortcuts')) {
|
|
return TRUE;
|
|
}
|
|
if (user_access('customize shortcut links')) {
|
|
return !isset($shortcut_set) || $shortcut_set == shortcut_current_displayed_set();
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* Access callback for switching the shortcut set assigned to a user account.
|
|
*
|
|
* @param $account
|
|
* (optional) The user account whose shortcuts will be switched. If not set,
|
|
* the account of the current logged-in user will be assumed.
|
|
* @return
|
|
* TRUE if the current user has access to switch the shortcut set of the
|
|
* provided account, FALSE otherwise.
|
|
*/
|
|
function shortcut_set_switch_access($account = NULL) {
|
|
global $user;
|
|
// Sufficiently-privileged users can switch their own shortcut sets, but not
|
|
// those of other users. Shortcut administrators can switch any user's set.
|
|
return user_access('administer shortcuts') || (user_access('switch shortcut sets') && (!isset($account) || $user->uid == $account->uid));
|
|
}
|
|
|
|
/**
|
|
* Access callback for editing a link in a shortcut set.
|
|
*/
|
|
function shortcut_link_access($menu_link) {
|
|
// The link must belong to a shortcut set that the current user has access
|
|
// to edit.
|
|
if ($shortcut_set = shortcut_set_load($menu_link['menu_name'])) {
|
|
return shortcut_set_edit_access($shortcut_set);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* Loads the data for a shortcut set.
|
|
*
|
|
* @param $set_name
|
|
* The name of the shortcut set to load.
|
|
* @return
|
|
* If the shortcut set exists, an object of type stdClass containing the
|
|
* following properties:
|
|
* - 'set_name': The internal name of the shortcut set.
|
|
* - 'title': The title of the shortcut set.
|
|
* - 'links': An array of links associated with this shortcut set.
|
|
* If the shortcut set does not exist, the function returns FALSE.
|
|
*/
|
|
function shortcut_set_load($set_name) {
|
|
$set = db_select('shortcut_set', 'ss')
|
|
->fields('ss')
|
|
->condition('set_name', $set_name)
|
|
->execute()
|
|
->fetchObject();
|
|
if (!$set) {
|
|
return FALSE;
|
|
}
|
|
$set->links = menu_load_links($set_name);
|
|
return $set;
|
|
}
|
|
|
|
/**
|
|
* Saves a shortcut set.
|
|
*
|
|
* @param $shortcut_set
|
|
* An object containing the following properties:
|
|
* - 'title': The title of the shortcut set.
|
|
* - 'set_name': (optional) The internal name of the shortcut set. If
|
|
* omitted, a new shortcut set will be created, and the 'set_name' property
|
|
* will be added to the passed-in array.
|
|
* - 'links': (optional) An array of menu links to save for the shortcut set.
|
|
* Each link is an array containing at least the following keys (which will
|
|
* be expanded to fill in other default values after the shortcut set is
|
|
* saved):
|
|
* - 'link_path': The Drupal path or external path that the link points to.
|
|
* - 'link_title': The title of the link.
|
|
* Any other keys accepted by menu_link_save() may also be provided.
|
|
* @return
|
|
* A constant which is either SAVED_NEW or SAVED_UPDATED depending on whether
|
|
* a new set was created or an existing one was updated.
|
|
*
|
|
* @see menu_link_save()
|
|
*/
|
|
function shortcut_set_save(&$shortcut_set) {
|
|
// First save the shortcut set itself.
|
|
if (isset($shortcut_set->set_name)) {
|
|
$return = drupal_write_record('shortcut_set', $shortcut_set, 'set_name');
|
|
}
|
|
else {
|
|
$shortcut_set->set_name = shortcut_set_get_unique_name();
|
|
$return = drupal_write_record('shortcut_set', $shortcut_set);
|
|
}
|
|
// If links were provided for the set, save them, replacing any that were
|
|
// there before.
|
|
if (isset($shortcut_set->links)) {
|
|
menu_delete_links($shortcut_set->set_name);
|
|
foreach ($shortcut_set->links as &$link) {
|
|
// Do not specifically associate these links with the shortcut module,
|
|
// since other modules may make them editable via the menu system.
|
|
// However, we do need to specify the correct menu name.
|
|
$link['menu_name'] = $shortcut_set->set_name;
|
|
menu_link_save($link);
|
|
}
|
|
// Make sure that we have a return value, since if the links were updated
|
|
// but the shortcut set was not, the call to drupal_write_record() above
|
|
// would not return an indication that anything had changed.
|
|
if (empty($return)) {
|
|
$return = SAVED_UPDATED;
|
|
}
|
|
}
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Deletes a shortcut set.
|
|
*
|
|
* Note that the default set cannot be deleted.
|
|
*
|
|
* @param $shortcut_set
|
|
* An object representing the shortcut set to delete.
|
|
* @return
|
|
* TRUE if the set was deleted, FALSE otherwise.
|
|
*/
|
|
function shortcut_set_delete($shortcut_set) {
|
|
// Make sure not to delete the default set.
|
|
$default_set = shortcut_default_set();
|
|
if ($shortcut_set->set_name == $default_set->set_name) {
|
|
return FALSE;
|
|
}
|
|
// First, delete any user assignments for this set, so that each of these
|
|
// users will go back to using whatever default set applies.
|
|
db_delete('shortcut_set_users')
|
|
->condition('set_name', $shortcut_set->set_name)
|
|
->execute();
|
|
// Next, delete the menu links for this set.
|
|
menu_delete_links($shortcut_set->set_name);
|
|
// Finally, delete the set itself.
|
|
$deleted = db_delete('shortcut_set')
|
|
->condition('set_name', $shortcut_set->set_name)
|
|
->execute();
|
|
return (bool) $deleted;
|
|
}
|
|
|
|
/**
|
|
* Reset the link weights in a shortcut set to match their current order.
|
|
*
|
|
* This function can be used, for example, when a new shortcut link is added to
|
|
* the set. If the link is added to the end of the array and this function is
|
|
* called, it will force that link to display at the end of the list.
|
|
*
|
|
* @param $shortcut_set
|
|
* An object representing a shortcut set. The link weights of the passed-in
|
|
* object will be reset as described above.
|
|
*/
|
|
function shortcut_set_reset_link_weights(&$shortcut_set) {
|
|
$weight = -50;
|
|
foreach ($shortcut_set->links as &$link) {
|
|
$link['weight'] = $weight;
|
|
$weight++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Assign a user to a particular shortcut set.
|
|
*
|
|
* @param $shortcut_set
|
|
* An object representing the shortcut set.
|
|
* @param $account
|
|
* A user account that will be assigned to use the set.
|
|
*/
|
|
function shortcut_set_assign_user($shortcut_set, $account) {
|
|
db_merge('shortcut_set_users')
|
|
->key(array('uid' => $account->uid))
|
|
->fields(array('set_name' => $shortcut_set->set_name))
|
|
->execute();
|
|
}
|
|
|
|
/**
|
|
* Unassign a user from any shortcut set they may have been assigned to.
|
|
*
|
|
* The user will go back to using whatever default set applies.
|
|
*
|
|
* @param $account
|
|
* A user account that will be removed from the shortcut set assignment.
|
|
* @return
|
|
* TRUE if the user was previously assigned to a shortcut set and has been
|
|
* successfully removed from it. FALSE if the user was already not assigned
|
|
* to any set.
|
|
*/
|
|
function shortcut_set_unassign_user($account) {
|
|
$deleted = db_delete('shortcut_set')
|
|
->condition('uid', $account->uid)
|
|
->execute();
|
|
return (bool) $deleted;
|
|
}
|
|
|
|
/**
|
|
* Returns the current displayed shortcut set for the provided user account.
|
|
*
|
|
* @param $account
|
|
* (optional) The user account whose shortcuts will be returned. Defaults to
|
|
* the current logged-in user.
|
|
* @return
|
|
* An object representing the shortcut set that should be displayed to the
|
|
* current user. If the user does not have an explicit shortcut set defined,
|
|
* the default set is returned.
|
|
*/
|
|
function shortcut_current_displayed_set($account = NULL) {
|
|
$shortcut_sets = &drupal_static(__FUNCTION__, array());
|
|
global $user;
|
|
if (!isset($account)) {
|
|
$account = $user;
|
|
}
|
|
// Try to return a shortcut set from the static cache.
|
|
if (isset($shortcut_sets[$account->uid])) {
|
|
return $shortcut_sets[$account->uid];
|
|
}
|
|
// If none was found, try to find a shortcut set that is explicitly assigned
|
|
// to this user.
|
|
$query = db_select('shortcut_set', 's');
|
|
$query->fields('s');
|
|
$query->join('shortcut_set_users', 'u', 's.set_name = u.set_name');
|
|
$query->condition('u.uid', $account->uid);
|
|
$shortcut_set = $query->execute()->fetchObject();
|
|
// Otherwise, use the default set.
|
|
if (!$shortcut_set) {
|
|
$shortcut_set = shortcut_default_set($account);
|
|
}
|
|
$shortcut_sets[$account->uid] = $shortcut_set;
|
|
return $shortcut_set;
|
|
}
|
|
|
|
/**
|
|
* Returns the default shortcut set for a given user account.
|
|
*
|
|
* @param $account
|
|
* (optional) The user account whose shortcuts will be returned. Defaults to
|
|
* the current logged-in user.
|
|
* @return
|
|
* An object representing the default shortcut set.
|
|
*/
|
|
function shortcut_default_set($account = NULL) {
|
|
global $user;
|
|
if (!isset($account)) {
|
|
$account = $user;
|
|
}
|
|
// Allow modules to return a default shortcut set name. Since we can only
|
|
// have one, we allow the last module which returns a valid result to take
|
|
// precedence. If no module returns a valid set, fall back on the site-wide
|
|
// default.
|
|
$shortcut_set_names = array_reverse(array_merge(array(SHORTCUT_DEFAULT_SET_NAME), module_invoke_all('shortcut_default_set', $account)));
|
|
foreach ($shortcut_set_names as $name) {
|
|
if ($shortcut_set = shortcut_set_load($name)) {
|
|
break;
|
|
}
|
|
}
|
|
return $shortcut_set;
|
|
}
|
|
|
|
/**
|
|
* Returns a unique, machine-readable shortcut set name.
|
|
*/
|
|
function shortcut_set_get_unique_name() {
|
|
// Shortcut sets are numbered sequentially, so we keep trying until we find
|
|
// one that is available. For better performance, we start with a number
|
|
// equal to one more than the current number of shortcut sets, so that if
|
|
// no shortcut sets have been deleted from the database, this will
|
|
// automatically give us the correct one.
|
|
$number = db_query("SELECT COUNT(*) FROM {shortcut_set}")->fetchField() + 1;
|
|
do {
|
|
$name = shortcut_set_name($number);
|
|
$number++;
|
|
} while ($shortcut_set = shortcut_set_load($name));
|
|
return $name;
|
|
}
|
|
|
|
/**
|
|
* Returns the name of a shortcut set, based on a provided number.
|
|
*
|
|
* All shortcut sets have names like "shortcut-set-N" so that they can be
|
|
* matched with a properly-namespaced entry in the {menu_links} table.
|
|
*
|
|
* @param $number
|
|
* A number representing the shortcut set whose name should be retrieved.
|
|
* @return
|
|
* A string representing the expected shortcut name.
|
|
*/
|
|
function shortcut_set_name($number) {
|
|
return "shortcut-set-$number";
|
|
}
|
|
|
|
/**
|
|
* Returns an array of all shortcut sets, keyed by the set name.
|
|
*
|
|
* @return
|
|
* An array of shortcut sets. Note that only the basic shortcut set
|
|
* properties (name and title) are returned by this function, not the list
|
|
* of menu links that belong to the set.
|
|
*/
|
|
function shortcut_sets() {
|
|
return db_select('shortcut_set', 'ss')
|
|
->fields('ss')
|
|
->execute()
|
|
->fetchAllAssoc('set_name');
|
|
}
|
|
|
|
/**
|
|
* Determines if a path corresponds to a valid shortcut link.
|
|
*
|
|
* @param $path
|
|
* The path to the link.
|
|
* @return
|
|
* TRUE if the shortcut link is valid, FALSE otherwise. Valid links are ones
|
|
* that correspond to actual paths on the site.
|
|
*
|
|
* @see menu_edit_item_validate()
|
|
*/
|
|
function shortcut_valid_link($path) {
|
|
// Do not use URL aliases.
|
|
$normal_path = drupal_get_normal_path($path);
|
|
if ($path != $normal_path) {
|
|
$path = $normal_path;
|
|
}
|
|
// Only accept links that correspond to valid paths on the site itself.
|
|
return !url_is_external($path) && menu_get_item($path);
|
|
}
|
|
|
|
/**
|
|
* Returns an array of shortcut links, suitable for rendering.
|
|
*
|
|
* @param $shortcut_set
|
|
* (optional) An object representing the set whose links will be displayed.
|
|
* If not provided, the user's current set will be displayed.
|
|
* @return
|
|
* An array of shortcut links, in the format returned by the menu system.
|
|
*
|
|
* @see menu_tree()
|
|
*/
|
|
function shortcut_renderable_links($shortcut_set = NULL) {
|
|
if (!isset($shortcut_set)) {
|
|
$shortcut_set = shortcut_current_displayed_set();
|
|
}
|
|
return menu_tree($shortcut_set->set_name);
|
|
}
|
|
|
|
/**
|
|
* Implement hook_page_build().
|
|
*/
|
|
function shortcut_page_build(&$page) {
|
|
if (shortcut_set_edit_access()) {
|
|
$link = $_GET['q'];
|
|
$query_parameters = drupal_get_query_parameters();
|
|
if (!empty($query_parameters)) {
|
|
$link .= '?' . drupal_http_build_query($query_parameters);
|
|
}
|
|
$query = array(
|
|
'link' => $link,
|
|
'name' => drupal_get_title(),
|
|
'token' => drupal_get_token('shortcut-add-link'),
|
|
);
|
|
$query += drupal_get_destination();
|
|
|
|
$shortcut_set = shortcut_current_displayed_set();
|
|
$link_text = shortcut_set_switch_access() ? t('Add to %shortcut_set shortcuts', array('%shortcut_set' => $shortcut_set->title)) : t('Add to shortcuts');
|
|
$page['add_to_shortcuts'] = array(
|
|
'#prefix' => '<div class="add-to-shortcuts">',
|
|
'#markup' => l('<span class="icon"></span><span class="text">' . $link_text . '</span>', 'admin/config/system/shortcut/' . $shortcut_set->set_name . '/add-link-inline', array('query' => $query, 'html' => TRUE)),
|
|
'#suffix' => '</div>',
|
|
);
|
|
}
|
|
|
|
$links = shortcut_renderable_links();
|
|
$links['#attached'] = array('css' => array(drupal_get_path('module', 'shortcut') . '/shortcut.css'));
|
|
$links['#prefix'] = '<div class="toolbar-shortcuts">';
|
|
$links['#suffix'] = '</div>';
|
|
$shortcut_set = shortcut_current_displayed_set();
|
|
$configure_link = NULL;
|
|
if (shortcut_set_edit_access($shortcut_set)) {
|
|
$configure_link = array('#markup' => l(t('edit shortcuts'), 'admin/config/system/shortcut/' . $shortcut_set->set_name, array('attributes' => array('id' => 'toolbar-customize'))));
|
|
}
|
|
|
|
$drawer = array(
|
|
'shortcuts' => $links,
|
|
'configure' => $configure_link,
|
|
);
|
|
|
|
$page['toolbar_drawer'] = $drawer;
|
|
}
|
|
|
|
/**
|
|
* Implement hook_preprocess_page().
|
|
*/
|
|
function shortcut_preprocess_page(&$variables) {
|
|
if (isset($variables['page']['add_to_shortcuts'])) {
|
|
$variables['add_to_shortcuts'] = drupal_render($variables['page']['add_to_shortcuts']);
|
|
}
|
|
}
|