'Views', 'description' => 'Manage customized lists of content.', 'route_name' => 'views_ui.list', ); // @todo - remove all items of type MENU_VISIBLE_IN_BREADCRUMB // when there is a route-aware breadcrumb builder. $items['admin/structure/views/settings'] = array( 'title' => 'Settings', 'route_name' => 'views_ui.settings_basic', 'type' => MENU_VISIBLE_IN_BREADCRUMB, ); $items['admin/structure/views/settings/advanced'] = array( 'title' => 'Advanced', 'route_name' => 'views_ui.settings_advanced', 'type' => MENU_VISIBLE_IN_BREADCRUMB, ); // The primary Edit View page. Secondary tabs for each Display are added in // views_ui_menu_local_tasks_alter(). $items['admin/structure/views/view/%'] = array( 'route_name' => 'views_ui.edit', ); $items['admin/structure/views/view/%/edit'] = array( 'title' => 'Edit view', 'type' => MENU_DEFAULT_LOCAL_TASK, 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE, ); $items['admin/structure/views/view/%/preview/%'] = array( 'route_name' => 'views_ui.preview', 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE, 'type' => MENU_VISIBLE_IN_BREADCRUMB, ); // Additional pages for acting on a View. $items['admin/structure/views/view/%/break-lock'] = array( 'title' => 'Break lock', 'route_name' => 'views_ui.break_lock', 'type' => MENU_VISIBLE_IN_BREADCRUMB, ); // NoJS/AJAX callbacks that can use the default Views AJAX form system. $items['admin/structure/views/nojs/%/%'] = array( 'type' => MENU_VISIBLE_IN_BREADCRUMB, ); // A page in the Reports section to show usage of fields in all views $items['admin/reports/fields/views-fields'] = array( 'title' => 'Used in views', 'description' => 'Overview of fields used in all views.', 'route_name' => 'views_ui.reports_fields', 'type' => MENU_LOCAL_TASK, ); // A page in the Reports section to show usage of plugins in all views. $items['admin/reports/views-plugins'] = array( 'title' => 'Views plugins', 'description' => 'Overview of plugins used in all views.', 'route_name' => 'views_ui.reports_plugins', ); return $items; } /** * Implements hook_entity_info(). */ function views_ui_entity_info(&$entity_info) { $entity_info['view']['controllers'] += array( 'list' => 'Drupal\views_ui\ViewListController', 'form' => array( 'edit' => 'Drupal\views_ui\ViewEditFormController', 'add' => 'Drupal\views_ui\ViewAddFormController', 'preview' => 'Drupal\views_ui\ViewPreviewFormController', 'clone' => 'Drupal\views_ui\ViewCloneFormController', 'delete' => 'Drupal\views_ui\ViewDeleteFormController', 'break_lock' => 'Drupal\views_ui\Form\BreakLockForm', ), ); } /** * Implements hook_theme(). */ function views_ui_theme() { return array( // edit a view 'views_ui_display_tab_setting' => array( 'variables' => array('description' => '', 'link' => '', 'settings_links' => array(), 'overridden' => FALSE, 'defaulted' => FALSE, 'description_separator' => TRUE, 'class' => array()), 'template' => 'views-ui-display-tab-setting', 'file' => 'views_ui.theme.inc', ), 'views_ui_display_tab_bucket' => array( 'render element' => 'element', 'template' => 'views-ui-display-tab-bucket', 'file' => 'views_ui.theme.inc', ), 'views_ui_rearrange_filter_form' => array( 'render element' => 'form', 'file' => 'views_ui.theme.inc', ), 'views_ui_expose_filter_form' => array( 'render element' => 'form', 'file' => 'views_ui.theme.inc', ), // list views 'views_ui_view_info' => array( 'variables' => array('view' => NULL, 'displays' => NULL), 'file' => 'views_ui.theme.inc', 'template' => 'views-ui-view-info', ), // Group of filters. 'views_ui_build_group_filter_form' => array( 'render element' => 'form', 'file' => 'views_ui.theme.inc', ), // On behalf of a plugin 'views_ui_style_plugin_table' => array( 'render element' => 'form', 'file' => 'views_ui.theme.inc', 'template' => 'views-ui-style-plugin-table', ), // When previewing a view. 'views_ui_view_preview_section' => array( 'variables' => array('view' => NULL, 'section' => NULL, 'content' => NULL, 'links' => ''), 'file' => 'views_ui.theme.inc', 'template' => 'views-ui-view-preview-section', ), // Generic container wrapper, to use instead of theme_container when an id // is not desired. 'views_ui_container' => array( 'variables' => array('children' => NULL, 'attributes' => array()), 'template' => 'views-ui-container', 'file' => 'views_ui.theme.inc', ), ); } /** * Implements hook_permission(). */ function views_ui_permission() { return array( 'administer views' => array( 'title' => t('Administer views'), 'description' => t('Access the views administration pages.'), 'restrict access' => TRUE, ), ); } /** * Implements hook_library_info(). */ function views_ui_library_info() { $libraries = array(); $path = drupal_get_path('module', 'views_ui') . '/js/'; $libraries['views_ui.admin'] = array( 'title' => 'Views UI ADMIN', 'version' => \Drupal::VERSION, 'js' => array( $path . 'ajax.js' => array('group' => JS_DEFAULT), $path . 'views-admin.js' => array('group' => JS_DEFAULT), ), 'dependencies' => array( array('system', 'jquery'), array('system', 'drupal'), array('system', 'drupalSettings'), array('system', 'drupal.debounce'), array('system', 'jquery.once'), array('system', 'jquery.form'), array('system', 'drupal.ajax'), array('views', 'views.ajax'), ), ); $libraries['views_ui.listing'] = array( 'title' => 'Views UI listing', 'version' => Drupal::VERSION, 'js' => array( $path . 'views_ui.listing.js' => array('group' => JS_DEFAULT), ), ); return $libraries; } /** * Implements hook_preprocess_HOOK() for views templates. */ function views_ui_preprocess_views_view(&$variables) { $view = $variables['view']; if (!empty($view->live_preview) && \Drupal::moduleHandler()->moduleExists('contextual')) { $view->setShowAdminLinks(FALSE); foreach (array('title', 'header', 'exposed', 'rows', 'pager', 'more', 'footer', 'empty', 'attachment_after', 'attachment_before') as $section) { if (!empty($variables[$section])) { $variables[$section] = array( '#theme' => 'views_ui_view_preview_section', '#view' => $view, '#section' => $section, '#content' => $variables[$section], '#theme_wrappers' => array('views_ui_container'), '#attributes' => array('class' => 'contextual-region'), ); $variables[$section] = $variables[$section]; } } } } /** * Returns contextual links for each handler of a certain section. * * @TODO * Bring in relationships * Refactor this function to use much stuff of views_ui_edit_form_get_bucket. * * @param $title * Add a bolded title of this section. */ function views_ui_view_preview_section_handler_links(ViewExecutable $view, $type, $title = FALSE) { $display = $view->display_handler->display; $handlers = $view->display_handler->getHandlers($type); $links = array(); $types = ViewExecutable::viewsHandlerTypes(); if ($title) { $links[$type . '-title'] = array( 'title' => $types[$type]['title'], ); } foreach ($handlers as $id => $handler) { $field_name = $handler->adminLabel(TRUE); $links[$type . '-edit-' . $id] = array( 'title' => t('Edit @section', array('@section' => $field_name)), 'href' => "admin/structure/views/nojs/config-item/{$view->storage->id()}/{$display['id']}/$type/$id", 'attributes' => array('class' => array('views-ajax-link')), ); } $links[$type . '-add'] = array( 'title' => t('Add new'), 'href' => "admin/structure/views/nojs/add-item/{$view->storage->id()}/{$display['id']}/$type", 'attributes' => array('class' => array('views-ajax-link')), ); return $links; } /** * Returns a link to editing a certain display setting. */ function views_ui_view_preview_section_display_category_links(ViewExecutable $view, $type, $title) { $display = $view->display_handler->display; $links = array( $type . '-edit' => array( 'title' => t('Edit @section', array('@section' => $title)), 'href' => "admin/structure/views/nojs/display/{$view->storage->id()}/{$display['id']}/$type", 'attributes' => array('class' => array('views-ajax-link')), ), ); return $links; } /** * Returns all contextual links for the main content part of the view. */ function views_ui_view_preview_section_rows_links(ViewExecutable $view) { $display = $view->display_handler->display; $links = array(); $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'filter', TRUE)); $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'field', TRUE)); $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'sort', TRUE)); $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'argument', TRUE)); $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'relationship', TRUE)); return $links; } /** * Implements hook_views_plugins_display_alter(). */ function views_ui_views_plugins_display_alter(&$plugins) { // Attach contextual links to each display plugin. The links will point to // paths underneath "admin/structure/views/view/{$view->id()}" (i.e., paths // for editing and performing other contextual actions on the view). foreach ($plugins as &$display) { $display['contextual links']['views_ui'] = array( 'parent path' => 'admin/structure/views/view', 'argument properties' => array('id'), ); } } /** * Implements hook_contextual_links_view_alter(). */ function views_ui_contextual_links_view_alter(&$element, $items) { // Remove contextual links from being rendered, when so desired, such as // within a View preview. if (views_ui_contextual_links_suppress()) { $element['#links'] = array(); } // Append the display ID to the Views UI edit links, so that clicking on the // contextual link takes you directly to the correct display tab on the edit // screen. elseif (!empty($element['#links']['views-ui-edit'])) { $display_id = $element['#contextual_links']['views_ui'][2]['display_id']; $element['#links']['views-ui-edit']['href'] .= '/edit/' . $display_id; } } /** * Sets a static variable for controlling whether contextual links are rendered. * * @see views_ui_contextual_links_view_alter() */ function views_ui_contextual_links_suppress($set = NULL) { $suppress = &drupal_static(__FUNCTION__); if (isset($set)) { $suppress = $set; } return $suppress; } /** * Increments the views_ui_contextual_links_suppress() static variable. * * When this function is added to the #pre_render of an element, and * 'views_ui_contextual_links_suppress_pop' is added to the #post_render of the * same element, then all contextual links within the element and its * descendants are suppressed from being rendered. This is used, for example, * during a View preview, when it is not desired for nodes in the Views result * to have contextual links. * * @see views_ui_contextual_links_suppress_pop() */ function views_ui_contextual_links_suppress_push() { views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress())+1); } /** * Decrements the views_ui_contextual_links_suppress() static variable. * * @see views_ui_contextual_links_suppress_push() */ function views_ui_contextual_links_suppress_pop() { views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress())-1); } /** * This is part of a patch to address a jQueryUI bug. The bug is responsible * for the inability to scroll a page when a modal dialog is active. If the content * of the dialog extends beyond the bottom of the viewport, the user is only able * to scroll with a mousewheel or up/down keyboard keys. * * @see http://bugs.jqueryui.com/ticket/4671 * @see https://bugs.webkit.org/show_bug.cgi?id=19033 * @see /js/jquery.ui.dialog.patch.js * @see /js/jquery.ui.dialog.min.js * * The javascript patch overwrites the $.ui.dialog.overlay.events object to remove * the mousedown, mouseup and click events from the list of events that are bound * in $.ui.dialog.overlay.create. */ function views_ui_library_alter(&$libraries, $module) { if ($module == 'system' && isset($libraries['jquery.ui.dialog'])) { if (version_compare($libraries['jquery.ui.dialog']['version'], '1.7.2', '>=')) { $libraries['jquery.ui.dialog']['js'][drupal_get_path('module', 'views') . '/js/jquery.ui.dialog.patch.js'] = array(); } } } /** * Implements hook_views_analyze(). * * This is the basic views analysis that checks for very minimal problems. * There are other analysis tools in core specific sections, such as * node.views.inc as well. */ function views_ui_views_analyze(ViewExecutable $view) { $ret = array(); // Check for something other than the default display: if (count($view->displayHandlers) < 2) { $ret[] = Analyzer::formatMessage(t('This view has only a default display and therefore will not be placed anywhere on your site; perhaps you want to add a page or a block display.'), 'warning'); } // You can give a page display the same path as an alias existing in the // system, so the alias will not work anymore. Report this to the user, // because he probably wanted something else. foreach ($view->displayHandlers as $display) { if (empty($display)) { continue; } if ($display->hasPath() && $path = $display->getOption('path')) { $normal_path = \Drupal::service('path.alias_manager.cached')->getSystemPath($path); if ($path != $normal_path) { $ret[] = Analyzer::formatMessage(t('You have configured display %display with a path which is an path alias as well. This might lead to unwanted effects so better use an internal path.', array('%display' => $display->display['display_title'])), 'warning'); } } } return $ret; } /** * Truncate strings to a set length and provide a ... if they truncated. * * This is often used in the UI to ensure long strings fit. */ function views_ui_truncate($string, $length) { if (drupal_strlen($string) > $length) { $string = drupal_substr($string, 0, $length); $string .= '...'; } return $string; } /** * Magic load function. Wrapper to load a view. */ function views_ui_load($name) { return views_get_view($name); }