trestle 0.8.5 → 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/trestle/admin.js +11 -10
  3. data/app/assets/javascripts/trestle/{_confirmation.js → components/_confirmation.js} +1 -1
  4. data/app/assets/javascripts/trestle/{_datepicker.js → components/_datepicker.js} +4 -4
  5. data/app/assets/javascripts/trestle/components/_dialog.js +107 -0
  6. data/app/assets/javascripts/trestle/{_errors.js → components/_errors.js} +2 -2
  7. data/app/assets/javascripts/trestle/components/_form.js +48 -0
  8. data/app/assets/javascripts/trestle/{_gallery.js → components/_gallery.js} +3 -3
  9. data/app/assets/javascripts/trestle/{_select.js → components/_select.js} +2 -2
  10. data/app/assets/javascripts/trestle/{_sidebar.js → components/_sidebar.js} +3 -1
  11. data/app/assets/javascripts/trestle/{_table.js → components/_table.js} +1 -1
  12. data/app/assets/javascripts/trestle/components/_tabs.js +24 -0
  13. data/app/assets/javascripts/trestle/components/_tooltips.js +3 -0
  14. data/app/assets/javascripts/trestle/core/_contexts.js +13 -0
  15. data/app/assets/javascripts/trestle/{_cookies.js → core/_cookies.js} +2 -1
  16. data/app/assets/javascripts/trestle/core/_events.js +39 -0
  17. data/app/assets/javascripts/trestle/core/_visit.js +10 -0
  18. data/app/assets/stylesheets/trestle/components/_buttons.scss +9 -0
  19. data/app/assets/stylesheets/trestle/components/_modal.scss +92 -0
  20. data/app/assets/stylesheets/trestle/components/_navigation.scss +47 -12
  21. data/app/assets/stylesheets/trestle/components/_sidebar.scss +1 -0
  22. data/app/assets/stylesheets/trestle/core/_defaults.scss +5 -1
  23. data/app/controllers/trestle/application_controller.rb +5 -1
  24. data/app/helpers/trestle/dialog_helper.rb +7 -0
  25. data/app/helpers/trestle/form_helper.rb +7 -0
  26. data/app/helpers/trestle/url_helper.rb +34 -6
  27. data/app/views/layouts/trestle/admin.html.erb +1 -1
  28. data/app/views/trestle/application/_dialog.html.erb +36 -0
  29. data/app/views/trestle/application/_tabs.html.erb +7 -1
  30. data/app/views/trestle/resource/edit.html.erb +5 -5
  31. data/app/views/trestle/resource/index.html.erb +2 -2
  32. data/app/views/trestle/resource/new.html.erb +2 -2
  33. data/app/views/trestle/resource/show.html.erb +5 -5
  34. data/bower.json +1 -1
  35. data/config/locales/en.yml +25 -21
  36. data/config/locales/fr.rb +18 -0
  37. data/config/locales/fr.yml +69 -0
  38. data/config/locales/nl.yml +14 -14
  39. data/config/locales/pl.rb +18 -0
  40. data/config/locales/pl.yml +70 -0
  41. data/config/locales/pt-BR.yml +22 -22
  42. data/lib/generators/trestle/resource/templates/admin.rb.erb +1 -1
  43. data/lib/trestle/admin.rb +14 -1
  44. data/lib/trestle/admin/builder.rb +10 -2
  45. data/lib/trestle/breadcrumb.rb +13 -0
  46. data/lib/trestle/configuration.rb +6 -1
  47. data/lib/trestle/form.rb +7 -3
  48. data/lib/trestle/form/automatic.rb +1 -1
  49. data/lib/trestle/reloader.rb +1 -1
  50. data/lib/trestle/resource.rb +20 -5
  51. data/lib/trestle/resource/builder.rb +15 -0
  52. data/lib/trestle/resource/controller.rb +19 -6
  53. data/lib/trestle/table.rb +4 -0
  54. data/lib/trestle/table/actions_column.rb +9 -7
  55. data/lib/trestle/table/column.rb +3 -2
  56. data/lib/trestle/table/row.rb +7 -1
  57. data/lib/trestle/version.rb +1 -1
  58. data/trestle.gemspec +3 -3
  59. data/vendor/assets/bower_components/trestle/select2/dist/js/select2.full.js +90 -69
  60. metadata +30 -19
  61. data/app/assets/javascripts/trestle/_form.js +0 -6
  62. data/app/assets/javascripts/trestle/_tabs.js +0 -13
  63. data/app/assets/javascripts/trestle/_tooltips.js +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f43ff0c051a7e29be0e0a815f1500753456f8aef
