govuk_elements_rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/LICENCE +20 -0
  3. data/README.md +54 -0
  4. data/lib/govuk_elements_rails.rb +4 -0
  5. data/lib/govuk_elements_rails/engine.rb +4 -0
  6. data/lib/govuk_elements_rails/version.rb +5 -0
  7. data/vendor/assets/javascripts/bind.js +40 -0
  8. data/vendor/assets/javascripts/details.polyfill.js +158 -0
  9. data/vendor/assets/javascripts/selection-buttons.js +137 -0
  10. data/vendor/assets/stylesheets/elements-page-ie6.scss +5 -0
  11. data/vendor/assets/stylesheets/elements-page-ie7.scss +4 -0
  12. data/vendor/assets/stylesheets/elements-page-ie8.scss +4 -0
  13. data/vendor/assets/stylesheets/elements-page.scss +333 -0
  14. data/vendor/assets/stylesheets/elements/_buttons.scss +44 -0
  15. data/vendor/assets/stylesheets/elements/_details.scss +39 -0
  16. data/vendor/assets/stylesheets/elements/_elements-typography.scss +179 -0
  17. data/vendor/assets/stylesheets/elements/_forms.scss +166 -0
  18. data/vendor/assets/stylesheets/elements/_helpers.scss +46 -0
  19. data/vendor/assets/stylesheets/elements/_icons.scss +224 -0
  20. data/vendor/assets/stylesheets/elements/_layout.scss +67 -0
  21. data/vendor/assets/stylesheets/elements/_lists.scss +32 -0
  22. data/vendor/assets/stylesheets/elements/_panels.scss +29 -0
  23. data/vendor/assets/stylesheets/elements/_reset.scss +33 -0
  24. data/vendor/assets/stylesheets/elements/_tables.scss +26 -0
  25. data/vendor/assets/stylesheets/elements/forms/_form-block-labels.scss +67 -0
  26. data/vendor/assets/stylesheets/elements/forms/_form-date.scss +46 -0
  27. data/vendor/assets/stylesheets/elements/forms/_form-validation.scss +68 -0
  28. data/vendor/assets/stylesheets/main-ie6.scss +5 -0
  29. data/vendor/assets/stylesheets/main-ie7.scss +4 -0
  30. data/vendor/assets/stylesheets/main-ie8.scss +4 -0
  31. data/vendor/assets/stylesheets/main.scss +36 -0
  32. data/vendor/assets/stylesheets/prism.scss +144 -0
  33. data/vendor/assets/stylesheets/service-design-manual/helpers/_breadcrumbs.scss +81 -0
  34. data/vendor/assets/stylesheets/service-design-manual/helpers/_page-header.scss +28 -0
  35. data/vendor/assets/stylesheets/service-design-manual/styleguide/_colours.scss +3 -0
  36. metadata +122 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0e4507b35a48b80125447d05206cad3cfe6f39f0
