FINAL suepr merge step : added all modules to this super repos

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-19 16:46:59 +02:00
7585 changed files with 1723356 additions and 18 deletions

View File

@@ -0,0 +1,84 @@
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.

View File

@@ -0,0 +1,339 @@
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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
<signature of Ty Coon>, 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.

View File

@@ -0,0 +1,37 @@
-- SUMMARY --
Libraries API provides external library handling for Drupal modules.
For a full description visit the project page:
http://drupal.org/project/libraries
Bug reports, feature suggestions and latest developments:
http://drupal.org/project/issues/libraries
-- REQUIREMENTS --
* None.
-- INSTALLATION --
* Install as usual, see http://drupal.org/node/70151 for further information.
Note that installing external libraries is separate from installing this
module and should happen in the sites/all/libraries directory. See
http://drupal.org/node/1440066 for more information.
-- CONTACT --
Current maintainers:
* Daniel F. Kudwien (sun) - http://drupal.org/user/54136
* Tobias Stöckler (tstoeckler) - http://drupal.org/user/107158
This project has been sponsored by:
* UNLEASHED MIND
Specialized in consulting and planning of Drupal powered sites, UNLEASHED
MIND offers installation, development, theming, customization, and hosting
to get you started. Visit http://www.unleashedmind.com for more information.

View File

@@ -0,0 +1,450 @@
<?php
/**
* @file
* Documents API functions for Libraries module.
*/
/**
* Return information about external libraries.
*
* @return
* An associative array whose keys are internal names of libraries and whose
* values are describing each library. Each key is the directory name below
* the 'libraries' directory, in which the library may be found. Each value is
* an associative array containing:
* - name: The official, human-readable name of the library.
* - vendor url: The URL of the homepage of the library.
* - download url: The URL of a web page on which the library can be obtained.
* - path: (optional) A relative path from the directory of the library to the
* actual library. Only required if the extracted download package contains
* the actual library files in a sub-directory.
* - library path: (optional) The absolute path to the library directory. This
* should not be declared normally, as it is automatically detected, to
* allow for multiple possible library locations. A valid use-case is an
* external library, in which case the full URL to the library should be
* specified here.
* - version: (optional) The version of the library. This should not be
* declared normally, as it is automatically detected (see 'version
* callback' below) to allow for version changes of libraries without code
* changes of implementing modules and to support different versions of a
* library simultaneously (though only one version can be installed per
* site). A valid use-case is an external library whose version cannot be
* determined programatically.
* - version callback: (optional) The name of a function that detects and
* returns the full version string of the library. The first argument is
* always $library, an array containing all library information as described
* here. There are two ways to declare the version callback's additional
* arguments, either as a single $options parameter or as multiple
* parameters, which correspond to the two ways to specify the argument
* values (see 'version arguments'). Defaults to libraries_get_version().
* - version arguments: A list of arguments to pass to the version callback.
* Version arguments can be declared either as an associative array whose
* keys are the argument names or as an indexed array without specifying
* keys. If declared as an associative array, the arguments get passed to
* the version callback as a single $options parameter whose keys are the
* argument names (i.e. $options is identical to the specified array). If
* declared as an indexed array, the array values get passed to the version
* callback as seperate arguments in the order they were declared. The
* default version callback libraries_get_version() expects a single,
* associative array with named keys:
* - file: The filename to parse for the version, relative to the library
* path. For example: 'docs/changelog.txt'.
* - pattern: A string containing a regular expression (PCRE) to match the
* library version. For example: '@version\s+([0-9a-zA-Z\.-]+)@'. 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.
* - files: An associative array of library files to load. Supported keys are:
* - js: A list of JavaScript files to load, using the same syntax as Drupal
* core's hook_library().
* - css: A list of CSS files to load, using the same syntax as Drupal
* core's hook_library().
* - php: A list of PHP files to load.
* - dependencies: An array of libraries this library depends on. Similar to
* declaring module dependencies, the dependency declaration may contain
* information on the supported version. Examples of supported declarations:
* @code
* $libraries['dependencies'] = array(
* // Load the 'example' library, regardless of the version available:
* 'example',
* // Only load the 'example' library, if version 1.2 is available:
* 'example (1.2)',
* // Only load a version later than 1.3-beta2 of the 'example' library:
* 'example (>1.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');
}

View File

@@ -0,0 +1,151 @@
<?php
/**
* @file
* Drush integration for Libraries API.
*/
/**
* Implements hook_drush_command().
*/
function libraries_drush_command() {
$items['libraries-list'] = array(
'callback' => 'libraries_drush_list',
'description' => dt('Lists registered library information.'),
'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
);
/**$items['libraries-download'] = array(
'callback' => 'libraries_drush_download',
'description' => dt('Downloads a registered library into the libraries directory for the active site.'),
'arguments' => array(
'name' => dt('The internal name of the registered library.'),
),
);*/
return $items;
}
/**
* Implements hook_drush_help().
*/
function libraries_drush_help($section) {
switch ($section) {
case 'drush:libraries-list':
return dt('Lists registered library information.');
case 'drush:libraries-download':
return dt('Downloads a registered library into the libraries directory for the active site.
See libraries-list for a list of registered libraries.');
}
}
/**
* Lists registered library information.
*/
function libraries_drush_list() {
$libraries = 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');
}
}