4
- data.tar.gz: 75bc749e3cd64de9c5339e98dda6c921985d5c61
3
+ metadata.gz: 1f07f2d3328a13c6ac319c7e04b8926a0dc09660
4
+ data.tar.gz: a8adb65b4c3bd295c5e80397fba9c8968d08febd
5
5
  SHA512:
6
- metadata.gz: 86dbf71a36e6cfb0499e7ec5d6852103f9148acead9755775883fbb7011b019e435ccb7331866f19a6555c5d7fb9de049aed2139874a70bbe3417c88e79a806e
7
- data.tar.gz: 10e8387dbb008465043180543be49f16a659372ce62f8d908b86595c91ebdb6b1b2950c7391c9ec7eb1041feb325f19c817e7c7f5c3e3fb5a078651d1518a0d2
6
+ metadata.gz: 9d565ea8bd72cca11c5eb2de1ea72332e8980093e5f4147f598f64958ee82b3f1799de37dc7c2c99b68cbb773821454ee62c5230b4ba55bdc50828e516dc347e
7
+ data.tar.gz: da2e9069173f7fa34f0af87c392af4b00dc9ea5b9b42eb2e6cb3c2df536065bd9648b5482043260c748e919fa735127d3fafb32537e523fe356da52765d7221a
@@ -7,17 +7,18 @@
7
7
  //= require trestle/select2
8
8
  //
9
9
  //= require_self
10
+ //
11
+ //= require_tree ./core
12
+ //= require_tree ./components
13
+ //
10
14
  //= require trestle/custom
11
- //= require_tree .
12
15
 
13
- var Trestle = window.Trestle = {};
16
+ var Trestle = {
17
+ // Is Turbolinks enabled?
18
+ turbolinks: typeof(Turbolinks) !== 'undefined' && Turbolinks.supported,
14
19
 
15
- Trestle.i18n = {};
20
+ // Store for i18n translations used within JS
21
+ i18n: {}
22
+ };
16
23
 
17
- if (typeof(Turbolinks) !== 'undefined' && Turbolinks.supported) {
18
- Trestle.ready = function(callback) { $(document).on('turbolinks:load', callback); };
19
- Trestle.visit = function(url) { Turbolinks.visit(url); };
20
- } else {
21
- Trestle.ready = function(callback) { $(callback); };
22
- Trestle.visit = function(url) { document.location = url; };
23
- }
24
+ window.Trestle = Trestle;
@@ -11,7 +11,7 @@ Trestle.ready(function() {
11
11
  selector: '[data-toggle="confirm-delete"]',
12
12
  singleton: true,
13
13
  popout: true,
14
- title: Trestle.i18n['admin.confirmation.title'],
14
+ title: Trestle.i18n['admin.confirmation.title'] || 'Are you sure?',
15
15
  btnOkIcon: '',
16
16
  btnOkClass: 'btn-danger',
17
17
  btnOkLabel: Trestle.i18n['admin.confirmation.delete'] || 'Delete',
@@ -1,18 +1,18 @@
1
- Trestle.ready(function() {
2
- $('input[type="date"][data-picker="true"]').flatpickr({
1
+ Trestle.init(function(e, root) {
2
+ $(root).find('input[type="date"][data-picker="true"]').flatpickr({
3
3
  allowInput: true,
4
4
  altInput: true,
5
5
  altFormat: "m/d/Y",
6
6
  });
7
7
 
8
- $('input[type="datetime"][data-picker="true"], input[type="datetime-local"][data-picker="true"]').flatpickr({
8
+ $(root).find('input[type="datetime"][data-picker="true"], input[type="datetime-local"][data-picker="true"]').flatpickr({
9
9
  enableTime: true,
10
10
  allowInput: true,
11
11
  altInput: true,
12
12
  altFormat: "m/d/Y h:i K",
13
13
  });
14
14
 
15
- $('input[type="time"][data-picker="true"]').flatpickr({
15
+ $(root).find('input[type="time"][data-picker="true"]').flatpickr({
16
16
  enableTime: true,
17
17
  noCalendar: true,
18
18
  allowInput: true,
@@ -0,0 +1,107 @@
1
+ Trestle.Dialog = function() {
2
+ this.el = Trestle.Dialog.getElement();
3
+ };
4
+
5
+ Trestle.Dialog.TEMPLATE =
6
+ '<div id="dialog" class="modal fade" tabindex="-1">' +
7
+ '<div class="modal-dialog">' +
8
+ '<div class="modal-content" data-context></div>' +
9
+ '</div>' +
10
+ '</div>';
11
+
12
+ Trestle.Dialog.getElement = function() {
13
+ var el = $('#dialog');
14
+
15
+ if (el.length == 0) {
16
+ el = $(Trestle.Dialog.TEMPLATE).appendTo('body');
17
+
18
+ el.modal({ show: false });
19
+
20
+ // Remove dialog elements once hidden
21
+ el.on('hidden.bs.modal', function() {
22
+ el.remove();
23
+ });
24
+
25
+ // Set X-Trestle-Dialog header on AJAX requests initiated from the dialog
26
+ el.on('ajax:beforeSend', '[data-remote]', function(e, xhr, options) {
27
+ xhr.setRequestHeader("X-Trestle-Dialog", true);
28
+ });
29
+ }
30
+
31
+ return el;
32
+ };
33
+
34
+ Trestle.Dialog.prototype.load = function(url) {
35
+ var dialog = this;
36
+
37
+ dialog.show();
38
+ dialog.setLoading(true);
39
+
40
+ $.ajax({
41
+ url: url,
42
+ dataType: 'html',
43
+ headers: {
44
+ "X-Trestle-Dialog": true
45
+ },
46
+ complete: function() {
47
+ dialog.setLoading(false);
48
+ },
49
+ success: function(content) {
50
+ dialog.setContent(content);
51
+ },
52
+ error: function(xhr, status, error) {
53
+ dialog.showError(error);
54
+ }
55
+ });
56
+ };
57
+
58
+ Trestle.Dialog.prototype.setLoading = function(loading) {
59
+ if (loading) {
60
+ this.el.addClass('loading');
61
+ } else {
62
+ this.el.removeClass('loading');
63
+ }
64
+ }
65
+
66
+ Trestle.Dialog.prototype.setContent = function(content) {
67
+ this.el.find('.modal-content').html(content);
68
+ $(Trestle).trigger('init', this.el);
69
+ };
70
+
71
+ Trestle.Dialog.prototype.showError = function(error) {
72
+ this.el.addClass('error');
73
+
74
+ var container = this.el.find('.modal-content').empty();
75
+
76
+ var errorMessage = Trestle.i18n['trestle.dialog.error'] || 'The request could not be completed.';
77
+
78
+ $('<div class="modal-header">')
79
+ .append('<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>')
80
+ .append('<h4 class="modal-title"></h4>').find('h4').text(error || errorMessage).end()
81
+ .appendTo(container);
82
+
83
+ $('<div class="modal-body">')
84
+ .append('<p>').find('p').text(errorMessage).end()
85
+ .appendTo(container);
86
+
87
+ $('<div class="modal-footer">')
88
+ .append('<button type="button" class="btn btn-default" data-dismiss="modal" aria-label="OK">').find('button').text(Trestle.i18n['admin.buttons.ok'] || 'OK').end()
89
+ .appendTo(container);
90
+ };
91
+
92
+ Trestle.Dialog.prototype.show = function() {
93
+ this.el.modal('show');
94
+ };
95
+
96
+ Trestle.Dialog.prototype.hide = function() {
97
+ this.el.modal('hide');
98
+ };
99
+
100
+ $(document).on('click', '[data-behavior="dialog"]', function(e) {
101
+ e.preventDefault();
102
+
103
+ var url = $(this).data('url') || $(this).attr('href');
104
+
105
+ var dialog = new Trestle.Dialog();
106
+ dialog.load(url);
107
+ });
@@ -1,6 +1,6 @@
1
1
  // Add error indicators to tabs
2
- Trestle.ready(function() {
3
- $('.tab-pane').each(function() {
2
+ Trestle.init(function(e, root) {
3
+ $(root).find('.tab-pane').each(function() {
4
4
  var errorCount = $(this).find('.has-error').length;
5
5
 
6
6
  if (errorCount > 0) {
@@ -0,0 +1,48 @@
1
+ // Prevent enter key from submitting the form
2
+ $(document).on('keypress', 'form[data-behavior="trestle-form"] :input:not(textarea):not([type=submit])', function(e) {
3
+ if (e.keyCode == 13) {
4
+ e.preventDefault();
5
+ }
6
+ });
7
+
8
+ Trestle.init(function(e, root) {
9
+ var form = $(root).find('form[data-behavior="trestle-form"]');
10
+
11
+ form
12
+ .on('ajax:complete', function(e, xhr, status) {
13
+ // Find the parent context and replace content
14
+ var context = $(this).closest('[data-context]');
15
+ context.html(xhr.responseText);
16
+
17
+ // Initialize replaced elements within the context
18
+ $(Trestle).trigger('init', context);
19
+
20
+ // Focus the correct tab
21
+ Trestle.focusActiveTab();
22
+ })
23
+ .on('ajax:success', function(e, data, status, xhr) {
24
+ var context = $(this).closest('[data-context]');
25
+ var location = xhr.getResponseHeader("X-Trestle-Location");
26
+
27
+ if (location) {
28
+ // Update the URL in the browser and context
29
+ history.replaceState({}, "", location);
30
+ context.data('context', location);
31
+ }
32
+
33
+ // Refresh the main context
34
+ if (!context.hasClass('app-main')) {
35
+ Trestle.refreshMainContext();
36
+ }
37
+ });
38
+
39
+ // Loading indicator
40
+ form.find(':submit').click(function() {
41
+ var button = $(this);
42
+
43
+ // Delay to ensure form is still submitted
44
+ setTimeout(function() {
45
+ button.prop('disabled', true).addClass('loading');
46
+ }, 1);
47
+ });
48
+ });
@@ -1,5 +1,5 @@
1
- Trestle.ready(function() {
2
- $('[data-behavior~="zoom"]').magnificPopup({
1
+ Trestle.init(function(e, root) {
2
+ $(root).find('[data-behavior~="zoom"]').magnificPopup({
3
3
  type: 'image',
4
4
  closeOnContentClick: false,
5
5
  closeBtnInside: false,
@@ -10,7 +10,7 @@ Trestle.ready(function() {
10
10
  }
11
11
  });
12
12
 
13
- $('[data-behavior~="gallery"]').magnificPopup({
13
+ $(root).find('[data-behavior~="gallery"]').magnificPopup({
14
14
  delegate: 'a',
15
15
  type: 'image',
16
16
  closeOnContentClick: false,
@@ -1,5 +1,5 @@
1
- Trestle.ready(function() {
2
- $('select[data-enable-select2]').each(function() {
1
+ Trestle.init(function(e, root) {
2
+ $(root).find('select[data-enable-select2]').each(function() {
3
3
  $(this).select2({
4
4
  theme: 'bootstrap',
5
5
  containerCssClass: ':all:',
@@ -69,5 +69,7 @@ Trestle.ready(function() {
69
69
  // Scroll sidebar to active item
70
70
 
71
71
  var active = sidebar.find('.active');
72
- sidebar.find('.app-sidebar-inner').scrollTop(active.offset().top - 100);
72
+ if (active.length) {
73
+ sidebar.find('.app-sidebar-inner').scrollTop(active.offset().top - 100);
74
+ }
73
75
  });
@@ -1,4 +1,4 @@
1
- $(document).on('click', 'tr[data-url]', function(e) {
1
+ $(document).on('click', 'tr[data-url]:not([data-behavior="dialog"])', function(e) {
2
2
  var row = $(e.currentTarget);
3
3
 
4
4
  if (row.data('url') == 'auto') {
@@ -0,0 +1,24 @@
1
+ Trestle.init(function(e, root) {
2
+ $(root).find("a[data-toggle='tab']").on('shown.bs.tab', function(e) {
3
+ var hash = $(this).attr("href");
4
+
5
+ if (hash.substr(0, 1) == "#") {
6
+ history.replaceState({ turbolinks: {} }, "", "#!" + hash.substr(1));
7
+ }
8
+ });
9
+ });
10
+
11
+ Trestle.focusActiveTab = function() {
12
+ if (location.hash.substr(0, 2) == "#!") {
13
+ // Focus on active tab from URL
14
+ $("a[data-toggle='tab'][href='#" + location.hash.substr(2) + "']").tab("show");
15
+ } else if ($(".tab-pane:has(.has-error)").length) {
16
+ // Focus on first tab with errors
17
+ var pane = $(".tab-pane:has(.has-error)").first();
18
+ $("a[data-toggle='tab'][href='#" + pane.attr("id") + "']").tab("show");
19
+ }
20
+ };
21
+
22
+ Trestle.ready(function() {
23
+ Trestle.focusActiveTab();
24
+ });
@@ -0,0 +1,3 @@
1
+ Trestle.init(function(e, root) {
2
+ $(root).find('[data-toggle="tooltip"]').tooltip();
3
+ });
@@ -0,0 +1,13 @@
1
+ Trestle.refreshContext = function(context) {
2
+ var url = context.data('context');
3
+
4
+ $.get(url, function(data) {
5
+ context.html(data);
6
+ $(Trestle).trigger('init', context);
7
+ });
8
+ };
9
+
10
+ Trestle.refreshMainContext = function() {
11
+ var context = $('.app-main[data-context]');
12
+ Trestle.refreshContext(context);
13
+ };
@@ -6,7 +6,8 @@ Trestle.cookie = {
6
6
 
7
7
  for (i = cookies.length - 1; i >= 0; i--) {
8
8
  if (!cookies[i].indexOf(name)) {
9
- return cookies[i].replace(name, '');
9
+ var value = cookies[i].replace(name, '');
10
+ return decodeURIComponent(value);
10
11
  }
11
12
  }
12
13
 
@@ -0,0 +1,39 @@
1
+ // The ready function sets up a callback to run on each page load.
2
+ //
3
+ // Trestle.ready(function() {
4
+ // ...
5
+ // });
6
+ //
7
+ Trestle.ready = function(callback) {
8
+ $(Trestle).on('load', callback);
9
+ };
10
+
11
+ // The init function sets up a callback to run on each page load, as well as when elements are added to the page
12
+ // dynamically (e.g. via a modal). It is used to initialize dynamic elements such as date pickers, although it is
13
+ // preferable if they can be set up using event delegation on the document element.
14
+ //
15
+ // The callback is triggered with the applicable root/container element as the second argument.
16
+ //
17
+ // Trestle.init(function(e, root) {
18
+ // $(root).find('...');
19
+ // });
20
+ //
21
+ Trestle.init = function(callback) {
22
+ $(Trestle).on('init', callback);
23
+ };
24
+
25
+ // Initialize all elements within the document on page load.
26
+ Trestle.ready(function() {
27
+ $(Trestle).trigger('init', document);
28
+ });
29
+
30
+ // Trigger the page load events.
31
+ if (Trestle.turbolinks) {
32
+ $(document).on('turbolinks:load', function() {
33
+ $(Trestle).trigger("load");
34
+ });
35
+ } else {
36
+ $(document).ready(function() {
37
+ $(Trestle).trigger("load");
38
+ });
39
+ }
@@ -0,0 +1,10 @@
1
+ // The visit function is used to direct the user to the given URL. It is provided as an abstraction as the redirection
2
+ // is handled differently depending on whether or not Turbolinks is enabled.
3
+ //
4
+ // Trestle.visit("/admin/pages");
5
+ //
6
+ if (Trestle.turbolinks) {
7
+ Trestle.visit = function(url) { Turbolinks.visit(url); };
8
+ } else {
9
+ Trestle.visit = function(url) { document.location = url; };
10
+ }
@@ -1,6 +1,15 @@
1
1
  .btn {
2
2
  border: none;
3
3
  box-shadow: none;
4
+
5
+ &.loading {
6
+ &::before {
7
+ @extend .fa;
8
+ @extend .fa-spin;
9
+ content: $fa-var-spinner;
10
+ margin-right: 10px;
11
+ }
12
+ }
4
13
  }
5
14
 
6
15
  .btn-delete {
@@ -0,0 +1,92 @@
1
+ .modal-content {
2
+ border: none;
3
+ border-radius: 0;
4
+
5
+ .modal.loading & {
6
+ min-height: 100px;
7
+
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+
12
+ &:after {
13
+ @extend .fa;
14
+ @extend .fa-spin;
15
+ content: $fa-var-spinner;
16
+
17
+ font-size: 32px;
18
+ opacity: 0.25;
19
+ }
20
+ }
21
+ }
22
+
23
+ .modal-header {
24
+ background: $theme-bg;
25
+ border-bottom: none;
26
+
27
+ .close {
28
+ opacity: 0.75;
29
+
30
+ &, &:hover, &:focus {
31
+ color: white;
32
+ }
33
+
34
+ &:hover, &:focus {
35
+ opacity: 1;
36
+ }
37
+ }
38
+
39
+ .modal.error & {
40
+ background: $error-bg;
41
+ }
42
+ }
43
+
44
+ .modal-title {
45
+ font-size: 18px;
46
+ font-weight: 500;
47
+ text-shadow: rgba(black, 0.5) 0 1px 1px;
48
+ color: white;
49
+ }
50
+
51
+ .modal-tabs .nav-tabs {
52
+ background: $body-bg;
53
+ padding: 10px 15px 0 15px;
54
+ }
55
+
56
+ .modal-flash {
57
+ .alert {
58
+ margin-bottom: 0;
59
+ border-radius: 0;
60
+ border-width: 0 0 1px 0;
61
+
62
+ padding-top: 10px;
63
+ padding-bottom: 10px;
64
+
65
+ .alert-icon {
66
+ font-size: 40px;
67
+ margin-right: 15px;
68
+ }
69
+
70
+ h3 {
71
+ font-size: 18px;
72
+ }
73
+
74
+ p {
75
+ font-size: 13px;
76
+ }
77
+ }
78
+ }
79
+
80
+ .modal-body {
81
+ @extend .tab-content;
82
+ }
83
+
84
+ .modal-footer {
85
+ .primary-toolbar {
86
+ float: right;
87
+ }
88
+
89
+ .secondary-toolbar {
90
+ float: left;
91
+ }
92
+ }