pure-admin-rails 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +131 -0
  4. data/app/assets/images/menu-fade-left.png +0 -0
  5. data/app/assets/images/menu-fade-right.png +0 -0
  6. data/app/assets/images/pending.gif +0 -0
  7. data/app/assets/javascripts/pure_admin.js +6 -0
  8. data/app/assets/javascripts/pure_admin/dropdown.js +178 -0
  9. data/app/assets/javascripts/pure_admin/flash_messages.js +13 -0
  10. data/app/assets/javascripts/pure_admin/inputs.js +24 -0
  11. data/app/assets/javascripts/pure_admin/inputs/select.js +21 -0
  12. data/app/assets/javascripts/pure_admin/main_header.js +21 -0
  13. data/app/assets/javascripts/pure_admin/main_menu.js +108 -0
  14. data/app/assets/javascripts/pure_admin/modals.js +228 -0
  15. data/app/assets/javascripts/pure_admin/partial_refresh.js +92 -0
  16. data/app/assets/javascripts/pure_admin/portlets.js +139 -0
  17. data/app/assets/javascripts/pure_admin/tabs.js +14 -0
  18. data/app/assets/stylesheets/pure_admin.css.scss +23 -0
  19. data/app/assets/stylesheets/pure_admin/_dropdowns.scss +58 -0
  20. data/app/assets/stylesheets/pure_admin/_tabs.scss +76 -0
  21. data/app/assets/stylesheets/pure_admin/auth.css.scss +22 -0
  22. data/app/assets/stylesheets/pure_admin/breadcrumbs.css.scss +69 -0
  23. data/app/assets/stylesheets/pure_admin/buttons.css.scss +48 -0
  24. data/app/assets/stylesheets/pure_admin/details_panels.css.scss +99 -0
  25. data/app/assets/stylesheets/pure_admin/flash_messages.css.scss +97 -0
  26. data/app/assets/stylesheets/pure_admin/forms.css.scss +129 -0
  27. data/app/assets/stylesheets/pure_admin/inputs/select.css.scss +99 -0
  28. data/app/assets/stylesheets/pure_admin/jquery.tagsinput.css.scss +67 -0
  29. data/app/assets/stylesheets/pure_admin/main_menu.css.scss +146 -0
  30. data/app/assets/stylesheets/pure_admin/modals.css.scss +122 -0
  31. data/app/assets/stylesheets/pure_admin/pagination.css.scss +67 -0
  32. data/app/assets/stylesheets/pure_admin/portlets.css.scss +154 -0
  33. data/app/assets/stylesheets/pure_admin/scopes.css.scss +44 -0
  34. data/app/assets/stylesheets/pure_admin/shell.css.scss +222 -0
  35. data/app/assets/stylesheets/pure_admin/side_menu.css.scss +70 -0
  36. data/app/assets/stylesheets/pure_admin/table_filters.css.scss +90 -0
  37. data/app/assets/stylesheets/pure_admin/tables.css.scss +70 -0
  38. data/app/assets/stylesheets/pure_admin/tags.css.scss +37 -0
  39. data/app/assets/stylesheets/pure_admin/utilities.css.scss +24 -0
  40. data/app/assets/stylesheets/pure_admin/variables.css.scss +38 -0
  41. data/app/helpers/pure_admin/application_helper.rb +12 -0
  42. data/app/helpers/pure_admin/button_helper.rb +58 -0
  43. data/app/helpers/pure_admin/details_panel_helper.rb +121 -0
  44. data/app/helpers/pure_admin/dropdown_helper.rb +40 -0
  45. data/app/helpers/pure_admin/menu_helper.rb +120 -0
  46. data/app/helpers/pure_admin/portlet_helper.rb +75 -0
  47. data/app/helpers/pure_admin/table_filters_helper.rb +158 -0
  48. data/app/inputs/addon_input.rb +17 -0
  49. data/app/inputs/collection_select_input.rb +17 -0
  50. data/app/inputs/email_input.rb +5 -0
  51. data/app/inputs/tel_input.rb +5 -0
  52. data/lib/generators/pure_admin/layout/USAGE +10 -0
  53. data/lib/generators/pure_admin/layout/layout_generator.rb +8 -0
  54. data/lib/generators/pure_admin/layout/templates/admin.css.scss +8 -0
  55. data/lib/generators/pure_admin/layout/templates/admin.html.erb +105 -0
  56. data/lib/generators/pure_admin/scaffold/USAGE +11 -0
  57. data/lib/generators/pure_admin/scaffold/scaffold_generator.rb +66 -0
  58. data/lib/generators/pure_admin/scaffold/templates/_form.html.erb +12 -0
  59. data/lib/generators/pure_admin/scaffold/templates/_show.html.erb +11 -0
  60. data/lib/generators/pure_admin/scaffold/templates/_table.html.erb +21 -0
  61. data/lib/generators/pure_admin/scaffold/templates/models_controller.rb +69 -0
  62. data/lib/generators/pure_admin/simple_form/USAGE +8 -0
  63. data/lib/generators/pure_admin/simple_form/simple_form_generator.rb +7 -0
  64. data/lib/pure-admin-rails.rb +8 -0
  65. data/lib/pure-admin-rails/version.rb +5 -0
  66. metadata +261 -0