4
+ data.tar.gz: 98b68bd115ef63a93316504d741f4130c486f493
5
+ SHA512:
6
+ metadata.gz: 10ecd7e53790c3d74e3853f4d40b0f83d786a8d6af4e222d7c0ebd4c27c95ffad1780d0a4615a138aa2b2f58a649c847f15dca8aa95014c30e234c2574e27429
7
+ data.tar.gz: ff14ffac1525b39272214c70e6e6c408377de2365fbff171f6386bb3a221169dd3d561fe88f41aae4f7fd51324133776e199a5805a9ab3928052c687f916b27a
data/LICENCE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014 HM Government
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # GOV.UK Elements Rails gem
2
+
3
+ A gem wrapper around [govuk_elements](http://github.com/alphagov/govuk_elements)
4
+ that pulls stylesheet and javascript files into a Rails app.
5
+
6
+ ## Installing
7
+
8
+ Just include `govuk_elements_rails` in your `Gemfile`. It
9
+ automatically attaches itself to your asset path so the static/SCSS
10
+ files will be available to the asset pipeline.
11
+
12
+ ### Development
13
+
14
+ If you are installing from git, ensure you enable submodules like so:
15
+
16
+ gem 'govuk_elements_rails', :git => "https://github.com/ministryofjustice/govuk_elements_rails.git", :submodules => true
17
+
18
+ ## Usage
19
+
20
+ At the top of a Sass file in your Rails project you should use an `@import` rule
21
+ to include the file for the mixins you require. For example here are all the
22
+ imports possible:
23
+
24
+ @import 'elements/helpers';
25
+ @import 'elements/reset';
26
+ @import 'elements/elements-typography';
27
+ @import 'elements/layout';
28
+
29
+ @import 'elements/forms';
30
+ @import 'elements/tables';
31
+ @import 'elements/buttons';
32
+ @import 'elements/details';
33
+ @import 'elements/lists';
34
+ @import 'elements/panels';
35
+ @import "elements/icons";
36
+
37
+ In the `app/assets/javascripts/application.js` file in your Rails project use
38
+ `require` rule to include the files for the javascript enhancements you require.
39
+ For example here are all the requires possible at present:
40
+
41
+ // from govuk_elements gem
42
+ //= require details.polyfill
43
+ //= require bind
44
+ //= require selection-buttons
45
+
46
+ ## Alternate ways to reuse GOV.UK Elements
47
+
48
+ There are other alternate ways to include GOV.UK Elements files in a Rails
49
+ project, for example via `Bower`. Feel free to use an alternate approach if it
50
+ is more appropriate for your team.
51
+
52
+ ## Feedback
53
+
54
+ Please provide feedback via [GitHub issues](https://github.com/ministryofjustice/govuk_elements_rails/issues).
@@ -0,0 +1,4 @@
1
+ module GovUKElementsRails
2
+ require 'govuk_elements_rails/engine'
3
+ autoload 'Version', 'govuk_elements_rails/version'
4
+ end
@@ -0,0 +1,4 @@
1
+ module GovUKElementsRails
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module GovUKElementsRails
2
+ def self.elements_version
3
+ '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,40 @@
1
+ // Function.prototype.bind
2
+ //
3
+ // A polyfill for Function.prototype.bind. Which lets you bind a defined
4
+ // value to the `this` keyword in a function call.
5
+ //
6
+ // Bind is natively supported in:
7
+ // IE9+
8
+ // Chrome 7+
9
+ // Firefox 4+
10
+ // Safari 5.1.4+
11
+ // iOS 6+
12
+ // Android Browser 4+
13
+ // Chrome for Android 0.16+
14
+ //
15
+ // Originally from:
16
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
17
+ if (!Function.prototype.bind) {
18
+ Function.prototype.bind = function (oThis) {
19
+ if (typeof this !== "function") {
20
+ // closest thing possible to the ECMAScript 5
21
+ // internal IsCallable function
22
+ throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
23
+ }
24
+
25
+ var aArgs = Array.prototype.slice.call(arguments, 1),
26
+ fToBind = this,
27
+ fNOP = function () {},
28
+ fBound = function () {
29
+ return fToBind.apply(this instanceof fNOP && oThis
30
+ ? this
31
+ : oThis,
32
+ aArgs.concat(Array.prototype.slice.call(arguments)));
33
+ };
34
+
35
+ fNOP.prototype = this.prototype;
36
+ fBound.prototype = new fNOP();
37
+
38
+ return fBound;
39
+ };
40
+ }
@@ -0,0 +1,158 @@
1
+ // <details> polyfill
2
+ // http://caniuse.com/#feat=details
3
+
4
+ // FF Support for HTML5's <details> and <summary>
5
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=591737
6
+
7
+ // http://www.sitepoint.com/fixing-the-details-element/
8
+
9
+ (function () {
10
+
11
+ // Add event construct for modern browsers or IE
12
+ // which fires the callback with a pre-converted target reference
13
+ function addEvent(node, type, callback) {
14
+ if (node.addEventListener) {
15
+ node.addEventListener(type, function (e) {
16
+ callback(e, e.target);
17
+ }, false);
18
+ } else if (node.attachEvent) {
19
+ node.attachEvent('on' + type, function (e) {
20
+ callback(e, e.srcElement);
21
+ });
22
+ }
23
+ }
24
+
25
+ // Handle cross-modal click events
26
+ function addClickEvent(node, callback) {
27
+ var keydown = false;
28
+ addEvent(node, 'keydown', function () {
29
+ keydown = true;
30
+ });
31
+ addEvent(node, 'keyup', function (e, target) {
32
+ keydown = false;
33
+ if (e.keyCode === 13) { callback(e, target); }
34
+ });
35
+ addEvent(node, 'click', function (e, target) {
36
+ if (!keydown) { callback(e, target); }
37
+ });
38
+ }
39
+
40
+ // Get the nearest ancestor element of a node that matches a given tag name
41
+ function getAncestor(node, match) {
42
+ do {
43
+ if (!node || node.nodeName.toLowerCase() === match) {
44
+ break;
45
+ }
46
+ } while (node = node.parentNode);
47
+
48
+ return node;
49
+ }
50
+
51
+ // Create a started flag so we can prevent the initialisation
52
+ // function firing from both DOMContentLoaded and window.onload
53
+ var started = false;
54
+
55
+ // Initialisation function
56
+ function addDetailsPolyfill(list) {
57
+
58
+ // If this has already happened, just return
59
+ // else set the flag so it doesn't happen again
60
+ if (started) {
61
+ return;
62
+ }
63
+ started = true;
64
+
65
+ // Get the collection of details elements, but if that's empty
66
+ // then we don't need to bother with the rest of the scripting
67
+ if ((list = document.getElementsByTagName('details')).length === 0) {
68
+ return;
69
+ }
70
+
71
+ // else iterate through them to apply their initial state
72
+ var n = list.length, i = 0;
73
+ for (n; i < n; i++) {
74
+ var details = list[i];
75
+
76
+ // Detect native implementations
77
+ details.__native = typeof(details.open) == 'boolean';
78
+
79
+ // Save shortcuts to the inner summary and content elements
80
+ details.__summary = details.getElementsByTagName('summary').item(0);
81
+ details.__content = details.getElementsByTagName('div').item(0);
82
+
83
+ // If the content doesn't have an ID, assign it one now
84
+ // which we'll need for the summary's aria-controls assignment
85
+ if (!details.__content.id) {
86
+ details.__content.id = 'details-content-' + i;
87
+ }
88
+
89
+ // Add role=button to summary
90
+ details.__summary.setAttribute('role', 'button');
91
+
92
+ // Add aria-controls
93
+ details.__summary.setAttribute('aria-controls', details.__content.id);
94
+
95
+ // Set tabindex so the summary is keyboard accessible
96
+ details.__summary.setAttribute('tabindex', '0');
97
+
98
+ // Detect initial open/closed state
99
+ var detailsAttr = details.hasAttribute('open');
100
+ if (typeof detailsAttr !== 'undefined' && detailsAttr !== false) {
101
+ details.__summary.setAttribute('aria-expanded', 'true');
102
+ details.__content.setAttribute('aria-hidden', 'false');
103
+ } else {
104
+ details.__summary.setAttribute('aria-expanded', 'false');
105
+ details.__content.setAttribute('aria-hidden', 'true');
106
+ details.__content.style.display = 'none';
107
+ }
108
+
109
+ // Create a circular reference from the summary back to its
110
+ // parent details element, for convenience in the click handler
111
+ details.__summary.__details = details;
112
+
113
+ // If this is not a native implementation, create an arrow
114
+ // inside the summary, saving its reference as a summary property
115
+ if (!details.__native) {
116
+ var twisty = document.createElement('i');
117
+ twisty.className = 'arrow arrow-closed';
118
+ twisty.appendChild(document.createTextNode('\u25ba'));
119
+ details.__summary.__twisty = details.__summary.insertBefore(twisty, details.__summary.firstChild);
120
+ }
121
+ }
122
+
123
+ // Define a statechange function that updates aria-expanded and style.display
124
+ // Also update the arrow position
125
+ function statechange(summary) {
126
+
127
+ // Update aria-expanded attribute on click
128
+ var expanded = summary.__details.__summary.getAttribute('aria-expanded') == 'true';
129
+ var hidden = summary.__details.__content.getAttribute('aria-hidden') == 'true';
130
+
131
+ summary.__details.__summary.setAttribute('aria-expanded', (expanded ? 'false' : 'true'));
132
+ summary.__details.__content.setAttribute('aria-hidden', (hidden ? 'false' : 'true'));
133
+ summary.__details.__content.style.display = (expanded ? 'none' : 'block');
134
+
135
+ if (summary.__twisty) {
136
+ summary.__twisty.firstChild.nodeValue = (expanded ? '\u25ba' : '\u25bc');
137
+ summary.__twisty.setAttribute('class', (expanded ? 'arrow arrow-closed' : 'arrow arrow-open'));
138
+ }
139
+
140
+ return true;
141
+ }
142
+
143
+ // Bind a click event to handle summary elements
144
+ addClickEvent(document, function(e, summary) {
145
+ if (!(summary = getAncestor(summary, 'summary'))) {
146
+ return true;
147
+ }
148
+ return statechange(summary);
149
+ });
150
+ }
151
+
152
+ // Bind two load events for modern and older browsers
153
+ // If the first one fires it will set a flag to block the second one
154
+ // but if it's not supported then the second one will fire
155
+ addEvent(document, 'DOMContentLoaded', addDetailsPolyfill);
156
+ addEvent(window, 'load', addDetailsPolyfill);
157
+
158
+ })();
@@ -0,0 +1,137 @@
1
+ (function () {
2
+ "use strict"
3
+ var root = this,
4
+ $ = root.jQuery;
5
+
6
+ if (typeof GOVUK === 'undefined') { root.GOVUK = {}; }
7
+
8
+ var BaseButtons = function ($elms, opts) {
9
+ this.$elms = $elms;
10
+ this.selectedClass = 'selected';
11
+ this.focusedClass = 'focused';
12
+ if (opts !== undefined) {
13
+ $.each(opts, function (optionName, optionObj) {
14
+ this[optionName] = optionObj;
15
+ }.bind(this));
16
+ }
17
+ this.setEventNames();
18
+ this.getSelections();
19
+ this.bindEvents();
20
+ };
21
+ BaseButtons.prototype.setEventNames = function () {
22
+ this.selectionEvents = 'click';
23
+ this.focusEvents = 'focus blur';
24
+ };
25
+ BaseButtons.prototype.markFocused = function ($elm, state) {
26
+ var elmId = $elm.attr('id');
27
+
28
+ if (state === 'focused') {
29
+ $elm.parent('label').addClass(this.focusedClass);
30
+ } else {
31
+ $elm.parent('label').removeClass(this.focusedClass);
32
+ }
33
+ };
34
+ BaseButtons.prototype.bindEvents = function () {
35
+ var selectionEventHandler = this.markSelected.bind(this),
36
+ focusEventHandler = this.markFocused.bind(this);
37
+
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
+ }
68
+ if ($elm.is(':checked')) {
69
+ selectionEventHandler($elm);
70
+ }
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
+ }
83
+ $elm.parent('label').addClass(this.selectedClass);
84
+ this.selections[radioName] = $elm;
85
+ };
86
+ RadioButtons.prototype.markFocused = function ($elm) {
87
+ BaseButtons.prototype.markFocused.apply(this, arguments);
88
+ };
89
+
90
+ var CheckboxButtons = function ($elms, opts) {
91
+ BaseButtons.apply(this, arguments);
92
+ };
93
+ CheckboxButtons.prototype.setEventNames = function () {
94
+ BaseButtons.prototype.setEventNames.call(this);
95
+ };
96
+ CheckboxButtons.prototype.getSelections = function () {
97
+ var selectionEventHandler = this.markSelected.bind(this);
98
+
99
+ this.$elms.each(function (idx, elm) {
100
+ var $elm = $(elm);
101
+
102
+ if ($elm.is(':checked')) {
103
+ selectionEventHandler($elm);
104
+ }
105
+ });
106
+ };
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);
113
+ } 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);
133
+ }
134
+ };
135
+
136
+ root.GOVUK.selectionButtons = selectionButtons;
137
+ }).call(this);
@@ -0,0 +1,5 @@
1
+ $is-ie: true;
2
+ $ie-version: 6;
3
+ $mobile-ie6: false;
4
+
5
+ @import "elements-page";