govuk_admin_template 0.0.1 → 0.0.2

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.
data/README.md CHANGED
@@ -6,6 +6,7 @@ This gem provides (via a Rails engine):
6
6
  * jQuery
7
7
  * Bootstrap 3 standard styles and javascript — including HTML5 and respond.js shims necessary for IE <= IE8
8
8
  * An admin layout with header and footer
9
+ * A [lightweight javascript framework](JAVASCRIPT.md)
9
10
  * Admin design patterns available from __/style-guide__
10
11
  * SASS variables for the admin theme
11
12
 
@@ -34,6 +35,8 @@ You will also need to include your styles within the `<head>` of your HTML, do t
34
35
 
35
36
  The gem source includes a [dummy app](spec/dummy) configured to behave like an app using the gem. If you have the gem checked out it can be run from the `spec\dummy` directory using `rails s`.
36
37
 
38
+ For Javascript usage, available modules and writing modules, see the [Javascript guide](JAVASCRIPT.md).
39
+
37
40
  ### Content blocks
38
41
 
39
42
  The gem [uses nested layouts](http://guides.rubyonrails.org/layouts_and_rendering.html#using-nested-layouts) for customisation.
@@ -90,4 +93,4 @@ bundle exec rake dummy_app:jasmine:ci
90
93
 
91
94
  ## Publishing
92
95
 
93
- There is no automatic compilation and publish step yet.
96
+ Version bumps will automatically update RubyGems.org.
@@ -1,3 +1,12 @@
1
1
  //= require jquery
2
2
  //= require jquery_ujs
3
3
  //= require bootstrap
4
+ //= require govuk-admin
5
+ //= require_tree ./modules
6
+
7
+ // Find and auto-start modules specified using the data-module="" pattern in markup
8
+ (function($, GOVUKAdmin) {
9
+ $(function(){
10
+ GOVUKAdmin.startAll();
11
+ });
12
+ })(jQuery, window.GOVUKAdmin);
@@ -0,0 +1,103 @@
1
+ (function($, root) {
2
+ "use strict";
3
+
4
+ var GOVUKAdmin = root.GOVUKAdmin = {
5
+ Modules: {}
6
+ };
7
+
8
+ GOVUKAdmin.find = function(container) {
9
+
10
+ var modules,
11
+ moduleSelector = '[data-module]',
12
+ container = container || $('body');
13
+
14
+ modules = container.find(moduleSelector);
15
+
16
+ // Include container if it matches pattern, as that could
17
+ // be a module too
18
+ if (container.is(moduleSelector)) {
19
+ modules.push(container);
20
+ }
21
+
22
+ return modules;
23
+ }
24
+
25
+ GOVUKAdmin.start = function(container) {
26
+
27
+ var modules = this.find(container);
28
+
29
+ for (var i = 0, l = modules.length; i < l; i++) {
30
+
31
+ var module,
32
+ element = $(modules[i]),
33
+ type = camelCaseAndCapitalise(element.data('module'));
34
+
35
+ if (typeof GOVUKAdmin.Modules[type] === "function") {
36
+ module = new GOVUKAdmin.Modules[type]();
37
+ module.start(element);
38
+ }
39
+ }
40
+
41
+ // eg selectable-table to SelectableTable
42
+ function camelCaseAndCapitalise(string) {
43
+ return capitaliseFirstLetter(camelCase(string));
44
+ }
45
+
46
+ // http://stackoverflow.com/questions/6660977/convert-hyphens-to-camel-case-camelcase
47
+ function camelCase(string) {
48
+ return string.replace(/-([a-z])/g, function (g) {
49
+ return g[1].toUpperCase();
50
+ });
51
+ }
52
+
53
+ // http://stackoverflow.com/questions/1026069/capitalize-the-first-letter-of-string-in-javascript
54
+ function capitaliseFirstLetter(string) {
55
+ return string.charAt(0).toUpperCase() + string.slice(1);
56
+ }
57
+
58
+ }
59
+
60
+ GOVUKAdmin.startAll = function() {
61
+ GOVUKAdmin.start();
62
+ GOVUKAdmin.startBootstrapComponents();
63
+ }
64
+
65
+ GOVUKAdmin.startBootstrapComponents = function() {
66
+ $('[data-toggle="tooltip"]').tooltip();
67
+ }
68
+
69
+ // Google Analytics event tracking
70
+ // https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide
71
+ // Label and value are optional
72
+ GOVUKAdmin.track = function(action, label, value) {
73
+
74
+ // Default category to the page an event occurs on
75
+ var category = root.location.pathname,
76
+ event;
77
+
78
+ // _gaq is the Google Analytics tracking object we
79
+ // push events to, GA asynchronously sends them on
80
+ root._gaq = root._gaq || [];
81
+
82
+ event = ["_trackEvent", category, action];
83
+
84
+ // Label is optional
85
+ if (typeof label === "string") {
86
+ event.push(label);
87
+ }
88
+
89
+ // Value is optional, but when used must be an
90
+ // integer, otherwise the event will be invalid
91
+ // and not logged
92
+ if (value) {
93
+ value = parseInt(value, 10);
94
+ if (typeof value === "number" && !isNaN(value)) {
95
+ event.push(value);
96
+ }
97
+ }
98
+
99
+ // Useful for debugging: console.log(event);
100
+ _gaq.push(event);
101
+ }
102
+
103
+ })(jQuery, window);
@@ -0,0 +1,13 @@
1
+ (function(Modules) {
2
+ "use strict";
3
+
4
+ Modules.AutoShowModal = function() {
5
+ var that = this;
6
+ that.start = function(element) {
7
+ element.modal('show').on('hidden.bs.modal', function () {
8
+ $(this).remove();
9
+ });
10
+ }
11
+ };
12
+
13
+ })(window.GOVUKAdmin.Modules);
@@ -0,0 +1,15 @@
1
+ (function(Modules) {
2
+ "use strict";
3
+
4
+ Modules.AutoTrackEvent = function() {
5
+ var that = this;
6
+ that.start = function(element) {
7
+ var action = element.data('track-action'),
8
+ label = element.data('track-label'),
9
+ value = element.data('track-value');
10
+
11
+ GOVUKAdmin.track(action, label, value);
12
+ }
13
+ };
14
+
15
+ })(window.GOVUKAdmin.Modules);
@@ -0,0 +1,29 @@
1
+ (function(Modules) {
2
+ "use strict";
3
+
4
+ Modules.FilterableTable = function() {
5
+ var that = this;
6
+ that.start = function(element) {
7
+
8
+ var rows = element.find('tbody tr'),
9
+ tableInput = element.find('.js-filter-table-input');
10
+
11
+ element.on('keyup change', '.js-filter-table-input', filterTableBasedOnInput);
12
+
13
+ function filterTableBasedOnInput(event) {
14
+ var searchString = $.trim(tableInput.val()),
15
+ regExp = new RegExp(searchString, 'i');
16
+
17
+ rows.each(function() {
18
+ var row = $(this);
19
+ if (row.text().search(regExp) > -1) {
20
+ row.show();
21
+ } else {
22
+ row.hide();
23
+ }
24
+ });
25
+ }
26
+ }
27
+ };
28
+
29
+ })(window.GOVUKAdmin.Modules);
@@ -0,0 +1,38 @@
1
+ (function(Modules) {
2
+ "use strict";
3
+
4
+ Modules.FixedTableHeader = function() {
5
+ var that = this;
6
+ that.start = function(element) {
7
+
8
+ // Clone the current table header into a fixed container
9
+ // Use .container class for correct width and responsiveness
10
+ // Setup a dummy table for correct rendering of cloned <thead>
11
+ // Basics derived from http://stackoverflow.com/questions/4709390/
12
+
13
+ var header = element.find('thead'),
14
+ headerOffset = header.offset().top,
15
+ fixedHeader = header.clone(),
16
+ fixedHeaderContainer = $('\
17
+ <div class="fixed-table-header-container">\
18
+ <div class="container">\
19
+ <table class="table table-bordered">\
20
+ </table>\
21
+ </div>\
22
+ </div>');
23
+
24
+ fixedHeaderContainer.hide().find('table').append(fixedHeader);
25
+ element.prepend(fixedHeaderContainer);
26
+ $(window).bind("scroll", checkOffsetAndToggleFixedHeader);
27
+
28
+ function checkOffsetAndToggleFixedHeader() {
29
+ var offset = $(window).scrollTop();
30
+ if (offset >= headerOffset && fixedHeaderContainer.is(":hidden")) {
31
+ fixedHeaderContainer.show();
32
+ } else if (offset < headerOffset) {
33
+ fixedHeaderContainer.hide();
34
+ }
35
+ }
36
+ }
37
+ };
38
+ })(window.GOVUKAdmin.Modules);
@@ -0,0 +1,154 @@
1
+ (function(Modules) {
2
+ "use strict";
3
+
4
+ Modules.SelectableTable = function() {
5
+
6
+ var that = this;
7
+
8
+ that.start = function(element) {
9
+
10
+ var tableRows = element.find('tbody tr'),
11
+ SELECTED_ROW_CLASS = 'selected-row',
12
+ RECENTLY_CHANGED_CLASS = 'js-most-recently-changed';
13
+
14
+ element.on('click', '.js-toggle-row', toggleRow);
15
+ element.on('click', '.js-toggle-all', toggleAllRows);
16
+ element.on('click', '.js-submit-form', submitForm);
17
+
18
+ element.on('ajax:success', 'form', createModal);
19
+ element.on('ajax:error', 'form', handleModalError);
20
+ element.on('ajax:complete','form', resetSubmitButtons);
21
+
22
+ onLoadMarkSelectedRowsWithClass();
23
+ updateHeaderToggleState();
24
+
25
+ function onLoadMarkSelectedRowsWithClass() {
26
+
27
+ var selectedRows = tableRows.find('.js-toggle-row:checked').parents('tr');
28
+ selectedRows.addClass(SELECTED_ROW_CLASS);
29
+
30
+ }
31
+
32
+ function toggleRow(event) {
33
+
34
+ var row = $(event.target).parents('tr');
35
+
36
+ event.shiftKey ? shiftToggleRow(row) : row.toggleClass(SELECTED_ROW_CLASS);
37
+
38
+ markRowAsRecentlyChanged(row);
39
+ updateHeaderToggleState();
40
+ }
41
+
42
+ function updateHeaderToggleState() {
43
+
44
+ var selectedRowsCount = tableRows.filter('.' + SELECTED_ROW_CLASS).length,
45
+ inputHeader = element.find('.js-toggle-all');
46
+
47
+ if (selectedRowsCount > 0 && selectedRowsCount < tableRows.length) {
48
+ inputHeader.prop('indeterminate', true);
49
+ inputHeader.prop('checked', false);
50
+ resetSubmitButtons();
51
+ } else if (selectedRowsCount === 0) {
52
+ inputHeader.prop('checked', false);
53
+ inputHeader.prop('indeterminate', false);
54
+ disableSubmitButtons();
55
+ } else {
56
+ inputHeader.prop('checked', true);
57
+ inputHeader.prop('indeterminate', false);
58
+ resetSubmitButtons();
59
+ }
60
+
61
+ }
62
+
63
+ function markRowAsRecentlyChanged(row) {
64
+ tableRows.removeClass(RECENTLY_CHANGED_CLASS);
65
+ row.addClass(RECENTLY_CHANGED_CLASS);
66
+ }
67
+
68
+ function shiftToggleRow(targetRow) {
69
+
70
+ var targetIndex = tableRows.index(targetRow),
71
+ targetState = targetRow.is('.' + SELECTED_ROW_CLASS),
72
+ mostRecentlyChanged = tableRows.filter('.' + RECENTLY_CHANGED_CLASS),
73
+ mostRecentlyChangedIndex = tableRows.index(mostRecentlyChanged),
74
+ rows, range;
75
+
76
+ // If we don't have a most recently changed, only toggle the current row
77
+ if (mostRecentlyChangedIndex < 0) {
78
+ mostRecentlyChangedIndex = targetIndex;
79
+ }
80
+
81
+ range = mostRecentlyChangedIndex < targetIndex ? [mostRecentlyChangedIndex, targetIndex + 1] : [targetIndex, mostRecentlyChangedIndex + 1];
82
+ rows = tableRows.slice.apply(tableRows, range);
83
+ toggleRows(rows, ! targetState);
84
+
85
+ }
86
+
87
+ function toggleAllRows(event) {
88
+
89
+ var rows = element.find('tbody tr');
90
+
91
+ // If everything selected
92
+ if (tableRows.length == element.find('.' + SELECTED_ROW_CLASS).length) {
93
+ toggleRows(rows, false);
94
+ } else {
95
+ toggleRows(rows, true);
96
+ }
97
+
98
+ updateHeaderToggleState();
99
+ }
100
+
101
+ function toggleRows(rows, select) {
102
+ if (select) {
103
+ rows.addClass(SELECTED_ROW_CLASS)
104
+ } else {
105
+ rows.removeClass(SELECTED_ROW_CLASS)
106
+ }
107
+ rows.find('input').prop('checked', select);
108
+ }
109
+
110
+ function submitForm(event) {
111
+ var target = $(event.target),
112
+ type = target.data('type');
113
+
114
+ if (target.is('.disabled')) {
115
+ event.preventDefault();
116
+ return;
117
+ }
118
+
119
+ disableSubmitButtons();
120
+ target.button('loading');
121
+
122
+ element.find('input[type="radio"][value="' + type + '"]').prop('checked', true);
123
+ element.find('form').submit();
124
+ event.preventDefault();
125
+ }
126
+
127
+ function createModal(event, html, status) {
128
+ var modal = $(html);
129
+
130
+ $('body').append(modal);
131
+
132
+ modal.modal('show').on('hidden.bs.modal', function () {
133
+ modal.remove();
134
+ });
135
+
136
+ GOVUKAdmin.start(modal);
137
+ }
138
+
139
+ function handleModalError(xhr, status, error) {
140
+ alert('There was a problem loading this. Please try again.');
141
+ }
142
+
143
+ function resetSubmitButtons() {
144
+ element.find('.js-submit-form').removeClass('disabled').button('reset');
145
+ element.find('.js-submit-container').addClass('buttons-enabled');
146
+ }
147
+
148
+ function disableSubmitButtons() {
149
+ element.find('.js-submit-form').addClass('disabled');
150
+ element.find('.js-submit-container').removeClass('buttons-enabled');
151
+ }
152
+ }
153
+ };
154
+ })(window.GOVUKAdmin.Modules);
@@ -0,0 +1,25 @@
1
+ (function(Modules) {
2
+ "use strict";
3
+
4
+ Modules.Toggle = function() {
5
+
6
+ var that = this;
7
+
8
+ that.start = function(element) {
9
+ element.on('click', '.js-toggle', toggle);
10
+ element.on('click', '.js-cancel', cancel);
11
+
12
+ function toggle(event) {
13
+ element.find('.js-toggle-target').toggleClass('if-js-hide');
14
+ element.find('input').first().focus();
15
+ event.preventDefault();
16
+ }
17
+
18
+ function cancel(event) {
19
+ toggle(event);
20
+ element.find('input').first().val('');
21
+ }
22
+ };
23
+ };
24
+
25
+ })(window.GOVUKAdmin.Modules);
@@ -1,3 +1,3 @@
1
1
  module GovukAdminTemplate
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: govuk_admin_template
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -159,6 +159,13 @@ files:
159
159
  - app/assets/images/header-crown.png
160
160
  - app/assets/javascripts/vendor/html5.js
161
161
  - app/assets/javascripts/vendor/respond.min.js
162
+ - app/assets/javascripts/govuk-admin.js
163
+ - app/assets/javascripts/modules/selectable_table.js
164
+ - app/assets/javascripts/modules/filterable_table.js
165
+ - app/assets/javascripts/modules/fixed_table_header.js
166
+ - app/assets/javascripts/modules/auto_track_event.js
167
+ - app/assets/javascripts/modules/toggle.js
168
+ - app/assets/javascripts/modules/auto_show_modal.js
162
169
  - app/assets/javascripts/lte-ie8.js
163
170
  - app/assets/javascripts/govuk-admin-template.js
164
171
  - app/controllers/govuk_admin_template/style_guide_controller.rb
@@ -181,7 +188,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
181
188
  version: '0'
182
189
  segments:
183
190
  - 0
184
- hash: 2646519301251615576
191
+ hash: -1211471381049981484
185
192
  required_rubygems_version: !ruby/object:Gem::Requirement
186
193
  none: false
187
194
  requirements:
@@ -190,7 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
190
197
  version: '0'
191
198
  segments:
192
199
  - 0
193
- hash: 2646519301251615576
200
+ hash: -1211471381049981484
194
201
  requirements: []
195
202
  rubyforge_project:
196
203
  rubygems_version: 1.8.23