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