@christianwiedemann/drupal-twig-extensions
Version:
JavaScript implementation of Drupal’s Twig extensions
128 lines (118 loc) • 4.19 kB
JavaScript
/**
* @file The file_url function
*
* Docs for FileUrlGenerator::generateString (Drupal 9.3.x):
*
* ```
* new TwigFunction('file_url', [$this->fileUrlGenerator, 'generateString'])
* ```
*
* ```
* Creates a root-relative web-accessible URL string.
*
* @param string $uri
* The URI to a file for which we need an external URL, or the path to a
* shipped file.
*
* @return string
* For a local URL (matching domain), a root-relative string containing a
* URL that may be used to access the file. An absolute URL may be returned
* when using a CDN or a remote stream wrapper.
*
* @throws \Drupal\Core\File\Exception\InvalidStreamWrapperException
* If a stream wrapper could not be found to generate an external URL.
* ```
*/
export const name = 'file_url';
export const options = {};
export const acceptedArguments = [{ name: 'uri' }];
/**
* Creates a root-relative web-accessible URL string.
*
* @param {Object<string, ?string|Object<string, ?string>>} config
* The shared Drupal config.
* @param {string} uri
* The URI to a file for which we need an external URL, or the path to a
* shipped file.
*
* @returns {string}
* For a local URL (matching domain), a root-relative string containing a
* URL that may be used to access the file. An absolute URL may be returned
* when using a CDN or a remote stream wrapper.
*
* @throws \Drupal\Core\File\Exception\InvalidStreamWrapperException
* If a stream wrapper could not be found to generate an external URL.
*/
export function fileUrl(config, uri) {
// Non-strings are cast to a string with Drupal's file_url.
const path = `${uri}`;
// This regex matches against uri schemes (e.g. 'public://', 'https://'). It
// is copied from \Drupal\Core\StreamWrapper\StreamWrapperManager::getScheme()
const scheme = /^([\w-]+):\/\//;
// If the uri includes a streamWrapper scheme, replace it.
if (
scheme.test(path) &&
Object.keys(config.streamWrapper).includes(path.match(scheme)[0])
) {
return `${config.baseUrl}${path.replace(scheme, (substring) => {
return config.streamWrapper[substring] + '/';
})}`;
}
// Allow for:
// - root-relative URIs (e.g. /foo.jpg in http://example.com/foo.jpg)
// - protocol-relative URIs (e.g. //bar.jpg, which is expanded to
// http://example.com/bar.jpg by the browser when viewing a page over
// HTTP and to https://example.com/bar.jpg when viewing a HTTPS page)
// Both types of relative URIs are characterized by a leading slash, hence
// we can use a single check.
if (path.slice(0, 1) === '/') {
return path;
}
// TODO: Add escaping of path, query and fragment.
// If this is not a properly formatted stream, then it is a shipped
// file. Therefore, return the urlencoded URI with the base URL
// prepended.
// $options = UrlHelper::parse($uri);
// $path = $base_url . UrlHelper::encodePath($options['path']);
// // Append the query.
// if ($options['query']) {
// $path .= '?' . UrlHelper::buildQuery($options['query']);
// }
//
// // Append fragment.
// if ($options['fragment']) {
// $path .= '#' . $options['fragment'];
// }
return path;
}
/**
* Initializes the Drupal base_url and streamWrapper config.
*
* @param {Object<string, ?string|Object<string, ?string>>} state
* The shared configuration state object.
* @param {Object<string, ?string|Object<string, ?string>>} config
* The Drupal config to save.
*/
export function configInit(state, config) {
// The default Drupal base_url.
state.baseUrl = '/';
// The default Drupal streamWrapper paths.
state.streamWrapper = {
'public://': 'sites/default/files',
'private://': 'sites/default/private',
'temporary://': 'sites/default/tmp',
};
if (Object.prototype.hasOwnProperty.call(config, 'base_url')) {
state.baseUrl = config.base_url;
if (state.baseUrl.slice(-1) !== '/') {
state.baseUrl += '/';
}
}
if (Object.prototype.hasOwnProperty.call(config, 'streamWrapper')) {
// Merge the given streamWrapper with the defaults.
state.streamWrapper = {
...state.streamWrapper,
...config.streamWrapper,
};
}
}