root / drupal7 / sites / all / modules / field_group / multipage / multipage.js @ a84ddea4
1 |
(function ($) { |
---|---|
2 |
|
3 |
/**
|
4 |
* This script transforms a set of wrappers into a stack of multipage pages.
|
5 |
* Another pane can be entered by clicking next/previous.
|
6 |
*
|
7 |
*/
|
8 |
Drupal.behaviors.MultiPage = { |
9 |
attach: function (context) { |
10 |
$('.multipage-panes', context).once('multipage', function () { |
11 |
|
12 |
var focusID = $(':hidden.multipage-active-control', this).val(); |
13 |
var paneWithFocus;
|
14 |
|
15 |
// Check if there are some wrappers that can be converted to multipages.
|
16 |
var $panes = $('> div.field-group-multipage', this); |
17 |
var $form = $panes.parents('form'); |
18 |
if ($panes.length == 0) { |
19 |
return;
|
20 |
} |
21 |
|
22 |
// Create the next/previous controls.
|
23 |
var $controls; |
24 |
|
25 |
// Transform each div.multipage-pane into a multipage with controls.
|
26 |
$panes.each(function () { |
27 |
|
28 |
$controls = $('<div class="multipage-controls-list clearfix"></div>'); |
29 |
$(this).append($controls); |
30 |
|
31 |
// Check if the submit button needs to move to the latest pane.
|
32 |
if (Drupal.settings.field_group.multipage_move_submit && $('.form-actions').length) { |
33 |
$('.form-actions', $form).remove().appendTo($($controls, $panes.last())); |
34 |
} |
35 |
|
36 |
var multipageControl = new Drupal.multipageControl({ |
37 |
title: $('> .multipage-pane-title', this).text(), |
38 |
wrapper: $(this), |
39 |
has_next: $(this).next().length, |
40 |
has_previous: $(this).prev().length |
41 |
}); |
42 |
|
43 |
$controls.append(multipageControl.item);
|
44 |
$(this) |
45 |
.addClass('multipage-pane')
|
46 |
.data('multipageControl', multipageControl);
|
47 |
|
48 |
if (this.id == focusID) { |
49 |
paneWithFocus = $(this); |
50 |
} |
51 |
|
52 |
}); |
53 |
|
54 |
if (paneWithFocus === undefined) { |
55 |
// If the current URL has a fragment and one of the tabs contains an
|
56 |
// element that matches the URL fragment, activate that tab.
|
57 |
if (window.location.hash && window.location.hash !== '#' && $(window.location.hash, this).length) { |
58 |
paneWithFocus = $(window.location.hash, this).closest('.multipage-pane'); |
59 |
} |
60 |
else {
|
61 |
paneWithFocus = $('multipage-open', this).length ? $('multipage-open', this) : $('> .multipage-pane:first', this); |
62 |
} |
63 |
} |
64 |
if (paneWithFocus !== undefined) { |
65 |
paneWithFocus.data('multipageControl').focus();
|
66 |
} |
67 |
}); |
68 |
} |
69 |
}; |
70 |
|
71 |
/**
|
72 |
* The multipagePane object represents a single div as a page.
|
73 |
*
|
74 |
* @param settings
|
75 |
* An object with the following keys:
|
76 |
* - title: The name of the tab.
|
77 |
* - wrapper: The jQuery object of the <div> that is the tab pane.
|
78 |
*/
|
79 |
Drupal.multipageControl = function (settings) { |
80 |
var self = this; |
81 |
var controls = Drupal.theme('multipage', settings); |
82 |
$.extend(self, settings, controls);
|
83 |
|
84 |
this.nextLink.click(function () { |
85 |
self.nextPage(); |
86 |
return false; |
87 |
}); |
88 |
|
89 |
this.previousLink.click(function () { |
90 |
self.previousPage(); |
91 |
return false; |
92 |
}); |
93 |
|
94 |
/*
|
95 |
// Keyboard events added:
|
96 |
// Pressing the Enter key will open the tab pane.
|
97 |
this.nextLink.keydown(function(event) {
|
98 |
if (event.keyCode == 13) {
|
99 |
self.focus();
|
100 |
// Set focus on the first input field of the visible wrapper/tab pane.
|
101 |
$("div.multipage-pane :input:visible:enabled:first").focus();
|
102 |
return false;
|
103 |
}
|
104 |
});
|
105 |
|
106 |
// Pressing the Enter key lets you leave the tab again.
|
107 |
this.wrapper.keydown(function(event) {
|
108 |
// Enter key should not trigger inside <textarea> to allow for multi-line entries.
|
109 |
if (event.keyCode == 13 && event.target.nodeName != "TEXTAREA") {
|
110 |
// Set focus on the selected tab button again.
|
111 |
$(".multipage-tab-button.selected a").focus();
|
112 |
return false;
|
113 |
}
|
114 |
});
|
115 |
*/
|
116 |
}; |
117 |
|
118 |
Drupal.multipageControl.prototype = { |
119 |
|
120 |
/**
|
121 |
* Displays the tab's content pane.
|
122 |
*/
|
123 |
focus: function () { |
124 |
this.wrapper
|
125 |
.show() |
126 |
.siblings('div.multipage-pane')
|
127 |
.each(function () {
|
128 |
var tab = $(this).data('multipageControl'); |
129 |
tab.wrapper.hide(); |
130 |
}) |
131 |
.end() |
132 |
.siblings(':hidden.multipage-active-control')
|
133 |
.val(this.wrapper.attr('id')); |
134 |
// Mark the active control for screen readers.
|
135 |
$('#active-multipage-control').remove(); |
136 |
this.nextLink.after('<span id="active-multipage-control" class="element-invisible">' + Drupal.t('(active page)') + '</span>'); |
137 |
}, |
138 |
|
139 |
/**
|
140 |
* Continues to the next page or step in the form.
|
141 |
*/
|
142 |
nextPage: function () { |
143 |
this.wrapper.next().data('multipageControl').focus(); |
144 |
$('html, body').scrollTop(this.wrapper.parents('.field-group-multipage-group-wrapper').offset().top); |
145 |
}, |
146 |
|
147 |
/**
|
148 |
* Returns to the previous page or step in the form.
|
149 |
*/
|
150 |
previousPage: function () { |
151 |
this.wrapper.prev().data('multipageControl').focus(); |
152 |
$('html, body').scrollTop(this.wrapper.parents('.field-group-multipage-group-wrapper').offset().top); |
153 |
}, |
154 |
|
155 |
/**
|
156 |
* Shows a horizontal tab pane.
|
157 |
*/
|
158 |
tabShow: function () { |
159 |
// Display the tab.
|
160 |
this.item.show();
|
161 |
// Update .first marker for items. We need recurse from parent to retain the
|
162 |
// actual DOM element order as jQuery implements sortOrder, but not as public
|
163 |
// method.
|
164 |
this.item.parent().children('.multipage-control').removeClass('first') |
165 |
.filter(':visible:first').addClass('first'); |
166 |
// Display the wrapper.
|
167 |
this.wrapper.removeClass('multipage-control-hidden').show(); |
168 |
// Focus this tab.
|
169 |
this.focus();
|
170 |
return this; |
171 |
}, |
172 |
|
173 |
/**
|
174 |
* Hides a horizontal tab pane.
|
175 |
*/
|
176 |
tabHide: function () { |
177 |
// Hide this tab.
|
178 |
this.item.hide();
|
179 |
// Update .first marker for items. We need recurse from parent to retain the
|
180 |
// actual DOM element order as jQuery implements sortOrder, but not as public
|
181 |
// method.
|
182 |
this.item.parent().children('.multipage-control').removeClass('first') |
183 |
.filter(':visible:first').addClass('first'); |
184 |
// Hide the wrapper.
|
185 |
this.wrapper.addClass('horizontal-tab-hidden').hide(); |
186 |
// Focus the first visible tab (if there is one).
|
187 |
var $firstTab = this.wrapper.siblings('.multipage-pane:not(.multipage-control-hidden):first'); |
188 |
if ($firstTab.length) { |
189 |
$firstTab.data('multipageControl').focus(); |
190 |
} |
191 |
return this; |
192 |
} |
193 |
}; |
194 |
|
195 |
/**
|
196 |
* Theme function for a multipage control.
|
197 |
*
|
198 |
* @param settings
|
199 |
* An object with the following keys:
|
200 |
* - title: The name of the tab.
|
201 |
* @return
|
202 |
* This function has to return an object with at least these keys:
|
203 |
* - item: The root tab jQuery element
|
204 |
* - nextLink: The anchor tag that acts as the clickable area of the control
|
205 |
* - nextTitle: The jQuery element that contains the group title
|
206 |
* - previousLink: The anchor tag that acts as the clickable area of the control
|
207 |
* - previousTitle: The jQuery element that contains the group title
|
208 |
*/
|
209 |
Drupal.theme.prototype.multipage = function (settings) { |
210 |
|
211 |
var controls = {};
|
212 |
controls.item = $('<span class="multipage-button"></span>'); |
213 |
|
214 |
controls.previousLink = $('<input type="button" class="form-submit multipage-link-previous" value="" />'); |
215 |
controls.previousTitle = Drupal.t('Previous page');
|
216 |
controls.item.append(controls.previousLink.val(controls.previousTitle)); |
217 |
|
218 |
controls.nextLink = $('<input type="button" class="form-submit multipage-link-next" value="" />'); |
219 |
controls.nextTitle = Drupal.t('Next page');
|
220 |
controls.item.append(controls.nextLink.val(controls.nextTitle)); |
221 |
|
222 |
if (!settings.has_next) {
|
223 |
controls.nextLink.hide(); |
224 |
} |
225 |
if (!settings.has_previous) {
|
226 |
controls.previousLink.hide(); |
227 |
} |
228 |
|
229 |
return controls;
|
230 |
}; |
231 |
|
232 |
|
233 |
Drupal.FieldGroup = Drupal.FieldGroup || {}; |
234 |
Drupal.FieldGroup.Effects = Drupal.FieldGroup.Effects || {}; |
235 |
|
236 |
/**
|
237 |
* Implements Drupal.FieldGroup.processHook().
|
238 |
*/
|
239 |
Drupal.FieldGroup.Effects.processMultipage = { |
240 |
execute: function (context, settings, type) { |
241 |
if (type == 'form') { |
242 |
|
243 |
var $firstErrorItem = false; |
244 |
|
245 |
// Add required fields mark to any element containing required fields
|
246 |
$('div.multipage-pane').each(function(i){ |
247 |
if ($('.error', $(this)).length) { |
248 |
|
249 |
// Save first error item, for focussing it.
|
250 |
if (!$firstErrorItem) { |
251 |
$firstErrorItem = $(this).data('multipageControl'); |
252 |
} |
253 |
|
254 |
Drupal.FieldGroup.setGroupWithfocus($(this)); |
255 |
$(this).data('multipageControl').focus(); |
256 |
} |
257 |
}); |
258 |
|
259 |
// Focus on first multipage that has an error.
|
260 |
if ($firstErrorItem) { |
261 |
$firstErrorItem.focus();
|
262 |
} |
263 |
|
264 |
} |
265 |
} |
266 |
} |
267 |
|
268 |
})(jQuery); |