govuk_admin_template 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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