View File

@@ -0,0 +1,11 @@
name = 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"

View File

@@ -0,0 +1,27 @@
<?php
/**
* @file
* Install, uninstall, and update functions for libraries.module.
*/
/**
* Implements hook_schema().
*/
function libraries_schema() {
$schema['cache_libraries'] = drupal_get_schema_unprocessed('system', 'cache');
$schema['cache_libraries']['description'] = 'Cache table to store library information.';
return $schema;
}
/**
* Create the 'cache_libraries' table.
*/
function libraries_update_7200() {
// Note that previous versions of this function created the table with a
// different table comment.
if (!db_table_exists('cache_libraries')) {
$specs = libraries_schema();
db_create_table('cache_libraries', $specs['cache_libraries']);
}
}

View File

@@ -0,0 +1,765 @@
<?php
/**
* @file
* External library handling for Drupal modules.
*/
/**
* Implements hook_flush_caches().
*/
function libraries_flush_caches() {
// @todo When upgrading from 1.x, update.php attempts to flush caches before
// the cache table has been created.
// @see http://drupal.org/node/1477932
if (db_table_exists('cache_libraries')) {
return array('cache_libraries');
}
}
/**
* Gets the path of a library.
*
* @param $name
* The machine name of a library to return the path for.
* @param $base_path
* Whether to prefix the resulting path with base_path().
*
* @return
* The path to the specified library or FALSE if the library wasn't found.
*
* @ingroup libraries
*/
function libraries_get_path($name, $base_path = FALSE) {
$libraries = &drupal_static(__FUNCTION__);
if (!isset($libraries)) {
$libraries = libraries_get_libraries();
}
$path = ($base_path ? base_path() : '');
if (!isset($libraries[$name])) {
return FALSE;
}
else {
$path .= $libraries[$name];
}
return $path;
}
/**
* Returns an array of library directories.
*
* Returns an array of library directories from the all-sites directory
* (i.e. sites/all/libraries/), the profiles directory, and site-specific
* directory (i.e. sites/somesite/libraries/). The returned array will be keyed
* by the library name. Site-specific libraries are prioritized over libraries
* in the default directories. That is, if a library with the same name appears
* in both the site-wide directory and site-specific directory, only the
* site-specific version will be listed.
*
* @return
* A list of library directories.
*
* @ingroup libraries
*/
function libraries_get_libraries() {
$searchdir = array();
$profile = drupal_get_path('profile', drupal_get_profile());
$config = conf_path();
// Similar to 'modules' and 'themes' directories in the root directory,
// certain distributions may want to place libraries into a 'libraries'
// directory in Drupal's root directory.
$searchdir[] = 'libraries';
// Similar to 'modules' and 'themes' directories inside an installation
// profile, installation profiles may want to place libraries into a
// 'libraries' directory.
$searchdir[] = "$profile/libraries";
// Always search sites/all/libraries.
$searchdir[] = 'sites/all/libraries';
// Also search sites/<domain>/*.
$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);
}

View File

