trestle 0.8.6 → 0.8.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +10 -9
  3. data/app/assets/javascripts/trestle/components/_dialog.js +29 -8
  4. data/app/assets/javascripts/trestle/components/_form.js +28 -7
  5. data/app/assets/javascripts/trestle/components/_sidebar.js +10 -8
  6. data/app/assets/javascripts/trestle/components/_tabs.js +2 -1
  7. data/app/assets/javascripts/trestle/components/_tooltips.js +16 -0
  8. data/app/assets/stylesheets/trestle/components/_modal.scss +4 -0
  9. data/app/assets/stylesheets/trestle/components/_navigation.scss +31 -11
  10. data/app/assets/stylesheets/trestle/components/_sidebar.scss +2 -2
  11. data/app/assets/stylesheets/trestle/components/_tags.scss +9 -0
  12. data/app/assets/stylesheets/trestle/components/_wells.scss +9 -1
  13. data/app/assets/stylesheets/trestle/core/_defaults.scss +4 -4
  14. data/app/assets/stylesheets/trestle/core/_layout.scss +8 -0
  15. data/app/assets/stylesheets/trestle/core/_typography.scss +39 -0
  16. data/app/controllers/concerns/trestle/controller/breadcrumbs.rb +21 -0
  17. data/app/controllers/concerns/trestle/controller/callbacks.rb +21 -0
  18. data/app/controllers/concerns/trestle/controller/dialog.rb +16 -0
  19. data/app/controllers/concerns/trestle/controller/helpers.rb +18 -0
  20. data/app/controllers/concerns/trestle/controller/layout.rb +16 -0
  21. data/app/controllers/concerns/trestle/controller/location.rb +15 -0
  22. data/app/controllers/trestle/application_controller.rb +6 -34
  23. data/app/helpers/trestle/debug_helper.rb +11 -0
  24. data/app/helpers/trestle/format_helper.rb +7 -3
  25. data/app/helpers/trestle/headings_helper.rb +27 -0
  26. data/app/helpers/trestle/panel_helper.rb +24 -0
  27. data/app/helpers/trestle/table_helper.rb +41 -2
  28. data/app/helpers/trestle/url_helper.rb +3 -1
  29. data/app/views/layouts/trestle/admin.html.erb +1 -1
  30. data/app/views/trestle/application/_flash.html.erb +1 -1
  31. data/app/views/trestle/shared/_sidebar.html.erb +2 -2
  32. data/app/views/trestle/table/_table.html.erb +2 -6
  33. data/lib/generators/trestle/resource/templates/admin.rb.erb +2 -2
  34. data/lib/trestle.rb +6 -4
  35. data/lib/trestle/adapters/active_record_adapter.rb +0 -4
  36. data/lib/trestle/adapters/adapter.rb +15 -10
  37. data/lib/trestle/adapters/sequel_adapter.rb +0 -4
  38. data/lib/trestle/admin.rb +18 -1
  39. data/lib/trestle/admin/builder.rb +22 -10
  40. data/lib/trestle/form/automatic.rb +5 -2
  41. data/lib/trestle/form/builder.rb +5 -1
  42. data/lib/trestle/form/field.rb +1 -1
  43. data/lib/trestle/form/fields/form_group.rb +3 -1
  44. data/lib/trestle/form/fields/select.rb +5 -1
  45. data/lib/trestle/form/fields/tag_select.rb +1 -1
  46. data/lib/trestle/form/renderer.rb +1 -1
  47. data/lib/trestle/navigation.rb +11 -5
  48. data/lib/trestle/navigation/item.rb +10 -0
  49. data/lib/trestle/resource.rb +27 -61
  50. data/lib/trestle/resource/builder.rb +15 -14
  51. data/lib/trestle/resource/collection.rb +48 -0
  52. data/lib/trestle/resource/controller.rb +36 -23
  53. data/lib/trestle/scope.rb +13 -3
  54. data/lib/trestle/table.rb +10 -4
  55. data/lib/trestle/table/column.rb +13 -2
  56. data/lib/trestle/table/row.rb +10 -0
  57. data/lib/trestle/version.rb +1 -1
  58. data/trestle.gemspec +1 -0
  59. data/vendor/assets/stylesheets/trestle/magnific-popup.scss +13 -1
  60. metadata +27 -4
  61. data/app/helpers/trestle/dialog_helper.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 1f07f2d3328a13c6ac319c7e04b8926a0dc09660
