trestle 0.8.7 → 0.8.8
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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/app/assets/javascripts/trestle/components/_datepicker.js +18 -3
- data/app/assets/javascripts/trestle/components/_dialog.js +5 -1
- data/app/assets/javascripts/trestle/components/_form.js +3 -1
- data/app/assets/javascripts/trestle/core/_l10n.js +23 -0
- data/app/assets/stylesheets/trestle/components/_avatar.scss +23 -0
- data/app/assets/stylesheets/trestle/components/_datepicker.scss +28 -0
- data/app/assets/stylesheets/trestle/components/_input-group.scss +18 -0
- data/app/helpers/trestle/avatar_helper.rb +7 -2
- data/app/helpers/trestle/debug_helper.rb +1 -1
- data/app/helpers/trestle/form_helper.rb +1 -1
- data/app/helpers/trestle/i18n_helper.rb +14 -0
- data/app/helpers/trestle/tab_helper.rb +2 -2
- data/app/helpers/trestle/url_helper.rb +37 -9
- data/app/views/layouts/trestle/admin.html.erb +1 -3
- data/app/views/trestle/application/_layout.html.erb +1 -1
- data/app/views/trestle/application/_tabs.html.erb +1 -1
- data/app/views/trestle/{application → flash}/_alert.html.erb +2 -2
- data/app/views/trestle/flash/_debug.html.erb +8 -0
- data/app/views/trestle/flash/_flash.html.erb +7 -0
- data/app/views/trestle/resource/edit.html.erb +5 -5
- data/app/views/trestle/resource/index.html.erb +2 -2
- data/app/views/trestle/resource/new.html.erb +4 -4
- data/app/views/trestle/resource/show.html.erb +5 -5
- data/app/views/trestle/shared/_sidebar.html.erb +2 -2
- data/config/locales/cs.rb +18 -0
- data/config/locales/cs.yml +95 -0
- data/config/locales/en.yml +43 -22
- data/config/locales/fr.yml +37 -22
- data/config/locales/nl.yml +37 -22
- data/config/locales/pl.yml +37 -22
- data/config/locales/pt-BR.yml +37 -22
- data/config/locales/zh-CN.rb +18 -0
- data/config/locales/zh-CN.yml +94 -0
- data/gemfiles/rails-5.2.gemfile +14 -0
- data/lib/trestle/adapters/adapter.rb +3 -3
- data/lib/trestle/admin.rb +30 -2
- data/lib/trestle/admin/builder.rb +17 -7
- data/lib/trestle/breadcrumb.rb +3 -1
- data/lib/trestle/configurable.rb +6 -0
- data/lib/trestle/configuration.rb +7 -1
- data/lib/trestle/engine.rb +5 -1
- data/lib/trestle/form/fields/date_picker.rb +2 -2
- data/lib/trestle/form/fields/form_group.rb +1 -1
- data/lib/trestle/resource.rb +38 -3
- data/lib/trestle/resource/builder.rb +10 -0
- data/lib/trestle/resource/controller.rb +36 -22
- data/lib/trestle/tab.rb +4 -0
- data/lib/trestle/table/column.rb +4 -4
- data/lib/trestle/table/row.rb +1 -1
- data/lib/trestle/version.rb +1 -1
- data/vendor/assets/javascripts/trestle/flatpickr.js.erb +2 -0
- metadata +12 -4
- data/app/views/trestle/application/_flash.html.erb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53abdb7410eddcbc8964772c60fb759385fd0cc94574234473d29613e3dc62ef
|
4
|
+
data.tar.gz: a204be909209b9d159d1c6939911ccd7b5cddaf8437d7e20158c68c2051e3528
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7542b845d75753fd65f9908674a9728977f11657babfdf4a59489f5c023778ae29ce0a38d423d6fff4dc2249cb264cbe541b5e530ca5d9f60bfe0d06b901c1f6
|
7
|
+
data.tar.gz: 4a16e94cc8a64ad8691f99243b137ea897258ac4fa2595d7ce45573e1cc2ffd96dcba6e801c2e587f910587e89713fe671fa62209f79cd6c3f1cda8f6964ce65
|
data/.travis.yml
CHANGED
@@ -1,15 +1,29 @@
|
|
1
|
+
Trestle.setupDatePicker = function(selectedDates, dateStr, instance) {
|
2
|
+
if ($(instance.input).data('allow-clear')) {
|
3
|
+
$('<a href="#">')
|
4
|
+
.on('click', function(e) {
|
5
|
+
e.preventDefault();
|
6
|
+
instance.clear();
|
7
|
+
})
|
8
|
+
.addClass('clear-datepicker')
|
9
|
+
.insertBefore(instance.altInput);
|
10
|
+
}
|
11
|
+
};
|
12
|
+
|
1
13
|
Trestle.init(function(e, root) {
|
2
14
|
$(root).find('input[type="date"][data-picker="true"]').flatpickr({
|
3
15
|
allowInput: true,
|
4
16
|
altInput: true,
|
5
|
-
altFormat: "m/d/Y",
|
17
|
+
altFormat: Trestle.i18n["admin.datepicker.formats.date"] || "m/d/Y",
|
18
|
+
onReady: Trestle.setupDatePicker
|
6
19
|
});
|
7
20
|
|
8
21
|
$(root).find('input[type="datetime"][data-picker="true"], input[type="datetime-local"][data-picker="true"]').flatpickr({
|
9
22
|
enableTime: true,
|
10
23
|
allowInput: true,
|
11
24
|
altInput: true,
|
12
|
-
altFormat: "m/d/Y h:i K",
|
25
|
+
altFormat: Trestle.i18n["admin.datepicker.formats.datetime"] || "m/d/Y h:i K",
|
26
|
+
onReady: Trestle.setupDatePicker
|
13
27
|
});
|
14
28
|
|
15
29
|
$(root).find('input[type="time"][data-picker="true"]').flatpickr({
|
@@ -17,6 +31,7 @@ Trestle.init(function(e, root) {
|
|
17
31
|
noCalendar: true,
|
18
32
|
allowInput: true,
|
19
33
|
altInput: true,
|
20
|
-
altFormat: "h:i K"
|
34
|
+
altFormat: Trestle.i18n["admin.datepicker.formats.time"] || "h:i K",
|
35
|
+
onReady: Trestle.setupDatePicker
|
21
36
|
});
|
22
37
|
});
|
@@ -46,7 +46,7 @@ Trestle.Dialog.showError = function(title, errorText) {
|
|
46
46
|
return dialog;
|
47
47
|
};
|
48
48
|
|
49
|
-
Trestle.Dialog.prototype.load = function(url) {
|
49
|
+
Trestle.Dialog.prototype.load = function(url, callback) {
|
50
50
|
var dialog = this;
|
51
51
|
|
52
52
|
dialog.show();
|
@@ -63,6 +63,10 @@ Trestle.Dialog.prototype.load = function(url) {
|
|
63
63
|
},
|
64
64
|
success: function(content) {
|
65
65
|
dialog.setContent(content);
|
66
|
+
|
67
|
+
if (callback) {
|
68
|
+
callback.apply(dialog);
|
69
|
+
}
|
66
70
|
},
|
67
71
|
error: function(xhr, status, error) {
|
68
72
|
var errorMessage = Trestle.i18n['trestle.dialog.error'] || 'The request could not be completed.';
|
@@ -63,7 +63,9 @@ Trestle.init(function(e, root) {
|
|
63
63
|
|
64
64
|
// Delay to ensure form is still submitted
|
65
65
|
setTimeout(function() {
|
66
|
-
|
66
|
+
if (form[0].checkValidity()) {
|
67
|
+
button.prop('disabled', true).addClass('loading');
|
68
|
+
}
|
67
69
|
}, 1);
|
68
70
|
});
|
69
71
|
});
|
@@ -0,0 +1,23 @@
|
|
1
|
+
(function() {
|
2
|
+
|
3
|
+
// Some of Flatpickr's locale names differ from Rails. This maps the Rails I18n locale to their Flatpickr equivalent.
|
4
|
+
var FlatpickrLocaleConversions = { ca: "cat", el: "gr", nb: "no", vi: "vn" };
|
5
|
+
|
6
|
+
// Sets up localization for Trestle and its dependencies, in particular Flatpickr.
|
7
|
+
// This method accepts a list of locales in descending order of priority.
|
8
|
+
//
|
9
|
+
// Trestle.localize('es-MX', 'es', 'en');
|
10
|
+
//
|
11
|
+
Trestle.localize = function() {
|
12
|
+
for (var i = 0; i < arguments.length; ++i) {
|
13
|
+
var locale = arguments[i];
|
14
|
+
var flatpickrLocale = FlatpickrLocaleConversions[locale] || locale;
|
15
|
+
|
16
|
+
if (flatpickr.l10ns[flatpickrLocale]) {
|
17
|
+
flatpickr.localize(flatpickr.l10ns[flatpickrLocale]);
|
18
|
+
break;
|
19
|
+
}
|
20
|
+
}
|
21
|
+
};
|
22
|
+
|
23
|
+
})();
|
@@ -1,5 +1,6 @@
|
|
1
1
|
.avatar {
|
2
2
|
display: inline-block;
|
3
|
+
position: relative;
|
3
4
|
|
4
5
|
width: 40px;
|
5
6
|
height: 40px;
|
@@ -14,5 +15,27 @@
|
|
14
15
|
height: 100%;
|
15
16
|
object-fit: cover;
|
16
17
|
border-radius: 50%;
|
18
|
+
|
19
|
+
position: relative;
|
20
|
+
z-index: 1;
|
21
|
+
}
|
22
|
+
|
23
|
+
.avatar-fallback {
|
24
|
+
position: absolute;
|
25
|
+
top: 0;
|
26
|
+
bottom: 0;
|
27
|
+
left: 0;
|
28
|
+
right: 0;
|
29
|
+
border-radius: 50%;
|
30
|
+
|
31
|
+
background: #ccc;
|
32
|
+
color: white;
|
33
|
+
|
34
|
+
display: flex;
|
35
|
+
align-items: center;
|
36
|
+
justify-content: center;
|
37
|
+
|
38
|
+
font-size: 11px;
|
39
|
+
font-weight: 500;
|
17
40
|
}
|
18
41
|
}
|
@@ -1,3 +1,31 @@
|
|
1
|
+
.clear-datepicker {
|
2
|
+
position: absolute;
|
3
|
+
top: 0;
|
4
|
+
right: 0;
|
5
|
+
z-index: 4;
|
6
|
+
|
7
|
+
width: 34px;
|
8
|
+
height: 34px;
|
9
|
+
line-height: 34px;
|
10
|
+
text-align: center;
|
11
|
+
|
12
|
+
color: #ccc;
|
13
|
+
|
14
|
+
&:hover, &:focus {
|
15
|
+
color: #aaa;
|
16
|
+
}
|
17
|
+
|
18
|
+
&::before {
|
19
|
+
@extend .fa;
|
20
|
+
content: $fa-var-times;
|
21
|
+
}
|
22
|
+
|
23
|
+
input[value=""] ~ &,
|
24
|
+
input:not([value]) ~ & {
|
25
|
+
display: none;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
1
29
|
.flatpickr-calendar {
|
2
30
|
background: $theme-bg;
|
3
31
|
|
@@ -2,6 +2,24 @@
|
|
2
2
|
|
3
3
|
.input-group {
|
4
4
|
display: flex;
|
5
|
+
|
6
|
+
.field_with_errors {
|
7
|
+
flex: 1;
|
8
|
+
|
9
|
+
.form-control {
|
10
|
+
border-radius: $input-border-radius;
|
11
|
+
}
|
12
|
+
|
13
|
+
&:not(:last-child) .form-control {
|
14
|
+
border-top-right-radius: 0;
|
15
|
+
border-bottom-right-radius: 0;
|
16
|
+
}
|
17
|
+
|
18
|
+
&:not(:first-child) .form-control {
|
19
|
+
border-top-left-radius: 0;
|
20
|
+
border-bottom-left-radius: 0;
|
21
|
+
}
|
22
|
+
}
|
5
23
|
}
|
6
24
|
|
7
25
|
.input-group-addon {
|
@@ -1,10 +1,15 @@
|
|
1
1
|
module Trestle
|
2
2
|
module AvatarHelper
|
3
|
-
def avatar(
|
4
|
-
content_tag(:div, class: "avatar"
|
3
|
+
def avatar(options={})
|
4
|
+
content_tag(:div, class: "avatar") do
|
5
|
+
concat content_tag(:span, options[:fallback], class: "avatar-fallback") if options[:fallback]
|
6
|
+
concat yield if block_given?
|
7
|
+
end
|
5
8
|
end
|
6
9
|
|
7
10
|
def gravatar(email, options={})
|
11
|
+
options = { d: "mm" }.merge(options)
|
12
|
+
|
8
13
|
url = "https://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(email.to_s.downcase)}.png"
|
9
14
|
url << "?#{options.to_query}" if options.any?
|
10
15
|
|
@@ -2,7 +2,7 @@ module Trestle
|
|
2
2
|
module FormHelper
|
3
3
|
def trestle_form_for(instance, options={}, &block)
|
4
4
|
options[:builder] ||= Form::Builder
|
5
|
-
options[:as] ||= admin.
|
5
|
+
options[:as] ||= admin.parameter_name
|
6
6
|
|
7
7
|
options[:data] ||= {}
|
8
8
|
options[:data].merge!(remote: true, type: :html, behavior: "trestle-form", turbolinks: false)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Trestle
|
2
|
+
module I18nHelper
|
3
|
+
def i18n_fallbacks(locale=I18n.locale)
|
4
|
+
if I18n.respond_to?(:fallbacks)
|
5
|
+
I18n.fallbacks[locale]
|
6
|
+
elsif locale.to_s.include?("-")
|
7
|
+
fallback = locale.to_s.split("-").first
|
8
|
+
[locale, fallback]
|
9
|
+
else
|
10
|
+
[locale]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -5,9 +5,9 @@ module Trestle
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def tab(name, options={})
|
8
|
-
tabs[name] = Tab.new(name, options)
|
8
|
+
tabs[name] = tab = Tab.new(name, options)
|
9
9
|
|
10
|
-
content_tag(:div, id:
|
10
|
+
content_tag(:div, id: tab.id(("modal" if dialog_request?)), class: ["tab-pane", ('active' if name == tabs.keys.first)], role: "tabpanel") do
|
11
11
|
if block_given?
|
12
12
|
yield
|
13
13
|
elsif options[:partial]
|
@@ -3,38 +3,51 @@ module Trestle
|
|
3
3
|
DIALOG_ACTIONS = [:new, :show, :edit]
|
4
4
|
|
5
5
|
def admin_link_to(content, instance_or_url=nil, options={}, &block)
|
6
|
+
# Block given - ignore content parameter and capture content from block
|
6
7
|
if block_given?
|
7
8
|
instance_or_url, options = content, instance_or_url || {}
|
8
9
|
content = capture(&block)
|
9
10
|
end
|
10
11
|
|
11
12
|
if instance_or_url.is_a?(String)
|
13
|
+
# Treat string URL as regular link
|
12
14
|
link_to(content, instance_or_url, options)
|
13
15
|
else
|
16
|
+
# Normalize options if instance is not provided
|
14
17
|
if instance_or_url.is_a?(Hash)
|
15
|
-
|
18
|
+
instance, options = nil, instance_or_url
|
19
|
+
else
|
20
|
+
instance = instance_or_url
|
16
21
|
end
|
17
22
|
|
23
|
+
# Determine admin
|
18
24
|
if options.key?(:admin)
|
19
25
|
admin = Trestle.lookup(options.delete(:admin))
|
20
|
-
elsif
|
21
|
-
admin = admin_for(
|
26
|
+
elsif instance
|
27
|
+
admin = admin_for(instance)
|
22
28
|
end
|
23
29
|
|
24
30
|
admin ||= self.admin if respond_to?(:admin)
|
25
31
|
|
26
32
|
if admin
|
33
|
+
# Generate path
|
27
34
|
action = options.delete(:action) || :show
|
28
|
-
|
29
35
|
params = options.delete(:params) || {}
|
30
|
-
params[:id] ||= admin.to_param(instance_or_url) if instance_or_url
|
31
36
|
|
37
|
+
if admin.respond_to?(:instance_path) && instance
|
38
|
+
path = admin.instance_path(instance, params.reverse_merge(action: action))
|
39
|
+
else
|
40
|
+
params[:id] ||= admin.to_param(instance) if instance
|
41
|
+
path = admin.path(action, params)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Determine link data options
|
32
45
|
if DIALOG_ACTIONS.include?(action) && admin.form.dialog?
|
33
46
|
options[:data] ||= {}
|
34
47
|
options[:data][:behavior] ||= "dialog"
|
35
48
|
end
|
36
49
|
|
37
|
-
link_to(content,
|
50
|
+
link_to(content, path, options)
|
38
51
|
else
|
39
52
|
raise ActionController::UrlGenerationError, "An admin could not be inferred. Please specify an admin using the :admin option."
|
40
53
|
end
|
@@ -42,14 +55,29 @@ module Trestle
|
|
42
55
|
end
|
43
56
|
|
44
57
|
def admin_url_for(instance, options={})
|
45
|
-
admin = Trestle.lookup(options
|
58
|
+
admin = Trestle.lookup(options.delete(:admin)) if options.key?(:admin)
|
46
59
|
admin ||= admin_for(instance)
|
60
|
+
return unless admin
|
47
61
|
|
48
|
-
admin.
|
62
|
+
if admin.respond_to?(:instance_path)
|
63
|
+
admin.instance_path(instance, options)
|
64
|
+
else
|
65
|
+
admin.path(options[:action] || :show, id: admin.to_param(instance))
|
66
|
+
end
|
49
67
|
end
|
50
68
|
|
51
69
|
def admin_for(instance)
|
52
|
-
|
70
|
+
klass = instance.class
|
71
|
+
|
72
|
+
while klass
|
73
|
+
admin = Trestle.admins[klass.name.underscore.pluralize]
|
74
|
+
return admin if admin
|
75
|
+
|
76
|
+
klass = klass.superclass
|
77
|
+
end
|
78
|
+
|
79
|
+
# No admin found
|
80
|
+
nil
|
53
81
|
end
|
54
82
|
end
|
55
83
|
end
|
@@ -26,9 +26,7 @@
|
|
26
26
|
Trestle.i18n['<%= key %>'] = "<%= escape_javascript(t(key, default: t(key, locale: :en))) %>";
|
27
27
|
<% end %>
|
28
28
|
|
29
|
-
|
30
|
-
flatpickr.localize(flatpickr.l10ns['<%= I18n.locale %>']);
|
31
|
-
}
|
29
|
+
Trestle.localize(<%= i18n_fallbacks.map { |l| "'#{l}'" }.join(", ").html_safe %>);
|
32
30
|
</script>
|
33
31
|
|
34
32
|
<%= hook :javascripts %>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<%= render "header", hide_breadcrumbs: local_assigns.fetch(:hide_breadcrumbs, false) if local_assigns.fetch(:header, true) %>
|
2
2
|
|
3
3
|
<div class="main-content-area">
|
4
|
-
<%= render "flash" %>
|
4
|
+
<%= render "trestle/flash/flash" %>
|
5
5
|
<%= render "utilities" %>
|
6
6
|
<%= render "tabs" %>
|
7
7
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
<ul class="nav nav-tabs">
|
3
3
|
<% tabs.each do |name, tab| %>
|
4
4
|
<li<% if name == tabs.keys.first %> class="active"<% end %>>
|
5
|
-
<%= link_to tab.label, "
|
5
|
+
<%= link_to tab.label, "##{tab.id(("modal" if dialog_request?))}", role: "tab", data: { toggle: "tab" } %>
|
6
6
|
</li>
|
7
7
|
<% end %>
|
8
8
|
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%= link_to "Debug errors", "#debug-errors", class: "toggle-debug-errors small", data: { toggle: "collapse" } %>
|
2
|
+
<div id="debug-errors" class="debug-errors collapse">
|
3
|
+
<ul>
|
4
|
+
<% instance.errors.each do |key, message| %>
|
5
|
+
<li class="small"><tt><%= key %>:</tt> <%= message %></li>
|
6
|
+
<% end %>
|
7
|
+
</ul>
|
8
|
+
</div>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<% if flash[:message] -%>
|
2
|
+
<%= render "trestle/flash/alert", html_class: "alert-success", icon: icon("alert-icon ion-ios-checkmark-outline"), alert: flash[:message].with_indifferent_access %>
|
3
|
+
<% elsif flash[:error] -%>
|
4
|
+
<%= render layout: "trestle/flash/alert", locals: { html_class: "alert-danger", icon: icon("alert-icon ion-ios-close-outline"), alert: flash[:error].with_indifferent_access } do %>
|
5
|
+
<%= render "trestle/flash/debug" if debug_form_errors? %>
|
6
|
+
<% end %>
|
7
|
+
<% end -%>
|
@@ -1,18 +1,18 @@
|
|
1
|
-
<% title = t("
|
1
|
+
<% title = admin.t("titles.edit", default: "Editing %{model_name}") %>
|
2
2
|
|
3
3
|
<% content_for(:title, title) %>
|
4
|
-
<% breadcrumb
|
4
|
+
<% breadcrumb(title) %>
|
5
5
|
|
6
6
|
<% content_for(:primary_toolbar) do %>
|
7
|
-
<%= button_tag t("
|
7
|
+
<%= button_tag admin.t("buttons.save", default: "Save %{model_name}"), class: "btn btn-success btn-lg" if admin.actions.include?(:update) %>
|
8
8
|
<% end %>
|
9
9
|
|
10
10
|
<% content_for(:secondary_toolbar) do %>
|
11
11
|
<%= admin_link_to instance, action: :destroy, method: :delete, class: "btn btn-danger", data: { toggle: "confirm-delete", placement: "bottom" } do %>
|
12
|
-
<%= icon("fa fa-trash") %> <%= t("
|
12
|
+
<%= icon("fa fa-trash") %> <%= admin.t("buttons.delete", default: "Delete %{model_name}") %>
|
13
13
|
<% end if admin.actions.include?(:destroy) %>
|
14
14
|
<% end %>
|
15
15
|
|
16
|
-
<%= trestle_form_for instance, url: admin.actions.include?(:update) ? admin.
|
16
|
+
<%= trestle_form_for instance, url: admin.actions.include?(:update) ? admin.instance_path(instance, action: :update) : "#", method: :patch do |f| %>
|
17
17
|
<%= render partial: "form", layout: dialog_request? ? "dialog" : "layout" %>
|
18
18
|
<% end %>
|