libraries/0000755001412200141220000000000012116665234012312 5ustar benderbenderlibraries/libraries.install0000644001412200141220000000126112116664161015654 0ustar benderbender '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 = array(); foreach (libraries_info() as $name => $info) { $libraries[$name] = libraries_detect($name); } ksort($libraries); if (empty($libraries)) { drush_print('There are no registered libraries.'); } else { $rows = array(); // drush_print_table() automatically treats the first row as the header, if // $header is TRUE. $rows[] = array(dt('Name'), dt('Status'), dt('Version'), dt('Variants'), dt('Dependencies')); foreach ($libraries as $name => $library) { $status = ($library['installed'] ? dt('OK') : drupal_ucfirst($library['error'])); $version = (($library['installed'] && !empty($library['version'])) ? $library['version'] : '-'); // Only list installed variants. $variants = array(); foreach ($library['variants'] as $variant_name => $variant) { if ($variant['installed']) { $variants[] = $variant_name; } } $variants = (empty($variants) ? '-' : implode(', ', $variants)); $dependencies = (!empty($library['dependencies']) ? implode(', ', $library['dependencies']) : '-'); $rows[] = array($name, $status, $version, $variants, $dependencies); } // Make the possible values for the 'Status' column and the 'Version' header // wrap nicely. $widths = array(0, 12, 7, 0, 0); drush_print_table($rows, TRUE, $widths); } } /** * 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'); } } libraries/LICENSE.txt0000664001412200141220000004325411635213033014136 0ustar benderbender GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. libraries/tests/0000755001412200141220000000000012116664161013452 5ustar benderbenderlibraries/tests/libraries.test0000644001412200141220000005742212116664161016341 0ustar benderbender 'Libraries API unit tests', 'description' => 'Tests basic functions provided by Libraries API.', 'group' => 'Libraries API', ); } function setUp() { drupal_load('module', 'libraries'); parent::setUp(); } /** * Tests libraries_get_path(). */ function testLibrariesGetPath() { // Note that, even though libraries_get_path() doesn't find the 'example' // library, we are able to make it 'installed' by specifying the 'library // path' up-front. This is only used for testing purposed and is strongly // discouraged as it defeats the purpose of Libraries API in the first // place. $this->assertEqual(libraries_get_path('example'), FALSE, 'libraries_get_path() returns FALSE for a missing library.'); } /** * Tests libraries_prepare_files(). */ function testLibrariesPrepareFiles() { $expected = array( 'files' => array( 'js' => array('example.js' => array()), 'css' => array('example.css' => array()), 'php' => array('example.php' => array()), ), ); $library = array( 'files' => array( 'js' => array('example.js'), 'css' => array('example.css'), 'php' => array('example.php'), ), ); libraries_prepare_files($library, NULL, NULL); $this->assertEqual($expected, $library, 'libraries_prepare_files() works correctly.'); } } /** * 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_detect_dependencies(). */ function testLibrariesDetectDependencies() { $library = array( 'name' => 'Example', 'dependencies' => array('example_missing'), ); libraries_detect_dependencies($library); $this->assertEqual($library['error'], 'missing dependency', 'libraries_detect_dependencies() detects missing dependency'); $error_message = t('The %dependency library, which the %library library depends on, is not installed.', array( '%dependency' => 'Example missing', '%library' => $library['name'], )); $this->verbose("Expected:
$error_message"); $this->verbose('Actual:
' . $library['error message']); $this->assertEqual($library['error message'], $error_message, 'Correct error message for a missing dependency'); // Test versioned dependencies. $version = '1.1'; $compatible = array( '1.1', '<=1.1', '>=1.1', '<1.2', '<2.0', '>1.0', '>1.0-rc1', '>1.0-beta2', '>1.0-alpha3', '>0.1', '<1.2, >1.0', '>0.1, <=1.1', ); $incompatible = array( '1.2', '2.0', '<1.1', '>1.1', '<=1.0', '<=1.0-rc1', '<=1.0-beta2', '<=1.0-alpha3', '>=1.2', '<1.1, >0.9', '>=0.1, <1.1', ); $library = array( 'name' => 'Example', ); foreach ($compatible as $version_string) { $library['dependencies'][0] = "example_dependency ($version_string)"; // libraries_detect_dependencies() is a post-detect callback, so // 'installed' is already set, when it is called. It sets the value to // FALSE for missing or incompatible dependencies. $library['installed'] = TRUE; libraries_detect_dependencies($library); $this->assertTrue($library['installed'], "libraries_detect_dependencies() detects compatible version string: '$version_string' is compatible with '$version'"); } foreach ($incompatible as $version_string) { $library['dependencies'][0] = "example_dependency ($version_string)"; $library['installed'] = TRUE; unset($library['error'], $library['error message']); libraries_detect_dependencies($library); $this->assertEqual($library['error'], 'incompatible dependency', "libraries_detect_dependencies() detects incompatible version strings: '$version_string' is incompatible with '$version'"); } // Instead of repeating this assertion for each version string, we just // re-use the $library variable from the foreach loop. $error_message = t('The version %dependency_version of the %dependency library is not compatible with the %library library.', array( '%dependency_version' => $version, '%dependency' => 'Example dependency', '%library' => $library['name'], )); $this->verbose("Expected:
$error_message"); $this->verbose('Actual:
' . $library['error message']); $this->assertEqual($library['error message'], $error_message, 'Correct error message for an incompatible dependency'); } /** * Tests libraries_scan_info_files(). */ function testLibrariesScanInfoFiles() { $expected = array('example_info_file' => (object) array( 'uri' => drupal_get_path('module', 'libraries') . '/tests/example/example_info_file.libraries.info', 'filename' => 'example_info_file.libraries.info', 'name' => 'example_info_file.libraries', )); $this->assertEqual(libraries_scan_info_files(), $expected, 'libraries_scan_info_files() correctly finds the example info file.'); $this->verbose('
' . var_export(libraries_scan_info_files(), TRUE) . '
'); } /** * Tests libraries_info(). */ function testLibrariesInfo() { // Test that library information is found correctly. $expected = array( 'name' => 'Example files', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version' => '1', 'files' => array( 'js' => array('example_1.js' => array()), 'css' => array('example_1.css' => array()), 'php' => array('example_1.php' => array()), ), 'module' => 'libraries_test', ); libraries_info_defaults($expected, 'example_files'); $library = libraries_info('example_files'); $this->verbose('Expected:
' . var_export($expected, TRUE) . '
'); $this->verbose('Actual:
' . 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( 'name' => 'Example info file', 'info file' => drupal_get_path('module', 'libraries_test') . '/example/example_info_file.libraries.info', ); libraries_info_defaults($expected, 'example_info_file'); $library = libraries_info('example_info_file'); // If this module was downloaded from Drupal.org, the Drupal.org packaging // system has corrupted the test info file. // @see http://drupal.org/node/1606606 unset($library['core'], $library['datestamp'], $library['project'], $library['version']); $this->verbose('Expected:
' . var_export($expected, TRUE) . '
'); $this->verbose('Actual:
' . var_export($library, TRUE) . '
'); $this->assertEqual($library, $expected, 'Library specified with an .info file found'); } /** * Tests libraries_detect(). */ function testLibrariesDetect() { // Test missing library. $library = libraries_detect('example_missing'); $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_detect('example_undetected_version'); $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_detect('example_unsupported_version'); $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_detect('example_supported_version'); $this->verbose('
' . var_export($library, TRUE) . '
'); $this->assertEqual($library['installed'], TRUE, 'Supported library version found.'); // Test libraries_get_version(). $library = libraries_detect('example_default_version_callback'); $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_detect('example_multiple_parameter_version_callback'); $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_detect('example_files'); $files = array( 'js' => array('example_1.js' => array()), 'css' => array('example_1.css' => array()), 'php' => array('example_1.php' => array()), ); $this->verbose('
' . var_export($library, TRUE) . '
'); $this->assertEqual($library['files'], $files, 'Top-level files property works.'); // Test version-specific library files. $library = libraries_detect('example_versions'); $files = array( 'js' => array('example_2.js' => array()), 'css' => array('example_2.css' => array()), 'php' => array('example_2.php' => array()), ); $this->verbose('
' . var_export($library, TRUE) . '
'); $this->assertEqual($library['files'], $files, 'Version-specific library files found.'); // Test missing variant. $library = libraries_detect('example_variant_missing'); $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' => 'example_variant', '%library' => 'Example variant missing', )); $this->assertEqual($library['variants']['example_variant']['error message'], $error_message, 'Correct error message for a missing variant.'); // Test existing variant. $library = libraries_detect('example_variant'); $this->verbose('
' . var_export($library, TRUE) . '
'); $this->assertEqual($library['variants']['example_variant']['installed'], TRUE, 'Existing variant found.'); } /** * Tests libraries_load(). */ function testLibrariesLoad() { // Test dependencies. $library = libraries_load('example_dependency_missing'); $this->verbose('
' . var_export($library, TRUE) . '
'); $this->assertFalse($library['loaded'], 'Library with missing dependency cannot be loaded'); $library = libraries_load('example_dependency_incompatible'); $this->verbose('
' . var_export($library, TRUE) . '
'); $this->assertFalse($library['loaded'], 'Library with incompatible dependency cannot be loaded'); $library = libraries_load('example_dependency_compatible'); $this->verbose('
' . var_export($library, TRUE) . '
'); $this->assertEqual($library['loaded'], 1, 'Library with compatible dependency is loaded'); $loaded = &drupal_static('libraries_load'); $this->verbose('
' . var_export($loaded, TRUE) . '
'); $this->assertEqual($loaded['example_dependency']['loaded'], 1, 'Dependency library is also loaded'); } /** * Tests the applying of callbacks. */ function testCallbacks() { $expected = array( 'name' => 'Example callback', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version' => '1', 'versions' => array( '1' => array( 'variants' => array( 'example_variant' => array( 'info callback' => 'not applied', 'pre-detect callback' => 'not applied', 'post-detect callback' => 'not applied', 'pre-dependencies-load callback' => 'not applied', 'pre-load callback' => 'not applied', 'post-load callback' => 'not applied', ), ), 'info callback' => 'not applied', 'pre-detect callback' => 'not applied', 'post-detect callback' => 'not applied', 'pre-dependencies-load callback' => 'not applied', 'pre-load callback' => 'not applied', 'post-load callback' => 'not applied', ), ), 'variants' => array( 'example_variant' => array( 'info callback' => 'not applied', 'pre-detect callback' => 'not applied', 'post-detect callback' => 'not applied', 'pre-dependencies-load callback' => 'not applied', 'pre-load callback' => 'not applied', 'post-load callback' => 'not applied', ), ), 'callbacks' => array( 'info' => array('_libraries_test_info_callback'), 'pre-detect' => array('_libraries_test_pre_detect_callback'), 'post-detect' => array('_libraries_test_post_detect_callback'), 'pre-dependencies-load' => array('_libraries_test_pre_dependencies_load_callback'), 'pre-load' => array('_libraries_test_pre_load_callback'), 'post-load' => array('_libraries_test_post_load_callback'), ), 'info callback' => 'not applied', 'pre-detect callback' => 'not applied', 'post-detect callback' => 'not applied', 'pre-dependencies-load callback' => 'not applied', 'pre-load callback' => 'not applied', 'post-load callback' => 'not applied', 'module' => 'libraries_test', ); libraries_info_defaults($expected, 'example_callback'); // Test a callback in the 'info' group. $expected['info callback'] = 'applied (top-level)'; $expected['versions']['1']['info callback'] = 'applied (version 1)'; $expected['versions']['1']['variants']['example_variant']['info callback'] = 'applied (version 1, variant example_variant)'; $expected['variants']['example_variant']['info callback'] = 'applied (variant example_variant)'; $library = libraries_info('example_callback'); $this->verbose('Expected:
' . var_export($expected, TRUE) . '
'); $this->verbose('Actual:
' . var_export($library, TRUE) . '
'); $this->assertEqual($library, $expected, 'Prepare callback was applied correctly.'); // Test a callback in the 'pre-detect' and 'post-detect' phases. // Successfully detected libraries should only contain version information // for the detected version and thus, be marked as installed. unset($expected['versions']); $expected['installed'] = TRUE; // Additionally, version-specific properties of the detected version are // supposed to override the corresponding top-level properties. $expected['info callback'] = 'applied (version 1)'; $expected['variants']['example_variant']['installed'] = TRUE; $expected['variants']['example_variant']['info callback'] = 'applied (version 1, variant example_variant)'; // Version-overloading takes place after the 'pre-detect' callbacks have // been applied. $expected['pre-detect callback'] = 'applied (version 1)'; $expected['post-detect callback'] = 'applied (top-level)'; $expected['variants']['example_variant']['pre-detect callback'] = 'applied (version 1, variant example_variant)'; $expected['variants']['example_variant']['post-detect callback'] = 'applied (variant example_variant)'; $library = libraries_detect('example_callback'); $this->verbose('Expected:
' . var_export($expected, TRUE) . '
'); $this->verbose('Actual:
' . var_export($library, TRUE) . '
'); $this->assertEqual($library, $expected, 'Detect callback was applied correctly.'); // Test a callback in the 'pre-dependencies-load', 'pre-load' and // 'post-load' phases. // Successfully loaded libraries should only contain information about the // already loaded variant. unset($expected['variants']); $expected['loaded'] = 0; $expected['pre-dependencies-load callback'] = 'applied (top-level)'; $expected['pre-load callback'] = 'applied (top-level)'; $expected['post-load callback'] = 'applied (top-level)'; $library = libraries_load('example_callback'); $this->verbose('Expected:
' . var_export($expected, TRUE) . '
'); $this->verbose('Actual:
' . var_export($library, TRUE) . '
'); $this->assertEqual($library, $expected, 'Pre-load and post-load callbacks were applied correctly.'); // This is not recommended usually and is only used for testing purposes. drupal_static_reset('libraries_load'); // Successfully loaded library variants are supposed to contain the specific // variant information only. $expected['info callback'] = 'applied (version 1, variant example_variant)'; $expected['pre-detect callback'] = 'applied (version 1, variant example_variant)'; $expected['post-detect callback'] = 'applied (variant example_variant)'; $library = libraries_load('example_callback', 'example_variant'); $this->verbose('Expected:
' . var_export($expected, TRUE) . '
'); $this->verbose('Actual:
' . var_export($library, TRUE) . '
'); $this->assertEqual($library, $expected, 'Pre-detect and post-detect callbacks were applied correctly to a variant.'); } /** * Tests that library files are properly added to the page output. * * We check for JavaScript and CSS files directly in the DOM and add a list of * included PHP files manually to the page output. * * @see _libraries_test_load() */ function testLibrariesOutput() { // 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'); // Test caching. variable_set('libraries_test_cache', TRUE); cache_clear_all('example_callback', 'cache_libraries'); // When the library information is not cached, all callback groups should be // invoked. $this->drupalGet('libraries_test/cache'); $this->assertRaw('The info callback group was invoked.', 'Info callback invoked for uncached libraries.'); $this->assertRaw('The pre-detect callback group was invoked.', 'Pre-detect callback invoked for uncached libraries.'); $this->assertRaw('The post-detect callback group was invoked.', 'Post-detect callback invoked for uncached libraries.'); $this->assertRaw('The pre-load callback group was invoked.', 'Pre-load callback invoked for uncached libraries.'); $this->assertRaw('The post-load callback group was invoked.', 'Post-load callback invoked for uncached libraries.'); // When the library information is cached only the 'pre-load' and // 'post-load' callback groups should be invoked. $this->drupalGet('libraries_test/cache'); $this->assertNoRaw('The info callback group was not invoked.', 'Info callback not invoked for cached libraries.'); $this->assertNoRaw('The pre-detect callback group was not invoked.', 'Pre-detect callback not invoked for cached libraries.'); $this->assertNoRaw('The post-detect callback group was not invoked.', 'Post-detect callback not invoked for cached libraries.'); $this->assertRaw('The pre-load callback group was invoked.', 'Pre-load callback invoked for cached libraries.'); $this->assertRaw('The post-load callback group was invoked.', 'Post-load callback invoked for cached libraries.'); variable_set('libraries_test_cache', FALSE); } /** * 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')) { $label = ($label !== '' ? "$label: " : ''); // Test that the wrong files are not loaded... $names = array( 'example_1' => FALSE, 'example_2' => FALSE, 'example_3' => FALSE, 'example_4' => FALSE, ); // ...and the correct ones are. $names[$name] = TRUE; // Test for the specific HTML that the different file types appear as in the // DOM. $html = array( 'js' => array(''), 'css' => array('@import url("', '");'), // PHP files do not get added to the DOM directly. // @see _libraries_test_load() 'php' => array('
  • ', '
  • '), ); foreach ($names as $name => $expected) { foreach ($extensions as $extension) { $filepath = drupal_get_path('module', 'libraries_test') . "/example/$name.$extension"; // JavaScript and CSS files appear as full URLs and with an appended // query string. if (in_array($extension, array('js', 'css'))) { $filepath = url('', array('absolute' => TRUE)) . $filepath . '?' . variable_get('css_js_query_string'); } $raw = $html[$extension][0] . $filepath . $html[$extension][1]; if ($expected) { $this->assertRaw($raw, "$label$name.$extension found."); } else { $this->assertNoRaw($raw, "$label$name.$extension not found."); } } } } } libraries/tests/libraries_test.inc0000644001412200141220000000024712116664161017163 0ustar benderbender 'Example missing', 'library path' => drupal_get_path('module', 'libraries') . '/tests/missing', ); $libraries['example_undetected_version'] = array( 'name' => 'Example undetected version', 'library path' => drupal_get_path('module', 'libraries') . '/tests', 'version callback' => '_libraries_test_return_version', 'version arguments' => array(FALSE), ); $libraries['example_unsupported_version'] = array( 'name' => 'Example unsupported version', 'library path' => drupal_get_path('module', 'libraries') . '/tests', 'version callback' => '_libraries_test_return_version', 'version arguments' => array('1'), 'versions' => array( '2' => array(), ), ); $libraries['example_supported_version'] = array( 'name' => 'Example supported version', 'library path' => drupal_get_path('module', 'libraries') . '/tests', 'version callback' => '_libraries_test_return_version', 'version arguments' => array('1'), 'versions' => array( '1' => array(), ), ); // Test the default version callback. $libraries['example_default_version_callback'] = array( 'name' => 'Example default version callback', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version arguments' => array( 'file' => 'README.txt', // Version 1 'pattern' => '/Version (\d+)/', 'lines' => 5, ), ); // Test a multiple-parameter version callback. $libraries['example_multiple_parameter_version_callback'] = array( 'name' => 'Example multiple parameter version callback', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', // Version 1 'version callback' => '_libraries_test_get_version', 'version arguments' => array('README.txt', '/Version (\d+)/', 5), ); // Test a top-level files property. $libraries['example_files'] = array( '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'), ), ); // Test loading of integration files. // Normally added by the corresponding module via hook_libraries_info_alter(), // these files should be automatically loaded when the library is loaded. $libraries['example_integration_files'] = array( 'name' => 'Example integration files', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version' => '1', 'integration files' => array( 'libraries_test' => array( 'js' => array('libraries_test.js'), 'css' => array('libraries_test.css'), 'php' => array('libraries_test.inc'), ), ), ); // Test version overloading. $libraries['example_versions'] = array( 'name' => 'Example versions', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version' => '2', 'versions' => array( '1' => array( 'files' => array( 'js' => array('example_1.js'), 'css' => array('example_1.css'), 'php' => array('example_1.php'), ), ), '2' => array( 'files' => array( 'js' => array('example_2.js'), 'css' => array('example_2.css'), 'php' => array('example_2.php'), ), ), ), ); // Test variant detection. $libraries['example_variant_missing'] = array( 'name' => 'Example variant missing', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version' => '1', 'variants' => array( 'example_variant' => array( 'files' => array( 'js' => array('example_3.js'), 'css' => array('example_3.css'), 'php' => array('example_3.php'), ), 'variant callback' => '_libraries_test_return_installed', 'variant arguments' => array(FALSE), ), ), ); $libraries['example_variant'] = array( 'name' => 'Example variant', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version' => '1', 'variants' => array( 'example_variant' => array( 'files' => array( 'js' => array('example_3.js'), 'css' => array('example_3.css'), 'php' => array('example_3.php'), ), 'variant callback' => '_libraries_test_return_installed', 'variant arguments' => array(TRUE), ), ), ); // Test correct behaviour with multiple versions and multiple variants. $libraries['example_versions_and_variants'] = array( 'name' => 'Example versions and variants', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version' => '2', 'versions' => array( '1' => array( 'variants' => array( 'example_variant_1' => array( 'files' => array( 'js' => array('example_1.js'), 'css' => array('example_1.css'), 'php' => array('example_1.php'), ), 'variant callback' => '_libraries_test_return_installed', 'variant arguments' => array(TRUE), ), 'example_variant_2' => array( 'files' => array( 'js' => array('example_2.js'), 'css' => array('example_2.css'), 'php' => array('example_2.php'), ), 'variant callback' => '_libraries_test_return_installed', 'variant arguments' => array(TRUE), ), ), ), '2' => array( 'variants' => array( 'example_variant_1' => array( 'files' => array( 'js' => array('example_3.js'), 'css' => array('example_3.css'), 'php' => array('example_3.php'), ), 'variant callback' => '_libraries_test_return_installed', 'variant arguments' => array(TRUE), ), 'example_variant_2' => array( 'files' => array( 'js' => array('example_4.js'), 'css' => array('example_4.css'), 'php' => array('example_4.php'), ), 'variant callback' => '_libraries_test_return_installed', 'variant arguments' => array(TRUE), ), ), ), ), ); // Test dependency loading. // We add one file to each library to be able to verify if it was loaded with // libraries_load(). // This library acts as a dependency for the libraries below. $libraries['example_dependency'] = array( 'name' => 'Example dependency', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version' => '1.1', 'files' => array('js' => array('example_1.js')), ); $libraries['example_dependency_missing'] = array( 'name' => 'Example dependency missing', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version' => '1', 'dependencies' => array('example_missing'), 'files' => array('js' => array('example_1.js')), ); $libraries['example_dependency_incompatible'] = array( 'name' => 'Example dependency incompatible', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version' => '1', 'dependencies' => array('example_dependency (>1.1)'), 'files' => array('js' => array('example_1.js')), ); $libraries['example_dependency_compatible'] = array( 'name' => 'Example dependency compatible', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version' => '1', 'dependencies' => array('example_dependency (>=1.1)'), 'files' => array('js' => array('example_1.js')), ); // Test the applying of callbacks. $libraries['example_callback'] = array( 'name' => 'Example callback', 'library path' => drupal_get_path('module', 'libraries') . '/tests/example', 'version' => '1', 'versions' => array( '1' => array( 'variants' => array( 'example_variant' => array( // These keys are for testing purposes only. 'info callback' => 'not applied', 'pre-detect callback' => 'not applied', 'post-detect callback' => 'not applied', 'pre-dependencies-load callback' => 'not applied', 'pre-load callback' => 'not applied', 'post-load callback' => 'not applied', ), ), // These keys are for testing purposes only. 'info callback' => 'not applied', 'pre-detect callback' => 'not applied', 'post-detect callback' => 'not applied', 'pre-dependencies-load callback' => 'not applied', 'pre-load callback' => 'not applied', 'post-load callback' => 'not applied', ), ), 'variants' => array( 'example_variant' => array( // These keys are for testing purposes only. 'info callback' => 'not applied', 'pre-detect callback' => 'not applied', 'post-detect callback' => 'not applied', 'pre-dependencies-load callback' => 'not applied', 'pre-load callback' => 'not applied', 'post-load callback' => 'not applied', ), ), 'callbacks' => array( 'info' => array('_libraries_test_info_callback'), 'pre-detect' => array('_libraries_test_pre_detect_callback'), 'post-detect' => array('_libraries_test_post_detect_callback'), 'pre-dependencies-load' => array('_libraries_test_pre_dependencies_load_callback'), 'pre-load' => array('_libraries_test_pre_load_callback'), 'post-load' => array('_libraries_test_post_load_callback'), ), // These keys are for testing purposes only. 'info callback' => 'not applied', 'pre-detect callback' => 'not applied', 'post-detect callback' => 'not applied', 'pre-dependencies-load callback' => 'not applied', 'pre-load callback' => 'not applied', 'post-load callback' => 'not applied', ); return $libraries; } /** * Implements hook_libraries_info_file_paths() */ function libraries_test_libraries_info_file_paths() { return array(drupal_get_path('module', 'libraries_test') . '/example'); } /** * Gets the version of an example library. * * Returns exactly the version string entered as the $version parameter. This * function cannot be collapsed with _libraries_test_return_installed(), because * of the different arguments that are passed automatically. */ function _libraries_test_return_version($library, $version) { return $version; } /** * Gets the version information from an arbitrary library. * * Test function for a version callback with multiple arguments. This is an * exact copy of libraries_get_version(), which uses a single $option argument, * except for the fact that it uses multiple arguments. Since we support both * type of version callbacks, detecting the version of a test library with this * function ensures that the arguments are passed correctly. This function might * be a useful reference for a custom version callback that uses multiple * parameters. * * @param $library * An associative array containing all information about the library. * @param $file * The filename to parse for the version, relative to the library path. For * example: 'docs/changelog.txt'. * @param pattern * A string containing a regular expression (PCRE) to match the library * version. For example: '/@version (\d+)\.(\d+)/'. * @param lines * (optional) The maximum number of lines to search the pattern in. Defaults * to 20. * @param 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_version() */ function _libraries_test_get_version($library, $file, $pattern, $lines = 20, $cols = 200) { $file = DRUPAL_ROOT . '/' . $library['library path'] . '/' . $file; if (!file_exists($file)) { return; } $file = fopen($file, 'r'); while ($lines && $line = fgets($file, $cols)) { if (preg_match($pattern, $line, $version)) { fclose($file); return $version[1]; } $lines--; } fclose($file); } /** * Detects the variant of an example library. * * Returns exactly the value of $installed, either TRUE or FALSE. This function * cannot be collapsed with _libraries_test_return_version(), because of the * different arguments that are passed automatically. */ function _libraries_test_return_installed($library, $name, $installed) { return $installed; } /** * Sets the 'info callback' key. * * This function is used as a test callback for the 'info' callback group. * * @see _libraries_test_callback() */ function _libraries_test_info_callback(&$library, $version, $variant) { _libraries_test_callback($library, $version, $variant, 'info'); } /** * Sets the 'pre-detect callback' key. * * This function is used as a test callback for the 'pre-detect' callback group. * * @see _libraries_test_callback() */ function _libraries_test_pre_detect_callback(&$library, $version, $variant) { _libraries_test_callback($library, $version, $variant, 'pre-detect'); } /** * Sets the 'post-detect callback' key. * * This function is used as a test callback for the 'post-detect callback group. * * @see _libraries_test_callback() */ function _libraries_test_post_detect_callback(&$library, $version, $variant) { _libraries_test_callback($library, $version, $variant, 'post-detect'); } /** * Sets the 'pre-dependencies-load callback' key. * * This function is used as a test callback for the 'pre-dependencies-load' * callback group. * * @see _libraries_test_callback() */ function _libraries_test_pre_dependencies_load_callback(&$library, $version, $variant) { _libraries_test_callback($library, $version, $variant, 'pre-dependencies-load'); } /** * Sets the 'pre-load callback' key. * * This function is used as a test callback for the 'pre-load' callback group. * * @see _libraries_test_callback() */ function _libraries_test_pre_load_callback(&$library, $version, $variant) { _libraries_test_callback($library, $version, $variant, 'pre-load'); } /** * Sets the 'post-load callback' key. * * This function is used as a test callback for the 'post-load' callback group. * * @see _libraries_test_callback() */ function _libraries_test_post_load_callback(&$library, $version, $variant) { _libraries_test_callback($library, $version, $variant, 'post-load'); } /** * Sets the '[group] callback' key, where [group] is prepare, detect, or load. * * This function is used as a test callback for the all callback groups. * * It sets the '[group] callback' (see above) key to 'applied ([part])' where * [part] is either 'top-level', 'version x.y' (where x.y is the passed-in * version string), 'variant example' (where example is the passed-in variant * name), or 'version x.y, variant example' (see above), depending on the part * of the library the passed-in library information belongs to. * * @param $library * An array of library information, which may be version- or variant-specific. * Passed by reference. * @param $version * The version the library information passed in $library belongs to, or NULL * if the passed library information is not version-specific. * @param $variant * The variant the library information passed in $library belongs to, or NULL * if the passed library information is not variant-specific. */ function _libraries_test_callback(&$library, $version, $variant, $group) { $string = 'applied'; if (isset($version) && isset($variant)) { $string .= " (version $version, variant $variant)"; } elseif (isset($version)) { $string .= " (version $version)"; } elseif (isset($variant)) { $string .= " (variant $variant)"; } else { $string .= ' (top-level)'; } $library["$group callback"] = $string; // The following is used to test caching of library information. // Only set the message for the top-level library to prevent confusing, // duplicate messages. if (!isset($version) && !isset($variant) && variable_get('libraries_test_cache', FALSE)) { drupal_set_message("The $group callback group was invoked."); } } /** * Implements hook_menu(). */ function libraries_test_menu() { $base = array( 'page callback' => '_libraries_test_load', 'access callback' => TRUE, ); $items['libraries_test/files'] = $base + array( 'title' => 'Test files', 'page arguments' => array('example_files'), ); $items['libraries_test/integration_files'] = $base + array( 'title' => 'Test integration files', 'page arguments' => array('example_integration_files'), ); $items['libraries_test/versions'] = $base + array( 'title' => 'Test version loading', 'page arguments' => array('example_versions'), ); $items['libraries_test/variant'] = $base + array( 'title' => 'Test variant loading', 'page arguments' => array('example_variant', 'example_variant'), ); $items['libraries_test/versions_and_variants'] = $base + array( 'title' => 'Test concurrent version and variant loading', 'page arguments' => array('example_versions_and_variants', 'example_variant_2'), ); $items['libraries_test/cache'] = $base + array( 'title' => 'Test caching of library information', 'page arguments' => array('example_callback'), ); return $items; } /** * Loads a specified library (variant) for testing. * * JavaScript and CSS files can be checked directly by SimpleTest, so we only * need to manually check for PHP files. We provide information about the loaded * JavaScript and CSS files for easier debugging. See example/README.txt for * more information. */ function _libraries_test_load($library, $variant = NULL) { libraries_load($library, $variant); // JavaScript and CSS files can be checked directly by SimpleTest, so we only // need to manually check for PHP files. $output = ''; // For easer debugging of JS loading, a text is shown that the JavaScript will // replace. $output .= '

    JavaScript

    '; $output .= '
    '; $output .= 'If this text shows up, no JavaScript test file was loaded.'; $output .= '
    '; // For easier debugging of CSS loading, the loaded CSS files will color the // following text. $output .= '

    CSS

    '; $output .= '
    '; $output .= 'If one of the CSS test files has been loaded, this text will be colored:'; $output .= '
      '; // Do not reference the actual CSS files (i.e. including '.css'), because that // breaks testing. $output .= '
    • example_1: red
    • '; $output .= '
    • example_2: green
    • '; $output .= '
    • example_3: orange
    • '; $output .= '
    • example_4: blue
    • '; $output .= '
    • libraries_test: purple
    • '; $output .= '
    '; $output .= '
    '; $output .= '

    PHP

    '; $output .= '
    '; $output .= 'The following is a list of all loaded test PHP files:'; $output .= '
      '; $files = get_included_files(); foreach ($files as $file) { if (strpos($file, 'libraries/test') && !strpos($file, 'libraries_test.module')) { $output .= '
    • ' . str_replace(DRUPAL_ROOT . '/', '', $file) . '
    • '; } } $output .= '
    '; $output .= '
    '; return $output; } libraries/CHANGELOG.txt0000644001412200141220000001005512116664161014341 0ustar benderbender Libraries 7.x-2.1, 2013-03-09 ----------------------------- #1937446 by Pol, tstoeckler: Add a 'pre-dependencies-load' callback group. #1775668 by tstoeckler: Fix bogus assertion message in assertLibraryFiles(). #1773640 by tstoeckler: Use drupal_get_path() to find the profile directory. #1565426 by tstoeckler: Invoke hook_libraries_info() in enabled themes. Libraries 7.x-2.0, 2012-07-29 ----------------------------- #1606018 by chemical: Tests fail if the module is downloaded from Drupal.org. #1386250 by tstoeckler: Clarify module and library installation in README.txt. #1578618 by iamEAP: Fixed Fatal cache flush failure on major version upgrades. #1449346 by tstoeckler, sun: Clean-up libraries.test Libraries 7.x-2.0-alpha2, 2011-12-15 ------------------------------------ #1299076 by tstoeckler: Improve testing of JS, CSS, and PHP files. #1347214 by rfay: Improve update function 7200. #1323530 by tstoeckler: Document libraries_get_version() pattern matching. #1325524 by sun, Rob Loach, tstoeckler: Statically cache libraries_detect(). #1321372 by Rob Loach: Provide a 'post-load' callback group. #1205854 by tstoeckler, sun: Test library caching. Libraries 7.x-2.0-alpha1, 2011-10-01 ------------------------------------ #1268342 by tstoeckler: Clean up drush libraries-list command. #962214 by tstoeckler, sun: Add support for library dependencies. #1224838 by sun, mjpa: Fix library path not being prepended to JS/CSS files. #1023258 by tstoeckler: Make 'files' consistently keyed by filename. #958162 by sun, tstoeckler: Add pre-detect callback group. #958162 by sun, tstoeckler: Make tests debuggable and provide libraries_info_defaults(). #961476 by tstoeckler: Changed libraries_get_path() to return FALSE by default. #958162 by tstoeckler, sun, good_man: Allow to apply callbacks to libraries. #1125904 by tstoeckler, boombatower: Fix drush libraries-list. #1050076 by tstoeckler: Re-utilize libraries_detect() and remove libraries_detect_library(). #466090 by tstoeckler: Add update function. #466090 by tstoeckler: Allow cache to be flushed. #466090 by tstoeckler, sun: Cache library information. #1064008 by tstoeckler, bfroehle: Fix outdated API examples in libraries.api.php. #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(). Libraries 7.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 ----------------------------- #1028744 by tstoeckler: Code clean-up. #496732 by tstoeckler, robphillips: Allow placing libraries in root directory. Libraries 6.x-1.0-ALPHA1, 2009-12-30 ------------------------------------ #480440 by markus_petrux: Fixed base_path() not applied to default library path. #320562 by sun: Added basic functions. libraries/libraries.module0000644001412200141220000006144112116664161015501 0ustar benderbender/*. $searchdir[] = "$config/libraries"; // Retrieve list of directories. $directories = array(); $nomask = array('CVS'); foreach ($searchdir as $dir) { if (is_dir($dir) && $handle = opendir($dir)) { while (FALSE !== ($file = readdir($handle))) { if (!in_array($file, $nomask) && $file[0] != '.') { if (is_dir("$dir/$file")) { $directories[$file] = "$dir/$file"; } } } closedir($handle); } } 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_path('profile', drupal_get_profile()); $config = conf_path(); // Build a list of directories. $directories = module_invoke_all('libraries_info_file_paths'); $directories[] = 'libraries'; $directories[] = "$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; } /** * Invokes library callbacks. * * @param $group * A string containing the group of callbacks that is to be applied. Should be * either 'info', 'pre-detect', 'post-detect', or 'load'. * @param $library * An array of library information, passed by reference. */ function libraries_invoke($group, &$library) { foreach ($library['callbacks'][$group] as $callback) { libraries_traverse_library($library, $callback); } } /** * Helper function to apply a callback to all parts of a library. * * Because library declarations can include variants and versions, and those * version declarations can in turn include variants, modifying e.g. the 'files' * property everywhere it is declared can be quite cumbersome, in which case * this helper function is useful. * * @param $library * An array of library information, passed by reference. * @param $callback * A string containing the callback to apply to all parts of a library. */ function libraries_traverse_library(&$library, $callback) { // Always apply the callback to the top-level library. $callback($library, NULL, NULL); // Apply the callback to versions. if (isset($library['versions'])) { foreach ($library['versions'] as $version_string => &$version) { $callback($version, $version_string, NULL); // Versions can include variants as well. if (isset($version['variants'])) { foreach ($version['variants'] as $version_variant_name => &$version_variant) { $callback($version_variant, $version_string, $version_variant_name); } } } } // Apply the callback to variants. if (isset($library['variants'])) { foreach ($library['variants'] as $variant_name => &$variant) { $callback($variant, NULL, $variant_name); } } } /** * Library info callback to make all 'files' properties consistent. * * This turns libraries' file information declared as e.g. * @code * $library['files']['js'] = array('example_1.js', 'example_2.js'); * @endcode * into * @code * $library['files']['js'] = array( * 'example_1.js' => array(), * 'example_2.js' => array(), * ); * @endcode * It does the same for the 'integration files' property. * * @param $library * An associative array of library information or a part of it, passed by * reference. * @param $version * If the library information belongs to a specific version, the version * string. NULL otherwise. * @param $variant * If the library information belongs to a specific variant, the variant name. * NULL otherwise. * * @see libraries_info() * @see libraries_invoke() */ function libraries_prepare_files(&$library, $version = NULL, $variant = NULL) { // Both the 'files' property and the 'integration files' property contain file // declarations, and we want to make both consistent. $file_types = array(); if (isset($library['files'])) { $file_types[] = &$library['files']; } if (isset($library['integration files'])) { // Integration files are additionally keyed by module. foreach ($library['integration files'] as &$integration_files) { $file_types[] = &$integration_files; } } foreach ($file_types as &$files) { // Go through all supported types of files. foreach (array('js', 'css', 'php') as $type) { if (isset($files[$type])) { foreach ($files[$type] as $key => $value) { // Unset numeric keys and turn the respective values into keys. if (is_numeric($key)) { $files[$type][$value] = array(); unset($files[$type][$key]); } } } } } } /** * Library post-detect callback to process and detect dependencies. * * It checks whether each of the dependencies of a library are installed and * available in a compatible version. * * @param $library * An associative array of library information or a part of it, passed by * reference. * @param $version * If the library information belongs to a specific version, the version * string. NULL otherwise. * @param $variant * If the library information belongs to a specific variant, the variant name. * NULL otherwise. * * @see libraries_info() * @see libraries_invoke() */ function libraries_detect_dependencies(&$library, $version = NULL, $variant = NULL) { if (isset($library['dependencies'])) { foreach ($library['dependencies'] as &$dependency_string) { $dependency_info = drupal_parse_dependency($dependency_string); $dependency = libraries_detect($dependency_info['name']); if (!$dependency['installed']) { $library['installed'] = FALSE; $library['error'] = 'missing dependency'; $library['error message'] = t('The %dependency library, which the %library library depends on, is not installed.', array( '%dependency' => $dependency['name'], '%library' => $library['name'], )); } elseif (drupal_check_incompatibility($dependency_info, $dependency['version'])) { $library['installed'] = FALSE; $library['error'] = 'incompatible dependency'; $library['error message'] = t('The version %dependency_version of the %dependency library is not compatible with the %library library.', array( '%dependency_version' => $dependency['version'], '%dependency' => $dependency['name'], '%library' => $library['name'], )); } // Remove the version string from the dependency, so libraries_load() can // load the libraries directly. $dependency_string = $dependency_info['name']; } } } /** * 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. If omitted, information about all registered libraries is returned. * * @return array|false * An associative array containing registered information for all libraries, * the registered information for the library specified by $name, or FALSE if * the library $name is not registered. * * @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) { // This static cache is re-used by libraries_detect() to save memory. $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 hook_libraries_info() in enabled themes. // @see drupal_alter() global $theme, $base_theme_info; if (isset($theme)) { $theme_keys = array(); foreach ($base_theme_info as $base) { $theme_keys[] = $base->name; } $theme_keys[] = $theme; foreach ($theme_keys as $theme_key) { $function = $theme_key . '_' . 'libraries_info'; if (function_exists($function)) { foreach ($function() as $machine_name => $properties) { $properties['theme'] = $theme_key; $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) { libraries_info_defaults($properties, $machine_name); } // Allow modules to alter the registered libraries. drupal_alter('libraries_info', $libraries); // Invoke callbacks in the 'info' group. foreach ($libraries as &$properties) { libraries_invoke('info', $properties); } } if (isset($name)) { if (!empty($libraries[$name])) { return $libraries[$name]; } else { $false = FALSE; return $false; } } return $libraries; } /** * Applies default properties to a library definition. * * @library * An array of library information, passed by reference. * @name * The machine name of the passed-in library. */ function libraries_info_defaults(&$library, $name) { $library += array( 'machine name' => $name, 'name' => $name, 'vendor url' => '', 'download url' => '', 'path' => '', 'library path' => NULL, 'version callback' => 'libraries_get_version', 'version arguments' => array(), 'files' => array(), 'dependencies' => array(), 'variants' => array(), 'versions' => array(), 'integration files' => array(), 'callbacks' => array(), ); $library['callbacks'] += array( 'info' => array(), 'pre-detect' => array(), 'post-detect' => array(), 'pre-dependencies-load' => array(), 'pre-load' => array(), 'post-load' => array(), ); // Add our own callbacks before any others. array_unshift($library['callbacks']['info'], 'libraries_prepare_files'); array_unshift($library['callbacks']['post-detect'], 'libraries_detect_dependencies'); return $library; } /** * Tries to detect a library and its installed version. * * @param $name * The machine name of a library to return registered information for. * * @return array|false * An associative array containing registered information for the library * specified by $name, or FALSE if the library $name is not registered. * In addition to the keys returned by libraries_info(), the following keys * are contained: * - installed: A boolean indicating whether the library is installed. Note * that not only the top-level library, but also each variant contains this * key. * - version: If the version could be detected, the full version string. * - error: If an error occurred during library detection, one of the * following error statuses: "not found", "not detected", "not supported". * - error message: If an error occurred during library detection, a detailed * error message. * * @see libraries_info() */ function libraries_detect($name) { // Re-use the statically cached value of libraries_info() to save memory. $library = &libraries_info($name); if ($library === FALSE) { return $library; } // If 'installed' is set, library detection ran already. if (isset($library['installed'])) { return $library; } $library['installed'] = FALSE; // Check whether the library exists. if (!isset($library['library path'])) { $library['library path'] = libraries_get_path($library['machine name']); } if ($library['library path'] === FALSE || !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 $library; } // Invoke callbacks in the 'pre-detect' group. libraries_invoke('pre-detect', $library); // 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 $library; } } // 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 $library; } // 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; // Invoke callbacks in the 'post-detect' group. libraries_invoke('post-detect', $library); 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 = cache_get($name, 'cache_libraries'); if ($library) { $library = $library->data; } else { $library = libraries_detect($name); cache_set($name, $library, 'cache_libraries'); } // 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']); // Invoke callbacks in the 'pre-dependencies-load' group. libraries_invoke('pre-dependencies-load', $library); // If the library (variant) is installed, load it. $library['loaded'] = FALSE; if ($library['installed']) { // Load library dependencies. if (isset($library['dependencies'])) { foreach ($library['dependencies'] as $dependency) { libraries_load($dependency); } } // Invoke callbacks in the 'pre-load' group. libraries_invoke('pre-load', $library); // Load all the files associated with the library. $library['loaded'] = libraries_load_files($library); // Invoke callbacks in the 'post-load' group. libraries_invoke('post-load', $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)) { $data = $options; $options = array(); } // 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']); } // Prepend the library path to the file name. $data = "$path/$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 => $array) { $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\.-]+)@'. Note that * the returned version is not the match of the entire pattern (i.e. * '@version 1.2.3' in the above example) but the match of the first * sub-pattern (i.e. '1.2.3' in the above example). * - 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); } libraries/libraries.api.php0000644001412200141220000005040512116664161015551 0ustar benderbender1.3-beta2)' * // Only load a version equal to or later than 1.3-beta3: * 'example (>=1.3-beta3)', * // Only load a version earlier than 1.5: * 'example (<1.5)', * // Only load a version equal to or earlier than 1.4: * 'example (<=1.4)', * // Combinations of the above are allowed as well: * 'example (>=1.3-beta2, <1.5)', * ); * @endcode * - 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. * - callbacks: An associative array whose keys are callback groups and whose * values are arrays of callbacks to apply to the library in that group. * Each callback receives the following arguments: * - $library: An array of library information belonging to the top-level * library, a specific version, a specific variant or a specific variant * of a specific version. Because library information such as the 'files' * property (see above) can be declared in all these different locations * of the library array, but a callback may have to act on all these * different parts of the library, it is called recursively for each * library with a certain part of the libraries array passed as $library * each time. * - $version: If the $library array belongs to a certain version (see * above), a string containing the version. This argument may be empty, so * NULL should be specified as the default value. * - $variant: If the $library array belongs to a certain variant (see * above), a string containing the variant name. This argument may be * empty, so NULL should be specified as the default value. * Valid callback groups are: * - info: Callbacks registered in this group are applied after the library * information has been retrieved via hook_libraries_info() or info files. * - pre-detect: Callbacks registered in this group are applied after the * library path has been determined and before the version callback is * invoked. At this point the following additional information is available: * - $library['library path']: The path on the file system to the library. * - post-detect: Callbacks registered in this group are applied after the * library has been successfully detected. At this point the library * contains the version-specific information, if specified, and following * additional information is available: * - $library['installed']: A boolean indicating whether the library is * installed or not. * - $library['version']: If it could be detected, a string containing the * version of the library. * - $library['variants'][$variant]['installed']: For each specified * variant, a boolean indicating whether the variant is installed or * not. * Note that in this group the 'versions' property is no longer available. * - pre-dependencies-load: Callbacks registered in this group are applied * directly before the library's dependencies are loaded. At this point * the library contains variant-specific information, if specified. Note * that in this group the 'variants' property is no longer available. * - pre-load: Callbacks registered in this group are applied directly after * the library's dependencies are loaded and before the library itself is * loaded. * - post-load: Callbacks registered in this group are applied directly * after this library is loaded. At this point, the library contains a * 'loaded' key, which contains the number of files that were loaded. * 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. 'name' => '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'), ), ), // Optionally register callbacks to apply to the library during different // stages of its lifetime ('callback groups'). 'callbacks' => array( // Used to alter the info associated with the library. 'info' => array( 'mymodule_example_libraries_info_callback', ), // Called before detecting the given library. 'pre-detect' => array( 'mymodule_example_libraries_predetect_callback', ), // Called after detecting the library. 'post-detect' => array( 'mymodule_example_libraries_postdetect_callback', ), // Called before the library's dependencies are loaded. 'pre-dependencie-load' => array( 'mymodule_example_libraries_pre_dependencies_load_callback', ), // Called before the library is loaded. 'pre-load' => array( 'mymodule_example_libraries_preload_callback', ), // Called after the library is loaded. 'post-load' => array( 'mymodule_example_libraries_postload_callback', ), ), ); // A very simple library. No changing APIs (hence, no versions), no variants. // Expected to be extracted into 'sites/all/libraries/simple'. $libraries['simple'] = array( 'name' => '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( 'name' => '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'); } libraries/libraries.info0000644001412200141220000000043512116665234015145 0ustar benderbendername = Libraries description = Allows version-dependent and shared usage of external libraries. core = 7.x files[] = tests/libraries.test ; Information added by drupal.org packaging script on 2013-03-09 version = "7.x-2.1" core = "7.x" project = "libraries" datestamp = "1362848412"