Commit 01cfda8c authored by merlinofchaos's avatar merlinofchaos
Browse files

Sync from HEAD

parent 9bdf7f2e
......@@ -63,4 +63,42 @@ Views 5.x-1.2-beta-1
o 98492: Comment moderation status filter
o 101025: Sort by node type
Views 5.x-1.3-beta-1
Bugs fixed:
o Reverted 99783 which doesn't work.
o 100769: link book table via vid instead of nid.
o 101306: views_new_table() used incorrect right_field
o 99225: theme wizard wasn't CSS safing classes in an ironic fashion.
o 101363: Made the DISTINCT more forceful by adding a GROUP BY.
o 101167: Proper use of drupal_add_feed
o 'node' arguments weren't properly using node in the title.
o 102142: Default table sorting broken if field with no label comes after
field to sort on.
o 88343: $arg in urls (foo/$arg/bar) had locale problems.
o 97497: rss feed did not call module_invoke_all('exit') as it should.
o 89332: Don't default tables to MyISAM type
o 83478: Properly encode block titles & block descriptions.
New features:
o 101324: New op for views_build_view: 'queries'
o 77526: Automatically enable views_ui if views is installed without it. But not
just when the module is enabled.
Views 5.x-1.4-rc1
Bugs fixed:
o All the date-based arguments were broken due to changes in $query->add_orderby
o 103475: updated rss feed to match fixes in Drupal core.
o 103773: Fixed some obnoxious t() % placeholder <em> stupidity.
o Replaced theme_views_nodate with theme('views_nodate') which is actually themable.
o 103115: Validation for individual views fields/etc was never called.
o 101275: Prevent node.nid from being added as a field twice (was happening when sorting)
o 102746: * was being used instead of actual wildcard in feed URLs.
o 102457: Spurious warnings when displayed node has no terms
New Features:
o 89421: New last changed sort / filter / field
o 103649: allow customizing date interval granularity
Views --dev
......@@ -12,10 +12,10 @@ function book_views_tables() {
'join' => array(
'left' => array(
'table' => 'node',
'field' => 'nid'
'field' => 'vid'
),
'right' => array(
'field' => 'nid'
'field' => 'vid'
)
),
"filters" => array(
......
......@@ -118,6 +118,15 @@ function comment_views_tables() {
),
'help' => t('This will display the comment count.'),
),
'last_changed' => array(
'name' => t('Comment: Last Changed Time'),
'query_handler' => 'views_query_handler_field_last_changed',
'sortable' => TRUE,
'handler' => views_handler_field_dates(),
'option' => 'string',
'notafield' => TRUE,
'help' => t('This will display the time of the last comment or node edit.'),
),
),
'filters' => array(
'comment_count' => array(
......@@ -134,6 +143,15 @@ function comment_views_tables() {
'option' => 'string',
'help' => t('This filter allows nodes to be filtered by the last comment timestamp. Enter dates in the format: CCYY-MM-DD HH:MM:SS. Enter \'now\' to use the current time. You may enter a delta (in seconds) to the option that will be added to the time; this is most useful when combined with now. If you have the jscalendar module from jstools installed, you can use a popup date picker here.'),
),
'last_changed' => array(
'name' => t('Comment: Last Changed Time'),
'operator' => 'views_handler_operator_gtlt',
'value' => views_handler_filter_date_value_form(),
'handler' => 'views_handler_filter_last_changed',
'option' => 'string',
'help' => t('This filter allows nodes to be filtered by the timestamp for the last comment or node edit. Enter dates in the format: CCYY-MM-DD HH:MM:SS. Enter \'now\' to use the current time. You may enter a delta (in seconds) to the option that will be added to the time; this is most useful when combined with now. If you have the jscalendar module from jstools installed, you can use a popup date picker here.'),
),
),
'sorts' => array(
'last_comment_timestamp' => array(
......@@ -146,11 +164,37 @@ function comment_views_tables() {
'name' => t('Comment: Comment Count'),
'help' => t('This filter allows you to sort by the number of comments.'),
),
'last_changed' => array(
'name' => t('Comment: Last Changed'),
'handler' => 'views_handler_sort_last_changed',
'option' => views_handler_sort_date_options(),
'help' => t('Sort based on the most recent comment or edit for the node.'),
),
),
);
return $tables;
}
function views_query_handler_field_last_changed($field, $fieldinfo, &$query) {
$query->add_field('GREATEST(node.changed, node_comment_statistics.last_comment_timestamp)', '', $field['tablename'] . '_last_changed');
}
function views_handler_filter_last_changed($op, $filter, $filterinfo, &$query) {
$value = $filter['value'] == 'now' ? "***CURRENT_TIME***" : strtotime($filter['value']);
$table = $filterinfo['table'];
$column = $table . '_' . $filterinfo['field'];
$field = "GREATEST(node.changed, node_comment_statistics.last_comment_timestamp)";
$query->ensure_table($table);
$query->add_where("%s %s %s + %d", $field, $filter['operator'], $value, $filter['options']);
}
function views_handler_sort_last_changed($action, &$query, $sortinfo, $sort) {
$query->ensure_table('node_comment_statistics');
$query->orderby[] = 'GREATEST(node.changed, node_comment_statistics.last_comment_timestamp) ' . $sort['sortorder'];
}
function views_query_handler_field_last_comment_name($field, $fieldinfo, &$query) {
$num = $query->add_table('users', false, 1, array(
'left' => array(
......@@ -192,7 +236,7 @@ function views_handler_comments_with_new($fieldinfo, $fielddata, $value, $data)
$comments = intval($value);
if ($comments && $new = comment_num_new($data->nid)) {
$comments .= '<br />';
$comments .= l(t('@num new', array('@num' => $new)), "node/$data->nid", NULL, comment_page_new_query($data->nid), 'new');
$comments .= l(t('@num new', array('@num' => $new)), "node/$data->nid", NULL, NULL, 'new');
}
return $comments;
}
......
......@@ -519,7 +519,7 @@ function views_handler_arg_year($op, &$query, $argtype, $arg = '') {
return $fieldinfo;
break;
case 'sort':
$query->add_orderby(NULL, 'year', $argtype);
$query->add_orderby(NULL, "YEAR(FROM_UNIXTIME(node.created+$timezone))", $argtype, 'year');
break;
case 'filter':
$year = intval($arg);
......@@ -542,7 +542,7 @@ function views_handler_arg_month($op, &$query, $argtype, $arg = '') {
return $fieldinfo;
break;
case 'sort':
$query->add_orderby(NULL, 'name', $argtype);
$query->add_orderby(NULL, "MONTH(FROM_UNIXTIME(node.created+$timezone))", $argtype, 'name');
break;
case 'filter':
$month = intval($arg);
......@@ -567,7 +567,7 @@ function views_handler_arg_week($op, &$query, $argtype, $arg = '') {
return $fieldinfo;
break;
case 'sort':
$query->add_orderby(NULL, 'name', $argtype);
$query->add_orderby(NULL, "WEEK(FROM_UNIXTIME(node.created+$timezone), 3)", $argtype, 'name');
break;
case 'filter':
// The 3 makes the week 1-53, the first week of the year has at least 3 days
......@@ -591,7 +591,7 @@ function views_handler_arg_monthyear($op, &$query, $argtype, $arg = '') {
return $fieldinfo;
break;
case 'sort':
$query->add_orderby(NULL, "name", $argtype);
$query->add_orderby(NULL, "DATE_FORMAT(FROM_UNIXTIME(node.created+$timezone), '%Y%m')", $argtype, "name");
break;
case 'filter':
$query->add_where("DATE_FORMAT(FROM_UNIXTIME(node.created+$timezone), '%Y%m') = '%s'", $arg);
......@@ -599,7 +599,7 @@ function views_handler_arg_monthyear($op, &$query, $argtype, $arg = '') {
case 'link':
return l(format_date($query->created, 'custom', 'F, Y'), "$arg/$query->name");
case 'title':
return format_date(strtotime("${query}01"), 'custom', 'F, Y', 0);
return format_date(strtotime("${query}15"), 'custom', 'F, Y', 0);
}
}
function views_handler_arg_fulldate($op, &$query, $argtype, $arg = '') {
......@@ -613,7 +613,7 @@ function views_handler_arg_fulldate($op, &$query, $argtype, $arg = '') {
return $fieldinfo;
break;
case 'sort':
$query->add_orderby(NULL, 'name', $argtype);
$query->add_orderby(NULL, "DATE_FORMAT(FROM_UNIXTIME(node.created+$timezone), '%Y%m%%d')", $argtype, 'name');
break;
case 'filter':
$query->add_where("DATE_FORMAT(FROM_UNIXTIME(node.created+$timezone), '%Y%m%%d') = '%s'", $arg);
......@@ -660,7 +660,7 @@ function views_handler_arg_nid($op, &$query, $argtype, $arg = '') {
while ($node = db_fetch_object($result)) {
$title .= ($title ? ($type == 'or' ? ' + ' : ', ') : '') . check_plain($node->title);
}
return $title;
}
}
......@@ -719,6 +719,7 @@ function views_handler_filter_nodetype($op) {
*/
function views_handler_filter_distinct($op, $filter, $filterinfo, &$query) {
$query->set_distinct();
$query->add_groupby('node.nid');
}
/*
......@@ -798,7 +799,7 @@ function views_post_view_make_url($view, $feed_id, $arg) {
$args[] = $arg;
}
else if ($argdata['argdefault'] != 1) {
$args[] = '*';
$args[] = $argdata['wildcard'] ? check_plain($argdata['wildcard']) : '*';
}
}
}
......
......@@ -63,7 +63,7 @@ function profile_views_get_fields() {
function profile_views_add_field(&$table, $field) {
$name = 'value';
$label = t('Profile: %field-name', array('%field-name' => $field->title));
$label = t('Profile: @field-name', array('@field-name' => $field->title));
switch ($field->type) {
case 'vocabulary':
......@@ -112,7 +112,7 @@ function profile_views_add_field(&$table, $field) {
function profile_views_add_sort(&$table, $field) {
$name = 'value';
$label = t('Profile: %field-name', array('%field-name' => $field->title));
$label = t('Profile: @field-name', array('@field-name' => $field->title));
$others = array();
......@@ -146,7 +146,7 @@ function profile_views_add_sort(&$table, $field) {
function profile_views_add_filter(&$table, $field) {
$name = 'value';
$label = t('Profile: %field-name', array('%field-name' => $field->title));
$label = t('Profile: @field-name', array('@field-name' => $field->title));
switch ($field->type) {
case 'vocabulary':
......
......@@ -47,7 +47,7 @@ function taxonomy_views_tables() {
),
'fields' => array(
'name' => array(
'name' => t('Taxonomy: Terms for %voc-name', array('%voc-name' => $voc->name)),
'name' => t('Taxonomy: Terms for @voc-name', array('@voc-name' => $voc->name)),
'sortable' => false,
'help' => t('This will display all taxonomy terms associated with the node that are members of %voc-name. Note that this causes one extra query per row displayed, and might have a minor performance impact.', array('%voc-name' => $voc->name)),
'handler' => 'views_handler_field_allterms',
......@@ -64,7 +64,7 @@ function taxonomy_views_tables() {
),
'filters' => array(
'tid' => array(
'name' => t('Taxonomy: Terms for %voc-name', array('%voc-name' => $voc->name)),
'name' => t('Taxonomy: Terms for @voc-name', array('@voc-name' => $voc->name)),
'list' => 'views_handler_filter_tid_by_voc',
'value-type' => 'array',
'option' => 'string',
......@@ -254,7 +254,7 @@ function views_handler_field_allterms($fieldinfo, $fielddata, $value, $data) {
$node->taxonomy = $terms;
$links = taxonomy_link('taxonomy terms', $node);
}
return implode(' | ', $links);
return !empty($links) ? implode(' | ', $links) : '';
}
/**
......
; $Id$
name = Views
description = The views module creates customized views of node lists.
version = $Name$
version = "$Name$"
package = Views
......@@ -54,7 +54,7 @@
view_args_php longtext,
PRIMARY KEY (vid),
KEY (name)
) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;");
) /*!40100 DEFAULT CHARACTER SET utf8 */");
db_query("CREATE TABLE if not exists {view_sort} (
vid int(10) unsigned NOT NULL default '0',
......@@ -64,7 +64,7 @@
options varchar(255),
tablename varchar(255),
KEY (vid)
) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;");
) /*!40100 DEFAULT CHARACTER SET utf8 */");
db_query("CREATE TABLE if not exists {view_argument} (
vid int(10) unsigned NOT NULL default '0',
......@@ -76,7 +76,7 @@
wildcard varchar(32),
wildcard_substitution varchar(32),
KEY (vid)
) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;");
) /*!40100 DEFAULT CHARACTER SET utf8 */");
db_query("CREATE TABLE if not exists {view_tablefield} (
vid int(10) unsigned NOT NULL default '0',
......@@ -89,7 +89,7 @@
options varchar(255),
position int(2),
KEY (vid)
) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;");
) /*!40100 DEFAULT CHARACTER SET utf8 */");
db_query("CREATE TABLE if not exists {view_filter} (
vid int(10) unsigned NOT NULL default '0',
......@@ -100,7 +100,7 @@
options varchar(255),
position int(2),
KEY (vid)
) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;");
) /*!40100 DEFAULT CHARACTER SET utf8 */");
db_query("CREATE TABLE if not exists {view_exposed_filter} (
vid int(10) unsigned NOT NULL default '0',
......@@ -112,7 +112,7 @@
single int(1),
position int(2),
KEY (vid)
) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;");
) /*!40100 DEFAULT CHARACTER SET utf8 */");
$success = TRUE;
break;
......@@ -229,6 +229,7 @@
} // End case
if ($success) {
module_enable(array('views_ui'));
drupal_set_message(t('Views module installed tables successfully.'));
}
else {
......
......@@ -31,9 +31,13 @@ function views_menu($may_cache) {
}
$result = db_query("SELECT * FROM {view_view} WHERE page = 1");
$views_with_inline_args = array();
while ($view = db_fetch_object($result)) {
// Skip views with arguments.
if (strrpos($view->url, '$arg') !== FALSE) {
continue;
}
// unpack the array
$view->access = ($view->access ? explode(', ', $view->access) : array());
......@@ -41,13 +45,6 @@ function views_menu($may_cache) {
// it is still used.
$used[$view->name] = true;
if (strrpos($view->url, '$arg')) {
$arg_result = db_query("SELECT * FROM {view_argument} WHERE vid = %d", $view->vid);
while ($view->argument[] = db_fetch_array($arg_result));
array_pop($view->argument); // get rid of the NULL at the end.
$views_with_inline_args[$view->name] = $view;
continue;
}
_views_create_menu_item($items, $view, $view->url);
}
$default_views = _views_get_default_views();
......@@ -57,18 +54,22 @@ function views_menu($may_cache) {
if ($view->page && !$used[$name] &&
($views_status[$name] == 'enabled' || (!$view->disabled && $views_status[$name] != 'disabled'))) {
if (strrpos($view->url, '$arg')) {
$views_with_inline_args[$view->name] = $view;
if (strrpos($view->url, '$arg') !== FALSE) {
continue;
}
_views_create_menu_item($items, $view, $view->url);
}
}
cache_set("views_with_inline_args:$locale", 'cache', serialize($views_with_inline_args));
}
else {
$data = cache_get("views_with_inline_args:$locale", 'cache');
if ($data == 0) {
// There's no cache for our language, regenerate it.
views_reset_inline_args_cache($locale);
$data = cache_get("views_with_inline_args:$locale");
}
$views = unserialize($data->data);
if (is_array($views)) {
foreach ($views as $view) {
......@@ -93,11 +94,52 @@ function views_menu($may_cache) {
return $items;
}
/**
* Reset the views with inline arguments cache for a locale.
*/
function views_reset_inline_args_cache($locale = 'en') {
$result = db_query("SELECT * FROM {view_view} WHERE page = 1");
$views_with_inline_args = array();
while ($view = db_fetch_object($result)) {
// Skip over any non-argument views
if (strrpos($view->url, '$arg') == FALSE) {
continue;
}
// unpack the array
$view->access = ($view->access ? explode(', ', $view->access) : array());
// This happens before the next check; even if it's put off for later
// it is still used.
$used[$view->name] = true;
$arg_result = db_query("SELECT * FROM {view_argument} WHERE vid = %d", $view->vid);
while ($arg = db_fetch_array($arg_result)) {
$view->argument[] = $arg;
}
$views_with_inline_args[$view->name] = $view;
}
views_load_cache();
$default_views = _views_get_default_views();
$views_status = variable_get('views_defaults', array());
foreach ($default_views as $name => $view) {
if ($view->page && !$used[$name] && ($views_status[$name] == 'enabled' || (!$view->disabled && $views_status[$name] != 'disabled'))) {
if (strrpos($view->url, '$arg')) {
$views_with_inline_args[$view->name] = $view;
}
}
}
cache_set("views_with_inline_args:$locale", 'cache', serialize($views_with_inline_args));
}
/**
* Helper function to add a menu item for a view.
*/
function _views_create_menu_item(&$items, $view, $path, $local_task_type = MENU_NORMAL_ITEM, $args = array()) {
views_load_cache();
static $roles = NULL;
if ($roles == NULL) {
global $user;
......@@ -165,7 +207,7 @@ function views_block($op = 'list', $delta = 0) {
// Grab views from the database and provide them as blocks.
$result = db_query("SELECT vid, block_title, page_title, name FROM {view_view} WHERE block = 1");
while ($view = db_fetch_object($result)) {
$block[$view->name]['info'] = views_get_title($view, 'block-info');
$block[$view->name]['info'] = filter_xss_admin(views_get_title($view, 'block-info'));
}
$default_views = _views_get_default_views();
......@@ -174,7 +216,7 @@ function views_block($op = 'list', $delta = 0) {
foreach ($default_views as $name => $view) {
if (!isset($block[$name]) && $view->block &&
($views_status[$name] == 'enabled' || (!$view->disabled && $views_status[$name] != 'disabled'))) {
$block[$name]['info'] = views_get_title($view, 'block');
$block[$name]['info'] = filter_xss_admin(views_get_title($view, 'block'));
}
}
return $block;
......@@ -278,7 +320,7 @@ function views_view_block($vid) {
$content = views_build_view('block', $view, array(), false, $view->nodes_per_block);
if ($content) {
$block['content'] = $content;
$block['subject'] = views_get_title($view, 'block');
$block['subject'] = filter_xss_admin(views_get_title($view, 'block'));
return $block;
}
else {
......@@ -319,6 +361,8 @@ function &views_get_current_view() {
* result: Database object you can use db_fetch_object on.
* 'items' -- return info array as above, except instead of result,
* items: An array of objects containing the results of the query.
* 'queries' -- returns an array, summarizing the queries, but does not
* run them.
* @param $view
* The actual view object. Use views_get_view() if you only have the name or
* vid.
......@@ -404,7 +448,11 @@ function views_build_view($type, &$view, $args = array(), $use_pager = false, $l
}
$query = db_rewrite_sql($info['query'], 'node');
if ($type == 'queries') {
return $info;
}
if ($use_pager) {
$cquery = db_rewrite_sql($info['countquery'], 'node', 'nid', $info['rewrite_args']);
$result = pager_query($query, $limit, $use_pager - 1, $cquery, $info['args']);
......@@ -604,6 +652,7 @@ function views_get_title($view, $context = 'menu', $args = NULL) {
return $title;
}
views_load_cache();
$arginfo = _views_get_arguments();
foreach ($view->argument as $i => $arg) {
if (!isset($args[$i])) {
......@@ -876,7 +925,7 @@ function views_new_table($table_name, $provider, $left_table, $left_field, $righ
$table['provider'] = $provider;
$table['join']['left']['table'] = $left_table;
$table['join']['left']['field'] = $left_field;
$table['join']['right']['field'] = $left_field;
$table['join']['right']['field'] = $right_field;
if ($extra) {
$table['join']['extra'] = $extra;
}
......@@ -1078,7 +1127,7 @@ function _views_construct_header($view, $fields) {
$header['field'] = $field['fullname'];
}
}
else {
else if ($field['label']) {
$header['data'] = $field['label'];
}
......@@ -1418,35 +1467,35 @@ function theme_views_summary($view, $type, $level, $nodes, $args) {
* Format a date.
*/
function views_handler_field_date($fieldinfo, $fielddata, $value, $data) {
return $value ? format_date($value) : theme_views_nodate();
return $value ? format_date($value) : theme('views_nodate');
}
/**
* Format a date using small representation.
*/
function views_handler_field_date_small($fieldinfo, $fielddata, $value, $data) {
return $value ? format_date($value, 'small') : theme_views_nodate();
return $value ? format_date($value, 'small') : theme('views_nodate');
}
/**
* Format a date using large representation.
*/
function views_handler_field_date_large($fieldinfo, $fielddata, $value, $data) {
return $value ? format_date($value, 'large') : theme_views_nodate();
return $value ? format_date($value, 'large') : theme('views_nodate');
}
/**
* Format a date using custom representation.
*/
function views_handler_field_date_custom($fieldinfo, $fielddata, $value, $data) {
return $value ? format_date($value, 'custom', $fielddata['options']) : theme_views_nodate();
return $value ? format_date($value, 'custom', $fielddata['options']) : theme('views_nodate');
}
/**
* Format a date as "X time ago".
*/
function views_handler_field_since($fieldinfo, $fielddata, $value, $data) {
return $value ? t('%time ago', array('%time' => format_interval(time() - $value))) : theme_views_nodate();
return $value ? t('%time ago', array('%time' => format_interval(time() - $value, is_numeric($fielddata['options']) ? $fielddata['options'] : 2))) : theme('views_nodate');
}
function theme_views_nodate() {
......@@ -1509,9 +1558,9 @@ function views_handler_sort_date($op, &$query, $sortinfo, $sort) {
$alias = $field;
}
$query->add_field($field, $table, $as);
$query->orderby[] = "$alias $sort[sortorder]";
// $query->add_orderby($table, $field, $sort['sortorder']);
// $query->add_field($field, $table, $as);
// $query->orderby[] = "$alias $sort[sortorder]";
$query->add_orderby($table, $field, $sort['sortorder'], $as);
}
function views_handler_sort_date_minute($op, &$query, $sortinfo, $sort) {
......
......@@ -273,8 +273,8 @@ class _views_query {
/*
* Create the basic query object and fill with default values.
*/
function _views_query($views_get_title_table = 'node', $views_get_title_field = 'nid', $alias_prefix = '') {
$this->views_get_title_table = $views_get_title_table;
function _views_query($primary_table = 'node', $primary_field = 'nid', $alias_prefix = '') {
$this->primary_table = $primary_table;
$this->joins = array();
$this->where = array();
$this->orderby = array();
......@@ -285,10 +285,10 @@ class _views_query {
// Joins care about order, so we put our tables in a queue to make sure
// the order is correct.
$this->tablequeue = array();
if ($views_get_title_field) {
$this->fields = array($alias_prefix ."$views_get_title_table.$views_get_title_field");
if ($primary_field) {
$this->fields = array($alias_prefix ."$primary_table.$primary_field");
}
$this->count_field = $alias_prefix ."$views_get_title_table.$views_get_title_field";
$this->count_field = $alias_prefix ."$primary_table.$primary_field";
$this->header = array();
}
......@@ -301,15 +301,23 @@ class _views_query {
if ($table == '$$') {
// I picked $$ because it's not a legal name for a table and NULL is
// actually a valid possibility here, and I can't default to a variable.
$table = $this->views_get_title_table;
$table = $this->primary_table;
}
// We check for this specifically because we don't want to add it aliased.
if ($table == $query->primary_table && $field == $view->primary_field) {
return;
}
if ($table) {
$this->ensure_table($table);
$table = $this->use_alias_prefix . $table .".";
}
if ($alias) {
$a = " AS $this->use_alias_prefix$alias";
}
if (!in_array("$table$field$a", $this->fields)) {
$this->fields[] = "$table$field$a";
}
......@@ -410,7 +418,7 @@ class _views_query {
* a path leads back to the views_get_title table.
*/
function ensure_table($table) {
if ($table == $this->views_get_title_table || $this->tables[$table]) {
if ($table == $this->primary_table || $this->tables[$table]) {
return;