4
- data.tar.gz: a8adb65b4c3bd295c5e80397fba9c8968d08febd
2
+ SHA256:
3
+ metadata.gz: a9c0345d2065a71ba7b11d5044f6cf0db55e08d8a9e0d5d3a83c715bf029f76f
4
+ data.tar.gz: 8ce2f2a003d051204d1ad0017be70a9fe220ed0e4bf47bc2f3e6234ad751c316
5
5
  SHA512:
6
- metadata.gz: 9d565ea8bd72cca11c5eb2de1ea72332e8980093e5f4147f598f64958ee82b3f1799de37dc7c2c99b68cbb773821454ee62c5230b4ba55bdc50828e516dc347e
7
- data.tar.gz: da2e9069173f7fa34f0af87c392af4b00dc9ea5b9b42eb2e6cb3c2df536065bd9648b5482043260c748e919fa735127d3fafb32537e523fe356da52765d7221a
6
+ metadata.gz: 8638b5a1c9cd255fde7251ebb44d86f602523d5c6ef383044a033e2239973c6239ff4f7d018d9273fc232805b41bb7a4ad15f83110fd5e95d0cddcdf4c2fbca4
7
+ data.tar.gz: b4f2bcdb3835d26b81186b790952c602069e4bae7a59cf0791370c455a6488502943f426fc91505595761a6fc1f6b57718bda02a0fff638fdd154c2b7c8b0d7d
data/README.md CHANGED
@@ -4,10 +4,10 @@
4
4
 
5
5
  # Trestle
6
6
 
