Commit b553325e authored by merlinofchaos's avatar merlinofchaos

Dependenct javascript so some form elements can appear and disappear when needed/not needed.

parent 6d634f78
......@@ -506,3 +506,8 @@ form#views-ui-preview-form input#preview-submit {
border: 1px solid red;
padding: 1em;
}
/* Hide by default only with js */
html.js .views-hidden {
display: none;
}
......@@ -916,7 +916,12 @@ function views_ui_standard_form_buttons(&$form, &$form_state, $form_id, $name =
$form_state['url'] = $form['#url'];
}
if (isset($form['#js'])) {
$form_state['js settings'] = $form['#js'];
if (is_array($form_state['js settings'])) {
$form_state['js settings'] = array_merge($form_state['settings'], $form['#js']);
}
else {
$form_state['js settings'] = $form['#js'];
}
}
if (isset($form['#section'])) {
$form_state['#section'] = $form['#section'];
......
......@@ -185,3 +185,29 @@ function drupal_process_form_new($form_id, &$form, &$form_state) {
}
}
}
/**
* Process callback to add dependency to form items.
*
* Usage:
*
* On any form item, add
* - '#process' => 'views_process_dependency' and
* - '#dependency' => array('id-of-form-without-the-#' => array(list, of, values, that, make, this, gadget, visible));
*/
function views_process_dependency($element, $edit, &$form_state, &$form) {
if (isset($element['#dependency'])) {
if (!isset($element['#dependency_count'])) {
$element['#dependency_count'] = 1;
}
if ($form_state['ajax']) {
$form_state['js settings']['viewsAjax']['formRelationships'][$element['#id']] = array('num' => $element['#dependency_count'], 'values' => $element['#dependency']);
}
else {
views_add_js('dependent');
drupal_add_js(array('views' => array('formRelationships' => $form_state['dependency'])), 'setting');
}
}
return $element;
}
......@@ -10,6 +10,7 @@
* Implementation of hook_views_plugins
*/
function views_views_plugins() {
$path = drupal_get_path('module', 'views') . '/js';
return array(
'module' => 'views', // This just tells our themes are elsewhere.
'display' => array(
......@@ -19,7 +20,7 @@ function views_views_plugins() {
'handler' => 'views_plugin_display_default',
'no ui' => TRUE,
'no remove' => TRUE,
'js' => array('misc/collapse.js', 'misc/textarea.js', 'misc/tabledrag.js'),
'js' => array('misc/collapse.js', 'misc/textarea.js', 'misc/tabledrag.js', "$path/dependent.js"),
'use pager' => TRUE,
),
'page' => array(
......@@ -624,13 +625,17 @@ class views_plugin_display extends views_object {
'#default_value' => $access['type'],
);
$form['access']['role'] = array(
'#prefix' => '<div class="views-left-25">',
'#suffix' => '</div>',
// Add an id to the surrounding div because checkboxes don't get ids
// as a whole group. =(
'#prefix' => '<div class="views-left-25"><div id="edit-access-role">',
'#suffix' => '</div></div>',
'#type' => 'checkboxes',
'#title' => t('If by role'),
'#default_value' => $access['role'],
'#options' => views_ui_get_roles(),
'#description' => t('Only the checked roles will be able to access this display.'),
'#process' => array('expand_checkboxes', 'views_process_dependency'),
'#dependency' => array('radio:access[type]' => array('role')),
);
$perms = array();
......@@ -648,6 +653,10 @@ class views_plugin_display extends views_object {
'#title' => t('If by perm'),
'#default_value' => $access['perm'],
'#description' => t('Only users with the selected permission flag will be able to access this display.'),
'#process' => array('views_process_dependency'),
// Radios don't *get* ids in this system, so we use a special format
// for the id.
'#dependency' => array('radio:access[type]' => array('perm')),
);
break;
case 'header':
......@@ -1310,7 +1319,12 @@ class views_plugin_display_page extends views_plugin_display {
'#suffix' => '</div>',
'#title' => t('Type'),
'#type' => 'radios',
'#options' => array('none' => t('No menu entry'), 'normal' => t('Normal menu entry'), 'tab' => t('Menu tab'), 'default tab' => t('Default menu tab')),
'#options' => array(
'none' => t('No menu entry'),
'normal' => t('Normal menu entry'),
'tab' => t('Menu tab'),
'default tab' => t('Default menu tab')
),
'#default_value' => $menu['type'],
);
$form['menu']['title'] = array(
......@@ -1319,13 +1333,17 @@ class views_plugin_display_page extends views_plugin_display {
'#type' => 'textfield',
'#default_value' => $menu['title'],
'#description' => t('If set to normal or tab, enter the text to use for the menu item.'),
'#process' => array('views_process_dependency'),
'#dependency' => array('radio:menu[type]' => array('normal', 'tab', 'default tab')),
);
$form['menu']['weight'] = array(
'#suffix' => '</div>',
'#title' => t('Weight'),
'#type' => 'textfield',
'#default_value' => isset($menu['weight']) ? $menu['weight'] : 0,
'#description' => t('If set to normal or tab, enter the weight of the item. The lower th weight the higher/further left it will appear.'),
'#description' => t('If set to tab, enter the weight of the item. The lower th weight the higher/further left it will appear.'),
'#process' => array('views_process_dependency'),
'#dependency' => array('radio:menu[type]' => array('tab', 'default tab')),
);
break;
case 'tab_options':
......@@ -1360,6 +1378,8 @@ class views_plugin_display_page extends views_plugin_display {
'#type' => 'textfield',
'#default_value' => $tab_options['title'],
'#description' => t('If creating a parent menu item, enter the title of the item.'),
'#process' => array('views_process_dependency'),
'#dependency' => array('radio:tab_options[type]' => array('normal', 'tab')),
);
$form['tab_options']['weight'] = array(
'#suffix' => '</div>',
......@@ -1368,6 +1388,8 @@ class views_plugin_display_page extends views_plugin_display {
'#default_value' => $tab_options['weight'],
'#size' => 5,
'#description' => t('If the parent menu item is a tab, enter the weight of the tab. The lower the number, the more to the left it will be.'),
'#process' => array('views_process_dependency'),
'#dependency' => array('radio:tab_options[type]' => array('tab')),
);
break;
}
......@@ -1824,8 +1846,6 @@ class views_plugin_style_table extends views_plugin_style {
'#description' => t('If a default sort order is selected, what order should it use by default.'),
);
// @todo: add dependency here.
// Note: views UI registers this theme handler on our behalf. Your module
// will have to register your theme handlers if you do stuff like this.
$form['#theme'] = 'views_ui_style_plugin_table';
......@@ -1858,6 +1878,10 @@ class views_plugin_style_table extends views_plugin_style {
}
foreach ($columns as $field => $column) {
$safe = str_replace(array('][', '_', ' '), '-', $field);
// the $id of the column for dependency checking.
$id = 'edit-style-options-columns-' . $safe;
$form['columns'][$field] = array(
'#type' => 'select',
'#options' => $field_names,
......@@ -1867,19 +1891,29 @@ class views_plugin_style_table extends views_plugin_style {
$form['info'][$field]['sortable'] = array(
'#type' => 'checkbox',
'#default_value' => !empty($this->options['info'][$field]['sortable']),
'#process' => array('views_process_dependency'),
'#dependency' => array($id => array($field)),
);
// Provide an ID so we can have such things.
$radio_id = form_clean_id('edit-default-' . $field);
$form['default'][$field] = array(
'#type' => 'radio',
'#return_value' => $field,
'#parents' => array('style_options', 'default'),
'#id' => form_clean_id('edit-default-' . $field),
'#id' => $radio_id,
// because 'radio' doesn't fully support '#id' =(
'#attributes' => array('id' => $radio_id),
'#default_value' => $default,
'#process' => array('views_process_dependency'),
'#dependency' => array($id => array($field)),
);
}
$form['info'][$field]['separator'] = array(
'#type' => 'textfield',
'#size' => 10,
'#default_value' => isset($this->options['info'][$field]['separator']) ? $this->options['info'][$field]['separator'] : '',
'#process' => array('views_process_dependency'),
'#dependency' => array($id => array($field)),
);
// markup for the field name
......@@ -1893,7 +1927,7 @@ class views_plugin_style_table extends views_plugin_style {
'#type' => 'radio',
'#return_value' => -1,
'#parents' => array('style_options', 'default'),
'#id' => form_clean_id('edit-default-0'),
'#id' => 'edit-default-0',
'#default_value' => $default,
);
......
......@@ -35,6 +35,9 @@ Drupal.Views.Ajax.ajaxResponse = function(data) {
// See if we have any settings to extend. Do this first so that behaviors
// can access the new settings easily.
if (Drupal.settings.viewsAjax) {
Drupal.settings.viewsAjax = {};
}
if (data.js) {
$.extend(Drupal.settings, data.js);
}
......@@ -135,6 +138,10 @@ Drupal.Views.Ajax.previewResponse = function(data) {
// See if we have any settings to extend. Do this first so that behaviors
// can access the new settings easily.
// Clear any previous viewsAjax settings.
if (Drupal.settings.viewsAjax) {
Drupal.settings.viewsAjax = {};
}
if (data.js) {
$.extend(Drupal.settings, data.js);
}
......
// $Id$
/**
* @file dependent.js
*
* Written by dmitrig01 (Dmitri Gaskin) for Views; this provides dependent
* visibility for form items in Views' ajax forms.
*
* To your $form item definition add:
* - '#process' => array('views_process_dependency'),
* - Add '#dependency' => array('id-of-form-item' => array(list, of, values, that,
make, this, item, show),
*
* Special considerations:
* - radios are harder. Because Drupal doesn't give radio groups individual ids,
* use 'radio:name-of-radio'
*
* - Checkboxes don't have their own id, so you need to add one in a div
* around the checkboxes via #prefix and #suffix. You actually need to add TWO
* divs because it's the parent that gets hidden. Also be sure to retain the
* 'expand_checkboxes' in the #process array, because the views process will
* override it.
*/
Drupal.Views.dependent = {};
Drupal.Views.dependent.bindings = {};
Drupal.Views.dependent.activeBindings = {};
Drupal.Views.dependent.activeTriggers = [];
Drupal.Views.dependent.inArray = function(array, search_term) {
var i = array.length;
if (i > 0) {
do {
if (array[i] == search_term) {
return true;
}
} while (i--);
}
return false;
}
Drupal.Views.dependent.autoAttach = function() {
// Clear active bindings and triggers.
for (i in Drupal.Views.dependent.activeTriggers) {
jQuery(Drupal.Views.dependent.activeTriggers[i]).unbind('change');
}
Drupal.Views.dependent.activeTriggers = [];
Drupal.Views.dependent.activeBindings = {};
Drupal.Views.dependent.bindings = {};
if (!Drupal.settings.viewsAjax) {
return;
}
// Iterate through all relationships
for (id in Drupal.settings.viewsAjax.formRelationships) {
// Drupal.Views.dependent.activeBindings[id] is a boolean,
// whether the binding is active or not. Defaults to no.
Drupal.Views.dependent.activeBindings[id] = 0;
// Iterate through all possible values
for(bind_id in Drupal.settings.viewsAjax.formRelationships[id].values) {
// This creates a backward relationship. The bind_id is the ID
// of the element which needs to change in order for the id to hide or become shown.
// The id is the ID of the item which will be conditionally hidden or shown.
// Here we're setting the bindings for the bind
// id to be an empty array if it doesn't already have bindings to it
if (!Drupal.Views.dependent.bindings[bind_id]) {
Drupal.Views.dependent.bindings[bind_id] = [];
}
// Add this ID
Drupal.Views.dependent.bindings[bind_id].push(id);
// Big long if statement.
// Drupal.settings.viewsAjax.formRelationships[id].values[bind_id] holds the possible values
if (bind_id.substring(0, 6) == 'radio:') {
var trigger_id = "input[@name='" + bind_id.substring(6) + "']";
}
else {
var trigger_id = '#' + bind_id;
}
Drupal.Views.dependent.activeTriggers.push(trigger_id);
var getValue = function(item, trigger) {
if (item.substring(0, 6) == 'radio:') {
var val = jQuery(trigger + ':checked').val();
}
else {
switch (jQuery(trigger).attr('type')) {
case 'checkbox':
var val = jQuery(trigger).attr('checked') || 0;
break;
default:
var val = jQuery(trigger).val();
}
}
return val;
}
var setChangeTrigger = function(trigger_id, bind_id) {
// Triggered when change() is clicked.
var changeTrigger = function() {
var val = getValue(bind_id, trigger_id);
for (i in Drupal.Views.dependent.bindings[bind_id]) {
var id = Drupal.Views.dependent.bindings[bind_id][i];
// Fix numerous errors
if (typeof id != 'string') {
continue;
}
// This bit had to be rewritten a bit because two properties on the
// same set caused the counter to go up and up and up.
if (!Drupal.Views.dependent.activeBindings[id]) {
Drupal.Views.dependent.activeBindings[id] = {};
}
if (Drupal.Views.dependent.inArray(Drupal.settings.viewsAjax.formRelationships[id].values[bind_id], val)) {
Drupal.Views.dependent.activeBindings[id][bind_id] = 'bind';
}
else {
delete Drupal.Views.dependent.activeBindings[id][bind_id];
}
var len = 0;
for (i in Drupal.Views.dependent.activeBindings[id]) {
len++;
}
if (Drupal.settings.viewsAjax.formRelationships[id].num <= len) {
// Show if the element if criteria is matched
jQuery('#'+ id).parent().show(0);
}
else {
// Otherwise hide
jQuery('#'+ id).parent().hide(0);
}
}
}
jQuery(trigger_id).change(function() {
// Trigger the internal change function
// the attr('id') is used because closures are more confusing
changeTrigger(trigger_id, bind_id);
});
// Trigger initial reaction
changeTrigger(trigger_id, bind_id);
}
}
setChangeTrigger(trigger_id, bind_id);
}
}
Drupal.behaviors.viewsDependent = function (context) {
Drupal.Views.dependent.autoAttach();
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment