From 7f82e1219f44e9511494a3631a0dd2c01d77eae1 Mon Sep 17 00:00:00 2001
From: Leighton Whiting
Date: Sun, 18 Nov 2012 12:01:58 -0700
Subject: [PATCH 1/2] Lots of cleanup
---
.../modules/project_browser/project_browser.module | 548 +++++++++++++++++++
.../project_browser/project_browser.pages.inc | 557 ++++++++++++++++++++
2 files changed, 1105 insertions(+), 0 deletions(-)
create mode 100644 core/modules/project_browser/project_browser.module
create mode 100644 core/modules/project_browser/project_browser.pages.inc
diff --git a/core/modules/project_browser/project_browser.module b/core/modules/project_browser/project_browser.module
new file mode 100644
index 0000000..e633fe5
--- /dev/null
+++ b/core/modules/project_browser/project_browser.module
@@ -0,0 +1,548 @@
+' . t("Provides a UI for users to browse for and install new modules and themes from
+ within their Drupal admin interface.") . '
';
+ break;
+ }
+ return $output;
+}
+
+/**
+ * Implements hook_perm().
+ */
+function project_browser_permission() {
+ return array(
+ 'use project browser' => array(
+ 'title' => t('Use Project Browser'),
+ 'description' => t('This allows the user to browse for and install new modules and themes using Project Browser.'),
+ 'restrict access' => TRUE,
+ )
+ );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function project_browser_menu() {
+ $items = array();
+ $items['admin/config/development/project_browser'] = array(
+ 'title' => 'Project Browser settings',
+ 'description' => 'Add new repositories and set other settings for Project Browser.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('project_browser_admin'),
+ 'access arguments' => array('access administration pages'),
+ 'file' => 'project_browser.admin.inc',
+ );
+
+ $items['admin/modules/project-browser'] = array(
+ 'title' => 'Project Browser',
+ 'description' => 'Browse and search for new modules',
+ 'page callback' => 'project_browser_page',
+ 'page arguments' => array('module'),
+ 'access arguments' => array('use project browser'),
+ 'file' => 'project_browser.pages.inc',
+ );
+
+ $items['admin/modules/project-browser/modules'] = array(
+ 'title' => 'Modules',
+ 'description' => 'Browse and search for new modules',
+ 'page callback' => 'project_browser_page',
+ 'page arguments' => array('module'),
+ 'access arguments' => array('use project browser'),
+ 'file' => 'project_browser.pages.inc',
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ );
+
+ $items['admin/modules/project-browser/themes'] = array(
+ 'title' => 'Themes',
+ 'description' => 'Browse and search for new themes',
+ 'page callback' => 'project_browser_page',
+ 'page arguments' => array('theme'),
+ 'access arguments' => array('use project browser'),
+ 'file' => 'project_browser.pages.inc',
+ 'type' => MENU_LOCAL_TASK,
+ );
+
+ $items['admin/modules/project-browser/install/%'] = array(
+ 'title' => 'Install',
+ 'page callback' => 'project_browser_installation_page',
+ 'page arguments' => array(4),
+ 'access arguments' => array('use project browser'),
+ 'type' => MENU_NORMAL_ITEM,
+ 'file' => 'project_browser.pages.inc',
+ );
+
+ $items['project-browser/%/install-queue/%/%'] = array(
+ 'page callback' => 'project_browser_install_queue_callback',
+ 'page arguments' => array(1, 3, 4),
+ 'access arguments' => array('use project browser'),
+ 'type' => MENU_CALLBACK,
+ );
+ return $items;
+}
+
+/**
+ * Page callback: Allows for adding to and removing from the install queue.
+ *
+ * This is invoked via AJAX most of the time.
+ *
+ * @param string $method
+ * The method used for this callback.
+ * @param string $op
+ * The operation to perform.
+ * @param string $project_name
+ * The short name of the project.
+ *
+ * @return array
+ * An array of elements that should be changed.
+ */
+function project_browser_install_queue_callback($method, $op, $project_name) {
+ module_load_include('inc', 'project_browser', 'project_browser');
+
+ switch ($op) {
+ case 'add':
+ $projects = project_browser_get_listed_projects();
+
+ if (isset($projects[$project_name])) {
+ $project = $projects[$project_name];
+ project_browser_install_queue_add($project);
+ }
+ else {
+ drupal_set_message(t('Error: The project was not found.'), 'error');
+ }
+ break;
+
+ case 'remove':
+ project_browser_install_queue_remove($project_name);
+ break;
+ }
+
+ switch ($method) {
+ case 'nojs':
+ // Redirect to the page it came from.
+ $redirect = (isset($_GET['destination'])) ? $_GET['destination'] : 'admin/modules/project-browser';
+
+ drupal_goto($redirect);
+ break;
+ case 'ajax':
+ $commands = array();
+
+ // Refresh the install queue.
+ $commands[] = ajax_command_replace('#project-browser-install-queue', project_browser_get_install_list());
+ // Refresh the add to queue link.
+ $commands[] = ajax_command_replace('#add-to-queue-link-' . $project_name, project_browser_add_remove_queue_link($project_name));
+
+ return array('#type' => 'ajax', '#commands' => $commands);
+ break;
+ }
+}
+
+/**
+ * Implements hook_menu_local_tasks_alter().
+ */
+function project_browser_menu_local_tasks_alter(&$data, $router_item, $root_path) {
+ switch ($root_path) {
+ // This is used to put the 'Project Browser' action on the 'Modules' page.
+ case 'admin/modules':
+ // Unset the install theme page.
+ foreach ($data['actions']['output'] as $num => $item) {
+ if ($item['#link']['path'] == 'admin/modules/install') {
+ unset($data['actions']['output'][$num]);
+ }
+ }
+ $item = menu_get_item('admin/modules/project-browser/modules');
+ if ($item['access']) {
+ $item['title'] = t('Install new modules');
+ $data['actions']['output'][] = array(
+ '#theme' => 'menu_local_action',
+ '#link' => $item,
+ );
+ }
+ break;
+ // This is used to include the old 'Install a module' link
+ case 'admin/modules/project-browser':
+ case 'admin/modules/project-browser/modules':
+ case 'admin/modules/project-browser/themes':
+ $item = menu_get_item('admin/modules/install');
+ if ($item['access']) {
+ $item['title'] = t('Install manually');
+ $data['actions']['output'][] = array(
+ '#theme' => 'menu_local_action',
+ '#link' => $item,
+ );
+ }
+ break;
+ // This is used to put the 'Project Browser' action on the 'Appearance'
+ // page.
+ case 'admin/appearance':
+ // Unset the install theme page.
+ foreach ($data['actions']['output'] as $num => $item) {
+ if ($item['#link']['path'] == 'admin/appearance/install') {
+ unset($data['actions']['output'][$num]);
+ }
+ }
+ $item = menu_get_item('admin/modules/project-browser/themes');
+ if ($item['access']) {
+ $item['title'] = t('Install new themes');
+ $data['actions']['output'][] = array(
+ '#theme' => 'menu_local_action',
+ '#link' => $item,
+ );
+ }
+ break;
+ }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function project_browser_theme($existing, $type, $theme, $path) {
+ return array(
+ // Template for installation page.
+ 'project_browser_install' => array(
+ 'variables' => array('current_task' => NULL, 'main_content' => NULL),
+ 'path' => $path . '/theme',
+ 'template' => 'project-browser-install',
+ ),
+ // Template for list of projects.
+ 'project_browser_list' => array(
+ 'variables' => array('projects_list' => NULL, 'type' => NULL),
+ 'path' => $path . '/theme',
+ 'template' => 'project-browser-list',
+ ),
+ // Template for list of projects.
+ 'project_browser_block' => array(
+ 'render element' => 'element',
+ 'path' => $path . '/theme',
+ 'template' => 'project-browser-block',
+ ),
+ // Template for single project.
+ 'project_browser_project' => array(
+ 'variables' => array('project' => NULL, 'first' => NULL),
+ 'path' => $path . '/theme',
+ 'template' => 'project-browser-project',
+ ),
+ // Template for install queue item.
+ 'project_browser_install_queue' => array(
+ 'variables' => array('projects' => NULL),
+ 'path' => $path . '/theme',
+ 'template' => 'project-browser-install-queue',
+ ),
+ );
+}
+
+/**
+ * Implements hook_preprocess_HOOK() for project-browser-install.tpl.php.
+ *
+ * Adds some variables for the projects install theme.
+ *
+ * @param array $variables
+ * An associative array containing:
+ * - current_task : the current task.
+ *
+ * @ingroup themeable
+ */
+function project_browser_preprocess_project_browser_install(&$variables) {
+ module_load_include('inc', 'project_browser', 'project_browser.pages');
+ // Add the themed list
+ $variables['task_list'] = project_browser_installation_task_list($variables['current_task']);
+}
+
+/**
+ * Implements hook_preprocess_HOOK() for project-browser-install-queue.tpl.php.
+ *
+ * Adds some variables for the projects install queue theme.
+ *
+ * @param array $variables
+ * An associative array containing:
+ * - projects : an array of projects in the install queue.
+ *
+ * @ingroup themeable
+ */
+function project_browser_preprocess_project_browser_install_queue(&$variables) {
+ $build = array();
+ if (empty($variables['projects'])) {
+ $build['empty_text'] = array(
+ '#markup' => t('Install queue is empty.'),
+ );
+ }
+ else {
+ foreach ($variables['projects'] as $project) {
+ $build['queued-item-' . $project['name']] = array(
+ '#prefix' => "",
+ '#markup' => project_browser_add_remove_queue_link($project['name'], $project['title'], 'remove-queue-link'),
+ '#suffix' => "
",
+ );
+ }
+ $build['install-link'] = drupal_get_form('project_browser_install_button_form');
+ }
+
+ // Add the install button.
+ $variables['queue_html'] = drupal_render($build);
+}
+
+/**
+ * Implements hook_preprocess_HOOK() for project-browser-block.tpl.php.
+ *
+ * Adds some variables for the project browser block theme.
+ *
+ * @param array $variables
+ * An associative array containing:
+ * - element['#title'] : the title of the block.
+ * - element['#content'] : the content of the block.
+ *
+ * @ingroup themeable
+ */
+function project_browser_preprocess_project_browser_block(&$variables) {
+ // Add the title and content variables.
+ $variables['title'] = $variables['element']['#title'];
+ $variables['content'] = $variables['element']['#content'];
+}
+
+/**
+ * Implements hook_preprocess_HOOK() for project-browser-list.tpl.php.
+ *
+ * Adds some variables for the projects list theme.
+ *
+ * @param array $variables
+ * An associative array containing:
+ * - projects_list : array of all projects.
+ *
+ * @ingroup themeable
+ */
+function project_browser_preprocess_project_browser_list(&$variables) {
+ module_load_include('inc', 'project_browser', 'project_browser');
+ drupal_add_library('project_browser', 'drupal.project_browser.css');
+
+ if (is_array($variables['projects_list']) AND !empty($variables['projects_list'])) {
+ $content = '';
+ $first = TRUE;
+ // Theme each individual project and add to the list.
+ foreach ($variables['projects_list'] as $project) {
+ $content .= theme('project_browser_project', array('project' => $project, 'first' => $first));
+ $first = FALSE;
+ }
+ }
+ else {
+ $content = t('No results found.');
+ }
+
+ switch ($variables['type']) {
+ case 'module':
+ $title = t('Modules');
+ break;
+ case 'theme':
+ $title = t('Themes');
+ break;
+ default:
+ $title = t('Projects');
+ break;
+ }
+
+ $main_content['project_browser_main_block'] = array(
+ '#theme' => 'project_browser_block',
+ '#title' => $title,
+ '#content' => $content,
+ '#contextual_links' => array(
+ 'project_browser' => array('admin/config/development/project_browser', array()),
+ ),
+ );
+ $variables['main_content'] = render($main_content);
+
+ // Add the pager.
+ $variables['pager'] = theme('pager', array('tags' => NULL));
+
+ // Add the filters.
+ $filters_form = drupal_get_form('project_browser_filters_form', $variables['type']);
+ $filters['project_browser_filters_block'] = array(
+ '#theme' => 'project_browser_block',
+ '#title' => t('Filters'),
+ '#content' => drupal_render($filters_form),
+ );
+ $variables['filters'] = render($filters);
+
+ // Add the install list.
+ $install_list['project_browser_filters_block'] = array(
+ '#theme' => 'project_browser_block',
+ '#title' => t('Install queue'),
+ '#content' => project_browser_get_install_list(),
+ );
+ $variables['install_list'] = render($install_list);
+}
+
+/**
+ * Implements hook_preprocess_HOOK() for project-browser-project.tpl.php.
+ *
+ * Adds some variables for the project theme.
+ *
+ * @param array $variables
+ * An associative array containing:
+ * - project : associative array of project variables.
+ *
+ * @ingroup themeable
+ */
+function project_browser_preprocess_project_browser_project(&$variables) {
+ module_load_include('inc', 'project_browser', 'project_browser');
+ $project = $variables['project'];
+
+ $variables['title'] = l($project['title'], check_url($project['project url']),
+ array('attributes' => array('target' => '_blank'), 'html' => TRUE));
+ $variables['author'] = t('Author: @author', array('@author' => $project['author']));
+ $variables['description'] = _filter_htmlcorrector(filter_xss($project['description']));
+ $variables['image'] = $project['image'];
+ $variables['last_updated'] = ($project['last updated']) ? t('Last Updated: @date', array('@date' => format_date($project['last updated'], 'long'))) : '';
+
+ $extras = array();
+
+ if ($project['maintenance status']) {
+ $extras[] = check_plain($project['maintenance status']);
+ }
+ if ($project['development status']) {
+ // We are not showing this because it isn't a good indicator right now.
+ // $extras[] = check_plain($project['development status']);
+ }
+ if ($project['usage'] AND is_numeric($project['usage'])) {
+ $extras[] = format_plural($project['usage'], '1 Install', '@count Installs');
+ }
+ if ($project['rating']) {
+ $extras[] = check_plain($project['rating']);
+ }
+
+ $variables['extras'] = implode(' | ', $extras);
+
+ // Check if the project is installed.
+ if (_project_browser_is_project_enabled($project['type'], $project['name'])) {
+ $variables['status'] = 'Already installed
';
+ $variables['install'] = '';
+ }
+ elseif (drupal_get_filename($project['type'], $project['name'])) {
+ $variables['status'] = 'Already downloaded
';
+ $variables['install'] = '';
+ }
+ else {
+ $variables['status'] = '';
+ $variables['install'] = project_browser_add_remove_queue_link($project['name']);
+ }
+}
+
+/**
+ * Builds the add/remove project to install queue link.
+ *
+ * @param string $project_name
+ * The short name of the project, such as 'views'.
+ * @param string|null $title
+ * (Optional) The title of the project. Defaults to NULL.
+ * @param string $id_prefix
+ * (Optional) The prefix that should be prepended to the id, to ensure unique
+ * id names. Defaults to 'add-to-queue-link'.
+ *
+ * @return string
+ * A themed link to remove or add an item from the install queue.
+ */
+function project_browser_add_remove_queue_link($project_name, $title = NULL, $id_prefix = 'add-to-queue-link') {
+ $queued_projects = project_browser_get_queued_projects();
+ if (!$title) {
+ $title = isset($queued_projects[$project_name]) ? t('Remove from Install queue') : t('Add to Install queue');
+ }
+ $op = isset($queued_projects[$project_name]) ? 'remove' : 'add';
+
+ $build['ajax_link'] = array(
+ '#type' => 'link',
+ '#title' => $title,
+ '#href' => 'project-browser/nojs/install-queue/' . $op . '/'. $project_name,
+ '#options' => array(
+ 'query' => drupal_get_destination(),
+ ),
+ '#id' => $id_prefix . '-' . $project_name,
+ '#ajax' => array(
+ 'effect' => 'fade',
+ 'speed' => 1000,
+ 'progress' => array(
+ 'type' => 'throbber',
+ 'message' => '',
+ ),
+ ),
+ );
+
+ return drupal_render($build);
+}
+
+/**
+ * Implements hook_library_info().
+ */
+function project_browser_library_info() {
+ // Adds the multiselect library for use with the categories widget.
+ $libraries['multiselect'] = array(
+ 'title' => 'jQuery MultiSelect',
+ 'website' => 'http://example.com/library-1',
+ 'version' => '1.10a',
+ 'js' => array(
+ drupal_get_path('module', 'project_browser') . '/js/jquery.multiselect.min.js' => array(),
+ ),
+ 'css' => array(
+ drupal_get_path('module', 'project_browser') . '/css/jquery.multiselect.css' => array(
+ 'type' => 'file',
+ 'media' => 'screen',
+ ),
+ ),
+ 'dependencies' => array(
+ array('system', 'jquery'),
+ array('system', 'drupal'),
+ array('system', 'jquery.ui.widget'),
+ array('system', 'jquery.ui.dialog'),
+ array('system', 'jquery.ui.position'),
+ ),
+ );
+ $libraries['drupal.project_browser'] = array(
+ 'title' => 'Project Browser',
+ 'version' => VERSION,
+ 'js' => array(
+ drupal_get_path('module', 'project_browser') . '/js/project_browser_more_link.js' => array(),
+ drupal_get_path('module', 'project_browser') . '/js/project_browser_multiselect.js' => array(),
+ ),
+ 'dependencies' => array(
+ array('system', 'jquery'),
+ array('system', 'drupal'),
+ array('project_browser', 'multiselect'),
+ array('project_browser', 'drupal.project_browser.css'),
+ ),
+ );
+ $libraries['drupal.project_browser.select_releases'] = array(
+ 'title' => 'Project Browser Select Releases',
+ 'version' => VERSION,
+ 'js' => array(
+ drupal_get_path('module', 'project_browser') . '/js/project_browser_select_releases.js' => array(),
+ ),
+ 'dependencies' => array(
+ array('system', 'jquery'),
+ array('system', 'drupal'),
+ array('project_browser', 'drupal.project_browser.css'),
+ ),
+ );
+ $libraries['drupal.project_browser.css'] = array(
+ 'title' => 'Project Browser CSS',
+ 'version' => VERSION,
+ 'css' => array(
+ drupal_get_path('module', 'project_browser') . '/css/project_browser.admin.css' => array(
+ 'type' => 'file',
+ 'media' => 'screen',
+ ),
+ ),
+ );
+ return $libraries;
+}
diff --git a/core/modules/project_browser/project_browser.pages.inc b/core/modules/project_browser/project_browser.pages.inc
new file mode 100644
index 0000000..b756199
--- /dev/null
+++ b/core/modules/project_browser/project_browser.pages.inc
@@ -0,0 +1,557 @@
+ $drupal_version[0],
+ 'type' => $type,
+ );
+
+ // Add filters.
+ if (isset($_SESSION['project_browser_category_filter_' . $type])) {
+ $categories = array_filter($_SESSION['project_browser_category_filter_' . $type]);
+ if (!empty($categories)) {
+ $filters['categories'] = project_browser_prepare_categories($categories, $type);
+ }
+ }
+ if (isset($_SESSION['project_browser_text_filter_' . $type])) {
+ $filters['text'] = $_SESSION['project_browser_text_filter_' . $type];
+ }
+ if (isset($_SESSION['project_browser_order_by_filter_' . $type])) {
+ $filters['order_by'] = $_SESSION['project_browser_order_by_filter_' . $type];
+ }
+ if (isset($_SESSION['project_browser_sort_filter_' . $type])) {
+ $filters['sort'] = $_SESSION['project_browser_sort_filter_' . $type];
+ }
+ if (isset($_SESSION['project_browser_server_filter'])) {
+ $filters['server'] = $_SESSION['project_browser_server_filter'];
+ }
+ else {
+ $filters['server'] = 0;
+ }
+ $filters['requested'] = 10;
+ $filters['page'] = isset($_GET['page']) ? $_GET['page'] : 0;
+
+ // Get the projects to display here based on the filters.
+ $results = project_browser_fetch_results($filters);
+
+ // Save the listed projects in the session so it can be used.
+ $_SESSION['project_browser_listed_projects'] = $results['projects'];
+
+ $test = project_browser_get_listed_projects();
+
+ $list = array();
+ foreach ($results['projects'] as $project) {
+ $list[] = $project;
+ }
+
+ // Add the pager.
+ $total = $results['total'];
+ $num_per_page = 10;
+ $page = pager_default_initialize($total, $num_per_page);
+ $offset = $num_per_page * $page;
+ $start = ($total) ? $offset + 1 : 0;
+ $finish = $offset + $num_per_page;
+ if ($finish > $total) {
+ $finish = $total;
+ }
+
+ $sort_options = project_browser_get_sort_options();
+ $current_order_by = isset($_SESSION['project_browser_order_by_filter_' . $type]) ? $_SESSION['project_browser_order_by_filter_' . $type] : 'score';
+ $current_sort = isset($_SESSION['project_browser_sort_filter_' . $type]) ? $_SESSION['project_browser_sort_filter_' . $type] : 'desc';
+
+ $build = array();
+ $build['content'] = array(
+ 'project_browser_header' => array(
+ '#markup' => t('Showing @start to @finish of @total.', array(
+ '@start' => $start, '@finish' => $finish, '@total' => $total)),
+ '#weight' => 0,
+ ),
+ 'project_browser_sort_header' => array(
+ '#type' => 'item',
+ '#weight' => 2,
+ '#markup' => project_browser_get_sort_widget($sort_options, $current_order_by, $current_sort),
+ ),
+ 'project_browser_list' => array(
+ '#markup' => theme('project_browser_list', array('projects_list' => $list, 'type' => $type)),
+ '#weight' => 3,
+ ),
+ 'pager' => array(
+ '#theme' => 'pager',
+ '#weight' => 99,
+ ),
+ );
+
+ $servers = project_browser_get_servers();
+
+ if (count($servers) > 1) {
+ $build['content']['project_browser_server_header'] = array(
+ '#type' => 'item',
+ '#weight' => 1,
+ '#markup' => project_browser_get_server_widget($servers, $filters['server']),
+ );
+ }
+
+ $build['#attached']['library'][] = array('project_browser', 'drupal.project_browser');
+
+ return $build;
+}
+
+/**
+ * Builds a page from the install process.
+ *
+ * @param string $op
+ * Operation to perform.
+ *
+ * @return string
+ * A themed page from the install process, depending on the $op.
+ */
+function project_browser_installation_page($op) {
+ drupal_add_library('project_browser', 'drupal.project_browser.css');
+
+ switch ($op) {
+ case 'select_versions':
+ drupal_set_title(t("Select versions"));
+ $content = project_browser_installation_select_versions_page();
+ break;
+ case 'install_dependencies':
+ drupal_set_title(t("Install Dependencies"));
+ $content = project_browser_installation_install_dependencies_page();
+ break;
+ case 'enable':
+ drupal_set_title(t("Enable modules"));
+ $content = project_browser_installation_enable_page();
+ break;
+ }
+ return theme('project_browser_install', array('current_task' => $op, 'main_content' => drupal_render($content)));
+}
+
+/**
+ * Page callback: Shows the Select versions installation task.
+ *
+ * Shows a form where the user can select which versions to install for each
+ * project.
+ *
+ * @return array
+ * The form to select the versions of the projects the user wants to install.
+ *
+ * @see project_browser_menu()
+ */
+function project_browser_installation_select_versions_page() {
+ module_load_include('inc', 'project_browser', 'project_browser');
+ // Show a form that lets the user select which version of the projects to
+ // install.
+ $queued_projects = project_browser_get_queued_projects();
+ unset($_SESSION['project_browser_installed_projects']);
+
+ return drupal_get_form('project_browser_installation_select_versions_form', $queued_projects);
+}
+
+/**
+ * Form constructor for the select versions form.
+ *
+ * @param array $projects
+ * An array of projects to get the releases for.
+ *
+ * @see project_browser_installation_select_versions_form_submit()
+ * @ingroup forms
+ */
+function project_browser_installation_select_versions_form($form, &$form_state, $projects) {
+ module_load_include('inc', 'project_browser', 'project_browser');
+ drupal_add_library('project_browser', 'drupal.project_browser.select_releases');
+
+ $form = array();
+
+ // First unset any old data.
+ unset($_SESSION['project_browser_install_releases_list']);
+
+ $form['#tree'] = TRUE;
+
+ $form['releases-header'] = array(
+ '#type' => 'item',
+ '#markup' => t("You're about to install:"),
+ );
+
+ $form['releases'] = array();
+
+ foreach ($projects as $project) {
+ // Get the available releases for this project.
+ if (!$release_data = project_browser_get_project_release_data($project)) {
+ drupal_set_message(t('Could not fetch releases for project %project.',
+ array('%project' => $project['title'])), 'warning');
+ watchdog('project_browser', 'Could not fetch releases for project %project.',
+ array('%project' => $project['title']), WATCHDOG_ERROR);
+ project_browser_install_queue_remove($project['name']);
+ continue;
+ }
+
+ // We use the update module to calculate the recommended version.
+ $project_data = array(
+ 'existing_major' => 0,
+ 'existing_version' => 0,
+ 'install_type' => '',
+ );
+ module_load_include('inc', 'update', 'update.compare');
+ update_calculate_project_update_status($project_data, $release_data);
+
+ $releases_list = array();
+
+ foreach ($release_data['releases'] as $version => $release) {
+ $release_title = t("@project @version - @date", array(
+ '@project' => $project['title'],
+ '@version' => $release['version'],
+ '@date' => format_date($release['date'], 'custom', 'M j, Y'),
+ ));
+ if (isset($release['terms']['Release type']) AND !empty($release['terms']['Release type'])) {
+ $release_title .= " (" . implode(', ', $release['terms']['Release type']) . ")";
+ }
+ if (isset($release['release_link'])) {
+ $releases_list[$version] = l($release_title, $release['release_link']);
+ }
+ else {
+ $releases_list[$version] = $release_title;
+ }
+ }
+
+ $form['releases'][$project['name']]['project'] = array(
+ '#type' => 'value',
+ '#value' => $project,
+ );
+
+ $form['releases'][$project['name']]['release_name'] = array(
+ '#type' => 'radios',
+ '#title' => t('Select release for @project', array('@project' => $project['title'])),
+ '#options' => $releases_list,
+ '#default_value' => key($releases_list),
+ '#prefix' => '',
+ '#suffix' => '
',
+ '#attributes' => array(
+ 'class' => array('project-browser-releases-radios'),
+ ),
+ '#required' => TRUE,
+ );
+ $form['releases'][$project['name']]['selected_text'] = array(
+ '#type' => 'item',
+ '#prefix' => '',
+ '#suffix' => '
',
+ '#markup' => reset($releases_list),
+ );
+ if (isset($project_data['recommended'])) {
+ // If there is a recommended release set, then only show it and show the
+ // jQuery link.
+ $recommended_releases = array();
+ $recommended_releases[$project_data['recommended']] = $releases_list[$project_data['recommended']];
+ $form['releases'][$project['name']]['release_name']['#default_value'] = $project_data['recommended'];
+ $form['releases'][$project['name']]['selected_text']['#markup'] = $releases_list[$project_data['recommended']];
+ }
+ if (count($releases_list) > 1) {
+ $form['releases'][$project['name']]['selected_text']['#markup'] .=
+ " (" . t('change release') . ")";
+ }
+ }
+
+ // If there is nothing to install, go to the enable page.
+ if (empty($form['releases'])) {
+ drupal_set_message(t('No releases data found for any of the selected projects.'), 'warning');
+ drupal_goto('admin/modules/project-browser/install/enable');
+ }
+
+ $form['backup_warning'] = array(
+ '#type' => 'markup',
+ '#markup' => t('Back up your database and site before you continue. !link.',
+ array('!link' => l(t('Learn how'), 'http://drupal.org/node/22281'))),
+ );
+ $form['maintenance_mode'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Perform updates with site in maintenance mode (strongly recommended)'),
+ '#default_value' => TRUE,
+ );
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Install'),
+ );
+
+ return $form;
+}
+
+/**
+ * Form submission handler for project_browser_installation_select_versions_form()
+ *
+ * This sets the batch to install the different selected releases one by one.
+ */
+function project_browser_installation_select_versions_form_submit($form, &$form_state) {
+ module_load_include('inc', 'project_browser', 'project_browser');
+ // Store maintenance_mode setting so we can restore it when done.
+ $_SESSION['maintenance_mode'] = variable_get('maintenance_mode', FALSE);
+ if ($form_state['values']['maintenance_mode'] == TRUE) {
+ variable_set('maintenance_mode', TRUE);
+ }
+
+ foreach ($form_state['values']['releases'] as $item) {
+ // Load the selected release.
+ if ($release = project_browser_get_release($item['release_name'], $item['project'])) {
+ // Add the release to a session variable.
+ $_SESSION['project_browser_install_releases_list'][$item['project']['name']] = array(
+ 'release_name' => $item['release_name'],
+ 'project' => $item['project'],
+ );
+ }
+ }
+
+ // Install the projects with batch.
+ module_load_include('inc', 'update', 'update.manager');
+
+ $queued_releases = project_browser_get_queued_releases();
+
+ $operations = array();
+ foreach ($queued_releases as $short_name => $info) {
+ $operations[] = array('_project_browser_batch_install_release', array($info['release_name'], $info['project']));
+ }
+ $batch = array(
+ 'operations' => $operations,
+ 'finished' => '_project_browser_batch_install_releases_finished',
+ 'title' => t('Installing projects'),
+ 'init_message' => t('Installing modules...'),
+ 'progress_message' => t('Installed @current out of @total.'),
+ 'error_message' => t('Installation has encountered an error.'),
+ 'file' => drupal_get_path('module', 'project_browser') . '/project_browser.inc',
+ );
+ batch_set($batch);
+}
+
+/**
+ * Page callback: Handles the Install Dependencies installation task.
+ *
+ * This shows a form which lets the user select which version of dependencies
+ * to install. This is only shown if there are missing dependencies. If there
+ * are no missing dependencies, then we redirect to the enable page.
+ *
+ * @return array
+ * The form array to let the user select the dependencies to install.
+ *
+ * @see project_browser_menu()
+ */
+function project_browser_installation_install_dependencies_page() {
+ module_load_include('inc', 'project_browser', 'project_browser');
+ $projects = project_browser_get_installed_projects();
+ $missing = project_browser_get_missing_dependencies($projects);
+
+ if (count($missing) > 0) {
+ $missing_projects = array();
+ // Add the project data in the array as best we can.
+ foreach ($missing as $project_shortname => $dependencies) {
+ foreach ($dependencies as $shortname) {
+ $missing_projects[$shortname] = array(
+ 'name' => $shortname,
+ // Missing dependencies only works for projects of type 'module'
+ 'type' => 'module',
+ 'title' => $shortname,
+ );
+ }
+ }
+
+ return drupal_get_form('project_browser_installation_select_versions_form', $missing_projects);
+ }
+ else {
+ drupal_goto('admin/modules/project-browser/install/enable');
+ }
+}
+
+/**
+ * Page callback: Shows the options for the Enable projects installation task.
+ *
+ * This shows a form which lets the user enable the newly installed projects. If
+ * there are unresolved dependencies, then the project is shown with a message
+ * about why it can't be enabled. This redirects to the project-browser page if
+ * there were no installed projects.
+ *
+ * @return array
+ * The form array to enable projects, or redirect to
+ * 'admin/modules/project-browser'.
+ *
+ * @see project_browser_menu()
+ */
+function project_browser_installation_enable_page() {
+ module_load_include('inc', 'project_browser', 'project_browser');
+ $installed_projects = project_browser_get_installed_projects();
+
+ if (count($installed_projects) > 0) {
+ return drupal_get_form('project_browser_installation_enable_form', $installed_projects);
+ }
+ else {
+ drupal_goto('admin/modules/project-browser');
+ }
+}
+
+/**
+ * Form constructor for the enable projects form.
+ *
+ * @param array $projects
+ * An array of newly installed projects to enable.
+ *
+ * @see project_browser_installation_enable_form_submit()
+ * @ingroup forms
+ */
+function project_browser_installation_enable_form($form, &$form_state, $projects) {
+ $modules = system_rebuild_module_data();
+ $form['instructions'] = array(
+ '#type' => 'item',
+ '#markup' => t('The projects you selected have been successfully installed.
+ If you installed any new modules, you may enable them using the form below
+ or on the main !link page.', array('!link' => l(t('Modules'), 'admin/modules'))),
+ );
+
+ $options = array();
+ $missing = array();
+
+ foreach ($projects as $project) {
+ if ($project['type'] == 'module') {
+ $dependency_check = TRUE;
+ $dependencies = array();
+ if (isset($modules[$project['name']])) {
+ foreach ($modules[$project['name']]->info['dependencies'] as $dependency) {
+ if (isset($modules[$dependency])) {
+ $dependencies[] = $modules[$dependency]->info['name'] . ' (' . t('Installed') . ')';
+ }
+ else {
+ $dependency_check = FALSE;
+ $dependencies[] = $dependency . ' (' . t('Missing') . ')';
+ }
+ }
+ if ($dependency_check) {
+ $options[$project['name']] = array(
+ array('data' => $modules[$project['name']]->info['name']),
+ array('data' => $modules[$project['name']]->info['version']),
+ array('data' => implode(', ', $dependencies)),
+ );
+ }
+ else {
+ $missing[$project['name']] = array(
+ array('data' => $modules[$project['name']]->info['name']),
+ array('data' => $modules[$project['name']]->info['version']),
+ array('data' => implode(', ', $dependencies)),
+ );
+ }
+ }
+ else {
+ drupal_set_message(t('There was an error getting information for @module',
+ array('@module' => $project['name'])), 'error');
+ }
+ }
+ }
+
+ $headers = array(
+ array('data' => t('Title')),
+ array('data' => t('Version')),
+ array('data' => t('Dependencies')),
+ );
+
+ if (!empty($options)) {
+ $form['modules'] = array(
+ '#type' => 'tableselect',
+ '#title' => t('Enable modules'),
+ '#description' => t('Select which modules you would like to enable.'),
+ '#header' => $headers,
+ '#options' => $options,
+ '#empty' => t('No new modules installed.'),
+ '#multiple' => TRUE,
+ '#js_select' => TRUE,
+ '#weight' => 1,
+ );
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#submit' => array('project_browser_installation_enable_form_submit'),
+ '#value' => t('Enable modules'),
+ '#weight' => 99,
+ );
+ }
+
+ if (!empty($missing)) {
+ $form['missing'] = array(
+ '#type' => 'item',
+ '#title' => t('Missing Dependencies'),
+ '#description' => t('These modules are missing one or more dependencies,
+ and so cannot be enabled.'),
+ '#markup' => theme('table', array('header' => $headers, 'rows' => $missing)),
+ '#weight' => 2,
+ );
+ }
+
+ return $form;
+}
+
+/**
+ * Enables the selected projects from the enable projects form.
+ *
+ * After the selected projects are enabled, we flush all caches and then
+ * redirect to the modules page.
+ */
+function project_browser_installation_enable_form_submit($form, &$form_state) {
+ $enable_queue = array_filter($form_state['values']['modules']);
+ // Enable these all at once so that dependencies are handled properly.
+ module_enable($enable_queue);
+
+ drupal_flush_all_caches();
+
+ drupal_goto('admin/modules');
+}
+
+/**
+ * Builds a task list to the sidebar area when installing projects.
+ *
+ * This will need to be called from every page of the install process.
+ *
+ * @param string $active
+ * (Optional) Set the active task by key. Defaults to NULL.
+ *
+ * @return array
+ * The themed task list for the install projects process.
+ */
+function project_browser_installation_task_list($active = NULL) {
+ // Default list of tasks.
+ $tasks = array(
+ 'select_versions' => t('Select versions'),
+ 'install_dependencies' => t('Install Dependencies'),
+ 'enable' => t('Enable projects'),
+ );
+
+ require_once DRUPAL_ROOT . '/core/includes/theme.maintenance.inc';
+
+ return theme_task_list(array('items' => $tasks, 'active' => $active));
+}
--
1.7.3.1.msysgit.0
From 67143ce11ebacaad3427c08fca7e33131161c154 Mon Sep 17 00:00:00 2001
From: Leighton Whiting
Date: Sun, 18 Nov 2012 12:02:23 -0700
Subject: [PATCH 2/2] Lots of cleanup
---
.../project_browser/css/jquery.multiselect.css | 23 +
.../project_browser/css/project_browser.admin.css | 203 ++++
core/modules/project_browser/images/arrow-asc.png | 5 +
core/modules/project_browser/images/arrow-desc.png | 4 +
core/modules/project_browser/images/circle.png | 3 +
core/modules/project_browser/images/red-x.png | 7 +
.../project_browser/js/jquery.multiselect.min.js | 44 +
.../js/project_browser_more_link.js | 42 +
.../js/project_browser_multiselect.js | 23 +
.../js/project_browser_select_releases.js | 23 +
.../project_browser/Tests/ProjectBrowserTest.php | 95 ++
.../project_browser/project_browser.admin.inc | 36 +
core/modules/project_browser/project_browser.inc | 987 ++++++++++++++++++++
core/modules/project_browser/project_browser.info | 6 +
.../tests/project_browser_test.info | 5 +
.../tests/project_browser_test.module | 329 +++++++
.../theme/project-browser-block.tpl.php | 21 +
.../theme/project-browser-install-queue.tpl.php | 16 +
.../theme/project-browser-install.tpl.php | 22 +
.../theme/project-browser-list.tpl.php | 27 +
.../theme/project-browser-project.tpl.php | 59 ++
21 files changed, 1980 insertions(+), 0 deletions(-)
create mode 100644 core/modules/project_browser/css/jquery.multiselect.css
create mode 100644 core/modules/project_browser/css/project_browser.admin.css
create mode 100644 core/modules/project_browser/images/arrow-asc.png
create mode 100644 core/modules/project_browser/images/arrow-desc.png
create mode 100644 core/modules/project_browser/images/circle.png
create mode 100644 core/modules/project_browser/images/red-x.png
create mode 100644 core/modules/project_browser/js/jquery.multiselect.min.js
create mode 100644 core/modules/project_browser/js/project_browser_more_link.js
create mode 100644 core/modules/project_browser/js/project_browser_multiselect.js
create mode 100644 core/modules/project_browser/js/project_browser_select_releases.js
create mode 100644 core/modules/project_browser/lib/Drupal/project_browser/Tests/ProjectBrowserTest.php
create mode 100644 core/modules/project_browser/project_browser.admin.inc
create mode 100644 core/modules/project_browser/project_browser.inc
create mode 100644 core/modules/project_browser/project_browser.info
create mode 100644 core/modules/project_browser/tests/project_browser_test.info
create mode 100644 core/modules/project_browser/tests/project_browser_test.module
create mode 100644 core/modules/project_browser/theme/project-browser-block.tpl.php
create mode 100644 core/modules/project_browser/theme/project-browser-install-queue.tpl.php
create mode 100644 core/modules/project_browser/theme/project-browser-install.tpl.php
create mode 100644 core/modules/project_browser/theme/project-browser-list.tpl.php
create mode 100644 core/modules/project_browser/theme/project-browser-project.tpl.php
diff --git a/core/modules/project_browser/css/jquery.multiselect.css b/core/modules/project_browser/css/jquery.multiselect.css
new file mode 100644
index 0000000..e8f8e00
--- /dev/null
+++ b/core/modules/project_browser/css/jquery.multiselect.css
@@ -0,0 +1,23 @@
+.ui-multiselect { padding:2px 0 2px 4px; text-align:left }
+.ui-multiselect span.ui-icon { float:right }
+.ui-multiselect-single .ui-multiselect-checkboxes input { position:absolute !important; top: auto !important; left:-9999px; }
+.ui-multiselect-single .ui-multiselect-checkboxes label { padding:5px !important }
+
+.ui-multiselect-header { margin-bottom:3px; padding:3px 0 3px 4px }
+.ui-multiselect-header ul { font-size:0.9em }
+.ui-multiselect-header ul li { float:left; padding:0 10px 0 0; list-style: none; }
+.ui-multiselect-header a { text-decoration:none }
+.ui-multiselect-header a:hover { text-decoration:underline }
+.ui-multiselect-header span.ui-icon { float:left }
+.ui-multiselect-header li.ui-multiselect-close { float:right; text-align:right; padding-right:0 }
+
+.ui-multiselect-menu { display:none; padding:3px; position:absolute; z-index:10000; width: 500px; }
+.ui-multiselect-checkboxes { position:relative /* fixes bug in IE6/7 */; overflow-y:scroll }
+.ui-multiselect-checkboxes label { cursor:default; display:block; border:1px solid transparent; padding:3px 1px }
+.ui-multiselect-checkboxes label input { position:relative; top:1px; margin-right: 5px; }
+.ui-multiselect-checkboxes li { float:left; width: 225px; font-size:0.9em; padding-right:3px; list-style: none; }
+.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label { text-align:center; font-weight:bold; border-bottom:1px solid }
+.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label a { display:block; padding:3px; margin:1px 0; text-decoration:none }
+
+/* remove label borders in IE6 because IE6 does not support transparency */
+* html .ui-multiselect-checkboxes label { border:none }
diff --git a/core/modules/project_browser/css/project_browser.admin.css b/core/modules/project_browser/css/project_browser.admin.css
new file mode 100644
index 0000000..cef087e
--- /dev/null
+++ b/core/modules/project_browser/css/project_browser.admin.css
@@ -0,0 +1,203 @@
+#project-browser-install-button-form {
+ clear: both;
+ margin: 10px 0 0;
+}
+
+#project-browser-install-queue {
+ margin: 5px 0 0;
+}
+
+.project-browser-install-queue-item {
+ margin: 5px 0;
+}
+
+.project-browser-install-queue-items {
+ clear: both;
+ margin: 0 0 15px;
+}
+
+.project-browser-install-link {
+ clear: both;
+}
+
+.project-browser-install-queue-item a {
+ padding-left: 20px;
+ background: url("../images/red-x.png") no-repeat scroll left 2px transparent;
+}
+
+.project-browser-selected-release {
+ display: none;
+}
+
+.project-browser-show-releases-link {
+ cursor: pointer;
+}
+
+div.item-list ul.project-browser-sort-list,
+div.item-list ul.project-browser-servers-list {
+ margin: 0;
+}
+
+div.item-list ul.project-browser-sort-list li,
+div.item-list ul.project-browser-servers-list li {
+ display: inline;
+ list-style-image: none;
+ margin-right: 10px;
+}
+
+div.item-list ul.project-browser-sort-list li a,
+div.item-list ul.project-browser-servers-list li a {
+ color: #0074BD;
+}
+
+div.item-list ul.project-browser-sort-list li.sort-active a,
+div.item-list ul.project-browser-servers-list li.server-active a {
+ color: #000;
+}
+
+div.item-list ul.project-browser-sort-list li.sort-header,
+div.item-list ul.project-browser-servers-list li.server-header {
+ font-weight: bold;
+}
+
+div.item-list ul.project-browser-sort-list li.sort-asc {
+ background: url("../images/arrow-asc.png") no-repeat scroll right 2px transparent;
+ padding-right: 15px;
+}
+
+div.item-list ul.project-browser-sort-list li.sort-desc {
+ background: url("../images/arrow-desc.png") no-repeat scroll right 2px transparent;
+ padding-right: 15px;
+}
+
+a.show-more {
+ float: right;
+}
+
+.project-extra {
+ clear: both;
+ color: gray;
+ text-align: right;
+}
+
+.project-author {
+ color: gray;
+ font-size: 0.9em;
+}
+
+.project-updated {
+ color: gray;
+ font-size: 0.9em;
+}
+
+.project-image {
+ float: left;
+ margin-right: 10px;
+}
+
+.project-image img {
+ max-height: 150px;
+ max-width: 200px;
+}
+
+#project-browser-main ul, #project-browser-main ol {
+ list-style-position: inside;
+}
+
+.project-item {
+ border-top: 1px solid #E0E0D8;
+ clear: both;
+ padding: 10px;
+ position: relative;
+}
+
+.project-item-first {
+ clear: both;
+ padding: 10px;
+ position: relative;
+}
+
+div.project-status {
+ position: absolute;
+ right: 10px;
+ text-align: right;
+ top: 5px;
+}
+
+div.project-information {
+
+}
+
+.project-browser-install-main {
+ padding: 10px;
+ float: right;
+ width: 76%;
+}
+
+.install-disabled {
+ color: gray;
+}
+
+.install-enabled {
+ color: green;
+}
+
+.project-browser-install-sidebar-left {
+ float: left;
+ width: 19%;
+ padding: 10px;
+}
+
+div.project-title {
+ font-size: 18px;
+}
+
+fieldset#edit-category,
+fieldset#edit-version {
+ border: none;
+}
+
+div.install-item-prefix {
+ float:left;
+ margin-left: 50px;
+}
+
+#project-browser-main div.form-item-install {
+ float: right;
+}
+
+#project-browser div.project-browser-region {
+ min-height: 1px;
+}
+
+#project-browser div#project-browser-main {
+ width: 75%;
+ float: left;
+ margin-right: 1%;
+}
+
+#project-browser div#project-browser-sidebar-right {
+ width: 23%;
+ float: right;
+}
+
+#project-browser div.project_browser_block {
+ margin-bottom: 20px;
+ border: 1px solid #CCCCCC;
+}
+
+#project-browser .project-browser-region .project_browser_block {
+ clear: both;
+}
+
+#project-browser div.project_browser_block h2 {
+ float: none;
+ font-size: 1em;
+ margin: 0;
+ padding: 3px 10px;
+ background: none repeat scroll 0 0 #E0E0D8;
+}
+
+#project-browser div#project-browser-sidebar-right div.project_browser_block div.content {
+ padding: 5px 10px;
+}
diff --git a/core/modules/project_browser/images/arrow-asc.png b/core/modules/project_browser/images/arrow-asc.png
new file mode 100644
index 0000000..a3ccabc
--- /dev/null
+++ b/core/modules/project_browser/images/arrow-asc.png
@@ -0,0 +1,5 @@
+PNG
+
+
IHDR
H%v? PLTEkR% tRNS @f IDATc`@LLLL
+
+Li |q) IENDB`
\ No newline at end of file
diff --git a/core/modules/project_browser/images/arrow-desc.png b/core/modules/project_browser/images/arrow-desc.png
new file mode 100644
index 0000000..2edbb17
--- /dev/null
+++ b/core/modules/project_browser/images/arrow-desc.png
@@ -0,0 +1,4 @@
+PNG
+
+
IHDR
H%v? PLTEkR% tRNS @f IDATxc`@0`o``g``
+ KzH IENDB`
\ No newline at end of file
diff --git a/core/modules/project_browser/images/circle.png b/core/modules/project_browser/images/circle.png
new file mode 100644
index 0000000..6b2d63f
--- /dev/null
+++ b/core/modules/project_browser/images/circle.png
@@ -0,0 +1,3 @@
+PNG
+
+
IHDR 6|J PLTE E<