7
- [![RubyGem](https://img.shields.io/gem/v/trestle.svg?style=flat-square&colorB=4065a9)](https://rubygems.org/gems/trestle)
8
- [![Travis](https://img.shields.io/travis/TrestleAdmin/trestle.svg?style=flat-square)](https://travis-ci.org/TrestleAdmin/trestle)
9
- [![Code Climate](https://img.shields.io/codeclimate/github/TrestleAdmin/trestle.svg?style=flat-square)](https://codeclimate.com/github/TrestleAdmin/trestle)
10
- [![Coveralls](https://img.shields.io/coveralls/TrestleAdmin/trestle.svg?style=flat-square)](https://coveralls.io/github/TrestleAdmin/trestle)
7
+ [![RubyGem](https://img.shields.io/gem/v/trestle.svg?style=flat&colorB=4065a9)](https://rubygems.org/gems/trestle)
8
+ [![Travis](https://img.shields.io/travis/TrestleAdmin/trestle.svg?style=flat)](https://travis-ci.org/TrestleAdmin/trestle)
9
+ [![Coveralls](https://img.shields.io/coveralls/TrestleAdmin/trestle.svg?style=flat)](https://coveralls.io/github/TrestleAdmin/trestle)
10
+ [![Code Climate](https://api.codeclimate.com/v1/badges/c529a7a9c500ed81baed/maintainability)](https://codeclimate.com/github/TrestleAdmin/trestle)
11
11
 
12
12
  > A modern, responsive admin framework for Ruby on Rails
13
13
 
@@ -87,12 +87,13 @@ end
87
87
 
88
88
  The following plugins are currently available:
89
89
 
90
- | Name | Description | GitHub |
90
+ | Name | Description | Links |
91
91
  | --- | --- | --- |
92
- | *trestle-auth* | User authentication plugin | https://github.com/TrestleAdmin/trestle-auth |
93
- | *trestle-search* | Search plugin | https://github.com/TrestleAdmin/trestle-search |
94
- | *trestle-tinymce* | TinyMCE (WYSIWYG editor) integration | https://github.com/TrestleAdmin/trestle-tinymce |
95
- | *trestle-simplemde* | SimpleMDE (Markdown editor) integration | https://github.com/TrestleAdmin/trestle-simplemde |
92
+ | *trestle-auth* | User authentication plugin | [GitHub](https://github.com/TrestleAdmin/trestle-auth) \| [RubyGems](https://rubygems.org/gems/trestle-auth) |
93
+ | *trestle-search* | Search plugin | [GitHub](https://github.com/TrestleAdmin/trestle-search) \| [RubyGems](https://rubygems.org/gems/trestle-search) |
94
+ | *trestle-tinymce* | [TinyMCE](https://www.tinymce.com/) (WYSIWYG editor) integration | [GitHub](https://github.com/TrestleAdmin/trestle-tinymce) \| [RubyGems](https://rubygems.org/gems/trestle-tinymce) |
95
+ | *trestle-simplemde* | [SimpleMDE](https://simplemde.com/) (Markdown editor) integration | [GitHub](https://github.com/TrestleAdmin/trestle-simplemde) \| [RubyGems](https://rubygems.org/gems/trestle-simplemde) |
96
+ | *trestle-sidekiq* | [Sidekiq](http://sidekiq.org/) integration | [GitHub](https://github.com/TrestleAdmin/trestle-sidekiq) \| [RubyGems](https://rubygems.org/gems/trestle-sidekiq) |
96
97
 
97
98
 
98
99
  ## License
@@ -1,5 +1,11 @@
1
- Trestle.Dialog = function() {
1
+ Trestle.Dialog = function(options) {
2
+ options = options || {};
3
+
2
4
  this.el = Trestle.Dialog.getElement();
5
+
6
+ if (options.modalClass) {
7
+ this.el.find('.modal-dialog').addClass(options.modalClass);
8
+ }
3
9
  };
4
10
 
5
11
  Trestle.Dialog.TEMPLATE =
@@ -31,6 +37,15 @@ Trestle.Dialog.getElement = function() {
31
37
  return el;
32
38
  };
33
39
 
40
+ Trestle.Dialog.showError = function(title, errorText) {
41
+ var dialog = new Trestle.Dialog({ modalClass: 'modal-lg' });
42
+
43
+ dialog.showError(title, $('<pre>').addClass('exception').text(errorText));
44
+ dialog.show();
45
+
46
+ return dialog;
47
+ };
48
+
34
49
  Trestle.Dialog.prototype.load = function(url) {
35
50
  var dialog = this;
36
51
 
@@ -50,7 +65,12 @@ Trestle.Dialog.prototype.load = function(url) {
50
65
  dialog.setContent(content);
51
66
  },
52
67
  error: function(xhr, status, error) {
53
- dialog.showError(error);
68
+ var errorMessage = Trestle.i18n['trestle.dialog.error'] || 'The request could not be completed.';
69
+
70
+ var title = error || errorMessage;
71
+ var content = $('<p>').text(errorMessage);
72
+
73
+ dialog.showError(title, content);
54
74
  }
55
75
  });
56
76
  };
@@ -68,20 +88,18 @@ Trestle.Dialog.prototype.setContent = function(content) {
68
88
  $(Trestle).trigger('init', this.el);
69
89
  };
70
90
 
71
- Trestle.Dialog.prototype.showError = function(error) {
91
+ Trestle.Dialog.prototype.showError = function(title, content) {
72
92
  this.el.addClass('error');
73
93
 
74
94
  var container = this.el.find('.modal-content').empty();
75
95
 
76
- var errorMessage = Trestle.i18n['trestle.dialog.error'] || 'The request could not be completed.';
77
-
78
96
  $('<div class="modal-header">')
79
97
  .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()
98
+ .append('<h4 class="modal-title"></h4>').find('h4').text(title).end()
81
99
  .appendTo(container);
82
100
 
83
101
  $('<div class="modal-body">')
84
- .append('<p>').find('p').text(errorMessage).end()
102
+ .append(content)
85
103
  .appendTo(container);
86
104
 
87
105
  $('<div class="modal-footer">')
@@ -102,6 +120,9 @@ $(document).on('click', '[data-behavior="dialog"]', function(e) {
102
120
 
103
121
  var url = $(this).data('url') || $(this).attr('href');
104
122
 
105
- var dialog = new Trestle.Dialog();
123
+ var dialog = new Trestle.Dialog({
124
+ modalClass: $(this).data('dialog-class')
125
+ });
126
+
106
127
  dialog.load(url);
107
128
  });
@@ -10,15 +10,36 @@ Trestle.init(function(e, root) {
10
10
 
11
11
  form
12
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);
13
+ var contentType = xhr.getResponseHeader("Content-Type").split(";")[0];
14
+
15
+ if (contentType == "text/html") {
16
+ if (/<html/i.test(xhr.responseText)) {
17
+ // Response is a full HTML page, likely an error page. Render within an iframe.
18
+
19
+ var context = $(this).closest('[data-context]');
20
+ var iframe = $("<iframe>").addClass('error-iframe').get(0);
21
+ context.html(iframe);
16
22
 
17
- // Initialize replaced elements within the context
18
- $(Trestle).trigger('init', context);
23
+ iframe.contentWindow.document.documentElement.innerHTML = xhr.responseText;
24
+ } else {
25
+ // Find the parent context and replace content
26
+ var context = $(this).closest('[data-context]');
27
+ context.html(xhr.responseText);
19
28
 
20
- // Focus the correct tab
21
- Trestle.focusActiveTab();
29
+ // Initialize replaced elements within the context
30
+ $(Trestle).trigger('init', context);
31
+
32
+ // Focus the correct tab
33
+ Trestle.focusActiveTab();
34
+ }
35
+ } else {
36
+ // Assume an error response
37
+ var title = xhr.status + " (" + xhr.statusText + ")";
38
+ Trestle.Dialog.showError(title, xhr.responseText);
39
+
40
+ // Reset submit button
41
+ form.find(':submit').prop('disabled', false).removeClass('loading');
42
+ }
22
43
  })
23
44
  .on('ajax:success', function(e, data, status, xhr) {
24
45
  var context = $(this).closest('[data-context]');
@@ -1,4 +1,6 @@
1
1
  Trestle.ready(function() {
2
+ var body = $('body');
3
+ var wrapper = $('.app-wrapper');
2
4
  var sidebar = $('.app-sidebar');
3
5
 
4
6
  // Toggle mobile navigation using menu button
@@ -6,18 +8,18 @@ Trestle.ready(function() {
6
8
  sidebar.find('.navbar-toggle').on('click', function(e) {
7
9
  e.preventDefault();
8
10
 
9
- $('.app-wrapper').addClass('animate');
10
- $('body').toggleClass('mobile-nav-expanded');
11
+ wrapper.addClass('animate');
12
+ body.toggleClass('mobile-nav-expanded');
11
13
  });
12
14
 
13
- $('.app-wrapper').on('transitionend webkitTransitionEnd', function() {
15
+ wrapper.on('transitionend webkitTransitionEnd', function() {
14
16
  $(this).removeClass('animate');
15
17
  });
16
18
 
17
19
 
18
20
  // Interacting outside of the sidebar closes the navigation
19
21
 
20
- $('.app-wrapper').on('click touchstart', function(e) {
22
+ wrapper.on('click touchstart', function(e) {
21
23
  var navExpanded = $('body').hasClass('mobile-nav-expanded');
22
24
 
23
25
  var clickInHeader = $(e.target).closest('.app-header').length;
@@ -38,14 +40,14 @@ Trestle.ready(function() {
38
40
  sidebar.find('.toggle-sidebar').on('click', function(e) {
39
41
  e.preventDefault();
40
42
 
41
- if (sidebar.hasClass('expanded') || sidebar.hasClass('collapsed')) {
42
- sidebar.removeClass('expanded').removeClass('collapsed');
43
+ if (body.hasClass('sidebar-expanded') || body.hasClass('sidebar-collapsed')) {
44
+ body.removeClass('sidebar-expanded').removeClass('sidebar-collapsed');
43
45
  Trestle.cookie.delete("trestle:sidebar");
44
46
  } else if ($(document).width() >= 1200) {
45
- sidebar.addClass('collapsed');
47
+ body.addClass('sidebar-collapsed');
46
48
  Trestle.cookie.set("trestle:sidebar", "collapsed");
47
49
  } else if ($(document).width() >= 768) {
48
- sidebar.addClass('expanded');
50
+ body.addClass('sidebar-expanded');
49
51
  Trestle.cookie.set("trestle:sidebar", "expanded");
50
52
  }
51
53
  });
@@ -1,8 +1,9 @@
1
1
  Trestle.init(function(e, root) {
2
2
  $(root).find("a[data-toggle='tab']").on('shown.bs.tab', function(e) {
3
3
  var hash = $(this).attr("href");
4
+ var withinModal = $(this).closest('.modal').length > 0;
4
5
 
5
- if (hash.substr(0, 1) == "#") {
6
+ if (hash.substr(0, 1) == "#" && !withinModal) {
6
7
  history.replaceState({ turbolinks: {} }, "", "#!" + hash.substr(1));
7
8
  }
8
9
  });
@@ -1,3 +1,19 @@
1
1
  Trestle.init(function(e, root) {
2
2
  $(root).find('[data-toggle="tooltip"]').tooltip();
3
+ $(root).find('[data-toggle="popover"]').popover();
3
4
  });
5
+
6
+ if (!('ontouchstart' in window)) {
7
+ Trestle.ready(function() {
8
+ $(document).tooltip({
9
+ selector: '.app-nav a',
10
+ trigger: 'hover',
11
+ placement: 'right',
12
+ container: 'body',
13
+ template: '<div class="tooltip nav-tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
14
+ title: function() {
15
+ return $(this).find('.nav-label').text();
16
+ }
17
+ });
18
+ });
19
+ };
@@ -79,6 +79,10 @@
79
79
 
80
80
  .modal-body {
81
81
  @extend .tab-content;
82
+
83
+ pre.exception {
84
+ max-height: 75vh;
85
+ }
82
86
  }
83
87
 
84
88
  .modal-footer {
@@ -93,6 +93,10 @@
93
93
  }
94
94
  }
95
95
 
96
+ .nav-tooltip {
97
+ display: none !important;
98
+ }
99
+
96
100
  @mixin collapsed-nav-header {
97
101
  height: 0;
98
102
  padding: 10px 15px 15px;
@@ -124,6 +128,10 @@
124
128
  }
125
129
 
126
130
  @include tablet {
131
+ .nav-tooltip {
132
+ display: block !important;
133
+ }
134
+
127
135
  .app-nav {
128
136
  .nav-label, .nav-badge {
129
137
  display: none;
@@ -138,8 +146,10 @@
138
146
  display: block;
139
147
  }
140
148
  }
149
+ }
141
150
 
142
- .expanded & {
151
+ .sidebar-expanded {
152
+ .app-nav {
143
153
  .nav-header a {
144
154
  height: auto;
145
155
  padding: 5px 20px;
@@ -159,23 +169,33 @@
159
169
  .nav-label { display: inline; }
160
170
  .nav-badge { display: block; }
161
171
  }
172
+
173
+ .nav-tooltip {
174
+ display: none !important;
175
+ }
162
176
  }
163
177
  }
164
178
 
165
179
  @include desktop {
166
- .collapsed .app-nav {
167
- .nav-label, .nav-badge {
168
- display: none;
169
- }
180
+ .sidebar-collapsed {
181
+ .app-nav {
182
+ .nav-label, .nav-badge {
183
+ display: none;
184
+ }
170
185
 
171
- .nav-header a {
172
- @include collapsed-nav-header;
173
- }
186
+ .nav-header a {
187
+ @include collapsed-nav-header;
188
+ }
174
189
 
175
- .collapsed .nav-header a {
176
- &::after {
177
- display: block;
190
+ .collapsed .nav-header a {
191
+ &::after {
192
+ display: block;
193
+ }
178
194
  }
179
195
  }
196
+
197
+ .nav-tooltip {
198
+ display: block !important;
199
+ }
180
200
  }
181
201
  }
@@ -171,7 +171,7 @@
171
171
  content: $fa-var-angle-double-right;
172
172
  }
173
173
 
174
- &.expanded {
174
+ .sidebar-expanded & {
175
175
  width: $sidebar-width;
176
176
 
177
177
  .app-sidebar-header {
@@ -204,7 +204,7 @@
204
204
 
205
205
  @include desktop {
206
206
  .app-sidebar {
207
- &.collapsed {
207
+ .sidebar-collapsed & {
208
208
  width: $sidebar-width-collapsed;
209
209
 
210
210
  .app-sidebar-header {
@@ -14,6 +14,15 @@
14
14
  }
15
15
  }
16
16
 
17
+ a.tag {
18
+ &:hover, &:focus {
19
+ text-decoration: none;
20
+ color: white;
21
+ background: $brand-primary;
22
+ border-left-color: darken($brand-primary, 10%);
23
+ }
24
+ }
25
+
17
26
  .tag-select {
18
27
  &.select2-selection--multiple {
19
28
  .select2-selection__choice {
@@ -1,5 +1,5 @@
1
1
  .well {
2
- padding: 20px;
2
+ padding: 15px;
3
3
 
4
4
  box-shadow: none;
5
5
  border-radius: 0;
@@ -13,6 +13,14 @@
13
13
  }
14
14
  }
15
15
 
16
+ .well-lg {
17
+ padding: 24px;
18
+ }
19
+
20
+ .well-sm {
21
+ padding: 9px;
22
+ }
23
+
16
24
  .main-content-sidebar .well {
17
25
  margin: 0 -20px;
18
26
  background: darken($well-bg, 3%);
@@ -31,8 +31,8 @@ $sidebar-toggle-color: rgba(white, 0.5) !default;
31
31
 
32
32
  $content-header-background: rgba(white, 0.6) !default;
33
33
 
34
- $content-sidebar-width: 275px !default;
35
- $content-sidebar-background: rgba(black, 0.025);
34
+ $content-sidebar-width: 285px !default;
35
+ $content-sidebar-background: rgba(black, 0.025) !default;
36
36
 
37
37
  $sidebar-transition-duration: 250ms !default;
38
38
 
@@ -65,9 +65,9 @@ $table-bg-accent: rgba(black, 0.02) !default;
65
65
  $table-bg-hover: rgba(black, 0.04) !default;
66
66
  $table-border-color: rgba(black, 0.13) !default;
67
67
 
68
- $well-border: transparent;
68
+ $well-border: transparent !default;
69
69
 
70
- $panel-border-radius: 0;
70
+ $panel-border-radius: 0 !default;
71
71
 
72
72
  $popover-shadow: 0 3px 6px rgba(black, .175) !default;
73
73
  $dropdown-shadow: $popover-shadow !default;
@@ -41,6 +41,9 @@ img {
41
41
 
42
42
  .app-main {
43
43
  flex: 1 0 auto;
44
+
45
+ display: flex;
46
+ flex-direction: column;
44
47
  }
45
48
 
46
49
  .app-footer {
@@ -57,6 +60,11 @@ img {
57
60
  }
58
61
  }
59
62
 
63
+ .error-iframe {
64
+ border: 0;
65
+ flex: 1;
66
+ }
67
+
60
68
  @include mobile {
61
69
  body {
62
70
  height: auto;
@@ -19,6 +19,45 @@ a {
19
19
  border-radius: 10em !important;
20
20
  }
21
21
 
22
+ .main-content-sidebar {
23
+ font-size: 13px;
24
+
25
+ h1, h2, h3, h4, h5, h6 {
26
+ color: #666;
27
+ border-bottom: 1px solid #ddd;
28
+
29
+ padding-top: 5px;
30
+ padding-bottom: 0.5em;
31
+
32
+ margin-top: 20px;
33
+ margin-bottom: 15px;
34
+ }
35
+
36
+ h1 {
37
+ font-size: 28px;
38
+ }
39
+
40
+ h2 {
41
+ font-size: 24px;
42
+ }
43
+
44
+ h3 {
45
+ font-size: 21px;
46
+ }
47
+
48
+ h4 {
49
+ font-size: 17px;
50
+ }
51
+
52
+ h5 {
53
+ font-size: 14px;
54
+ }
55
+
56
+ h6 {
57
+ font-size: 12px;
58
+ }
59
+ }
60
+
22
61
  @include mobile {
23
62
  h1 {
24
63
  font-size: $font-size-h1 - 6px;