View source
<?php
use Drupal\Core\Form\FormStateInterface;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\Core\Menu\MenuLinkInterface;
define('RESPONSIVE_MENU_BREAKPOINT_FILENAME', '/responsive_menu_breakpoint.css');
function responsive_menu_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'responsive_menu.settings':
$readme = Link::fromTextAndUrl('README.md', Url::fromUri('base:' . drupal_get_path('module', 'responsive_menu') . '/README.md'))
->toRenderable();
return '<p>' . t('3rd party libraries are required to enable some of the features. See the @readme file for more information about where to download and place them.', [
'@readme' => render($readme),
]) . '</p><p>' . t("At a minimum you need to place the 'Responsive menu mobile icon' block in a region. If you want to display a horizontal menu at a specified breakpoint then you also need to place the 'Horizontal menu' block, although this is optional.") . '</p>';
}
}
function responsive_menu_theme($existing, $type, $theme, $path) {
$return = [];
$return['responsive_menu_block_wrapper'] = [
'template' => 'responsive-menu-block-wrapper',
'variables' => [
'content' => [],
],
];
$return['responsive_menu_block_toggle'] = [
'template' => 'responsive-menu-block-toggle',
'variables' => [],
];
$return['responsive_menu_horizontal'] = [
'template' => 'responsive-menu-horizontal',
'variables' => [
'items' => [],
'menu_name' => '',
'attributes' => [],
],
'preprocess functions' => [
'template_preprocess',
'contextual_preprocess',
'template_preprocess_horizontal',
'responsive_menu_preprocess_horizontal',
],
];
$return['responsive_menu_page_wrapper'] = [
'template' => 'responsive-menu-page-wrapper',
'variables' => [
'children' => [],
],
];
return $return;
}
function responsive_menu_preprocess_block(&$variables) {
if ($variables['plugin_id'] == 'responsive_menu_toggle') {
$variables['attributes']['class'][] = 'responsive-menu-toggle-wrapper';
$variables['attributes']['class'][] = 'responsive-menu-toggle';
unset($variables['title_suffix']['contextual_links']);
}
}
function responsive_menu_preprocess_html(&$variables) {
$config = \Drupal::config('responsive_menu.settings');
if (_current_theme_is_admin()) {
if ($config
->get('allow_admin') && $config
->get('wrapper_admin')) {
$variables['page']['#theme_wrappers'][] = 'responsive_menu_page_wrapper';
}
}
else {
if ($config
->get('wrapper_theme') == TRUE) {
$variables['page']['#theme_wrappers'][] = 'responsive_menu_page_wrapper';
}
}
}
function responsive_menu_page_bottom(&$page) {
$config = \Drupal::config('responsive_menu.settings');
if ($config
->get('allow_admin') == FALSE && _current_theme_is_admin()) {
return;
}
$output = [
'#prefix' => '<div class="off-canvas-wrapper"><div id="off-canvas">',
'#suffix' => '</div></div>',
'#pre_render' => [
'responsive_menu_off_canvas_pre_render',
],
];
if ($config
->get('use_breakpoint')) {
if (!file_exists(_get_breakpoint_css_filepath() . RESPONSIVE_MENU_BREAKPOINT_FILENAME)) {
$breakpoint = $config
->get('horizontal_media_query');
responsive_menu_generate_breakpoint_css($breakpoint);
}
$output['#attached']['library'][] = 'responsive_menu/responsive_menu.breakpoint';
}
$hammerjs_setting = $config
->get('hammerjs');
if ($hammerjs_setting) {
$output['#attached']['library'][] = 'responsive_menu/responsive_menu.hammerjs';
}
$output['#attached']['library'][] = 'responsive_menu/responsive_menu.mmenu';
$output['#attached']['library'][] = 'responsive_menu/responsive_menu.config';
if ($config
->get('include_css')) {
$output['#attached']['library'][] = 'responsive_menu/responsive_menu.styling';
}
$output['#attached']['drupalSettings']['responsive_menu'] = [
'position' => $config
->get('off_canvas_position'),
'theme' => $config
->get('off_canvas_theme'),
'pagedim' => $config
->get('pagedim'),
'breakpoint' => $config
->get('horizontal_media_query'),
'extension_keyboard' => $config
->get('extension_keyboard'),
'superfish' => [
'active' => $config
->get('horizontal_superfish'),
'delay' => $config
->get('horizontal_superfish_delay'),
'speed' => $config
->get('horizontal_superfish_speed'),
'speedOut' => $config
->get('horizontal_superfish_speed_out'),
],
];
$output['#cache']['keys'] = [
'responsive_menu',
'off_canvas',
];
$off_canvas_menus = \Drupal::config('responsive_menu.settings')
->get('off_canvas_menus');
\Drupal::ModuleHandler()
->alter('responsive_menu_off_canvas_menu_names', $off_canvas_menus);
$menus = explode(',', $off_canvas_menus);
$output['#cache']['keys'] += $menus;
foreach ($menus as $menu_name) {
$output['#cache']['tags'][] = 'config:system.menu.' . $menu_name;
$output['#cache']['context'][] = 'route.menu_active_trails:' . $menu_name;
}
$page['page_bottom']['off_canvas'] = $output;
}
function responsive_menu_off_canvas_pre_render(array $build) {
$off_canvas_menus = \Drupal::config('responsive_menu.settings')
->get('off_canvas_menus');
\Drupal::ModuleHandler()
->alter('responsive_menu_off_canvas_menu_names', $off_canvas_menus);
$menus = explode(',', $off_canvas_menus);
$combined_tree = [];
$menu_tree = \Drupal::menuTree();
$manipulators = [
[
'callable' => 'menu.default_tree_manipulators:checkNodeAccess',
],
[
'callable' => 'menu.default_tree_manipulators:checkAccess',
],
[
'callable' => 'menu.default_tree_manipulators:generateIndexAndSort',
],
];
foreach ($menus as $menu_name) {
$menu_name = trim($menu_name);
$parameters = $menu_tree
->getCurrentRouteMenuTreeParameters($menu_name);
$parameters->expandedParents = [];
$tree_items = $menu_tree
->load($menu_name, $parameters);
$tree_manipulated = $menu_tree
->transform($tree_items, $manipulators);
$combined_tree = array_merge($combined_tree, $tree_manipulated);
$build['#cache']['contexts'][] = 'route.menu_active_trails:' . $menu_name;
$build['#cache']['tags'][] = 'config:system.menu.' . $menu_name;
}
$menu = $menu_tree
->build($combined_tree);
\Drupal::ModuleHandler()
->alter('responsive_menu_off_canvas_tree', $menu);
$build['#markup'] = \Drupal::service("renderer")
->renderRoot($menu);
return $build;
}
function responsive_menu_form_menu_link_content_form_alter(&$form, FormStateInterface $form_state) {
$menu_link = $form_state
->getFormObject()
->getEntity();
$menu_link_options = $menu_link->link
->first()->options ?: [];
$flyleft = isset($menu_link_options['attributes']['flyleft']) ? TRUE : FALSE;
$build_info = $form_state
->getBuildInfo()['callback_object'];
$menu_link_content = $build_info
->getEntity();
$parent = $menu_link_content->parent->value;
if (!$parent) {
return;
}
$definition = \Drupal::service('plugin.manager.menu.link')
->hasDefinition($parent);
if (!$definition) {
return;
}
$parent_link = \Drupal::service('plugin.manager.menu.link')
->createInstance($parent);
$grandparent = $parent_link
->getParent();
if (!empty($grandparent)) {
$form['flyleft'] = [
'#type' => 'checkbox',
'#title' => t('Fly left'),
'#description' => t('Whether this item (and its children) should fly left instead of right'),
'#default_value' => $flyleft,
];
$form['#submit'][] = 'responsive_menu_menu_link_content_submit';
$form['actions']['submit']['#submit'][] = 'responsive_menu_menu_link_content_submit';
}
}
function responsive_menu_menu_link_content_submit($form, FormStateInterface $form_state) {
if ($form_state
->getValue('flyleft')) {
$menu_link = $form_state
->getFormObject()
->getEntity();
$options = [
'attributes' => [
'flyleft' => TRUE,
],
];
$menu_link_options = $menu_link->link
->first()->options;
$menu_link->link
->first()->options = array_merge($menu_link_options, $options);
$menu_link
->save();
}
}
function responsive_menu_preprocess_horizontal(&$variables) {
foreach ($variables['items'] as &$item) {
responsive_menu_assign_attributes_to_item($item);
}
}
function responsive_menu_assign_attributes_to_item(array &$item) {
$item['fly_left'] = responsive_menu_get_flyleft_attribute($item['original_link']);
if (!empty($item['below'])) {
foreach ($item['below'] as &$item) {
responsive_menu_assign_attributes_to_item($item);
}
}
}
function responsive_menu_get_flyleft_attribute(MenuLinkInterface $menu_link_content_plugin) {
try {
$plugin_id = $menu_link_content_plugin
->getPluginId();
} catch (PluginNotFoundException $e) {
return FALSE;
}
if (strpos($plugin_id, ':') === FALSE) {
return FALSE;
}
list($entity_type, $uuid) = explode(':', $plugin_id, 2);
if ($entity_type == 'menu_link_content') {
$entity = \Drupal::entityManager()
->loadEntityByUuid($entity_type, $uuid);
if ($entity) {
$options = $entity->link
->first()->options;
$attributes = isset($options['attributes']) ? $options['attributes'] : [];
if (isset($attributes['flyleft'])) {
return TRUE;
}
}
}
return FALSE;
}
function responsive_menu_get_breakpoints() {
$queries = [];
$theme_settings = \Drupal::config('system.theme')
->get();
$default_theme = $theme_settings['default'];
$breakpoint_groups = \Drupal::service('breakpoint.manager')
->getGroups();
foreach ($breakpoint_groups as $key => $value) {
if (strpos($key, $default_theme) !== 0) {
continue;
}
$breakpoints = \Drupal::service('breakpoint.manager')
->getBreakpointsByGroup($key);
foreach ($breakpoints as $breakpoint) {
$label = $breakpoint
->getLabel()
->render();
$mediaQuery = $breakpoint
->getMediaQuery();
if ($mediaQuery) {
$queries[$label] = $mediaQuery;
}
}
}
return $queries;
}
function responsive_menu_library_info_build() {
$libraries = [];
$libraries['responsive_menu.breakpoint'] = [
'css' => [
'theme' => [
_get_breakpoint_css_filepath() . RESPONSIVE_MENU_BREAKPOINT_FILENAME => [],
],
],
];
return $libraries;
}
function responsive_menu_generate_breakpoint_css($breakpoint) {
$element = \Drupal::config('responsive_menu.settings')
->get('horizontal_wrapping_element');
$css = '@media ' . $breakpoint . ' { ' . $element . '.responsive-menu-block-wrapper { display: block; } .responsive-menu-toggle-wrapper.responsive-menu-toggle { display: none; } }';
$path = _get_breakpoint_css_filepath();
if (!file_exists($path)) {
file_prepare_directory($path, FILE_CREATE_DIRECTORY);
}
$filepath = $path . RESPONSIVE_MENU_BREAKPOINT_FILENAME;
file_unmanaged_save_data($css, $filepath, FILE_EXISTS_REPLACE);
}
function responsive_menu_preprocess_toolbar(&$variables) {
$config = \Drupal::config('responsive_menu.settings');
if (!$config
->get('allow_admin') && _current_theme_is_admin()) {
return;
}
$variables['#attached']['library'][] = 'responsive_menu/responsive_menu.toolbar';
}
function responsive_menu_cache_flush() {
$path = _get_breakpoint_css_filepath();
if (file_exists($path . RESPONSIVE_MENU_BREAKPOINT_FILENAME)) {
unlink($path . RESPONSIVE_MENU_BREAKPOINT_FILENAME);
}
}
function _get_breakpoint_css_filepath() {
return \Drupal::config('responsive_menu.settings')
->get('breakpoint_css_filepath');
}
function _current_theme_is_admin() {
$theme_info =& drupal_static(__FUNCTION__);
if (!isset($theme_info)) {
$theme_info['system_theme'] = \Drupal::config('system.theme');
$theme_info['admin_theme'] = $theme_info['system_theme']
->get('admin');
$theme_info['current_theme'] = \Drupal::service('theme.manager')
->getActiveTheme()
->getName();
}
return $theme_info['current_theme'] == $theme_info['admin_theme'] ? TRUE : FALSE;
}