@@ -0,0 +1,42 @@
Example library
Version 1
This file is an example file to test version detection.
The various other files in this directory are to test the loading of JavaScript,
CSS and PHP files.
- JavaScript: The filenames of the JavaScript files are asserted to be in the
raw HTML via SimpleTest. Since the filename could appear, for instance, in an
error message, this is not very robust. Explicit testing of JavaScript,
though, is not yet possible with SimpleTest. To allow for easier debugging, we
place the following text on the page:
"If this text shows up, no JavaScript test file was loaded."
This text is replaced via JavaScript by a text of the form:
"If this text shows up, [[file] was loaded successfully."
[file] is either 'example_1.js', 'example_2.js', 'example_3.js',
'example_4.js' or 'libraries_test.js'. If you have SimpleTest's verbose mode
enabled and see the above text in one of the debug pages, the noted JavaScript
file was loaded successfully.
- CSS: The filenames of the CSS files are asserted to be in the raw HTML via
SimpleTest. Since the filename could appear, for instance, in an error
message, this is not very robust. Explicit testing of CSS, though, is not yet
possible with SimpleTest. Hence, the CSS files, if loaded, make the following
text a certain color:
"If one of the CSS test files has been loaded, this text will be colored:
- example_1: red
- example_2: green
- example_3: orange
- example_4: blue
- libraries_test: purple"
If you have SimpleTest's verbose mode enabled, and see the above text in a
certain color (i.e. not in black), a CSS file was loaded successfully. Which
file depends on the color as referenced in the text above.
- PHP: The loading of PHP files is tested by defining a dummy function in the
PHP files and then checking whether this function was defined using
function_exists(). This can be checked programatically with SimpleTest.
The loading of integration files is tested with the same method. The integration
files are libraries_test.js, libraries_test.css, libraries_test.inc and are
located in the tests directory alongside libraries_test.module (i.e. they are
not in the same directory as this file).

View File

@@ -0,0 +1,11 @@
/**
* @file
* Test CSS file for Libraries loading.
*
* Color the 'libraries-test-css' div red. See README.txt for more information.
*/
.libraries-test-css {
color: red;
}

View File

@@ -0,0 +1,18 @@
/**
* @file
* Test JavaScript file for Libraries loading.
*
* Replace the text in the 'libraries-test-javascript' div. See README.txt for
* more information.
*/
(function ($) {
Drupal.behaviors.librariesTest = {
attach: function(context, settings) {
$('.libraries-test-javascript').text('If this text shows up, example_1.js was loaded successfully.')
}
};
})(jQuery);

View File

@@ -0,0 +1,12 @@
<?php
/**
* @file
* Test PHP file for Libraries loading.
*/
/**
* Dummy function to see if this file was loaded.
*/
function _libraries_test_example_1() {
}

View File

@@ -0,0 +1,11 @@
/**
* @file
* Test CSS file for Libraries loading.
*
* Color the 'libraries-test-css' div green. See README.txt for more information.
*/
.libraries-test-css {
color: green;
}

View File

@@ -0,0 +1,18 @@
/**
* @file
* Test JavaScript file for Libraries loading.
*
* Replace the text in the 'libraries-test-javascript' div. See README.txt for
* more information.
*/
(function ($) {
Drupal.behaviors.librariesTest = {
attach: function(context, settings) {
$('.libraries-test-javascript').text('If this text shows up, example_2.js was loaded successfully.')
}
};
})(jQuery);

View File

@@ -0,0 +1,12 @@
<?php
/**
* @file
* Test PHP file for Libraries loading.
*/
/**
* Dummy function to see if this file was loaded.
*/
function _libraries_test_example_2() {
}

View File

@@ -0,0 +1,11 @@
/**
* @file
* Test CSS file for Libraries loading.
*
* Color the 'libraries-test-css' div orange. See README.txt for more information.
*/
.libraries-test-css {
color: orange;
}

View File

@@ -0,0 +1,18 @@
/**
* @file
* Test JavaScript file for Libraries loading.
*
* Replace the text in the 'libraries-test-javascript' div. See README.txt for
* more information.
*/
(function ($) {
Drupal.behaviors.librariesTest = {
attach: function(context, settings) {
$('.libraries-test-javascript').text('If this text shows up, example_3.js was loaded successfully.')
}
};
})(jQuery);

View File

