security update core+modules

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-26 18:38:56 +02:00
parent 2f45ea820a
commit 7c96373038
1022 changed files with 30319 additions and 11259 deletions

View File

@@ -0,0 +1,34 @@
<?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;
}
}

View File

@@ -56,7 +56,7 @@ class views_handler_area_text extends views_handler_area {
if (!empty($options[$type])) {
$items = array();
foreach ($options[$type] as $key => $value) {
$items[] = $key . ' == ' . $value;
$items[] = $key . ' == ' . check_plain($value);
}
$output .= theme('item_list',
array(

View File

@@ -423,11 +423,13 @@ class views_handler_argument extends views_handler {
$plugin->options_validate($form['argument_default'][$default_id], $form_state, $form_state['values']['options']['argument_default'][$default_id]);
}
// summary plugin
$summary_id = $form_state['values']['options']['summary']['format'];
$plugin = $this->get_plugin('style', $summary_id);
if ($plugin) {
$plugin->options_validate($form['summary']['options'][$summary_id], $form_state, $form_state['values']['options']['summary']['options'][$summary_id]);
// Validate summary plugin options if one is present.
if (isset($form_state['values']['options']['summary']['format'])) {
$summary_id = $form_state['values']['options']['summary']['format'];
$plugin = $this->get_plugin('style', $summary_id);
if ($plugin) {
$plugin->options_validate($form['summary']['options'][$summary_id], $form_state, $form_state['values']['options']['summary']['options'][$summary_id]);
}
}
$validate_id = $form_state['values']['options']['validate']['type'];
@@ -453,14 +455,16 @@ class views_handler_argument extends views_handler {
$form_state['values']['options']['default_argument_options'] = $options;
}
// summary plugin
$summary_id = $form_state['values']['options']['summary']['format'];
$plugin = $this->get_plugin('style', $summary_id);
if ($plugin) {
$options = &$form_state['values']['options']['summary']['options'][$summary_id];
$plugin->options_submit($form['summary']['options'][$summary_id], $form_state, $options);
// Copy the now submitted options to their final resting place so they get saved.
$form_state['values']['options']['summary_options'] = $options;
// Handle summary plugin options if one is present.
if (isset($form_state['values']['options']['summary']['format'])) {
$summary_id = $form_state['values']['options']['summary']['format'];
$plugin = $this->get_plugin('style', $summary_id);
if ($plugin) {
$options = &$form_state['values']['options']['summary']['options'][$summary_id];
$plugin->options_submit($form['summary']['options'][$summary_id], $form_state, $options);
// Copy the now submitted options to their final resting place so they get saved.
$form_state['values']['options']['summary_options'] = $options;
}
}
$validate_id = $form_state['values']['options']['validate']['type'];

View File

@@ -814,7 +814,7 @@ If you would like to have the characters \'[\' and \']\' please use the html ent
if (!empty($options[$type])) {
$items = array();
foreach ($options[$type] as $key => $value) {
$items[] = $key . ' == ' . $value;
$items[] = $key . ' == ' . check_plain($value);
}
$output .= theme('item_list',
array(

View File

@@ -25,6 +25,8 @@ class views_handler_field_boolean extends views_handler_field {
function option_definition() {
$options = parent::option_definition();
$options['type'] = array('default' => 'yes-no');
$options['type_custom_true'] = array('default' => '', 'translatable' => TRUE);
$options['type_custom_false'] = array('default' => '', 'translatable' => TRUE);
$options['not'] = array('definition bool' => 'reverse');
return $options;
@@ -42,7 +44,8 @@ class views_handler_field_boolean extends views_handler_field {
'unicode-yes-no' => array('✔', '✖'),
);
$output_formats = isset($this->definition['output formats']) ? $this->definition['output formats'] : array();
$this->formats = array_merge($default_formats, $output_formats);
$custom_format = array('custom' => array(t('Custom')));
$this->formats = array_merge($default_formats, $output_formats, $custom_format);
}
function options_form(&$form, &$form_state) {
@@ -56,6 +59,29 @@ class views_handler_field_boolean extends views_handler_field {
'#options' => $options,
'#default_value' => $this->options['type'],
);
$form['type_custom_true'] = array(
'#type' => 'textfield',
'#title' => t('Custom output for TRUE'),
'#default_value' => $this->options['type_custom_true'],
'#states' => array(
'visible' => array(
'select[name="options[type]"]' => array('value' => 'custom'),
),
),
);
$form['type_custom_false'] = array(
'#type' => 'textfield',
'#title' => t('Custom output for FALSE'),
'#default_value' => $this->options['type_custom_false'],
'#states' => array(
'visible' => array(
'select[name="options[type]"]' => array('value' => 'custom'),
),
),
);
$form['not'] = array(
'#type' => 'checkbox',
'#title' => t('Reverse'),
@@ -71,7 +97,10 @@ class views_handler_field_boolean extends views_handler_field {
$value = !$value;
}
if (isset($this->formats[$this->options['type']])) {
if ($this->options['type'] == 'custom') {
return $value ? filter_xss_admin($this->options['type_custom_true']) : filter_xss_admin($this->options['type_custom_false']);
}
else if (isset($this->formats[$this->options['type']])) {
return $value ? $this->formats[$this->options['type']][0] : $this->formats[$this->options['type']][1];
}
else {

View File

@@ -14,6 +14,7 @@ class views_handler_field_counter extends views_handler_field {
function option_definition() {
$options = parent::option_definition();
$options['counter_start'] = array('default' => 1);
$options['reverse'] = array('default' => FALSE);
return $options;
}
@@ -26,6 +27,13 @@ class views_handler_field_counter extends views_handler_field {
'#size' => 2,
);
$form['reverse'] = array(
'#type' => 'checkbox',
'#title' => t('Reverse'),
'#default_value' => $this->options['reverse'],
'#description' => t('Reverse the counter.'),
);
parent::options_form($form, $form_state);
}
@@ -34,16 +42,24 @@ class views_handler_field_counter extends views_handler_field {
}
function render($values) {
$reverse = empty($this->options['reverse']) ? 1 : -1;
// Note: 1 is subtracted from the counter start value below because the
// counter value is incremented by 1 at the end of this function.
$count = is_numeric($this->options['counter_start']) ? $this->options['counter_start'] - 1 : 0;
$counter_start = is_numeric($this->options['counter_start']) ? $this->options['counter_start'] : 0;
$count = ($reverse == -1) ? count($this->view->result) + $counter_start : $counter_start -1;
$pager = $this->view->query->pager;
// Get the base count of the pager.
if ($pager->use_pager()) {
$count += ($pager->get_items_per_page() * $pager->get_current_page() + $pager->get_offset());
if ($reverse == -1) {
$count = ($pager->total_items + $counter_start - ($pager->get_current_page() * $pager->get_items_per_page()) + $pager->get_offset());
} else {
$count += (($pager->get_items_per_page() * $pager->get_current_page() + $pager->get_offset())) * $reverse;
}
}
// Add the counter for the current site.
$count += $this->view->row_index + 1;
$count += ($this->view->row_index + 1) * $reverse;
return $count;
}

View File

@@ -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':

View File

@@ -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');

View File

@@ -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);
}
}

View File

@@ -0,0 +1,142 @@
<?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']
);
}
}

View File

@@ -258,7 +258,7 @@ class views_handler_filter_numeric extends views_handler_filter {
}
function op_regex($field) {
$this->query->add_where($this->options['group'], $field, $this->value, 'RLIKE');
$this->query->add_where($this->options['group'], $field, $this->value['value'], 'RLIKE');
}
function admin_summary() {

View File

@@ -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'])));
}
}
@@ -835,10 +835,10 @@ function theme_views_ui_view_info($variables) {
}
$output = '';
$output .= '<div class="views-ui-view-title">' . $title . "</div>\n";
$output .= '<div class="views-ui-view-title">' . check_plain($title) . "</div>\n";
$output .= '<div class="views-ui-view-displays">' . $displays . "</div>\n";
$output .= '<div class="views-ui-view-storage">' . $type . "</div>\n";
$output .= '<div class="views-ui-view-base">' . t('Type') . ': ' . $variables['base']. "</div>\n";
$output .= '<div class="views-ui-view-base">' . t('Type') . ': ' . check_plain($variables['base']). "</div>\n";
return $output;
}
@@ -855,9 +855,6 @@ function views_ui_break_lock_confirm($form, &$form_state, $view) {
}
$cancel = 'admin/structure/views/view/' . $view->name . '/edit';
if (!empty($_REQUEST['cancel'])) {
$cancel = $_REQUEST['cancel'];
}
$account = user_load($view->locked->uid);
return confirm_form($form,
@@ -2214,7 +2211,7 @@ function views_ui_edit_form_get_bucket($type, $view, $display) {
switch ($type) {
case 'filter':
$rearrange_url = "admin/structure/views/nojs/rearrange-$type/$view->name/$display->id/$type";
$rearrange_text = t('and/or, rearrange');
$rearrange_text = t('And/Or, Rearrange');
// TODO: Add another class to have another symbol for filter rearrange.
$class = 'icon compact rearrange';
break;
@@ -2233,7 +2230,7 @@ function views_ui_edit_form_get_bucket($type, $view, $display) {
default:
$rearrange_url = "admin/structure/views/nojs/rearrange/$view->name/$display->id/$type";
$rearrange_text = t('rearrange');
$rearrange_text = t('Rearrange');
$class = 'icon compact rearrange';
}
@@ -2241,16 +2238,16 @@ function views_ui_edit_form_get_bucket($type, $view, $display) {
$actions = array();
$count_handlers = count($display->handler->get_handlers($type));
$actions['add'] = array(
'title' => t('add'),
'title' => t('Add'),
'href' => "admin/structure/views/nojs/add-item/$view->name/$display->id/$type",
'attributes'=> array('class' => array('icon compact add', 'views-ajax-link'), 'title' => t('add'), 'id' => 'views-add-' . $type),
'attributes'=> array('class' => array('icon compact add', 'views-ajax-link'), 'title' => t('Add'), 'id' => 'views-add-' . $type),
'html' => TRUE,
);
if ($count_handlers > 0) {
$actions['rearrange'] = array(
'title' => $rearrange_text,
'href' => $rearrange_url,
'attributes' => array('class' => array($class, 'views-ajax-link'), 'title' => $rearrange_text, 'id' => 'views-rearrange-' . $type),
'attributes' => array('class' => array($class, 'views-ajax-link'), 'title' => t('Rearrange'), 'id' => 'views-rearrange-' . $type),
'html' => TRUE,
);
}
@@ -2964,7 +2961,7 @@ function views_ui_ajax_form($js, $key, $view, $display_id = '') {
else {
$output = array();
$output[] = views_ajax_command_dismiss_form();
$output[] = views_ajax_command_show_buttons();
$output[] = views_ajax_command_show_buttons(!empty($view->changed));
$output[] = views_ajax_command_trigger_preview();
if (!empty($form_state['#page_title'])) {
$output[] = views_ajax_command_replace_title($form_state['#page_title']);
@@ -3038,7 +3035,7 @@ function views_ui_reorder_displays_form($form, &$form_state) {
foreach ($view->display as $display) {
$form[$display->id] = array(
'title' => array('#markup' => $display->display_title),
'title' => array('#markup' => check_plain($display->display_title)),
'weight' => array(
'#type' => 'weight',
'#value' => $display->position,
@@ -4122,8 +4119,8 @@ function views_ui_add_item_form($form, &$form_state) {
$zebra_class = ($zebra % 2) ? 'odd' : 'even';
$form['options']['name'][$key] = array(
'#type' => 'checkbox',
'#title' => t('!group: !field', array('!group' => $option['group'], '!field' => $option['title'])),
'#description' => $option['help'],
'#title' => t('!group: !field', array('!group' => check_plain($option['group']), '!field' => check_plain($option['title']))),
'#description' => filter_xss_admin($option['help']),
'#return_value' => $key,
'#prefix' => "<div class='$zebra_class filterable-option'>",
'#suffix' => '</div>',
@@ -5047,7 +5044,7 @@ function views_ui_autocomplete_tag($string = '') {
$views = views_get_all_views();
foreach ($views as $view) {
if (!empty($view->tag) && strpos($view->tag, $string) === 0) {
$matches[$view->tag] = $view->tag;
$matches[$view->tag] = check_plain($view->tag);
if (count($matches) >= 10) {
break;
}
@@ -5267,7 +5264,7 @@ function theme_views_ui_style_plugin_table($variables) {
$rows = array();
foreach (element_children($form['columns']) as $id) {
$row = array();
$row[] = drupal_render($form['info'][$id]['name']);
$row[] = check_plain(drupal_render($form['info'][$id]['name']));
$row[] = drupal_render($form['columns'][$id]);
$row[] = drupal_render($form['info'][$id]['align']);
$row[] = drupal_render($form['info'][$id]['separator']);

View File

@@ -169,12 +169,16 @@ function views_ajax_command_scroll_top($selector) {
/**
* Shows Save and Cancel buttons.
*
* @param bool $changed
* Whether of not the view has changed.
*
* @return
* An array suitable for use with the ajax_render() function.
*/
function views_ajax_command_show_buttons() {
function views_ajax_command_show_buttons($changed) {
$command = array(
'command' => 'viewsShowButtons',
'changed' => (bool) $changed,
);
return $command;
}

View File

@@ -117,7 +117,7 @@ class views_object {
$localization_keys = $this->localization_keys;
}
// but plugins don't because there isn't a common init() these days.
else if (!empty($this->is_plugin)) {
else if (!empty($this->is_plugin) && empty($localization_keys)) {
if ($this->plugin_type != 'display') {
$localization_keys = array($this->view->current_display);
$localization_keys[] = $this->plugin_type;
@@ -346,8 +346,8 @@ class views_object {
$value = $options;
// Build source data and add to the array
$format = NULL;
if (isset($definition['format_key']) && isset($options[$definition['format_key']])) {
$format = $options[$definition['format_key']];
if (isset($definition['format_key']) && isset($storage[$definition['format_key']])) {
$format = $storage[$definition['format_key']];
}
$translatable[] = array(
'value' => $value,

View File

@@ -23,14 +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 {
// No cache entry, rebuild.
$cache = _views_fetch_data_build();
$fully_loaded = TRUE;
if (!$fully_loaded) {
// 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])) {
@@ -80,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;
}

View File

@@ -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";
}

View File

@@ -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;

View File

@@ -61,7 +61,9 @@
Drupal.ajax.prototype.commands.viewsShowButtons = function (ajax, response, status) {
$('div.views-edit-view div.form-actions').removeClass('js-hide');
$('div.views-edit-view div.view-changed.messages').removeClass('js-hide');
if (response.changed) {
$('div.views-edit-view div.view-changed.messages').removeClass('js-hide');
}
};
Drupal.ajax.prototype.commands.viewsTriggerPreview = function (ajax, response, status) {

View File

@@ -57,7 +57,7 @@ Drupal.views.ajaxView = function(settings) {
this.settings = settings;
// Add the ajax to exposed forms.
this.$exposed_form = $('form#views-exposed-form-'+ settings.view_name.replace(/_/g, '-') + '-' + settings.view_display_id.replace(/_/g, '-'));
this.$exposed_form = this.$view.children('.view-filters').children('form');
this.$exposed_form.once(jQuery.proxy(this.attachExposedFormAjax, this));
// Add the ajax to pagers.
@@ -66,10 +66,21 @@ 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. In order to trigger a
// refresh use the following code.
//
// @code
// jQuery('.view-name').trigger('RefreshView');
// @endcode
// 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() {
var button = $('input[type=submit], input[type=image]', this.$exposed_form);
var button = $('input[type=submit], button[type=submit], input[type=image]', this.$exposed_form);
button = button[0];
this.exposedFormAjax = new Drupal.ajax($(button).attr('id'), button, this.element_settings);

View File

@@ -20,7 +20,7 @@
*/
(function ($, undefined) {
if ($.ui && $.ui.dialog) {
if ($.ui && $.ui.dialog && $.ui.dialog.overlay) {
$.ui.dialog.overlay.events = $.map('focus,keydown,keypress'.split(','),
function(event) { return event + '.dialog-overlay'; }).join(' ');
}

View File

@@ -209,7 +209,7 @@ Drupal.viewsUi.addItemForm.prototype.handleCheck = function (event) {
*/
Drupal.viewsUi.addItemForm.prototype.refreshCheckedItems = function() {
// Perhaps we should precache the text div, too.
this.$selected_div.find('.views-selected-options').html(this.checkedItems.join(', '));
this.$selected_div.find('.views-selected-options').html(Drupal.checkPlain(this.checkedItems.join(', ')));
Drupal.viewsUi.resizeModal('', true);
}
@@ -255,10 +255,11 @@ Drupal.behaviors.viewsUiRenderAddViewButton.attach = function (context, settings
// away from the item. We use mouseleave instead of mouseout because
// the user is going to trigger mouseout when she moves from the trigger
// link to the sub menu items.
// We use the live binder because the open class on this item will be
//
// We use the 'li.add' selector because the open class on this item will be
// toggled on and off and we want the handler to take effect in the cases
// that the class is present, but not when it isn't.
$('li.add', $menu).live('mouseleave', function (event) {
$menu.delegate('li.add', 'mouseleave', function (event) {
var $this = $(this);
var $trigger = $this.children('a[href="#"]');
if ($this.children('.action-list').is(':visible')) {

View File

@@ -9,7 +9,7 @@ Drupal.behaviors.viewsContextualLinks = {
// If there are views-related contextual links attached to the main page
// content, find the smallest region that encloses both the links and the
// view, and display it as a contextual links region.
$('.views-contextual-links-page', context).closest(':has(.view)').addClass('contextual-links-region');
$('.views-contextual-links-page', context).closest(':has(".view"):not("body")').addClass('contextual-links-region');
}
};

View File

@@ -18,9 +18,9 @@ class views_handler_argument_aggregator_iid extends views_handler_argument_numer
$titles = array();
$placeholders = implode(', ', array_fill(0, sizeof($this->value), '%d'));
$result = db_select('aggregator_item')
$result = db_select('aggregator_item', 'ai')
->condition('iid', $this->value, 'IN')
->fields(array('title'))
->fields('ai', array('title'))
->execute();
foreach ($result as $term) {
$titles[] = check_plain($term->title);

View File

@@ -25,7 +25,8 @@ function comment_views_default_views() {
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['title'] = 'Recent comments';
$handler->display->display_options['use_more'] = TRUE;
$handler->display->display_options['access']['type'] = 'none';
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['access']['perm'] = 'access comments';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['query']['options']['query_comment'] = FALSE;
@@ -134,7 +135,8 @@ function comment_views_default_views() {
/* Display: Master */
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['title'] = 'Recent posts';
$handler->display->display_options['access']['type'] = 'none';
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['access']['perm'] = 'access content';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['query']['options']['query_comment'] = FALSE;

View File

@@ -488,7 +488,13 @@ function list_field_views_data($field) {
foreach ($data as $table_name => $table_data) {
foreach ($table_data as $field_name => $field_data) {
if (isset($field_data['filter']) && $field_name != 'delta') {
$data[$table_name][$field_name]['filter']['handler'] = 'views_handler_filter_field_list';
if ($field['type'] == 'list_boolean') {
// Special handler for boolean fields.
$data[$table_name][$field_name]['filter']['handler'] = 'views_handler_filter_field_list_boolean';
}
else {
$data[$table_name][$field_name]['filter']['handler'] = 'views_handler_filter_field_list';
}
}
if (isset($field_data['argument']) && $field_name != 'delta') {
if ($field['type'] == 'list_text') {

View File

@@ -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();
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* @file
* Definition of views_handler_filter_field_list_boolean.
*/
/**
* Filter handler for boolean fields.
*
* @ingroup views_filter_handlers
*/
class views_handler_filter_field_list_boolean extends views_handler_filter_field_list {
function get_value_options() {
$field = field_info_field($this->definition['field_name']);
$value_options = list_allowed_values($field);
// Boolean fields have an option for using the label as the 'on' value. This
// results in there being no label values in the allows values array.
// If this is the case, we need to provide the labels.
$filtered = array_filter($value_options);
if (empty($filtered)) {
// We can't provide the label in the same way the FieldAPI formatter does,
// as these are different on each instance, and we may be operating on
// more than one bundle.
$value_options[0] = t('Off');
$value_options[1] = t('On');
}
$this->value_options = $value_options;
}
}

View File

@@ -24,7 +24,8 @@ function node_views_default_views() {
/* Display: Master */
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['title'] = 'Monthly archive';
$handler->display->display_options['access']['type'] = 'none';
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['access']['perm'] = 'access content';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['query']['options']['query_comment'] = FALSE;
@@ -110,7 +111,8 @@ function node_views_default_views() {
/* Display: Master */
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['access']['type'] = 'none';
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['access']['perm'] = 'access content';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['query']['options']['query_comment'] = FALSE;
@@ -192,7 +194,8 @@ function node_views_default_views() {
/* Display: Master */
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['use_ajax'] = TRUE;
$handler->display->display_options['access']['type'] = 'none';
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['access']['perm'] = 'access content';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['query']['options']['query_comment'] = FALSE;

View File

@@ -24,6 +24,7 @@ function node_views_templates() {
$handler = $view->new_display('default', 'Defaults', 'default');
$handler->display->display_options['title'] = 'Image gallery';
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['access']['perm'] = 'access content';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['exposed_form']['type'] = 'basic';

View File

@@ -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),

View File

@@ -23,7 +23,8 @@ function search_views_default_views() {
/* Display: Master */
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['access']['type'] = 'none';
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['access']['perm'] = 'access content';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['query']['options']['query_comment'] = FALSE;

View File

@@ -25,7 +25,8 @@ function statistics_views_default_views() {
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['title'] = 'Popular content';
$handler->display->display_options['use_more'] = TRUE;
$handler->display->display_options['access']['type'] = 'none';
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['access']['perm'] = 'access content';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['query']['options']['query_comment'] = FALSE;

View File

@@ -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);
}
}
}
}

View File

@@ -23,7 +23,8 @@ function taxonomy_views_default_views() {
/* Display: Master */
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['access']['type'] = 'none';
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['access']['perm'] = 'access content';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['query']['options']['query_comment'] = FALSE;

View File

@@ -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();

View File

@@ -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;

View File

@@ -96,15 +96,15 @@ class views_plugin_argument_validate_taxonomy_term extends views_plugin_argument
$query = db_select('taxonomy_term_data', 'td');
$query->leftJoin('taxonomy_vocabulary', 'tv', 'td.vid = tv.vid');
$query->fields('td');
$query->fields('tv', array('machine_name'));
$query->condition('td.tid', $argument);
$query->addTag('term_access');
$term = $query->execute()->fetchObject();
if (!$term) {
return FALSE;
}
$this->argument->validated_title = check_plain($term->name);
return empty($vocabularies) || !empty($vocabularies[$term->machine_name]);
$term = taxonomy_term_load($term->tid);
$this->argument->validated_title = check_plain(entity_label('taxonomy_term', $term));
return empty($vocabularies) || !empty($vocabularies[$term->vocabulary_machine_name]);
case 'tids':
// An empty argument is not a term so doesn't pass.
@@ -151,8 +151,8 @@ class views_plugin_argument_validate_taxonomy_term extends views_plugin_argument
$validated_cache[$term->tid] = FALSE;
return FALSE;
}
$titles[] = $validated_cache[$term->tid] = check_plain($term->name);
$term = taxonomy_term_load($term->tid);
$titles[] = $validated_cache[$term->tid] = check_plain(entity_label('taxonomy_term', $term));
unset($test[$term->tid]);
}
}
@@ -185,7 +185,8 @@ class views_plugin_argument_validate_taxonomy_term extends views_plugin_argument
if ($type == 'convert') {
$this->argument->argument = $term->tid;
}
$this->argument->validated_title = check_plain($term->name);
$term = taxonomy_term_load($term->tid);
$this->argument->validated_title = check_plain(entity_label('taxonomy_term', $term));
return TRUE;
}
return FALSE;

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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;
}
}
/**

View File

@@ -476,7 +476,7 @@ class views_plugin_display extends views_plugin {
'display_description' => FALSE,
'use_ajax' => TRUE,
'hide_attachment_summary' => TRUE,
'hide_admin_links' => FALSE,
'hide_admin_links' => TRUE,
'pager' => TRUE,
'pager_options' => TRUE,
'use_more' => TRUE,
@@ -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();

View File

@@ -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;
}

View File

@@ -30,6 +30,7 @@ class views_plugin_display_page extends views_plugin_display {
'weight' => array('default' => 0),
'name' => array('default' => variable_get('menu_default_node_menu', 'navigation')),
'context' => array('default' => ''),
'context_only_inline' => array('default' => FALSE),
),
);
$options['tab_options'] = array(
@@ -153,7 +154,7 @@ class views_plugin_display_page extends views_plugin_display {
// Add context for contextual links.
// @see menu_contextual_links()
if (!empty($menu['context'])) {
$items[$path]['context'] = MENU_CONTEXT_INLINE;
$items[$path]['context'] = !empty($menu['context_only_inline']) ? MENU_CONTEXT_INLINE : (MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE);
}
// If this is a 'default' tab, check to see if we have to create teh
@@ -215,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);
@@ -386,12 +387,23 @@ class views_plugin_display_page extends views_plugin_display {
);
$form['menu']['context'] = array(
'#title' => t('Context'),
'#suffix' => '</div>',
'#type' => 'checkbox',
'#default_value' => !empty($menu['context']),
'#description' => t('Displays the link in contextual links'),
'#dependency' => array('radio:menu[type]' => array('tab')),
);
$form['menu']['context_only_inline'] = array(
'#title' => t('Hide menu tab'),
'#suffix' => '</div>',
'#type' => 'checkbox',
'#default_value' => !empty($menu['context_only_inline']),
'#description' => t('Only display menu item entry in contextual links. Menu tab should not be displayed.'),
'#dependency' => array(
'radio:menu[type]' => array('tab'),
'edit-menu-context' => array(1),
),
'#dependency_count' => 2,
);
break;
case 'tab_options':
$form['#title'] .= t('Default tab options');

View File

@@ -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])) {

View File

@@ -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);

View File

@@ -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;
}
/**

View File

@@ -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;
}
}

View File

@@ -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,
));
}

View File

@@ -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();

View File

@@ -19,6 +19,7 @@ class views_plugin_style_jump_menu extends views_plugin_style {
$options['text'] = array('default' => 'Go', 'translatable' => TRUE);
$options['label'] = array('default' => '', 'translatable' => TRUE);
$options['choose'] = array('default' => '- Choose -', 'translatable' => TRUE);
$options['inline'] = array('default' => TRUE, 'bool' => TRUE);
$options['default_value'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
@@ -83,6 +84,12 @@ class views_plugin_style_jump_menu extends views_plugin_style {
'#description' => t('The text that will appear as the selected option in the jump menu.'),
);
$form['inline'] = array(
'#type' => 'checkbox',
'#title' => t('Set this field to display inline'),
'#default_value' => !empty($this->options['inline']),
);
$form['default_value'] = array(
'#type' => 'checkbox',
'#title' => t('Select the current contextual filter value'),
@@ -135,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');
@@ -145,6 +161,7 @@ class views_plugin_style_jump_menu extends views_plugin_style {
'button' => $this->options['text'],
'title' => $this->options['label'],
'choose' => $this->options['choose'],
'inline' => $this->options['inline'],
'default_value' => $default_value,
);

View File

@@ -20,6 +20,7 @@ class views_plugin_style_summary_jump_menu extends views_plugin_style {
$options['text'] = array('default' => 'Go', 'translatable' => TRUE);
$options['label'] = array('default' => '', 'translatable' => TRUE);
$options['choose'] = array('default' => '- Choose -', 'translatable' => TRUE);
$options['inline'] = array('default' => TRUE, 'bool' => TRUE);
$options['default_value'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
@@ -78,6 +79,12 @@ class views_plugin_style_summary_jump_menu extends views_plugin_style {
'#description' => t('The text that will appear as the selected option in the jump menu.'),
);
$form['inline'] = array(
'#type' => 'checkbox',
'#title' => t('Set this field to display inline'),
'#default_value' => !empty($this->options['inline']),
);
$form['default_value'] = array(
'#type' => 'checkbox',
'#title' => t('Select the current contextual filter value'),
@@ -129,6 +136,7 @@ class views_plugin_style_summary_jump_menu extends views_plugin_style {
'button' => $this->options['text'],
'title' => $this->options['label'],
'choose' => $this->options['choose'],
'inline' => $this->options['inline'],
'default_value' => $default_value,
);

View File

@@ -75,6 +75,7 @@ class ViewsUiCommentViewsWizard extends ViewsUiBaseViewsWizard {
// Add permission-based access control.
$display_options['access']['type'] = 'perm';
$display_options['access']['perm'] = 'access comments';
// Add a relationship to nodes.
$display_options['relationships']['nid']['id'] = 'nid';

View File

@@ -64,6 +64,7 @@ class ViewsUiNodeViewsWizard extends ViewsUiBaseViewsWizard {
// Add permission-based access control.
$display_options['access']['type'] = 'perm';
$display_options['access']['perm'] = 'access content';
// Remove the default fields, since we are customizing them here.
unset($display_options['fields']);

View File

@@ -15,6 +15,7 @@ class ViewsUiTaxonomyTermViewsWizard extends ViewsUiBaseViewsWizard {
// Add permission-based access control.
$display_options['access']['type'] = 'perm';
$display_options['access']['perm'] = 'access content';
// Remove the default fields, since we are customizing them here.
unset($display_options['fields']);

View File

@@ -66,11 +66,43 @@ class ViewsHandlerFieldBooleanTest extends ViewsSqlTest {
$this->assertEqual('✖', $view->field['age']->advanced_render($view->result[0]));
$this->assertEqual('✔', $view->field['age']->advanced_render($view->result[1]));
// Set a custom output format.
// Set a custom output format programmatically.
$view->field['age']->formats['test'] = array(t('Test-True'), t('Test-False'));
$view->field['age']->options['type'] = 'test';
$this->assertEqual(t('Test-False'), $view->field['age']->advanced_render($view->result[0]));
$this->assertEqual(t('Test-True'), $view->field['age']->advanced_render($view->result[1]));
// Set a custom output format through the UI using plain-text inputs.
$view->field['age']->options['type'] = 'custom';
$values = array(
'false' => 'Nay',
'true' => 'Yay',
);
$view->field['age']->options['type_custom_false'] = $values['false'];
$view->field['age']->options['type_custom_true'] = $values['true'];
$this->assertEqual($values['false'], $view->field['age']->advanced_render($view->result[0]));
$this->assertEqual($values['true'], $view->field['age']->advanced_render($view->result[1]));
// Set a custom output format through the UI using valid HTML inputs.
$view->field['age']->options['type'] = 'custom';
$values = array(
'false' => '<div class="bar">Nay</div>',
'true' => '<div class="foo">Yay</div>',
);
$view->field['age']->options['type_custom_false'] = $values['false'];
$view->field['age']->options['type_custom_true'] = $values['true'];
$this->assertEqual($values['false'], $view->field['age']->advanced_render($view->result[0]));
$this->assertEqual($values['true'], $view->field['age']->advanced_render($view->result[1]));
// Set a custom output format through the UI using unsafe inputs.
$view->field['age']->options['type'] = 'custom';
$values = array(
'false' => '<script>alert("Nay");</script>',
'true' => '<script>alert("Yay");</script>',
);
$view->field['age']->options['type_custom_false'] = $values['false'];
$view->field['age']->options['type_custom_true'] = $values['true'];
$this->assertNotEqual($values['false'], $view->field['age']->advanced_render($view->result[0]));
$this->assertNotEqual($values['true'], $view->field['age']->advanced_render($view->result[1]));
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,66 @@
<?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]), '');
}
}

View File

@@ -0,0 +1,81 @@
<?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']));
}
}

View File

@@ -0,0 +1,28 @@
<?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;
}
}

View File

@@ -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();
}
}

View File

@@ -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');
}
}

View File

@@ -5,9 +5,9 @@ core = 7.x
dependencies[] = views
hidden = TRUE
; Information added by drupal.org packaging script on 2013-02-04
version = "7.x-3.5+38-dev"
; Information added by Drupal.org packaging script on 2015-02-11
version = "7.x-3.10"
core = "7.x"
project = "views"
datestamp = "1359942791"
datestamp = "1423648085"

View File

@@ -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());
}

View File

@@ -114,7 +114,6 @@ class ViewsTranslatableTest extends ViewsSqlTest {
'more1' => array('use_more_text'),
'Reset1' => array('exposed_form', 'reset_button_label'),
'Offset1' => array('pager', 'expose', 'offset_label'),
'Master1' => array('title'),
'title1' => array('title'),
'Tag first1' => array('pager', 'tags', 'first'),
'Tag prev1' => array('pager', 'tags', 'previous'),
@@ -124,9 +123,23 @@ class ViewsTranslatableTest extends ViewsSqlTest {
'fieldlabel1' => array('field', 'node', 'nid', 'label'),
'filterlabel1' => array('filter', 'node', 'nid', 'expose', 'label'),
'- All -' => array('pager', 'expose', 'items_per_page_options_all_label'),
'Header1' => array('header', 'views', 'area', 'content'),
);
$formats = array(
'Header1' => 'filtered_html',
);
foreach ($translatables as $translatable) {
$this->assertEqual($translatable['keys'], $this->string_keys[$translatable['value']]);
// Make sure the format is correct.
if (isset($formats[$translatable['value']])) {
$this->assertEqual($translatable['format'], $formats[$translatable['value']]);
}
else {
$this->assertNull($translatable['format'], 'No format defined');
}
}
}
}
@@ -169,6 +182,14 @@ class ViewsTranslatableTest extends ViewsSqlTest {
$handler->display->display_options['pager']['options']['expose']['offset_label'] = 'Offset1';
$handler->display->display_options['style_plugin'] = 'default';
$handler->display->display_options['row_plugin'] = 'fields';
/* Global: Header */
$handler->display->display_options['header']['area']['id'] = 'area';
$handler->display->display_options['header']['area']['table'] = 'views';
$handler->display->display_options['header']['area']['field'] = 'area';
$handler->display->display_options['header']['area']['empty'] = FALSE;
$handler->display->display_options['header']['area']['content'] = 'Header1';
$handler->display->display_options['header']['area']['format'] = 'filtered_html';
$handler->display->display_options['header']['area']['tokenize'] = 0;
/* Field: Content: Nid */
$handler->display->display_options['fields']['nid']['id'] = 'nid';
$handler->display->display_options['fields']['nid']['table'] = 'node';

View File

@@ -482,13 +482,15 @@ function hook_views_data_alter(&$data) {
$data['users']['example_field'] = array(
'title' => t('Example field'),
'help' => t('Some example content that references a user'),
'handler' => 'hook_handlers_field_example_field',
'field' => array(
'handler' => 'modulename_handler_field_example_field',
),
);
// This example changes the handler of the node title field.
// In this handler you could do stuff, like preview of the node when clicking
// the node title.
$data['node']['title']['handler'] = 'modulename_handlers_field_node_title';
$data['node']['title']['field']['handler'] = 'modulename_handler_field_node_title';
// This example adds a relationship to table {foo}, so that 'foo' views can
// add this table using a relationship. Because we don't want to write over
@@ -511,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.
@@ -834,7 +910,7 @@ function hook_views_pre_view(&$view, &$display_id, &$args) {
user_access('administer site configuration') &&
$display_id == 'public_display'
) {
$display_id = 'private_display';
$view->set_display('private_display');
}
}

View File

@@ -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
@@ -100,6 +102,7 @@ files[] = modules/contact/views_handler_field_contact_link.inc
files[] = modules/field/views_handler_field_field.inc
files[] = modules/field/views_handler_relationship_entity_reverse.inc
files[] = modules/field/views_handler_argument_field_list.inc
files[] = modules/field/views_handler_filter_field_list_boolean.inc
files[] = modules/field/views_handler_argument_field_list_string.inc
files[] = modules/field/views_handler_filter_field_list.inc
files[] = modules/filter/views_handler_field_filter_format_name.inc
@@ -253,6 +256,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 +265,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 +279,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 +318,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-02-04
version = "7.x-3.5+38-dev"
; Information added by Drupal.org packaging script on 2015-02-11
version = "7.x-3.10"
core = "7.x"
project = "views"
datestamp = "1359942791"
datestamp = "1423648085"

View File

@@ -341,10 +341,12 @@ function views_permission() {
'administer views' => array(
'title' => t('Administer views'),
'description' => t('Access the views administration pages.'),
'restrict access' => TRUE,
),
'access all views' => array(
'title' => t('Bypass views access control'),
'description' => t('Bypass access control when accessing views.'),
'restrict access' => TRUE,
),
);
}
@@ -353,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',
@@ -466,16 +465,31 @@ function views_menu_alter(&$callbacks) {
* The menu argument index. This counts from 1.
*/
function views_arg_load($value, $name, $display_id, $index) {
static $views = array();
static $views = array();
// Make sure we haven't already loaded this views argument for a similar menu
// item elsewhere.
$key = $name . ':' . $display_id . ':' . $value . ':' . $index;
if (isset($views[$key])) {
return $views[$key];
$display_ids = is_array($display_id) ? $display_id : array($display_id);
$display_id = reset($display_ids);
foreach ($display_ids as $id) {
// Make sure we haven't already loaded this views argument for a similar
// menu item elsewhere. Since access is always checked for the current user,
// we are sure that the static cache contains valid entries.
$key = $name . ':' . $id . ':' . $value . ':' . $index;
if (isset($views[$key])) {
return $views[$key];
}
// Lazy load the view object to avoid unnecessary work.
if (!isset($view)) {
$view = views_get_view($name);
}
// Pick the first display we have access to.
if ($view && count($display_ids) > 1 && $view->access($id)) {
$display_id = $id;
break;
}
}
if ($view = views_get_view($name)) {
if ($view) {
$view->set_display($display_id);
$view->init_handlers();
@@ -549,7 +563,7 @@ function views_page_alter(&$page) {
}
/**
* Implements MODULE_preprocess_HOOK().
* Implements MODULE_preprocess_HOOK() for html.tpl.php.
*/
function views_preprocess_html(&$variables) {
// If the page contains a view as its main content, contextual links may have
@@ -567,7 +581,7 @@ function views_preprocess_html(&$variables) {
if (!empty($variables['page']['#views_contextual_links_info'])) {
$key = array_search('contextual-links-region', $variables['classes_array']);
if ($key !== FALSE) {
unset($variables['classes_array'][$key]);
$variables['classes_array'] = array_diff($variables['classes_array'], array('contextual-links-region'));
// Add the JavaScript, with a group and weight such that it will run
// before modules/contextual/contextual.js.
drupal_add_js(drupal_get_path('module', 'views') . '/js/views-contextual.js', array('group' => JS_LIBRARY, 'weight' => -1));
@@ -575,6 +589,27 @@ function views_preprocess_html(&$variables) {
}
}
/**
* Implements hook_preprocess_HOOK() for page.tpl.php.
*/
function views_preprocess_page(&$variables) {
// If the page contains a view as its main content, contextual links may have
// been attached to the page as a whole; for example, by views_page_alter().
// This allows them to be associated with the page and rendered by default
// next to the page title (which we want). However, it also causes the
// Contextual Links module to treat the wrapper for the entire page (i.e.,
// the <body> tag) as the HTML element that these contextual links are
// associated with. This we don't want; for better visual highlighting, we
// prefer a smaller region to be chosen. The region we prefer differs from
// theme to theme and depends on the details of the theme's markup in
// page.tpl.php, so we can only find it using JavaScript. We therefore remove
// the "contextual-links-region" class from the <body> tag here and add
// JavaScript that will insert it back in the correct place.
if (!empty($variables['page']['#views_contextual_links_info'])) {
$variables['classes_array'] = array_diff($variables['classes_array'], array('contextual-links-region'));
}
}
/**
* Implements hook_contextual_links_view_alter().
*/

View File

@@ -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-02-04
version = "7.x-3.5+38-dev"
; Information added by Drupal.org packaging script on 2015-02-11
version = "7.x-3.10"
core = "7.x"
project = "views"
datestamp = "1359942791"
datestamp = "1423648085"

View File

@@ -845,7 +845,8 @@ function _views_ui_get_displays_list($view) {
function views_ui_library_alter(&$libraries, $module) {
if ($module == 'system' && isset($libraries['ui.dialog'])) {
if (version_compare($libraries['ui.dialog']['version'], '1.7.2', '>=')) {
// Only apply the fix, if we don't have an up to date jQueryUI version.
if (version_compare($libraries['ui.dialog']['version'], '1.7.2', '>=') && version_compare($libraries['ui.dialog']['version'], '1.10.0', '<')) {
$libraries['ui.dialog']['js'][drupal_get_path('module', 'views') . '/js/jquery.ui.dialog.patch.js'] = array();
}
}