Skip to content
Snippets Groups Projects
Commit 9ee03ffe authored by Daniel Kudwien's avatar Daniel Kudwien
Browse files

Preparing new release.

parent dbb7c2d4
Branches
Tags 7.x-1.0
No related merge requests found
Showing
with 2 additions and 1372 deletions
...@@ -2,31 +2,11 @@ ...@@ -2,31 +2,11 @@
Libraries 7.x-1.x, xxxx-xx-xx Libraries 7.x-1.x, xxxx-xx-xx
----------------------------- -----------------------------
#1028744 by tstoeckler: Code clean-up.
#1023322 by tstoeckler, sun: Fixed libraries shouldn't be loaded multiple times.
#1024080 by hswong3i, tstoeckler: Fixed installation profile retrieval.
#995988 by good_man: Wrong default install profile.
#975498 by Gábor Hojtsy: Update JS/CSS-loading to new drupal_add_js/css() API.
#958162 by tsteoeckler, sun: Consistent variable naming.
#924130 by aaronbauman: Fixed libraries_get_path() should use drupal_static().
#958162 by tstoeckler, sun: Code clean-up, tests revamp, more robust loading.
#919632 by tstoeckler, sun: Allow library information to be stored in info files.
by sun: Fixed testbot breaks upon directory name/info file name mismatch.
#864376 by tstoeckler, sun: Code-cleanup, allow hard-coded 'version'.
#939174 by sun, tstoeckler: Rename example.info to libraries_example.info.
by sun: Fixed testbot breaks upon .info file without .module file.
#542940 by tstoeckler, sun: Add libraries-list command.
#919632 by tstoeckler: Add example library info file for testing purposes.
#719896 by tstoeckler, sun: Documentation clean-up and tests improvement.
#542940 by sun: Added initial Drush integration file.
#719896 by tstoeckler, sun: Improved library detection and library loading.
#855050 by Gábor Hojtsy: Avoid call-time pass by reference in libraries_detect().
#719896 by tstoeckler, sun: Added starting point for hook_libraries_info().
#743522 by sun: Ported to D7.
Libraries 6.x-1.x, xxxx-xx-xx Libraries 7.x-1.0, 2010-01-27
----------------------------- -----------------------------
#743522 by sun: Ported to D7.
Libraries 6.x-1.0, 2010-01-27 Libraries 6.x-1.0, 2010-01-27
......
<?php
// $Id$
/**
* @file
* Documents API functions for Libraries module.
*/
/**
* Return information about external libraries.
*
* @return
* An associative array whose keys are internal names of libraries and whose
* values are describing each library. Each key is the directory name below
* the 'libraries' directory, in which the library may be found. Each value is
* an associative array containing:
* - name: The official, human-readable name of the library.
* - vendor url: The URL of the homepage of the library.
* - download url: The URL of a web page on which the library can be obtained.
* - path: (optional) A relative path from the directory of the library to the
* actual library. Only required if the extracted download package contains
* the actual library files in a sub-directory.
* - library path: (optional) The absolute path to the library directory. This
* should not be declared normally, as it is automatically detected, to
* allow for multiple possible library locations. A valid use-case is an
* external library, in which case the full URL to the library should be
* specified here.
* - version: (optional) The version of the library. This should not be
* declared normally, as it is automatically detected (see 'version
* callback' below) to allow for version changes of libraries without code
* changes of implementing modules and to support different versions of a
* library simultaneously (though only one version can be installed per
* site). A valid use-case is an external library whose version cannot be
* determined programatically.
* - version callback: (optional) The name of a function that detects and
* returns the full version string of the library. The first argument is
* always $library, an array containing all library information as described
* here. There are two ways to declare the version callback's additional
* arguments, either as a single $options parameter or as multiple
* parameters, which correspond to the two ways to specify the argument
* values (see 'version arguments'). Defaults to libraries_get_version().
* - version arguments: A list of arguments to pass to the version callback.
* Version arguments can be declared either as an associative array whose
* keys are the argument names or as an indexed array without specifying
* keys. If declared as an associative array, the arguments get passed to
* the version callback as a single $options parameter whose keys are the
* argument names (i.e. $options is identical to the specified array). If
* declared as an indexed array, the array values get passed to the version
* callback as seperate arguments in the order they were declared. The
* default version callback libraries_get_version() expects a single,
* associative array with named keys:
* - file: The filename to parse for the version, relative to the library
* path. For example: 'docs/changelog.txt'.
* - pattern: A string containing a regular expression (PCRE) to match the
* library version. For example: '@version\s+([0-9a-zA-Z\.-]+)@'.
* - lines: (optional) The maximum number of lines to search the pattern in.
* Defaults to 20.
* - cols: (optional) The maximum number of characters per line to take into
* account. Defaults to 200. In case of minified or compressed files, this
* prevents reading the entire file into memory.
* - files: An associative array of library files to load. Supported keys are:
* - js: A list of JavaScript files to load, using the same syntax as Drupal
* core's hook_library().
* - css: A list of CSS files to load, using the same syntax as Drupal
* core's hook_library().
* - php: A list of PHP files to load.
* - variants: (optional) An associative array of available library variants.
* For example, the top-level 'files' property may refer to a default
* variant that is compressed. If the library also ships with a minified and
* uncompressed/source variant, those can be defined here. Each key should
* describe the variant type, e.g. 'minified' or 'source'. Each value is an
* associative array of top-level properties that are entirely overridden by
* the variant, most often just 'files'. Additionally, each variant can
* contain following properties:
* - variant callback: (optional) The name of a function that detects the
* variant and returns TRUE or FALSE, depending on whether the variant is
* available or not. The first argument is always $library, an array
* containing all library information as described here. The second
* argument is always a string containing the variant name. There are two
* ways to declare the variant callback's additinal arguments, either as a
* single $options parameter or as multiple parameters, which correspond
* to the two ways to specify the argument values (see 'variant
* arguments'). If ommitted, the variant is expected to always be
* available.
* - variant arguments: A list of arguments to pass to the variant callback.
* Variant arguments can be declared either as an associative array whose
* keys are the argument names or as an indexed array without specifying
* keys. If declared as an associative array, the arguments get passed to
* the variant callback as a single $options parameter whose keys are the
* argument names (i.e. $options is identical to the specified array). If
* declared as an indexed array, the array values get passed to the
* variant callback as seperate arguments in the order they were declared.
* Variants can be version-specific (see 'versions').
* - versions: (optional) An associative array of supported library versions.
* Naturally, libraries evolve over time and so do their APIs. In case a
* library changes between versions, different 'files' may need to be
* loaded, different 'variants' may become available, or Drupal modules need
* to load different integration files adapted to the new version. Each key
* is a version *string* (PHP does not support floats as keys). Each value
* is an associative array of top-level properties that are entirely
* overridden by the version.
* - integration files: (optional) An associative array whose keys are module
* names and whose values are sets of files to load for the module, using
* the same notion as the top-level 'files' property. Each specified file
* should contain the path to the file relative to the module it belongs to.
* Additional top-level properties can be registered as needed.
*
* @see hook_library()
*/
function hook_libraries_info() {
// The following is a full explanation of all properties. See below for more
// concrete example implementations.
// This array key lets Libraries API search for 'sites/all/libraries/example'
// directory, which should contain the entire, original extracted library.
$libraries['example'] = array(
// Only used in administrative UI of Libraries API.
'title' => 'Example library',
'vendor url' => 'http://example.com',
'download url' => 'http://example.com/download',
// Optional: If, after extraction, the actual library files are contained in
// 'sites/all/libraries/example/lib', specify the relative path here.
'path' => 'lib',
// Optional: Define a custom version detection callback, if required.
'version callback' => 'mymodule_get_version',
// Specify arguments for the version callback. By default,
// libraries_get_version() takes a named argument array:
'version arguments' => array(
'file' => 'docs/CHANGELOG.txt',
'pattern' => '@version\s+([0-9a-zA-Z\.-]+)@',
'lines' => 5,
'cols' => 20,
),
// Default list of files of the library to load. Important: Only specify
// third-party files belonging to the library here, not integration files of
// your module.
'files' => array(
// 'js' and 'css' follow the syntax of hook_library(), but file paths are
// relative to the library path.
'js' => array(
'exlib.js',
'gadgets/foo.js',
),
'css' => array(
'lib_style.css',
'skin/example.css',
),
// For PHP libraries, specify include files here, still relative to the
// library path.
'php' => array(
'exlib.php',
'exlib.inc',
),
),
// Optional: Specify alternative variants of the library, if available.
'variants' => array(
// All properties defined for 'minified' override top-level properties.
'minified' => array(
'files' => array(
'js' => array(
'exlib.min.js',
'gadgets/foo.min.js',
),
'css' => array(
'lib_style.css',
'skin/example.css',
),
),
'variant callback' => 'mymodule_check_variant',
'variant arguments' => array(
'variant' => 'minified',
),
),
),
// Optional, but usually required: Override top-level properties for later
// versions of the library. The properties of the minimum version that is
// matched override the top-level properties. Note:
// - When registering 'versions', it usually does not make sense to register
// 'files', 'variants', and 'integration files' on the top-level, as most
// of those likely need to be different per version and there are no
// defaults.
// - The array keys have to be strings, as PHP does not support floats for
// array keys.
'versions' => array(
'2' => array(
'files' => array(
'js' => array('exlib.js'),
'css' => array('exlib_style.css'),
),
),
'3.0' => array(
'files' => array(
'js' => array('exlib.js'),
'css' => array('lib_style.css'),
),
),
'3.2' => array(
'files' => array(
'js' => array(
'exlib.js',
'gadgets/foo.js',
),
'css' => array(
'lib_style.css',
'skin/example.css',
),
),
),
),
// Optional: Register files to auto-load for your module. All files must be
// keyed by module, and follow the syntax of the 'files' property.
'integration files' => array(
'mymodule' => array(
'js' => array('ex_lib.inc'),
),
),
);
// A very simple library. No changing APIs (hence, no versions), no variants.
// Expected to be extracted into 'sites/all/libraries/simple'.
$libraries['simple'] = array(
'title' => 'Simple library',
'vendor url' => 'http://example.com/simple',
'download url' => 'http://example.com/simple',
'version arguments' => array(
'file' => 'readme.txt',
// Best practice: Document the actual version strings for later reference.
// 1.x: Version 1.0
'pattern' => '/Version (\d+)/',
'lines' => 5,
),
'files' => array(
'js' => array('simple.js'),
),
);
// A library that (naturally) evolves over time with API changes.
$libraries['tinymce'] = array(
'title' => 'TinyMCE',
'vendor url' => 'http://tinymce.moxiecode.com',
'download url' => 'http://tinymce.moxiecode.com/download.php',
'path' => 'jscripts/tiny_mce',
// The regular expression catches two parts (the major and the minor
// version), which libraries_get_version() doesn't allow.
'version callback' => 'tinymce_get_version',
'version arguments' => array(
// It can be easier to parse the first characters of a minified file
// instead of doing a multi-line pattern matching in a source file. See
// 'lines' and 'cols' below.
'file' => 'jscripts/tiny_mce/tiny_mce.js',
// Best practice: Document the actual version strings for later reference.
// 2.x: this.majorVersion="2";this.minorVersion="1.3"
// 3.x: majorVersion:'3',minorVersion:'2.0.1'
'pattern' => '@majorVersion[=:]["\'](\d).+?minorVersion[=:]["\']([\d\.]+)@',
'lines' => 1,
'cols' => 100,
),
'versions' => array(
'2.1' => array(
'files' => array(
'js' => array('tiny_mce.js'),
),
'variants' => array(
'source' => array(
'files' => array(
'js' => array('tiny_mce_src.js'),
),
),
),
'integration files' => array(
'wysiwyg' => array(
'js' => array('editors/js/tinymce-2.js'),
'css' => array('editors/js/tinymce-2.css'),
),
),
),
// Definition used if 3.1 or above is detected.
'3.1' => array(
// Does not support JS aggregation.
'files' => array(
'js' => array(
'tiny_mce.js' => array('preprocess' => FALSE),
),
),
'variants' => array(
// New variant leveraging jQuery. Not stable yet; therefore not the
// default variant.
'jquery' => array(
'files' => array(
'js' => array(
'tiny_mce_jquery.js' => array('preprocess' => FALSE),
),
),
),
'source' => array(
'files' => array(
'js' => array(
'tiny_mce_src.js' => array('preprocess' => FALSE),
),
),
),
),
'integration files' => array(
'wysiwyg' => array(
'js' => array('editors/js/tinymce-3.js'),
'css' => array('editors/js/tinymce-3.css'),
),
),
),
),
);
return $libraries;
}
/**
* Alter the library information before detection and caching takes place.
*
* The library definitions are passed by reference. A common use-case is adding
* a module's integration files to the library array, so that the files are
* loaded whenever the library is. As noted above, it is important to declare
* integration files inside of an array, whose key is the module name.
*
* @see hook_libraries_info()
*/
function hook_libraries_info_alter(&$libraries) {
$files = array(
'php' => array('example_module.php_spellchecker.inc'),
);
$libraries['php_spellchecker']['integration files']['example_module'] = $files;
}
/**
* Specify paths to look for library info files.
*
* Libraries API looks in the following directories for library info files by
* default:
* - libraries
* - profiles/$profile/libraries
* - sites/all/libraries
* - sites/$site/libraries
* This hook allows you to specify additional locations to look for library info
* files. This should only be used for modules that declare many libraries.
* Modules that only implement a few libraries should implement
* hook_libraries_info().
*
* @return
* An array of paths.
*/
function hook_libraries_paths() {
// Taken from the Libraries test module, which needs to specify the path to
// the test library.
return array(drupal_get_path('module', 'libraries_test') . '/example');
}
<?php
// $Id$
/**
* @file
* Drush integration for Libraries API.
*/
/**
* Implements hook_drush_command().
*/
function libraries_drush_command() {
$items['libraries-list'] = array(
'callback' => 'libraries_drush_list',
'description' => dt('Lists registered library information.'),
'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
);
/**$items['libraries-download'] = array(
'callback' => 'libraries_drush_download',
'description' => dt('Downloads a registered library into the libraries directory for the active site.'),
'arguments' => array(
'name' => dt('The internal name of the registered library.'),
),
);*/
return $items;
}
/**
* Implements hook_drush_help().
*/
function libraries_drush_help($section) {
switch ($section) {
case 'drush:libraries-list':
return dt('Lists registered library information.');
case 'drush:libraries-download':
return dt('Downloads a registered library into the libraries directory for the active site.
See libraries-list for a list of registered libraries.');
}
}
/**
* Lists registered library information.
*/
function libraries_drush_list() {
$libraries = libraries_detect(libraries_info());
ksort($libraries);
if (empty($libraries)) {
drush_print('There are no registered libraries.');
}
else {
$header = array('Name', 'Status', 'Version', 'Variants');
$rows = array();
foreach ($libraries as $name => $library) {
// Status and version
if ($library['installed']) {
$status = 'OK';
$version = $library['version'];
}
else {
$status = drupal_ucfirst($library['error']);
$version = (empty($library['version']) ? '-' : $library['version']);
}
// Variants
$variants = array();
foreach ($library['variants'] as $variant_name => $variant) {
if ($variant['installed']) {
$variants[] = $variant_name;
}
}
if (empty($variants)) {
$variants = '-';
}
else {
$variants = implode(', ', $variants);
}
$rows[] = array($name, $status, $version, $variants);
}
$table = new Console_Table();
drush_print($table->fromArray($header, $rows));
}
}
/**
* Downloads a library.
*
* @param $name
* The internal name of the library to download.
*/
function libraries_drush_download($name) {
return;
// @todo Looks wonky?
if (!drush_shell_exec('type unzip')) {
return drush_set_error(dt('Missing dependency: unzip. Install it before using this command.'));
}
// @todo Simply use current drush site.
$args = func_get_args();
if ($args[0]) {
$path = $args[0];
}
else {
$path = 'sites/all/libraries';
}
// Create the path if it does not exist.
if (!is_dir($path)) {
drush_op('mkdir', $path);
drush_log(dt('Directory @path was created', array('@path' => $path)), 'notice');
}
// Set the directory to the download location.
$olddir = getcwd();
chdir($path);
$filename = basename(COLORBOX_DOWNLOAD_URI);
$dirname = basename(COLORBOX_DOWNLOAD_URI, '.zip');
// Remove any existing Colorbox plugin directory
if (is_dir($dirname)) {
drush_log(dt('A existing Colorbox plugin was overwritten at @path', array('@path' => $path)), 'notice');
}
// Remove any existing Colorbox plugin zip archive
if (is_file($filename)) {
drush_op('unlink', $filename);
}
// Download the zip archive
if (!drush_shell_exec('wget '. COLORBOX_DOWNLOAD_URI)) {
drush_shell_exec('curl -O '. COLORBOX_DOWNLOAD_URI);
}
if (is_file($filename)) {
// Decompress the zip archive
drush_shell_exec('unzip -qq -o '. $filename);
// Remove the zip archive
drush_op('unlink', $filename);
}
// Set working directory back to the previous working directory.
chdir($olddir);
if (is_dir($path .'/'. $dirname)) {
drush_log(dt('Colorbox plugin has been downloaded to @path', array('@path' => $path)), 'success');
}
else {
drush_log(dt('Drush was unable to download the Colorbox plugin to @path', array('@path' => $path)), 'error');
}
}
...@@ -2,4 +2,3 @@ ...@@ -2,4 +2,3 @@
name = Libraries name = Libraries
description = Allows version dependent and shared usage of external libraries. description = Allows version dependent and shared usage of external libraries.
core = 7.x core = 7.x
files[] = tests/libraries.test
...@@ -102,405 +102,3 @@ function libraries_get_libraries() { ...@@ -102,405 +102,3 @@ function libraries_get_libraries() {
return $directories; return $directories;
} }
/**
* Looks for library info files.
*
* This function scans the following directories for info files:
* - libraries
* - profiles/$profilename/libraries
* - sites/all/libraries
* - sites/$sitename/libraries
* - any directories specified via hook_libraries_info_file_paths()
*
* @return
* An array of info files, keyed by library name. The values are the paths of
* the files.
*/
function libraries_scan_info_files() {
$profile = drupal_get_profile();
$config = conf_path();
// Build a list of directories.
$directories = module_invoke_all('libraries_info_file_paths');
$directories[] = 'libraries';
$directories[] = "profiles/$profile/libraries";
$directories[] = 'sites/all/libraries';
$directories[] = "$config/libraries";
// Scan for info files.
$files = array();
foreach ($directories as $dir) {
if (file_exists($dir)) {
$files = array_merge($files, file_scan_directory($dir, '@^[a-z0-9._-]+\.libraries\.info$@', array(
'key' => 'name',
'recurse' => FALSE,
)));
}
}
foreach ($files as $filename => $file) {
$files[basename($filename, '.libraries')] = $file;
unset($files[$filename]);
}
return $files;
}
/**
* Returns information about registered libraries.
*
* The returned information is unprocessed, i.e. as registered by modules.
*
* @param $name
* (optional) The machine name of a library to return registered information
* for, or FALSE if no library with the given name exists. If omitted,
* information about all libraries is returned.
*
* @return
* An associative array containing registered information for all libraries,
* or the registered information for the library specified by $name.
*
* @see hook_libraries_info()
*
* @todo Re-introduce support for include file plugin system - either by copying
* Wysiwyg's code, or directly switching to CTools.
*/
function libraries_info($name = NULL) {
$libraries = &drupal_static(__FUNCTION__);
if (!isset($libraries)) {
$libraries = array();
// Gather information from hook_libraries_info().
foreach (module_implements('libraries_info') as $module) {
foreach (module_invoke($module, 'libraries_info') as $machine_name => $properties) {
$properties['module'] = $module;
$libraries[$machine_name] = $properties;
}
}
// Gather information from .info files.
// .info files override module definitions.
foreach (libraries_scan_info_files() as $machine_name => $file) {
$properties = drupal_parse_info_file($file->uri);
$properties['info file'] = $file->uri;
$libraries[$machine_name] = $properties;
}
// Provide defaults.
foreach ($libraries as $machine_name => &$properties) {
$properties += array(
'machine name' => $machine_name,
'name' => $machine_name,
'vendor url' => '',
'download url' => '',
'path' => '',
'library path' => NULL,
'version callback' => 'libraries_get_version',
'version arguments' => array(),
'files' => array(),
'variants' => array(),
'versions' => array(),
'integration files' => array(),
);
}
// Allow modules to alter the registered libraries.
drupal_alter('libraries_info', $libraries);
}
if (isset($name)) {
return !empty($libraries[$name]) ? $libraries[$name] : FALSE;
}
return $libraries;
}
/**
* Detect libraries and library versions.
*
* @todo We need to figure out whether, and if, how we want to retain the
* processed information. I.e. either use a static cache here, or make
* libraries_info() conditionally invoke libraries_detect($name). D7 only way:
* Re-use drupal_static() of libraries_info() - but would still require to
* update the (DB) cache (there likely will be one soon). Also, we probably do
* not want to ALWAYS parse ALL possible libraries; rather, the
* requesting/consuming module likely wants to know whether a list of
* supported libraries (possibly those registered by itself, or in a certain
* "category") is available... Food for thought.
*
* @param $libraries
* An array of libraries to detect, as returned from libraries_info().
*
* @see libraries_info()
*/
function libraries_detect($libraries) {
foreach ($libraries as &$library) {
$library = libraries_detect_library($library);
}
return $libraries;
}
/**
* Tries to detect a library and its installed version.
*
* @param $library
* An associative array describing a single library, as returned from
* libraries_info().
*/
function libraries_detect_library($library) {
$library['installed'] = FALSE;
// Check whether the library exists.
if (!isset($library['library path'])) {
$library['library path'] = libraries_get_path($library['machine name']);
}
if (!file_exists($library['library path'])) {
$library['error'] = 'not found';
$library['error message'] = t('The %library library could not be found.', array(
'%library' => $library['name'],
));
return;
}
// Detect library version, if not hardcoded.
if (!isset($library['version'])) {
// We support both a single parameter, which is an associative array, and an
// indexed array of multiple parameters.
if (isset($library['version arguments'][0])) {
// Add the library as the first argument.
$library['version'] = call_user_func_array($library['version callback'], array_merge(array($library), $library['version arguments']));
}
else {
$library['version'] = $library['version callback']($library, $library['version arguments']);
}
if (empty($library['version'])) {
$library['error'] = 'not detected';
$library['error message'] = t('The version of the %library library could not be detected.', array(
'%library' => $library['name'],
));
return;
}
}
// Determine to which supported version the installed version maps.
if (!empty($library['versions'])) {
ksort($library['versions']);
$version = 0;
foreach ($library['versions'] as $supported_version => $version_properties) {
if (version_compare($library['version'], $supported_version, '>=')) {
$version = $supported_version;
}
}
if (!$version) {
$library['error'] = 'not supported';
$library['error message'] = t('The installed version %version of the %library library is not supported.', array(
'%version' => $library['version'],
'%library' => $library['name'],
));
return;
}
// Apply version specific definitions and overrides.
$library = array_merge($library, $library['versions'][$version]);
unset($library['versions']);
}
// Check each variant if it is installed.
if (!empty($library['variants'])) {
foreach ($library['variants'] as $variant_name => &$variant) {
// If no variant callback has been set, assume the variant to be
// installed.
if (!isset($variant['variant callback'])) {
$variant['installed'] = TRUE;
}
else {
// We support both a single parameter, which is an associative array,
// and an indexed array of multiple parameters.
if (isset($variant['variant arguments'][0])) {
// Add the library as the first argument, and the variant name as the second.
$variant['installed'] = call_user_func_array($variant['variant callback'], array_merge(array($library, $variant_name), $variant['variant arguments']));
}
else {
$variant['installed'] = $variant['variant callback']($library, $variant_name, $variant['variant arguments']);
}
if (!$variant['installed']) {
$variant['error'] = 'not found';
$variant['error message'] = t('The %variant variant of the %library library could not be found.', array(
'%variant' => $variant_name,
'%library' => $library['name'],
));
}
}
}
}
// If we end up here, the library should be usable.
$library['installed'] = TRUE;
return $library;
}
/**
* Loads a library.
*
* @param $name
* The name of the library to load.
* @param $variant
* The name of the variant to load. Note that only one variant of a library
* can be loaded within a single request. The variant that has been passed
* first is used; different variant names in subsequent calls are ignored.
*
* @return
* An associative array of the library information as returned from
* libraries_info(). The top-level properties contain the effective definition
* of the library (variant) that has been loaded. Additionally:
* - installed: Whether the library is installed, as determined by
* libraries_detect_library().
* - loaded: Either the amount of library files that have been loaded, or
* FALSE if the library could not be loaded.
* See hook_libraries_info() for more information.
*/
function libraries_load($name, $variant = NULL) {
$loaded = &drupal_static(__FUNCTION__, array());
if (!isset($loaded[$name])) {
$library = libraries_detect_library(libraries_info($name));
// If a variant was specified, override the top-level properties with the
// variant properties.
if (isset($variant)) {
// Ensure that the $variant key exists, and if it does not, set its
// 'installed' property to FALSE by default. This will prevent the loading
// of the library files below.
$library['variants'] += array($variant => array('installed' => FALSE));
$library = array_merge($library, $library['variants'][$variant]);
}
// Regardless of whether a specific variant was requested or not, there can
// only be one variant of a library within a single request.
unset($library['variants']);
// If the library (variant) is installed, load it.
$library['loaded'] = FALSE;
if ($library['installed']) {
$library['loaded'] = libraries_load_files($library);
}
$loaded[$name] = $library;
}
return $loaded[$name];
}
/**
* Loads a library's files.
*
* @param $library
* An array of library information as returned by libraries_info().
*
* @return
* The number of loaded files.
*/
function libraries_load_files($library) {
// Load integration files.
if (!empty($library['integration files'])) {
foreach ($library['integration files'] as $module => $files) {
libraries_load_files(array(
'files' => $files,
'path' => '',
'library path' => drupal_get_path('module', $module),
));
}
}
// Construct the full path to the library for later use.
$path = $library['library path'];
$path = ($library['path'] !== '' ? $path . '/' . $library['path'] : $path);
// Count the number of loaded files for the return value.
$count = 0;
// Load both the JavaScript and the CSS files.
// The parameters for drupal_add_js() and drupal_add_css() require special
// handling.
// @see drupal_process_attached()
foreach (array('js', 'css') as $type) {
if (!empty($library['files'][$type])) {
foreach ($library['files'][$type] as $data => $options) {
// If the value is not an array, it's a filename and passed as first
// (and only) argument.
if (!is_array($options)) {
// Prepend the library path to the file name.
$data = "$path/$options";
$options = NULL;
}
// In some cases, the first parameter ($data) is an array. Arrays can't
// be passed as keys in PHP, so we have to get $data from the value
// array.
if (is_numeric($data)) {
$data = $options['data'];
unset($options['data']);
}
// Apply the default group if the group isn't explicitly given.
if (!isset($options['group'])) {
$options['group'] = ($type == 'js') ? JS_DEFAULT : CSS_DEFAULT;
}
call_user_func('drupal_add_' . $type, $data, $options);
$count++;
}
}
}
// Load PHP files.
if (!empty($library['files']['php'])) {
foreach ($library['files']['php'] as $file) {
$file_path = DRUPAL_ROOT . '/' . $path . '/' . $file;
if (file_exists($file_path)) {
require_once $file_path;
$count++;
}
}
}
return $count;
}
/**
* Gets the version information from an arbitrary library.
*
* @param $library
* An associative array containing all information about the library.
* @param $options
* An associative array containing with the following keys:
* - file: The filename to parse for the version, relative to the library
* path. For example: 'docs/changelog.txt'.
* - pattern: A string containing a regular expression (PCRE) to match the
* library version. For example: '@version\s+([0-9a-zA-Z\.-]+)@'.
* - lines: (optional) The maximum number of lines to search the pattern in.
* Defaults to 20.
* - cols: (optional) The maximum number of characters per line to take into
* account. Defaults to 200. In case of minified or compressed files, this
* prevents reading the entire file into memory.
*
* @return
* A string containing the version of the library.
*
* @see libraries_get_path()
*/
function libraries_get_version($library, $options) {
// Provide defaults.
$options += array(
'file' => '',
'pattern' => '',
'lines' => 20,
'cols' => 200,
);
$file = DRUPAL_ROOT . '/' . $library['library path'] . '/' . $options['file'];
if (empty($options['file']) || !file_exists($file)) {
return;
}
$file = fopen($file, 'r');
while ($options['lines'] && $line = fgets($file, $options['cols'])) {
if (preg_match($options['pattern'], $line, $version)) {
fclose($file);
return $version[1];
}
$options['lines']--;
}
fclose($file);
}
; $Id$
Example library
Version 1
This file is an example file to test version detection.
The various other files in this directory are to test the loading of JavaScript,
CSS and PHP files.
- JavaScript: The filenames of the JavaScript files are asserted to be in the
raw HTML via SimpleTest. Since the filename could appear, for instance, in an
error message, this is not very robust. Explicit testing of JavaScript,
though, is not yet possible with SimpleTest. To allow for easier debugging, we
place the following text on the page:
"If this text shows up, no JavaScript test file was loaded."
This text is replaced via JavaScript by a text of the form:
"If this text shows up, [[file] was loaded successfully."
[file] is either 'example_1.js', 'example_2.js', 'example_3.js',
'example_4.js' or 'libraries_test.js'. If you have SimpleTest's verbose mode
enabled and see the above text in one of the debug pages, the noted JavaScript
file was loaded successfully.
- CSS: The filenames of the CSS files are asserted to be in the raw HTML via
SimpleTest. Since the filename could appear, for instance, in an error
message, this is not very robust. Explicit testing of CSS, though, is not yet
possible with SimpleTest. Hence, the CSS files, if loaded, make the following
text a certain color:
"If one of the CSS test files has been loaded, this text will be colored:
- example_1: red
- example_2: green
- example_3: orange
- example_4: blue
- libraries_test: purple"
If you have SimpleTest's verbose mode enabled, and see the above text in a
certain color (i.e. not in black), a CSS file was loaded successfully. Which
file depends on the color as referenced in the text above.
- PHP: The loading of PHP files is tested by defining a dummy function in the
PHP files and then checking whether this function was defined using
function_exists(). This can be checked programatically with SimpleTest.
The loading of integration files is tested with the same method. The integration
files are libraries_test.js, libraries_test.css, libraries_test.inc and are
located in the tests directory alongside libraries_test.module (i.e. they are
not in the same directory as this file).
/* $Id$ */
/**
* @file
* Test CSS file for Libraries loading.
*
* Color the 'libraries-test-css' div red. See README.txt for more information.
*/
.libraries-test-css {
color: red;
}
// $Id$
/**
* @file
* Test JavaScript file for Libraries loading.
*
* Replace the text in the 'libraries-test-javascript' div. See README.txt for
* more information.
*/
(function ($) {
Drupal.behaviors.librariesTest = {
attach: function(context, settings) {
$('.libraries-test-javascript').text('If this text shows up, example_1.js was loaded successfully.')
}
};
})(jQuery);
<?php
// $Id$
/**
* @file
* Test PHP file for Libraries loading.
*/
/**
* Dummy function to see if this file was loaded.
*/
function _libraries_test_example_1() {
}
/* $Id$ */
/**
* @file
* Test CSS file for Libraries loading.
*
* Color the 'libraries-test-css' div green. See README.txt for more information.
*/
.libraries-test-css {
color: green;
}
// $Id$
/**
* @file
* Test JavaScript file for Libraries loading.
*
* Replace the text in the 'libraries-test-javascript' div. See README.txt for
* more information.
*/
(function ($) {
Drupal.behaviors.librariesTest = {
attach: function(context, settings) {
$('.libraries-test-javascript').text('If this text shows up, example_2.js was loaded successfully.')
}
};
})(jQuery);
<?php
// $Id$
/**
* @file
* Test PHP file for Libraries loading.
*/
/**
* Dummy function to see if this file was loaded.
*/
function _libraries_test_example_2() {
}
/* $Id$ */
/**
* @file
* Test CSS file for Libraries loading.
*
* Color the 'libraries-test-css' div orange. See README.txt for more information.
*/
.libraries-test-css {
color: orange;
}
// $Id$
/**
* @file
* Test JavaScript file for Libraries loading.
*
* Replace the text in the 'libraries-test-javascript' div. See README.txt for
* more information.
*/
(function ($) {
Drupal.behaviors.librariesTest = {
attach: function(context, settings) {
$('.libraries-test-javascript').text('If this text shows up, example_3.js was loaded successfully.')
}
};
})(jQuery);
<?php
// $Id$
/**
* @file
* Test PHP file for Libraries loading.
*/
/**
* Dummy function to see if this file was loaded.
*/
function _libraries_test_example_3() {
}
/* $Id$ */
/**
* @file
* Test CSS file for Libraries loading.
*
* Color the 'libraries-test-css' div blue. See README.txt for more information.
*/
.libraries-test-css {
color: blue;
}
// $Id$
/**
* @file
* Test JavaScript file for Libraries loading.
*
* Replace the text in the 'libraries-test-javascript' div. See README.txt for
* more information.
*/
(function ($) {
Drupal.behaviors.librariesTest = {
attach: function(context, settings) {
$('.libraries-test-javascript').text('If this text shows up, example_4.js was loaded successfully.')
}
};
})(jQuery);
<?php
// $Id$
/**
* @file
* Test PHP file for Libraries loading.
*/
/**
* Dummy function to see if this file was loaded.
*/
function _libraries_test_example_4() {
}
; $Id$
; This is an example info file of a library used for testing purposes.
name = Example info file
<?php
// $Id$
/**
* @file
* Tests for Libraries API.
*/
/**
* Tests basic detection and loading of libraries.
*/
class LibrariesTestCase extends DrupalWebTestCase {
protected $profile = 'testing';
public static function getInfo() {
return array(
'name' => 'Libraries detection and loading',
'description' => 'Tests detection and loading of libraries.',
'group' => 'Libraries API',
);
}
function setUp() {
parent::setUp('libraries', 'libraries_test');
}
/**
* Tests libraries detection and loading.
*
* @todo Better method name(s); split into detection/loading/overloading/etc.
*/
function testLibraries() {
// Test that library information is found correctly.
$expected = array_merge(libraries_info('example_empty'), array(
'machine name' => 'example_files',
'name' => 'Example files',
'library path' => drupal_get_path('module', 'libraries') . '/tests/example',
'version' => '1',
'files' => array(
'js' => array('example_1.js'),
'css' => array('example_1.css'),
'php' => array('example_1.php'),
),
));
$library = libraries_info('example_files');
$this->verbose(var_export($expected, TRUE));
$this->verbose(var_export($library, TRUE));
$this->assertEqual($library, $expected, 'Library information is correctly gathered.');
// Test a library specified with an .info file gets detected.
$expected = array_merge(libraries_info('example_empty'), array(
'machine name' => 'example_info_file',
'name' => 'Example info file',
'info file' => drupal_get_path('module', 'libraries_test') . '/example/example_info_file.libraries.info',
));
unset($expected['module']);
$library = libraries_info('example_info_file');
$this->verbose(var_export($expected, TRUE));
$this->verbose(var_export($library, TRUE));
$this->assertEqual($library, $expected, 'Library specified with an .info file found');
// Test missing library.
$library = libraries_info('example_missing');
libraries_detect_library($library);
$this->verbose(var_export($library, TRUE));
$this->assertEqual($library['error'], 'not found', 'Missing library not found.');
$error_message = t('The %library library could not be found.', array(
'%library' => $library['name'],
));
$this->assertEqual($library['error message'], $error_message, 'Correct error message for a missing library.');
// Test unknown library version.
$library = libraries_info('example_undetected_version');
libraries_detect_library($library);
$this->verbose(var_export($library, TRUE));
$this->assertEqual($library['error'], 'not detected', 'Undetected version detected as such.');
$error_message = t('The version of the %library library could not be detected.', array(
'%library' => $library['name'],
));
$this->assertEqual($library['error message'], $error_message, 'Correct error message for a library with an undetected version.');
// Test unsupported library version.
$library = libraries_info('example_unsupported_version');
libraries_detect_library($library);
$this->verbose(var_export($library, TRUE));
$this->assertEqual($library['error'], 'not supported', 'Unsupported version detected as such.');
$error_message = t('The installed version %version of the %library library is not supported.', array(
'%version' => $library['version'],
'%library' => $library['name'],
));
$this->assertEqual($library['error message'], $error_message, 'Correct error message for a library with an unsupported version.');
// Test supported library version.
$library = libraries_info('example_supported_version');
libraries_detect_library($library);
$this->verbose(var_export($library, TRUE));
$this->assertEqual($library['installed'], TRUE, 'Supported library version found.');
// Test libraries_get_version().
$library = libraries_info('example_default_version_callback');
libraries_detect_library($library);
$this->verbose(var_export($library, TRUE));
$this->assertEqual($library['version'], '1', 'Expected version returned by default version callback.');
// Test a multiple-parameter version callback.
$library = libraries_info('example_multiple_parameter_version_callback');
libraries_detect_library($library);
$this->verbose(var_export($library, TRUE));
$this->assertEqual($library['version'], '1', 'Expected version returned by multiple parameter version callback.');
// Test a top-level files property.
$library = libraries_info('example_files');
libraries_detect_library($library);
$files = array(
'js' => array('example_1.js'),
'css' => array('example_1.css'),
'php' => array('example_1.php'),
);
$this->verbose(var_export($library, TRUE));
$this->assertEqual($library['files'], $files, 'Top-level files property works.');
// Test version-specific library files.
$library = libraries_info('example_versions');
libraries_detect_library($library);
$files = array(
'js' => array('example_2.js'),
'css' => array('example_2.css'),
'php' => array('example_2.php'),
);
$this->verbose(var_export($library, TRUE));
$this->assertEqual($library['files'], $files, 'Version-specific library files found.');
// Test missing variant.
$library = libraries_info('example_variant_missing');
libraries_detect_library($library);
$variants = array_keys($library['variants']);
$this->verbose(var_export($library, TRUE));
$this->assertEqual($library['variants']['example_variant']['error'], 'not found', 'Missing variant not found');
$error_message = t('The %variant variant of the %library library could not be found.', array(
'%variant' => $variants[0],
'%library' => $library['name'],
));
$this->assertEqual($library['variants']['example_variant']['error message'], $error_message, 'Correct error message for a missing variant.');
// Test existing variant.
$library = libraries_info('example_variant');
libraries_detect_library($library);
$this->verbose(var_export($library, TRUE));
$this->assertEqual($library['variants']['example_variant']['installed'], TRUE, 'Existing variant found.');
// Test loading of a simple library with a top-level files property.
$this->drupalGet('libraries_test/files');
$this->assertLibraryFiles('example_1', 'File loading');
// Test loading of integration files.
$this->drupalGet('libraries_test/integration_files');
$this->assertRaw('libraries_test.js', 'Integration file loading: libraries_test.js found');
$this->assertRaw('libraries_test.css', 'Integration file loading: libraries_test.css found');
$this->assertRaw('libraries_test.inc', 'Integration file loading: libraries_test.inc found');
// Test version overloading.
$this->drupalGet('libraries_test/versions');
$this->assertLibraryFiles('example_2', 'Version overloading');
// Test variant loading.
$this->drupalGet('libraries_test/variant');
$this->assertLibraryFiles('example_3', 'Variant loading');
// Test version overloading and variant loading.
$this->drupalGet('libraries_test/versions_and_variants');
$this->assertLibraryFiles('example_4', 'Concurrent version and variant overloading');
}
/**
* Helper function to assert that a library was correctly loaded.
*
* Asserts that all the correct files were loaded and all the incorrect ones
* were not.
*
* @param $name
* The name of the files that should be loaded. The current testing system
* knows of 'example_1', 'example_2', 'example_3' and 'example_4'. Each name
* has an associated JavaScript, CSS and PHP file that will be asserted. All
* other files will be asserted to not be loaded. See
* tests/example/README.txt for more information on how the loading of the
* files is tested.
* @param $label
* (optional) A label to prepend to the assertion messages, to make them
* less ambiguous.
* @param $extensions
* (optional) The expected file extensions of $name. Defaults to
* array('js', 'css', 'php').
*/
function assertLibraryFiles($name, $label = '', $extensions = array('js', 'css', 'php')) {
$names = drupal_map_assoc(array('example_1', 'example_2', 'example_3', 'example_4'));
unset($names[$name]);
// Test that the wrong files are not loaded.
foreach ($names as $filename) {
foreach ($extensions as $extension) {
$message = "$filename.$extension not found";
$message = ($label !== '' ? "$label: $message" : $message);
$this->assertNoRaw("$filename.$extension", $message);
}
}
// Test that the correct files are loaded.
foreach ($extensions as $extension) {
$message = "$name.$extension found";
$message = ($label !== '' ? "$label: $message" : $message);
$this->assertRaw("$name.$extension", $message);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment