diff --git a/libraries.admin.inc b/libraries.admin.inc
new file mode 100644
index 0000000..8fa920d
--- /dev/null
+++ b/libraries.admin.inc
@@ -0,0 +1,353 @@
+ $info) {
+ $libraries[$name] = libraries_detect($name);
+ }
+ ksort($libraries);
+
+ foreach ($libraries as $machine_name => $library) {
+ $actions = array();
+
+ if ($library['vendor url']) {
+ $actions[] = l('Homepage', $library['vendor url']);
+ }
+ if ($library['download url']) {
+ $actions[] = l('Download', $library['download url']);
+ }
+
+ switch ($library['info type']) {
+ case 'module':
+ $provider = 'Module';
+ $provider_info = system_get_info('module', $library['module']);
+ $name = sprintf('%s (%s)', $provider_info['name'], $library['module']);
+ break;
+
+ case 'theme':
+ // @todo: verify this.
+ $provider = 'Theme';
+ $provider_info = system_get_info('theme', $library['theme']);
+ $name = sprintf('%s (%s)', $provider_info['name'], $library['theme']);
+ break;
+
+ case 'info file':
+ $provider = 'Info file';
+ $provider_info = array('name' => $library['info file']);
+ $name = $library['info file'];
+ break;
+ }
+
+ $rows[] = array(
+ 'data' => array(
+ l($library['name'], 'admin/reports/libraries/' . $machine_name),
+ ($library['installed'] ? t('OK') : drupal_ucfirst($library['error'])),
+ (isset($library['version']) ? $library['version'] : ''),
+ $provider . '
' . $name,
+ implode(' | ', $actions),
+ ),
+ 'class' => ($library['installed'] ? array('ok') : array('error')),
+ );
+ }
+
+ $form['libraries']['list'] = array(
+ '#theme' => 'table',
+ '#header' => $header,
+ '#rows' => $rows,
+ '#empty' => t('There are currently no libraries installed'),
+ );
+
+ return $form;
+}
+
+/**
+ * Form generation callback for the status overview for a single library.
+ *
+ * This is a form instead of a page to allow easier extending in contributed
+ * modules.
+ *
+ * @param array $form
+ * An associative array containing the structure of the form.
+ * @param array $form_state
+ * A keyed array containing the current state of the form.
+ * @param string $name
+ * The name of the library to return the status report for.
+ *
+ * @return array|null
+ * The form array for the status form or NULL if the library was not found.
+ *
+ * @todo Add some var_export($library)-style output
+ */
+function libraries_admin_library_status_form(array $form, array &$form_state, $library) {
+ drupal_set_title(t('Status report for library %library', array('%library' => $library['name'])), PASS_THROUGH);
+
+ if (isset($library['info type'])) {
+ switch ($library['info type']) {
+ case 'module':
+ $provider = 'Module';
+ $provider_info = system_get_info('module', $library['module']);
+ $name = sprintf('%s (%s)', $provider_info['name'], $library['module']);
+ break;
+
+ case 'theme':
+ // @todo: verify this.
+ $provider = 'Theme';
+ $provider_info = system_get_info('theme', $library['theme']);
+ $name = sprintf('%s (%s)', $provider_info['name'], $library['theme']);
+ break;
+
+ case 'info file':
+ $provider = 'Info file';
+ $provider_info = array('name' => $library['info file']);
+ $name = $library['info file'];
+ break;
+ }
+ }
+
+ if ($library['installed']) {
+ $rows = array();
+ drupal_set_message(t('The %name library is installed correctly.', array('%name' => $library['name'])));
+ $header = array(array('data' => '' . t('General information') . '', 'colspan' => 2, 'class' => 'table-heading', 'no_striping' => TRUE));
+
+ $rows[] = array('' . t('Provider') . '', sprintf('%s %s', $provider, $name));
+ $rows[] = array('' . t('Name') . '', check_plain($library['name']));
+ $rows[] = array('' . t('Machine name') . '', check_plain($library['machine name']));
+
+ if ($library['vendor url']) {
+ $rows[] = array('' . t('Vendor URL') . '', l($library['vendor url'], $library['vendor url']));
+ }
+
+ if ($library['download url']) {
+ $rows[] = array('' . t('Download URL') . '', l($library['download url'], $library['download url']));
+ }
+
+ $rows[] = array('' . t('Location') . '', $library['library path']);
+ $rows[] = array('' . t('Version') . '', $library['version']);
+
+ if (!empty($library['variants'])) {
+ $rows[] = array('' . t('Variants') . '', implode(', ', array_keys($library['variants'])));
+ }
+
+ $form['status']['overview'] = array(
+ '#theme' => 'table',
+ '#header' => $header,
+ '#rows' => $rows,
+ );
+ }
+ else {
+ drupal_set_message($library['error message'], 'error');
+
+ switch ($library['error']) {
+ case 'not found':
+ $form['status']['not_found']['instruction']['#markup'] = t('Follow these steps to install the library:');
+ $items = array();
+ // 1. Download the library.
+ // If no supported versions are specified, the latest version is
+ // recommended.
+ if (empty($library['versions'])) {
+ $items[] = t('Download the latest version of the library here.', array(
+ '@download-url' => $library['download url'],
+ ));
+ }
+ // Otherwise, the latest supported version is recommended.
+ else {
+ $versions = array_keys($library['versions']);
+ usort($versions, 'version_compare');
+ $versions = array_reverse($versions);
+ $version = $versions[0];
+ $items[] = t('Download version %version of the library here.', array(
+ '%version' => $version,
+ '@download-url' => $library['download url'],
+ ));
+ }
+ // 2. Unpack it.
+ $items[] = t('If the library is an archive, i.e. if the file ending is for example .tar.gz or .zip, unpack it.');
+ // 3. Create the libraries folder.
+ $items[] = t('In the %library-directory directory of your Drupal installation create a %library directory.', array(
+ '%library-directory' => 'sites/all/libraries',
+ '%library' => $library['machine name'],
+ ));
+ // 4. Upload it.
+ // If the library has variant-independent files, give the user the
+ // location of an example file to check his filesystem against.
+ list($filepath, $file) = libraries_get_example_filepath($library);
+ if ($filepath !== FALSE) {
+ $items[] = t('Upload the whole library (which can consist of multiple directories) into the newly created %library-path directory. For example, the %file file, should be located at following filepath: %filepath', array(
+ '%library-path' => 'sites/all/libraries/' . $library['machine name'],
+ '%file' => $file,
+ '%filepath' => $filepath,
+ ));
+ }
+ else {
+ $items[] = t('Upload the whole library (which can consist of multiple directories) into the newly created %library-path directory.', array(
+ '%library-path' => 'sites/all/libraries/' . $library['machine name'],
+ ));
+ }
+ // 5. Reload.
+ $items[] = t('Reload the page. If successful, you should see status information about this library.');
+
+ $form['status']['not_found']['steps'] = array(
+ '#theme' => 'item_list',
+ '#items' => $items,
+ '#type' => 'ol'
+ );
+ break;
+
+ case 'not detected':
+ // Re-check location.
+ // If the library has variant-independent files, give the user the
+ // location of an example file to check his filesystem against.
+ list($filepath, $file) = libraries_get_example_filepath($library);
+ if ($filepath !== FALSE) {
+ $form['status']['not_detected']['instruction']['#markup'] = t('Check that the whole library is located at %library-path. For example, the %file file, should be located at following filepath: %filepath', array(
+ '%library-path' => $library['library path'],
+ '%file' => $file,
+ '%filepath' => $filepath,
+ )) . '
';
+ }
+ else {
+ $form['status']['not_detected']['instruction']['#markup'] = t('Check that the whole library is located at %library-path.', array(
+ '%library-path' => $library['library path'],
+ )) . '
';
+ }
+ // If the library information was provided by a module, contact the maintainer.
+ // @todo Add support for themes by accessing $library['info type']
+ if (!empty($library['module'])) {
+ $form['status']['not_detected']['help']['#markup'] = t('If yes, the library information is corrupted. Contact the maintainer of the %module module with the following information:', array(
+ '%module' => $provider_info['name'],
+ )) . '
';
+ }
+ // Otherwise contact the author of the info file.
+ elseif (!empty($library['info file'])) {
+ $form['status']['not_detected']['help']['#markup'] = t("If yes, the library's info file (%info-file) is corrupted. Contact the author of this file with the following information:", array(
+ '%info-file' => $library['info file'],
+ )) . '
';
+ }
+ break;
+
+ case 'not supported':
+ // Either download a different version of the library...
+ $versions = array_keys($library['versions']);
+ usort($versions, 'version_compare');
+ $versions = array_reverse($versions);
+ $version = $versions[0];
+ $form['status']['not_supported']['instruction']['#markup'] = t('Please install version %version of the library by following the following steps:', array(
+ '%version' => $version,
+ ));
+ // 1. Delete the old library.
+ $items[] = t('Delete the entire contents of the %library-path directory.', array(
+ '%library-path' => $library['library path'],
+ ));
+ // 2. Download the new library.
+ $items[] = t('Download version %version of the library here.', array(
+ '%version' => $version,
+ '@download-url' => $library['download url'],
+ ));
+ // 3. Unpack it.
+ $items[] = t('If the library is an archive, i.e. if the file ending is for example .tar.gz or .zip, unpack it.');
+ // 4. Upload the new library.
+ // If the library has variant-independent files, give the user the
+ // location of an example file to check his filesystem against.
+ list($filepath, $file) = libraries_get_example_filepath($library);
+ if ($filepath !== FALSE) {
+ $items[] = t('Upload the new files into the %library-path directory. For example, the %file file, should be located at following filepath: %filepath', array(
+ '%library-path' => $library['library path'],
+ '%file' => $file,
+ '%filepath' => $filepath,
+ ));
+ }
+ else {
+ $items[] = t('Upload the new files into the %library-path directory.', array(
+ '%library-path' => $library['library path'],
+ ));
+ }
+ // 5. Reload.
+ $items[] = t('Reload the page. If successful, you should see status information about this library.');
+ $form['status']['not_supported']['steps'] = array(
+ '#theme' => 'item_list',
+ '#items' => $items,
+ '#type' => 'ol',
+ );
+ // ...or contact the maintainer of the library information.
+ // If the library information was provided by a module, contact the maintainer.
+ // @todo Add support for themes by accessing $library['info type']
+ if (!empty($library['module'])) {
+ $form['status']['not_supported']['help']['#markup'] = t('If you are bound to the current version of the library, ask the maintainer of the %module module to provide support for version %version.', array(
+ // @todo Use the human-readable module name instead.
+ '%module' => $provider_info['name'],
+ '%version' => $library['version'],
+ )) . '
';
+ }
+ // Otherwise contact the author of the info file.
+ elseif (!empty($library['info file'])) {
+ $form['status']['not_supported']['help']['#markup'] = t("If you are bound to the current version of the library, ask the author of this library's info file (%info-file) to provide support for version %version", array(
+ '%info-file' => $library['info file'],
+ '%version' => $library['version'],
+ )) . '
';
+ }
+ break;
+
+ case 'missing dependency':
+ $form['status']['missing_dependency']['instruction']['#markup'] = t('There a missing dependency in your configuration that prevent this library to work properly.') . '
';
+ break;
+
+ case 'incompatible dependency':
+ $form['status']['incompatible_dependency']['instruction']['#markup'] = t('There an incompatible dependency in your configuration that prevent this library to work properly.') . '
';
+ break;
+ }
+ }
+
+ return $form;
+}
+
+/**
+ * Returns an example file path and file name from a library, if possible.
+ *
+ * The result of this function can help users to verify that they have uploaded
+ * the library to the correct location.
+ *
+ * @param array $library
+ * A library information array.
+ *
+ * @return array
+ * A list containing the example filepath and the example filename. If no
+ * example file was found, both entries will be FALSE.
+ */
+function libraries_get_example_filepath(array $library) {
+ $filepath = FALSE;
+ $file = FALSE;
+ foreach (array('js', 'css', 'php') as $type) {
+ if (!empty($library['files'][$type])) {
+ $files = array_keys($library['files'][$type]);
+ $filepath = $files[0];
+ $parts = array_reverse(explode('/', $filepath));
+ $file = $parts[0];
+ $filepath = (!empty($library['path']) ? $library['path'] . '/' . $filepath : $filepath);
+ $filepath = 'sites/all/libraries/' . $library['machine name'] . '/' . $filepath;
+ }
+ }
+ return array($filepath, $file);
+}
diff --git a/libraries.module b/libraries.module
index 503c001..d4f4f8e 100644
--- a/libraries.module
+++ b/libraries.module
@@ -33,7 +33,7 @@ function libraries_flush_caches() {
* @param $base_path
* Whether to prefix the resulting path with base_path().
*
- * @return
+ * @return string
* The path to the specified library or FALSE if the library wasn't found.
*
* @ingroup libraries
@@ -67,7 +67,7 @@ function libraries_get_path($name, $base_path = FALSE) {
* in both the site-wide directory and site-specific directory, only the
* site-specific version will be listed.
*
- * @return
+ * @return array
* A list of library directories.
*
* @ingroup libraries
@@ -122,7 +122,7 @@ function libraries_get_libraries() {
* - sites/$sitename/libraries
* - any directories specified via hook_libraries_info_file_paths()
*
- * @return
+ * @return array
* An array of info files, keyed by library name. The values are the paths of
* the files.
*/
@@ -871,3 +871,37 @@ function libraries_get_version($library, $options) {
}
fclose($file);
}
+
+/**
+ * Implements hook_help().
+ */
+function libraries_help($path, $arg) {
+ switch ($path) {
+ case 'admin/reports/libraries':
+ return t('Click on a library for a status report or detailed installation instructions in case the library is not installed correctly.');
+ }
+}
+
+/**
+ * Implements hook_menu().
+ */
+function libraries_menu() {
+ $items = array();
+ $items['admin/reports/libraries'] = array(
+ 'title' => 'Libraries',
+ 'description' => 'An overview of libraries installed on this site.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('libraries_admin_overview'),
+ 'access arguments' => array('access site reports'),
+ 'file' => 'libraries.admin.inc'
+ );
+ $items['admin/reports/libraries/%libraries'] = array(
+ 'title' => 'Library status report',
+ 'description' => 'Status overview for a single library',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('libraries_admin_library_status_form', 3),
+ 'access arguments' => array('access site reports'),
+ 'file' => 'libraries.admin.inc'
+ );
+ return $items;
+}