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