@@ -0,0 +1,12 @@
<?php
/**
* @file
* Test PHP file for Libraries loading.
*/
/**
* Dummy function to see if this file was loaded.
*/
function _libraries_test_example_3() {
}

View File

@@ -0,0 +1,11 @@
/**
* @file
* Test CSS file for Libraries loading.
*
* Color the 'libraries-test-css' div blue. See README.txt for more information.
*/
.libraries-test-css {
color: blue;
}

View File

@@ -0,0 +1,18 @@
/**
* @file
* Test JavaScript file for Libraries loading.
*
* Replace the text in the 'libraries-test-javascript' div. See README.txt for
* more information.
*/
(function ($) {
Drupal.behaviors.librariesTest = {
attach: function(context, settings) {
$('.libraries-test-javascript').text('If this text shows up, example_4.js was loaded successfully.')
}
};
})(jQuery);

View File

@@ -0,0 +1,12 @@
<?php
/**
* @file
* Test PHP file for Libraries loading.
*/
/**
* Dummy function to see if this file was loaded.
*/
function _libraries_test_example_4() {
}

View File

@@ -0,0 +1,11 @@
; This is an example info file of a library used for testing purposes.
name = Example info file
; Information added by drupal.org packaging script on 2013-03-09
version = "7.x-2.1"
core = "7.x"
project = "libraries"
datestamp = "1362848412"

View File

