summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEarl Miles2008-02-13 06:30:37 (GMT)
committer Earl Miles2008-02-13 06:30:37 (GMT)
commit3a69a04ce801b6199cecaf4358d56a282d3c4ea7 (patch)
treeb5ee287f10bbe32bb6a8673c238d60eee33c7bd4
parentd3b06159198cc90bbfb16615fee565a4a22f7153 (diff)
UI is really getting there now.
-rw-r--r--css/admin.css195
-rw-r--r--images/sprites.pngbin0 -> 1926 bytes
-rw-r--r--includes/admin.inc527
-rw-r--r--includes/ajax.inc10
-rw-r--r--includes/handlers.inc533
-rw-r--r--includes/plugins.inc295
-rw-r--r--includes/view.inc63
-rw-r--r--js/ajax.js11
-rw-r--r--js/base.js9
-rw-r--r--modules/node.views.inc93
-rw-r--r--views.module68
-rw-r--r--views_ui.module19
12 files changed, 1481 insertions, 342 deletions
diff --git a/css/admin.css b/css/admin.css
index 3edb6b0..3b0f544 100644
--- a/css/admin.css
+++ b/css/admin.css
@@ -1,5 +1,9 @@
/* $Id$ */
+.views-tabset {
+ background: #E0E5E8;
+}
+
.views-tabset .views-tab fieldset {
margin-top: 0;
}
@@ -7,7 +11,7 @@
.views-tabset .views-tabs ul {
list-style-type: none !important;
list-style-image: none !important;
- border: 1px solid black;
+ border-bottom: #5C707E 1px solid;
margin: 0;
padding: 0;
}
@@ -15,19 +19,27 @@
.views-tabset .views-tabs ul li {
list-style-type: none;
list-style-image: none;
- background: none;
- margin-left: 0;
+ background: #B3BEC6;
+ border-top: #5C707E 1px solid;
+ border-right: #5C707E 1px solid;
+ border-left: #5C707E 1px solid;
+ margin: 0;
+ padding: 3px 3px 3px 6px;
}
.views-tabset .views-tabs ul li.active {
- background: #ccc;
+ background: #fff;
+ border-top: #5C707E 2px solid;
+ border-right: 0;
+ border-bottom: #5C707E 1px solid;
margin-left: 0;
+ font-weight: bold;
}
.views-tabset .views-tabs {
float: left;
- width: 120px;
+ width: 119px;
}
.views-tabset .extra {
@@ -39,9 +51,9 @@
}
.views-tabset .views-display {
- border: 1px solid black;
- margin-left: 119px; /* 120 -1 causes borders to overlap */
- min-height: 300px;
+ border: #5C707E 1px solid;
+ margin-left: 118px; /* 120 -1 causes borders to overlap */
+ min-height: 302px;
_height: 300px; /* stupid IE hack */
}
.views-tabset .views-display-deleted {
@@ -49,20 +61,23 @@
}
.views-display .top {
- padding: 2px 5px;
- border-left: 1px solid black;
- border-right: 1px solid black;
- border-bottom: 2px solid black;
+ padding: 0.5em 0em 0em 1em;
+ background: #fff;
}
+.views-display .top .display-title {
+ font-weight: bold;
+}
.views-display .top .display-description {
margin-left: 1em;
font-style: italic;
overflow: hide;
white-space: nowrap;
+ font-size: 90%;
}
.views-display .tab-section {
+ background: #fff;
width: 33%;
padding: 0;
margin: 0;
@@ -79,6 +94,8 @@
.views-display .tab-section .links {
float: right;
font-size: 6pt;
+ position: relative;
+ display: inline;
}
.views-display .tab-section .links a {
@@ -93,11 +110,13 @@
.views-display #views-add-display-form {
float: right;
+ margin-bottom: 0;
+ margin-right: 0.5em;
}
.views-display .middle {
width: 34%;
- background-color: #ccc;
+
}
.views-display dl {
@@ -105,28 +124,65 @@
}
.views-basic-info {
- border: 1px solid black;
- padding: 2px 5px;
- background-color: #eee;
+ margin-top: 0.75em;
+ padding: 0.25em;
+ font-weight: bold;
+ background: #E0E5E8;
+}
+
+.views-display dl {
+ margin: 0.25em;
+ display: block;
+ padding: 0.25em 0.5em 0.5em 0.25em;
+ background: #F0F2F4;
+}
+
+
+
+.views-display dt {
+ font-weight: bold;
+ padding: 0 0 0em 0.5em;
+}
+
+.views-display dd,
+.views-display dd a {
+ font-size: 8pt;
+ line-height: 12pt;
}
+.views-display dd {
+ padding: 0 0 0 1.7em;
+ margin: 0;
+ text-indent: -1em;
+}
+
+
#views-ajax-pad {
- border: 1px solid black;
- margin-top: 10px;
+ background: #E0E5E8;
+ margin-top: 0px;
min-height: 200px;
_height: 200px; /* stupid IE */
- padding: 5px;
+
}
#views-ajax-pad .message {
- margin-top: 75px;
+ padding-top: 75px;
text-align: center;
}
+#views-ajax-pad form {
+ background: #ffd;
+ margin-left: 118px;
+ border: #5C707E 1px solid;
+ border-top: #D1D8DD 4px solid;
+}
+
#views-ajax-pad .form-buttons {
- float: right;
margin: 0;
- padding: 0;
+ padding: 0.5em 1em;
+ border-top: #E0E5E8 1px solid;
+ background: #fff;
+ clear: left;
}
#views-ajax-pad .form-buttons .form-submit {
@@ -135,13 +191,29 @@
}
#views-ajax-pad .form-item {
- margin-top: 0;
+ margin: 0.5em;
+ padding: 0em 0.5em;
}
#views-ajax-pad {
display: none;
}
+#views-ajax-title {
+ margin-left: 118px;
+ padding-left: 5px;
+ border-left: 1px solid black;
+ border-right: 1px solid black;
+ height: 1.5em;
+ white-space: nowrap;
+ overflow: hide;
+ font-weight: bold;
+}
+
+#views-ajax-form {
+ background-color: #E0E5E8;
+}
+
html.js #views-ajax-pad {
display: block;
}
@@ -189,3 +261,80 @@ html.js #views-ajax-pad {
overflow: auto;
max-height: 180px;
}
+
+a.views-button-configure,
+a.views-button-add,
+a.views-button-rearrange,
+a.views-button-remove {
+ background:transparent url(../images/sprites.png);
+ display: inline-block;
+ float: right;
+ height: 12px;
+ width: 16px;
+ margin: 2px 0px 1px 0px;
+ border: #666 1px solid;
+}
+
+a.views-button-remove {
+ background-position: 0px -72px;
+ position: relative;
+ top: -4px;
+}
+a.views-button-remove:hover {
+ background-position: 0px -84px;
+}
+
+a.views-button-configure {
+ background-position: 0px -48px;
+ margin: 0;
+}
+a.views-button-configure:hover {
+ background-position: 0px -60px;
+}
+
+a.views-button-add {
+ background-position: 0px -24px;
+}
+a.views-button-add:hover {
+ background-position: 0px -36px;
+}
+
+a.views-button-rearrange {
+ background-position: 0px 0px;
+}
+a.views-button-rearrange:hover {
+ background-position: 0px -12px;
+}
+
+a.views-button-remove span,
+a.views-button-rearrange span,
+a.views-button-configure span,
+a.views-button-add span {
+ display: none;
+}
+html.js #arrange thead {
+ display: none;
+}
+
+html.js .views-remove-checkbox {
+ display: none;
+}
+
+a.views-button-remove {
+ display: none;
+}
+
+html.js a.views-button-remove {
+ display: inline;
+}
+
+#arrange tr.even,
+#arrange tr.odd,
+#arrange td {
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+#arrange .form-item {
+ padding: 0;
+} \ No newline at end of file
diff --git a/images/sprites.png b/images/sprites.png
new file mode 100644
index 0000000..9083622
--- /dev/null
+++ b/images/sprites.png
Binary files differ
diff --git a/includes/admin.inc b/includes/admin.inc
index 788f5ca..f92298b 100644
--- a/includes/admin.inc
+++ b/includes/admin.inc
@@ -240,10 +240,12 @@ function theme_views_ui_edit_view($view) {
$output .= $tabs->render();
$message = '<div class="message">' . t("Click on an item to edit that item's details.") . '</div>';
- $output .= '<div id="views-ajax-title">&nbsp;</div>';
+ $output .= '<div id="views-ajax-form">';
+ $output .= '<div id="views-ajax-title"></div>';
$output .= '<div id="views-ajax-pad">';
$output .= $message;
$output .= '</div>';
+ $output .= '</div>';
// Render the actual form here
$output .= $save_button;
@@ -307,25 +309,42 @@ function views_ui_display_tab($view, &$display) {
// If this is the default display, add some basic stuff here.
if ($display->id == 'default') {
$tag = empty($view->tag) ? t('None') : $view->tag;
- $left .= '<dt>' . t('View tag: !tag', array('!tag' => l($tag, "admin/build/views/nojs/details/$view->name", array('attributes' => array('class' => 'views-ajax-link'))))) . '</dt>';
+ $left .= '<dt>' . t('View settings') . '</dt>';
+ $left .= '<dd class="views-item-details">' . t('Tag') . ': ' . l($tag, "admin/build/views/nojs/details/$view->name", array('attributes' => array('class' => 'views-ajax-link'))) . '</dd>';
}
- $options = $display->handler->options_summary();
- if (!empty($options)) {
- if (!is_array($options)) {
- $left .= '<dt>' . $options . '</dt>';
+ $options = $categories = array();
+ $display->handler->options_summary($categories, $options);
+
+ // Build all of the options we were returned and put them into the
+ // category data fields.
+ foreach ($options as $id => $option) {
+ if (empty($categories[$option['category']]['data'])) {
+ $categories[$option['category']]['data'] = array();
}
- else {
- foreach ($options as $term => $definition) {
- // numeric terms mean they were just appended so use the def
- // for the dt.
- if (is_numeric($term)) {
- $left .= '<dt>' . $definition . '</dt>';
- }
- else {
- $left .= '<dt>' . $term . '</dt>';
- $left .= '<dd>' . $definition . '</dd>';
- }
+ $data = &$categories[$option['category']]['data'];
+ $data[$id] = '';
+
+ // If there are optional links, build them first so they float properly.
+ if (!empty($option['links'])) {
+ $links = array();
+ foreach ($option['links'] as $link_id => $link_value) {
+ $links[] = $display->handler->option_link($link_value, $link_id, 'views-button-configure');
+ }
+ $data[$id] .= implode(' ', $links);
+ }
+ if (!empty($option['title'])) {
+ $data[$id] .= $option['title'] . ': ';
+ }
+ $data[$id] .= $display->handler->option_link($option['value'], $id);
+ }
+
+ // Once the data is built up, display the categories.
+ foreach ($categories as $id => $category) {
+ $left .= '<dt class="views-category-' . $id . '">' . $category['title'] . '</dt>';
+ if (!empty($category['data'])) {
+ foreach ($category['data'] as $cid => $cdata) {
+ $left .= '<dd class="views-item-' . $cid . '">' . $cdata . '</dd>';
}
}
}
@@ -477,7 +496,7 @@ function views_ui_add_display_form_submit($form, &$form_state) {
}
/**
- * AJAX callback to add a display.
+ * AJAX callback to remove a display.
*/
function views_ui_remove_display($js, $view, $display_id) {
if (!$js) {
@@ -492,7 +511,7 @@ function views_ui_remove_display($js, $view, $display_id) {
}
/**
- * Form to add a display to a view.
+ * Form to remove a display from a view.
*/
function views_ui_remove_display_form(&$form_state, $view, $display_id) {
if (empty($view->display[$display_id]->deleted)) {
@@ -531,7 +550,7 @@ function views_ui_remove_display_form(&$form_state, $view, $display_id) {
*/
function views_ui_remove_display_form_submit($form, &$form_state) {
// Create the new display
- $plugin = views_fetch_plugin_data('display', $form_state['view']->display[$id]->display_plugin);
+ $plugin = views_fetch_plugin_data('display', $form_state['view']->display[$form_state['display_id']]->display_plugin);
if (empty($plugin['no remove'])) {
$id = $form_state['display_id'];
$form_state['view']->display[$id]->deleted = TRUE;
@@ -577,6 +596,7 @@ function views_ui_edit_details($js, $view) {
* Form constructor callback to edit details of a view
*/
function views_ui_edit_details_form(&$form_state, $view) {
+ $form['#title'] = t('View details');
$form['description'] = array(
'#type' => 'textfield',
'#title' => t('View description'),
@@ -641,6 +661,8 @@ function views_ui_edit_display_form(&$form_state, $view, $display_id, $section)
$form_state['view'] = $view;
$form_state['display_id'] = $display_id;
$form_state['section'] = $section;
+
+ // Get form from the handler.
$display->handler->options_form($form, $form_state);
views_ui_standard_form_buttons($form, 'views_ui_edit_display_form');
return $form;
@@ -670,7 +692,7 @@ function views_ui_edit_display_form_submit($form, &$form_state) {
* Override handler for views_ui_edit_display_form
*/
function views_ui_edit_display_form_override($form, &$form_state) {
- $display = &$form_state['233view']->display[$form_state['display_id']];
+ $display = &$form_state['view']->display[$form_state['display_id']];
$display->handler->options_override($form, $form_state);
views_ui_cache_set($form_state['view']);
@@ -679,83 +701,447 @@ function views_ui_edit_display_form_override($form, &$form_state) {
}
/**
- * Page callback to rearrange a section.
+ * Page callback to rearrange a type.
*/
-function views_ui_rearrange_section($js, $view, $display_id, $section) {
+function views_ui_rearrange_type($js, $view, $display_id, $type) {
if (!$js) {
- $output = drupal_get_form('views_ui_rearrange_form', $view, $section, $display_id);
+ $output = drupal_get_form('views_ui_rearrange_form', $view, $type, $display_id);
return $output;
}
else {
views_include('ajax');
- $form_state = views_ajax_form('views_ui_rearrange_form', $view, $display_id, $section);
+ $form_state = views_ajax_form('views_ui_rearrange_form', $view, $display_id, $type);
+ // Sometimes we need to re-generate the form for multi-step type operations.
+ $object = NULL;
+ if (!empty($form_state['regenerate form'])) {
+ $object = views_render_ajax_form('views_ui_rearrange_form', $form_state['view'], $display_id, $type);
+ }
+
// regenerate the tabset, set it to replace
- return views_ui_regenerate_tabs($form_state['view'], $display_id);
+ return views_ui_regenerate_tabs($form_state['view'], $display_id, $object);
}
}
/**
* Form to rearrange items in the views UI.
*/
-function views_ui_rearrange_form(&$form_state, $view, $display_id, $section) {
- $form['#title'] = t('Rearrange @section', array('@section' => $section));
- $form['markup'] = array('#value' => '<p>' . t('rearrange form here') . '</p>');
+function views_ui_rearrange_form(&$form_state, $view, $display_id, $type) {
+ $types = views_object_types();
+ $form['#title'] = t('Rearrange @type', array('@type' => $types[$type]['title']));
+ $types = views_object_types();
+ $view->init_display($display_id);
+ $display = &$view->display[$display_id];
+
+ if ($display->handler->defaultable_sections($types[$type]['plural'])) {
+ $display->handler->add_override_button($form, $types[$type]['plural']);
+ $form_state['section'] = $types[$type]['plural'];
+ }
+
+ $count = 0;
+
+ foreach ($display->handler->get_option($types[$type]['plural']) as $id => $field) {
+ $form[$id] = array('#tree' => TRUE);
+ $form[$id]['weight'] = array(
+ '#type' => 'weight',
+ '#delta' => 10,
+ '#default_value' => ++$count,
+ );
+ $handler = views_get_handler($field->table, $field->field, $type);
+ if ($handler) {
+ $handler->init($view, $field);
+ $form[$id]['name'] = array(
+ '#value' => t('@group: @title', array('@group' => $handler->definition['group'], '@title' => $handler->definition['title'])) . ' ' . $handler->admin_summary(),
+ );
+ $form[$id]['removed'] = array(
+ '#type' => 'checkbox',
+ '#id' => 'views-removed-' . $id,
+ '#attributes' => array('class' => 'views-remove-checkbox'),
+ '#default_value' => 0,
+ );
+
+ }
+ else {
+ $form[$id]['name'] = array('#value' => t('Broken field @id', $id));
+ }
+ }
$form_state['view'] = $view;
+ $form_state['display_id'] = $display_id;
+ $form_state['type'] = $type;
+
+ // Add javascript settings that will be added via $.extend for tabledragging
+ $form['#js']['tableDrag']['arrange']['weight'][0] = array(
+ 'target' => 'weight',
+ 'source' => NULL,
+ 'relationship' => 'sibling',
+ 'action' => 'order',
+ 'hidden' => TRUE,
+ 'limit' => 0,
+ );
+
views_ui_standard_form_buttons($form, 'views_ui_rearrange_form');
return $form;
}
/**
+ * Turn the rearrange form into a proper table
+ */
+function theme_views_ui_rearrange_form($form) {
+ $rows = array();
+ foreach (element_children($form) as $id) {
+ if (isset($form[$id]['name'])) {
+ $row = array();
+ $row[] = drupal_render($form[$id]['name']);
+ $form[$id]['weight']['#attributes']['class'] = 'weight';
+ $row[] = drupal_render($form[$id]['weight']);
+ $row[] = drupal_render($form[$id]['removed']) . l('<span>' . t('Remove') . '</span>', 'javascript:void()', array('attributes' => array('id' => 'views-remove-link-' . $id, 'class' => 'views-button-remove views-remove-link', 'alt' => t('Remove this item'), 'title' => t('Remove this item')), 'html' => true));
+
+ $rows[] = array('data' => $row, 'class' => 'draggable', 'id' => 'views-row-' . $id);
+ }
+ }
+ if (empty($rows)) {
+ $rows[] = array(array('data' => t('No fields available.'), 'colspan' => '2'));
+ }
+
+ $header = array('', t('Weight'), t('Remove'));
+ drupal_add_tabledrag('arrange', 'order', 'sibling', 'weight');
+ $output = drupal_render($form['override']);
+ $output .= theme('table', $header, $rows, array('id' => 'arrange'));
+ $output .= drupal_render($form);
+ return $output;
+
+}
+
+/**
* Submit handler for rearranging form
*/
function views_ui_rearrange_form_submit($form, &$form_state) {
+ $types = views_object_types();
+ $display = &$form_state['view']->display[$form_state['display_id']];
+
+ $old_fields = $display->handler->get_option($types[$form_state['type']]['plural']);
+ $new_fields = $order = array();
+
+ // Make an array with the weights
+ foreach ($form_state['values'] as $field => $info) {
+ // add each value that is a field with a weight to our list, but only if
+ // it has had its 'removed' checkbox checked.
+ if (is_array($info) && isset($info['weight']) && empty($info['removed'])) {
+ $order[$field] = $info['weight'];
+ }
+ }
+
+ // Sort the array
+ asort($order);
+
+ // Create a new list of fields in the new order.
+ foreach (array_keys($order) as $field) {
+ $new_fields[$field] = $old_fields[$field];
+ }
+ $display->handler->set_option($types[$form_state['type']]['plural'], $new_fields);
+
+ // Store in cache
+ views_ui_cache_set($form_state['view']);
+
$form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
}
/**
- * Page callback to add_item a section.
+ * Page callback to add_item a type.
*/
-function views_ui_add_item($js, $view, $display_id, $section) {
+function views_ui_add_item($js, $view, $display_id, $type) {
if (!$js) {
- $output = drupal_get_form('views_ui_add_item_form', $view, $section, $display_id);
+ $output = drupal_get_form('views_ui_add_item_form', $view, $display_id, $type);
return $output;
}
else {
views_include('ajax');
- $form_state = views_ajax_form('views_ui_add_item_form', $view, $display_id, $section);
+ $form_state = views_ajax_form('views_ui_add_item_form', $view, $display_id, $type);
// regenerate the tabset, set it to replace
- return views_ui_regenerate_tabs($form_state['view'], $display_id);
+ if (!empty($form_state['id'])) {
+ $object = views_render_ajax_form('views_ui_config_item_form', $form_state['view'], $display_id, $type, $form_state['id']);
+ // This form is at a different URL than $_GET['q'] so we have to pass via the object.
+ $object->url = url("admin/build/views/ajax/config-item/$view->name/$display_id/$type/$form_state[id]");
+ }
+ return views_ui_regenerate_tabs($form_state['view'], $display_id, $object);
}
}
/**
* Form to add_item items in the views UI.
*/
-function views_ui_add_item_form(&$form_state, $view, $display_id, $section) {
+function views_ui_add_item_form(&$form_state, $view, $display_id, $type) {
$view->init_display($display_id);
$display = &$view->display[$display_id];
- $form_state['view'] = $view;
+ $types = views_object_types();
+ $form['#title'] = t('Add @type', array('@type' => $types[$type]['title']));
+
+ $form_state['view'] = &$view;
$form_state['display_id'] = $display_id;
- $form_state['section'] = $section;
-
- $form['name'] = array(
- '#prefix' => '<div class="views-radio-box">',
- '#suffix' => '</div>',
- '#type' => 'radios',
- '#title' => $section,
- '#options' => views_fetch_field_names($view->base_table, $section),
- );
-
- views_ui_standard_form_buttons($form, 'views_ui_edit_display_form', t('Add'));
+ $form_state['type'] = $type;
+
+ $options = views_fetch_field_names($view->base_table, $type);
+
+ if (!empty($options)) {
+ $form['name'] = array(
+ '#prefix' => '<div class="views-radio-box">',
+ '#suffix' => '</div>',
+ '#type' => 'checkboxes',
+ '#options' => $options,
+ );
+
+ views_ui_standard_form_buttons($form, 'views_ui_add_item_form', t('Add'));
+ }
+ else {
+ $form['markup'] = array(
+ '#value' => t('There are no @types available to add.', array('@types' => strtolower($types[$type]['title']))),
+ );
+ }
+
return $form;
}
/**
- * Submit handler for rearranging form
+ * Submit handler for adding new item(s) to a view.
*/
function views_ui_add_item_form_submit($form, &$form_state) {
+ $type = $form_state['type'];
+ $types = views_object_types();
+
+ // Loop through each of the items that were checked and add them to the view.
+ foreach (array_keys(array_filter($form_state['values']['name'])) as $field) {
+ list($table, $field) = explode('.', $field, 2);
+ $id = $form_state['view']->add_item($form_state['display_id'], $type, $table, $field);
+ if (empty($form_state['id'])) {
+ $form_state['id'] = $id;
+ }
+ }
+
+ // Store in cache
+ views_ui_cache_set($form_state['view']);
+
+ $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
+}
+
+/**
+ * Page callback to configure an item
+ */
+function views_ui_config_item($js, $view, $display_id, $type, $id) {
+ if (!$js) {
+ $output = drupal_get_form('views_ui_config_item_form', $view, $display_id, $type, $id);
+ return $output;
+ }
+ else {
+ views_include('ajax');
+ $form_state = views_ajax_form('views_ui_config_item_form', $view, $display_id, $type, $id);
+ // regenerate the tabset, set it to replace
+ return views_ui_regenerate_tabs($form_state['view'], $display_id);
+ }
+}
+
+/**
+ * Form to config_item items in the views UI.
+ */
+function views_ui_config_item_form(&$form_state, $view, $display_id, $type, $id) {
+ $form = array('options' => array('#tree' => TRUE));
+ $view->init_display($display_id);
+ $item = $view->get_item($display_id, $type, $id);
+
+ if ($item) {
+ $handler = views_get_handler($item->table, $item->field, $type);
+ if (empty($handler)) {
+ $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item->tablename, '@field' => $item->field)));
+ break;
+ }
+ $handler->init($view, $item);
+ $types = views_object_types();
+ $form['#title'] = t('Configure @type "@group: @title"', array('@type' => strtolower($types[$type]['stitle']), '@group' => $handler->definition['group'], '@title' => $handler->definition['title']));
+
+ // Get form from the handler.
+ $handler->options_form($form['options'], $form_state);
+ $form_state['view'] = &$view;
+ $form_state['display_id'] = $display_id;
+ $form_state['type'] = $type;
+ $form_state['id'] = $id;
+ $form_state['handler'] = &$handler;
+
+ views_ui_standard_form_buttons($form, 'views_ui_config_item_form');
+ }
+ return $form;
+}
+
+/**
+ * Submit handler for configing new item(s) to a view.
+ */
+function views_ui_config_item_form_validate($form, &$form_state) {
+ $form_state['handler']->options_validate($form['options'], $form_state);
+}
+
+/**
+ * Submit handler for configing new item(s) to a view.
+ */
+function views_ui_config_item_form_submit($form, &$form_state) {
+ // Run it through the handler's submit function.
+ $form_state['handler']->options_submit($form['options'], $form_state);
+ $item = $form_state['handler']->data;
+
+ // Store the data we're given.
+ foreach ($form_state['values']['options'] as $key => $value) {
+ $item->$key = $value;
+ }
+
+ // Store the item back on the view
+ $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
+
+ // Write to cache
+ views_ui_cache_set($form_state['view']);
+ $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
+}
+
+/**
+ * Page callback to change the summary style of an argument
+ */
+function views_ui_change_style($js, $view, $display_id, $type, $id) {
+ if (!$js) {
+ $output = drupal_get_form('views_ui_change_style_form', $view, $display_id, $type, $id);
+ return $output;
+ }
+ else {
+ views_include('ajax');
+ $form_state = views_ajax_form('views_ui_change_style_form', $view, $display_id, $type, $id);
+ // regenerate the tabset, set it to replace
+ return views_ui_regenerate_tabs($form_state['view'], $display_id);
+ }
+}
+
+/**
+ * Form to change_style items in the views UI.
+ */
+function views_ui_change_style_form(&$form_state, $view, $display_id, $type, $id) {
+ $form = array('options' => array('#tree' => TRUE));
+ $view->init_display($display_id);
+ $item = $view->get_item($display_id, $type, $id);
+
+ if ($item) {
+ $handler = views_get_handler($item->table, $item->field, $type);
+ if (empty($handler)) {
+ $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item->tablename, '@field' => $item->field)));
+ break;
+ }
+ $handler->init($view, $item);
+ $types = views_object_types();
+ $form['#title'] = t('Change summary style for @type "@group: @title"', array('@type' => strtolower($types[$type]['stitle']), '@group' => $handler->definition['group'], '@title' => $handler->definition['title']));
+
+ $form['style_plugin'] = array(
+ '#type' => 'radios',
+ '#options' => views_fetch_plugin_names('style', 'summary', TRUE),
+ '#default_value' => $item->style_plugin,
+ );
+
+ $form_state['view'] = &$view;
+ $form_state['display_id'] = $display_id;
+ $form_state['type'] = $type;
+ $form_state['id'] = $id;
+ $form_state['handler'] = &$handler;
+
+ views_ui_standard_form_buttons($form, 'views_ui_change_style_form');
+ }
+ return $form;
+}
+
+/**
+ * Submit handler for configing new item(s) to a view.
+ */
+function views_ui_change_style_form_submit($form, &$form_state) {
+ // Run it through the handler's submit function.
+ $form_state['handler']->options_submit($form['options'], $form_state);
+ $item = $form_state['handler']->data;
+
+ // Store the data we're given.
+ $item->style_plugin = $form_state['values']['style_plugin'];
+
+ // Store the item back on the view
+ $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
+
+ // Write to cache
+ views_ui_cache_set($form_state['view']);
+ $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
+}
+
+/**
+ * Page callback to config the summary style of an argument
+ */
+function views_ui_config_style($js, $view, $display_id, $type, $id) {
+ if (!$js) {
+ $output = drupal_get_form('views_ui_config_style_form', $view, $display_id, $type, $id);
+ return $output;
+ }
+ else {
+ views_include('ajax');
+ $form_state = views_ajax_form('views_ui_config_style_form', $view, $display_id, $type, $id);
+ // regenerate the tabset, set it to replace
+ return views_ui_regenerate_tabs($form_state['view'], $display_id);
+ }
+}
+
+/**
+ * Form to config_style items in the views UI.
+ */
+function views_ui_config_style_form(&$form_state, $view, $display_id, $type, $id) {
+ $form = array('options' => array('#tree' => TRUE));
+ $view->init_display($display_id);
+ $item = $view->get_item($display_id, $type, $id);
+
+ if ($item) {
+ $handler = views_get_handler($item->table, $item->field, $type);
+ if (empty($handler)) {
+ $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item->tablename, '@field' => $item->field)));
+ break;
+ }
+ $handler->init($view, $item);
+ $types = views_object_types();
+ $form['#title'] = t('Configure summary style for @type "@group: @title"', array('@type' => strtolower($types[$type]['stitle']), '@group' => $handler->definition['group'], '@title' => $handler->definition['title']));
+
+ $plugin = views_get_plugin('style', $item->style_plugin);
+ if ($plugin) {
+ $form['style_options'] = array(
+ '#tree' => TRUE,
+ );
+ $plugin->init($view, $view->display[$display_id]);
+ // Override the options since it thinks it's getting them from the display.
+ $plugin->options = $item->style_options;
+
+ $plugin->options_form($form['style_options'], $form_state);
+ }
+
+ $form_state['view'] = &$view;
+ $form_state['display_id'] = $display_id;
+ $form_state['type'] = $type;
+ $form_state['id'] = $id;
+ $form_state['handler'] = &$handler;
+
+ views_ui_standard_form_buttons($form, 'views_ui_config_style_form');
+ }
+ return $form;
+}
+
+/**
+ * Submit handler for configing new item(s) to a view.
+ */
+function views_ui_config_style_form_submit($form, &$form_state) {
+ // Run it through the handler's submit function.
+ $form_state['handler']->options_submit($form['style_options'], $form_state);
+ $item = $form_state['handler']->data;
+
+ // Store the data we're given.
+ $item->style_options = $form_state['values']['style_options'];
+
+ // Store the item back on the view
+ $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
+
+ // Write to cache
+ views_ui_cache_set($form_state['view']);
$form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name;
}
@@ -763,29 +1149,46 @@ function views_ui_add_item_form_submit($form, &$form_state) {
* Add information about a section to a display.
*/
function views_ui_add_info($type, $view, $display) {
+ $types = views_object_types();
+
$output = '';
+ $output .= l('<span>' . t('Rearrange') . '</span>', "admin/build/views/nojs/rearrange/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-button-rearrange views-ajax-link'), 'html' => true));
+ $output .= l('<span>' . t('Add') . '</span>', "admin/build/views/nojs/add-item/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-button-add views-ajax-link'), 'html' => true));
+
- foreach ($view->$type as $field) {
- $handler = views_get_handler($field->tablename, $field->field, $type);
+ $output .= '<dt>' . $types[$type]['title'] . '</dt>';
+ $fields = '';
+ foreach ($display->handler->get_option($types[$type]['plural']) as $field) {
+ $handler = views_get_handler($field->table, $field->field, $type);
if (empty($handler)) {
- $output .= t("Error: handler for @table > @field doesn't exist!", array('@table' => $field->tablename, '@field' => $field->field));
+ $output .= t("Error: handler for @table > @field doesn't exist!", array('@table' => $field->tablename, '@field' => $field->field)) . '<br/>';
continue;
}
- $output .= t('@group: @title', array('@group' => $handler->definition['group'], '@title' => $handler->definition['title'])) . '<br />';
- }
+ $handler->init($view, $field);
- if (empty($output)) {
- $output = '<p>' . t('None defined.') . '</p>';
- }
+ $f = t('@group: @title', array('@group' => $handler->definition['group'], '@title' => $handler->definition['title']));
+ $form = $form_state = array();
+ $handler->options_form($form, $form_state);
+ if (!empty($form)) {
+ $f = l($f, "admin/build/views/nojs/config-item/$view->name/$display->id/$type/$field->id", array('attributes' => array('class' => 'views-ajax-link')));
+ }
+ $fields .= '<dd class="views-item-' . $type . '-' . $field->id . '">' . $f . ' ' . $handler->admin_summary() . '</dt>';
- $links = "<div class=\"links\">";
- $links .= l(t('Add'), "admin/build/views/nojs/add-item/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-ajax-link')));
- $links .= " ยท ";
- $links .= l(t('Rearrange'), "admin/build/views/nojs/rearrange/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-ajax-link')));
- $links .= '</div>';
+ if ($handler->needs_style_plugin()) {
+ $style_plugin = views_fetch_plugin_data('style', $handler->data->style_plugin);
+ $style_title = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin['title'];
- return $links . '<dt>' . ucwords($type) . '</dt><dd>' . $output . '</dd>';
+ if (!empty($style_plugin['uses options'])) {
+ $fields .= l('<span>' . t('Settings') . '</span>', "admin/build/views/nojs/config-style/$view->name/$display->id/$type/$field->id", array('attributes' => array('class' => 'views-button-configure views-ajax-link'), 'html' => true));
+ }
+
+ $fields .= '<dd class="views-item-style-plugin">' . t(' &nbsp; Style: !style', array('!style' => l($style_title, "admin/build/views/nojs/change-style/$view->name/$display->id/$type/$field->id", array('attributes' => array('class' => 'views-ajax-link'))))) . '</dd>';
+ }
+ }
+
+ $output .= empty($fields) ? ('<dd>' . t('None defined.') . '</dd>') : $fields;
+ return $output;
}
/**
diff --git a/includes/ajax.inc b/includes/ajax.inc
index 88c7e67..10f559b 100644
--- a/includes/ajax.inc
+++ b/includes/ajax.inc
@@ -13,7 +13,7 @@
/**
* Simple render function to make sure output is what we want.
*/
-function views_ajax_render($output = NULL, $title = NULL, $url = NULL) {
+function views_ajax_render($output = NULL, $title = NULL, $url = NULL, $js = NULL) {
if (empty($output)) {
$output->display = t('Server reports invalid input error.');
$output->title = t('Error');
@@ -25,6 +25,10 @@ function views_ajax_render($output = NULL, $title = NULL, $url = NULL) {
$temp->url = $url;
$output = $temp;
}
+ if (!empty($js)) {
+ $output->js = $js;
+ }
+
drupal_set_header('Content-Type: text/javascript; charset=utf-8');
print drupal_to_js($output);
exit;
@@ -89,7 +93,9 @@ function views_ajax_form($form_id) {
$output .= drupal_render_form($form_id, $form);
$title = empty($form['#title']) ? '' : $form['#title'];
$url = empty($form['#url']) ? url($_GET['q'], array('absolute' => TRUE)) : $form['#url'];
- views_ajax_render($output, $title, $url);
+ $js = empty($form['#js']) ? NULL : $form['#js'];
+
+ views_ajax_render($output, $title, $url, $js);
}
/**
diff --git a/includes/handlers.inc b/includes/handlers.inc
index 0e09cd5..96ada70 100644
--- a/includes/handlers.inc
+++ b/includes/handlers.inc
@@ -151,15 +151,6 @@ class views_handler extends views_object {
$this->view = &$view;
$this->data = &$data;
- // Mostly this exists to make things easier to reference. $this->options['...']
- // is a little easier than $this->data->options['...'];
- if (isset($data->options)) {
- $this->options = $data->options;
- }
- else {
- $this->options = array();
- }
-
// This exist on most handlers, but not all. So they are still optional.
if (isset($data->tablename)) {
$this->table = $data->tablename;
@@ -182,9 +173,14 @@ class views_handler extends views_object {
}
/**
+ * Provide defaults for the handler.
+ */
+ function options(&$option) { }
+
+ /**
* Provide a form for setting options.
*/
- function options_form(&$form) { }
+ function options_form(&$form, &$form_state) { }
/**
* Validate the options form.
@@ -214,6 +210,18 @@ class views_handler extends views_object {
}
return $this->table_alias;
}
+
+ /**
+ * Provide text for the administrative summary
+ */
+ function admin_summary() { }
+
+ /**
+ * Determine if the argument needs a style plugin.
+ *
+ * @return TRUE/FALSE
+ */
+ function needs_style_plugin() { return FALSE; }
}
/**
@@ -307,7 +315,12 @@ class views_handler_field_date extends views_handler_field {
parent::construct($click_sortable, $additional_fields);
}
- function options_form(&$form) {
+ function options(&$item) {
+ $item->date_format = 'small';
+ $item->custom_date_format = '';
+ }
+
+ function options_form(&$form, &$form_state) {
$form['date_format'] = array(
'#type' => 'select',
'#title' => t('Date format'),
@@ -318,21 +331,21 @@ class views_handler_field_date extends views_handler_field {
'custom' => t('Custom'),
'time ago' => t('Time ago'),
),
- '#default_value' => isset($this->options['date_format']) ? $this->options['date_format'] : 'small',
+ '#default_value' => isset($this->data->date_format) ? $this->data->date_format : 'small',
);
$form['custom_date_format'] = array(
'#type' => 'textfield',
'#title' => t('Custom date format'),
'#description' => t('If "Custom", see <a href="http://us.php.net/manual/en/function.date.php">the PHP docs</a> for date formats. If "Time ago" this is the the number of different units to display, which defaults to two.'),
- '#default_value' => isset($this->options['custom_date_format']) ? $this->options['custom_date_format'] : '',
+ '#default_value' => isset($this->data->custom_date_format) ? $this->data->custom_date_format : '',
);
}
function render($values) {
$value = $values->{$this->field_alias};
- $format = !empty($this->options['date_format']) ? $this->options['date_format'] : 'medium';
+ $format = $this->data->date_format;
if ($format == 'custom') {
- $custom_format = $this->options['custom_date_format'];
+ $custom_format = $this->custom_date_format;
}
switch ($format) {
@@ -359,40 +372,43 @@ class views_handler_field_boolean extends views_handler_field {
parent::construct($click_sortable, $additional_fields);
}
- function options_form(&$form) {
+ function options(&$item) {
+ $item->type = 'yes-no';
+ $item->not = FALSE;
+ }
+
+ function options_form(&$form, &$form_state) {
$form['type'] = array(
'#type' => 'select',
- '#title' => t('Date format'),
+ '#title' => t('Output format'),
'#options' => array(
'yes-no' => t('Yes/No'),
'true-false' => t('True/False'),
'on-off' => t('On/Off'),
),
- '#default_value' => isset($this->options['type']) ? $this->options['type'] : 'yes-no',
+ '#default_value' => $this->data->type,
);
$form['not'] = array(
'#type' => 'checkbox',
'#title' => t('Reverse'),
'#description' => t('If checked, true will be displayed as false.'),
- '#default_value' => !empty($this->options['not']),
+ '#default_value' => $this->data->not,
);
}
function render($values) {
$value = $values->{$this->field_alias};
- if (!empty($this->options['not'])) {
+ if (!empty($this->data->not)) {
$value = !$value;
}
- $format = isset($this->options['type']) ? $this->options['type'] : 'yes';
-
- switch ($format) {
+ switch ($this->data->type) {
case 'yes-no':
default:
return $value ? t('Yes') : t('No');
case 'true-false':
return $value ? t('True') : t('False');
- case 'yes-no':
+ case 'on-off':
return $value ? t('On') : t('Off');
}
}
@@ -447,6 +463,43 @@ class views_handler_sort extends views_handler {
// Add the field.
$this->query->add_orderby($this->table_alias, $this->real_field, $this->data->order);
}
+
+ /**
+ * Set defaults for new handler
+ */
+ function options(&$options) {
+ $options->order = 'ASC';
+ }
+
+ /**
+ * Display whether or not the sort order is ascending or descending
+ */
+ function admin_summary() {
+ switch ($this->data->order) {
+ case 'ASC':
+ case 'asc':
+ default:
+ $type = t('asc');
+ break;
+ case 'DESC';
+ case 'desc';
+ $type = t('desc');
+ break;
+ }
+ return '<span class="views-ascending"><span>' . $type . '</span></span>';
+ }
+
+ /**
+ * Basic options for all sort criteria
+ */
+ function options_form(&$form, &$form_state) {
+ $form['order'] = array(
+ '#type' => 'radios',
+ '#title' => t('Sort order'),
+ '#options' => array('ASC' => t('Ascending'), 'DESC' => t('Descending')),
+ '#default_value' => $this->data->order,
+ );
+ }
}
/**
@@ -503,9 +556,57 @@ class views_handler_sort_formula extends views_handler_sort {
*/
class views_handler_filter extends views_handler {
/**
+ * Provide a simple default initializer -- should be overridden.
+ */
+ function options(&$item) {
+ $item->operator = array('operator' => '=');
+ $item->value = array('value' => '');
+ }
+
+ function admin_summary() {
+ return check_plain($this->data->operator['operator']) . ' ' . check_plain($this->data->value['value']);
+ }
+
+ /**
+ * Provide the basic form which calls through to subforms.
+ * If overridden, it is best to call through to the parent.
+ */
+ function options_form(&$form, &$form_state) {
+ $form['operator'] = array(
+ '#prefix' => '<div class="views-left-30">',
+ '#suffix' => '</div>',
+ );
+
+ $this->operator_form($form['operator'], $form_state);
+
+ $form['value'] = array(
+ '#prefix' => '<div class="views-left-50">',
+ '#suffix' => '</div>',
+ );
+
+ $this->value_form($form['value'], $form_state);
+ }
+
+ /**
+ * Simple validate handler
+ */
+ function options_validate(&$form, &$form_state) {
+ $this->operator_validate($form['operator'], $form_state);
+ $this->value_validate($form['value'], $form_state);
+ }
+
+ /**
+ * Simple submit handler
+ */
+ function options_submit(&$form, &$form_state) {
+ $this->operator_submit($form['operator'], $form_state);
+ $this->value_submit($form['value'], $form_state);
+ }
+
+ /**
* Provide a form for setting the operator.
*/
- function operator_form(&$form) { }
+ function operator_form(&$form, &$form_state) { }
/**
* Validate the operator form.
@@ -521,7 +622,7 @@ class views_handler_filter extends views_handler {
/**
* Provide a form for setting options.
*/
- function value_form(&$form) { }
+ function value_form(&$form, &$form_state) { }
/**
* Validate the options form.
@@ -536,10 +637,42 @@ class views_handler_filter extends views_handler {
/**
* Add this filter to the query.
+ *
+ * Due to the nature of fapi, the value and the operator have an unintended
+ * level of indirection. You will find them in $this->data->operator['operator']
+ * and $this->data->value['value'] respectively.
*/
function query() {
$this->ensure_my_table();
- $this->query->add_where($this->data->group, "$this->table_alias.$this->real_field " . $this->data->operator . " '%s'", $this->data->value);
+ $this->query->add_where($this->data->group, "$this->table_alias.$this->real_field " . $this->data->operator['operator'] . " '%s'", $this->data->value['value']);
+ }
+}
+
+/**
+ * Simple filter to handle equal to / not equal to filters
+ */
+class views_handler_filter_equality extends views_handler_filter {
+ /**
+ * Provide simple equality operator
+ */
+ function operator_form(&$form, &$form_state) {
+ $form['operator'] = array(
+ '#type' => 'radios',
+ '#title' => t('Operator'),
+ '#default_value' => $this->data->operator['operator'],
+ '#options' => array(
+ '=' => t('Is equal to'),
+ '!=' => t('Is not equal to'),
+ ),
+ );
+ }
+
+ function value_form(&$form, &$form_state) {
+ $form['value'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Value'),
+ '#default_value' => $this->data->value['value'],
+ );
}
}
@@ -566,6 +699,191 @@ class views_handler_argument extends views_handler {
}
/**
+ * Provide defaults for the argument when a new one is created.
+ */
+ function options(&$item) {
+ $item->default_action = 'ignore';
+ $item->style_plugin = 'default_summary';
+ $item->style_options = array();
+ $item->wildcard = 'all';
+ $item->wildcard_substitution = t('All');
+ }
+
+ /**
+ * Provide a default options form for the argument.
+ */
+ function options_form(&$form, &$form_state) {
+ $defaults = $this->default_actions();
+ foreach ($defaults as $id => $info) {
+ $options[$id] = $info['title'];
+ }
+ $form['default_action'] = array(
+ '#prefix' => '<div class="views-left-50">',
+ '#suffix' => '</div>',
+ '#type' => 'radios',
+ '#title' => t('Action to take if argument is not present'),
+ '#options' => $options,
+ '#default_value' => $this->data->default_action,
+ );
+ $form['wildcard'] = array(
+ '#prefix' => '<div class="views-left-40">',
+ // prefix and no suffix means these two items will be grouped together.
+ '#type' => 'textfield',
+ '#title' => t('Wildcard'),
+ '#size' => 20,
+ '#default_value' => $this->data->wildcard,
+ '#description' => t('If this value is received as an argument, the argument will be ignored; i.e, "all values"'),
+ );
+ $form['wildcard_substitution'] = array(
+ '#suffix' => '</div>',
+ '#type' => 'textfield',
+ '#title' => t('Wildcard title'),
+ '#size' => 20,
+ '#default_value' => $this->data->wildcard_substitution,
+ '#description' => t('The title to use for the wildcard in substitutions elsewhere.'),
+ );
+ }
+
+ /**
+ * Provide a list of default behaviors for this argument if the argument
+ * is not present.
+ *
+ * Override this method to provide additional (or fewer) default behaviors.
+ */
+ function default_actions($which = NULL) {
+ $defaults = array(
+ 'ignore' => array(
+ 'title' => t('Display all values'),
+ 'method' => 'default_ignore',
+ ),
+ 'not found' => array(
+ 'title' => t('Display page not found'),
+ 'method' => 'default_not_found',
+ ),
+ 'empty' => array(
+ 'title' => t('Display empty text'),
+ 'method' => 'default_empty',
+ ),
+ 'summary asc' => array(
+ 'title' => t('Summary, sorted ascending'),
+ 'method' => 'default_summary',
+ 'method args' => array('asc'),
+ 'style plugin' => TRUE,
+ ),
+ 'summary desc' => array(
+ 'title' => t('Summary, sorted descending'),
+ 'method' => 'default_summary',
+ 'method args' => array('desc'),
+ 'style plugin' => TRUE,
+ ),
+ );
+
+ if ($which) {
+ if (!empty($defaults[$which])) {
+ return $defaults[$which];
+ }
+ }
+ else {
+ return $defaults;
+ }
+ }
+
+ /**
+ * Determine if the argument needs a style plugin.
+ *
+ * @return TRUE/FALSE
+ */
+ function needs_style_plugin() {
+ $info = $this->default_actions($this->data->default_action);
+ return !empty($info['style plugin']);
+ }
+
+ /**
+ * Handle the default action, which means our argument wasn't present.
+ *
+ * Override this method only with extreme care.
+ *
+ * @return
+ * A boolean value; if TRUE, continue building this view. If FALSE,
+ * building the view will be aborted here.
+ */
+ function default_action() {
+ $info = $this->default_actions($this->data->default_action);
+ if (!$info) {
+ return FALSE;
+ }
+
+ if (!empty($info['method args'])) {
+ return call_user_func_array(array($this, $info['method']), $info['method args']);
+ }
+ else {
+ return $this->{$info['method']};
+ }
+ }
+
+ /**
+ * Default action: ignore.
+ *
+ * If an argument was expected and was not given, in this case, simply
+ * ignore the argument entirely.
+ */
+ function default_ignore() {
+ return TRUE;
+ }
+
+ /**
+ * Default action: not found.
+ *
+ * If an argument was expected and was not given, in this case, report
+ * the view as 'not found' or hide it.
+ */
+ function default_not_found() {
+ // Set a failure condition and let the display manager handle it.
+ $this->view->build_info['fail'] = TRUE;
+ return FALSE;
+ }
+
+ /**
+ * Default action: empty
+ *
+ * If an argument was expected and was not given, in this case, display
+ * the view's empty text
+ */
+ function default_empty() {
+ // We return with no query; this will force the empty text.
+ $this->view->built = TRUE;
+ return FALSE;
+ }
+
+ /**
+ * Default action: summary.
+ *
+ * If an argument was expected and was not given, in this case, display
+ * a summary query.
+ */
+ function default_summary($order) {
+ $this->view->build_info['summary'] = TRUE;
+ $this->view->build_info['summary_level'] = $this->data->position;
+
+ // Change the display style to the summary style for this
+ // argument.
+ $this->view->style_plugin = $this->style_plugin;
+ $this->view->style_options = $this->style_options;
+
+ // Clear out the normal primary field and whatever else may have
+ // been added and let the summary do the work.
+ $this->query->clear_fields();
+ $this->summary_query();
+
+ $argument->handler->summary_sort($order);
+
+ // Summaries have their own sorting and fields, so tell the View not
+ // to build these.
+ $this->view->build_sort = $this->view->build_fields = FALSE;
+ return TRUE;
+ }
+
+ /**
* Build the info for the summary query.
*
* This must:
@@ -645,86 +963,6 @@ class views_handler_argument extends views_handler {
function summary_name($data) {
return check_plain($data->{$this->name_alias});
}
- /**
- * Provide a list of default behaviors for this argument if the argument
- * is not present.
- *
- * Override this method to provide additional (or fewer) default behaviors.
- */
- function defaults() {
- return array(
- 'ignore' => t('Display all values'),
- 'not found' => t('Display page not found'),
- 'empty' => t('Display empty text'),
- 'summary asc' => t('Summary, sorted ascending'),
- 'summary desc' => t('Summary, sorted descending'),
- );
- }
-
- /**
- * Handle the default action, which means our argument wasn't present.
- *
- * Override this method only with extreme care.
- *
- * @return
- * A boolean value; if TRUE, continue building this view. If FALSE,
- * building the view will be aborted here.
- */
- function default_action() {
- $action = $this->data->default_action;
- switch ($action) {
- default:
- case 'ignore':
- // Do nothing at all.
- return TRUE;
- case 'not found':
- // Set a failure condition and let the display manager handle it.
- $this->view->build_info['fail'] = TRUE;
- return FALSE;
- case 'empty':
- // We return with no query; this will force the empty text.
- $this->view->built = TRUE;
- return FALSE;
- case 'summary':
- case 'summary asc':
- case 'summary desc':
- $this->view->build_info['summary'] = TRUE;
- $this->view->build_info['summary_level'] = $this->data->position;
-
- // Change the display style to the summary style for this
- // argument.
- $this->view->style_plugin = isset($this->options['style_plugin']) ? $this->options['style_plugin'] : 'default_summary';
-
- // Give it the style's options, too.
- // @todo
-
-
- // Clear out the normal primary field and whatever else may have
- // been added and let the summary do the work.
- $this->query->clear_fields();
- $this->summary_query();
-
- // Allow the new style to add additional fields if it wants.
- // @todo
-
- // Cut 'summary' out of our action to see how, if at all, we should
- // sort.
- $order = trim(str_replace($action, 'summary', ''));
- if ($order) {
- $argument->handler->summary_sort($order);
- }
-
- // DISTINCT can cause the summaries to fail.
- // @todo: This may not be true anymore.
-// $this->query->no_distinct = TRUE;
-
-
- // Summaries have their own sorting and fields, so tell the View not
- // to build these.
- $this->view->build_sort = $this->view->build_fields = FALSE;
- return TRUE;
- }
- }
/**
* Set up the query for this argument.
@@ -792,86 +1030,5 @@ class views_handler_argument_formula extends views_handler_argument {
}
/**
- * Argument handler for a year (CCYY)
- */
-class views_handler_argument_date_year extends views_handler_argument_formula {
- /**
- * Constructor implementation
- */
- function construct() {
- $timezone = views_get_timezone();
- $this->formula = "YEAR(FROM_UNIXTIME(node.created+$timezone))";
- }
-
- /**
- * Provide a link to the next level of the view
- */
- function summary_link($data, $url) {
- $value = $data->{$this->base_alias};
- return l($value, "$url/$value");
- }
-}
-
-/**
- * Argument handler for a year plus month (CCYYMM)
- */
-class views_handler_argument_date_year_month extends views_handler_argument_formula {
- /**
- * Constructor implementation
- */
- function construct() {
- $timezone = views_get_timezone();
- $this->formula = "DATE_FORMAT(FROM_UNIXTIME(node.created+$timezone), '%Y%m')";
- $this->format = 'F, Y';
- }
-
- /**
- * Provide a link to the next level of the view
- */
- function summary_link($data, $url) {
- $value = $data->{$this->base_alias};
- $created = $data->{$this->name_alias};
- return l(format_date($created, 'custom', $this->format), "$url/$value");
- }
-
- /**
- * Provide a link to the next level of the view
- */
- function title($data, $url) {
- return format_date(strtotime($this->argument . "15"), 'custom', $this->format, 0);
- }
-}
-
-/**
- * Argument handler for a month (MM)
- */
-class views_handler_argument_date_month extends views_handler_argument_formula {
- /**
- * Constructor implementation
- */
- function construct() {
- $timezone = views_get_timezone();
- $this->formula = "MONTH(FROM_UNIXTIME(node.created+$timezone))";
- $this->format = 'F';
- }
-
- /**
- * Provide a link to the next level of the view
- */
- function summary_link($data, $url) {
- $value = $data->{$this->base_alias};
- $created = $data->{$this->name_alias};
- return l(format_date($created, 'custom', $this->format), "$url/$value");
- }
-
- /**
- * Provide a link to the next level of the view
- */
- function title($data, $url) {
- return format_date(strtotime("2005" . $this->argument . "15"), 'custom', $this->format, 0);
- }
-}
-
-/**
* @}
*/
diff --git a/includes/plugins.inc b/includes/plugins.inc
index acb1e6f..afddb8d 100644
--- a/includes/plugins.inc
+++ b/includes/plugins.inc
@@ -19,7 +19,7 @@ function views_views_plugins() {
'handler' => 'views_display_plugin_default',
'no ui' => TRUE,
'no remove' => TRUE,
- 'js' => array('misc/collapse.js', 'misc/textarea.js'),
+ 'js' => array('misc/collapse.js', 'misc/textarea.js', 'misc/tabledrag.js'),
),
'page' => array(
'title' => t('Page'),
@@ -72,7 +72,6 @@ function views_views_plugins() {
'handler' => 'views_style_plugin_summary',
'theme' => 'views_view_summary',
'summary' => TRUE, // only shows up as a summary style
- 'uses row plugin' => TRUE,
'uses options' => TRUE,
),
),
@@ -191,7 +190,9 @@ class views_display_plugin extends views_object {
'style_options' => array('style_plugin', 'style_options', 'row_plugin', 'row_options'),
'row_plugin' => array('style_plugin', 'style_options', 'row_plugin', 'row_options'),
'row_options' => array('style_plugin', 'style_options', 'row_plugin', 'row_options'),
+
// These guys are special
+ 'relationships' => array('relationships'),
'fields' => array('fields'),
'sorts' => array('sorts'),
'arguments' => array('arguments'),
@@ -241,11 +242,18 @@ class views_display_plugin extends views_object {
'row_plugin' => TRUE,
'row_options' => TRUE,
+ 'relationships' => TRUE,
'fields' => TRUE,
'sorts' => TRUE,
'arguments' => TRUE,
'filters' => TRUE,
);
+
+ $display->display_options['relationships'] = array();
+ $display->display_options['fields'] = array();
+ $display->display_options['sorts'] = array();
+ $display->display_options['arguments'] = array();
+ $display->display_options['filters'] = array();
}
/**
@@ -278,8 +286,12 @@ class views_display_plugin extends views_object {
* Because forms may be split up into sections, this provides
* an easy URL to exactly the right section. Don't override this.
*/
- function option_link($text, $section) {
- return l($text, 'admin/build/views/nojs/display/' . $this->view->name . '/' . $this->display->id . '/' . $section, array('attributes' => array('class' => 'views-ajax-link')));
+ function option_link($text, $section, $class = '') {
+ if (!empty($class)) {
+ $text = '<span>' . $text . '</span>';
+ }
+
+ return l($text, 'admin/build/views/nojs/display/' . $this->view->name . '/' . $this->display->id . '/' . $section, array('attributes' => array('class' => 'views-ajax-link ' . $class), 'html' => TRUE));
}
/**
@@ -287,36 +299,57 @@ class views_display_plugin extends views_object {
*
* This output is returned as an array.
*/
- function options_summary() {
- $output = array();
- $output[] = t('Name: !field', array('!field' => $this->option_link($this->display->display_title, 'display_title')));
+ function options_summary(&$categories, &$options) {
+ $categories['basic'] = array(
+ 'title' => t('Basic settings'),
+ );
+
+ $options['display_title'] = array(
+ 'category' => 'basic',
+ 'title' => t('Name'),
+ 'value' => $this->display->display_title,
+ );
$title = $this->get_option('title');
if (!$title) {
$title = t('None');
}
- $output[] = t('Title: !field', array('!field' => $this->option_link($title, 'title')));
+
+ $options['title'] = array(
+ 'category' => 'basic',
+ 'title' => t('Title'),
+ 'value' => $title,
+ );
$style_plugin = views_fetch_plugin_data('style', $this->get_option('style_plugin'));
$style_title = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin['title'];
$style = '';
+
+ $options['style_plugin'] = array(
+ 'category' => 'basic',
+ 'title' => t('Style'),
+ 'value' => $style_title,
+ );
+
+ // This adds a 'Settings' link to the style_options setting if the style has options.
if (!empty($style_plugin['uses options'])) {
- $style = '<div class="links">' . $this->option_link(t('Settings'), 'style_options') . '</div>';
+ $options['style_plugin']['links']['style_options'] = t('Settings');
}
- $output[] = $style . t('Style: !field', array('!field' => $this->option_link($style_title, 'style_plugin'), ));
-
if (!empty($style_plugin['uses row plugin'])) {
$row_plugin = views_fetch_plugin_data('row', $this->get_option('row_plugin'));
$row_title = empty($row_plugin['title']) ? t('Missing style plugin') : $row_plugin['title'];
- $row = '';
+ $options['row_plugin'] = array(
+ 'category' => 'basic',
+ 'title' => t('Row style'),
+ 'value' => $row_title,
+ );
+ // This adds a 'Settings' link to the row_options setting if the row style has options.
if (!empty($row_plugin['uses options'])) {
- $row = '<div class="links">' . $this->option_link(t('Settings'), 'row_options') . '</div>';
+ $options['row_plugin']['links']['row_options'] = t('Settings');
}
-
- $output[] = $row . t('Row style: !field', array('!field' => $this->option_link($row_title, 'row_plugin')));
}
$access = $this->get_option('access');
@@ -343,7 +376,12 @@ class views_display_plugin extends views_object {
}
break;
}
- $output[] = t('Access: !field', array('!field' => $this->option_link($access_str, 'access')));
+
+ $options['access'] = array(
+ 'category' => 'basic',
+ 'title' => t('Access'),
+ 'value' => $access_str,
+ );
foreach (array('header' => t('Header'), 'footer' => t('Footer'), 'empty' => t('Empty text')) as $type => $name) {
if (!$this->get_option($type)) {
@@ -361,9 +399,12 @@ class views_display_plugin extends views_object {
}
$output[] = t('!name: !field', array('!name' => $name, '!field' => $this->option_link($field, $type)));
+ $options[$type] = array(
+ 'category' => 'basic',
+ 'title' => $name,
+ 'value' => $field,
+ );
}
-
- return $output;
}
/**
@@ -373,25 +414,27 @@ class views_display_plugin extends views_object {
if ($this->defaultable_sections($form_state['section'])) {
$this->add_override_button($form, $form_state['section']);
}
+ $form['#title'] = check_plain($this->display->display_title) . ': ';
switch ($form_state['section']) {
case 'display_title':
+ $form['#title'] .= t('The name of this display');
$form['display_title'] = array(
'#type' => 'textfield',
- '#title' => t('The name of this display'),
'#description' => t('This title will appear only in the administrative interface for the View.'),
'#default_value' => $this->display->display_title,
);
break;
case 'title':
+ $form['#title'] .= t('The title of this view');
$form['title'] = array(
'#type' => 'textfield',
- '#title' => t('The title of this view'),
'#description' => t('This title will be displayed with the view, wherever titles are normally displayed; i.e, as the page title, block title, etc.'),
'#default_value' => $this->get_option('title'),
);
break;
case 'access':
+ $form['#title'] .= t('Access restrictions');
$form['access'] = array(
'#prefix' => '<div class="clear-block">',
'#suffix' => '</div>',
@@ -438,6 +481,7 @@ class views_display_plugin extends views_object {
);
break;
case 'header':
+ $form['#title'] .= t('Header');
$form['header_empty'] = array(
'#type' => 'checkbox',
'#title' => t('Display even if view has no result'),
@@ -445,7 +489,6 @@ class views_display_plugin extends views_object {
);
$form['header'] = array(
'#type' => 'textarea',
- '#title' => t('Header'),
'#default_value' => $this->get_option('header'),
'#rows' => 6,
'#description' => t('Text to display at the top of the view. May contain an explanation or links or whatever you like. Optional.'),
@@ -454,6 +497,7 @@ class views_display_plugin extends views_object {
$form['header_format'] = filter_form($this->get_option('header_format'), NULL, array('header_format'));
break;
case 'footer':
+ $form['#title'] .= t('Footer');
$form['footer_empty'] = array(
'#type' => 'checkbox',
'#title' => t('Display even if view has no result'),
@@ -461,7 +505,6 @@ class views_display_plugin extends views_object {
);
$form['footer'] = array(
'#type' => 'textarea',
- '#title' => t('Footer'),
'#default_value' => $this->get_option('footer'),
'#rows' => 6,
'#description' => t('Text to display beneath the view. May contain an explanation or links or whatever you like. Optional.'),
@@ -470,9 +513,9 @@ class views_display_plugin extends views_object {
$form['footer_format'] = filter_form($this->get_option('footer_format'), NULL, array('footer_format'));
break;
case 'empty':
+ $form['#title'] .= t('Empty text');
$form['empty'] = array(
'#type' => 'textarea',
- '#title' => t('Empty'),
'#default_value' => $this->get_option('empty'),
'#rows' => 6,
'#description' => t('Text to display if the view has no results. Optional.'),
@@ -481,29 +524,33 @@ class views_display_plugin extends views_object {
$form['empty_format'] = filter_form($this->get_option('empty_format'), NULL, array('empty_format'));
break;
case 'style_plugin':
+ $form['#title'] .= t('How should this view be styled');
$form['style_plugin'] = array(
- '#title' => t('How should this view be styled'),
'#type' => 'radios',
'#options' => views_fetch_plugin_names('style', 'summary', FALSE),
'#default_value' => $this->get_option('style_plugin'),
);
break;
case 'style_options':
+ $form['#title'] .= t('Style options');
$style = TRUE;
case 'row_options':
// if row, $style will be empty.
+ if (empty($style)) {
+ $form['#title'] .= t('Row style options');
+ }
$plugin = views_get_plugin(empty($style) ? 'row' : 'style', $this->get_option('style_plugin'));
if ($plugin) {
$form[$form_state['section']] = array(
'#tree' => TRUE,
);
$plugin->init($this->view, $this);
- $plugin->options_form($form[$form_state['section']]);
+ $plugin->options_form($form[$form_state['section']], $form_state);
}
break;
case 'row_plugin':
+ $form['#title'] .= t('How should each row in this view be styled');
$form['row_plugin'] = array(
- '#title' => t('How should each row in this view be styled'),
'#type' => 'radios',
'#options' => views_fetch_plugin_names('row', 'summary', FALSE),
'#default_value' => $this->get_option('row_plugin'),
@@ -733,7 +780,13 @@ class views_display_plugin_default extends views_display_plugin {
$display->display_options['style_options'] = array();
$display->display_options['row_plugin'] = 'fields';
$display->display_options['row_options'] = array();
+ $display->display_options['relationships'] = array();
+ $display->display_options['fields'] = array();
+ $display->display_options['sorts'] = array();
+ $display->display_options['arguments'] = array();
+ $display->display_options['filters'] = array();
}
+
/**
* The default execute handler fully renders the view.
*
@@ -776,11 +829,11 @@ class views_display_plugin_page extends views_display_plugin {
$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);
+ $path = str_replace('%', '%views_arg', $this->get_option('path'));
// 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(
+ $items[$path] = array(
// default views page entry
'page callback' => 'views_page',
'page arguments' => array($this->view->name, $this->display->id),
@@ -809,6 +862,90 @@ class views_display_plugin_page extends views_display_plugin {
drupal_set_title(filter_xss_admin($this->view->get_title('page')));
return $this->view->render();
}
+
+ /**
+ * Provide the summary for page options in the views UI.
+ *
+ * This output is returned as an array.
+ */
+ function options_summary(&$categories, &$options) {
+ // It is very important to call the parent function here:
+ parent::options_summary($categories, $options);
+
+ $categories['page'] = array(
+ 'title' => t('Page settings'),
+ );
+
+ $path = $this->get_option('path');
+ if (empty($path)) {
+ $path = t('None');
+ }
+
+ if (strlen($path) > 16) {
+ $path = substr($path, 0, 16) . '...';
+ }
+
+ $options['path'] = array(
+ 'category' => 'page',
+ 'title' => t('Path'),
+ 'value' => $path,
+ );
+
+ $options['menu'] = array(
+ 'category' => 'page',
+ 'title' => t('Menu'),
+ 'value' => 'TODO',
+ );
+ }
+
+ /**
+ * Provide the default form for setting options.
+ */
+ function options_form(&$form, &$form_state) {
+ // It is very important to call the parent function here:
+ parent::options_form($form, $form_state);
+
+ switch ($form_state['section']) {
+ case 'path':
+ $form['#title'] .= t('The menu path or URL of this view');
+ $form['path'] = array(
+ '#type' => 'textfield',
+ '#description' => t('This view will be displayed by visiting this path on your site.'),
+ '#default_value' => block_description,
+ );
+ break;
+ }
+ }
+
+ /**
+ * Validate the options form.
+ */
+ function options_validate($form, &$form_state) {
+ // It is very important to call the parent function here:
+ parent::options_validate($form, $form_state);
+
+ switch ($form_state['section']) {
+ case 'path':
+ // @todo: validate the path against other views
+
+ // @todo: validate the path against aliases.
+ break;
+ }
+ }
+
+ /**
+ * Perform any necessary changes to the form values prior to storage.
+ * There is no need for this function to actually store the data.
+ */
+ function options_submit($form, &$form_state) {
+ // It is very important to call the parent function here:
+ parent::options_submit($form, $form_state);
+ switch ($form_state['section']) {
+ case 'path':
+ $this->set_option('path', $form_state['values']['path']);
+ break;
+ }
+ }
}
/**
@@ -823,7 +960,7 @@ class views_display_plugin_block extends views_display_plugin {
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));
+ return array($delta => array('info' => $this->get_option('block_description')));
}
}
@@ -834,9 +971,87 @@ class views_display_plugin_block extends views_display_plugin {
// 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'));
+ $info['subject'] = filter_xss_admin($this->view->get_title());
return $info;
}
+
+ /**
+ * Provide the summary for page options in the views UI.
+ *
+ * This output is returned as an array.
+ */
+ function options_summary(&$categories, &$options) {
+ // It is very important to call the parent function here:
+ parent::options_summary($categories, $options);
+
+ $categories['block'] = array(
+ 'title' => t('Block settings'),
+ );
+
+ $block_description = $this->get_option('block_description');
+ if (empty($block_description)) {
+ $block_description = t('None');
+ }
+
+ if (strlen($block_description) > 16) {
+ $block_description = substr($block_description, 0, 16) . '...';
+ }
+
+ $options['block_description'] = array(
+ 'category' => 'block',
+ 'title' => t('Admin'),
+ 'value' => $block_description,
+ );
+ }
+
+ /**
+ * Provide the default form for setting options.
+ */
+ function options_form(&$form, &$form_state) {
+ // It is very important to call the parent function here:
+ parent::options_form($form, $form_state);
+
+ switch ($form_state['section']) {
+ case 'block_description':
+ $form['#title'] .= t('Block admin description');
+ $form['block_description'] = array(
+ '#type' => 'textfield',
+ '#description' => t('This will appear as the name of this block in administer >> site building >> blocks.'),
+ '#default_value' => $this->get_option('block_description'),
+ );
+ break;
+ }
+ }
+
+ /**
+ * Validate the options form.
+ */
+ function options_validate($form, &$form_state) {
+ // It is very important to call the parent function here:
+ parent::options_validate($form, $form_state);
+
+ switch ($form_state['section']) {
+ case 'block_description':
+ // @todo: validate the block_description against other views
+
+ // @todo: validate the block_description against aliases.
+ break;
+ }
+ }
+
+ /**
+ * Perform any necessary changes to the form values prior to storage.
+ * There is no need for this function to actually store the data.
+ */
+ function options_submit($form, &$form_state) {
+ // It is very important to call the parent function here:
+ parent::options_submit($form, $form_state);
+ switch ($form_state['section']) {
+ case 'block_description':
+ $this->set_option('block_description', $form_state['values']['block_description']);
+ break;
+ }
+ }
}
/**
@@ -868,7 +1083,7 @@ class views_style_plugin extends views_object {
function init(&$view, &$display) {
$this->view = $view;
$this->display = $display;
- $this->options = $display->get_option('style_options');
+ $this->options = $display->handler->get_option('style_options');
if ($this->uses_row_plugin) {
$this->row_plugin = views_get_plugin('row', $display->get_options('row_plugin'));
@@ -889,7 +1104,7 @@ class views_style_plugin extends views_object {
/**
* Provide a form for setting options.
*/
- function options_form(&$form) { }
+ function options_form(&$form, &$form_state) { }
/**
* Validate the options form.
@@ -946,7 +1161,7 @@ class views_style_plugin_list extends views_style_plugin {
/**
* Render the given style.
*/
- function options_form(&$form) {
+ function options_form(&$form, &$form_state) {
$form['type'] = array(
'#type' => 'radios',
'#title' => t('List type'),
@@ -987,7 +1202,7 @@ class views_style_plugin_table extends views_style_plugin {
/**
* Render the given style.
*/
- function options_form(&$form) {
+ function options_form(&$form, &$form_state) {
$form['markup'] = array(
'#default_value' => 'ToDo',
);
@@ -1010,18 +1225,18 @@ class views_style_plugin_table extends views_style_plugin {
* The default style plugin for summaries.
*/
class views_style_plugin_summary extends views_style_plugin {
- function options_form(&$form) {
- // provide an option form to select from our list of node renderers
+ function options_form(&$form, &$form_state) {
+ $form['count'] = array(
+ '#type' => 'checkbox',
+ '#default_value' => !empty($this->options['count']),
+ '#title' => t('Display record count with link'),
+ );
}
/**
* Render the given style.
*/
function render() {
- if (empty($this->row_plugin)) {
- // @todo: Log some form of error here?
- return;
- }
// @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.
diff --git a/includes/view.inc b/includes/view.inc
index d027d61..8b42264 100644
--- a/includes/view.inc
+++ b/includes/view.inc
@@ -866,6 +866,69 @@ class views_db_object {
$this->display[$id] = $display;
return $id;
}
+ /**
+ * Add an item with a handler to the view.
+ *
+ * These items may be fields, filters, sort criteria, or arguments.
+ */
+ function add_item($display_id, $type, $table, $field) {
+ $types = views_object_types();
+ $this->init_display($display_id);
+
+ $fields = $this->display[$display_id]->handler->get_option($types[$type]['plural']);
+
+ $count = 0;
+ $id = $field;
+ while (!empty($fields[$id])) {
+ $id = $field . '_' . ++$count;
+ }
+ $object = new $types[$type]['object'];
+ $object->id = $id;
+ $object->table = $table;
+ $object->field = $field;
+
+ $handler = views_get_handler($table, $field, $type);
+ $handler->options($object);
+
+ $fields[$id] = $object;
+ $this->display[$display_id]->handler->set_option($types[$type]['plural'], $fields);
+
+ return $id;
+ }
+
+ /**
+ * Get the configuration of an item (field/sort/filter/etc) on a given
+ * display.
+ */
+ function get_item($display_id, $type, $id) {
+ // Get info about the types so we can get the right data.
+ $types = views_object_types();
+ // Initialize the display
+ $this->init_display($display_id);
+
+ // Get the existing configuration
+ $fields = $this->display[$display_id]->handler->get_option($types[$type]['plural']);
+
+ return isset($fields[$id]) ? $fields[$id] : NULL;
+ }
+
+ /**
+ * Get the configuration of an item (field/sort/filter/etc) on a given
+ * display.
+ */
+ function set_item($display_id, $type, $id, $item) {
+ // Get info about the types so we can get the right data.
+ $types = views_object_types();
+ // Initialize the display
+ $this->init_display($display_id);
+
+ // Get the existing configuration
+ $fields = $this->display[$display_id]->handler->get_option($types[$type]['plural']);
+ $fields[$id] = $item;
+
+ // Store.
+ $this->display[$display_id]->handler->set_option($types[$type]['plural'], $fields);
+ }
}
/**
diff --git a/js/ajax.js b/js/ajax.js
index f42a09c..eece897 100644
--- a/js/ajax.js
+++ b/js/ajax.js
@@ -32,6 +32,13 @@ Drupal.Views.Ajax.ajaxResponse = function(data) {
alert(data.debug);
}
+ // See if we have any settings to extend. Do this first so that behaviors
+ // can access the new settings easily.
+
+ if (data.js) {
+ $.extend(Drupal.settings, data.js);
+ }
+
// Check the 'display' for data.
if (data.display) {
Drupal.Views.Ajax.setForm(data.title, data.display);
@@ -89,8 +96,10 @@ Drupal.Views.Ajax.ajaxResponse = function(data) {
// Go through and add any requested tabs
if (data.tab) {
for (id in data.tab) {
+ console.log(data.tab[id]['title']);
$('#views-tabset').addTab(id, data.tab[id]['title'], 0);
$(id).html(data.tab[id]['body']);
+ $(id).addClass('views-tab');
Drupal.attachBehaviors(id);
// This is kind of annoying, but we have to actually to find where the new
@@ -141,6 +150,6 @@ Drupal.behaviors.ViewsAjaxLinks = function() {
});
return false;
- });
+ });
}
diff --git a/js/base.js b/js/base.js
index d4efb12..5ff918e 100644
--- a/js/base.js
+++ b/js/base.js
@@ -8,4 +8,13 @@ Drupal.behaviors.viewsTabs = function (context) {
$('#views-tabset:not(.views-processed)').addClass('views-processed').tabs({
selectedClass: 'active'
});
+
+ $('a.views-remove-link')
+ .addClass('views-processed')
+ .click(function() {
+ var id = $(this).attr('id').replace('views-remove-link-', '');
+ $('#views-row-' + id).hide();
+ $('#views-removed-' + id).attr('checked', true);
+ return false;
+ });
}
diff --git a/modules/node.views.inc b/modules/node.views.inc
index f04e844..95fa7f5 100644
--- a/modules/node.views.inc
+++ b/modules/node.views.inc
@@ -74,7 +74,7 @@ function node_views_data() {
),
// Information for accepting a nid as a filter
'filter' => array(
- 'handler' => 'views_handler_filter',
+ 'handler' => 'views_handler_filter_equality',
),
// Information for sorting on a nid.
'sort' => array(
@@ -222,7 +222,7 @@ class views_handler_field_node extends views_handler_field {
*/
function init(&$view, &$data) {
parent::init($view, $data);
- if (isset($data->options['link_to_node']) && $view->base_table != 'node') {
+ if (isset($data->data->link_to_node) && $view->base_table != 'node') {
$this->additional_fields[] = $nid;
$this->nid_field = 'node_nid';
}
@@ -234,16 +234,16 @@ class views_handler_field_node extends views_handler_field {
/**
* Provide link to node option
*/
- function options_form(&$form) {
+ function options_form(&$form, &$form_state) {
$form['link_to_node'] = array(
'#title' => t('Link this field to its node'),
'#type' => 'checkbox',
- '#default_value' => $this->data->options['link_to_node'],
+ '#default_value' => !empty($this->data->link_to_node),
);
}
function render_link($data, $values) {
- if (!empty($this->data->options['link_to_node'])) {
+ if (!empty($this->data->link_to_node)) {
return l($data, "node/" . $values->{$this->node_field}, array('html' => TRUE));
}
else {
@@ -324,6 +324,89 @@ class views_handler_argument_node_nid extends views_handler_argument {
}
}
+/**
+ * Argument handler for a year (CCYY)
+ */
+class views_handler_argument_node_date_year extends views_handler_argument_formula {
+ /**
+ * Constructor implementation
+ *
+ * @todo node.created should instead know about table aliases otherwise this
+ * will explode in relationships.
+ */
+ function construct() {
+ $timezone = views_get_timezone();
+ $this->formula = "YEAR(FROM_UNIXTIME(node.created+$timezone))";
+ }
+
+ /**
+ * Provide a link to the next level of the view
+ */
+ function summary_link($data, $url) {
+ $value = $data->{$this->base_alias};
+ return l($value, "$url/$value");
+ }
+}
+
+/**
+ * Argument handler for a year plus month (CCYYMM)
+ */
+class views_handler_argument_date_year_month extends views_handler_argument_formula {
+ /**
+ * Constructor implementation
+ */
+ function construct() {
+ $timezone = views_get_timezone();
+ $this->formula = "DATE_FORMAT(FROM_UNIXTIME(node.created+$timezone), '%Y%m')";
+ $this->format = 'F, Y';
+ }
+
+ /**
+ * Provide a link to the next level of the view
+ */
+ function summary_link($data, $url) {
+ $value = $data->{$this->base_alias};
+ $created = $data->{$this->name_alias};
+ return l(format_date($created, 'custom', $this->format), "$url/$value");
+ }
+
+ /**
+ * Provide a link to the next level of the view
+ */
+ function title($data, $url) {
+ return format_date(strtotime($this->argument . "15"), 'custom', $this->format, 0);
+ }
+}
+
+/**
+ * Argument handler for a month (MM)
+ */
+class views_handler_argument_date_month extends views_handler_argument_formula {
+ /**
+ * Constructor implementation
+ */
+ function construct() {
+ $timezone = views_get_timezone();
+ $this->formula = "MONTH(FROM_UNIXTIME(node.created+$timezone))";
+ $this->format = 'F';
+ }
+
+ /**
+ * Provide a link to the next level of the view
+ */
+ function summary_link($data, $url) {
+ $value = $data->{$this->base_alias};
+ $created = $data->{$this->name_alias};
+ return l(format_date($created, 'custom', $this->format), "$url/$value");
+ }
+
+ /**
+ * Provide a link to the next level of the view
+ */
+ function title($data, $url) {
+ return format_date(strtotime("2005" . $this->argument . "15"), 'custom', $this->format, 0);
+ }
+}
/**
* Implementation of hook_views_plugins
diff --git a/views.module b/views.module
index 9ee6632..1d25c97 100644
--- a/views.module
+++ b/views.module
@@ -447,29 +447,22 @@ function views_get_plugin($type, $plugin) {
* A keyed array of in the form of 'base_table' => 'Description'.
*/
function views_fetch_plugin_names($type, $key = NULL, $empty = FALSE) {
- static $plugins = array();
- if (empty($plugins)) {
- $data = views_fetch_plugin_data();
-
- foreach ($data as $plugin_type => $plugs) {
- // Skip some info data
- if (!is_array($plugs)) {
- continue;
- }
- foreach ($plugs as $id => $plugin) {
- // Skip plugins that don't conform to our key.
- if ($key && (($empty && empty($plugin[$key])) || (!$empty && !empty($plugin[$key])))) {
- continue;
- }
- if (empty($plugin['no ui'])) {
- $plugins[$plugin_type][$id] = $plugin['title'];
- }
- }
- asort($plugins[$plugin_type]);
+ $data = views_fetch_plugin_data();
+
+ $plugins[$type] = array();
+
+ foreach ($data[$type] as $id => $plugin) {
+ // Skip plugins that don't conform to our key.
+ if ($key && (($empty && empty($plugin[$key])) || (!$empty && !empty($plugin[$key])))) {
+ continue;
+ }
+ if (empty($plugin['no ui'])) {
+ $plugins[$type][$id] = $plugin['title'];
}
}
if (!empty($plugins[$type])) {
+ asort($plugins[$type]);
return $plugins[$type];
}
// fall-through
@@ -708,4 +701,39 @@ function vsm($message) {
if (module_exists('devel')) {
dsm($message);
}
-} \ No newline at end of file
+}
+
+function views_object_types() {
+ return array(
+ 'field' => array(
+ 'title' => t('Fields'),
+ 'stitle' => t('Field'),
+ 'plural' => 'fields',
+ 'object' => 'views_field',
+ ),
+ 'argument' => array(
+ 'title' => t('Arguments'),
+ 'stitle' => t('Argument'),
+ 'plural' => 'arguments',
+ 'object' => 'views_argument',
+ ),
+ 'sort' => array(
+ 'title' => t('Sort criteria'),
+ 'stitle' => t('Sort criterion'),
+ 'plural' => 'sorts',
+ 'object' => 'views_sort',
+ ),
+ 'filter' => array(
+ 'title' => t('Filters'),
+ 'stitle' => t('Filter'),
+ 'plural' => 'filters',
+ 'object' => 'views_filter',
+ ),
+ 'relationship' => array(
+ 'title' => t('Relationships'),
+ 'stitle' => t('Relationship'),
+ 'plural' => 'relationships',
+ 'object' => 'views_relationship',
+ ),
+ );
+}
diff --git a/views_ui.module b/views_ui.module
index 278ef51..03be679 100644
--- a/views_ui.module
+++ b/views_ui.module
@@ -78,18 +78,31 @@ function views_ui_menu() {
'page arguments' => array(3, 5),
);
$items['admin/build/views/%views_ui_js/rearrange/%views_ui_cache'] = $callback + array(
- 'page callback' => 'views_ui_rearrange_section',
+ 'page callback' => 'views_ui_rearrange_type',
'page arguments' => array(3, 5),
);
$items['admin/build/views/%views_ui_js/add-item/%views_ui_cache'] = $callback + array(
'page callback' => 'views_ui_add_item',
'page arguments' => array(3, 5),
);
+ $items['admin/build/views/%views_ui_js/config-item/%views_ui_cache'] = $callback + array(
+ 'page callback' => 'views_ui_config_item',
+ 'page arguments' => array(3, 5),
+ );
// display specific parameters
$items['admin/build/views/%views_ui_js/display/%views_ui_cache'] = $callback + array(
'page callback' => 'views_ui_edit_display',
'page arguments' => array(3, 5),
);
+ // Special style plugin stuff for arguments
+ $items['admin/build/views/%views_ui_js/change-style/%views_ui_cache'] = $callback + array(
+ 'page callback' => 'views_ui_change_style',
+ 'page arguments' => array(3, 5),
+ );
+ $items['admin/build/views/%views_ui_js/config-style/%views_ui_cache'] = $callback + array(
+ 'page callback' => 'views_ui_config_style',
+ 'page arguments' => array(3, 5),
+ );
return $items;
}
@@ -106,6 +119,10 @@ function views_ui_theme() {
'arguments' => array('form'),
'file' => '/includes/admin.inc',
),
+ 'views_ui_rearrange_form' => array(
+ 'arguments' => array('form'),
+ 'file' => '/includes/admin.inc',
+ ),
'views_tabset' => array(
'arguments' => array('tabs'),
'file' => '/includes/tabs.inc',