Index: libraries.api.php =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/libraries/libraries.api.php,v retrieving revision 1.2 diff -u -p -r1.2 libraries.api.php --- libraries.api.php 23 Jul 2010 12:57:01 -0000 1.2 +++ libraries.api.php 26 Aug 2010 13:12:26 -0000 @@ -20,6 +20,10 @@ * - 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. + * - external: (optional) A Boolean indicating whether the library is hosted + * externally. If defined, the 'library path' property has to be predefined + * manually. In case of multiple variants, of which some are external and + * some are not, set this to TRUE. * - version callback: (optional) The name of a function that detects and * returns the full version string of the library. Defaults to * libraries_get_version(). The first argument is always $library, an array @@ -30,6 +34,9 @@ * be declared as an associative array. * - or any number of independent arguments. In this case the version * arguments (see below) must be declared as an indexed array. + * In case the library version is static, the 'version' property may also be + * predefined (without corresponding 'version callback'), so as to not try + * to detect the library's version. * - version arguments: A list of arguments to pass to the version callback. * The default version callback libraries_get_version() expects a single, * associative array with named keys: @@ -303,6 +310,43 @@ function hook_libraries_info() { ), ), ); + + // An example library that is external, because it defines an external + // variant. + $libraries['openlayers'] = array( + 'title' => 'OpenLayers', + 'vendor url' => 'http://www.openlayers.org/', + 'download url' => 'http://openlayers.org/download/', + 'external' => TRUE, + // This should determine which variant is available (the local or the + // remote one) with 'libraries_get_path', and then use + // 'libraries_get_version' conditionally with or without the 'external' flag + // to determine the version. Note that in case of the remote variant the + // library information that is passed to 'libraries_get_version' must be + // padded with the 'library path' property as it is defined below in the + // variant information of the local variant. + 'version callback' => 'openlayers_get_version', + 'variants' => array( + 'local' => array( + 'library path' => 'http://openlayers.org/api', + 'files' => array( + 'js' => array( + // This syntax makes drupal_process_attached() pass the 'external' + // property correctly. + 'OpenLayers.js' => array( + 'type' => 'external', + ), + ), + ), + ), + 'remote' => array( + 'files' => array( + 'js' => array('OpenLayers.js'), + ), + ), + ), + ), + ); return $libraries; } Index: libraries.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/libraries/libraries.module,v retrieving revision 1.6 diff -u -p -r1.6 libraries.module --- libraries.module 23 Jul 2010 12:57:01 -0000 1.6 +++ libraries.module 26 Aug 2010 13:12:26 -0000 @@ -146,6 +146,7 @@ function libraries_info($library = NULL) 'vendor url' => '', 'download url' => '', 'path' => '', + 'external' => FALSE, 'version callback' => 'libraries_get_version', 'version arguments' => array(), 'files' => array(), @@ -208,20 +209,24 @@ function libraries_detect_library(&$libr if (!isset($library['library path'])) { $library['library path'] = libraries_get_path($name); } - if (!file_exists($library['library path'])) { + // @todo Verify 'external' condition in light of PHP stream wrappers and + // http://php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen + if (!$library['external'] && !file_exists($library['library path'])) { $library['error'] = t('%library could not be found.', array('%library' => $library['title'])); return; } - // Detect 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']); + // Detect library version, if not hard-coded. + 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'] = t('The version of %library could not be detected.', array('%library' => $library['title'])); @@ -291,6 +296,9 @@ function libraries_detect_library(&$libr function libraries_load($library, $variant = NULL) { $library = libraries_info($library); libraries_detect_library($library); + if (!$library['installed']) { + return $library['error']; + } libraries_load_files($library, $variant); } @@ -308,7 +316,7 @@ function libraries_load_files($library, // If a variant was specified, override the top-level properties with the // variant properties. - if (!empty($variant) && !empty($library['variants'][$variant]['installed'])) { + if (!empty($variant) && $library['variants'][$variant]['installed']) { $library = array_merge($library, $library['variants'][$variant]); } @@ -378,6 +386,9 @@ function libraries_load_files($library, * - 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. + * - external: (optional) A boolean indicating whether the file is external. + * The 'library path' property must be set to the (external) base path of + * the file in the library declaration. * * @return * A string containing the version of the library. @@ -391,12 +402,17 @@ function libraries_get_version($library, 'pattern' => '', 'lines' => 20, 'cols' => 200, + 'external' => FALSE, ); - $file = DRUPAL_ROOT . '/' . $library['library path'] . '/' . $options['file']; - if (empty($options['file']) || !file_exists($file)) { + // Construct the file path. + $file = $library['library path'] . '/' . $options['file']; + $file = ($options['external'] ? $file : DRUPAL_ROOT . '/' . $file); + + if (empty($library['library path']) || 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)) { Index: tests/libraries.test =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/libraries/tests/libraries.test,v retrieving revision 1.3 diff -u -p -r1.3 libraries.test --- tests/libraries.test 23 Jul 2010 12:57:01 -0000 1.3 +++ tests/libraries.test 26 Aug 2010 13:12:26 -0000 @@ -103,6 +103,16 @@ class LibrariesTestCase extends DrupalWe libraries_detect_library($library); $this->assertEqual($library['variants']['example_variant_1']['installed'], TRUE, 'Existing variant found.'); + // Test external library. + $library = libraries_info('example_external'); + libraries_detect_library($library); + $this->assertEqual($library['installed'], TRUE, 'External library found.'); + + // Test external library with version callback. + $library = libraries_info('example_external_version'); + libraries_detect_library($library); + $this->assertEqual($library['version'], '2', 'Library version of an external library found.'); + // Test loading of a simple library with a top-level files property. $this->drupalGet('libraries_test/simple'); $this->assertRaw('example_installed_1.js', 'A JavaScript file is loaded correctly.'); Index: tests/libraries_test.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/libraries/tests/libraries_test.module,v retrieving revision 1.2 diff -u -p -r1.2 libraries_test.module --- tests/libraries_test.module 23 Jul 2010 12:57:01 -0000 1.2 +++ tests/libraries_test.module 26 Aug 2010 13:12:26 -0000 @@ -276,6 +276,26 @@ function libraries_test_libraries_info() ), ); + // Test detection of an externally hosted library using hard-coded version. + $libraries['example_external'] = array( + 'external' => TRUE, + 'library path' => url(NULL, array('absolute' => TRUE)) . drupal_get_path('module', 'libraries') . '/tests/example', + 'version' => '1.26', + ); + // Test version detection of an externally hosted library. + $libraries['example_external_version'] = array( + 'external' => TRUE, + 'library path' => url(NULL, array('absolute' => TRUE)) . drupal_get_path('module', 'libraries') . '/tests/example', + 'version callback' => 'libraries_get_version', + 'version arguments' => array( + 'file' => 'example_installed.txt', + // Version 2 + 'pattern' => '/Version (\d+)/', + 'lines' => 5, + 'external' => TRUE, + ), + ); + return $libraries; }