Commit b06399e3 authored by merlinofchaos's avatar merlinofchaos

Basic menu code (needs patch to core). Maybe basic block code too, but I didn't test that part.

parent 4291d390
...@@ -202,6 +202,7 @@ class views_handler_relationship extends views_handler { ...@@ -202,6 +202,7 @@ class views_handler_relationship extends views_handler {
* Base field handler that has no options and renders an unformatted field. * Base field handler that has no options and renders an unformatted field.
*/ */
class views_handler_field extends views_handler { class views_handler_field extends views_handler {
var $field_alias = 'unknown';
/** /**
* Construct a new field handler. * Construct a new field handler.
...@@ -218,7 +219,7 @@ class views_handler_field extends views_handler { ...@@ -218,7 +219,7 @@ class views_handler_field extends views_handler {
$this->ensure_my_table(); $this->ensure_my_table();
// Add the field. // Add the field.
$this->field_alias = $this->query->add_field($this->table_alias, $this->real_field); $this->field_alias = $this->query->add_field($this->table_alias, $this->real_field);
dpr("alias: $this->field_alias");
// Add any additional fields we are given. // Add any additional fields we are given.
if (!empty($this->additional_fields) && is_array($this->additional_fields)) { if (!empty($this->additional_fields) && is_array($this->additional_fields)) {
foreach ($this->additional_fields as $field) { foreach ($this->additional_fields as $field) {
...@@ -591,6 +592,13 @@ class views_handler_argument extends views_handler { ...@@ -591,6 +592,13 @@ class views_handler_argument extends views_handler {
function title() { function title() {
return check_plain($this->argument); return check_plain($this->argument);
} }
/**
* Validate that this argument works. By default, all arguments are valid.
*/
function validate($arg) {
return TRUE;
}
} }
/** /**
......
...@@ -17,11 +17,13 @@ function views_views_plugins() { ...@@ -17,11 +17,13 @@ function views_views_plugins() {
'title' => t('Page'), 'title' => t('Page'),
'help' => t('Creates a page with a URL, menu links, etc.'), 'help' => t('Creates a page with a URL, menu links, etc.'),
'handler' => 'views_display_plugin_page', 'handler' => 'views_display_plugin_page',
'uses_hook_menu' => TRUE,
), ),
'block' => array( 'block' => array(
'title' => t('Block'), 'title' => t('Block'),
'help' => t('Creates a block that can be used from the block administration page.'), 'help' => t('Creates a block that can be used from the block administration page.'),
'handler' => 'views_display_plugin_block', 'handler' => 'views_display_plugin_block',
'uses_hook_block' => TRUE,
), ),
'embed' => array( 'embed' => array(
'title' => t('Embedded'), 'title' => t('Embedded'),
...@@ -127,35 +129,51 @@ class views_display_plugin extends views_object { ...@@ -127,35 +129,51 @@ class views_display_plugin extends views_object {
function render_more_link() { } function render_more_link() { }
/** /**
* Not all display plugins will have a feed icon, nor will they * Not all display plugins will have a feed icon.
* put it in the same place.
*/ */
function render_feed_icon() { } function render_feed_icon() { }
/** /**
* Render the view's title for display * Render the view's title for display
* TODO: Necessary? Hm.
*/ */
function render_title() { } function render_title() { }
function render_header() { } function render_textarea($area) {
function render_footer() { } $format_string = $area . '_format';
function render_empty() { return 'empty text'; } return check_markup($this->display->$area, $this->display->$format_string);
}
/**
* Render the header of the view.
*/
function render_header() { return $this->render_textarea('header'); }
/**
* Render the footer of the view.
*/
function render_footer() { return $this->render_textarea('footer'); }
/**
* Render the empty text of the view.
*/
function render_empty() { return $this->render_textarea('empty'); }
/** /**
* If this display creates a block, implement one of these. * If this display creates a block, implement one of these.
*/ */
// function hook_block($op = 'list', $delta = 0, $edit = array()) {} function hook_block($op = 'list', $delta = 0, $edit = array()) { return array(); }
/** /**
* If this display creates a page with a menu item, implement it here. * If this display creates a page with a menu item, implement it here.
*/ */
// function hook_menu() {} function hook_menu() { return array(); }
/** /**
* Render this display. * Render this display.
*/ */
function render() { function render() {
// TODO: Remove this when the 'file' tag on theme registry is fixed. // TODO: Remove this when the 'file' tag on theme registry is fixed.
include_once drupal_get_path('module', 'views') . '/theme/theme.inc'; // include_once drupal_get_path('module', 'views') . '/theme/theme.inc';
$themes = array( $themes = array(
'views_view__' . $this->display->id . '__' . $this->view->name, 'views_view__' . $this->display->id . '__' . $this->view->name,
'views_view__' . $this->display->id, 'views_view__' . $this->display->id,
...@@ -167,6 +185,17 @@ class views_display_plugin extends views_object { ...@@ -167,6 +185,17 @@ class views_display_plugin extends views_object {
return theme($themes, $this->view); return theme($themes, $this->view);
} }
/**
* Determine if the user has access to this display of the view.
*
* TODO: Implement this.
*/
function access($account) { return TRUE; }
/**
* When used externally, this is how a view gets run and returns
* data in the format required.
*/
function execute() { }
} }
/** /**
...@@ -175,9 +204,43 @@ class views_display_plugin extends views_object { ...@@ -175,9 +204,43 @@ class views_display_plugin extends views_object {
class views_display_plugin_page extends views_display_plugin { class views_display_plugin_page extends views_display_plugin {
var $uses_hook_menu = TRUE; var $uses_hook_menu = TRUE;
function hook_menu() {} function execute_hook_menu() {
$items = array();
// Replace % with the link to our standard views argument loader
// views_arg_load -- which lives in views.module
$url = str_replace('%', '%views_arg', $this->display->url);
function render_page() {} // NOTE: This is the very simple 'menu normal item' version. The
// tab version needs to come later. Maybe it should be its own plugin.
$items[$url] = array(
// default views page entry
'page callback' => 'views_page',
'page arguments' => array($this->view->name, $this->display->id),
// Default access check (per display)
'access callback' => 'views_access',
'access arguments' => array(array($this->view->name, $this->display->id)),
// Identify URL embedded arguments and correlate them to a handler
'load arguments' => array($this->view->name, '%index'),
// Basic menu title
'title' => $this->display->title,
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
/**
* The display page handler returns a normal view, but it also does
* a drupal_set_title for the page, and does a views_set_page_view
* on the view.
*/
function execute() {
views_set_page_view($this);
// Prior to this being called, the $view should already be set to this
// display, and arguments should be set on the view.
$this->view->build();
drupal_set_title(filter_xss_admin($this->view->get_title('page')));
return $this->view->render();
}
} }
/** /**
...@@ -185,10 +248,30 @@ class views_display_plugin_page extends views_display_plugin { ...@@ -185,10 +248,30 @@ class views_display_plugin_page extends views_display_plugin {
*/ */
class views_display_plugin_block extends views_display_plugin { class views_display_plugin_block extends views_display_plugin {
var $uses_hook_block = TRUE; var $uses_hook_block = TRUE;
/** /**
* If this display creates a block, implement one of these. * The default block handler doesn't support configurable items,
* but extended block handlers might be able to do interesting
* stuff with it.
*/
function hook_block($op = 'list', $delta = 0, $edit = array()) {
if ($op == 'list') {
$delta = $this->view->name . '-' . $this->display->id;
return array($delta => array('info' => $this->display->block_description));
}
}
/**
* The display block handler returns the structure necessary for a block.
*/ */
function hook_block($op = 'list', $delta = 0, $edit = array()) {} function execute() {
drupal_set_page_view($this);
// Prior to this being called, the $view should already be set to this
// display, and arguments should be set on the view.
$info['content'] = $this->view->render();
$info['subject'] = filter_xss_admin($this->view->get_title('page'));
return $info;
}
} }
/** /**
...@@ -230,7 +313,13 @@ class views_style_plugin_default extends views_style_plugin { ...@@ -230,7 +313,13 @@ class views_style_plugin_default extends views_style_plugin {
// provide an option form to select from our list of node renderers // provide an option form to select from our list of node renderers
} }
/**
* Render the given style.
*/
function render() { function render() {
// TODO: This needs to be able to support either a database resource OR
// an array, because our input format doesn't actually have to be from
// a query.
$plugin = new views_row_plugin; $plugin = new views_row_plugin;
$rows = ''; $rows = '';
while ($row = db_fetch_object($this->view->result)) { while ($row = db_fetch_object($this->view->result)) {
......
...@@ -32,7 +32,7 @@ class view extends views_db_object { ...@@ -32,7 +32,7 @@ class view extends views_db_object {
var $page_size = 25; var $page_size = 25;
var $pager_element = 0; var $pager_element = 0;
var $offset = 0; var $offset = 0;
var $current_page = 0;
/** /**
* Constructor * Constructor
*/ */
...@@ -63,7 +63,7 @@ class view extends views_db_object { ...@@ -63,7 +63,7 @@ class view extends views_db_object {
* Set the arguments that come to this view. Usually from the URL * Set the arguments that come to this view. Usually from the URL
* but possibly from elsewhere. * but possibly from elsewhere.
*/ */
function set_args($args) { function set_arguments($args) {
$this->args = $args; $this->args = $args;
} }
...@@ -192,7 +192,7 @@ class view extends views_db_object { ...@@ -192,7 +192,7 @@ class view extends views_db_object {
} }
// Execute the initial PHP code that a view can have. // Execute the initial PHP code that a view can have.
if ($this->view_args_php) { if (!empty($this->view_args_php)) {
ob_start(); ob_start();
$result = eval($this->view_args_php); $result = eval($this->view_args_php);
if (is_array($result)) { if (is_array($result)) {
...@@ -211,6 +211,7 @@ class view extends views_db_object { ...@@ -211,6 +211,7 @@ class view extends views_db_object {
$views_data = views_fetch_data($this->base_table); $views_data = views_fetch_data($this->base_table);
$this->base_field = $views_data['table']['base']['field']; $this->base_field = $views_data['table']['base']['field'];
views_include('query');
$this->query = new views_query($this->base_table, $this->base_field); $this->query = new views_query($this->base_table, $this->base_field);
// Call a module hook and see if it wants to present us with a // Call a module hook and see if it wants to present us with a
...@@ -219,7 +220,7 @@ class view extends views_db_object { ...@@ -219,7 +220,7 @@ class view extends views_db_object {
// TODO: Implement this. // TODO: Implement this.
// Run through our handlers and ensure they have necessary information. // Run through our handlers and ensure they have necessary information.
$this->_seed_handlers(); $this->seed_handlers();
// Build all the filters. // Build all the filters.
$this->_build('filter'); $this->_build('filter');
...@@ -237,7 +238,7 @@ class view extends views_db_object { ...@@ -237,7 +238,7 @@ class view extends views_db_object {
continue; continue;
} }
if (isset($this->args[$id])) { if (isset($this->args[$id]) && $argument->handler->validate($this->args[$id])) {
// handle argument that is present. // handle argument that is present.
// TODO: Do we want to put in argument placeholders here // TODO: Do we want to put in argument placeholders here
// So that we can try to cache queries with arguments too? // So that we can try to cache queries with arguments too?
...@@ -257,6 +258,9 @@ class view extends views_db_object { ...@@ -257,6 +258,9 @@ class view extends views_db_object {
} }
} }
// TODO: if $argument_title is set, get the argument and
// set it in the build info.
// Build our sort criteria if we were instructed to do so. // Build our sort criteria if we were instructed to do so.
if (!empty($this->build_sort)) { if (!empty($this->build_sort)) {
$this->_build('sort'); $this->_build('sort');
...@@ -290,7 +294,7 @@ class view extends views_db_object { ...@@ -290,7 +294,7 @@ class view extends views_db_object {
/** /**
* Acquire and attach all of the handlers. * Acquire and attach all of the handlers.
*/ */
function _seed_handlers() { function seed_handlers() {
if (empty($this->seeded)) { if (empty($this->seeded)) {
foreach ($this->objects() as $key) { foreach ($this->objects() as $key) {
$this->_seed_handler($key); $this->_seed_handler($key);
...@@ -374,6 +378,51 @@ class view extends views_db_object { ...@@ -374,6 +378,51 @@ class view extends views_db_object {
return $this->display_handler->render(); return $this->display_handler->render();
} }
/**
* To be called externally. Execute the given display, with
* the given arguments.
*/
function execute_display($display_id = NULL, $args = array()) {
// Prepare the view with the information we have.
$this->set_arguments($args);
$this->set_display($display_id);
// Execute the view
if (isset($this->display_handler)) {
return $this->display_handler->execute();
}
}
/**
* Called to get hook_menu information from the view and the
* named display handler.
*/
function execute_hook_menu($display_id = NULL) {
// Prepare the view with the information we have.
$this->set_display($display_id);
// Execute the view
if (isset($this->display_handler)) {
return $this->display_handler->execute_hook_menu();
}
}
/**
* Determine if the given user has access to the view. Note that
* this sets the display handler if it hasn't been.
*/
function access($account) {
if (empty($this->display_handler) && !$this->set_display()) {
return FALSE;
}
if (!$account) {
$account = $GLOBALS['user'];
}
return $this->display_handler->access($account);
}
/** /**
* Get the view's current title. This can change depending upon how it * Get the view's current title. This can change depending upon how it
* was built. * was built.
...@@ -395,7 +444,8 @@ class view extends views_db_object { ...@@ -395,7 +444,8 @@ class view extends views_db_object {
/** /**
* Load a view from the database based upon either vid or name. * Load a view from the database based upon either vid or name.
*/ */
function load($arg) { function load($arg) {
// TODO: Move caching to here, make this a factory method.
$where = (is_numeric($arg) ? "vid = %d" : "name = '%s'"); $where = (is_numeric($arg) ? "vid = %d" : "name = '%s'");
$data = db_fetch_object(db_query("SELECT * FROM {views_view} WHERE $where", $arg)); $data = db_fetch_object(db_query("SELECT * FROM {views_view} WHERE $where", $arg));
if (empty($data)) { if (empty($data)) {
...@@ -408,17 +458,52 @@ class view extends views_db_object { ...@@ -408,17 +458,52 @@ class view extends views_db_object {
foreach ($this->objects_all() as $key) { foreach ($this->objects_all() as $key) {
$this->_load_row($key); $this->_load_row($key);
} }
$view->loaded = TRUE; $this->loaded = TRUE;
return TRUE; return TRUE;
} }
/**
* Static factory method to load a list of views based upon a $where clause.
*/
function load_views($where, $join = '') {
// TODO: Integrate this in with caching.
$result = db_query("SELECT DISTINCT v.* FROM {views_view} v $join WHERE $where");
$views = array();
// Load all the views.
while ($data = db_fetch_object($result)) {
$view = new view;
$view->load_row($data);
$view->loaded = TRUE;
$views[$view->vid] = $view;
}
// Stop if we didn't get any views.
if (!$views) {
return array();
}
$vids = implode(', ', array_keys($views));
// Now load all the subtables:
foreach (view::objects_all() as $key) {
$object_name = "views_$key";
$result = db_query("SELECT * FROM {$object_name} WHERE vid IN ($vids) ORDER BY vid, position");
while ($data = db_fetch_object($result)) {
$object = new $object_name(FALSE);
$object->load_row($data);
array_push($views[$object->vid]->$key, $object);
}
}
return $views;
}
/** /**
* Load one of our sub tables. * Load one of our sub tables.
*/ */
function _load_row($key) { function _load_row($key) {
$object_name = "views_$key"; $object_name = "views_$key";
$table = $object_name; $result = db_query("SELECT * FROM {$object_name} WHERE vid = %d ORDER BY position", $this->vid);
$result = db_query("SELECT * FROM {$table} WHERE vid = %d ORDER BY position", $this->vid);
while ($data = db_fetch_object($result)) { while ($data = db_fetch_object($result)) {
$object = new $object_name(FALSE); $object = new $object_name(FALSE);
......
<?php <?php
/**
* @file
* Provides views data and handlers for node.module
*/
function node_views_data() { function node_views_data() {
// Basic table information. // Basic table information.
$data['node']['table'] = array( $data['node']['table'] = array(
...@@ -81,6 +85,8 @@ function node_views_data() { ...@@ -81,6 +85,8 @@ function node_views_data() {
/** /**
* Field handler to provide simple renderer that allows linking to a node. * Field handler to provide simple renderer that allows linking to a node.
*
* @ingroup views_field_handlers
*/ */
class views_handler_field_node extends views_handler_field { class views_handler_field_node extends views_handler_field {
/** /**
...@@ -124,6 +130,8 @@ class views_handler_field_node extends views_handler_field { ...@@ -124,6 +130,8 @@ class views_handler_field_node extends views_handler_field {
/** /**
* Field handler to translate a node type into its readable form. * Field handler to translate a node type into its readable form.
*
* @ingroup views_field_handlers
*/ */
class views_handler_field_node_type extends views_handler_field_node { class views_handler_field_node_type extends views_handler_field_node {
function render($values) { function render($values) {
......
This diff is collapsed.
...@@ -48,7 +48,6 @@ function views_theme() { ...@@ -48,7 +48,6 @@ function views_theme() {
$plugins = views_fetch_plugin_data(); $plugins = views_fetch_plugin_data();
// Register theme functions for all style plugins // Register theme functions for all style plugins
foreach ($plugins as $type => $info) { foreach ($plugins as $type => $info) {
foreach ($info as $plugin => $def) { foreach ($info as $plugin => $def) {
...@@ -69,6 +68,134 @@ function views_theme() { ...@@ -69,6 +68,134 @@ function views_theme() {
return $hooks; return $hooks;
} }
/**
* Implementation of hook_menu
*
* This probably needs to actually be hook_menu_alter or something.
*/
function views_menu() {
$items = array();
foreach (views_get_page_views() as $data) {
list($view, $display_id) = $data;
$items += $view->execute_hook_menu($display_id);
}
return $items;
}
/**
* Helper function for menu loading. This will automatically be
* called in order to 'load' a views argument; primarily it
* will be used to perform validation.
*
* @param $value
* The actual value passed.
* @param $name
* The name of the view. This needs to be specified in the 'load function'
* of the menu entry.
* @param $index
* The menu argument index. This counts from 1.
*/
function views_arg_load($value, $name, $index) {
if ($view = views_get_view($name)) {
$view->seed_handlers();
if (isset($view->argument[$index - 1])) {
return $view->argument[$index - 1]->handler->validate($value);
}
}
}
/**
* Page callback entry point; requires a view and a display id, then
* passes control to the display handler.
*/
function views_page() {
$args = func_get_args();
$name = array_shift($args);
$display_id = array_shift($args);
// Load the view
if ($view = views_get_view($name)) {
return $view->execute_display($display_id, $args);
}
// Fallback; if we get here no view was found or handler was not valid.
return drupal_not_found();
}
/**
* Implementation of hook_block
*/
function views_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$items = array();
foreach (views_get_block_views() as $data) {
list($view, $display_id) = $data;
$items += $view->execute_hook_block($display_id);
}
return $items;
case 'configure':
case 'list':
case 'view':
list($name, $display_id) = explode('-', $delta);
// Load the view
if ($view = views_get_view($name)) {
if ($op == 'view') {
return $view->execute_display($display_id, $args);
}
else {
return $view->execute_hook_block($display_id, $op, $delta, $edit);
}
}
break;
}
}
/**
* Determine if the given user has access to the view + display.
*/
function views_access($view, $account = NULL) {
if (is_array($view)) {
list($name, $display_id) = $view;
$view = views_get_view($name);
if (!$view) {
return FALSE;
}
$view->set_display($display_id);
}
if (is_string($view)) {
$view = views_get_view($name);
if (!$view) {
return FALSE;
}
}
return $view->access($account);
}
/**
* Set the current 'page view' that is being displayed so that it is easy
* for other modules or the theme to identify.
*/
function &views_set_page_view($view = NULL) {
static $cache = NULL;
if (isset($view)) {
$cache = $view;
}
return $cache;
}
/**
* Find out what, if any, page view is currently in use. Please note that
* this returns a reference, so be careful! You can unintentionally modify the
* $view object.
*/
function &views_get_page_view() {
return views_set_page_view();
}