Index: includes/menu.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/menu.inc,v retrieving revision 1.352 diff -u -p -r1.352 menu.inc --- includes/menu.inc 11 Oct 2009 19:39:30 -0000 1.352 +++ includes/menu.inc 13 Oct 2009 06:03:28 -0000 @@ -2228,6 +2228,24 @@ function _menu_navigation_links_rebuild( } /** + * Deletes all links for a menu. + * + * @param $menu_name + * The name of the menu whose links will be deleted. + */ +function menu_delete_links($menu_name) { + $links = db_query("SELECT * FROM {menu_links} WHERE menu_name = :menu_name", array(':menu_name' => $menu_name)); + foreach ($links as $link) { + // To speed up the deletion process, we reset some link properties that + // would trigger re-parenting logic in _menu_delete_item() and + // _menu_update_parental_status(). + $link['has_children'] = FALSE; + $link['plid'] = 0; + _menu_delete_item($link); + } +} + +/** * Delete one or several menu links. * * @param $mlid Index: modules/shortcut.admin.inc =================================================================== RCS file: modules/shortcut.admin.inc diff -N modules/shortcut.admin.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/shortcut.admin.inc 13 Oct 2009 06:03:28 -0000 @@ -0,0 +1,76 @@ +roles)) { + return variable_get('mymodule_admin_shortcut_default_set_name'); + } +} + +/** + * @} End of "addtogroup hooks". + */ Index: modules/shortcut.info =================================================================== RCS file: modules/shortcut.info diff -N modules/shortcut.info --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/shortcut.info 13 Oct 2009 06:03:28 -0000 @@ -0,0 +1,9 @@ +; $Id$ +name = Shortcut +description = Allows users to manage customizable lists of shortcut links. +package = Core +version = VERSION +core = 7.x +files[] = shortcut.module +files[] = shortcut.admin.inc +files[] = shortcut.install Index: modules/shortcut.install =================================================================== RCS file: modules/shortcut.install diff -N modules/shortcut.install --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/shortcut.install 13 Oct 2009 06:03:28 -0000 @@ -0,0 +1,104 @@ +title = $t('Default'); + $shortcut_set->links = array( + array( + 'link_path' => 'node/add', + 'link_title' => $t('Add content'), + 'weight' => -20, + ), + array( + 'link_path' => 'admin/content', + 'link_title' => $t('Find content'), + 'weight' => -19, + ), + array( + 'link_path' => 'admin', + 'link_title' => $t('Dashboard'), + 'weight' => -18, + ), + ); + shortcut_set_save($shortcut_set); +} + +/** + * Implement hook_uninstall(). + */ +function shortcut_uninstall() { + // Delete the menu links associated with each shortcut set. + foreach (shortcut_sets() as $shortcut_set) { + menu_delete_links($shortcut_set->set_name); + } +} + +/** + * Implement hook_schema(). + */ +function shortcut_schema() { + $schema['shortcut_set'] = array( + 'description' => 'Stores information about sets of shortcuts links.', + 'fields' => array( + 'set_name' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + 'description' => "Primary Key: The {menu_links}.menu_name under which the set's links are stored.", + ), + 'title' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The title of the set.', + ), + ), + 'primary key' => array('set_name'), + 'foreign keys' => array( + 'set_name' => array('menu_links' => 'menu_name'), + ), + ); + + $schema['shortcut_set_users'] = array( + 'description' => 'Maps users to shortcut sets.', + 'fields' => array( + 'uid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + 'description' => 'The {users}.uid for this set.', + ), + 'set_name' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + 'description' => "The {shortcut_set}.set_name that will be displayed for this user.", + ), + ), + 'primary key' => array('uid'), + 'indexes' => array( + 'set_name' => array('set_name'), + ), + 'foreign keys' => array( + 'uid' => array('users' => 'uid'), + 'set_name' => array('shortcut_set' => 'set_name'), + ), + ); + + return $schema; +} Index: modules/shortcut.module =================================================================== RCS file: modules/shortcut.module diff -N modules/shortcut.module --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/shortcut.module 13 Oct 2009 06:03:28 -0000 @@ -0,0 +1,312 @@ + array( + 'title' => t('Administer shortcuts'), + 'description' => t('Manage shortcuts and shortcut sets regardless of which user they are assigned to.'), + ), + 'customize shortcut links' => array( + 'title' => t('Customize shortcut links'), + 'description' => t("Edit, add and delete the links in the user's currently displayed shortcut set."), + ), + '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_switch_set'), + 'access arguments' => array('administer shortcuts'), + ); + $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_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_edit', 4), + 'access callback' => 'shortcut_set_access', + 'access arguments' => array(4), + 'type' => MENU_LOCAL_ACTION, + 'file' => 'shortcut.admin.inc', + ); + $items['admin/config/system/shortcut/%shortcut_set/link/%menu_link'] = array( + 'title' => 'Edit shortcut', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('shortcut_link_edit', 4, 6), + 'access callback' => 'shortcut_set_access', + 'access arguments' => array(4), + 'type' => MENU_CALLBACK, + 'file' => 'toolbar.admin.inc', + ); + $items['admin/config/system/shortcut/%shorcut_set/link/%menu_link/delete'] = array( + 'title' => 'Delete shortcut', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('shortcut_link_delete', 6), + 'access callback' => 'shortcut_set_access', + 'access arguments' => array(4), + 'type' => MENU_CALLBACK, + 'file' => 'toolbar.admin.inc', + ); + $items['user/%user/shortcuts'] = array( + 'title' => 'Shortcuts', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('shortcut_switch_set', 1), + 'access callback' => 'shortcut_switch_access', + 'access arguments' => array(1), + 'type' => MENU_LOCAL_TASK, + ); + return $items; +} + +/** + * Access callback for editing a shortcut set. + */ +function shortcut_set_access($shortcut_set) { + // Sufficiently-privileged users can edit their currently displayed shortcut + // set, but not other sets. Shortcut administrators can edit any set. + return user_access('administer shortcuts') || (user_access('customize shortcut links') && ($current_set = shortcut_current_displayed_set()) && $current_set->set_name == $shortcut_set->set_name); +} + +/** + * Access callback for switching the shortcut set assigned to a user account. + */ +function shortcut_switch_access($account) { + 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') && $user->uid == $account->uid); +} + +/** + * Loads the data for a shortcut set. + * + * @param $set_name + * The name of the shortcut set to load. + * @return + * An object containing the basic data about the set (name and title), or + * FALSE if the set does not exist. + */ +function shortcut_set_load($set_name) { + return db_query("SELECT * FROM {shortcut_set} WHERE set_name = :set_name", array(':set_name' => $set_name))->fetchObject(); +} + +/** + * Saves a shortcut set. + * + * @param $shortcut_set + * A shortcut set 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 object. + * - '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. + * @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. + */ +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_get_unique_set_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; +} + +/** + * Returns an array of all shortcut set objects, keyed by the set name. + */ +function shortcut_sets() { + return db_query("SELECT * FROM {shortcut_set}")->fetchAllAssoc('set_name'); +} + +/** + * 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. + $shortcut_set = db_select('shortcut_set', 's') + ->fields('s') + ->join('shortcut_set_users', 'u', 's.set_name = u.set_name') + ->condition('u.uid', $account->uid) + ->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 take the first valid result we get. If we don't find one, + // fall back on the site-wide default. + $shortcut_set_names = array_merge(module_invoke_all('shortcut_default_set_name', $account), variable_get('shortcut_default_set_name', shortcut_set_name())); + foreach ($shortcut_set_names as $name) { + if ($shortcut_set = shortcut_set_load($name)) { + break; + } + } + return $shortcut_set; +} + +/** + * 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 + * (optional) A number representing the shortcut set whose name should be + * retrieved. Defaults to one (i.e.,the first shortcut set). + * @return + * A string representing the expected shortcut name. + */ +function shortcut_set_name($number = 1) { + return "shortcut-set-$number"; +} + +/** + * Returns a unique, machine-readable shortcut set name. + */ +function shortcut_get_unique_set_name() { + // Shortcut sets are numbered sequentially, so we keep trying until we find + // one that is available. + $number = 1; + do { + $name = shortcut_set_name($number); + $number++; + } while ($shortcut_set = shortcut_set_load($name)); + return $name; +} + +/** + * 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_links($shortcut_set = NULL) { + if (!isset($shortcut_set)) { + $shortcut_set = shortcut_current_displayed_set(); + } + return menu_tree($shortcut_set->set_name); +} + +/** + * Menu callback; Build the form for switching shortcut sets. + * + * @param $account + * (optional) The user account whose shortcuts will be switched. Defaults to + * the current logged-in user. + * @return + * An array representing the form definition. + * + * @ingroup forms + * @see shortcut_switch_set_submit() + */ +function shortcut_switch_set($form, &$form_state, $account = NULL) { + global $user; + if (!isset($account)) { + $account = $user; + } + $sets = shortcut_sets(); + // TODO: Copy code here. +} + +/** + * Submit handler for the shorcut set switcher form. + */ +function shortcut_switch_set_submit($form, &$form_state) { + // TODO: Copy code here. +} Index: modules/menu/menu.module =================================================================== RCS file: /cvs/drupal/drupal/modules/menu/menu.module,v retrieving revision 1.209 diff -u -p -r1.209 menu.module --- modules/menu/menu.module 13 Oct 2009 01:24:07 -0000 1.209 +++ modules/menu/menu.module 13 Oct 2009 06:03:28 -0000 @@ -271,21 +271,13 @@ function menu_save($menu) { * * @see menu_load() * - * _menu_delete_item() will take care of clearing the page cache. Other modules + * menu_delete_links() will take care of clearing the page cache. Other modules * should take care of their menu-related data by implementing * hook_menu_delete(). */ function menu_delete($menu) { // Delete all links from the menu. - $links = db_query("SELECT * FROM {menu_links} WHERE menu_name = :menu_name", array(':menu_name' => $menu['menu_name'])); - foreach ($links as $link) { - // To speed up the deletion process, we reset some link properties that - // would trigger re-parenting logic in _menu_delete_item() and - // _menu_update_parental_status(). - $link['has_children'] = FALSE; - $link['plid'] = 0; - _menu_delete_item($link); - } + menu_delete_links($menu_name['menu_name']); // Delete the custom menu. db_delete('menu_custom') Index: modules/toolbar/toolbar.info =================================================================== RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.info,v retrieving revision 1.2 diff -u -p -r1.2 toolbar.info --- modules/toolbar/toolbar.info 6 Jul 2009 13:54:21 -0000 1.2 +++ modules/toolbar/toolbar.info 13 Oct 2009 06:03:28 -0000 @@ -1,9 +1,9 @@ ; $Id: toolbar.info,v 1.2 2009/07/06 13:54:21 dries Exp $ name = Toolbar -description = Toolbar exposing the top level administration menu items +description = Toolbar exposing the top level administration menu items. core = 7.x package = Core version = VERSION files[] = toolbar.install files[] = toolbar.module -dependencies[] = menu +dependencies[] = shortcut Index: modules/toolbar/toolbar.install =================================================================== RCS file: modules/toolbar/toolbar.install diff -N modules/toolbar/toolbar.install --- modules/toolbar/toolbar.install 9 Oct 2009 08:02:25 -0000 1.5 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,56 +0,0 @@ - 'admin_shortcuts', - 'title' => $t('Administration shortcuts'), - 'description' => $t('The Administration shortcuts menu contains commonly used links for administrative tasks.'), - ); - menu_save($menu); - - // Add starter convenience shortcuts. - menu_rebuild(); - $items = array( - 'node/add' => 'Add content', - 'admin/content' => 'Find content', - 'admin' => 'Dashboard', - ); - $weight = -20; - foreach ($items as $path => $title) { - $link = array( - 'mlid' => 0, - 'link_title' => $title, - 'link_path' => $path, - 'router_path' => $path, - 'menu_name' => 'admin_shortcuts', - 'module' => 'menu', - 'weight' => $weight, - ); - - // Check for an existing menu item before attempting to create a new one. - $menu_link = db_query("SELECT mlid FROM {menu_links} WHERE link_path = :path AND menu_name = :menu_name", array( - ':path' => $link['link_path'], - ':menu_name' => $link['menu_name'] - )) - ->fetchField(); - if (!$menu_link) { - menu_link_save($link); - } - - // Increment weight so items can be displayed in desired order. - $weight++; - } -} Index: modules/toolbar/toolbar.module =================================================================== RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.module,v retrieving revision 1.13 diff -u -p -r1.13 toolbar.module --- modules/toolbar/toolbar.module 15 Sep 2009 20:50:48 -0000 1.13 +++ modules/toolbar/toolbar.module 13 Oct 2009 06:03:28 -0000 @@ -102,11 +102,10 @@ function toolbar_build() { ); // Add convenience shortcut links. - $shortcuts = menu_tree_all_data('admin_shortcuts'); - $shortcuts = toolbar_menu_navigation_links($shortcuts); + $shortcuts = shortcut_links(); $build['toolbar_shortcuts'] = array( '#theme' => 'links', - '#links' => $shortcuts, + '#links' => toolbar_menu_navigation_links($shortcuts), '#attributes' => array('id' => 'toolbar-shortcuts'), ); Index: profiles/default/default.info =================================================================== RCS file: /cvs/drupal/drupal/profiles/default/default.info,v retrieving revision 1.4 diff -u -p -r1.4 default.info --- profiles/default/default.info 30 Aug 2009 06:02:08 -0000 1.4 +++ profiles/default/default.info 13 Oct 2009 06:03:28 -0000 @@ -13,6 +13,7 @@ dependencies[] = path dependencies[] = taxonomy dependencies[] = dblog dependencies[] = search +dependencies[] = shortcut dependencies[] = toolbar dependencies[] = field_ui dependencies[] = file