govuk_frontend_toolkit 1.7.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,8 @@
1
+ # 2.0.0
2
+
3
+ - Add support for selection-button events to be document-level https://github.com/alphagov/govuk_frontend_toolkit/pull/139
4
+ - The `GOVUK.selectionButtons` interface is now deprecated. Details are in the [README](https://github.com/alphagov/govuk_frontend_toolkit#deprecated-functionality).
5
+
1
6
  # 1.7.0
2
7
 
3
8
  - Create new grid helpers for creating grid layouts
data/app/assets/README.md CHANGED
@@ -862,7 +862,7 @@ and stop the elements before they get to the bottom.
862
862
 
863
863
  ## Selection buttons
864
864
 
865
- Script to support a specific design of radio buttons and checkboxes wrapped in `<label>` tags:
865
+ Script to support a design of radio buttons and checkboxes requiring them to be wrapped in `<label>` tags:
866
866
 
867
867
  <label>
868
868
  <input type="radio" name="size" value="medium" />
@@ -870,21 +870,55 @@ Script to support a specific design of radio buttons and checkboxes wrapped in `
870
870
 
871
871
  When the input is focused or its `checked` attribute is set, classes are added to their parent labels so their styling can show this.
872
872
 
873
- To apply this behaviour to elements with the above HTML pattern, call the `GOVUK.selectionButtons` function with their inputs:
873
+ ### Usage
874
+
875
+ #### GOVUK.SelectionButtons
876
+
877
+ To apply this behaviour to elements with the above HTML pattern, call the `GOVUK.SelectionButtons` constructor with their inputs:
874
878
 
875
879
  ```
876
880
  var $buttons = $("label input[type='radio'], label input[type='checkbox']");
877
- GOVUK.selectionButtons($buttons);
881
+ var selectionButtons = new GOVUK.SelectionButtons($buttons);
882
+ ```
883
+
884
+ You can also call `GOVUK.SelectionButtons` with a selector:
885
+
878
886
  ```
887
+ var selectionButtons = new GOVUK.SelectionButtons("label input[type='radio'], label input[type='checkbox']");
888
+ ```
889
+
890
+ This will bind all events to the document, meaning any changes to content (for example, by AJAX) will not effect the button's behaviour.
879
891
 
880
- The classes that get added can be passed in as options:
892
+ The classes that get added to the `<label>` tags can be passed in as options:
881
893
 
882
894
  ```
883
895
  var $buttons = $("label input[type='radio'], label input[type='checkbox']");
884
- GOVUK.selectionButtons($buttons, { focusedClass : 'selectable-focused', selectedClass : 'selectable-selected' });
896
+ var selectionButtons = new GOVUK.SelectionButtons($buttons, { focusedClass : 'selectable-focused', selectedClass : 'selectable-selected' });
897
+
898
+ var selectionButtons = new GOVUK.SelectionButtons("label input[type='radio'], label input[type='checkbox']", { focusedClass : 'selectable-focused', selectedClass : 'selectable-selected' });
899
+ ```
900
+
901
+ #### destroy method
902
+
903
+ The returned instance object includes a `destroy` method to remove all events bound to either the elements or the document.
904
+
905
+ Using any of the `selectionButtons` objects created above, it can be called like so:
906
+
907
+ ```
908
+ selectionButtons.destroy();
909
+ ```
910
+
911
+ ### Deprecated functionality
912
+
913
+ The previous method of calling selection buttons is now deprecated. If you need to call them using this method, you will need to define this function:
914
+
915
+ ```
916
+ GOVUK.selectionButtons = function (elms, opts) {
917
+ new GOVUK.SelectionButtons(elms, opts);
918
+ };
885
919
  ```
886
920
 
887
- Note that `GOVUK.selectionButtons` and the constructors it wraps, `GOVUK.RadioButtons` and `GOVUK.CheckboxButtons` use the `bind.js` polyfill.
921
+ This method will mean the `destroy` method is not available to call.
888
922
 
889
923
  ## Licence
890
924
 
@@ -1 +1 @@
1
- 1.7.0
1
+ 2.0.0
@@ -5,8 +5,9 @@
5
5
 
6
6
  if (typeof GOVUK === 'undefined') { root.GOVUK = {}; }
7
7
 
8
- var BaseButtons = function ($elms, opts) {
9
- this.$elms = $elms;
8
+ var SelectionButtons = function (elmsOrSelector, opts) {
9
+ var $elms;
10
+
10
11
  this.selectedClass = 'selected';
11
12
  this.focusedClass = 'focused';
12
13
  if (opts !== undefined) {
@@ -14,124 +15,97 @@
14
15
  this[optionName] = optionObj;
15
16
  }.bind(this));
16
17
  }
17
- this.setEventNames();
18
- this.getSelections();
19
- this.bindEvents();
18
+ if (typeof elmsOrSelector === 'string') {
19
+ $elms = $(elmsOrSelector);
20
+ this.selector = elmsOrSelector;
21
+ this.setInitialState($(this.selector));
22
+ } else {
23
+ this.$elms = elmsOrSelector;
24
+ this.setInitialState(this.$elms);
25
+ }
26
+ this.addEvents();
20
27
  };
21
- BaseButtons.prototype.setEventNames = function () {
22
- this.selectionEvents = 'click';
23
- this.focusEvents = 'focus blur';
28
+ SelectionButtons.prototype.addEvents = function () {
29
+ if (typeof this.$elms !== 'undefined') {
30
+ this.addElementLevelEvents();
31
+ } else {
32
+ this.addDocumentLevelEvents();
33
+ }
24
34
  };
25
- BaseButtons.prototype.markFocused = function ($elm, state) {
26
- var elmId = $elm.attr('id');
35
+ SelectionButtons.prototype.setInitialState = function ($elms) {
36
+ $elms.each(function (idx, elm) {
37
+ var $elm = $(elm);
27
38
 
39
+ if ($elm.is(':checked')) {
40
+ this.markSelected($elm);
41
+ }
42
+ }.bind(this));
43
+ };
44
+ SelectionButtons.prototype.markFocused = function ($elm, state) {
28
45
  if (state === 'focused') {
29
46
  $elm.parent('label').addClass(this.focusedClass);
30
47
  } else {
31
48
  $elm.parent('label').removeClass(this.focusedClass);
32
49
  }
33
50
  };
34
- BaseButtons.prototype.bindEvents = function () {
35
- var selectionEventHandler = this.markSelected.bind(this),
36
- focusEventHandler = this.markFocused.bind(this);
51
+ SelectionButtons.prototype.markSelected = function ($elm) {
52
+ var radioName;
37
53
 
38
- this.$elms
39
- .on(this.selectionEvents, function (e) {
40
- selectionEventHandler($(e.target));
41
- })
42
- .on(this.focusEvents, function (e) {
43
- var state = (e.type === 'focus') ? 'focused' : 'blurred';
44
-
45
- focusEventHandler($(e.target), state);
46
- });
47
- };
48
-
49
- var RadioButtons = function ($elms, opts) {
50
- BaseButtons.apply(this, arguments);
51
- };
52
- RadioButtons.prototype.setEventNames = function () {
53
- // some browsers fire the 'click' when the selected radio changes by keyboard
54
- this.selectionEvents = 'click change';
55
- this.focusEvents = 'focus blur';
56
- };
57
- RadioButtons.prototype.getSelections = function () {
58
- var selectionEventHandler = this.markSelected.bind(this);
59
-
60
- this.selections = {};
61
- $.each(this.$elms, function (index, elm) {
62
- var $elm = $(elm),
63
- radioName = $elm.attr('name');
64
-
65
- if (typeof this.selections[radioName] === 'undefined') {
66
- this.selections[radioName] = false;
67
- }
54
+ if ($elm.attr('type') === 'radio') {
55
+ radioName = $elm.attr('name'),
56
+ $($elm[0].form).find('input[name="' + radioName + '"]')
57
+ .parent('label')
58
+ .removeClass(this.selectedClass);
59
+ $elm.parent('label').addClass(this.selectedClass);
60
+ } else { // checkbox
68
61
  if ($elm.is(':checked')) {
69
- selectionEventHandler($elm);
62
+ $elm.parent('label').addClass(this.selectedClass);
63
+ } else {
64
+ $elm.parent('label').removeClass(this.selectedClass);
70
65
  }
71
- }.bind(this));
72
- };
73
- RadioButtons.prototype.bindEvents = function () {
74
- BaseButtons.prototype.bindEvents.call(this);
75
- };
76
- RadioButtons.prototype.markSelected = function ($elm) {
77
- var radioName = $elm.attr('name'),
78
- $previousSelection = this.selections[radioName];
79
-
80
- if ($previousSelection) {
81
- $previousSelection.parent('label').removeClass(this.selectedClass);
82
66
  }
83
- $elm.parent('label').addClass(this.selectedClass);
84
- this.selections[radioName] = $elm;
85
67
  };
86
- RadioButtons.prototype.markFocused = function ($elm) {
87
- BaseButtons.prototype.markFocused.apply(this, arguments);
68
+ SelectionButtons.prototype.addElementLevelEvents = function () {
69
+ this.clickHandler = this.getClickHandler();
70
+ this.focusHandler = this.getFocusHandler({ 'level' : 'element' });
71
+
72
+ this.$elms
73
+ .on('click', this.clickHandler)
74
+ .on('focus blur', this.focusHandler);
88
75
  };
76
+ SelectionButtons.prototype.addDocumentLevelEvents = function () {
77
+ this.clickHandler = this.getClickHandler();
78
+ this.focusHandler = this.getFocusHandler({ 'level' : 'document' });
89
79
 
90
- var CheckboxButtons = function ($elms, opts) {
91
- BaseButtons.apply(this, arguments);
80
+ $(document)
81
+ .on('click', this.selector, this.clickHandler)
82
+ .on('focus blur', this.selector, this.focusHandler);
92
83
  };
93
- CheckboxButtons.prototype.setEventNames = function () {
94
- BaseButtons.prototype.setEventNames.call(this);
84
+ SelectionButtons.prototype.getClickHandler = function () {
85
+ return function (e) {
86
+ this.markSelected($(e.target));
87
+ }.bind(this);
95
88
  };
96
- CheckboxButtons.prototype.getSelections = function () {
97
- var selectionEventHandler = this.markSelected.bind(this);
89
+ SelectionButtons.prototype.getFocusHandler = function (opts) {
90
+ var focusEvent = (opts.level === 'document') ? 'focusin' : 'focus'
98
91
 
99
- this.$elms.each(function (idx, elm) {
100
- var $elm = $(elm);
92
+ return function (e) {
93
+ var state = (e.type === focusEvent) ? 'focused' : 'blurred';
101
94
 
102
- if ($elm.is(':checked')) {
103
- selectionEventHandler($elm);
104
- }
105
- });
95
+ this.markFocused($(e.target), state);
96
+ }.bind(this);
106
97
  };
107
- CheckboxButtons.prototype.bindEvents = function () {
108
- BaseButtons.prototype.bindEvents.call(this);
109
- };
110
- CheckboxButtons.prototype.markSelected = function ($elm) {
111
- if ($elm.is(':checked')) {
112
- $elm.parent('label').addClass(this.selectedClass);
98
+ SelectionButtons.prototype.destroy = function () {
99
+ if (typeof this.selector !== 'undefined') {
100
+ $(document)
101
+ .off('click', this.selector, this.clickHandler)
102
+ .off('focus blur', this.selector, this.focusHandler);
113
103
  } else {
114
- $elm.parent('label').removeClass(this.selectedClass);
115
- }
116
- };
117
- CheckboxButtons.prototype.markFocused = function ($elm) {
118
- BaseButtons.prototype.markFocused.apply(this, arguments);
119
- };
120
-
121
- root.GOVUK.RadioButtons = RadioButtons;
122
- root.GOVUK.CheckboxButtons = CheckboxButtons;
123
-
124
- var selectionButtons = function ($elms, opts) {
125
- var $radios = $elms.filter('[type=radio]'),
126
- $checkboxes = $elms.filter('[type=checkbox]');
127
-
128
- if ($radios) {
129
- new GOVUK.RadioButtons($radios, opts);
130
- }
131
- if ($checkboxes) {
132
- new GOVUK.CheckboxButtons($checkboxes, opts);
104
+ this.$elms
105
+ .off('click', this.clickHandler)
106
+ .off('focus blur', this.focusHandler);
133
107
  }
134
108
  };
135
109
 
136
- root.GOVUK.selectionButtons = selectionButtons;
110
+ root.GOVUK.SelectionButtons = SelectionButtons;
137
111
  }).call(this);