all contrib module security updates done

This commit is contained in:
2020-09-24 22:47:32 +02:00
parent 7d87153100
commit 0fbb9c4610
1612 changed files with 116663 additions and 32269 deletions
+71 -8
View File
@@ -1,12 +1,75 @@
/* $Id*/
CHANGELOG for field_group for Drupal 7
Field_group 7.x-1.x-dev
o Issue #1095316: Field Groups disappear when Content Type is renamed.
o Issue #1095316 by swentel: Support for Entity API.
o Issue #1095002 by animelion: Upgrading removes all existing field groups.
o Issue #1095130 by willvincent: Features export not working with rc2.
Field Group origin/7.x-1.x, 2017-11-04
--------------------------------------
- Tests fail after new 'administer fields' permission.
- Update CHANGELOG.txt to 7.x-1.5 Release.
- Revert "Issue #2646106 by jribeiro: Update CHANGELOG.txt to 7.x-1.5 Release".
- Update CHANGELOG.txt to 7.x-1.5 Release.
- Fix whitespace between "&" and parameters for some functions.
- Avoid bad code pattern (that is picked up by security scanners) when getting hash.
- Should #array_parents be updated in field_group_fields_nest()?.
- "Show" appears in horizontal tab title if node form submitted through ajax.
- CSS breaks i18n string translation interface.
- "uncaught exception: Syntax error, unrecognized expression: #" after 7.x-1.4 update.
- PHP7 - Uniform Variable Syntax updates are causing exported field_groups to not have names.
Field_group 7.x-1.5
o Added extra formatting on html element attributes.
o Fixed bug on automatic ID generation in javascript.
o Issue #2511960 by rrfegade: spelling errors in D7.
o Issue #2194279 by Georgique: Export translatables (label and descriptions) in Features.
o Issue #2386335 by Dubs: Integer Group Array Keys can create empty node forms.
o Issue #2269133 by sammuell: Accordion is always closed when using jQuery update module.
o Issue #2258939 by Snipon: Fixed Change to preventDefault on multipage controls.
o Issue #2173937 by jantoine, omerida | Bernieman: Fixed Accordion Element has fixed height in HTML.
o Issue #2311789 by eelkeblok: Fixed Group is incorrectly determined to be empty with nested form elements.
o Issue #2272003 by karolrybak | Kwb: Fixed Fieldgroup no longer renders after using more than one 'HTML Element' on the same level.
o Issue #2309219 by czigor: Fixed Proper CTools exportable loading.
o Issue #2283245 by stefan.r | jrb: Fixed New id functionality breaks tests and CSS on existing field groups.
o Issue #2295133 by boyan.borisov, interX: Fixed field_group_update_7007 error.
o Remove field_group.css, the css is not needed anymore.
o Fix horiziontal tabs when used as standalone element.
Field_group 7.x-1.4
o Issue #2129805 by RaF: Incorrect markup when open div & custom classes provided.
o Issue #2037731 by maximpodorov, Zach Harkey: Remove id attribute from HTML elements.
o Issue #2099505 by borisson_ | Maks: Warning: Invalid argument supplied for foreach() in field_group_build_entity_groups() (line 1894 ..sites/all/modules/field_group.
o Issue #2102397 by thebruce: Field Group 7006 update fails with "Cannot use string offset as an array in /field_group/field_group.install on line 318.
o Issue #2122733 by Alan D.: Remove test module from admin listing.
o Issue #2212431 by tim.plunkett: Field groups that contain only elements that use #markup are hidden.
o Issue #2175731 by tobiasb, daggerhart: HTML produced by module is broken.
o Issue #2190425 by tobiasb: Fix attach behavior.
o Issue #1911530 by tobiasb, Simon Georges: Remove useless files[] directive from .info files.
o Issue #1358430 by oushen, tobiasb | FriedJam: JS "Error: uncaught exception: Syntax error, unrecognized expression:".
o Issue #2104391 by mike_san: Package descriptions.
o Issue #2189777 by gmercer: Exporting a feature with field groups sometimes leads to $field_group->data being set to an empty string.
o Issue #2168689 by Paul B: Beïng should be being.
o Issue #2037731 by rreiss, maximpodorov, Zach Harkey: Make id attribute optional. Current installations will default get the old ids
o Issue #2173351 by axe312: Add a label to html-element wrappers.
o Issue #1954056 by klonos: Proper capitalization in the project name.
o Issue #2224547 by sdrycroft: Fixed field_group_info_groups() clears all CTools caches when it should only clear the field_group caches.
o Issue #2099505 by joelpittet, borisson_ | Maks: Fixed Warning: Invalid argument supplied for foreach() in field_group_build_entity_groups() (line 1894 ..sites/all/modules/field_group.
o Issue #2223269 by barraponto: Fixed Don't filter and translate empty strings.
Field_group 7.x-1.3
o Issue #2077695 by FreekVR | ChoY: Fixed field group entity display bug after update.
o Issue #2078201 by DeFr, eneko1907 | cmriley: Fixed Started getting a ton of notices.
o Issue #2085137 by ar-jan: Fixed Collapse speed no longer works with field_group() 1.2
o Issue #2085225 by dtarc: Fixed Featurized Field Groups no longer have classes since marked optional.
o Issue #2080645 by bassthiam: Fixed Warning: Illegal string offset 'label' in field_group_unpack() line 1682 of field_group()/field_group().module.
o Issue #1942676 by Harlor | El Bandito: Added Change the text 'Mark group for required fields.'.
o Issue #1358430 by FriedJam: Fixed JS 'Error: uncaught exception: Syntax error, unrecognized expression:".
o Issue #2084999 by activelink: Fixed Empty field groups aren't being suppressed since move to 7.x-1.2.
o Issue #1557258 by Mark Trapp | Chris Gillis: Fixed Existing field groups disappear and Add Field Group UI is disabled when no fields are available.
o Issue #2000110 by bigjim: Fixed Comments on field_group_read_groups() wrong
o Issue #1169146 by ankur, Nephele | jeffrey.dalton: Fixed upgrade from 7.x-1.0-rc2 to 7.x-1.0 deletes all field_groups().
o Vertical tabs always appear when children elements have no access
o #1966624 Feature 7.x-2.0-beta2 defines fields in a new way
o #2090415 Make horizontal tabs not dependent on form.js. Also change drupal_add_x to #attached
o
Field_group 7.x-1.0-rc2
o Ran through coder, minor.
o Issue #1033036 by Stalski, swentel: Create a field_group.api.php.
@@ -20,7 +83,7 @@ Field_group 7.x-1.0-rc2
o #1045526 by stalski: Make formatter options more user-friendly and logical.
o #1041880 by robertgarrigos: duplicated entries in field_group table.
o #1043834 by amsri: Field Group module just does not work with profiles 2.
Field_group 7.x-1.0-rc1
o #1006464 Change #groups to #fieldgroups because of name collapsing with form_process_fieldset
o #1024184 fix collapsible when mode is set to open
@@ -34,7 +97,7 @@ Field_group 7.x-1.0-rc1
o #961106 Fixed notice on entity type and bundle check.
o #962072 by mori: Improve CSS for horizontal tabs & accordion.
o Changed Fieldgroup API: defaults and instance_settings are now merged.
o Changed save action so everything is gathered during form_state to
o Changed save action so everything is gathered during form_state to
postpone saving until the save button is hit.
o Changed some important variable name, so it makes more sense and easier to read.
o Add basic crud functions.
+20 -10
View File
@@ -1,28 +1,38 @@
History:
Field_group was written for Drupal 7. For drupal 6, the module is
Field_group was written for Drupal 7. For drupal 6, the module is
located in the CCK module (http://drupal.org/project/cck).
As drupal core has a fields API drupal > 6, the field_group module
As drupal core has a fields API drupal > 6, the field_group module
is considered a contribution.
Description:
field_group is a module that will group a set of fields. In Drupal7,
field_group is a module that will group a set of fields. In Drupal7,
with fields, one means all fields that come from fieldable entities.
You can add fieldgroups in several types with their own format settings.
field_group has API functions to add your own formatter and rendering for
it.
field_group has API functions to add your own formatter and rendering for
it.
One of the biggest improvements to previous versions, is that fieldgroups
have unlimited nesting, better display control.
Note that field_group will only group fields, it can not be used to hide
Note that field_group will only group fields, it can not be used to hide
certain fields since this a permission matter.
Module project page:
http://drupal.org/project/field_group
Documentation page:
Documentation page:
http://drupal.org/node/1017838
http://drupal.org/node/1017962
Available group types:
- Fieldsets
- Horizontal tabs
- Vertical tabs
- Accordions
- Divs
- Multipage steps: <strong>Note: This is only client side.
- HTML5 group type
- Html element
To submit bug reports and feature suggestions, or to track changes:
http://drupal.org/project/issues/field_group
@@ -0,0 +1,7 @@
/**
* Override the accordion default style for view_modes.
*/
form .ui-accordion h3, form .ui-accordion h3.ui-state-active {
padding-left: 0;
padding-right: 2em;
}
+32 -7
View File
@@ -2,7 +2,7 @@
/**
* @file
* Hooks provided by the Field group module.
* Hooks provided by the Field Group module.
*
* Fieldgroup is a module that will wrap fields and other fieldgroups. Nothing more, nothing less.
* For this there are formatters we can create on forms and view modes.
@@ -87,7 +87,7 @@ function hook_field_group_formatter_info() {
'form' => array(
'fieldset' => array(
'label' => t('Fieldset'),
'description' => t('This fieldgroup renders the inner content in a fieldset with the titel as legend.'),
'description' => t('This fieldgroup renders the inner content in a fieldset with the title as legend.'),
'format_types' => array('open', 'collapsible', 'collapsed'),
'instance_settings' => array('classes' => ''),
'default_formatter' => 'collapsible',
@@ -96,7 +96,7 @@ function hook_field_group_formatter_info() {
'display' => array(
'div' => array(
'label' => t('Div'),
'description' => t('This fieldgroup renders the inner content in a simple div with the titel as legend.'),
'description' => t('This fieldgroup renders the inner content in a simple div with the title as legend.'),
'format_types' => array('open', 'collapsible', 'collapsed'),
'instance_settings' => array('effect' => 'none', 'speed' => 'fast', 'classes' => ''),
'default_formatter' => 'collapsible',
@@ -220,7 +220,7 @@ function hook_field_group_format_settings($group) {
* @param Array $elements by address.
* @param Object $group The Field group info.
*/
function hook_field_group_pre_render(& $element, $group, & $form) {
function hook_field_group_pre_render(&$element, $group, &$form) {
// You can prepare some variables to use in the logic.
$view_mode = isset($form['#view_mode']) ? $form['#view_mode'] : 'form';
@@ -268,7 +268,7 @@ function hook_field_group_pre_render(& $element, $group, & $form) {
*
* Function that fungates as last resort to alter the pre_render build.
*/
function hook_field_group_pre_render_alter(&$element, $group, & $form) {
function hook_field_group_pre_render_alter(&$element, $group, &$form) {
if ($group->format_type == 'htab') {
$element['#theme_wrappers'] = array('my_horizontal_tab');
@@ -285,7 +285,7 @@ function hook_field_group_pre_render_alter(&$element, $group, & $form) {
*
* @param Array $elements by address.
*/
function hook_field_group_build_pre_render_alter(& $element) {
function hook_field_group_build_pre_render_alter(&$element) {
// Prepare variables.
$display = isset($element['#view_mode']);
@@ -345,6 +345,18 @@ function hook_field_group_info() {
}
/**
* Alter the field group definitions provided by other modules.
*
* @param array $groups
* Reference to an array of field group definition objects.
*/
function hook_field_group_info_alter(&$groups) {
if (!empty($groups['group_issue_metadata|node|project_issue|form'])) {
$groups['group_issue_metadata|node|project_issue|form']->data['children'][] = 'taxonomy_vocabulary_9';
}
}
/**
* Implements hook_field_group_update_field_group().
*
@@ -421,14 +433,27 @@ function field_group_info_groups($entity_type = NULL, $bundle = NULL, $view_mode
*
* @param Array $params
* The Entity type where field groups are requested.
* @param $enabled
* Return enabled or disabled groups.*
*
* @see field_group_info_groups()
* @see ctools_export_load_object()
*/
function field_group_read_groups($params = array()) {
function field_group_read_groups($conditions = array(), $enabled = TRUE) {
// This function loads the requested groups through ctools export api.
}
/**
* Hides field groups including children in a render array.
*
* @param array $element
* A render array. Can be a form, node, user, ...
* @param array $group_names
* An array of field group names that should be hidden.
*/
function field_group_hide_field_groups(&$element, $group_names) {
}
/**
* @} End of "addtogroup utility functions".
*/
@@ -1,32 +0,0 @@
/* $Id: field_group.css,v 1.1.2.12 2010/12/22 22:22:35 stalski Exp $ */
/**
* Fix for fieldsets in vertical tabs.
* Note that this can only be hardcoded to the Seven theme
* where people who override this, are in trouble.
*/
.vertical-tabs fieldset.default-fallback,
div.field-group-tabs-wrapper div.field-type-image fieldset,
div.field-group-tabs-wrapper div.field-type-file fieldset {
border: 1px solid #CCCCCC;
margin: 1em 0;
padding: 2.5em 0 0;
position: relative;
}
div.field-group-tabs-wrapper div.field-type-image legend,
div.field-group-tabs-wrapper div.field-type-file legend,
.vertical-tabs .field-group-fieldset legend {
display: block;
}
/**
* Override the accordion default style for view_modes.
*/
form .ui-accordion h3, form .ui-accordion h3.ui-state-active {
padding-left: 2em;
}
.ui-accordion h3.ui-state-active {
background: url("/misc/ui/images/ui-bg_glass_75_e6e6e6_1x400.png") repeat-x scroll 50% 50% #E6E6E6;
}
+31 -9
View File
@@ -9,25 +9,42 @@
* that are a part of this feature.
*/
function field_group_features_export_alter(&$export, $module_name) {
//Make sure we have fresh data by loading directly.
// Make sure we have fresh data by loading directly.
ctools_include('export');
$field_groups = ctools_export_load_object('field_group');
//Add fieldgroups based on the fields that are present.
if (!empty($export['features']['field'])) {
foreach ($export['features']['field'] as $field) {
// Support the separate field base -vs- field instance structure that was
// added in Features v7.x-2.0-beta2.
if (function_exists('field_instance_features_export')) {
$export_var = 'field_instance';
}
else {
$export_var = 'field';
}
// Add fieldgroups based on the fields that are present.
if (!empty($export['features'][$export_var])) {
if (!isset($export['features']['field_group'])) {
$export['features']['field_group'] = array();
}
foreach ($export['features'][$export_var] as $field) {
list($entity_type, $bundle, $field_name) = explode('-', $field);
foreach ($field_groups as $group_id => $group) {
if ($group->entity_type == $entity_type && $group->bundle == $bundle
&& in_array($field_name, $group->data['children'])) {
$export['features']['field_group'][$group_id] = $group_id;
if ($group->entity_type == $entity_type && $group->bundle == $bundle && in_array($field_name, $group->data['children']) && !in_array($group->identifier, $export['features']['field_group'])) {
if (isset($group->export_module) && $group->export_module != $module_name) {
$export['dependencies'][$group->export_module] = $group->export_module;
}
else {
$export['features']['field_group'][$group_id] = $group_id;
}
}
}
}
}
//Add any parent field groups that haven't been selected.
// Add any parent field groups that haven't been selected.
if (!empty($export['features']['field_group'])) {
foreach ($export['features']['field_group'] as $id) {
$group = isset($field_groups[$id]) ? $field_groups[$id] : FALSE;
@@ -37,7 +54,12 @@ function field_group_features_export_alter(&$export, $module_name) {
$parent_group = isset($field_groups[$parent_id]) ? $field_groups[$parent_id] : FALSE;
if ($parent_group && !isset($export['features']['field_group'][$parent_id])) {
$export['features']['field_group'][$parent_id] = $parent_id;
if (isset($parent_group->export_module) && $parent_group->export_module != $module_name) {
$export['dependencies'][$parent_group->export_module] = $parent_group->export_module;
}
else {
$export['features']['field_group'][$parent_id] = $parent_id;
}
}
}
}
View File
File diff suppressed because it is too large Load Diff
View File
@@ -1,18 +1,14 @@
name = Fieldgroup
description = Fieldgroup
name = Field Group
description = "Provides the ability to group your fields on both form and display."
package = Fields
dependencies[] = field
dependencies[] = ctools
core = 7.x
files[] = field_group.install
files[] = field_group.module
files[] = field_group.field_ui.inc
files[] = field_group.form.inc
files[] = field_group.features.inc
files[] = field_group.test
; Information added by drupal.org packaging script on 2011-10-19
version = "7.x-1.1"
files[] = tests/field_group.ui.test
files[] = tests/field_group.display.test
; Information added by Drupal.org packaging script on 2017-11-03
version = "7.x-1.6"
core = "7.x"
project = "field_group"
datestamp = "1319051133"
datestamp = "1509751991"
+138 -2
View File
@@ -17,6 +17,7 @@ function field_group_schema() {
'key' => 'identifier',
'identifier' => 'field_group',
'default hook' => 'field_group_info',
'load callback' => 'field_group_group_load_by_identifier',
'save callback' => 'field_group_group_save',
'delete callback' => 'field_group_group_export_delete',
'can disable' => TRUE,
@@ -108,14 +109,14 @@ function _field_group_install_read_groups() {
->condition('group_type', 'standard');
foreach ($query->execute() as $record) {
$record['settings'] = unserialize($record['settings']);
$groups[$record['group_name']] = $record;
$groups[$record['group_name'] . '-' . $record['type_name']] = $record;
}
foreach ($groups as $key => $group) {
$query2 = db_select('content_group_fields', 'cgf', array('fetch' => PDO::FETCH_ASSOC))
->fields('cgf')
->condition('group_name', $group['group_name']);
foreach ($query2->execute() as $field) {
$groups[$field['group_name']]['children'][] = $field;
$groups[$field['group_name'] . '-' . $field['type_name']]['children'][] = $field;
}
}
}
@@ -216,6 +217,8 @@ function field_group_update_7001() {
'default' => '',
'description' => 'The unique string identifier for a group.',
));
// Force drupal's schema to be rebuilt
drupal_get_schema('field_group', TRUE);
module_load_include('module', 'field_group');
_field_group_recreate_identifiers();
@@ -227,6 +230,8 @@ function field_group_update_7001() {
->condition('name', 'field_group')
->execute();
// Clear drupal and static cache.
field_group_info_groups(NULL, NULL, NULL, TRUE);
}
/**
@@ -244,6 +249,8 @@ function field_group_update_7002() {
// See http://drupal.org/node/1018550.
_field_group_recreate_identifiers();
// Clear drupal and static cache.
field_group_info_groups(NULL, NULL, NULL, TRUE);
}
/**
@@ -255,4 +262,133 @@ function field_group_update_7003() {
module_load_include('module', 'field_group');
_field_group_recreate_identifiers();
// Clear drupal and static cache.
field_group_info_groups(NULL, NULL, NULL, TRUE);
}
/**
* Update hook to make sure identifier is set as unique key.
*/
function field_group_update_7004() {
db_drop_unique_key('field_group', 'identifier');
db_add_unique_key('field_group', 'identifier', array('identifier'));
}
/**
* Checks all existing groups and removes optional HTML classes
* while adding them as extra classes.
*/
function field_group_update_7005() {
// Migrate the field groups so they have a unique identifier.
$result = db_select('field_group', 'fg')
->fields('fg')
->execute();
$rows = array();
foreach($result as $row) {
//$row->identifier = $row->group_name . '|' . $row->entity_type . '|' . $row->bundle . '|' . $row->mode;
$row->data = unserialize($row->data);
$classes = explode(" ", $row->data['format_settings']['instance_settings']['classes']);
$optional_classes = array(str_replace("_", "-", $row->group_name), 'field-group-' . $row->data['format_type']);
foreach ($optional_classes as $optional_class) {
if (!in_array($optional_class, $classes)) {
$classes[] = $optional_class;
}
}
$row->data['format_settings']['instance_settings']['classes'] = implode(" ", $classes);
$rows[] = $row;
}
foreach ($rows as $row) {
drupal_write_record('field_group', $row, array('id'));
}
// Clear drupal and static cache.
field_group_info_groups(NULL, NULL, NULL, TRUE);
}
/**
* Save all optional HTML classes for fieldgroups located in features.
* If you need the optional classes, recreate feature after this update.
* If not, you can revert it.
*/
function field_group_update_7006() {
ctools_include("export");
// Migrate the field groups so they have a unique identifier.
$field_groups = ctools_export_load_object("field_group");
foreach ($field_groups as $row) {
// Only update feature field_groups this time.
// Don't touch the fieldgroups in db.
if ($row->export_type == EXPORT_IN_CODE) {
$classes = array();
if (isset($row->data['format_settings'], $row->data['format_settings']['instance_settings'], $row->data['format_settings']['instance_settings']['classes'])) {
$classes = explode(" ", $row->data['format_settings']['instance_settings']['classes']);
}
$optional_classes = array(str_replace("_", "-", $row->group_name), 'field-group-' . $row->data['format_type']);
foreach ($optional_classes as $optional_class) {
if (!in_array($optional_class, $classes)) {
$classes[] = $optional_class;
}
}
$row->data['format_settings']['instance_settings']['classes'] = implode(" ", $classes);
unset($row->id);
drupal_write_record('field_group', $row);
}
}
// Clear drupal and static cache.
field_group_info_groups(NULL, NULL, NULL, TRUE);
}
/**
* Id attributes are now a setting. This update will insert the old id in the setting so old
* markup doesn't get broken. If you don't want an attribute, you can delete
* them on the fieldgroup settings.
*/
function field_group_update_7007() {
ctools_include("export");
// Migrate the field groups so they have a unique identifier.
$field_groups = ctools_export_load_object("field_group");
foreach ($field_groups as $row) {
// These field group types have an ID setting to populate.
$populate_id_setting = array(
'html-element',
'div',
'html5',
'fieldset',
'tabs',
'htabs',
'accordion',
);
if (in_array($row->data['format_type'], $populate_id_setting)) {
// If mode is default, we don't know what view mode it was. Take full then.
$view_mode = $row->mode == 'default' ? 'full' : $row->mode;
$id = $row->entity_type . '_' . $row->bundle . '_' . $view_mode . '_' . $row->group_name;
$row->data['format_settings']['instance_settings']['id'] = $id;
}
if ($row->export_type == EXPORT_IN_CODE) {
unset($row->id);
drupal_write_record('field_group', $row);
}
else {
drupal_write_record('field_group', $row, array('id'));
}
}
// Clear drupal and static cache.
field_group_info_groups(NULL, NULL, NULL, TRUE);
}
/**
* Clear cache to notice the CTools load callback.
*/
function field_group_update_7008() {
drupal_flush_all_caches();
}
+54 -9
View File
@@ -41,9 +41,17 @@ Drupal.FieldGroup.Effects.processAccordion = {
$('div.field-group-accordion-wrapper', context).once('fieldgroup-effects', function () {
var wrapper = $(this);
// Get the index to set active.
var active_index = false;
wrapper.find('.accordion-item').each(function(i) {
if ($(this).hasClass('field-group-accordion-active')) {
active_index = i;
}
});
wrapper.accordion({
autoHeight: false,
active: '.field-group-accordion-active',
heightStyle: "content",
active: active_index,
collapsible: true,
changestart: function(event, ui) {
if ($(this).hasClass('effect-none')) {
@@ -56,17 +64,29 @@ Drupal.FieldGroup.Effects.processAccordion = {
});
if (type == 'form') {
var $firstErrorItem = false;
// Add required fields mark to any element containing required fields
wrapper.find('div.accordion-item').each(function(i){
wrapper.find('div.field-group-accordion-item').each(function(i) {
if ($(this).is('.required-fields') && $(this).find('.form-required').length > 0) {
$('h3.ui-accordion-header').eq(i).append(' ').append($('.form-required').eq(0).clone());
$('h3.ui-accordion-header a').eq(i).append(' ').append($('.form-required').eq(0).clone());
}
if ($('.error', $(this)).length) {
// Save first error item, for focussing it.
if (!$firstErrorItem) {
$firstErrorItem = $(this).parent().accordion("activate" , i);
}
$('h3.ui-accordion-header').eq(i).addClass('error');
var activeOne = $(this).parent().accordion("activate" , i);
$('.ui-accordion-content-active', activeOne).css({height: 'auto', width: 'auto', display: 'block'});
}
});
// Save first error item, for focussing it.
if (!$firstErrorItem) {
$('.ui-accordion-content-active', $firstErrorItem).css({height: 'auto', width: 'auto', display: 'block'});
}
}
});
}
@@ -99,6 +119,9 @@ Drupal.FieldGroup.Effects.processHtabs = {
Drupal.FieldGroup.Effects.processTabs = {
execute: function (context, settings, type) {
if (type == 'form') {
var errorFocussed = false;
// Add required fields mark to any fieldsets containing required fields
$('fieldset.vertical-tabs-pane', context).once('fieldgroup-effects', function(i) {
if ($(this).is('.required-fields') && $(this).find('.form-required').length > 0) {
@@ -106,8 +129,12 @@ Drupal.FieldGroup.Effects.processTabs = {
}
if ($('.error', $(this)).length) {
$(this).data('verticalTab').link.parent().addClass('error');
Drupal.FieldGroup.setGroupWithfocus($(this));
$(this).data('verticalTab').focus();
// Focus the first tab with error.
if (!errorFocussed) {
Drupal.FieldGroup.setGroupWithfocus($(this));
$(this).data('verticalTab').focus();
errorFocussed = true;
}
}
});
}
@@ -171,6 +198,7 @@ Drupal.FieldGroup.Effects.processDiv = {
*/
Drupal.behaviors.fieldGroup = {
attach: function (context, settings) {
settings.field_group = settings.field_group || Drupal.settings.field_group;
if (settings.field_group == undefined) {
return;
}
@@ -189,7 +217,24 @@ Drupal.behaviors.fieldGroup = {
$('.fieldset-wrapper .fieldset > legend').css({display: 'block'});
$('.vertical-tabs fieldset.fieldset').addClass('default-fallback');
// Add a new ID to each fieldset.
$('.group-wrapper .horizontal-tabs-panes > fieldset', context).once('group-wrapper-panes-processed', function() {
// Tats bad, but we have to keep the actual id to prevent layouts to break.
var fieldgroupID = 'field_group-' + $(this).attr('id');
$(this).attr('id', fieldgroupID);
});
// Set the hash in url to remember last userselection.
$('.group-wrapper ul li').once('group-wrapper-ul-processed', function() {
var fieldGroupNavigationListIndex = $(this).index();
$(this).children('a').click(function() {
var fieldset = $('.group-wrapper fieldset').get(fieldGroupNavigationListIndex);
// Grab the first id, holding the wanted hashurl.
var hashUrl = $(fieldset).attr('id').replace(/^field_group-/, '').split(' ')[0];
window.location.hash = hashUrl;
});
});
}
};
})(jQuery);
})(jQuery);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,15 @@
div.horizontal-tabs {
margin: 0 0 1em 0;
}
.horizontal-tabs ul.horizontal-tabs-list {
border-right: 0;
border-left: 1px solid #dedede;
}
/* Layout of each tab */
.horizontal-tabs ul.horizontal-tabs-list li {
border-right: 0;
border-left: 1px solid #ccc;
float: right;
}
+14 -11
View File
@@ -1,5 +1,3 @@
@CHARSET "UTF-8";
div.horizontal-tabs {
margin: 0 0 1em 0; /* LTR */
padding: 0;
@@ -16,7 +14,7 @@ div.horizontal-tabs {
list-style: none;
list-style-image: none; /* IE6 */
background-color: #dedede;
border-right: 1px solid #dedede;
border-right: 1px solid #dedede; /* LTR */
width: 100%;
height: auto;
clear: both;
@@ -27,19 +25,20 @@ div.horizontal-tabs {
border: 0;
}
.horizontal-tabs-pane>legend {
fieldset.horizontal-tabs-pane > legend,
fieldset.vertical-tabs-pane fieldset.horizontal-tabs-pane > legend {
display: none;
}
/* Layout of each tab */
.horizontal-tabs ul.horizontal-tabs-list li {
background: #eee;
border-right: 1px solid #ccc;
border-right: 1px solid #ccc; /* LTR */
padding: 1px;
padding-top: 0;
padding-top: 0;
margin: 0;
min-width: 5em; /* IE7 */
float: left;
float: left; /* LTR */
}
.horizontal-tabs ul.horizontal-tabs-list li.selected {
background-color: #fff;
@@ -58,6 +57,9 @@ div.horizontal-tabs {
.horizontal-tabs ul.horizontal-tabs-list li:focus {
background-color: #ddd;
}
.horizontal-tabs ul.horizontal-tabs-list :focus {
outline: none;
}
.horizontal-tabs ul.horizontal-tabs-list li a:focus strong,
.horizontal-tabs ul.horizontal-tabs-list li a:active strong,
.horizontal-tabs ul.horizontal-tabs-list li a:hover strong {
@@ -70,7 +72,7 @@ div.horizontal-tabs {
text-decoration: none;
padding: 0.5em 0.6em 0.3em 0.6em;
position:relative;
top: 0px;
top: 0px;
}
.horizontal-tabs ul.horizontal-tabs-list .selected strong {
color: #000;
@@ -84,9 +86,9 @@ div.horizontal-tabs {
}
/**
* tab content
* tab content
*/
div.field-group-htabs-wrapper .field-group-format-wrapper {
div.field-group-htabs-wrapper .field-group-format-wrapper {
clear: both;
padding: 0 0 0.6em;
}
@@ -95,4 +97,5 @@ div.field-group-htabs-wrapper .field-group-format-wrapper {
display: block;
position: absolute;
top: -100000px;
}
width: 100%;
}
+206 -205
View File
@@ -1,205 +1,206 @@
(function ($) {
/**
* This script transforms a set of fieldsets into a stack of horizontal
* tabs. Another tab pane can be selected by clicking on the respective
* tab.
*
* Each tab may have a summary which can be updated by another
* script. For that to work, each fieldset has an associated
* 'horizontalTabCallback' (with jQuery.data() attached to the fieldset),
* which is called every time the user performs an update to a form
* element inside the tab pane.
*/
Drupal.behaviors.horizontalTabs = {
attach: function (context) {
$('.horizontal-tabs-panes', context).once('horizontal-tabs', function () {
var focusID = $(':hidden.horizontal-tabs-active-tab', this).val();
var tab_focus;
// Check if there are some fieldsets that can be converted to horizontal-tabs
var $fieldsets = $('> fieldset', this);
if ($fieldsets.length == 0) {
return;
}
// Create the tab column.
var tab_list = $('<ul class="horizontal-tabs-list"></ul>');
$(this).wrap('<div class="horizontal-tabs clearfix"></div>').before(tab_list);
// Transform each fieldset into a tab.
$fieldsets.each(function (i) {
var horizontal_tab = new Drupal.horizontalTab({
title: $('> legend', this).text(),
fieldset: $(this)
});
horizontal_tab.item.addClass('horizontal-tab-button-' + i);
tab_list.append(horizontal_tab.item);
$(this)
.removeClass('collapsible collapsed')
.addClass('horizontal-tabs-pane')
.data('horizontalTab', horizontal_tab);
if (this.id == focusID) {
tab_focus = $(this);
}
});
$('> li:first', tab_list).addClass('first');
$('> li:last', tab_list).addClass('last');
if (!tab_focus) {
// If the current URL has a fragment and one of the tabs contains an
// element that matches the URL fragment, activate that tab.
if (window.location.hash && $(window.location.hash, this).length) {
tab_focus = $(window.location.hash, this).closest('.horizontal-tabs-pane');
}
else {
tab_focus = $('> .horizontal-tabs-pane:first', this);
}
}
if (tab_focus.length) {
tab_focus.data('horizontalTab').focus();
}
});
}
};
/**
* The horizontal tab object represents a single tab within a tab group.
*
* @param settings
* An object with the following keys:
* - title: The name of the tab.
* - fieldset: The jQuery object of the fieldset that is the tab pane.
*/
Drupal.horizontalTab = function (settings) {
var self = this;
$.extend(this, settings, Drupal.theme('horizontalTab', settings));
this.link.click(function () {
self.focus();
return false;
});
// Keyboard events added:
// Pressing the Enter key will open the tab pane.
this.link.keydown(function(event) {
if (event.keyCode == 13) {
self.focus();
// Set focus on the first input field of the visible fieldset/tab pane.
$("fieldset.horizontal-tabs-pane :input:visible:enabled:first").focus();
return false;
}
});
// Pressing the Enter key lets you leave the tab again.
this.fieldset.keydown(function(event) {
// Enter key should not trigger inside <textarea> to allow for multi-line entries.
if (event.keyCode == 13 && event.target.nodeName != "TEXTAREA") {
// Set focus on the selected tab button again.
$(".horizontal-tab-button.selected a").focus();
return false;
}
});
this.fieldset
.bind('summaryUpdated', function () {
self.updateSummary();
})
.trigger('summaryUpdated');
};
Drupal.horizontalTab.prototype = {
/**
* Displays the tab's content pane.
*/
focus: function () {
this.fieldset
.removeClass('horizontal-tab-hidden')
.siblings('fieldset.horizontal-tabs-pane')
.each(function () {
var tab = $(this).data('horizontalTab');
tab.fieldset.addClass('horizontal-tab-hidden');
tab.item.removeClass('selected');
})
.end()
.siblings(':hidden.horizontal-tabs-active-tab')
.val(this.fieldset.attr('id'));
this.item.addClass('selected');
// Mark the active tab for screen readers.
$('#active-horizontal-tab').remove();
this.link.append('<span id="active-horizontal-tab" class="element-invisible">' + Drupal.t('(active tab)') + '</span>');
},
/**
* Updates the tab's summary.
*/
updateSummary: function () {
this.summary.html(this.fieldset.drupalGetSummary());
},
/**
* Shows a horizontal tab pane.
*/
tabShow: function () {
// Display the tab.
this.item.removeClass('horizontal-tab-hidden');
// Update .first marker for items. We need recurse from parent to retain the
// actual DOM element order as jQuery implements sortOrder, but not as public
// method.
this.item.parent().children('.horizontal-tab-button').removeClass('first')
.filter(':visible:first').addClass('first');
// Display the fieldset.
this.fieldset.removeClass('horizontal-tab-hidden');
// Focus this tab.
this.focus();
return this;
},
/**
* Hides a horizontal tab pane.
*/
tabHide: function () {
// Hide this tab.
this.item.addClass('horizontal-tab-hidden');
// Update .first marker for items. We need recurse from parent to retain the
// actual DOM element order as jQuery implements sortOrder, but not as public
// method.
this.item.parent().children('.horizontal-tab-button').removeClass('first')
.filter(':visible:first').addClass('first');
// Hide the fieldset.
this.fieldset.addClass('horizontal-tab-hidden');
// Focus the first visible tab (if there is one).
var $firstTab = this.fieldset.siblings('.horizontal-tabs-pane:not(.horizontal-tab-hidden):first');
if ($firstTab.length) {
$firstTab.data('horizontalTab').focus();
}
return this;
}
};
/**
* Theme function for a horizontal tab.
*
* @param settings
* An object with the following keys:
* - title: The name of the tab.
* @return
* This function has to return an object with at least these keys:
* - item: The root tab jQuery element
* - link: The anchor tag that acts as the clickable area of the tab
* (jQuery version)
* - summary: The jQuery element that contains the tab summary
*/
Drupal.theme.prototype.horizontalTab = function (settings) {
var tab = {};
tab.item = $('<li class="horizontal-tab-button" tabindex="-1"></li>')
.append(tab.link = $('<a href="#"></a>')
.append(tab.title = $('<strong></strong>').text(settings.title))
.append(tab.summary = $('<span class="summary"></span>')
)
);
return tab;
};
})(jQuery);
(function ($) {
/**
* This script transforms a set of fieldsets into a stack of horizontal
* tabs. Another tab pane can be selected by clicking on the respective
* tab.
*
* Each tab may have a summary which can be updated by another
* script. For that to work, each fieldset has an associated
* 'horizontalTabCallback' (with jQuery.data() attached to the fieldset),
* which is called every time the user performs an update to a form
* element inside the tab pane.
*/
Drupal.behaviors.horizontalTabs = {
attach: function (context) {
$('.horizontal-tabs-panes', context).once('horizontal-tabs', function () {
var focusID = $(':hidden.horizontal-tabs-active-tab', this).val();
var tab_focus;
// Check if there are some fieldsets that can be converted to horizontal-tabs
var $fieldsets = $('> fieldset', this);
if ($fieldsets.length == 0) {
return;
}
// Create the tab column.
var tab_list = $('<ul class="horizontal-tabs-list"></ul>');
$(this).wrap('<div class="horizontal-tabs clearfix"></div>').before(tab_list);
// Transform each fieldset into a tab.
$fieldsets.each(function (i) {
var $legend = $('> legend', this);
$('.element-invisible', $legend).remove();
var horizontal_tab = new Drupal.horizontalTab({
title: $legend.text(),
fieldset: $(this)
});
horizontal_tab.item.addClass('horizontal-tab-button-' + i);
tab_list.append(horizontal_tab.item);
$(this)
.removeClass('collapsible collapsed')
.addClass('horizontal-tabs-pane')
.data('horizontalTab', horizontal_tab);
if (this.id == focusID) {
tab_focus = $(this);
}
});
$('> li:first', tab_list).addClass('first');
$('> li:last', tab_list).addClass('last');
if (!tab_focus) {
// If the current URL has a fragment and one of the tabs contains an
// element that matches the URL fragment, activate that tab.
var hash = window.location.hash.replace(/[=%;,\/]/g, "");
if (hash !== '#' && $(hash, this).length) {
tab_focus = $(hash, this).closest('.horizontal-tabs-pane');
}
else {
tab_focus = $('> .horizontal-tabs-pane:first', this);
}
}
if (tab_focus.length) {
tab_focus.data('horizontalTab').focus();
}
});
}
};
/**
* The horizontal tab object represents a single tab within a tab group.
*
* @param settings
* An object with the following keys:
* - title: The name of the tab.
* - fieldset: The jQuery object of the fieldset that is the tab pane.
*/
Drupal.horizontalTab = function (settings) {
var self = this;
$.extend(this, settings, Drupal.theme('horizontalTab', settings));
this.link.click(function () {
self.focus();
return false;
});
// Keyboard events added:
// Pressing the Enter key will open the tab pane.
this.link.keydown(function(event) {
if (event.keyCode == 13) {
self.focus();
// Set focus on the first input field of the visible fieldset/tab pane.
$("fieldset.horizontal-tabs-pane :input:visible:enabled:first").focus();
return false;
}
});
// Only bind update summary on forms.
if (this.fieldset.drupalGetSummary) {
this.fieldset.bind('summaryUpdated', function() {
self.updateSummary();
}).trigger('summaryUpdated');
}
};
Drupal.horizontalTab.prototype = {
/**
* Displays the tab's content pane.
*/
focus: function () {
this.fieldset
.removeClass('horizontal-tab-hidden')
.siblings('fieldset.horizontal-tabs-pane')
.each(function () {
var tab = $(this).data('horizontalTab');
tab.fieldset.addClass('horizontal-tab-hidden');
tab.item.removeClass('selected');
})
.end()
.siblings(':hidden.horizontal-tabs-active-tab')
.val(this.fieldset.attr('id'));
this.item.addClass('selected');
// Mark the active tab for screen readers.
$('#active-horizontal-tab').remove();
this.link.append('<span id="active-horizontal-tab" class="element-invisible">' + Drupal.t('(active tab)') + '</span>');
},
/**
* Updates the tab's summary.
*/
updateSummary: function () {
this.summary.html(this.fieldset.drupalGetSummary());
},
/**
* Shows a horizontal tab pane.
*/
tabShow: function () {
// Display the tab.
this.item.removeClass('horizontal-tab-hidden');
// Update .first marker for items. We need recurse from parent to retain the
// actual DOM element order as jQuery implements sortOrder, but not as public
// method.
this.item.parent().children('.horizontal-tab-button').removeClass('first')
.filter(':visible:first').addClass('first');
// Display the fieldset.
this.fieldset.removeClass('horizontal-tab-hidden');
// Focus this tab.
this.focus();
return this;
},
/**
* Hides a horizontal tab pane.
*/
tabHide: function () {
// Hide this tab.
this.item.addClass('horizontal-tab-hidden');
// Update .first marker for items. We need recurse from parent to retain the
// actual DOM element order as jQuery implements sortOrder, but not as public
// method.
this.item.parent().children('.horizontal-tab-button').removeClass('first')
.filter(':visible:first').addClass('first');
// Hide the fieldset.
this.fieldset.addClass('horizontal-tab-hidden');
// Focus the first visible tab (if there is one).
var $firstTab = this.fieldset.siblings('.horizontal-tabs-pane:not(.horizontal-tab-hidden):first');
if ($firstTab.length) {
$firstTab.data('horizontalTab').focus();
}
return this;
}
};
/**
* Theme function for a horizontal tab.
*
* @param settings
* An object with the following keys:
* - title: The name of the tab.
* @return
* This function has to return an object with at least these keys:
* - item: The root tab jQuery element
* - link: The anchor tag that acts as the clickable area of the tab
* (jQuery version)
* - summary: The jQuery element that contains the tab summary
*/
Drupal.theme.prototype.horizontalTab = function (settings) {
var tab = {};
var idAttr = settings.fieldset.attr('id');
tab.item = $('<li class="horizontal-tab-button" tabindex="-1"></li>')
.append(tab.link = $('<a href="#' + idAttr + '"></a>')
.append(tab.title = $('<strong></strong>').text(settings.title))
);
// No need to add summary on frontend.
if (settings.fieldset.drupalGetSummary) {
tab.link.append(tab.summary = $('<span class="summary"></span>'))
}
return tab;
};
})(jQuery);
@@ -0,0 +1,13 @@
.multipage-controls-list #edit-actions {
float: right !important;
}
.multipage-button {
float: right !important;
}
.multipage-counter{
float: left !important;
margin-right: 0 !important;
margin-left: 5px !important;
}
+90 -87
View File
@@ -1,125 +1,128 @@
.multipage-controls-list #edit-actions {
float: left !important;
float: left; /* LTR */
}
.multipage-button {
margin-bottom: 1em !important;
margin-top: 0 !important;
float: left !important;
line-height: 36px !important;
margin-bottom: 1em;
margin-top: 0;
float: left; /* LTR */
line-height: 36px;
}
.multipage-button a {
padding-top: 10px !important;
padding-top: 10px;
}
.multipage-counter{
float: right !important;
margin-right: 5px !important;
height: 0 !important;
position: relative !important;
top: 1.8em !important;
line-height: 30px !important;
font: 12px arial,sans-serif !important;
font-weight: bold !important;
color:#666 !important;
.multipage-counter {
float: right; /* LTR */
margin-right: 5px; /* LTR */
height: 0;
position: relative;
top: 1.8em;
line-height: 30px;
font: 12px arial,sans-serif;
font-weight: bold;
color:#666;
}
a.multipage-link-previous{
font: 12px arial,sans-serif !important;
font-weight: bold !important;
color:#666 !important;
-webkit-transition: color 218ms !important;
-moz-transition: color 218ms !important;
-o-transition: color 218ms !important;
transition: color 218ms !important;
a.multipage-link-previous {
font: 12px arial,sans-serif;
font-weight: bold;
color:#666;
-webkit-transition: color 218ms;
-moz-transition: color 218ms;
-o-transition: color 218ms;
transition: color 218ms;
}
a.multipage-link-previous:hover{
text-decoration:none !important;
color: #333 !important;
a.multipage-link-previous:hover {
text-decoration:none;
color: #333;
}
.multipage-controls-list input.form-submit{
.multipage-controls-list input.form-submit {
background:none;
border: none;
border-radius: 2px !important;
-moz-border-radius: 2px !important;
-webkit-border-radius: 2px !important;
border: 1px solid rgba(0, 0, 0, 0.1) !important;
font: 12px arial,sans-serif !important;
font-weight: bold !important;
color: #666 !important;
text-shadow: 0 1px 0 white !important;
padding: 7px 12px !important;
background: -webkit-gradient(linear,0% 40%,0% 70%,from(whiteSmoke),to(#F1F1F1)) !important;
-o-transition: border-top-color 0.218s,border-right-color 0.218s,border-bottom-color 0.218s,border-left-color .218s !important;
-webkit-transition: border-color .218s !important;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border: 1px solid rgba(0, 0, 0, 0.1);
font: 12px arial,sans-serif;
font-weight: bold;
color: #666;
text-shadow: 0 1px 0 white;
padding: 7px 12px;
background: -webkit-gradient(linear,0% 40%,0% 70%,from(whiteSmoke),to(#F1F1F1));
-o-transition: border-top-color 0.218s,border-right-color 0.218s,border-bottom-color 0.218s,border-left-color .218s;
-webkit-transition: border-color .218s;
}
.multipage-controls-list input.form-submit:hover{
color:#333 !important;
box-shadow: 0 1px 1px rgba(0,0,0,0.1) !important;
-webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.1) !important;
border-color: #939393 !important;
.multipage-controls-list input.form-submit:hover {
color:#333;
box-shadow: 0 1px 1px rgba(0,0,0,0.1);
-webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.1);
border-color: #939393;
}
.multipage-controls-list input.form-submit:active{
background: -webkit-gradient(linear,0% 40%,0% 70%,from(#F1F1F1),to(whiteSmoke)) !important;
.multipage-controls-list input.form-submit:active {
background: -webkit-gradient(linear,0% 40%,0% 70%,from(#F1F1F1),to(whiteSmoke));
}
.multipage-controls-list input#edit-submit{
background-image: -moz-linear-gradient(top,#4d90fe,#4787ed) !important;
background-image: -o-linear-gradient(top,#4d90fe,#4787ed) !important;
background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#4787ed)) !important;
color: white !important;
text-shadow: none !important;
text-transform: uppercase !important;
min-width: 79px !important;
.multipage-controls-list input#edit-submit {
background: #4D90FE; /* for non-css3 browsers */
background-image: #4D90FE; /* for non-css3 browsers */
background-image: -o-linear-gradient(top,#4d90fe,#4787ed);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#4D90FE', endColorstr='#4787ED'); /* for IE */
background: -webkit-gradient(linear, center top, center bottom, from(#4D90FE), to(#4787ED)); /* for webkit browsers */
background: -moz-linear-gradient(center top, #4D90FE, #4787ED); /* for firefox 3.6+ */
color: white;
text-shadow: none;
text-transform: uppercase;
min-width: 79px;
}
.multipage-controls-list input#edit-submit:hover{
background-image: -moz-linear-gradient(top,#4d90fe,#357ae8) !important;
background-image: -o-linear-gradient(top,#4d90fe,#357ae8) !important;
background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#357ae8)) !important;
color: white !important;
text-shadow: none !important;
box-shadow: 0 1px 1px rgba(0,0,0,0.2) !important;
-webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.2) !important;
.multipage-controls-list input#edit-submit:hover {
background-image: -moz-linear-gradient(top,#4d90fe,#357ae8);
background-image: -o-linear-gradient(top,#4d90fe,#357ae8);
background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#357ae8));
color: white;
text-shadow: none;
box-shadow: 0 1px 1px rgba(0,0,0,0.2);
-webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.2);
}
.multipage-controls-list input#edit-submit:active{
background: #4D90FE !important;
border-color: #2F5BB7 !important;
.multipage-controls-list input#edit-submit:active {
background: #4D90FE;
border-color: #2F5BB7;
}
.multipage-controls-list input#edit-delete{
background-image: -moz-linear-gradient(top,#dd4b39,#d14836) !important;
background-image: -o-linear-gradient(top,#dd4b39,#d14836) !important;
background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#d14836)) !important;
text-shadow: 0 1px rgba(0, 0, 0, 0.1) !important;
border: 1px solid transparent !important;
color: white !important;
text-shadow: none !important;
.multipage-controls-list input#edit-delete {
background-image: -moz-linear-gradient(top,#dd4b39,#d14836);
background-image: -o-linear-gradient(top,#dd4b39,#d14836);
background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#d14836));
text-shadow: 0 1px rgba(0, 0, 0, 0.1);
border: 1px solid transparent;
color: white;
text-shadow: none;
}
.multipage-controls-list input#edit-delete:hover{
background-image: -moz-linear-gradient(top,#dd4b39,#c53727) !important;
background-image: -o-linear-gradient(top,#dd4b39,#c53727) !important;
background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#c53727)) !important;
.multipage-controls-list input#edit-delete:hover {
background-image: -moz-linear-gradient(top,#dd4b39,#c53727);
background-image: -o-linear-gradient(top,#dd4b39,#c53727);
background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#c53727));
border: 1px solid #B0281A!important;
border-bottom: 1px solid #AF301F!important;
box-shadow: 0 1px 1px rgba(0,0,0,0.2) !important;
-webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.2) !important;
color: white !important;
box-shadow: 0 1px 1px rgba(0,0,0,0.2);
-webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.2);
color: white;
}
.multipage-controls-list input#edit-delete:active{
background-image: -moz-linear-gradient(top,#dd4b39,#b0281a) !important;
background-image: -o-linear-gradient(top,#dd4b39,#b0281a) !important;
background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#b0281a)) !important;
.multipage-controls-list input#edit-delete:active {
background-image: -moz-linear-gradient(top,#dd4b39,#b0281a);
background-image: -o-linear-gradient(top,#dd4b39,#b0281a);
background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#b0281a));
border: 1px solid #992A1b!important;
box-shadow: 0 1px 2px rgba(0,0,0,0.3) !important;
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.3) !important;
box-shadow: 0 1px 2px rgba(0,0,0,0.3);
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.3);
}
+269 -241
View File
@@ -1,241 +1,269 @@
(function ($) {
/**
* This script transforms a set of wrappers into a stack of multipage pages.
* Another pane can be entered by clicking next/previous.
*
*/
Drupal.behaviors.MultiPage = {
attach: function (context) {
$('.multipage-panes', context).once('multipage', function () {
var focusID = $(':hidden.multipage-active-control', this).val();
var paneWithFocus;
// Check if there are some wrappers that can be converted to multipages.
var $panes = $('> div.field-group-multipage', this);
var $form = $panes.parents('form');
if ($panes.length == 0) {
return;
}
// Create the next/previous controls.
var $controls;
// Transform each div.multipage-pane into a multipage with controls.
$panes.each(function () {
$controls = $('<div class="multipage-controls-list"></div>');
$(this).append('<div class="multipage-controls clearfix"></div>').append($controls);
// Check if the submit button needs to move to the latest pane.
if (Drupal.settings.field_group.multipage_move_submit && $('.form-actions').length) {
$('.form-actions', $form).remove().appendTo($($controls, $panes.last()));
}
var multipageControl = new Drupal.multipageControl({
title: $('> .multipage-pane-title', this).text(),
wrapper: $(this),
has_next: $(this).next().length,
has_previous: $(this).prev().length
});
$controls.append(multipageControl.item);
$(this)
.addClass('multipage-pane')
.data('multipageControl', multipageControl);
if (this.id == focusID) {
paneWithFocus = $(this);
}
});
if (!paneWithFocus) {
// If the current URL has a fragment and one of the tabs contains an
// element that matches the URL fragment, activate that tab.
if (window.location.hash && $(window.location.hash, this).length) {
paneWithFocus = $(window.location.hash, this).closest('.multipage-pane');
}
else {
paneWithFocus = $('multipage-open', this).length ? $('multipage-open', this) : $('> .multipage-pane:first', this);
}
}
if (paneWithFocus.length) {
paneWithFocus.data('multipageControl').focus();
}
});
}
};
/**
* The multipagePane object represents a single div as a page.
*
* @param settings
* An object with the following keys:
* - title: The name of the tab.
* - wrapper: The jQuery object of the <div> that is the tab pane.
*/
Drupal.multipageControl = function (settings) {
var self = this;
$.extend(this, settings, Drupal.theme('multipage', settings));
this.nextLink.click(function () {
self.nextPage();
return false;
});
this.previousLink.click(function () {
self.previousPage();
return false;
});
/*
// Keyboard events added:
// Pressing the Enter key will open the tab pane.
this.nextLink.keydown(function(event) {
if (event.keyCode == 13) {
self.focus();
// Set focus on the first input field of the visible wrapper/tab pane.
$("div.multipage-pane :input:visible:enabled:first").focus();
return false;
}
});
// Pressing the Enter key lets you leave the tab again.
this.wrapper.keydown(function(event) {
// Enter key should not trigger inside <textarea> to allow for multi-line entries.
if (event.keyCode == 13 && event.target.nodeName != "TEXTAREA") {
// Set focus on the selected tab button again.
$(".multipage-tab-button.selected a").focus();
return false;
}
});
*/
};
Drupal.multipageControl.prototype = {
/**
* Displays the tab's content pane.
*/
focus: function () {
this.wrapper
.show()
.siblings('div.multipage-pane')
.each(function () {
var tab = $(this).data('multipageControl');
tab.wrapper.hide();
})
.end()
.siblings(':hidden.multipage-active-control')
.val(this.wrapper.attr('id'));
// Mark the active control for screen readers.
$('#active-multipage-control').remove();
this.nextLink.append('<span id="active-multipage-control" class="element-invisible">' + Drupal.t('(active page)') + '</span>');
},
/**
* Continues to the next page or step in the form.
*/
nextPage: function () {
this.wrapper.next().data('multipageControl').focus();
},
/**
* Returns to the previous page or step in the form.
*/
previousPage: function () {
this.wrapper.prev().data('multipageControl').focus();
},
/**
* Shows a horizontal tab pane.
*/
tabShow: function () {
// Display the tab.
this.item.show();
// Update .first marker for items. We need recurse from parent to retain the
// actual DOM element order as jQuery implements sortOrder, but not as public
// method.
this.item.parent().children('.multipage-control').removeClass('first')
.filter(':visible:first').addClass('first');
// Display the wrapper.
this.wrapper.removeClass('multipage-control-hidden').show();
// Focus this tab.
this.focus();
return this;
},
/**
* Hides a horizontal tab pane.
*/
tabHide: function () {
// Hide this tab.
this.item.hide();
// Update .first marker for items. We need recurse from parent to retain the
// actual DOM element order as jQuery implements sortOrder, but not as public
// method.
this.item.parent().children('.multipage-control').removeClass('first')
.filter(':visible:first').addClass('first');
// Hide the wrapper.
this.wrapper.addClass('horizontal-tab-hidden').hide();
// Focus the first visible tab (if there is one).
var $firstTab = this.wrapper.siblings('.multipage-pane:not(.multipage-control-hidden):first');
if ($firstTab.length) {
$firstTab.data('multipageControl').focus();
}
return this;
}
};
/**
* Theme function for a multipage control.
*
* @param settings
* An object with the following keys:
* - title: The name of the tab.
* @return
* This function has to return an object with at least these keys:
* - item: The root tab jQuery element
* - nextLink: The anchor tag that acts as the clickable area of the control
* - nextTitle: The jQuery element that contains the group title
* - previousLink: The anchor tag that acts as the clickable area of the control
* - previousTitle: The jQuery element that contains the group title
*/
Drupal.theme.prototype.multipage = function (settings) {
var controls = {};
controls.item = $('<span class="multipage-button"></span>');
controls.item.append(controls.nextLink = $('<input type="button" class="form-submit multipage-link-next" value="" />').val(controls.nextTitle = Drupal.t('Next page')));
controls.item.append(controls.previousLink = $('<a class="multipage-link-previous" href="#"></a>'));
if (!settings.has_next) {
controls.nextLink.hide();
}
if (settings.has_previous) {
controls.previousLink.append(controls.previousTitle = $('<strong></strong>').text(Drupal.t('Previous')));
}
return controls;
};
Drupal.FieldGroup = Drupal.FieldGroup || {};
Drupal.FieldGroup.Effects = Drupal.FieldGroup.Effects || {};
/**
* Implements Drupal.FieldGroup.processHook().
*/
Drupal.FieldGroup.Effects.processMultipage = {
execute: function (context, settings, type) {
if (type == 'form') {
// Add required fields mark to any element containing required fields
$('div.multipage-pane').each(function(i){
if ($('.error', $(this)).length) {
Drupal.FieldGroup.setGroupWithfocus($(this));
$(this).data('multipageControl').focus();
}
});
}
}
}
})(jQuery);
(function ($) {
/**
* This script transforms a set of wrappers into a stack of multipage pages.
* Another pane can be entered by clicking next/previous.
*
*/
Drupal.behaviors.MultiPage = {
attach: function (context) {
$('.multipage-panes', context).once('multipage', function () {
var focusID = $(':hidden.multipage-active-control', this).val();
var paneWithFocus;
// Check if there are some wrappers that can be converted to multipages.
var $panes = $('> div.field-group-multipage', this);
var $form = $panes.parents('form');
if ($panes.length == 0) {
return;
}
// Create the next/previous controls.
var $controls;
// Transform each div.multipage-pane into a multipage with controls.
$panes.each(function () {
$controls = $('<div class="multipage-controls-list clearfix"></div>');
$(this).append($controls);
// Check if the submit button needs to move to the latest pane.
if (Drupal.settings.field_group.multipage_move_submit && $('.form-actions').length) {
$('.form-actions', $form).remove().appendTo($($controls, $panes.last()));
}
var multipageControl = new Drupal.multipageControl({
title: $('> .multipage-pane-title', this).text(),
wrapper: $(this),
has_next: $(this).next().length,
has_previous: $(this).prev().length
});
$controls.append(multipageControl.item);
$(this)
.addClass('multipage-pane')
.data('multipageControl', multipageControl);
if (this.id == focusID) {
paneWithFocus = $(this);
}
});
if (paneWithFocus === undefined) {
// If the current URL has a fragment and one of the tabs contains an
// element that matches the URL fragment, activate that tab.
var hash = window.location.hash.replace(/[=%;,\/]/g, "");
if (hash !== '#' && $(hash, this).length) {
paneWithFocus = $(window.location.hash, this).closest('.multipage-pane');
}
else {
paneWithFocus = $('multipage-open', this).length ? $('multipage-open', this) : $('> .multipage-pane:first', this);
}
}
if (paneWithFocus !== undefined) {
paneWithFocus.data('multipageControl').focus();
}
});
}
};
/**
* The multipagePane object represents a single div as a page.
*
* @param settings
* An object with the following keys:
* - title: The name of the tab.
* - wrapper: The jQuery object of the <div> that is the tab pane.
*/
Drupal.multipageControl = function (settings) {
var self = this;
var controls = Drupal.theme('multipage', settings);
$.extend(self, settings, controls);
this.nextLink.click(function (e) {
e.preventDefault();
self.nextPage();
});
this.previousLink.click(function (e) {
e.preventDefault();
self.previousPage();
});
/*
// Keyboard events added:
// Pressing the Enter key will open the tab pane.
this.nextLink.keydown(function(event) {
if (event.keyCode == 13) {
self.focus();
// Set focus on the first input field of the visible wrapper/tab pane.
$("div.multipage-pane :input:visible:enabled:first").focus();
return false;
}
});
// Pressing the Enter key lets you leave the tab again.
this.wrapper.keydown(function(event) {
// Enter key should not trigger inside <textarea> to allow for multi-line entries.
if (event.keyCode == 13 && event.target.nodeName != "TEXTAREA") {
// Set focus on the selected tab button again.
$(".multipage-tab-button.selected a").focus();
return false;
}
});
*/
};
Drupal.multipageControl.prototype = {
/**
* Displays the tab's content pane.
*/
focus: function () {
this.wrapper
.show()
.siblings('div.multipage-pane')
.each(function () {
var tab = $(this).data('multipageControl');
tab.wrapper.hide();
})
.end()
.siblings(':hidden.multipage-active-control')
.val(this.wrapper.attr('id'));
// Mark the active control for screen readers.
$('#active-multipage-control').remove();
this.nextLink.after('<span id="active-multipage-control" class="element-invisible">' + Drupal.t('(active page)') + '</span>');
},
/**
* Continues to the next page or step in the form.
*/
nextPage: function () {
this.wrapper.next().data('multipageControl').focus();
$('html, body').scrollTop(this.wrapper.parents('.field-group-multipage-group-wrapper').offset().top);
},
/**
* Returns to the previous page or step in the form.
*/
previousPage: function () {
this.wrapper.prev().data('multipageControl').focus();
$('html, body').scrollTop(this.wrapper.parents('.field-group-multipage-group-wrapper').offset().top);
},
/**
* Shows a horizontal tab pane.
*/
tabShow: function () {
// Display the tab.
this.item.show();
// Update .first marker for items. We need recurse from parent to retain the
// actual DOM element order as jQuery implements sortOrder, but not as public
// method.
this.item.parent().children('.multipage-control').removeClass('first')
.filter(':visible:first').addClass('first');
// Display the wrapper.
this.wrapper.removeClass('multipage-control-hidden').show();
// Focus this tab.
this.focus();
return this;
},
/**
* Hides a horizontal tab pane.
*/
tabHide: function () {
// Hide this tab.
this.item.hide();
// Update .first marker for items. We need recurse from parent to retain the
// actual DOM element order as jQuery implements sortOrder, but not as public
// method.
this.item.parent().children('.multipage-control').removeClass('first')
.filter(':visible:first').addClass('first');
// Hide the wrapper.
this.wrapper.addClass('horizontal-tab-hidden').hide();
// Focus the first visible tab (if there is one).
var $firstTab = this.wrapper.siblings('.multipage-pane:not(.multipage-control-hidden):first');
if ($firstTab.length) {
$firstTab.data('multipageControl').focus();
}
return this;
}
};
/**
* Theme function for a multipage control.
*
* @param settings
* An object with the following keys:
* - title: The name of the tab.
* @return
* This function has to return an object with at least these keys:
* - item: The root tab jQuery element
* - nextLink: The anchor tag that acts as the clickable area of the control
* - nextTitle: The jQuery element that contains the group title
* - previousLink: The anchor tag that acts as the clickable area of the control
* - previousTitle: The jQuery element that contains the group title
*/
Drupal.theme.prototype.multipage = function (settings) {
var controls = {};
controls.item = $('<span class="multipage-button"></span>');
controls.previousLink = $('<input type="button" class="form-submit multipage-link-previous" value="" />');
controls.previousTitle = Drupal.t('Previous page');
controls.item.append(controls.previousLink.val(controls.previousTitle));
controls.nextLink = $('<input type="button" class="form-submit multipage-link-next" value="" />');
controls.nextTitle = Drupal.t('Next page');
controls.item.append(controls.nextLink.val(controls.nextTitle));
if (!settings.has_next) {
controls.nextLink.hide();
}
if (!settings.has_previous) {
controls.previousLink.hide();
}
return controls;
};
Drupal.FieldGroup = Drupal.FieldGroup || {};
Drupal.FieldGroup.Effects = Drupal.FieldGroup.Effects || {};
/**
* Implements Drupal.FieldGroup.processHook().
*/
Drupal.FieldGroup.Effects.processMultipage = {
execute: function (context, settings, type) {
if (type == 'form') {
var $firstErrorItem = false;
// Add required fields mark to any element containing required fields
$('div.multipage-pane').each(function(i){
if ($('.error', $(this)).length) {
// Save first error item, for focussing it.
if (!$firstErrorItem) {
$firstErrorItem = $(this).data('multipageControl');
}
Drupal.FieldGroup.setGroupWithfocus($(this));
$(this).data('multipageControl').focus();
}
});
// Focus on first multipage that has an error.
if ($firstErrorItem) {
$firstErrorItem.focus();
}
}
}
}
})(jQuery);
@@ -0,0 +1,414 @@
<?php
/**
* @file
* Test file for fieldgroup display.
*/
/**
* Group display tests
*/
class GroupDisplayTestCase extends DrupalWebTestCase {
protected $node;
public static function getInfo() {
return array(
'name' => 'Display tests',
'description' => 'Test the field group display.',
'group' => 'Field Group',
);
}
function setUp() {
parent::setUp('field_test', 'field_group', 'field_group_test');
$node = new stdClass();
$node->type = 'article';
$node->title = $this->randomName();
$node->status = 1;
// Create test fields.
$test_fields = array('field_test', 'field_test_2', 'field_no_access');
foreach ($test_fields as $field_name) {
$field = array(
'field_name' => $field_name,
'type' => 'test_field',
'cardinality' => 1,
);
$instance = array(
'field_name' => $field_name,
'entity_type' => 'node',
'bundle' => 'article',
'label' => $this->randomName(),
'display' => array(
'default' => array(
'type' => 'field_test_default',
'settings' => array(
'test_formatter_setting' => $this->randomName(),
),
),
'teaser' => array(
'type' => 'field_test_default',
'settings' => array(
'test_formatter_setting' => $this->randomName(),
),
),
),
);
field_create_field($field);
field_create_instance($instance);
$node->{$field_name}[LANGUAGE_NONE][0]['value'] = mt_rand(1, 127);
}
node_save($node);
$this->node = $node;
}
/**
* Create a new group.
* @param array $data
* Data for the field group.
*/
function createGroup($mode, array $data) {
$group_name = 'group_' . drupal_strtolower($this->randomName(8));
$identifier = $group_name . '|node|article|' . $mode;
$field_group = new stdClass;
$field_group->disabled = FALSE;
$field_group->api_version = 1;
$field_group->identifier = $identifier;
$field_group->group_name = $group_name;
$field_group->entity_type = 'node';
$field_group->bundle = 'article';
$field_group->mode = $mode;
$field_group->parent_name = '';
$field_group->children = $data['children'];
$field_group->data = $data;
drupal_write_record('field_group', $field_group);
ctools_export_crud_enable('field_group', $field_group->identifier);
return $field_group;
}
/**
* Test if an empty formatter.
*/
function testFieldAccess() {
$data = array(
'label' => 'Wrapper',
'weight' => '1',
'children' => array(
0 => 'field_no_access',
),
'format_type' => 'div',
'format_settings' => array(
'label' => 'Link',
'instance_settings' => array(
'required_fields' => 0,
'id' => 'wrapper-id',
'classes' => 'test-class',
'description' => '',
'show_label' => FALSE,
'label_element' => 'h3',
'effect' => 'blink',
'speed' => 'fast',
),
'formatter' => 'open',
),
);
$group = $this->createGroup('default', $data);
$groups = field_group_info_groups('node', 'article', 'default', TRUE);
$this->drupalGet('node/' . $this->node->nid);
// Test if group is not shown.
$this->assertNoFieldByXPath("//div[contains(@id, 'wrapper-id')]", NULL, t('Div that contains fields with no access is not shown.'));
}
/**
* Test the div formatter.
*/
function testDiv() {
$data = array(
'label' => 'Wrapper',
'weight' => '1',
'children' => array(
0 => 'field_test',
),
'format_type' => 'div',
'format_settings' => array(
'label' => 'Link',
'instance_settings' => array(
'required_fields' => 0,
'id' => 'wrapper-id',
'classes' => 'test-class',
'description' => '',
'show_label' => FALSE,
'label_element' => 'h3',
'effect' => 'blink',
'speed' => 'fast',
),
'formatter' => 'open',
),
);
$group = $this->createGroup('default', $data);
$groups = field_group_info_groups('node', 'article', 'default', TRUE);
$this->drupalGet('node/' . $this->node->nid);
// Test group ids and classes.
$this->assertFieldByXPath("//div[contains(@id, 'wrapper-id')]", NULL, t('Wrapper id set on wrapper div'));
$this->assertFieldByXPath("//div[contains(@class, 'test-class')]", NULL, t('Test class set on wrapper div') . 'class="' . $group->group_name . ' test-class');
// Test group label.
$this->assertNoRaw('<h3><span>' . $data['label'] . '</span></h3>', t('Label is not shown'));
// Set show label to true.
$group->data['format_settings']['instance_settings']['show_label'] = TRUE;
drupal_write_record('field_group', $group, array('identifier'));
$groups = field_group_info_groups('node', 'article', 'default', TRUE);
$this->drupalGet('node/' . $this->node->nid);
$this->assertRaw('<h3><span>' . $data['label'] . '</span></h3>', t('Label is shown'));
// Change to collapsible
$group->data['format_settings']['formatter'] = 'collapsible';
drupal_write_record('field_group', $group, array('identifier'));
$groups = field_group_info_groups('node', 'article', 'default', TRUE);
$this->drupalGet('node/' . $this->node->nid);
$this->assertFieldByXPath("//div[contains(@class, 'speed-fast')]", NULL, t('Speed class is set'));
$this->assertFieldByXPath("//div[contains(@class, 'effect-blink')]", NULL, t('Effect class is set'));
}
/**
* Test the horizontal tabs formatter.
*/
function testHorizontalTabs() {
$data = array(
'label' => 'Tab 1',
'weight' => '1',
'children' => array(
0 => 'field_test',
),
'format_type' => 'htab',
'format_settings' => array(
'label' => 'Tab 1',
'instance_settings' => array(
'classes' => 'test-class',
'description' => '',
),
'formatter' => 'open',
),
);
$first_tab = $this->createGroup('default', $data);
$data = array(
'label' => 'Tab 2',
'weight' => '1',
'children' => array(
0 => 'field_test_2',
),
'format_type' => 'htab',
'format_settings' => array(
'label' => 'Tab 1',
'instance_settings' => array(
'classes' => 'test-class-2',
'description' => 'description of second tab',
),
'formatter' => 'closed',
),
);
$second_tab = $this->createGroup('default', $data);
$data = array(
'label' => 'Tabs',
'weight' => '1',
'children' => array(
0 => $first_tab->group_name,
1 => $second_tab->group_name,
),
'format_type' => 'htabs',
'format_settings' => array(
'label' => 'Tab 1',
'instance_settings' => array(
'classes' => 'test-class-wrapper',
),
),
);
$tabs = $this->createGroup('default', $data);
$groups = field_group_info_groups('node', 'article', 'default', TRUE);
$this->drupalGet('node/' . $this->node->nid);
// Test properties.
$this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]", NULL, t('Test class set on tabs wrapper'));
$this->assertFieldByXPath("//fieldset[contains(@class, 'test-class-2')]", NULL, t('Test class set on second tab'));
$this->assertRaw('<div class="fieldset-description">description of second tab</div>', t('Description of tab is shown'));
$this->assertRaw('class="collapsible collapsed test-class-2', t('Second tab is default collapsed'));
// Test if correctly nested
$this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//fieldset[contains(@class, 'test-class')]", NULL, 'First tab is displayed as child of the wrapper.');
$this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//fieldset[contains(@class, 'test-class-2')]", NULL, 'Second tab is displayed as child of the wrapper.');
}
/**
* Test the vertical tabs formatter.
*/
function testVerticalTabs() {
$data = array(
'label' => 'Tab 1',
'weight' => '1',
'children' => array(
0 => 'field_test',
),
'format_type' => 'tab',
'format_settings' => array(
'label' => 'Tab 1',
'instance_settings' => array(
'classes' => 'test-class',
'description' => '',
),
'formatter' => 'open',
),
);
$first_tab = $this->createGroup('default', $data);
$first_tab_id = 'edit-' . $first_tab->group_name;
$data = array(
'label' => 'Tab 2',
'weight' => '1',
'children' => array(
0 => 'field_test_2',
),
'format_type' => 'tab',
'format_settings' => array(
'label' => 'Tab 1',
'instance_settings' => array(
'classes' => 'test-class-2',
'description' => 'description of second tab',
),
'formatter' => 'closed',
),
);
$second_tab = $this->createGroup('default', $data);
$second_tab_id = 'edit-' . $second_tab->group_name;
$data = array(
'label' => 'Tabs',
'weight' => '1',
'children' => array(
0 => $first_tab->group_name,
1 => $second_tab->group_name,
),
'format_type' => 'tabs',
'format_settings' => array(
'label' => 'Tab 1',
'instance_settings' => array(
'classes' => 'test-class-wrapper',
),
),
);
$tabs = $this->createGroup('default', $data);
$groups = field_group_info_groups('node', 'article', 'default', TRUE);
$this->drupalGet('node/' . $this->node->nid);
// Test properties.
$this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]", NULL, t('Test class set on tabs wrapper'));
$this->assertFieldByXPath("//fieldset[contains(@class, 'test-class-2')]", NULL, t('Test class set on second tab'));
$this->assertRaw('<div class="fieldset-description">description of second tab</div>', t('Description of tab is shown'));
$this->assertRaw('class="collapsible collapsed test-class-2', t('Second tab is default collapsed'));
// Test if correctly nested
$this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//fieldset[contains(@id, '$first_tab_id')]", NULL, 'First tab is displayed as child of the wrapper.');
$this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//fieldset[contains(@id, '$second_tab_id')]", NULL, 'Second tab is displayed as child of the wrapper.');
}
/**
* Test the accordion formatter.
*/
function testAccordion() {
$data = array(
'label' => 'Accordion item 1',
'weight' => '1',
'children' => array(
0 => 'field_test',
),
'format_type' => 'accordion-item',
'format_settings' => array(
'label' => 'Accordion item 1',
'instance_settings' => array(
'classes' => 'test-class',
),
'formatter' => 'closed',
),
);
$first_item = $this->createGroup('default', $data);
$first_item_id = 'node_article_full_' . $first_item->group_name;
$data = array(
'label' => 'Accordion item 2',
'weight' => '1',
'children' => array(
0 => 'field_test_2',
),
'format_type' => 'accordion-item',
'format_settings' => array(
'label' => 'Tab 2',
'instance_settings' => array(
'classes' => 'test-class-2',
),
'formatter' => 'open',
),
);
$second_item = $this->createGroup('default', $data);
$second_item_id = 'node_article_full_' . $second_item->group_name;
$data = array(
'label' => 'Accordion',
'weight' => '1',
'children' => array(
0 => $first_item->group_name,
1 => $second_item->group_name,
),
'format_type' => 'accordion',
'format_settings' => array(
'label' => 'Tab 1',
'instance_settings' => array(
'classes' => 'test-class-wrapper',
'effect' => 'bounceslide'
),
),
);
$accordion = $this->createGroup('default', $data);
$groups = field_group_info_groups('node', 'article', 'default', TRUE);
$this->drupalGet('node/' . $this->node->nid);
// Test properties.
$this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]", NULL, t('Test class set on tabs wrapper'));
$this->assertFieldByXPath("//div[contains(@class, 'effect-bounceslide')]", NULL, t('Correct effect is set on the accordion'));
$this->assertFieldByXPath("//div[contains(@class, 'test-class')]", NULL, t('Accordion item with test-class is shown'));
$this->assertFieldByXPath("//div[contains(@class, 'test-class-2')]", NULL, t('Accordion item with test-class-2 is shown'));
$this->assertFieldByXPath("//h3[contains(@class, 'field-group-accordion-active')]", NULL, t('Accordion item 2 was set active'));
// Test if correctly nested
$this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//div[contains(@class, 'test-class')]", NULL, 'First item is displayed as child of the wrapper.');
$this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//div[contains(@class, 'test-class-2')]", NULL, 'Second item is displayed as child of the wrapper.');
}
}
@@ -2,53 +2,39 @@
/**
* @file
* Unit test file for groups.
*
* @todo - fill along if we know more.
*
* - nest a group under another group and see if parent_name is first group
* - nest a group under second group and see if parent_name is second group
* - settings: open f and verify on front-end (classes)
* - settings: collapsible f and verify on front-end (classes)
* - settings: collapsed f and verify on front-end (classes)
* - settings: vertical tabs and verify on front-end (classes)
* - settings: horizontal item and verify on front-end (classes)
* - settings: vertical item and verify on front-end (classes)
* - settings: hidden (simple div) and verify on front-end (classes)
* - settings: label and verify on front-end
* - delete a fieldgroup - make sure we have a couple with the same name
* and make sure the right one is deleted!
* Test file for fieldgroup UI.
*/
/**
* Group UI tests.
*/
class GroupUITestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Group UI tests',
'description' => 'Test the group UI functionality.',
'group' => 'Field group',
'name' => 'UI tests',
'description' => 'Test the Field Group UI.',
'group' => 'Field Group',
);
}
function setUp() {
parent::setUp('field_test', 'field_group');
parent::setUp('field_test', 'field_group', 'field_group_test');
// Create test user.
$admin_user = $this->drupalCreateUser(array('administer content types'));
$admin_user = $this->drupalCreateUser(array('administer content types', 'administer nodes', 'access administration pages', 'bypass node access', 'administer fields'));
$this->drupalLogin($admin_user);
}
/**
* Test the creation a group on the article content type.
*/
function createGroup() {
// Create random group name.
$this->group_label = $this->randomName(8);
$this->group_name_input = drupal_strtolower($this->randomName(8));
$this->group_name = 'group_' . $this->group_name_input;
}
/**
* Creates a group on the article content type.
*/
function createGroup() {
// Setup new group.
$group = array(
@@ -57,7 +43,8 @@ class GroupUITestCase extends DrupalWebTestCase {
);
// Add new group on the 'Manage fields' page.
$this->drupalPost('admin/structure/types/manage/article/fields', $group, t('Save'));
$this->drupalPost('admin/structure/types/manage/article/fields', $group, t('Save'));
$this->assertRaw(t('New group %label successfully created.', array('%label' => $this->group_label)), t('Group message displayed on screen.'));
// Test if group is in the $groups array.
@@ -65,7 +52,7 @@ class GroupUITestCase extends DrupalWebTestCase {
$this->assertTrue(array_key_exists($this->group_name, $groups), t('Group found in groups array'));
// Add new group on the 'Manage display' page.
$this->drupalPost('admin/structure/types/manage/article/display', $group, t('Save'));
$this->drupalPost('admin/structure/types/manage/article/display', $group, t('Save'));
$this->assertRaw(t('New group %label successfully created.', array('%label' => $this->group_label)), t('Group message displayed on screen.'));
// Test if group is in the $groups array.
@@ -77,6 +64,7 @@ class GroupUITestCase extends DrupalWebTestCase {
* Delete a group.
*/
function deleteGroup() {
$this->drupalPost('admin/structure/types/manage/article/groups/' . $this->group_name . '/delete/form', array(), t('Delete'));
$this->assertRaw(t('The group %label has been deleted from the %article content type.', array('%label' => $this->group_label, '%article' => 'Article')), t('Group removal message displayed on screen.'));
@@ -104,13 +92,18 @@ class GroupUITestCase extends DrupalWebTestCase {
* Nest a field underneath a group.
*/
function testNestField() {
$this->createGroup();
$edit = array(
'fields[field_image][parent]' => $this->group_name,
);
$this->drupalPost('admin/structure/types/manage/article/fields', $edit, t('Save'));
$this->assertRaw(t('Your settings have been saved.'), t('Settings saved'));
$groups = field_group_info_groups('node', 'article', 'form', TRUE);
$this->assertTrue(in_array('field_image', $groups[$this->group_name]->children), t('Image is a child of %group', array('%group' => $this->group_label)));
$this->assertTrue(in_array('field_image', $groups[$this->group_name]->children), t('Image is a child of %group', array('%group' => $this->group_name)));
}
}
@@ -0,0 +1,13 @@
name = "Field Group Test"
description = "Test module for Field Group"
core = "7.x"
package = Fields
hidden = TRUE
; Information added by Drupal.org packaging script on 2017-11-03
version = "7.x-1.6"
core = "7.x"
project = "field_group"
datestamp = "1509751991"
@@ -0,0 +1,17 @@
<?php
/**
* @file
* Fieldgroup test module.
*/
/**
* Implements hook_field_access().
*/
function field_group_test_field_access($op, $field, $entity_type, $entity, $account) {
// Set access to false for field_no_access.
if ($op == 'view' && $field['field_name'] == 'field_no_access') {
return FALSE;
}
}