Commit b08c4483 authored by catch's avatar catch

Issue #1811828 by dawehner, tim.plunkett: Use #attached to find the css/js of a view.

parent 41ae1ead
......@@ -77,7 +77,8 @@ public function executeHookBlockList($delta = 0, $edit = array()) {
public function execute() {
// Prior to this being called, the $view should already be set to this
// display, and arguments should be set on the view.
$info['content'] = $this->view->render();
$element = $this->view->render();
$info['content'] = drupal_render($element);
$info['subject'] = filter_xss_admin($this->view->getTitle());
if (!empty($this->view->result) || $this->getOption('empty') || !empty($this->view->style_plugin->definition['even empty'])) {
return $info;
......
......@@ -43,12 +43,12 @@ public function buildOptionsForm(&$form, &$form_state) {
* Override the behavior of the render() function.
*/
function render($row) {
return theme($this->themeFunctions(),
array(
'view' => $this->view,
'options' => $this->options,
'row' => $row
));
return array(
'#theme' => $this->themeFunctions(),
'#view' => $this->view,
'#options' => $this->options,
'#row' => $row,
);
}
}
......@@ -135,6 +135,6 @@ public function pre_render($result) {
*/
function render($row) {
$entity_id = $row->{$this->field_alias};
return drupal_render($this->build[$entity_id]);
return $this->build[$entity_id];
}
}
......@@ -150,6 +150,15 @@ public function tokenForm(&$form, &$form_state) {
*/
public function query() { }
/**
* Performs any operations needed before full rendering.
*
* @param array $results
* The results of the view.
*/
public function preRender(array $results) {
}
/**
* Render the area
*/
......
......@@ -47,9 +47,9 @@ public function buildOptionsForm(&$form, &$form_state) {
}
/**
* Overrides Drupal\views\Plugin\views\AreaPluginBase::render().
* Overrides Drupal\views\Plugin\views\AreaPluginBase::preRender().
*/
function render($empty = FALSE) {
public function preRender(array $results) {
if (!empty($this->options['title'])) {
$value = $this->globalTokenReplace($this->options['title']);
$this->view->setTitle($this->sanitizeValue($value, 'xss_admin'), PASS_THROUGH);
......
......@@ -144,8 +144,8 @@ function cache_set($type) {
cache($this->table)->set($this->generateResultsKey(), $data, $this->cache_set_expire($type));
break;
case 'output':
$this->gather_headers();
$this->storage['output'] = $this->view->display_handler->output;
$this->gather_headers();
cache($this->table)->set($this->generateOutputKey(), $this->storage, $this->cache_set_expire($type));
break;
}
......@@ -222,20 +222,20 @@ function cache_flush() {
function post_render(&$output) { }
/**
* Start caching javascript, css and other out of band info.
* Start caching the html head.
*
* This takes a snapshot of the current system state so that we don't
* duplicate it. Later on, when gather_headers() is run, this information
* will be removed so that we don't hold onto it.
*
* @see drupal_add_html_head()
*/
function cache_start() {
$this->storage['head'] = drupal_add_html_head();
$this->storage['css'] = drupal_add_css();
$this->storage['js'] = drupal_add_js();
}
/**
* Gather out of band data, compare it to what we started with and store the difference.
* Gather the JS/CSS from the render array, the html head from the band data.
*/
function gather_headers() {
// Simple replacement for head
......@@ -246,22 +246,9 @@ function gather_headers() {
$this->storage['head'] = '';
}
// Slightly less simple for CSS:
$css = drupal_add_css();
$css_start = isset($this->storage['css']) ? $this->storage['css'] : array();
$this->storage['css'] = array_diff_assoc($css, $css_start);
// Get javascript after/before views renders.
$js = drupal_add_js();
$js_start = isset($this->storage['js']) ? $this->storage['js'] : array();
// If there are any differences between the old and the new javascript then
// store them to be added later.
$this->storage['js'] = array_diff_assoc($js, $js_start);
// Special case the settings key and get the difference of the data.
$settings = isset($js['settings']['data']) ? $js['settings']['data'] : array();
$settings_start = isset($js_start['settings']['data']) ? $js_start['settings']['data'] : array();
$this->storage['js']['settings'] = array_diff_assoc($settings, $settings_start);
$attached = drupal_render_collect_attached($this->storage['output']);
$this->storage['css'] = $attached['css'];
$this->storage['js'] = $attached['js'];
}
/**
......@@ -273,17 +260,17 @@ function restore_headers() {
}
if (!empty($this->storage['css'])) {
foreach ($this->storage['css'] as $args) {
drupal_add_css($args['data'], $args);
$this->view->element['#attached']['css'][] = $args;
}
}
if (!empty($this->storage['js'])) {
foreach ($this->storage['js'] as $key => $args) {
if ($key !== 'settings') {
drupal_add_js($args['data'], $args);
$this->view->element['#attached']['js'][] = $args;
}
else {
foreach ($args as $setting) {
drupal_add_js($setting, 'setting');
$this->view->element['#attached']['js']['setting'][] = $setting;
}
}
}
......
......@@ -943,7 +943,6 @@ public function overrideOption($option, $value) {
* an easy URL to exactly the right section. Don't override this.
*/
public function optionLink($text, $section, $class = '', $title = '') {
views_add_js('ajax');
if (!empty($class)) {
$text = '<span>' . $text . '</span>';
}
......@@ -2486,7 +2485,13 @@ public function hookMenu() { return array(); }
* Render this display.
*/
public function render() {
return theme($this->themeFunctions(), array('view' => $this->view));
$element = array(
'#theme' => $this->themeFunctions(),
'#view' => $this->view,
);
$element['#attached'] = &$this->view->element['#attached'];
return $element;
}
public function renderArea($area, $empty = FALSE) {
......@@ -2558,7 +2563,10 @@ public function execute() { }
* Fully render the display for the purposes of a live preview or
* some other AJAXy reason.
*/
function preview() { return $this->view->render(); }
function preview() {
$element = $this->view->render();
return drupal_render($element);
}
/**
* Displays can require a certain type of style plugin. By default, they will
......
......@@ -159,13 +159,13 @@ function pre_render($result) { }
* The rendered output of a single row, used by the style plugin.
*/
function render($row) {
return theme($this->themeFunctions(),
array(
'view' => $this->view,
'options' => $this->options,
'row' => $row,
'field_alias' => isset($this->field_alias) ? $this->field_alias : '',
));
return array(
'#theme' => $this->themeFunctions(),
'#view' => $this->view,
'#options' => $this->options,
'#row' => $row,
'#field_alias' => isset($this->field_alias) ? $this->field_alias : '',
);
}
}
......
......@@ -84,11 +84,12 @@ function render() {
$rows[] = $row;
}
return theme($this->themeFunctions(), array(
'view' => $this->view,
'options' => $this->options,
'rows' => $rows
));
return array(
'#theme' => $this->themeFunctions(),
'#view' => $this->view,
'#options' => $this->options,
'#rows' => $rows,
);
}
}
......@@ -132,12 +132,13 @@ public function buildOptionsForm(&$form, &$form_state) {
* Provides the mapping definition as an available variable.
*/
function render() {
return theme($this->themeFunctions(), array(
'view' => $this->view,
'options' => $this->options,
'rows' => $this->view->result,
'mapping' => $this->defineMapping(),
));
return array(
'#theme' => $this->themeFunctions(),
'#view' => $this->view,
'#options' => $this->options,
'#rows' => $this->view->result,
'#mapping' => $this->defineMapping(),
);
}
}
......@@ -431,18 +431,19 @@ function render() {
* Rendered output of given grouping sets.
*/
function render_grouping_sets($sets, $level = 0) {
$output = '';
$output = array();
$theme_functions = views_theme_functions('views_view_grouping', $this->view, $this->view->display_handler->display);
foreach ($sets as $set) {
$row = reset($set['rows']);
// Render as a grouping set.
if (is_array($row) && isset($row['group'])) {
$output .= theme(views_theme_functions('views_view_grouping', $this->view, $this->view->display_handler->display),
array(
'view' => $this->view,
'grouping' => $this->options['grouping'][$level],
'grouping_level' => $level,
'rows' => $set['rows'],
'title' => $set['group'])
$output[] = array(
'#theme' => $theme_functions,
'#view' => $this->view,
'#grouping' => $this->options['grouping'][$level],
'#grouping_level' => $level,
'#rows' => $set['rows'],
'#title' => $set['group'],
);
}
// Render as a record set.
......@@ -450,17 +451,19 @@ function render_grouping_sets($sets, $level = 0) {
if ($this->usesRowPlugin()) {
foreach ($set['rows'] as $index => $row) {
$this->view->row_index = $index;
$set['rows'][$index] = $this->row_plugin->render($row);
$render = $this->row_plugin->render($row);
// Row render arrays cannot be contained by style render arrays.
$set['rows'][$index] = drupal_render($render);
}
}
$output .= theme($this->themeFunctions(),
array(
'view' => $this->view,
'options' => $this->options,
'grouping_level' => $level,
'rows' => $set['rows'],
'title' => $set['group'])
$output[] = array(
'#theme' => $this->themeFunctions(),
'#view' => $this->view,
'#options' => $this->options,
'#grouping_level' => $level,
'#rows' => $set['rows'],
'#title' => $set['group'],
);
}
}
......
......@@ -253,6 +253,7 @@ public function testRenderNullPager() {
$view->use_ajax = TRUE; // force the value again here
$view->pager = NULL;
$output = $view->render();
$output = drupal_render($output);
$this->assertEqual(preg_match('/<ul class="pager">/', $output), 0, t('The pager is not rendered.'));
}
......
......@@ -397,6 +397,24 @@ class ViewExecutable {
*/
public $dom_id;
/**
* A render array container to store render related information.
*
* For example you can alter the array and attach some css/js via the
* #attached key. This is the required way to add custom css/js.
*
* @var array
*
* @see drupal_process_attached
*/
public $element = array(
'#attached' => array(
'css' => array(),
'js' => array(),
'library' => array(),
),
);
/**
* Constructs a new ViewExecutable object.
*
......@@ -407,6 +425,9 @@ public function __construct(View $storage) {
// Reference the storage and the executable to each other.
$this->storage = $storage;
$this->storage->set('executable', $this);
// Add the default css for a view.
$this->element['#attached']['css'][] = drupal_get_path('module', 'views') . '/css/views.base.css';
}
/**
......@@ -1273,6 +1294,13 @@ public function render($display_id = NULL) {
$this->style_plugin->pre_render($this->result);
// Let each area handler have access to the result set.
foreach (array('header', 'footer', 'empty') as $area) {
foreach ($this->{$area} as $handler) {
$handler->preRender($this->result);
}
}
// Let modules modify the view just prior to rendering it.
foreach (module_implements('views_pre_render') as $module) {
$function = $module . '_views_pre_render';
......@@ -2136,6 +2164,15 @@ public function getItem($display_id, $type, $id) {
return isset($fields[$id]) ? $fields[$id] : NULL;
}
/**
* Sets the build array used by the view.
*
* @param array $element
*/
public function setElement(&$element) {
$this->element =& $element;
}
/**
* Sets the configuration of a handler instance on a given display.
*
......
......@@ -114,10 +114,9 @@ public function submitOptionsForm(&$form, &$form_state) {
public function execute() {
$this->view->build();
$render = $this->view->render();
// Render the test option as the title before the view output.
$render = '<h1>' . filter_xss_admin($this->options['test_option']) . '</h1>';
// And now render the view.
$render .= $this->view->render();
$render['#prefix'] = '<h1>' . filter_xss_admin($this->options['test_option']) . '</h1>';
return $render;
}
......@@ -128,7 +127,8 @@ public function execute() {
* Override so preview and execute are the same output.
*/
public function preview() {
return $this->execute();
$element = $this->execute();
return drupal_render($element);
}
}
......@@ -81,8 +81,9 @@ function views_test_data_handler_test_access_callback_argument($argument = FALSE
*/
function views_test_data_views_pre_render(ViewExecutable $view) {
if ($view->storage->get('name') == 'test_cache_header_storage') {
drupal_add_js(drupal_get_path('module', 'views_test_data') . '/views_cache.test.js');
drupal_add_css(drupal_get_path('module', 'views_test_data') . '/views_cache.test.css');
$path = drupal_get_path('module', 'views_test_data');
$view->element['#attached']['js'][] = "$path/views_cache.test.js";
$view->element['#attached']['css'][] = "$path/views_cache.test.css";
$view->build_info['pre_render_called'] = TRUE;
}
}
......
......@@ -47,7 +47,11 @@ function template_preprocess_views_view(&$vars) {
$view = $vars['view'];
$vars['rows'] = (!empty($view->result) || $view->style_plugin->even_empty()) ? $view->style_plugin->render($view->result) : '';
$vars['rows'] = (!empty($view->result) || $view->style_plugin->even_empty()) ? $view->style_plugin->render($view->result) : '';
// Force a render array so CSS/JS can be added.
if (!is_array($vars['rows'])) {
$vars['rows'] = array('#markup' => $vars['rows']);
}
$vars['css_name'] = drupal_clean_css_identifier($view->storage->get('name'));
$vars['name'] = $view->storage->get('name');
......@@ -68,13 +72,14 @@ function template_preprocess_views_view(&$vars) {
$vars['attributes']['class'][] = $vars['css_class'];
}
$empty = empty($vars['rows']);
// Render the rows render array to check for contents.
$rows = $vars['rows'];
$rows = drupal_render($rows);
$empty = empty($rows);
$vars['header'] = $view->display_handler->renderArea('header', $empty);
$vars['footer'] = $view->display_handler->renderArea('footer', $empty);
if ($empty) {
$vars['empty'] = $view->display_handler->renderArea('empty', $empty);
}
$vars['empty'] = $empty ? $view->display_handler->renderArea('empty', $empty) : FALSE;
$vars['exposed'] = !empty($view->exposed_widgets) ? $view->exposed_widgets : '';
$vars['more'] = $view->display_handler->renderMoreLink();
......@@ -138,14 +143,13 @@ function template_preprocess_views_view(&$vars) {
),
),
);
drupal_add_js($settings, 'setting');
views_add_js('ajax_view');
$view->element['#attached']['js'][] = array('type' => 'setting', 'data' => $settings);
$view->element['#attached']['library'][] = array('views', 'views.ajax');
}
// If form fields were found in the View, reformat the View output as a form.
if (views_view_has_form_elements($view)) {
$output = !empty($vars['rows']) ? $vars['rows'] : $vars['empty'];
$output = !empty($rows) ? $rows : $vars['empty'];
$form = drupal_get_form(views_form_id($view), $view, $output);
// The form is requesting that all non-essential views elements be hidden,
// usually because the rendered step is not a view result.
......@@ -161,15 +165,6 @@ function template_preprocess_views_view(&$vars) {
}
}
/**
* Process function to render certain elements into the view.
*/
function template_process_views_view(&$vars) {
if (is_array($vars['rows'])) {
$vars['rows'] = drupal_render($vars['rows']);
}
}
/**
* Preprocess theme function to print a single record from a row, with fields
*/
......@@ -652,7 +647,7 @@ function template_preprocess_views_view_table(&$vars) {
}
if (!empty($options['sticky'])) {
drupal_add_js('misc/tableheader.js');
$vars['view']->element['#attached']['library'][] = array('system', 'drupal.tableheader');
$vars['attributes']['class'][] = "sticky-enabled";
}
$vars['attributes']['class'][] = 'cols-'. count($vars['header']);
......@@ -664,7 +659,7 @@ function template_preprocess_views_view_table(&$vars) {
// with the classes represented by the constants RESPONSIVE_PRIORITY_MEDIUM
// and RESPONSIVE_PRIORITY_LOW, add the tableresponsive behaviors.
if (count($vars['header']) && $responsive) {
drupal_add_library('system', 'drupal.tableresponsive');
$vars['view']->element['#attached']['library'][] = array('system', 'drupal.tableresponsive');
// Add 'responsive-enabled' class to the table to identify it for JS.
// This is needed to target tables constructed by this function.
$vars['attributes']['class'][] = 'responsive-enabled';
......@@ -786,7 +781,7 @@ function template_preprocess_views_view_grid(&$vars) {
// with the classes represented by the constants RESPONSIVE_PRIORITY_MEDIUM
// and RESPONSIVE_PRIORITY_LOW, add the tableresponsive behaviors.
if (count($vars['header']) && $responsive) {
drupal_add_library('system', 'drupal.tableresponsive');
$vars['view']->element['#attached']['library'][] = array('system', 'drupal.tableresponsive');
// Add 'responsive-enabled' class to the table to identify it for JS.
// This is needed to target tables constructed by this function.
$vars['attributes']['class'][] = 'responsive-enabled';
......
......@@ -51,7 +51,7 @@
</div>
<?php endif; ?>
<?php if ($rows): ?>
<?php if ($rows = render($rows)): ?>
<div class="view-content">
<?php print $rows; ?>
</div>
......
......@@ -3,4 +3,3 @@ description = Create customized lists and queries from your database.
package = Core
version = VERSION
core = 8.x
stylesheets[all][] = css/views.base.css
......@@ -1119,36 +1119,29 @@ function views_hook_info() {
}
/**
* Include views .css files.
*/
function views_add_css($file) {
// We set preprocess to FALSE because we are adding the files conditionally,
// and we don't want to generate duplicate cache files.
// TODO: at some point investigate adding some files unconditionally and
// allowing preprocess.
drupal_add_css(drupal_get_path('module', 'views') . "/css/$file.css", array('preprocess' => FALSE));
}
* Implements hook_library_info().
*/
function views_library_info() {
$path = drupal_get_path('module', 'views') . '/js';
$libraries['views.ajax'] = array(
'title' => 'Views AJAX',
'version' => VERSION,
'js' => array(
"$path/base.js" => array('group' => JS_DEFAULT),
"$path/ajax.js" => array('group' => JS_DEFAULT),
"$path/ajax_view.js" => array('group' => JS_DEFAULT),
),
'dependencies' => array(
array('system', 'jquery'),
array('system', 'drupal'),
array('system', 'drupalSettings'),
array('system', 'jquery.once'),
array('system', 'jquery.form'),
array('system', 'drupal.ajax'),
),
);
/**
* Include views .js files.
*/
function views_add_js($file) {
// If javascript has been disabled by the user, never add js files.
if (config('views.settings')->get('no_javascript')) {
return;
}
$path = drupal_get_path('module', 'views');
static $base = TRUE, $ajax = TRUE;
if ($base) {
drupal_add_js($path . "/js/base.js");
$base = FALSE;
}
if ($ajax && in_array($file, array('ajax', 'ajax_view'))) {
drupal_add_library('system', 'drupal.ajax');
drupal_add_library('system', 'jquery.form');
$ajax = FALSE;
}
drupal_add_js($path . "/js/$file.js");
return $libraries;
}
/**
......@@ -1859,7 +1852,7 @@ function views_exposed_form($form, &$form_state) {
// If using AJAX, we need the form plugin.
if ($view->use_ajax) {
drupal_add_library('system', 'jquery.form');
$form['#attached']['library'][] = array('system', 'jquery.form');
}
$exposed_form_plugin = $form_state['exposed_form_plugin'];
......
......@@ -55,14 +55,15 @@ public function form(array $form, array &$form_state, EntityInterface $view) {
$form['#attached']['library'][] = array('system', 'jquery.ui.tabs');
$form['#attached']['library'][] = array('system', 'jquery.ui.dialog');
$form['#attached']['library'][] = array('system', 'drupal.ajax');
$form['#attached']['library'][] = array('system', 'jquery.form');
$form['#attached']['library'][] = array('system', 'drupal.states');
$form['#attached']['library'][] = array('system', 'drupal.tabledrag');
if (!config('views.settings')->get('no_javascript')) {
$form['#attached']['library'][] = array('views_ui', 'views_ui.admin');
}
$form['#attached']['css'] = static::getAdminCSS();
$form['#attached']['js'][] = drupal_get_path('module', 'views_ui') . '/js/views-admin.js';
$form['#attached']['js'][] = array(
'data' => array('views' => array('ajax' => array(
'id' => '#views-ajax-body',
......
......@@ -285,6 +285,32 @@ function views_ui_theme() {
);
}
/**
* Implements hook_library_info().
*/
function views_ui_library_info() {
$libraries = array();
$libraries['views_ui.admin'] = array(
'title' => 'Views UI ADMIN',
'version' => VERSION,
'js' => array(
drupal_get_path('module', 'views_ui') . '/js/views-admin.js' => array('group' => JS_DEFAULT),
),
'dependencies' => array(
array('system', 'jquery'),
array('system', 'drupal'),
array('system', 'drupalSettings'),
array('system', 'jquery.once'),
array('system', 'jquery.form'),
array('system', 'drupal.ajax'),
array('views', 'views.ajax'),
),
);
return $libraries;
}
/**
* Page title callback for the Edit View page.
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment