View source
<?php
define('PWA_MODULE_ACTIVE_ROUTE', 'pwa/module-active');
define('PWA_SW_CACHE_EXCLUDE', [
'admin/.*',
'user/reset/.*',
]);
define('PWA_SW_REGISTRATION_EVENT_DEFAULT', 'windowonload');
function pwa_permission() {
return [
'administer pwa' => [
'title' => t('Administer Progressive Web App configuration'),
'restrict access' => TRUE,
],
'access pwa' => [
'title' => t('Access Progressive Web App'),
],
];
}
function pwa_menu() {
$items = [];
$items['pwa/serviceworker/js'] = [
'page callback' => 'pwa_serviceworker_file_data',
'access arguments' => [
'access pwa',
],
'delivery callback' => 'pwa_deliver_js_file',
'file' => 'pwa.pages.inc',
'type' => MENU_CALLBACK,
];
$items['offline'] = [
'page callback' => 'pwa_offline_page',
'access arguments' => [
'access pwa',
],
'file' => 'pwa.pages.inc',
'type' => MENU_CALLBACK,
];
$items[PWA_MODULE_ACTIVE_ROUTE] = [
'page callback' => 'pwa_module_active',
'access arguments' => [
'access pwa',
],
'file' => 'pwa.pages.inc',
'type' => MENU_CALLBACK,
];
$items['admin/config/system/pwa/manifest'] = [
'title' => t('Add to Homescreen'),
'description' => 'Control how your website appears on mobile devices when used as a PWA.',
'page callback' => 'drupal_get_form',
'page arguments' => [
'pwa_admin_configuration_manifest',
],
'access arguments' => [
'administer pwa',
],
'file' => 'pwa.admin.inc',
'type' => MENU_DEFAULT_LOCAL_TASK,
];
$items['admin/config/system/pwa/serviceworker'] = [
'title' => 'Service Worker',
'description' => 'Technical configuration for PWA Service Worker.',
'page callback' => 'drupal_get_form',
'page arguments' => [
'pwa_admin_configuration_sw',
],
'access arguments' => [
'administer pwa',
],
'file' => 'pwa.admin.inc',
'type' => MENU_LOCAL_TASK,
];
$items['admin/config/system/pwa'] = [
'title' => t('Progressive Web App'),
'description' => 'Control how your website appears on mobile devices when used as a PWA.',
'page callback' => 'drupal_get_form',
'page arguments' => [
'pwa_admin_configuration_manifest',
],
'access arguments' => [
'administer pwa',
],
'file' => 'pwa.admin.inc',
'type' => MENU_NORMAL_ITEM,
];
return $items;
}
function pwa_library() {
$path = drupal_get_path('module', 'pwa');
return [
'serviceworker' => [
'version' => '0.2',
'js' => [
$path . '/js/serviceworker-load.js' => [
'scope' => 'footer',
],
0 => [
'data' => [
'pwa' => [
'path' => url('/pwa/serviceworker/js'),
'registrationEvent' => variable_get('pwa_sw_registration_event', PWA_SW_REGISTRATION_EVENT_DEFAULT),
],
],
'type' => 'setting',
],
],
'dependencies' => [],
],
];
}
function _pwa_manifest_data() {
$path = drupal_get_path('module', 'pwa');
global $language;
$manifest = [
'name' => variable_get('pwa_name', variable_get('site_name')),
'short_name' => variable_get('pwa_short_name', variable_get('site_name')),
'description' => variable_get('pwa_description', ''),
'lang' => $language->language,
'dir' => $language->direction == LANGUAGE_LTR ? 'ltr' : 'rtl',
'background_color' => variable_get('pwa_background_color', '#ffffff'),
'theme_color' => variable_get('pwa_theme_color', '#ffffff'),
'start_url' => variable_get('pwa_start_url', '/'),
'orientation' => variable_get('pwa_orientation', 'portrait'),
'display' => variable_get('pwa_display', 'standalone'),
'icons' => [
[
'src' => url($path . '/assets/druplicon-512.png'),
'sizes' => '512x512',
'type' => 'image/png',
],
[
'src' => url($path . '/assets/druplicon-192.png'),
'sizes' => '192x192',
'type' => 'image/png',
],
[
'src' => url($path . '/assets/druplicon-144.png'),
'sizes' => '144x144',
'type' => 'image/png',
],
[
'src' => url($path . '/assets/druplicon-vector.svg'),
'type' => 'image/svg+xml',
],
],
];
drupal_alter('pwa_manifest', $manifest);
return $manifest;
}
function _pwa_manifest_file() {
$manifest = _pwa_manifest_data();
return drupal_json_encode($manifest);
}
function _pwa_serviceworker_file() {
$path = drupal_get_path('module', 'pwa');
$sw = file_get_contents($path . '/js/serviceworker.js');
$cacheUrls = (array) preg_split("/\r\n|\n|\r/", trim(variable_get('pwa_sw_cache_urls', '')));
$manifest = _pwa_manifest_data();
$cacheIcons = [];
foreach ($manifest['icons'] as $icon) {
$cacheIcons[] = $icon['src'];
}
$cacheWhitelist = array_merge($cacheUrls, $cacheIcons);
foreach ($cacheWhitelist as &$url) {
$url = url($url);
}
foreach ($cacheUrls as &$url) {
$url = url($url);
}
$pwa_module_info = system_get_info('module', 'pwa');
$pwa_module_version = $pwa_module_info['version'];
if ($pwa_module_version == null) {
$pwa_module_version = '7.x-1.x-dev';
}
$replace = [
'[/*cacheConditionsExclude*/]' => drupal_json_encode((array) preg_split("/\r\n|\n|\r/", trim(variable_get('pwa_sw_cache_exclude', '[\'' . PWA_MODULE_ACTIVE_ROUTE . '\']')))),
'[/*cacheUrls*/]' => drupal_json_encode($cacheWhitelist),
'[/*cacheUrlsAssets*/]' => drupal_json_encode((array) _pwa_fetch_offline_page_resources($cacheUrls)),
'1/*cacheVersion*/' => '\'' . $pwa_module_version . '-v' . variable_get('pwa_sw_cache_version', 1) . '\'',
'/offline' => url('/offline'),
'offline-image.png' => file_create_url(drupal_get_path('module', 'pwa') . '/assets/offline-image.png'),
];
return str_replace(array_keys($replace), array_values($replace), $sw);
}
function _pwa_fetch_offline_page_resources($pages) {
$resources = [];
foreach ($pages as $page) {
$response = drupal_http_request(url($page, [
'absolute' => TRUE,
]));
$dom = new DOMDocument();
@$dom
->loadHTML($response->data);
$xpath = new DOMXPath($dom);
foreach ($xpath
->query('//script[@src]') as $script) {
$resources[] = $script
->getAttribute('src');
}
foreach ($xpath
->query('//link[@rel="stylesheet"][@href]') as $stylesheet) {
$resources[] = $stylesheet
->getAttribute('href');
}
foreach ($xpath
->query('//img[@src]') as $image) {
$resources[] = $image
->getAttribute('src');
}
}
$dedupe = array_unique($resources);
return $dedupe;
}
function pwa_preprocess_html(&$variables) {
if (!user_access('access pwa')) {
return;
}
drupal_add_html_head([
'#tag' => 'link',
'#attributes' => [
'rel' => 'manifest',
'href' => variable_get('pwa_filecache_manifest', ''),
],
], 'manifest');
drupal_add_html_head([
'#tag' => 'meta',
'#attributes' => [
'name' => 'theme-color',
'content' => variable_get('pwa_theme_color', '#ffffff'),
],
], 'theme_color');
drupal_add_library('pwa', 'serviceworker');
drupal_add_js([
'pwa' => [
'path' => url('pwa/serviceworker/js'),
],
], 'setting');
}
function pwa_flush_caches() {
$scheme = file_default_scheme();
$directory = $scheme . '://pwa';
file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
$manifest = _pwa_manifest_file();
$manifest_uri = file_unmanaged_save_data($manifest, $directory . '/manifest.json', FILE_EXISTS_REPLACE);
$manifest_url = file_create_url($manifest_uri);
variable_set('pwa_filecache_manifest', str_replace($GLOBALS['base_url'] . '/', base_path(), $manifest_url));
cache_set('pwa:serviceworker', _pwa_serviceworker_file(), 'cache');
}
function pwa_modernizr_info() {
return [
'serviceworker',
];
}