crownpeak_autofix-1.0.0-alpha3/crownpeak_autofix.module
crownpeak_autofix.module
<?php /** * @file * General functionality for crownpeak autofix. */ use Drupal\Core\Asset\AttachedAssetsInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Routing\RouteMatchInterface; define('CROWNPEAK_AUTOFIX_JS_PATH', 'public://js'); // Crownpeak button type. define('CROWNPEAK_AUTOFIX_TRIGGER_BUTTON_TYPE_CROWNPEAK', 'crownpeak'); define('CROWNPEAK_AUTOFIX_TRIGGER_BUTTON_TYPE_BLOCK', 'block'); define('CROWNPEAK_AUTOFIX_TRIGGER_BUTTON_TYPE_CUSTOM', 'custom'); /** * Implements hook_help(). */ function crownpeak_autofix_help($route_name, RouteMatchInterface $route_match) { switch ($route_name) { case 'help.page.crownpeak_autofix': $output = ''; $output .= '<h3>' . t('About') . '</h3>'; $output .= '<p>' . t('Crownpeak Autofix provides an integration with crownpeak autofix service.') . '</p>'; $output .= '<h3>' . t('Uses') . '</h3>'; return $output; } } /** * Implements hook_theme(). */ function crownpeak_autofix_theme() { return [ 'crownpeak_autofix_js' => [ 'variables' => [ 'crownpeak_autofix_configs' => NULL, ], ], 'crownpeak_autofix_trigger_block' => [ 'variables' => [], ], ]; } /** * Implements hook_page_attachments(). * * Insert JavaScript to the appropriate scope/region of the page. */ function crownpeak_autofix_page_attachments(array &$page) { if (!_crownpeak_autofix_visibility_trigger_button_type()) { return; } $account = \Drupal::currentUser(); if (_crownpeak_autofix_visibility_roles($account) || _crownpeak_autofix_visibility_pages()) { $page['#attached']['library'][] = 'crownpeak_autofix/crownpeak_autofix_widget'; } } /** * Implements hook_js_alter(). */ function crownpeak_autofix_js_alter(&$javascript, AttachedAssetsInterface $assets) { foreach ($javascript as $key => $script) { if (strpos($key, '[crownpeak_autofix_js_placeholder]') !== FALSE) { $crownpeak_autofix_js_suffix = \Drupal::state()->get('crownpeak_autofix_js_suffix') ?: NULL; $crownpeak_autofix_current_js = CROWNPEAK_AUTOFIX_JS_PATH . '/crownpeak_autofix_' . $crownpeak_autofix_js_suffix . '.js'; $javascript[$key]['data'] = \Drupal::service('file_url_generator')->generateString($crownpeak_autofix_current_js); } } } /** * Implements hook_rebuild(). */ function crownpeak_autofix_rebuild() { crownpeak_autofix_generate_js(); } /** * Build JS based on form settings. */ function crownpeak_autofix_build_js($crownpeak_autofix_configs) { // Rendering JS based on form settings. $render_array_js = [ '#theme' => 'crownpeak_autofix_js', '#crownpeak_autofix_configs' => [ 'accessibility_statement_link' => $crownpeak_autofix_configs->get('accessibility_statement_link'), 'feedback_form_link' => $crownpeak_autofix_configs->get('feedback_form_link'), 'hide_trigger_button' => ($crownpeak_autofix_configs->get('trigger_button_type') === CROWNPEAK_AUTOFIX_TRIGGER_BUTTON_TYPE_CROWNPEAK) ? 'false' : 'true', 'interface_language' => $crownpeak_autofix_configs->get('interface_language'), 'interface_lead_color' => $crownpeak_autofix_configs->get('interface_lead_color'), 'trigger_button_color' => $crownpeak_autofix_configs->get('trigger_button_color'), 'interface_position' => $crownpeak_autofix_configs->get('interface_position'), 'hide_on_mobile' => $crownpeak_autofix_configs->get('hide_on_mobile'), 'trigger_horizontal_position' => $crownpeak_autofix_configs->get('trigger_horizontal_position'), 'trigger_vertical_position' => $crownpeak_autofix_configs->get('trigger_vertical_position'), 'mobile_trigger_horizontal_position' => $crownpeak_autofix_configs->get('mobile_trigger_horizontal_position'), 'mobile_trigger_vertical_position' => $crownpeak_autofix_configs->get('mobile_trigger_vertical_position'), 'trigger_button_size' => $crownpeak_autofix_configs->get('trigger_button_size'), 'mobile_trigger_size' => $crownpeak_autofix_configs->get('mobile_trigger_size'), 'trigger_button_shape' => $crownpeak_autofix_configs->get('trigger_button_shape'), 'mobile_trigger_shape' => $crownpeak_autofix_configs->get('mobile_trigger_shape'), 'trigger_button_icon' => $crownpeak_autofix_configs->get('trigger_button_icon'), 'trigger_horizontal_offset' => $crownpeak_autofix_configs->get('trigger_horizontal_offset'), 'trigger_vertical_offset' => $crownpeak_autofix_configs->get('trigger_vertical_offset'), 'mobile_trigger_horizontal_offset' => $crownpeak_autofix_configs->get('mobile_trigger_horizontal_offset'), 'mobile_trigger_vertical_offset' => $crownpeak_autofix_configs->get('mobile_trigger_vertical_offset'), ], ]; $renderer = \Drupal::service('renderer'); return $renderer->renderPlain($render_array_js); } /** * Generate JS based on form settings. */ function crownpeak_autofix_generate_js() { $js_path = CROWNPEAK_AUTOFIX_JS_PATH; $crownpeak_autofix_configs = \Drupal::config('crownpeak_autofix.settings'); $crownpeak_autofix_js = crownpeak_autofix_build_js($crownpeak_autofix_configs); // Generate suffix for new js file. $js_suffix = \Drupal::time()->getRequestTime(); // Delete old js file if exists. $js_old_suffix = \Drupal::state()->get('crownpeak_autofix_js_suffix') ?: NULL; if ($js_old_suffix) { \Drupal::service('file_system')->delete($js_path . '/crownpeak_autofix_' . $js_old_suffix . '.js'); } // Save suffix to db. \Drupal::state()->set('crownpeak_autofix_js_suffix', $js_suffix); // Save the JS to a file in the files directory. // make directory writable if it is read-only. \Drupal::service('file_system')->prepareDirectory($js_path, FileSystemInterface::MODIFY_PERMISSIONS); \Drupal::service('file_system')->saveData($crownpeak_autofix_js, $js_path . '/crownpeak_autofix_' . $js_suffix . '.js', FileSystemInterface::EXISTS_REPLACE); // We should flush JS cache so that aggregated JS gets rebuilt. \Drupal::service('asset.js.collection_optimizer')->deleteAll(); _drupal_flush_css_js(); } /** * Checking visibility by trigger type. * * Return true only if in configuration is selected 'crownpeak' or 'custom' * options for trigger button type. */ function _crownpeak_autofix_visibility_trigger_button_type() { $config = \Drupal::config('crownpeak_autofix.settings'); return in_array($config->get('trigger_button_type'), [ CROWNPEAK_AUTOFIX_TRIGGER_BUTTON_TYPE_CROWNPEAK, CROWNPEAK_AUTOFIX_TRIGGER_BUTTON_TYPE_CUSTOM, ]); } /** * Checking visibility for user roles. * * Based on visibility setting this function returns TRUE if JS code should * be added for the current role and otherwise FALSE. * * @param object $account * A user object containing an array of roles to check. * * @return bool * TRUE if JS code should be added for the current role and otherwise FALSE. */ function _crownpeak_autofix_visibility_roles($account) { $config = \Drupal::config('crownpeak_autofix.settings'); $enabled = $visibility_user_role_mode = $config->get('visibility_user_role_mode'); $visibility_user_role_roles = $config->get('visibility_user_role_roles'); if (count($visibility_user_role_roles) > 0) { // One or more roles are selected. foreach (array_values($account->getRoles()) as $user_role) { // Is the current user a member of one of these roles? if (in_array($user_role, $visibility_user_role_roles, TRUE)) { // Current user is a member of a role widget should be shown/excluded // from tracking. $enabled = !$visibility_user_role_mode; break; } } } else { // No role is selected for showing widget, therefore all roles should be // tracked. $enabled = TRUE; } return $enabled; } /** * Checking visibility for pages. * * Based on visibility setting this function returns TRUE if JS code should * be added to the current page and otherwise FALSE. */ function _crownpeak_autofix_visibility_pages() { static $page_match; // Cache visibility result if function is called more than once. if (!isset($page_match)) { $config = \Drupal::config('crownpeak_autofix.settings'); $visibility_request_path_mode = $config->get('visibility_request_path_mode'); $visibility_request_path_pages = $config->get('visibility_request_path_pages'); // Match path if necessary. if (!empty($visibility_request_path_pages)) { // Convert path to lowercase. This allows comparison of the same path // with different case. Ex: /Page, /page, /PAGE. $pages = mb_strtolower($visibility_request_path_pages); if ($visibility_request_path_mode < 2) { // Compare the lowercase path alias (if any) and internal path. $path = \Drupal::service('path.current')->getPath(); $path_alias = mb_strtolower(\Drupal::service('path_alias.manager')->getAliasByPath($path)); $page_match = \Drupal::service('path.matcher')->matchPath($path_alias, $pages) || (($path != $path_alias) && \Drupal::service('path.matcher')->matchPath($path, $pages)); // When $visibility_request_path_mode has a value of 0, the tracking // code is displayed on all pages except those listed in $pages. When // set to 1, it is displayed only on those pages listed in $pages. $page_match = !($visibility_request_path_mode xor $page_match); } else { $page_match = FALSE; } } else { $page_match = TRUE; } } return $page_match; }