@@ -0,0 +1,537 @@
<?php
/**
* @file
* Tests for Libraries API.
*/
/**
* Tests basic Libraries API functions.
*/
class LibrariesUnitTestCase extends DrupalUnitTestCase {
public static function getInfo() {
return array(
'name' => '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:<br>$error_message");
$this->verbose('Actual:<br>' . $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:<br>$error_message");
$this->verbose('Actual:<br>' . $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('<pre>' . var_export(libraries_scan_info_files(), TRUE) . '</pre>');
}
/**
* 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:<pre>' . var_export($expected, TRUE) . '</pre>');
$this->verbose('Actual:<pre>' . var_export($library, TRUE) . '</pre>');
$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:<pre>' . var_export($expected, TRUE) . '</pre>');
$this->verbose('Actual:<pre>' . var_export($library, TRUE) . '</pre>');
$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('<pre>' . var_export($library, TRUE) . '</pre>');
$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('<pre>' . var_export($library, TRUE) . '</pre>');
$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('<pre>' . var_export($library, TRUE) . '</pre>');
$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('<pre>' . var_export($library, TRUE) . '</pre>');
$this->assertEqual($library['installed'], TRUE, 'Supported library version found.');
// Test libraries_get_version().
$library = libraries_detect('example_default_version_callback');
$this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
$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('<pre>' . var_export($library, TRUE) . '</pre>');
$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('<pre>' . var_export($library, TRUE) . '</pre>');
$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('<pre>' . var_export($library, TRUE) . '</pre>');
$this->assertEqual($library['files'], $files, 'Version-specific library files found.');
// Test missing variant.
$library = libraries_detect('example_variant_missing');
$this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
$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('<pre>' . var_export($library, TRUE) . '</pre>');
$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('<pre>' . var_export($library, TRUE) . '</pre>');
$this->assertFalse($library['loaded'], 'Library with missing dependency cannot be loaded');
$library = libraries_load('example_dependency_incompatible');
$this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
$this->assertFalse($library['loaded'], 'Library with incompatible dependency cannot be loaded');
$library = libraries_load('example_dependency_compatible');
$this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
$this->assertEqual($library['loaded'], 1, 'Library with compatible dependency is loaded');
$loaded = &drupal_static('libraries_load');
$this->verbose('<pre>' . var_export($loaded, TRUE) . '</pre>');
$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:<pre>' . var_export($expected, TRUE) . '</pre>');
$this->verbose('Actual:<pre>' . var_export($library, TRUE) . '</pre>');
$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:<pre>' . var_export($expected, TRUE) . '</pre>');
$this->verbose('Actual:<pre>' . var_export($library, TRUE) . '</pre>');
$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:<pre>' . var_export($expected, TRUE) . '</pre>');
$this->verbose('Actual:<pre>' . var_export($library, TRUE) . '</pre>');
$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:<pre>' . var_export($expected, TRUE) . '</pre>');
$this->verbose('Actual:<pre>' . var_export($library, TRUE) . '</pre>');
$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 <em>info</em> callback group was invoked.', 'Info callback invoked for uncached libraries.');
$this->assertRaw('The <em>pre-detect</em> callback group was invoked.', 'Pre-detect callback invoked for uncached libraries.');
$this->assertRaw('The <em>post-detect</em> callback group was invoked.', 'Post-detect callback invoked for uncached libraries.');
$this->assertRaw('The <em>pre-load</em> callback group was invoked.', 'Pre-load callback invoked for uncached libraries.');
$this->assertRaw('The <em>post-load</em> 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 <em>info</em> callback group was not invoked.', 'Info callback not invoked for cached libraries.');
$this->assertNoRaw('The <em>pre-detect</em> callback group was not invoked.', 'Pre-detect callback not invoked for cached libraries.');
$this->assertNoRaw('The <em>post-detect</em> callback group was not invoked.', 'Post-detect callback not invoked for cached libraries.');
$this->assertRaw('The <em>pre-load</em> callback group was invoked.', 'Pre-load callback invoked for cached libraries.');
$this->assertRaw('The <em>post-load</em> 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('<script type="text/javascript" src="', '"></script>'),
'css' => array('@import url("', '");'),
// PHP files do not get added to the DOM directly.
// @see _libraries_test_load()
'php' => array('<li>', '</li>'),
);
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.");
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
/**
* @file
* Test CSS file for Libraries loading.
*
* Color the 'libraries-test-css' div purple. See README.txt for more
* information.
*/
.libraries-test-css {
color: purple;
}

View File

@@ -0,0 +1,11 @@
<?php
/**
* @file
* Test PHP file for Libraries loading.
/**
* Dummy function to see if this file was loaded.
*/
function _libraries_test_integration_file() {
}

View File

@@ -0,0 +1,12 @@
name = Libraries test module
description = Tests library detection and loading.
core = 7.x
dependencies[] = libraries
hidden = TRUE
; Information added by drupal.org packaging script on 2013-03-09
version = "7.x-2.1"
core = "7.x"
project = "libraries"
datestamp = "1362848412"

View File

@@ -0,0 +1,18 @@
/**
* @file
* Test JavaScript file for Libraries loading.
*
* Replace the text in the 'libraries-test-javascript' div. See README.txt for
* more information.
*/
(function ($) {
Drupal.behaviors.librariesTest = {
attach: function(context, settings) {
$('.libraries-test-javascript').text('If this text shows up, libraries_test.js was loaded successfully.')
}
};
})(jQuery);

View File

@@ -0,0 +1,569 @@
<?php
/**
* @file
* Tests the library detection and loading.
*/
/**
* Implements hook_libraries_info().
*/
function libraries_test_libraries_info() {
// Test library detection.
$libraries['example_missing'] = array(
'name' => '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 <em>$group</em> 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 .= '<h2>JavaScript</h2>';
$output .= '<div class="libraries-test-javascript">';
$output .= 'If this text shows up, no JavaScript test file was loaded.';
$output .= '</div>';
// For easier debugging of CSS loading, the loaded CSS files will color the
// following text.
$output .= '<h2>CSS</h2>';
$output .= '<div class="libraries-test-css">';
$output .= 'If one of the CSS test files has been loaded, this text will be colored:';
$output .= '<ul>';
// Do not reference the actual CSS files (i.e. including '.css'), because that
// breaks testing.
$output .= '<li>example_1: red</li>';
$output .= '<li>example_2: green</li>';
$output .= '<li>example_3: orange</li>';
$output .= '<li>example_4: blue</li>';
$output .= '<li>libraries_test: purple</li>';
$output .= '</ul>';
$output .= '</div>';
$output .= '<h2>PHP</h2>';
$output .= '<div class="libraries-test-php">';
$output .= 'The following is a list of all loaded test PHP files:';
$output .= '<ul>';
$files = get_included_files();
foreach ($files as $file) {
if (strpos($file, 'libraries/test') && !strpos($file, 'libraries_test.module')) {
$output .= '<li>' . str_replace(DRUPAL_ROOT . '/', '', $file) . '</li>';
}
}
$output .= '</ul>';
$output .= '</div>';
return $output;
}