Commit 71491f50 authored by Riccardo Padovani's avatar Riccardo Padovani

Updated module views to version 7.x-3.8

parent 145b873f
File mode changed from 100644 to 100755
<?php
/**
* @file
* Contains views_handler_area_messages.
*/
/**
* Provides an area for messages.
*/
class views_handler_area_messages extends views_handler_area {
/**
* {@inheritdoc}
*/
public function option_definition() {
$options = parent::option_definition();
// Set the default to TRUE so it shows on empty pages by default.
$options['empty']['default'] = TRUE;
return $options;
}
/**
* {@inheritdoc}
*/
public function render($empty = FALSE) {
$return = '';
if (!$empty || !empty($this->options['empty'])) {
$return = theme('status_messages');
}
return $return;
}
}
......@@ -16,6 +16,8 @@ class views_handler_field_date extends views_handler_field {
$options['date_format'] = array('default' => 'small');
$options['custom_date_format'] = array('default' => '');
$options['second_date_format_custom'] = array('default' => '');
$options['second_date_format'] = array('default' => 'small');
$options['timezone'] = array('default' => '');
return $options;
......@@ -36,6 +38,7 @@ class views_handler_field_date extends views_handler_field {
'custom' => t('Custom'),
'raw time ago' => t('Time ago'),
'time ago' => t('Time ago (with "ago" appended)'),
'today time ago' => t('Time ago (with "ago" appended) for today\'s date, but not for other dates'),
'raw time hence' => t('Time hence'),
'time hence' => t('Time hence (with "hence" appended)'),
'raw time span' => t('Time span (future dates have "-" prepended)'),
......@@ -49,8 +52,39 @@ class views_handler_field_date extends views_handler_field {
'#title' => t('Custom date format'),
'#description' => t('If "Custom", see the <a href="@url" target="_blank">PHP manual</a> for date formats. Otherwise, enter the number of different time units to display, which defaults to 2.', array('@url' => 'http://php.net/manual/function.date.php')),
'#default_value' => isset($this->options['custom_date_format']) ? $this->options['custom_date_format'] : '',
'#dependency' => array('edit-options-date-format' => array('custom', 'raw time ago', 'time ago', 'raw time hence', 'time hence', 'raw time span', 'time span', 'raw time span', 'inverse time span', 'time span')),
'#dependency' => array('edit-options-date-format' => array('custom', 'raw time ago', 'time ago', 'today time ago', 'raw time hence', 'time hence', 'raw time span', 'time span', 'raw time span', 'inverse time span', 'time span')),
);
$form['second_date_format'] = array(
'#type' => 'select',
'#title' => t('Second date format'),
'#options' => $date_formats + array(
'custom' => t('Custom'),
),
'#description' => t('The date format which will be used for rendering dates other than today.'),
'#default_value' => isset($this->options['second_date_format']) ? $this->options['second_date_format'] : 'small',
'#dependency' => array('edit-options-date-format' => array('today time ago')),
);
$form['second_date_format_custom'] = array(
'#type' => 'textfield',
'#title' => t('Custom date format of second date'),
'#description' => t('If "Custom" is selected in "Second date format", see the <a href="@url" target="_blank">PHP manual</a> for date formats. Otherwise, enter the number of different time units to display, which defaults to 2.', array('@url' => 'http://php.net/manual/function.date.php')),
'#default_value' => isset($this->options['second_date_format_custom']) ? $this->options['second_date_format_custom'] : '',
// We have to use states instead of ctools dependency because dependency
// doesn't handle multiple conditions.
'#states' => array(
'visible' => array(
'#edit-options-date-format' => array('value' => 'today time ago'),
'#edit-options-second-date-format' => array('value' => 'custom'),
),
),
// We have to use ctools dependency too because states doesn't add the
// correct left margin to the element's wrapper.
'#dependency' => array(
// This condition is handled by form API's states.
// 'edit-options-date-format' => array('today time ago'),
'edit-options-second-date-format' => array('custom'),
),
);
$form['timezone'] = array(
'#type' => 'select',
'#title' => t('Timezone'),
......@@ -66,7 +100,7 @@ class views_handler_field_date extends views_handler_field {
function render($values) {
$value = $this->get_value($values);
$format = $this->options['date_format'];
if (in_array($format, array('custom', 'raw time ago', 'time ago', 'raw time hence', 'time hence', 'raw time span', 'time span', 'raw time span', 'inverse time span', 'time span'))) {
if (in_array($format, array('custom', 'raw time ago', 'time ago', 'today time ago', 'raw time hence', 'time hence', 'raw time span', 'time span', 'raw time span', 'inverse time span', 'time span'))) {
$custom_format = $this->options['custom_date_format'];
}
......@@ -78,6 +112,21 @@ class views_handler_field_date extends views_handler_field {
return format_interval($time_diff, is_numeric($custom_format) ? $custom_format : 2);
case 'time ago':
return t('%time ago', array('%time' => format_interval($time_diff, is_numeric($custom_format) ? $custom_format : 2)));
case 'today time ago':
$second_format = $this->options['second_date_format'];
$second_custom_format = $this->options['second_date_format_custom'];
if (format_date(REQUEST_TIME, 'custom', 'Y-m-d', $timezone) == format_date($value, 'custom', 'Y-m-d', $timezone)) {
return t('%time ago', array('%time' => format_interval($time_diff, is_numeric($custom_format) ? $custom_format : 2)));
}
elseif ($second_format == 'custom') {
if ($second_custom_format == 'r') {
return format_date($value, $second_format, $second_custom_format, $timezone, 'en');
}
return format_date($value, $second_format, $second_custom_format, $timezone);
}
else {
return format_date($value, $this->options['second_date_format'], '', $timezone);
}
case 'raw time hence':
return format_interval(-$time_diff, is_numeric($custom_format) ? $custom_format : 2);
case 'time hence':
......
......@@ -91,7 +91,11 @@ class views_handler_filter extends views_handler {
}
if ($this->multiple_exposed_input()) {
$this->group_info = array_filter($options['group_info']['default_group_multiple']);
$this->group_info = NULL;
if (!empty($options['group_info']['default_group_multiple'])) {
$this->group_info = array_filter($options['group_info']['default_group_multiple']);
}
$this->options['expose']['multiple'] = TRUE;
}
......@@ -116,6 +120,7 @@ class views_handler_filter extends views_handler {
'label' => array('default' => '', 'translatable' => TRUE),
'description' => array('default' => '', 'translatable' => TRUE),
'use_operator' => array('default' => FALSE, 'bool' => TRUE),
'operator_label' => array('default' => '', 'translatable' => TRUE),
'operator' => array('default' => ''),
'identifier' => array('default' => ''),
'required' => array('default' => FALSE, 'bool' => TRUE),
......@@ -510,6 +515,16 @@ class views_handler_filter extends views_handler {
'#description' => t('Allow the user to choose the operator.'),
'#default_value' => !empty($this->options['expose']['use_operator']),
);
$form['expose']['operator_label'] = array(
'#type' => 'textfield',
'#default_value' => $this->options['expose']['operator_label'],
'#title' => t('Operator label'),
'#size' => 40,
'#description' => t('This will appear before your operator select field.'),
'#dependency' => array(
'edit-options-expose-use-operator' => array(1)
),
);
$form['expose']['operator_id'] = array(
'#type' => 'textfield',
'#default_value' => $this->options['expose']['operator_id'],
......@@ -754,10 +769,8 @@ class views_handler_filter extends views_handler {
$operator = $this->options['expose']['operator_id'];
$this->operator_form($form, $form_state);
$form[$operator] = $form['operator'];
if (isset($form[$operator]['#title'])) {
unset($form[$operator]['#title']);
}
$form[$operator]['#title'] = $this->options['expose']['operator_label'];
$form[$operator]['#title_display'] = 'invisible';
$this->exposed_translate($form[$operator], 'operator');
......
......@@ -30,6 +30,6 @@ class views_handler_filter_boolean_operator_string extends views_handler_filter_
else {
$where .= "<> ''";
}
$this->query->add_where($this->options['group'], $where);
$this->query->add_where_expression($this->options['group'], $where);
}
}
<?php
/**
* @file
* Definition of views_handler_filter_fields_compare.
*/
/**
* A handler to filter a view using fields comparison.
*
* @ingroup views_filter_handlers
*/
class views_handler_filter_fields_compare extends views_handler_filter {
function can_expose() {
return FALSE;
}
/**
* Overrides views_handler_filter#option_definition().
*/
function option_definition() {
$options = parent::option_definition();
$options['left_field'] = $options['right_field'] = array('default' => '');
return $options;
}
/**
* Provide a list of all operators.
*/
function fields_operator_options() {
return array(
'<' => t('Is less than'),
'<=' => t('Is less than or equal to'),
'=' => t('Is equal to'),
'<>' => t('Is not equal to'),
'>=' => t('Is greater than or equal to'),
'>' => t('Is greater than')
);
}
/**
* Provide a list of available fields.
*/
function field_options() {
$options = array();
$field_handlers = $this->view->display_handler->get_handlers('field');
foreach ($field_handlers as $field => $handler) {
if ($handler->table != 'views') {
$options[$field] = $handler->ui_name();
}
}
return $options;
}
/**
* Overrides views_handler_filter#options_form().
*/
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$field_options = $this->field_options();
$form['left_field'] = array(
'#type' => 'select',
'#title' => t('Left field'),
'#default_value' => $this->options['left_field'],
'#options' => $field_options,
'#weight' => -3,
);
$form['operator'] = array(
'#type' => 'select',
'#title' => t('Operator'),
'#default_value' => $this->options['operator'],
'#options' => $this->fields_operator_options(),
'#weight' => -2,
);
$form['right_field'] = array(
'#type' => 'select',
'#title' => t('Right field'),
'#default_value' => $this->options['right_field'],
'#options' => $field_options,
'#weight' => -1,
);
}
/**
* Overrides views_handler_filter#query().
*
* Build extra condition from existing fields (from existing joins).
*/
function query() {
$left = $this->options['left_field'];
$right = $this->options['right_field'];
// Get all existing field handlers.
$field_handlers = $this->view->display_handler->get_handlers('field');
// Make sure the selected fields still exist.
if (!isset($field_handlers[$left], $field_handlers[$right])) {
return;
}
// Get the left table and field.
$left_handler = $field_handlers[$left];
$left_handler->set_relationship();
$left_table_alias = $this->query->ensure_table($left_handler->table, $left_handler->relationship);
// Get the left table and field.
$right_handler = $field_handlers[$right];
$right_handler->set_relationship();
$right_table_alias = $this->query->ensure_table($right_handler->table, $right_handler->relationship);
// Build piece of SQL.
$snippet =
$left_table_alias . '.' . $left_handler->real_field .
' ' . $this->options['operator'] . ' ' .
$right_table_alias . '.' . $right_handler->real_field;
$this->query->add_where_expression($this->options['group'], $snippet);
}
/**
* Overrides views_handler_filter#admin_summary().
*/
function admin_summary() {
return check_plain(
$this->options['left_field'] . ' ' .
$this->options['operator'] . ' ' .
$this->options['right_field']
);
}
}
......@@ -408,7 +408,7 @@ function views_ui_add_form($form, &$form_state) {
*/
function views_element_validate_integer($element, &$form_state) {
$value = $element['#value'];
if ($value !== '' && (!is_numeric($value) || intval($value) != $value)) {
if ($value !== '' && (!is_numeric($value) || intval($value) != $value || abs($value) != $value)) {
form_error($element, t('%name must be a positive integer.', array('%name' => $element['#title'])));
}
}
......
......@@ -23,16 +23,31 @@ function _views_fetch_data($table = NULL, $move = TRUE, $reset = FALSE) {
if ($table) {
if (!isset($cache[$table])) {
$cid = 'views_data:' . $table;
$data = views_cache_get($cid, TRUE);
if (!empty($data->data)) {
if ($data = views_cache_get($cid, TRUE)) {
$cache[$table] = $data->data;
}
else {
if (!$fully_loaded) {
// No cache entry, rebuild.
$cache = _views_fetch_data_build();
// Try to load the full views cache.
if ($data = views_cache_get('views_data', TRUE)) {
$cache = $data->data;
}
else {
// No cache entry, rebuild.
$cache = _views_fetch_data_build();
}
$fully_loaded = TRUE;
}
// Write back a cache for this table.
if (isset($cache[$table])) {
views_cache_set($cid, $cache[$table], TRUE);
}
else {
// If there is still no information about that table, it is missing.
// Write an empty array to avoid repeated rebuilds.
views_cache_set($cid, array(), TRUE);
}
}
}
if (isset($cache[$table])) {
......@@ -82,11 +97,6 @@ function _views_fetch_data_build() {
// Keep a record with all data.
views_cache_set('views_data', $cache, TRUE);
// Save data in seperate cache entries.
foreach ($cache as $key => $data) {
$cid = 'views_data:' . $key;
views_cache_set($cid, $data, TRUE);
}
return $cache;
}
......
......@@ -1581,7 +1581,7 @@ class views_join {
// With an array of values, we need multiple placeholders and the
// 'IN' operator is implicit.
foreach ($info['value'] as $value) {
$placeholder_i = ':views_join_condition_' . $select_query->nextPlaceholder();
$placeholder_i = $view_query->placeholder('views_join_condition_');
$arguments[$placeholder_i] = $value;
}
......@@ -1591,10 +1591,9 @@ class views_join {
else {
// With a single value, the '=' operator is implicit.
$operator = !empty($info['operator']) ? $info['operator'] : '=';
$placeholder = ':views_join_condition_' . $select_query->nextPlaceholder();
$placeholder = $view_query->placeholder('views_join_condition_');
$arguments[$placeholder] = $info['value'];
}
$extras[] = "$join_table$info[field] $operator $placeholder";
}
......
......@@ -756,7 +756,7 @@ class view extends views_db_object {
*/
function _init_handler($key, $info) {
// Load the requested items from the display onto the object.
$this->$key = $this->display_handler->get_handlers($key);
$this->$key = &$this->display_handler->get_handlers($key);
// This reference deals with difficult PHP indirection.
$handlers = &$this->$key;
......
......@@ -66,6 +66,11 @@ Drupal.views.ajaxView = function(settings) {
// to a given element.
.filter(jQuery.proxy(this.filterNestedViews, this))
.once(jQuery.proxy(this.attachPagerAjax, this));
// Add a trigger to update this view specifically.
var self_settings = this.element_settings;
self_settings.event = 'RefreshView';
this.refreshViewAjax = new Drupal.ajax(this.selector, this.$view, self_settings);
};
Drupal.views.ajaxView.prototype.attachExposedFormAjax = function() {
......
......@@ -820,7 +820,10 @@ class views_handler_field_field extends views_handler_field {
* Return an array of items for the field.
*/
function set_items($values, $row_id) {
if (empty($values->_field_data[$this->field_alias]) || empty($values->_field_data[$this->field_alias]['entity'])) {
// In some cases the instance on the entity might be easy, see
// https://drupal.org/node/1161708 and https://drupal.org/node/1461536 for
// more information.
if (empty($values->_field_data[$this->field_alias]) || empty($values->_field_data[$this->field_alias]['entity']) || !isset($values->_field_data[$this->field_alias]['entity']->{$this->definition['field_name']})) {
return array();
}
......
......@@ -51,20 +51,21 @@ class views_handler_field_profile_date extends views_handler_field_date {
// But we *can* deal with non-year stuff:
$date = gmmktime(0, 0, 0, $value['month'], $value['day'], $value['year']);
$replace = array(
// day
'd' => sprintf('%02d', $value['day']),
'D' => NULL,
'l' => NULL,
'N' => NULL,
'S' => date('S', $date),
'S' => gmdate('S', $date),
'w' => NULL,
'j' => $value['day'],
// month
'F' => date('F', $date),
'F' => gmdate('F', $date),
'm' => sprintf('%02d', $value['month']),
'M' => date('M', $date),
'n' => date('n', $date),
'M' => gmdate('M', $date),
'n' => gmdate('n', $date),
'Y' => $value['year'],
'y' => substr($value['year'], 2, 2),
......
......@@ -10,10 +10,40 @@
* @ingroup views_field_handlers
*/
class views_handler_field_file_extension extends views_handler_field {
public function option_definition() {
$options = parent::option_definition();
$options['extension_detect_tar'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
}
public function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['extension_detect_tar'] = array(
'#type' => 'checkbox',
'#title' => t('Detect if tar is part of the extension'),
'#description' => t("See if the previous extension is '.tar' and if so, add that, so we see 'tar.gz' or 'tar.bz2' instead of just 'gz'."),
'#default_value' => $this->options['extension_detect_tar'],
);
}
function render($values) {
$value = $this->get_value($values);
if (preg_match('/\.([^\.]+)$/', $value, $match)) {
return $this->sanitize_value($match[1]);
if (!$this->options['extension_detect_tar']) {
if (preg_match('/\.([^\.]+)$/', $value, $match)) {
return $this->sanitize_value($match[1]);
}
}
else {
$file_parts = explode('.', basename($value));
// If there is an extension.
if (count($file_parts) > 1) {
$extension = array_pop($file_parts);
$last_part_in_name = array_pop($file_parts);
if ($last_part_in_name === 'tar') {
$extension = 'tar.' . $extension;
}
return $this->sanitize_value($extension);
}
}
}
}
......@@ -98,15 +98,12 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
if ($this->options['type'] == 'textfield') {
$default = '';
if ($this->value) {
$result = db_select('taxonomy_term_data', 'td')
->fields('td')
->condition('td.tid', $this->value)
->execute();
foreach ($result as $term) {
$result = taxonomy_term_load_multiple($this->value);
foreach ($result as $entity_term) {
if ($default) {
$default .= ', ';
}
$default .= $term->name;
$default .= entity_label('taxonomy_term', $entity_term);
}
}
......@@ -122,13 +119,14 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
}
else {
if (!empty($this->options['hierarchy']) && $this->options['limit']) {
$tree = taxonomy_get_tree($vocabulary->vid);
$tree = taxonomy_get_tree($vocabulary->vid, 0, NULL, TRUE);
$options = array();
if ($tree) {
// Translation system needs full entity objects, so we have access to label.
foreach ($tree as $term) {
$choice = new stdClass();
$choice->option = array($term->tid => str_repeat('-', $term->depth) . $term->name);
$choice->option = array($term->tid => str_repeat('-', $term->depth) . entity_label('taxonomy_term', $term));
$options[] = $choice;
}
}
......@@ -147,8 +145,14 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
$query->condition('tv.machine_name', $vocabulary->machine_name);
}
$result = $query->execute();
$tids = array();
foreach ($result as $term) {
$options[$term->tid] = $term->name;
$tids[] = $term->tid;
}
$entities = taxonomy_term_load_multiple($tids);
foreach ($entities as $entity_term) {
$options[$entity_term->tid] = entity_label('taxonomy_term', $entity_term);
}
}
......@@ -238,7 +242,7 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
$rc = parent::accept_exposed_input($input);
if ($rc) {
// If we have previously validated input, override.
if (isset($this->validated_exposed_input)) {
if (!$this->is_a_group() && isset($this->validated_exposed_input)) {
$this->value = $this->validated_exposed_input;
}
}
......@@ -347,12 +351,9 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
if ($this->value) {
$this->value = array_filter($this->value);
$result = db_select('taxonomy_term_data', 'td')
->fields('td')
->condition('td.tid', $this->value)
->execute();
foreach ($result as $term) {
$this->value_options[$term->tid] = $term->name;
$result = taxonomy_term_load_multiple($this->value);
foreach ($result as $entity_term) {
$this->value_options[$entity_term->tid] = entity_label('taxonomy_term', $entity_term);
}
}
return parent::admin_summary();
......
......@@ -75,7 +75,9 @@ class views_handler_relationship_node_term_data extends views_handler_relationsh
$query->addJoin($def['type'], 'taxonomy_vocabulary', 'tv', 'td.vid = tv.vid');
$query->addJoin($def['type'], 'taxonomy_index', 'tn', 'tn.tid = td.tid');
$query->condition('tv.machine_name', array_filter($this->options['vocabularies']));
$query->addTag('term_access');
if (empty($this->query->options['disable_sql_rewrite'])) {
$query->addTag('term_access');
}
$query->fields('td');
$query->fields('tn', array('nid'));
$def['table formula'] = $query;
......
......@@ -22,7 +22,7 @@ class views_handler_field_user_link_cancel extends views_handler_field_user_link
if ($uid && user_cancel_access($account)) {
$this->options['alter']['make_link'] = TRUE;
$text = !empty($this->options['text']) ? $this->options['text'] : t('cancel');
$text = !empty($this->options['text']) ? $this->options['text'] : t('Cancel account');
$this->options['alter']['path'] = "user/$uid/cancel";
$this->options['alter']['query'] = drupal_get_destination();
......
......@@ -81,6 +81,14 @@ function views_views_data() {
),
);
$data['views']['messages'] = array(
'title' => t('Messages'),
'help' => t('Displays messages in the area.'),
'area' => array(
'handler' => 'views_handler_area_messages',
),
);
if (module_exists('contextual')) {
$data['views']['contextual_links'] = array(
'title' => t('Contextual Links'),
......@@ -110,5 +118,14 @@ function views_views_data() {
);
}
$data['views']['fields_compare'] = array(
'title' => t('Fields comparison'),
'help' => t('Compare database fields against eachother.'),
'filter' => array(
'help' => t('Use fields comparison to filter the result of the view.'),
'handler' => 'views_handler_filter_fields_compare',
)
);
return $data;
}
......@@ -200,25 +200,28 @@ class views_plugin_cache extends views_plugin {
$this->storage['head'] = '';
}
// Check if the advanced mapping function of D 7.23 is available.
$array_mapping_func = function_exists('drupal_array_diff_assoc_recursive') ? 'drupal_array_diff_assoc_recursive' : 'array_diff_assoc';
// 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);
$this->storage['css'] = $array_mapping_func($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);
$this->storage['js'] = $array_mapping_func($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);
$this->storage['js']['settings'] = $array_mapping_func($settings, $settings_start);
// Get difference of HTTP headers.
$this->storage['headers'] = array_diff_assoc(drupal_get_http_header(), $this->storage['headers']);
$this->storage['headers'] = $array_mapping_func(drupal_get_http_header(), $this->storage['headers']);
}
/**
......@@ -253,59 +256,61 @@ class views_plugin_cache extends views_plugin {
}
function get_results_key() {
global $user;
if (!isset($this->_results_key)) {
$build_info = $this->view->build_info;
$query_plugin = $this->view->display_handler->get_plugin('query');
foreach (array('query','count_query') as $index) {
// If the default query back-end is used generate SQL query strings from
// the query objects.
if ($build_info[$index] instanceof SelectQueryInterface) {
$query = clone $build_info[$index];
$query->preExecute();
$build_info[$index] = (string) $query;
}
}
$key_data = array(
'build_info' => $build_info,
'roles' => array_keys($user->roles),
'super-user' => $user->uid == 1, // special caching for super user.
'language' => $GLOBALS['language']->language,
'base_url' => $GLOBALS['base_url'],
);
foreach (array('exposed_info', 'page', 'sort', 'order', 'items_per_page', 'offset') as $key) {
if (isset($_GET[$key])) {
$key_data[$key] = $_GET[$key];
}
}
$this->_results_key = $this->view->name . ':' . $this->display->id . ':results:' . md5(serialize($key_data));
$this->_results_key = $this->view->name . ':' . $this->display->id . ':results:' . $this->get_cache_key();
}
return $this->_results_key;
}
function get_output_key() {
global $user;
if (!isset($this->_output_key)) {
$key_data = array(
'result' => $this->view->result,
'roles' => array_keys($user->roles),
'super-user' => $user->uid == 1, // special caching for super user.
'theme' => $GLOBALS['theme'],
'language' => $GLOBALS['language']->language,
'base_url' => $GLOBALS['base_url'],
);
$this->_output_key = $this->view->name . ':' . $this->display->id . ':output:' . md5(serialize($key_data));
$this->_output_key = $this->view->name . ':' . $this->display->id . ':output:' . $this->get_cache_key($key_data);
}
return $this->_output_key;
}
/**
* Returns cache key.
*
* @param array $key_data
* Additional data for cache segmentation and/or overrides for default
* segmentation.
*
* @return string
*/
function get_cache_key($key_data = array()) {
global $user;
$key_data += array(
'roles' => array_keys($user->roles),
'super-user' => $user->uid == 1, // special caching for super user.
'language' => $GLOBALS['language']->language,
'base_url' => $GLOBALS['base_url'],
);
if (empty($key_data['build_info'])) {
$build_info = $this->view->build_info;
foreach (array('query','count_query') as $index) {
// If the default query back-end is used generate SQL query strings from
// the query objects.
if ($build_info[$index] instanceof SelectQueryInterface) {
$query = clone $build_info[$index];
$query->preExecute();
$key_data['build_info'][$index] = array(
'sql' => (string) $query,
'arguments' => $query->getArguments(),
);
}
}
}
$key = md5(serialize($key_data));
return $key;
}
}
/**
......
......@@ -918,7 +918,7 @@ class views_plugin_display extends views_plugin {
/**
* Get a full array of handlers for $type. This caches them.
*/
function get_handlers($type) {
function &get_handlers($type) {
if (!isset($this->handlers[$type])) {
$this->handlers[$type] = array();
$types = views_object_types();
......
......@@ -37,7 +37,7 @@ class views_plugin_display_feed extends views_plugin_display_page {
function execute() {
$output = $this->view->render();
if (empty($output)) {
return drupal_not_found();
return MENU_NOT_FOUND;
}
print $output;
}
......
......@@ -216,11 +216,11 @@ class views_plugin_display_page extends views_plugin_display {
// display, and arguments should be set on the view.
$this->view->build();
if (!empty($this->view->build_info['fail'])) {
return drupal_not_found();
return MENU_NOT_FOUND;
}
if (!empty($this->view->build_info['denied'])) {
return drupal_access_denied();
return MENU_ACCESS_DENIED;
}
$this->view->get_breadcrumb(TRUE);
......
......@@ -173,7 +173,7 @@ class views_plugin_exposed_form extends views_plugin {
$view = $this->view;
$exposed_data = isset($view->exposed_data) ? $view->exposed_data : array();
$sort_by = isset($exposed_data['sort_by']) ? $exposed_data['sort_by'] : NULL;
if (!empty($sort_by)) {
if (!empty($sort_by) && $this->view->style_plugin->build_sort()) {
// Make sure the original order of sorts is preserved
// (e.g. a sticky sort is often first)
if (isset($view->sort[$sort_by])) {
......
......@@ -71,6 +71,7 @@ class views_plugin_exposed_form_input_required extends views_plugin_exposed_form
'group_type' => 'group',
'content' => $this->options['text_input_required'],
'format' => $this->options['text_input_required_format'],
'empty' => TRUE,
);
$handler = views_get_handler('views', 'area', 'area');
$handler->init($this->view, $options);
......
......@@ -107,7 +107,7 @@ class views_plugin_pager extends views_plugin {
* Get the pager id, if it exists
*/
function get_pager_id() {
return isset($this->options['id']) ? $this->options['id'] : 0;
return !empty($this->options['id']) ? $this->options['id'] : 0;
}
/**
......
......@@ -276,7 +276,7 @@ class views_plugin_pager_full extends views_plugin_pager {
);
$output = theme($pager_theme, array(
'tags' => $tags,
'element' => $this->options['id'],
'element' => $this->get_pager_id(),
'parameters' => $input,
'quantity' => $this->options['quantity'],
));
......@@ -308,11 +308,12 @@ class views_plugin_pager_full extends views_plugin_pager {
// array hasn't been initialized before.
$page = isset($_GET['page']) ? explode(',', $_GET['page']) : array();
for ($i = 0; $i <= $this->options['id'] || $i < count($pager_page_array); $i++) {
$pager_id = $this->get_pager_id();
for ($i = 0; $i <= $pager_id || $i < count($pager_page_array); $i++) {
$pager_page_array[$i] = empty($page[$i]) ? 0 : $page[$i];
}
$this->current_page = intval($pager_page_array[$this->options['id']]);
$this->current_page = intval($pager_page_array[$pager_id]);
if ($this->current_page < 0) {
$this->current_page = 0;
......@@ -348,24 +349,25 @@ class views_plugin_pager_full extends views_plugin_pager {
// Dump information about what we already know into the globals.
global $pager_page_array, $pager_total, $pager_total_items, $pager_limits;
// Set the limit.
$pager_limits[$this->options['id']] = $this->options['items_per_page'];
$pager_id = $this->get_pager_id();
$pager_limits[$pager_id] = $this->options['items_per_page'];
// Set the item count for the pager.
$pager_total_items[$this->options['id']] = $this->total_items;
$pager_total_items[$pager_id] = $this->total_items;
// Calculate and set the count of available pages.
$pager_total[$this->options['id']] = $this->get_pager_total();
$pager_total[$pager_id] = $this->get_pager_total();
// See if the requested page was within range:
if ($this->current_page < 0) {
$this->current_page = 0;
}
else if ($this->current_page >= $pager_total[$this->options['id']]) {
else if ($this->current_page >= $pager_total[$pager_id]) {
// Pages are numbered from 0 so if there are 10 pages, the last page is 9.
$this->current_page = $pager_total[$this->options['id']] - 1;
$this->current_page = $pager_total[$pager_id] - 1;
}
// Put this number in to guarantee that we do not generate notices when the pager
// goes to look for it later.
$pager_page_array[$this->options['id']] = $this->current_page;
$pager_page_array[$pager_id] = $this->current_page;
}
}
......
......@@ -63,7 +63,7 @@ class views_plugin_pager_mini extends views_plugin_pager_full {
);
return theme($pager_theme, array(
'tags' => $tags,
'element' => $this->options['id'],
'element' => $this->get_pager_id(),
'parameters' => $input,
));
}
......
......@@ -1365,6 +1365,16 @@ class views_plugin_query_default extends views_plugin_query {
// Add all query substitutions as metadata.
$query->addMetaData('views_substitutions', module_invoke_all('views_query_substitutions', $this));
if (!$get_count) {
if (!empty($this->limit) || !empty($this->offset)) {
// We can't have an offset without a limit, so provide a very large limit
// instead.
$limit = intval(!empty($this->limit) ? $this->limit : 999999);
$offset = intval(!empty($this->offset) ? $this->offset : 0);
$query->range($offset, $limit);
}
}
return $query;
}
......@@ -1469,16 +1479,8 @@ class views_plugin_query_default extends views_plugin_query {
$this->pager->execute_count_query($count_query);
}
// Let the pager modify the query to add limits.
$this->pager->pre_execute($query);
if (!empty($this->limit) || !empty($this->offset)) {
// We can't have an offset without a limit, so provide a very large limit instead.
$limit = intval(!empty($this->limit) ? $this->limit : 999999);
$offset = intval(!empty($this->offset) ? $this->offset : 0);
$query->range($offset, $limit);
}
$result = $query->execute();
$view->result = array();
......
......@@ -142,8 +142,17 @@ class views_plugin_style_jump_menu extends views_plugin_style {
unset($this->view->row_index);
$default_value = '';
if ($this->options['default_value'] && !empty($paths[url($_GET['q'])])) {
$default_value = $paths[url($_GET['q'])];
if ($this->options['default_value']) {
$lookup_options = array();
// We need to check if the path is absolute
// or else language is not taken in account.
if ($this->view->display[$this->view->current_display]->display_options['fields'][$this->options['path']]['absolute']) {
$lookup_options['absolute'] = TRUE;
}
$lookup_url = url($_GET['q'], $lookup_options);
if (!empty($paths[$lookup_url])) {
$default_value = $paths[$lookup_url];
}
}
ctools_include('jump-menu');
......
......@@ -34,6 +34,8 @@ class ViewsHandlerFieldDateTest extends ViewsSqlTest {
'relationship' => 'none',
// c is iso 8601 date format @see http://php.net/manual/en/function.date.php
'custom_date_format' => 'c',
'second_date_format' => 'custom',
'second_date_format_custom' => 'c',
),
));
$time = gmmktime(0, 0, 0, 1, 1, 2000);
......@@ -51,6 +53,8 @@ class ViewsHandlerFieldDateTest extends ViewsSqlTest {
'medium' => format_date($time, 'medium', '', $timezone),
'large' => format_date($time, 'large', '', $timezone),
'custom' => format_date($time, 'custom', 'c', $timezone),
'today time ago custom' => format_date($time, 'custom', 'c', $timezone),
'today time ago' => t('%time ago', array('%time' => format_interval(120, 2))),
);
$this->assertRenderedDatesEqual($view, $dates, $timezone);
}
......@@ -67,6 +71,17 @@ class ViewsHandlerFieldDateTest extends ViewsSqlTest {
protected function assertRenderedDatesEqual($view, $map, $timezone = NULL) {
foreach ($map as $date_format => $expected_result) {
$check_result_number = 0;
// If it's "today time ago" format we have to check the 6th element.
if ($date_format == 'today time ago') {
$check_result_number = 5;
}
// Correct the date format.
if ($date_format == 'today time ago custom') {
$date_format = 'today time ago';
}
$view->field['created']->options['date_format'] = $date_format;
$t_args = array(
'%value' => $expected_result,
......@@ -80,8 +95,23 @@ class ViewsHandlerFieldDateTest extends ViewsSqlTest {
else {
$message = t('Value %value in %format format matches.', $t_args);
}
$actual_result = $view->field['created']->advanced_render($view->result[0]);
$actual_result = $view->field['created']->advanced_render($view->result[$check_result_number]);
$this->assertEqual($expected_result, $actual_result, $message);
}
}
/**
* Appends dataSet() with a data row for "today time ago" format testing.
*/
protected function dataSet() {
$data = parent::dataSet();
$data[] = array(
'name' => 'David',
'age' => 25,
'job' => 'Singer',
'created' => REQUEST_TIME - 120,
);
return $data;
}
}
<?php
/**
* @file
* Definition of ViewsHandlerFileExtensionTest.
*/
/**
* Tests the views_handler_field_file_extension handler.
*/
class ViewsHandlerFileExtensionTest extends ViewsSqlTest {
public static function getInfo() {
return array(
'name' => 'Field: File extension',
'description' => 'Test the views_handler_field_file_extension handler.',
'group' => 'Views Handlers',
);
}
function dataSet() {
$data = parent::dataSet();
$data[0]['name'] = 'file.png';
$data[1]['name'] = 'file.tar';
$data[2]['name'] = 'file.tar.gz';
$data[3]['name'] = 'file';
return $data;
}
function viewsData() {
$data = parent::viewsData();
$data['views_test']['name']['field']['handler'] = 'views_handler_field_file_extension';
$data['views_test']['name']['real field'] = 'name';
return $data;
}
/**
* Tests the 'extension_detect_tar' handler option.
*/
public function testFileExtensionTarOption() {
$view = $this->getBasicView();
$view->display['default']->handler->override_option('fields', array(
'name' => array(
'id' => 'name',
'table' => 'views_test',
'field' => 'name',
),
));
$this->executeView($view);
// Test without the tar option.
$this->assertEqual($view->field['name']->advanced_render($view->result[0]), 'png');
$this->assertEqual($view->field['name']->advanced_render($view->result[1]), 'tar');
$this->assertEqual($view->field['name']->advanced_render($view->result[2]), 'gz');
$this->assertEqual($view->field['name']->advanced_render($view->result[3]), '');
// Test with the tar option.
$view->field['name']->options['extension_detect_tar'] = TRUE;
$this->assertEqual($view->field['name']->advanced_render($view->result[0]), 'png');
$this->assertEqual($view->field['name']->advanced_render($view->result[1]), 'tar');
$this->assertEqual($view->field['name']->advanced_render($view->result[2]), 'tar.gz');
$this->assertEqual($view->field['name']->advanced_render($view->result[3]), '');
}
}
<?php
/**
* @file
* Contains ViewsHandlerTest.
*/
/**
* Tests generic handler functionality.
*
* @see view
*/
class ViewsHandlerTest extends ViewsSqlTest {
public static function getInfo() {
return array(
'name' => 'Handlers',
'description' => 'Tests generic handler functionality.',
'group' => 'Views Handlers',
);
}
/**
* {@inheritdoc}
*/
protected function viewsData() {
$views_data = parent::viewsData();
$views_data['views']['test_access'] = array(
'title' => 'test access',
'help' => '',
'area' => array(
'handler' => 'views_test_area_access',
),
);
return $views_data;
}
/**
* Tests access for handlers using an area handler.
*/
public function testHandlerAccess() {
$view = $this->getBasicView();
// add a test area
$view->display['default']->handler->override_option('header', array(
'test_access' => array(
'id' => 'test_access',
'table' => 'views',
'field' => 'test_access',
'custom_access' => FALSE,
),
));
$view->init_display();
$view->init_handlers();
$handlers = $view->display_handler->get_handlers('header');
$this->assertEqual(0, count($handlers));
$view->destroy();
$view = $this->getBasicView();
// add a test area
$view->display['default']->handler->override_option('header', array(
'test_access' => array(
'id' => 'test_access',
'table' => 'views',
'field' => 'test_access',
'custom_access' => TRUE,
),
));
$view->init_display();
$view->init_handlers();
$handlers = $view->display_handler->get_handlers('header');
$this->assertEqual(1, count($handlers));
$this->assertTrue(isset($handlers['test_access']));
}
}
<?php
/**
* @file
* Contains views_test_area_access
*/
class views_test_area_access extends views_handler_area {
/**
* {@inheritdoc}
*/
function access() {
return $this->options['custom_access'];
}
/**
* {@inheritdoc}
*/
function option_definition() {
$options = parent::option_definition();
$options['custom_access'] = array('default' => TRUE, 'bool' => TRUE);
return $options;
}
}
......@@ -241,4 +241,68 @@ class ViewsCacheTest extends ViewsSqlTest {
$this->assertEqual($first_content_type, $second_content_type, t('Content types of responses are equal.'));
}
/**
* Test caching of different exposed filter values with the same view result.
*
* Make sure the output is different.
*/
function testExposedFilterSameResultsCaching() {
// Create the view with time-based cache with hour lifetimes and add exposed
// filter to it with "Starts with" operator.
$view = $this->getBasicView();
$view->set_display();
$view->display_handler->override_option('cache', array(
'type' => 'time',
'results_lifespan' => '3600',
'output_lifespan' => '3600',
));
$view->display_handler->override_option('filters', array(
'name' => array(
'id' => 'name',
'table' => 'views_test',
'field' => 'name',
'relationship' => 'none',
'operator' => 'starts',
'exposed' => TRUE,
'expose' => array(
'operator_id' => 'name_op',
'operator' => 'name_op',
'identifier' => 'name',
),
),
));
// Clone the view before setting exposed input.
$clone = $view->copy();
// Pass "Rin" to the exposed filter and check that only one row returned.
$view->set_exposed_input(array(
'name' => 'Rin',
));
$this->executeView($view);
$first_result = $view->result;
$first_output = $view->render();
$this->assertEqual(1, count($first_result), t('The number of rows returned by the first view match.'));
// Pass full "Ringo" to the exposed filter at the second time and make sure
// results are the same.
$clone->set_exposed_input(array(
'name' => 'Ringo',
));
$this->executeView($clone);
$second_result = $clone->result;
$second_output = $clone->render();
$this->assertEqual($first_result, $second_result, t('Results of both views are the same.'));
// Check that output is not the same and it contains full "Ringo" word in
// default value of exposed input.
$this->assertNotEqual($first_output, $second_output, t('Output of the second view is different.'));
$this->drupalSetContent($second_output);
$element = $this->xpath('//input[@name="name" and @value="Ringo"]');
$this->assertTrue(!empty($element), t('Input field of exposed filter has the second value.'));
$view->destroy();
$clone->destroy();
}
}
......@@ -151,6 +151,51 @@ class ViewsModuleTest extends ViewsSqlTest {
$this->assertEqual('views_handler_filter', get_class($handler));
}
/**
* Tests views_fetch_data().
*/
function testFetchData() {
// Make sure we start with a empty cache.
$this->resetStaticViewsDataCache();
cache_clear_all('*', 'cache_views', TRUE);
variable_set('views_test_views_data_count', 0);
// Request info about an existing table.
$this->assertTrue(views_fetch_data('views_test'), 'Data about existing table returned');
// This should have triggered a views data rebuild, and written a cache
// entry for all tables and the requested table but no other tables.
$this->assertEqual(variable_get('views_test_views_data_count', 0), 1, 'Views data rebuilt once');
$this->assertTrue(cache_get('views_data:en', 'cache_views'), 'Cache for all tables written.');
$this->assertTrue(cache_get('views_data:views_test:en', 'cache_views'), 'Cache for requested table written.');
$this->assertFalse(cache_get('views_data:views_test_previous:en', 'cache_views'), 'No Cache written for not requested table.');
$this->assertTrue(drupal_static('_views_fetch_data_fully_loaded'), 'Views data is fully loaded');
$this->resetStaticViewsDataCache();
// Request the same table again.
$this->assertTrue(views_fetch_data('views_test'), 'Data about existing table returned');
$this->assertEqual(variable_get('views_test_views_data_count', 0), 1, 'Views data rebuilt once');
$this->assertFalse(drupal_static('_views_fetch_data_fully_loaded'), 'Views data is not fully loaded');
$this->resetStaticViewsDataCache();
// Request a missing table, this should load the full cache from cache but
// not rebuilt.
$this->assertFalse(views_fetch_data('views_test_missing'), 'No data about missing table returned');
$this->assertEqual(variable_get('views_test_views_data_count', 0), 1, 'Views data rebuilt once');
$this->assertTrue(drupal_static('_views_fetch_data_fully_loaded'), 'Views data is fully loaded');
$this->resetStaticViewsDataCache();
// Request the same empty table again, this should load only that (empty)
// cache for that table.
$this->assertFalse(views_fetch_data('views_test_missing'), 'No data about missing table returned');
$this->assertEqual(variable_get('views_test_views_data_count', 0), 1, 'Views data rebuilt once');
$this->assertFalse(drupal_static('_views_fetch_data_fully_loaded'), 'Views data is not fully loaded');
}
/**
* Ensure that a certain handler is a instance of a certain table/field.
*/
......@@ -160,4 +205,13 @@ class ViewsModuleTest extends ViewsSqlTest {
$this->assertEqual($field_data['handler'], get_class($handler));
}
/**
* Resets the views data cache.
*/
protected function resetStaticViewsDataCache() {
drupal_static_reset('_views_fetch_data_cache');
drupal_static_reset('_views_fetch_data_recursion_protected');
drupal_static_reset('_views_fetch_data_fully_loaded');
}
}
......@@ -5,9 +5,9 @@ core = 7.x
dependencies[] = views
hidden = TRUE
; Information added by drupal.org packaging script on 2013-04-09
version = "7.x-3.7"
; Information added by Drupal.org packaging script on 2014-05-20
version = "7.x-3.8"
core = "7.x"
project = "views"
datestamp = "1365499236"
datestamp = "1400618928"
......@@ -31,6 +31,10 @@ function views_test_views_api() {
* Implements hook_views_data().
*/
function views_test_views_data() {
// Count how often this hook is called.
$count = variable_get('views_test_views_data_count', 0);
$count++;
variable_set('views_test_views_data_count', $count);
return variable_get('views_test_views_data', array());
}
......
......@@ -513,6 +513,80 @@ function hook_views_data_alter(&$data) {
// Note that the $data array is not returned – it is modified by reference.
}
/**
* Override the default data for a Field API field.
*
* Field module's implementation of hook_views_data() invokes this for each
* field in the module that defines the field type (as declared in the field
* array). It is not invoked in other modules.
*
* If no hook implementation exists, hook_views_data() falls back to
* field_views_field_default_views_data().
*
* @see field_views_data()
* @see hook_field_views_data_alter()
* @see hook_field_views_data_views_data_alter()
*
* @param $field
* A field definition array, as returned by field_info_fields().
*
* @return
* An array of views data, in the same format as the return value of
* hook_views_data().
*/
function hook_field_views_data($field) {
}
/**
* Alter the views data for a single Field API field.
*
* This is called even if there is no hook_field_views_data() implementation for
* the field, and therefore may be used to alter the default data that
* field_views_field_default_views_data() supplies for the field.
*
* @param $result
* An array of views table data provided for a single field. This has the same
* format as the return value of hook_views_data().
* @param $field
* A field definition array, as returned by field_info_fields().
* @param $module
* The module that defines the field type.
*
* @see field_views_data()
* @see hook_field_views_data()
* @see hook_field_views_data_views_data_alter()
*/
function hook_field_views_data_alter(&$result, $field, $module) {
}
/**
* Alter the views data on a per field basis.
*
* Field module's implementation of hook_views_data_alter() invokes this for
* each field in the module that defines the field type (as declared in the
* field array). It is not invoked in other modules.
*
* Unlike hook_field_views_data_alter(), this operates on the whole of the views
* data. This allows a field module to add data that concerns its fields to
* other tables, which would not yet be defined at the point when
* hook_field_views_data() and hook_field_views_data_alter() are invoked. For
* example, entityreference adds reverse relationships on the tables for the
* entities which are referenced by entityreference fields.
*
* (Note: this is weirdly named so as not to conflict with
* hook_field_views_data_alter().)
*
* @see hook_field_views_data()
* @see hook_field_views_data_alter()
* @see field_views_data_alter()
*/
function hook_field_views_data_views_data_alter(&$data, $field) {
$field_name = $field['field_name'];
$data_key = 'field_data_' . $field_name;
// Views data for this field is in $data[$data_key]
}
/**
* Describes plugins defined by the module.
......
......@@ -10,6 +10,7 @@ stylesheets[all][] = css/views.css
dependencies[] = ctools
; Handlers
files[] = handlers/views_handler_area.inc
files[] = handlers/views_handler_area_messages.inc
files[] = handlers/views_handler_area_result.inc
files[] = handlers/views_handler_area_text.inc
files[] = handlers/views_handler_area_text_custom.inc
......@@ -49,6 +50,7 @@ files[] = handlers/views_handler_filter_in_operator.inc
files[] = handlers/views_handler_filter_many_to_one.inc
files[] = handlers/views_handler_filter_numeric.inc
files[] = handlers/views_handler_filter_string.inc
files[] = handlers/views_handler_filter_fields_compare.inc
files[] = handlers/views_handler_relationship.inc
files[] = handlers/views_handler_relationship_groupwise_max.inc
files[] = handlers/views_handler_sort.inc
......@@ -253,6 +255,7 @@ files[] = plugins/views_plugin_style_summary_unformatted.inc
files[] = plugins/views_plugin_style_table.inc
; Tests
files[] = tests/handlers/views_handlers.test
files[] = tests/handlers/views_handler_area_text.test
files[] = tests/handlers/views_handler_argument_null.test
files[] = tests/handlers/views_handler_argument_string.test
......@@ -261,6 +264,7 @@ files[] = tests/handlers/views_handler_field_boolean.test
files[] = tests/handlers/views_handler_field_custom.test
files[] = tests/handlers/views_handler_field_counter.test
files[] = tests/handlers/views_handler_field_date.test
files[] = tests/handlers/views_handler_field_file_extension.test
files[] = tests/handlers/views_handler_field_file_size.test
files[] = tests/handlers/views_handler_field_math.test
files[] = tests/handlers/views_handler_field_url.test
......@@ -274,6 +278,7 @@ files[] = tests/handlers/views_handler_filter_string.test
files[] = tests/handlers/views_handler_sort_random.test
files[] = tests/handlers/views_handler_sort_date.test
files[] = tests/handlers/views_handler_sort.test
files[] = tests/test_handlers/views_test_area_access.inc
files[] = tests/test_plugins/views_test_plugin_access_test_dynamic.inc
files[] = tests/test_plugins/views_test_plugin_access_test_static.inc
files[] = tests/test_plugins/views_test_plugin_style_test_mapping.inc
......@@ -312,9 +317,9 @@ files[] = tests/views_cache.test
files[] = tests/views_view.test
files[] = tests/views_ui.test
; Information added by drupal.org packaging script on 2013-04-09
version = "7.x-3.7"
; Information added by Drupal.org packaging script on 2014-05-20
version = "7.x-3.8"
core = "7.x"
project = "views"
datestamp = "1365499236"
datestamp = "1400618928"
......@@ -355,9 +355,6 @@ function views_permission() {
* Implement hook_menu().
*/
function views_menu() {
// Any event which causes a menu_rebuild could potentially mean that the
// Views data is updated -- module changes, profile changes, etc.
views_invalidate_cache();
$items = array();
$items['views/ajax'] = array(
'title' => 'Views',
......
......@@ -7,9 +7,9 @@ dependencies[] = views
files[] = views_ui.module
files[] = plugins/views_wizard/views_ui_base_views_wizard.class.php
; Information added by drupal.org packaging script on 2013-04-09
version = "7.x-3.7"
; Information added by Drupal.org packaging script on 2014-05-20
version = "7.x-3.8"
core = "7.x"
project = "views"
datestamp = "1365499236"
datestamp = "1400618928"
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