directories. if (file_exists("profiles/$profile/$directory")) { $searchdir[] = "profiles/$profile/$directory"; } // Always search sites/all/*. $searchdir[] = 'sites/all/' . $directory; // Also search sites//*. if (file_exists("$config/$directory")) { $searchdir[] = "$config/$directory"; } // Retrieve list of directories. // @todo Core: Allow to scan for 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; } /** * Returns information about registered libraries. * * The returned information is unprocessed, i.e. as registered by modules. * * @param $library * (optional) The internal name of a library to return registered information * for, or FALSE if no library with the given name exists. If omitted, * information about all libraries is returned. * * @return * An associative array containing registered information for all libraries, * or the registered information for the library specified by $name. * * @see hook_libraries_info() * * @todo Re-introduce support for include file plugin system - either by copying * Wysiwyg's code, or directly switching to CTools. */ function libraries_info($library = NULL) { $libraries = &drupal_static(__FUNCTION__); if (!isset($libraries)) { $libraries = array(); foreach (module_implements('libraries_info') as $module) { foreach (module_invoke($module, 'libraries_info') as $name => $properties) { $properties['module'] = $module; $properties['name'] = $name; $properties += array( 'title' => $name, 'vendor url' => '', 'download url' => '', 'path' => '', 'version callback' => 'libraries_get_version', 'version arguments' => array(), 'files' => array(), 'variants' => array(), 'versions' => array(), 'integration files' => array(), ); $libraries[$name] = $properties; } } // Allow modules to alter the registered libraries. drupal_alter('libraries_info', $libraries); } if (isset($library)) { return !empty($libraries[$library]) ? $libraries[$library] : FALSE; } return $libraries; } /** * Detect libraries and library versions. * * @todo It makes little sense to pass $libraries by reference here. We need to * figure out whether, and if, how we want to retain the processed * information. I.e. either use a static cache here, or make libraries_info() * conditionally invoke libraries_detect($name). D7 only way: Re-use * drupal_static() of libraries_info() - but would still require to update the * (DB) cache (there likely will be one soon). * Also, we probably do not want to ALWAYS parse ALL possible libraries; rather, * the requesting/consuming module likely wants to know whether a list of * supported libraries (possibly those registered by itself, or in a certain * "category") is available... Food for thought. * * @param $libraries * An array of libraries to detect, as returned from libraries_info(). * * @see libraries_info() */ function libraries_detect($libraries) { foreach ($libraries as &$library) { libraries_detect_library($library); } return $libraries; } /** * Tries to detect a library and its installed version. * * @param $library * An associative array describing a single library, as returned from * libraries_info(), passed by reference. */ function libraries_detect_library(&$library) { $library['installed'] = FALSE; $name = $library['name']; // Check whether the library exists. if (!isset($library['library path'])) { $library['library path'] = libraries_get_path($name); } if (!file_exists($library['library path'])) { $library['error'] = t('%library could not be found.', array('%library' => $library['title'])); return; } // Detect library version. // We support both a single parameter, which is an associative array, and an // indexed array of multiple parameters. if (isset($library['version arguments'][0])) { // Add the library as the first argument. $library['version'] = call_user_func_array($library['version callback'], array_merge(array($library), $library['version arguments'])); } else { $library['version'] = $library['version callback']($library, $library['version arguments']); } if (empty($library['version'])) { $library['error'] = t('The version of %library could not be detected.', array('%library' => $library['title'])); return; } // Determine to which supported version the installed version maps. if (!empty($library['versions'])) { ksort($library['versions']); $version = 0; foreach ($library['versions'] as $supported_version => $version_properties) { if (version_compare($library['version'], $supported_version, '>=')) { $version = $supported_version; } } if (!$version) { $library['error'] = t('The installed version %version of %library is not supported.', array( '%version' => $library['version'], '%library' => $library['title'], )); return; } // Apply version specific definitions and overrides. $library = array_merge($library, $library['versions'][$version]); unset($library['versions']); } // Check each variant if it is installed. if (!empty($library['variants'])) { foreach ($library['variants'] as $name => &$variant) { // If no variant callback has been set, assume the variant to be // installed. $variant['installed'] = TRUE; if (!empty($variant['variant callback'])) { // 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, $name), $variant['variant arguments'])); } else { $variant['installed'] = $variant['variant callback']($library, $name, $variant['variant arguments']); } if (empty($variant['installed'])) { $variant['error'] = t('The %variant variant of %library could not be found.', array( '%variant' => $name, '%library' => $library['title'], )); } } } } // If we end up here, the library should be usable. $library['installed'] = TRUE; } /** * Loads a library. * * @param $library * The name of the library to load. * @param $variant * The name of the variant to load. */ function libraries_load($library, $variant = NULL) { $library = libraries_info($library); libraries_detect_library($library); libraries_load_files($library, $variant); } /** * Loads a library's files. * * @param $library * The name of the library to load. * @param $variant * The name of the variant to load. */ function libraries_load_files($library, $variant = NULL) { // Construct the full path to the library for later use. $path = !empty($library['path']) ? $library['library path'] . '/' . $library['path'] : $library['library path']; // If a variant was specified, override the top-level properties with the // variant properties. if (!empty($variant) && !empty($library['variants'][$variant]['installed'])) { $library = array_merge($library, $library['variants'][$variant]); } // Load integration files. if (!empty($library['integration files'])) { foreach ($library['integration files'] as $module => $files) { libraries_load_files(array( 'files' => $files, 'library path' => drupal_get_path('module', $module), )); } } // Load both the JavaScript and the CSS files. // The parameters for drupal_add_js() and drupal_add_css() require special // handling. // @see drupal_process_attached() foreach (array('js', 'css') as $type) { if (!empty($library['files'][$type])) { foreach ($library['files'][$type] as $data => $options) { // If the value is not an array, it's a filename and passed as first // (and only) argument. if (!is_array($options)) { // Prepend the library path to the file name. $data = "$path/$options"; $options = NULL; } // In some cases, the first parameter ($data) is an array. Arrays can't be // passed as keys in PHP, so we have to get $data from the value array. if (is_numeric($data)) { $data = $options['data']; unset($options['data']); } // Apply the default weight if the weight isn't explicitly given. if (!isset($options['weight'])) { $options['weight'] = ($type == 'js') ? JS_DEFAULT : CSS_DEFAULT; } call_user_func('drupal_add_' . $type, $data, $options); } } } // Load PHP files. if (!empty($library['files']['php'])) { foreach ($library['files']['php'] as $file) { $file_path = DRUPAL_ROOT . '/' . $path . '/' . $file; if (file_exists($file_path)) { require_once $file_path; } } } } /** * 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 (\d+)\.(\d+)/'. * - 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); }