Skip to content

Commit b579749

Browse files
feat(wizard): Add ability to set initial focus component per page
1 parent e7e02f9 commit b579749

File tree

4 files changed

+87
-13
lines changed

4 files changed

+87
-13
lines changed

src/wizard/examples/wizard.js

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,8 @@
7878
</form>
7979
</pf-wizard-substep>
8080
</pf-wizard-step>
81-
<pf-wizard-step step-title="Second Step" next-tooltip="secondStepNextTooltip" prev-tooltip="secondStepPrevTooltip" substeps="false" step-id="configuration" step-priority="1" show-review="true" review-template="review-second-template.html" >
82-
<form class="form-horizontal">
83-
<h3>Wizards should make use of substeps consistently throughout (either using them or not using them). This is an example only.</h3>
84-
<pf-form-group pf-label="Lorem" pf-label-class="col-sm-3 col-md-2" pf-input-class="col-sm-9 col-md-10" >
85-
<input id="new-lorem" name="lorem" ng-model="data.lorem" type="text"/>
86-
</pf-form-group>
87-
<pf-form-group pf-label="Ipsum" pf-label-class="col-sm-3 col-md-2" pf-input-class="col-sm-9 col-md-10" >
88-
<input id="new-ipsum" name="ipsum" ng-model="data.ipsum" type="text" />
89-
</pf-form-group>
90-
</form>
91-
</pf-wizard-step>
81+
<div ng-include="'second-step.html'">
82+
</div>
9283
<pf-wizard-step step-title="Review" next-tooltip="reviewStepNextTooltip" prev-tooltip="reviewStepPrevTooltip" substeps="true" step-id="review" step-priority="2">
9384
<div ng-include="'summary.html'"></div>
9485
<div ng-include="'deployment.html'"></div>
@@ -97,7 +88,14 @@
9788
</file>
9889
<file name="detail-page.html">
9990
<div ng-controller="DetailsGeneralController">
100-
<pf-wizard-substep step-title="General" next-enabled="detailsGeneralComplete" step-id="details-general" step-priority="0" on-show="onShow" review-template="{{reviewTemplate}}" show-review-details="true">
91+
<pf-wizard-substep step-title="General"
92+
next-enabled="detailsGeneralComplete"
93+
step-id="details-general"
94+
step-priority="0"
95+
on-show="onShow"
96+
focus-selectors="focusSelectors"
97+
review-template="{{reviewTemplate}}"
98+
show-review-details="true">
10199
<form class="form-horizontal">
102100
<pf-form-group pf-label="Name" pf-label-class="col-sm-3 col-md-2" pf-input-class="col-sm-9 col-md-10" required>
103101
<input id="new-name" name="name" ng-model="data.name" type="text" ng-change="updateName()" required/>
@@ -137,6 +135,21 @@
137135
</form>
138136
</div>
139137
</file>
138+
<file name="second-step.html">
139+
<div ng-controller="SecondStepController">
140+
<pf-wizard-step focus-selectors="focusSelectors" step-title="Second Step" next-tooltip="secondStepNextTooltip" prev-tooltip="secondStepPrevTooltip" substeps="false" step-id="configuration" step-priority="1" show-review="true" review-template="review-second-template.html" >
141+
<form class="form-horizontal">
142+
<h3>Wizards should make use of substeps consistently throughout (either using them or not using them). This is an example only.</h3>
143+
<pf-form-group pf-label="Lorem" pf-label-class="col-sm-3 col-md-2" pf-input-class="col-sm-9 col-md-10" >
144+
<input id="step-two-new-lorem" name="lorem" ng-model="data.lorem" type="text"/>
145+
</pf-form-group>
146+
<pf-form-group pf-label="Ipsum" pf-label-class="col-sm-3 col-md-2" pf-input-class="col-sm-9 col-md-10" >
147+
<input id="step-two-new-ipsum" name="ipsum" ng-model="data.ipsum" type="text" />
148+
</pf-form-group>
149+
</form>
150+
</pf-wizard-step>
151+
</div>
152+
</file>
140153
<file name="summary.html">
141154
<div ng-controller="SummaryController">
142155
<pf-wizard-substep step-title="Summary" step-id="review-summary" step-priority="0" next-enabled="true" prev-enabled="true" ok-to-nav-away="true" wz-disabled="false" on-show="onShow">
@@ -262,7 +275,7 @@
262275
263276
$scope.reviewTemplate = "review-template.html";
264277
$scope.detailsGeneralComplete = false;
265-
278+
$scope.focusSelectors = ['#new-name'];
266279
$scope.onShow = function() { };
267280
268281
$scope.updateName = function() {
@@ -288,6 +301,14 @@
288301
}
289302
]);
290303
304+
angular.module('patternfly.wizard').controller('SecondStepController', ['$rootScope', '$scope',
305+
function ($rootScope, $scope) {
306+
'use strict';
307+
308+
$scope.focusSelectors = ['.invalid-classname', '#step-two-new-lorem'];
309+
}
310+
]);
311+
291312
angular.module('patternfly.wizard').controller('SummaryController', ['$rootScope', '$scope', '$timeout',
292313
function ($rootScope, $scope, $timeout) {
293314
'use strict';

src/wizard/wizard-step.component.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* @param {string=} description The step description (optional)
2121
* @param {object} wizardData Data passed to the step that is shared by the entire wizard
2222
* @param {function()=} onShow The function called when the wizard shows this step
23+
* @param {object=} focusSelectors Array of selectors to be used (in the order given) to find the initial focus component for the page
2324
* @param {boolean=} showReview Indicates whether review information should be displayed for this step when the review step is reached
2425
* @param {boolean=} showReviewDetails Indicators whether the review information should be expanded by default when the review step is reached
2526
* @param {string=} reviewTemplate The template that should be used for the review details screen
@@ -41,6 +42,7 @@ angular.module('patternfly.wizard').component('pfWizardStep', {
4142
description: '@',
4243
wizardData: '=',
4344
onShow: '=?',
45+
focusSelectors: '<?',
4446
showReview: '@?',
4547
showReviewDetails: '@?',
4648
reviewTemplate: '@?'
@@ -217,6 +219,8 @@ angular.module('patternfly.wizard').component('pfWizardStep', {
217219
};
218220

219221
ctrl.goTo = function (step) {
222+
var focusElement = null;
223+
220224
if (ctrl.wizard.isWizardDone() || !step.okToNavAway || step === ctrl.selectedStep) {
221225
return;
222226
}
@@ -232,6 +236,29 @@ angular.module('patternfly.wizard').component('pfWizardStep', {
232236
ctrl.selectedStep.onShow();
233237
}
234238

239+
// Give time for onShow to do its thing (maybe update the selectors), then time to display the elements
240+
$timeout(function () {
241+
if (step.focusSelectors) {
242+
_.find(step.focusSelectors, function (selector) {
243+
return focusElement = document.querySelector(selector);
244+
});
245+
}
246+
247+
// Default to next button if it is enabled
248+
if (!focusElement && step.nextEnabled) {
249+
focusElement = document.querySelector('.wizard-pf-next');
250+
}
251+
252+
// Use cancel button if we haven't found anything else to set focus on
253+
if (!focusElement) {
254+
focusElement = document.querySelector('.wizard-pf-cancel');
255+
}
256+
257+
if (focusElement) {
258+
focusElement.focus();
259+
}
260+
}, 300);
261+
235262
ctrl.currentStep = step.stepTitle;
236263

237264
firstRun = false;

src/wizard/wizard-substep.component.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* @param {string=} description The step description
1717
* @param {object} wizardData Data passed to the step that is shared by the entire wizard
1818
* @param {function()=} onShow The function called when the wizard shows this step
19+
* @param {object=} focusSelectors Array of selectors to be used (in the order given) to find the initial focus component for the page
1920
* @param {boolean=} showReviewDetails Indicators whether the review information should be expanded by default when the review step is reached
2021
* @param {string=} reviewTemplate The template that should be used for the review details screen
2122
*/
@@ -33,6 +34,7 @@ angular.module('patternfly.wizard').component('pfWizardSubstep', {
3334
description: '@',
3435
wizardData: '=',
3536
onShow: '=?',
37+
focusSelectors: '<?',
3638
showReviewDetails: '@?',
3739
reviewTemplate: '@?'
3840
},

src/wizard/wizard.component.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ angular.module('patternfly.wizard').component('pfWizard', {
165165
};
166166

167167
ctrl.goTo = function (step, resetStepNav) {
168+
var focusElement = null;
169+
168170
if (ctrl.wizardDone || (ctrl.selectedStep && !ctrl.selectedStep.okToNavAway) || step === ctrl.selectedStep) {
169171
return;
170172
}
@@ -183,6 +185,28 @@ angular.module('patternfly.wizard').component('pfWizard', {
183185
if (angular.isFunction(step.onShow)) {
184186
step.onShow();
185187
}
188+
// Give time for onShow to do its thing (maybe update the selectors), then time to display the elements
189+
$timeout(function () {
190+
if (step.focusSelectors) {
191+
_.find(step.focusSelectors, function (selector) {
192+
return focusElement = document.querySelector(selector);
193+
});
194+
}
195+
196+
// Default to next button if it is enabled
197+
if (!focusElement && step.nextEnabled) {
198+
focusElement = document.querySelector('.wizard-pf-next');
199+
}
200+
201+
// Use cancel button if we haven't found anything else to set focus on
202+
if (!focusElement) {
203+
focusElement = document.querySelector('.wizard-pf-cancel');
204+
}
205+
206+
if (focusElement) {
207+
focusElement.focus();
208+
}
209+
}, 300);
186210
}, 100);
187211

188212
// Make sure current step is not undefined

0 commit comments

Comments
 (0)