@@ -0,0 +1,228 @@
1
+ var PureAdmin = PureAdmin || {};
2
+
3
+ PureAdmin.modals = {
4
+ show: function (event) {
5
+ event.preventDefault();
6
+
7
+ var element = $(event.target).closest('*[modal]');
8
+ var modalType = element.attr('modal');
9
+
10
+ if ( PureAdmin.modals['_' + modalType] !== undefined ) {
11
+ PureAdmin.modals['_' + modalType](element);
12
+ } else {
13
+ PureAdmin.flash('alert', modalType + ' is not a valid modal type.');
14
+ }
15
+
16
+ return false;
17
+ },
18
+
19
+ _ajax: function (element) {
20
+ var icon = element.data('modal-icon') || 'fa-info-circle';
21
+ var url = element.data('modal-url') || element.attr('href');
22
+ var requestMethod = element.data('modal-request-method') || 'get';
23
+ var requestData = element.data('modal-request-data') || {};
24
+
25
+ var header = element.data('modal-text') || element.data('modal-heading');
26
+
27
+ if ( url === undefined ) {
28
+ PureAdmin.flashMessages.create('alert', 'You need to pass a URL to AJAX modals.');
29
+ return false;
30
+ }
31
+
32
+ var html = '<span class="fa ' + icon + '"></span>';
33
+
34
+ var modal = PureAdmin.modals._create('ajax', html);
35
+
36
+ $.ajax({
37
+ url: url,
38
+ type: requestMethod,
39
+ data: requestData,
40
+ timeout: 40000,
41
+ success: function(response) {
42
+ modal.find('.modal').append('<div class="modal-body">' + response + '</div>').show();
43
+ if (header) {
44
+ modal.find('.modal-body').prepend('<div class="modal-header"><h3>' + header + '</h3></div>');
45
+ }
46
+
47
+ modal.find('.modal-background').on('click', function(event) {
48
+ PureAdmin.modals._destroy(modal);
49
+ });
50
+
51
+ element.trigger('pure-admin:modal:shown');
52
+ },
53
+ error: function(response) {
54
+ element.trigger('pure-admin:modal:error');
55
+ PureAdmin.modals._destroy(modal);
56
+ PureAdmin.flashMessages.create('error', 'An error occured when loading the remote URL.');
57
+ }
58
+ });
59
+
60
+ return false;
61
+ },
62
+
63
+ _alert: function (element) {
64
+ var icon = element.data('modal-icon') || 'fa-exclamation-circle';
65
+ var text = element.data('modal-text') || 'Oh no!';
66
+
67
+ var yesCallbackFunction = PureAdmin.modals._getCallbackFunction(element.data('modal-yes-callback'));
68
+
69
+ var yesCallback = function() {
70
+ if ( yesCallbackFunction !== undefined ) yesCallbackFunction(element);
71
+ PureAdmin.modals._destroy(modal);
72
+ }
73
+
74
+ var html = '\
75
+ <span class="fa ' + icon + '"></span>\
76
+ <div class="modal-body">\
77
+ <p>' + text + '</p>\
78
+ </div>\
79
+ <div class="modal-controls">\
80
+ <a class="pure-button pure-button-primary" modal-button="yes">OK</a>\
81
+ </div>\
82
+ ';
83
+
84
+ var modal = PureAdmin.modals._create('alert', html);
85
+
86
+ modal.find('*[modal-button=yes]').on('click', yesCallback);
87
+
88
+ return false;
89
+ },
90
+
91
+ _confirm: function (element) {
92
+ var icon = element.data('modal-icon') || 'fa-question-circle';
93
+ var text = element.data('modal-text') || 'Are you sure?';
94
+ var url = element.data('modal-url') || element.attr('href');
95
+ var requestMethod = element.data('modal-request-method') || 'get';
96
+
97
+ var yesCallbackFunction = PureAdmin.modals._getCallbackFunction(element.data('modal-yes-callback'));
98
+ var noCallbackFunction = PureAdmin.modals._getCallbackFunction(element.data('modal-no-callback'));
99
+
100
+ var yesCallback = function() {
101
+ if ( yesCallbackFunction !== undefined ) yesCallbackFunction(element);
102
+ PureAdmin.modals._destroy(modal);
103
+ }
104
+
105
+ var noCallback = function() {
106
+ if ( noCallbackFunction !== undefined ) noCallbackFunction(element);
107
+ PureAdmin.modals._destroy(modal);
108
+ }
109
+
110
+ if ( yesCallbackFunction === undefined ) {
111
+ var yesButton = '<a href="' + url + '" class="pure-button pure-button-primary"\
112
+ modal-button="yes" data-method="' + requestMethod + '">Yes</a>';
113
+ } else {
114
+ var yesButton = '<a class="pure-button pure-button-primary" modal-button="yes">Yes</a>';
115
+ }
116
+
117
+ var html = '\
118
+ <span class="fa ' + icon + '"></span>\
119
+ <div class="modal-body">\
120
+ <p>' + text + '</p>\
121
+ </div>\
122
+ <div class="modal-controls">\
123
+ <a class="pure-button" modal-button="no">No</a>\
124
+ ' + yesButton + '\
125
+ </div>\
126
+ ';
127
+
128
+ var modal = PureAdmin.modals._create('confirm', html);
129
+
130
+ modal.find('*[modal-button=yes]').on('click', yesCallback);
131
+ modal.find('*[modal-button=no], .modal-background').on('click', noCallback);
132
+
133
+ return false;
134
+ },
135
+
136
+ _html: function (element) {
137
+ var icon = element.data('modal-icon') || 'fa-info-circle';
138
+ var modalHtmlElement = element.data('modal-html-element');
139
+ var innerHtml;
140
+
141
+ if (modalHtmlElement) {
142
+ innerHtml = $(modalHtmlElement).html();
143
+ } else {
144
+ innerHtml = element.data('modal-html') || '';
145
+ }
146
+
147
+ var html = '<span class="fa ' + icon + '"></span>' + innerHtml;
148
+
149
+ var modal = PureAdmin.modals._create('html', html);
150
+
151
+ modal.find('.modal-background').on('click', function(event) { PureAdmin.modals._destroy(modal) });
152
+
153
+ return false;
154
+ },
155
+
156
+ _create: function(type, innerHtml) {
157
+ var timestamp = new Date().getTime();
158
+ var html = '\
159
+ <div id="modal-container-' + timestamp + '" class="modal-container">\
160
+ <div class="modal-background"></div>\
161
+ <div class="modal-loading"></div>\
162
+ <div class="modal ' + type + '">\
163
+ ' + innerHtml + '\
164
+ </div>\
165
+ </div>\
166
+ ';
167
+
168
+ $('body').addClass('no-scroll').append(html);
169
+
170
+ var modal = $('#modal-container-' + timestamp);
171
+
172
+ // if the wait is longer than the loading timeout we show a loading gif
173
+ setTimeout(function() { modal.find('.modal-loading').css('opacity', 1) }, PureAdmin.LOADING_TIMEOUT);
174
+
175
+ /*
176
+ * Allow any click on an element with modal-action="close" within the modal to close the modal.
177
+ */
178
+ modal.on('click', '*[modal-action=close]', function(event) {
179
+ event.preventDefault();
180
+ PureAdmin.modals._destroy(modal);
181
+ });
182
+
183
+ /*
184
+ * Allow the modal to be closed by sending the modal element a 'hide' event.
185
+ */
186
+ modal.on('hide', function(event) {
187
+ event.preventDefault();
188
+ PureAdmin.modals._destroy(modal);
189
+ });
190
+
191
+ return modal;
192
+ },
193
+
194
+ _destroy: function(modal) {
195
+ modal.trigger('pure-admin:modal:destroy');
196
+ modal.remove();
197
+ $('body').removeClass('no-scroll');
198
+ },
199
+
200
+ _getCallbackFunction: function(callbackString) {
201
+ if ( callbackString === undefined ) return undefined;
202
+
203
+ var objects = callbackString.split('.');
204
+
205
+ var getObject = function(objects, object) {
206
+ object = object || window;
207
+ object = object[objects.shift()]
208
+
209
+ if ( object === undefined ) return undefined;
210
+
211
+ return ( objects.length > 0 ) ? getObject(objects, object) : object;
212
+ }
213
+
214
+ return getObject(objects);
215
+ }
216
+ };
217
+
218
+ $(document).ready(function() {
219
+ $('*[modal]:not(.bound-modal)').addClass('bound-modal').on('click', PureAdmin.modals.show);
220
+ });
221
+
222
+ $(document).ajaxSuccess(function() {
223
+ $('*[modal]:not(.bound-modal)').addClass('bound-modal').on('click', PureAdmin.modals.show);
224
+ });
225
+
226
+ $(document).on('turbolinks:load', function() {
227
+ $('*[modal]:not(.bound-modal)').addClass('bound-modal').on('click', PureAdmin.modals.show);
228
+ })
@@ -0,0 +1,92 @@
1
+ var PureAdmin = PureAdmin || {};
2
+
3
+ PureAdmin.partial_refresh = {
4
+ loadingTimer: {},
5
+
6
+ init: function() {
7
+ var matchElem = '.js-partial-refresh';
8
+ // Only initialise once, multiple times caused loading issues
9
+ if (window.partial_refresh_init == true)
10
+ return;
11
+
12
+ /*
13
+ * When the ajaxSend event is triggered on matchElem, show the loading indicator.
14
+ */
15
+ $(document).on('ajax:beforeSend', matchElem, function(e, data) {
16
+ var target = $(e.currentTarget);
17
+ var uniqueId = Math.floor((Math.random() * 1000) + 1);
18
+
19
+ target.data('pure-admin-unique-id', uniqueId);
20
+ loading(parentWrapper(target), true, uniqueId);
21
+ e.stopPropagation();
22
+ });
23
+
24
+ /*
25
+ * When the ajaxSuccess event is triggered on matchElem, replace the contents.
26
+ */
27
+ $(document).on('ajax:success', matchElem, function(e, data) {
28
+ var target = $(e.currentTarget);
29
+ var uniqueId = target.data('pure-admin-unique-id');
30
+ var wrapper = parentWrapper(target);
31
+
32
+ // Data will be undefined if we are using Rails 5.1 since UJS dropped
33
+ // jQuery, so we get the data from the Event
34
+ wrapper.html(data || e.detail[2].response);
35
+ loading(wrapper, false, uniqueId);
36
+ e.stopPropagation();
37
+ });
38
+
39
+ /*
40
+ * When the ajaxError event is triggered on matchElem, show a flash message.
41
+ */
42
+ $(document).on('ajax:error', matchElem, function(e, xhr, status, thrown) {
43
+ var target = $(e.currentTarget);
44
+
45
+ PureAdmin.flashMessages.create('error', thrown || 'Error');
46
+ loading(parentWrapper(target), false, target.data('pure-admin-unique-id'));
47
+ e.stopPropagation();
48
+ });
49
+
50
+ /*
51
+ * Return the appropriate parent of the target element.
52
+ * If the element has a data-parent attribute, return the matching jQuery object.
53
+ * Otherwise, return the portlet or main-content div elements, whichever comes first.
54
+ * @param (jQuery Object) target
55
+ * @return (jQuery Object) the appropriate parent
56
+ */
57
+ function parentWrapper(target) {
58
+ if (target.data('parent')) {
59
+ return $(target.data('parent'));
60
+ } else {
61
+ return target.parents('.portlet-body, #main-content').first();
62
+ }
63
+ }
64
+
65
+ /*
66
+ * Adds a loading class to the given element if 'loading' is not false and removes it if 'loading'
67
+ * is false.
68
+ * @param elem (jQuery Object)
69
+ * @param loadingStatus (Boolean)
70
+ */
71
+ function loading(elem, loadingStatus, uniqueId) {
72
+ if (loadingStatus !== false) {
73
+ PureAdmin.partial_refresh.loadingTimer[uniqueId] = setTimeout(function() {
74
+ // if the wait is longer than the loading timeout we show a loading animation
75
+ elem.addClass('loading');
76
+ }, PureAdmin.LOADING_TIMEOUT);
77
+ } else {
78
+ clearTimeout(PureAdmin.partial_refresh.loadingTimer[uniqueId]);
79
+ delete PureAdmin.partial_refresh.loadingTimer[uniqueId];
80
+ elem.removeClass('loading');
81
+ }
82
+ }
83
+ window.partial_refresh_init = true;
84
+ }
85
+ };
86
+
87
+ // Init via Turbolinks load if that exists
88
+ if (typeof(Turbolinks) == 'undefined') {
89
+ $(document).ready(PureAdmin.partial_refresh.init);
90
+ } else {
91
+ $(document).on('turbolinks:load', PureAdmin.partial_refresh.init);
92
+ }
@@ -0,0 +1,139 @@
1
+ var PureAdmin = PureAdmin || {};
2
+
3
+ PureAdmin.portlets = {
4
+
5
+ loadingTimer: {},
6
+
7
+ /*
8
+ * Toggles the 'expanded' class for the clicked portlet if it is closable.
9
+ * Additionally calls the loadPortlet function if the portlet is now expanded.
10
+ * @param e (Event)
11
+ */
12
+ toggle: function(e) {
13
+ e.preventDefault();
14
+ var portlet = $(e.target).parents('.portlet');
15
+ if (portlet.data('closable') === true) {
16
+ portlet.toggleClass('expanded');
17
+
18
+ if (portlet.hasClass('expanded')) {
19
+ PureAdmin.portlets.loadPortlet(portlet);
20
+ }
21
+ }
22
+ },
23
+
24
+ /*
25
+ * Sets the body of the given portlet to be the given newContent.
26
+ * @param portlet (jQuery Object)
27
+ * @param newContent (jQuery Object)
28
+ */
29
+ setPortletBody: function(portlet, newContent) {
30
+ portlet.find('.portlet-body').html(newContent);
31
+ },
32
+
33
+ /*
34
+ * Loads remote content to be inserted into the given portlet.
35
+ * If a URL is given, this will be used as the endpoint. Otherwise the value of data-source will
36
+ * be used.
37
+ * This function sets a sentinal value to determine if the content has already been loaded.
38
+ * If this sentinal value is present, the function will return early.
39
+ * Similarly if no source URL can be found, the function will return early.
40
+ * @param portlet (jQuery Object)
41
+ * @param url (String) - optional
42
+ */
43
+ loadPortlet: function(portlet, url) {
44
+ var source = (url || portlet.data('source'));
45
+
46
+ // Return early if the contents have already been loaded or if no source can be found.
47
+ if (portlet.data('body-loaded') || !source) { return; }
48
+
49
+ // If this function has been called before the toggle function, the portlet will not be expanded.
50
+ // To save duplicating that logic here, we just rely on the click handler to intercept a
51
+ // simulated click on the title and let the toggle function call this function again.
52
+ if (!portlet.hasClass('expanded')) {
53
+ portlet.find('.portlet-heading').click();
54
+ return;
55
+ }
56
+
57
+ PureAdmin.portlets.loading(portlet, true, source);
58
+
59
+ $.ajax(source, {
60
+ success: function(data, textStatus, jqXHR) {
61
+ PureAdmin.portlets.setPortletBody(portlet, $(data));
62
+ },
63
+ error: function(jxXHR, textStatus, thrown) {
64
+ PureAdmin.portlets.setPortletBody(portlet, PureAdmin.portlets.errorResponse(thrown));
65
+ },
66
+ complete: function(jxXHR, textStatus) {
67
+ portlet.data('body-loaded', true);
68
+ PureAdmin.portlets.loading(portlet, false, source);
69
+ }
70
+ });
71
+ },
72
+
73
+ /*
74
+ * Adds a loading class to the given element if 'loading' is not false and removes it if 'loading'
75
+ * is false.
76
+ * @param elem (jQuery Object)
77
+ * @param loading (Boolean)
78
+ */
79
+ loading: function(elem, loading, uniqueId) {
80
+ if (loading !== false) {
81
+ if (!PureAdmin.portlets.loadingTimer[uniqueId]) {
82
+ PureAdmin.portlets.loadingTimer[uniqueId] = setTimeout(function() {
83
+ // if the wait is longer than the loading timeout we show a loading animation
84
+ elem.addClass('loading');
85
+ }, PureAdmin.LOADING_TIMEOUT);
86
+ }
87
+ } else {
88
+ clearTimeout(PureAdmin.portlets.loadingTimer[uniqueId]);
89
+ delete PureAdmin.portlets.loadingTimer[uniqueId];
90
+ elem.removeClass('loading');
91
+ }
92
+ },
93
+
94
+ /*
95
+ * Creates a flash message then returns a jQuery object that shows the type of error if given,
96
+ * or a generic message.
97
+ * @param thrown (String) - optional
98
+ * @return (jQuery Object)
99
+ */
100
+ errorResponse: function(thrown) {
101
+ PureAdmin.flash_messages.create('error', 'An error occured when loading the remote URL.');
102
+ return $('<p class="text-error text-center"><i class="fa fa-exclamation-triangle"></i> "' +
103
+ (thrown || 'Error') + '" loading content</p>');
104
+ },
105
+
106
+ /*
107
+ * Load portlets that have a data-expand attribute
108
+ */
109
+ autoExpand: function() {
110
+ $('.portlet[data-expand]').each(function() {
111
+ PureAdmin.portlets.loadPortlet($(this));
112
+ });
113
+ },
114
+
115
+ ready: function() {
116
+ // Automatically open portlets that match the anchor
117
+ var anchorValue = document.location.toString().split("#")[1];
118
+ if (typeof anchorValue !== 'undefined' && anchorValue.length !== 0) {
119
+ var anchorPortlet = $('.portlet.' + anchorValue);
120
+ PureAdmin.portlets.loadPortlet(anchorPortlet);
121
+ }
122
+
123
+ // Automatically open portlets that have the data-expand attribute set
124
+ PureAdmin.portlets.autoExpand();
125
+ }
126
+ };
127
+
128
+ /*
129
+ * Intercepts clicks on the portlet title and calls the toggle function.
130
+ */
131
+ $(document).on('click', '.portlet-heading', PureAdmin.portlets.toggle);
132
+
133
+ $(document).ready(PureAdmin.portlets.ready);
134
+ $(document).on('turbolinks:load', PureAdmin.portlets.ready);
135
+
136
+ $(document).ajaxSuccess(function() {
137
+ // Automatically open portlets that have the data-expand attribute set
138
+ PureAdmin.portlets.autoExpand();
139
+ });