govuk_frontend_toolkit 1.7.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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);