trestle 0.8.4 → 0.8.11
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 +5 -5
- data/.gitignore +4 -0
- data/.travis.yml +14 -1
- data/Gemfile +6 -0
- data/README.md +15 -9
- data/app/assets/javascripts/trestle/admin.js +11 -10
- data/app/assets/javascripts/trestle/components/_confirmation.js +40 -0
- data/app/assets/javascripts/trestle/components/_datepicker.js +37 -0
- data/app/assets/javascripts/trestle/components/_dialog.js +136 -0
- data/app/assets/javascripts/trestle/{_errors.js → components/_errors.js} +2 -2
- data/app/assets/javascripts/trestle/components/_form.js +75 -0
- data/app/assets/javascripts/trestle/{_gallery.js → components/_gallery.js} +3 -3
- data/app/assets/javascripts/trestle/{_select.js → components/_select.js} +2 -2
- data/app/assets/javascripts/trestle/components/_sidebar.js +77 -0
- data/app/assets/javascripts/trestle/{_table.js → components/_table.js} +1 -1
- data/app/assets/javascripts/trestle/components/_tabs.js +25 -0
- data/app/assets/javascripts/trestle/components/_tooltips.js +19 -0
- data/app/assets/javascripts/trestle/core/_contexts.js +13 -0
- data/app/assets/javascripts/trestle/core/_cookies.js +24 -0
- data/app/assets/javascripts/trestle/core/_events.js +39 -0
- data/app/assets/javascripts/trestle/core/_l10n.js +23 -0
- data/app/assets/javascripts/trestle/core/_visit.js +10 -0
- data/app/assets/stylesheets/trestle/components/_alerts.scss +28 -0
- data/app/assets/stylesheets/trestle/components/_avatar.scss +23 -1
- data/app/assets/stylesheets/trestle/components/_breadcrumbs.scss +12 -0
- data/app/assets/stylesheets/trestle/components/_buttons.scss +111 -1
- data/app/assets/stylesheets/trestle/components/_content.scss +53 -21
- data/app/assets/stylesheets/trestle/components/_datepicker.scss +28 -0
- data/app/assets/stylesheets/trestle/components/_fields.scss +17 -0
- data/app/assets/stylesheets/trestle/components/_input-group.scss +26 -1
- data/app/assets/stylesheets/trestle/components/_modal.scss +108 -0
- data/app/assets/stylesheets/trestle/components/_navigation.scss +104 -14
- data/app/assets/stylesheets/trestle/components/_pagination.scss +3 -3
- data/app/assets/stylesheets/trestle/components/_scopes.scss +11 -2
- data/app/assets/stylesheets/trestle/components/_sidebar.scss +3 -2
- data/app/assets/stylesheets/trestle/components/_table.scss +34 -10
- data/app/assets/stylesheets/trestle/components/_tags.scss +9 -0
- data/app/assets/stylesheets/trestle/components/_timestamp.scss +4 -1
- data/app/assets/stylesheets/trestle/components/_toolbars.scss +55 -0
- data/app/assets/stylesheets/trestle/components/_wells.scss +9 -1
- data/app/assets/stylesheets/trestle/core/_defaults.scss +21 -6
- data/app/assets/stylesheets/trestle/core/_layout.scss +8 -0
- data/app/assets/stylesheets/trestle/core/_mixins.scss +11 -0
- data/app/assets/stylesheets/trestle/core/_typography.scss +39 -0
- data/app/controllers/concerns/trestle/controller/breadcrumbs.rb +21 -0
- data/app/controllers/concerns/trestle/controller/callbacks.rb +21 -0
- data/app/controllers/concerns/trestle/controller/dialog.rb +16 -0
- data/app/controllers/concerns/trestle/controller/helpers.rb +18 -0
- data/app/controllers/concerns/trestle/controller/layout.rb +16 -0
- data/app/controllers/concerns/trestle/controller/location.rb +15 -0
- data/app/controllers/trestle/application_controller.rb +6 -30
- data/app/helpers/trestle/avatar_helper.rb +9 -2
- data/app/helpers/trestle/flash_helper.rb +15 -0
- data/app/helpers/trestle/form_helper.rb +8 -5
- data/app/helpers/trestle/format_helper.rb +7 -3
- data/app/helpers/trestle/headings_helper.rb +27 -0
- data/app/helpers/trestle/hook_helper.rb +13 -4
- data/app/helpers/trestle/i18n_helper.rb +14 -0
- data/app/helpers/trestle/panel_helper.rb +24 -0
- data/app/helpers/trestle/tab_helper.rb +2 -2
- data/app/helpers/trestle/table_helper.rb +41 -2
- data/app/helpers/trestle/timestamp_helper.rb +49 -7
- data/app/helpers/trestle/toolbars_helper.rb +34 -0
- data/app/helpers/trestle/url_helper.rb +72 -8
- data/app/views/layouts/trestle/admin.html.erb +3 -5
- data/app/views/trestle/application/_dialog.html.erb +34 -0
- data/app/views/trestle/application/_header.html.erb +22 -20
- data/app/views/trestle/application/_layout.html.erb +1 -1
- data/app/views/trestle/application/_tabs.html.erb +8 -2
- data/app/views/trestle/{application → flash}/_alert.html.erb +7 -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/_scopes.html.erb +1 -1
- data/app/views/trestle/resource/edit.html.erb +8 -10
- data/app/views/trestle/resource/index.html.erb +16 -4
- data/app/views/trestle/resource/new.html.erb +6 -6
- data/app/views/trestle/resource/show.html.erb +8 -10
- data/app/views/trestle/shared/_sidebar.html.erb +10 -7
- data/app/views/trestle/shared/_title.html.erb +14 -0
- data/app/views/trestle/table/_table.html.erb +4 -6
- data/bower.json +1 -1
- data/config/locales/cs.rb +18 -0
- data/config/locales/cs.yml +95 -0
- data/config/locales/en.yml +65 -36
- data/config/locales/es-MX.yml +94 -0
- data/config/locales/es.yml +94 -0
- data/config/locales/fr.rb +18 -0
- data/config/locales/fr.yml +84 -0
- data/config/locales/lv.rb +18 -0
- data/config/locales/lv.yml +94 -0
- data/config/locales/nl.rb +18 -0
- data/config/locales/nl.yml +82 -0
- data/config/locales/pl.rb +18 -0
- data/config/locales/pl.yml +85 -0
- data/config/locales/pt-BR.rb +18 -0
- data/config/locales/pt-BR.yml +84 -0
- data/config/locales/zh-CN.rb +18 -0
- data/config/locales/zh-CN.yml +94 -0
- data/gemfiles/rails-4.2.gemfile +16 -0
- data/gemfiles/rails-5.0.gemfile +16 -0
- data/gemfiles/rails-5.1.gemfile +16 -0
- data/gemfiles/rails-5.2.gemfile +16 -0
- data/gemfiles/rails-edge.gemfile +17 -0
- data/lib/generators/trestle/install/templates/trestle.rb.erb +18 -2
- data/lib/generators/trestle/resource/templates/admin.rb.erb +2 -2
- data/lib/trestle/adapters/active_record_adapter.rb +2 -6
- data/lib/trestle/adapters/adapter.rb +40 -15
- data/lib/trestle/adapters/sequel_adapter.rb +2 -6
- data/lib/trestle/admin/builder.rb +42 -12
- data/lib/trestle/admin/controller.rb +3 -1
- data/lib/trestle/admin.rb +84 -3
- data/lib/trestle/breadcrumb.rb +16 -1
- data/lib/trestle/configurable.rb +6 -0
- data/lib/trestle/configuration.rb +28 -5
- data/lib/trestle/display.rb +1 -1
- data/lib/trestle/engine.rb +10 -4
- data/lib/trestle/form/automatic.rb +6 -3
- data/lib/trestle/form/builder.rb +5 -1
- data/lib/trestle/form/field.rb +1 -1
- data/lib/trestle/form/fields/date_picker.rb +2 -2
- data/lib/trestle/form/fields/form_control.rb +14 -4
- data/lib/trestle/form/fields/form_group.rb +14 -3
- data/lib/trestle/form/fields/select.rb +5 -1
- data/lib/trestle/form/fields/tag_select.rb +1 -1
- data/lib/trestle/form/renderer.rb +2 -2
- data/lib/trestle/form.rb +7 -3
- data/lib/trestle/hook.rb +27 -0
- data/lib/trestle/model_name.rb +64 -0
- data/lib/trestle/navigation/group.rb +16 -0
- data/lib/trestle/navigation/item.rb +11 -1
- data/lib/trestle/navigation.rb +24 -6
- data/lib/trestle/options.rb +7 -5
- data/lib/trestle/reloader.rb +1 -1
- data/lib/trestle/resource/adapter_methods.rb +62 -0
- data/lib/trestle/resource/builder.rb +43 -17
- data/lib/trestle/resource/collection.rb +68 -0
- data/lib/trestle/resource/controller.rb +70 -33
- data/lib/trestle/resource.rb +97 -105
- data/lib/trestle/scope.rb +13 -3
- data/lib/trestle/tab.rb +4 -0
- data/lib/trestle/table/actions_column.rb +41 -31
- data/lib/trestle/table/automatic.rb +1 -2
- data/lib/trestle/table/builder.rb +2 -2
- data/lib/trestle/table/column.rb +40 -9
- data/lib/trestle/table/row.rb +18 -2
- data/lib/trestle/table.rb +18 -2
- data/lib/trestle/toolbar/builder.rb +52 -0
- data/lib/trestle/toolbar/context.rb +39 -0
- data/lib/trestle/toolbar.rb +43 -0
- data/lib/trestle/version.rb +1 -1
- data/lib/trestle.rb +9 -4
- data/trestle.gemspec +5 -3
- data/vendor/assets/bower_components/trestle/select2/dist/js/select2.full.js +90 -69
- data/vendor/assets/javascripts/trestle/flatpickr.js.erb +2 -0
- data/vendor/assets/stylesheets/trestle/magnific-popup.scss +13 -1
- metadata +99 -22
- data/app/assets/javascripts/trestle/_confirmation.js +0 -23
- data/app/assets/javascripts/trestle/_datepicker.js +0 -22
- data/app/assets/javascripts/trestle/_form.js +0 -6
- data/app/assets/javascripts/trestle/_sidebar.js +0 -52
- data/app/assets/javascripts/trestle/_tabs.js +0 -13
- data/app/assets/javascripts/trestle/_tooltips.js +0 -3
- data/app/helpers/trestle/title_helper.rb +0 -26
- data/app/views/trestle/application/_flash.html.erb +0 -11
data/lib/trestle/table/column.rb
CHANGED
|
@@ -31,24 +31,47 @@ module Trestle
|
|
|
31
31
|
def header
|
|
32
32
|
if options[:header]
|
|
33
33
|
options[:header]
|
|
34
|
-
elsif
|
|
35
|
-
admin.human_attribute_name(field)
|
|
34
|
+
elsif table.admin
|
|
35
|
+
table.admin.t("table.headers.#{field}", default: table.admin.human_attribute_name(field))
|
|
36
36
|
else
|
|
37
|
-
field.to_s.humanize.titleize
|
|
37
|
+
I18n.t("admin.table.headers.#{field}", default: field.to_s.humanize.titleize)
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
class Renderer
|
|
42
|
-
delegate :options, to: :@column
|
|
42
|
+
delegate :options, :table, to: :@column
|
|
43
43
|
|
|
44
44
|
def initialize(column, template)
|
|
45
45
|
@column, @template = column, template
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
def render(instance)
|
|
49
|
+
@template.content_tag(:td, content(instance), class: classes, data: data)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def render?
|
|
53
|
+
if options.key?(:if)
|
|
54
|
+
if options[:if].respond_to?(:call)
|
|
55
|
+
@template.instance_exec(&options[:if])
|
|
56
|
+
else
|
|
57
|
+
options[:if]
|
|
58
|
+
end
|
|
59
|
+
elsif options.key?(:unless)
|
|
60
|
+
if options[:unless].respond_to?(:call)
|
|
61
|
+
!@template.instance_exec(&options[:unless])
|
|
62
|
+
else
|
|
63
|
+
!options[:unless]
|
|
64
|
+
end
|
|
65
|
+
else
|
|
66
|
+
true
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
48
70
|
def header
|
|
49
|
-
return if options.
|
|
71
|
+
return if options.key?(:header) && options[:header].in?([nil, false])
|
|
50
72
|
|
|
51
|
-
header =
|
|
73
|
+
header = @column.header
|
|
74
|
+
header = @template.instance_exec(&header) if header.respond_to?(:call)
|
|
52
75
|
header = @template.sort_link(header, @column.sort_field, @column.sort_options) if @column.sortable?
|
|
53
76
|
header
|
|
54
77
|
end
|
|
@@ -58,11 +81,12 @@ module Trestle
|
|
|
58
81
|
content = @template.format_value(value, options)
|
|
59
82
|
|
|
60
83
|
if value.respond_to?(:id) && options[:link] != false
|
|
84
|
+
# Column value was a model instance (e.g. from an association).
|
|
61
85
|
# Automatically link to instance's admin if available
|
|
62
86
|
content = @template.admin_link_to(content, value)
|
|
63
87
|
elsif options[:link]
|
|
64
88
|
# Explicitly link to the specified admin, or the table's admin
|
|
65
|
-
content = @template.admin_link_to(content, instance, admin: options[:admin] ||
|
|
89
|
+
content = @template.admin_link_to(content, instance, admin: options[:admin] || table.admin)
|
|
66
90
|
end
|
|
67
91
|
|
|
68
92
|
content
|
|
@@ -86,10 +110,17 @@ module Trestle
|
|
|
86
110
|
# evaluate the block using instance_exec, we need to set this up manually.
|
|
87
111
|
-> {
|
|
88
112
|
_hamlout = eval('_hamlout', @column.block.binding)
|
|
89
|
-
|
|
113
|
+
value = nil
|
|
114
|
+
buffer = @template.capture { value = @template.instance_exec(instance, &@column.block) }
|
|
115
|
+
value.is_a?(String) ? buffer : value
|
|
90
116
|
}.call
|
|
91
117
|
else
|
|
92
|
-
|
|
118
|
+
# Capture both the immediate value and captured output of the block.
|
|
119
|
+
# If the result of the block is a string, then use the contents of the buffer.
|
|
120
|
+
# Otherwise return the result of the block as a raw value (for auto-formatting).
|
|
121
|
+
value = nil
|
|
122
|
+
buffer = @template.capture { value = @template.instance_exec(instance, &@column.block) }
|
|
123
|
+
value.is_a?(String) ? buffer : value
|
|
93
124
|
end
|
|
94
125
|
else
|
|
95
126
|
instance.send(@column.field)
|
data/lib/trestle/table/row.rb
CHANGED
|
@@ -19,17 +19,33 @@ module Trestle
|
|
|
19
19
|
@row, @template = row, template
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
def columns
|
|
23
|
+
table.columns.map { |column| column.renderer(@template) }.select(&:render?)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def render(instance)
|
|
27
|
+
@template.content_tag(:tr, options(instance)) do
|
|
28
|
+
@template.safe_join(columns.map { |column| column.render(instance) }, "\n")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
22
32
|
def options(instance)
|
|
23
33
|
options = Trestle::Options.new
|
|
24
|
-
|
|
34
|
+
|
|
35
|
+
if table.admin && table.autolink? && table.admin.actions.include?(:show)
|
|
36
|
+
options.merge!(data: { url: admin_url_for(instance) })
|
|
37
|
+
options.merge!(data: { behavior: "dialog" }) if table.admin.form.dialog?
|
|
38
|
+
end
|
|
39
|
+
|
|
25
40
|
options.merge!(@row.options)
|
|
26
41
|
options.merge!(@template.instance_exec(instance, &@row.block)) if @row.block
|
|
42
|
+
|
|
27
43
|
options
|
|
28
44
|
end
|
|
29
45
|
|
|
30
46
|
protected
|
|
31
47
|
def admin_url_for(instance)
|
|
32
|
-
@template.admin_url_for(instance, admin: table.
|
|
48
|
+
@template.admin_url_for(instance, admin: table.admin)
|
|
33
49
|
end
|
|
34
50
|
end
|
|
35
51
|
end
|
data/lib/trestle/table.rb
CHANGED
|
@@ -17,10 +17,22 @@ module Trestle
|
|
|
17
17
|
@columns = []
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
def admin
|
|
21
|
+
Trestle.lookup(options[:admin]) if options.key?(:admin)
|
|
22
|
+
end
|
|
23
|
+
|
|
20
24
|
def sortable?
|
|
21
25
|
options[:sortable] == true
|
|
22
26
|
end
|
|
23
27
|
|
|
28
|
+
def autolink?
|
|
29
|
+
options[:autolink] != false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def header?
|
|
33
|
+
options[:header] != false
|
|
34
|
+
end
|
|
35
|
+
|
|
24
36
|
def renderer(template)
|
|
25
37
|
Renderer.new(self, template)
|
|
26
38
|
end
|
|
@@ -30,7 +42,7 @@ module Trestle
|
|
|
30
42
|
end
|
|
31
43
|
|
|
32
44
|
class Renderer
|
|
33
|
-
delegate :options, to: :@table
|
|
45
|
+
delegate :options, :header?, to: :@table
|
|
34
46
|
|
|
35
47
|
def initialize(table, template)
|
|
36
48
|
@table, @template = table, template
|
|
@@ -41,7 +53,11 @@ module Trestle
|
|
|
41
53
|
end
|
|
42
54
|
|
|
43
55
|
def columns
|
|
44
|
-
@columns ||=
|
|
56
|
+
@columns ||= row.columns
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def id
|
|
60
|
+
options[:id]
|
|
45
61
|
end
|
|
46
62
|
|
|
47
63
|
def classes
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Trestle
|
|
2
|
+
class Toolbar
|
|
3
|
+
class Builder
|
|
4
|
+
def initialize(template)
|
|
5
|
+
@template = template
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def button(content, options={})
|
|
9
|
+
options[:class] = button_classes_from_options(options)
|
|
10
|
+
|
|
11
|
+
button_tag(button_label(content, options), options)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def link(content, instance_or_url={}, options={})
|
|
15
|
+
options = instance_or_url if instance_or_url.is_a?(Hash)
|
|
16
|
+
options[:class] = button_classes_from_options(options)
|
|
17
|
+
|
|
18
|
+
admin_link_to(button_label(content, options), instance_or_url, options)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Only methods explicitly tagged as builder methods will be automatically
|
|
22
|
+
# appended to the toolbar when called by Toolbar::Context.
|
|
23
|
+
|
|
24
|
+
class_attribute :builder_methods
|
|
25
|
+
self.builder_methods = []
|
|
26
|
+
|
|
27
|
+
def self.builder_method(*methods)
|
|
28
|
+
self.builder_methods += methods
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
builder_method :button, :link
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
delegate :admin_link_to, :button_tag, :content_tag, :safe_join, :icon, to: :@template
|
|
35
|
+
|
|
36
|
+
def button_classes_from_options(options)
|
|
37
|
+
classes = (options[:class] || "").split("\s")
|
|
38
|
+
classes.unshift("btn-#{options.delete(:style) || "default"}")
|
|
39
|
+
classes.unshift("btn") unless classes.include?("btn")
|
|
40
|
+
classes.push("has-icon") if options[:icon]
|
|
41
|
+
classes
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def button_label(content, options)
|
|
45
|
+
icon = icon(options.delete(:icon)) if options[:icon]
|
|
46
|
+
label = content_tag(:span, content, class: "btn-label")
|
|
47
|
+
|
|
48
|
+
safe_join([icon, label].compact, " ")
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Trestle
|
|
2
|
+
class Toolbar
|
|
3
|
+
# The toolbar Context is the object that is yielded to a toolbar block and handles the delegation of builder methods.
|
|
4
|
+
class Context
|
|
5
|
+
attr_reader :builder
|
|
6
|
+
|
|
7
|
+
def initialize(builder, enumerator, *args)
|
|
8
|
+
@builder, @enumerator = builder, enumerator
|
|
9
|
+
@args = args
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def group
|
|
13
|
+
if @current_group
|
|
14
|
+
yield
|
|
15
|
+
else
|
|
16
|
+
@current_group = []
|
|
17
|
+
yield
|
|
18
|
+
@enumerator << @current_group
|
|
19
|
+
@current_group = nil
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
def respond_to_missing?(name, include_all=false)
|
|
25
|
+
builder.respond_to?(name) || super
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def method_missing(name, *args, &block)
|
|
29
|
+
result = builder.send(name, *args, &block)
|
|
30
|
+
|
|
31
|
+
if builder.builder_methods.include?(name)
|
|
32
|
+
group { @current_group << result }
|
|
33
|
+
else
|
|
34
|
+
result
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Trestle
|
|
2
|
+
class Toolbar
|
|
3
|
+
extend ActiveSupport::Autoload
|
|
4
|
+
|
|
5
|
+
autoload :Builder
|
|
6
|
+
autoload :Context
|
|
7
|
+
|
|
8
|
+
def initialize(builder=Builder)
|
|
9
|
+
@builder = builder
|
|
10
|
+
@blocks = []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def groups(template, *args)
|
|
14
|
+
Enumerator.new do |y|
|
|
15
|
+
@blocks.each do |block|
|
|
16
|
+
builder = @builder.new(template, *args)
|
|
17
|
+
block.evaluate(builder, template, y, *args)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def append(&block)
|
|
23
|
+
@blocks.push(Block.new(&block))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def prepend(&block)
|
|
27
|
+
@blocks.unshift(Block.new(&block))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Wraps a toolbar block to provide evaluation within the context of a template and enumerator
|
|
31
|
+
class Block
|
|
32
|
+
def initialize(&block)
|
|
33
|
+
@block = block
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def evaluate(builder, template, enumerator, *args)
|
|
37
|
+
context = Context.new(builder, enumerator, *args)
|
|
38
|
+
result = template.capture { template.instance_exec(context, *args, &@block) }
|
|
39
|
+
enumerator << [result] if result.present?
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/trestle/version.rb
CHANGED
data/lib/trestle.rb
CHANGED
|
@@ -18,6 +18,8 @@ module Trestle
|
|
|
18
18
|
autoload :Configuration
|
|
19
19
|
autoload :Display
|
|
20
20
|
autoload :Form
|
|
21
|
+
autoload :Hook
|
|
22
|
+
autoload :ModelName
|
|
21
23
|
autoload :Navigation
|
|
22
24
|
autoload :Options
|
|
23
25
|
autoload :Reloader
|
|
@@ -25,17 +27,20 @@ module Trestle
|
|
|
25
27
|
autoload :Scope
|
|
26
28
|
autoload :Tab
|
|
27
29
|
autoload :Table
|
|
30
|
+
autoload :Toolbar
|
|
28
31
|
|
|
29
32
|
mattr_accessor :admins
|
|
30
33
|
self.admins = {}
|
|
31
34
|
|
|
32
35
|
def self.admin(name, options={}, &block)
|
|
33
|
-
|
|
34
|
-
self.admins[admin.admin_name] = admin
|
|
36
|
+
register(Admin::Builder.create(name, options, &block))
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
def self.resource(name, options={}, &block)
|
|
38
|
-
|
|
40
|
+
register(Resource::Builder.create(name, options, &block))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.register(admin)
|
|
39
44
|
self.admins[admin.admin_name] = admin
|
|
40
45
|
end
|
|
41
46
|
|
|
@@ -53,7 +58,7 @@ module Trestle
|
|
|
53
58
|
end
|
|
54
59
|
|
|
55
60
|
def self.navigation
|
|
56
|
-
Navigation.
|
|
61
|
+
Navigation.build(config.menus + admins.values.map(&:menu).compact)
|
|
57
62
|
end
|
|
58
63
|
end
|
|
59
64
|
|
data/trestle.gemspec
CHANGED
|
@@ -34,14 +34,16 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
spec.required_ruby_version = ">= 2.2.2"
|
|
35
35
|
|
|
36
36
|
spec.add_dependency "railties", ">= 4.2.0"
|
|
37
|
-
spec.add_dependency "
|
|
38
|
-
spec.add_dependency "
|
|
39
|
-
spec.add_dependency "
|
|
37
|
+
spec.add_dependency "activemodel", ">= 4.2.0"
|
|
38
|
+
spec.add_dependency "sass-rails", ">= 5.0.6"
|
|
39
|
+
spec.add_dependency "autoprefixer-rails", ">= 7.1.2"
|
|
40
|
+
spec.add_dependency "kaminari", "~> 1.1.0"
|
|
40
41
|
|
|
41
42
|
spec.add_development_dependency "bundler", "~> 1.12"
|
|
42
43
|
spec.add_development_dependency "rake", "~> 10.0"
|
|
43
44
|
spec.add_development_dependency "rspec-rails", "~> 3.5"
|
|
44
45
|
spec.add_development_dependency "rspec-html-matchers", "~> 0.7.1"
|
|
46
|
+
spec.add_development_dependency "database_cleaner", "~> 1.6.2"
|
|
45
47
|
|
|
46
48
|
spec.add_development_dependency "sqlite3"
|
|
47
49
|
spec.add_development_dependency "turbolinks"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Select2 4.0.
|
|
2
|
+
* Select2 4.0.5
|
|
3
3
|
* https://select2.github.io
|
|
4
4
|
*
|
|
5
5
|
* Released under the MIT license
|
|
@@ -9,19 +9,33 @@
|
|
|
9
9
|
if (typeof define === 'function' && define.amd) {
|
|
10
10
|
// AMD. Register as an anonymous module.
|
|
11
11
|
define(['jquery'], factory);
|
|
12
|
-
} else if (typeof
|
|
12
|
+
} else if (typeof module === 'object' && module.exports) {
|
|
13
13
|
// Node/CommonJS
|
|
14
|
-
|
|
14
|
+
module.exports = function (root, jQuery) {
|
|
15
|
+
if (jQuery === undefined) {
|
|
16
|
+
// require('jQuery') returns a factory that requires window to
|
|
17
|
+
// build a jQuery instance, we normalize how we use modules
|
|
18
|
+
// that require this pattern but the window provided is a noop
|
|
19
|
+
// if it's defined (how jquery works)
|
|
20
|
+
if (typeof window !== 'undefined') {
|
|
21
|
+
jQuery = require('jquery');
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
jQuery = require('jquery')(root);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
factory(jQuery);
|
|
28
|
+
return jQuery;
|
|
29
|
+
};
|
|
15
30
|
} else {
|
|
16
31
|
// Browser globals
|
|
17
32
|
factory(jQuery);
|
|
18
33
|
}
|
|
19
|
-
}(function (jQuery) {
|
|
34
|
+
} (function (jQuery) {
|
|
20
35
|
// This is needed so we can catch the AMD loader configuration and use it
|
|
21
36
|
// The inner file should be wrapped (by `banner.start.js`) in a function that
|
|
22
37
|
// returns the AMD loader references.
|
|
23
|
-
var S2 =
|
|
24
|
-
(function () {
|
|
38
|
+
var S2 =(function () {
|
|
25
39
|
// Restore the Select2 AMD loader so it can be used
|
|
26
40
|
// Needed mostly in the language files, where the loader is not inserted
|
|
27
41
|
if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {
|
|
@@ -30,13 +44,11 @@
|
|
|
30
44
|
var S2;(function () { if (!S2 || !S2.requirejs) {
|
|
31
45
|
if (!S2) { S2 = {}; } else { require = S2; }
|
|
32
46
|
/**
|
|
33
|
-
* @license almond 0.3.
|
|
34
|
-
*
|
|
35
|
-
* see: http://github.com/jrburke/almond for details
|
|
47
|
+
* @license almond 0.3.3 Copyright jQuery Foundation and other contributors.
|
|
48
|
+
* Released under MIT license, http://github.com/requirejs/almond/LICENSE
|
|
36
49
|
*/
|
|
37
50
|
//Going sloppy to avoid 'use strict' string cost, but strict practices should
|
|
38
51
|
//be followed.
|
|
39
|
-
/*jslint sloppy: true */
|
|
40
52
|
/*global setTimeout: false */
|
|
41
53
|
|
|
42
54
|
var requirejs, require, define;
|
|
@@ -64,60 +76,58 @@ var requirejs, require, define;
|
|
|
64
76
|
*/
|
|
65
77
|
function normalize(name, baseName) {
|
|
66
78
|
var nameParts, nameSegment, mapValue, foundMap, lastIndex,
|
|
67
|
-
foundI, foundStarMap, starI, i, j, part,
|
|
79
|
+
foundI, foundStarMap, starI, i, j, part, normalizedBaseParts,
|
|
68
80
|
baseParts = baseName && baseName.split("/"),
|
|
69
81
|
map = config.map,
|
|
70
82
|
starMap = (map && map['*']) || {};
|
|
71
83
|
|
|
72
84
|
//Adjust any relative paths.
|
|
73
|
-
if (name
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
+
if (name) {
|
|
86
|
+
name = name.split('/');
|
|
87
|
+
lastIndex = name.length - 1;
|
|
88
|
+
|
|
89
|
+
// If wanting node ID compatibility, strip .js from end
|
|
90
|
+
// of IDs. Have to do this here, and not in nameToUrl
|
|
91
|
+
// because node allows either .js or non .js to map
|
|
92
|
+
// to same file.
|
|
93
|
+
if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
|
|
94
|
+
name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
|
|
95
|
+
}
|
|
85
96
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
//baseName
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
97
|
+
// Starts with a '.' so need the baseName
|
|
98
|
+
if (name[0].charAt(0) === '.' && baseParts) {
|
|
99
|
+
//Convert baseName to array, and lop off the last part,
|
|
100
|
+
//so that . matches that 'directory' and not name of the baseName's
|
|
101
|
+
//module. For instance, baseName of 'one/two/three', maps to
|
|
102
|
+
//'one/two/three.js', but we want the directory, 'one/two' for
|
|
103
|
+
//this normalization.
|
|
104
|
+
normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
|
|
105
|
+
name = normalizedBaseParts.concat(name);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
//start trimDots
|
|
109
|
+
for (i = 0; i < name.length; i++) {
|
|
110
|
+
part = name[i];
|
|
111
|
+
if (part === '.') {
|
|
112
|
+
name.splice(i, 1);
|
|
113
|
+
i -= 1;
|
|
114
|
+
} else if (part === '..') {
|
|
115
|
+
// If at the start, or previous value is still ..,
|
|
116
|
+
// keep them so that when converted to a path it may
|
|
117
|
+
// still work when converted to a path, even though
|
|
118
|
+
// as an ID it is less than ideal. In larger point
|
|
119
|
+
// releases, may be better to just kick out an error.
|
|
120
|
+
if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') {
|
|
121
|
+
continue;
|
|
122
|
+
} else if (i > 0) {
|
|
123
|
+
name.splice(i - 1, 2);
|
|
124
|
+
i -= 2;
|
|
111
125
|
}
|
|
112
126
|
}
|
|
113
|
-
//end trimDots
|
|
114
|
-
|
|
115
|
-
name = name.join("/");
|
|
116
|
-
} else if (name.indexOf('./') === 0) {
|
|
117
|
-
// No baseName, so this is ID is resolved relative
|
|
118
|
-
// to baseUrl, pull off the leading dot.
|
|
119
|
-
name = name.substring(2);
|
|
120
127
|
}
|
|
128
|
+
//end trimDots
|
|
129
|
+
|
|
130
|
+
name = name.join('/');
|
|
121
131
|
}
|
|
122
132
|
|
|
123
133
|
//Apply map config if available.
|
|
@@ -230,32 +240,39 @@ var requirejs, require, define;
|
|
|
230
240
|
return [prefix, name];
|
|
231
241
|
}
|
|
232
242
|
|
|
243
|
+
//Creates a parts array for a relName where first part is plugin ID,
|
|
244
|
+
//second part is resource ID. Assumes relName has already been normalized.
|
|
245
|
+
function makeRelParts(relName) {
|
|
246
|
+
return relName ? splitPrefix(relName) : [];
|
|
247
|
+
}
|
|
248
|
+
|
|
233
249
|
/**
|
|
234
250
|
* Makes a name map, normalizing the name, and using a plugin
|
|
235
251
|
* for normalization if necessary. Grabs a ref to plugin
|
|
236
252
|
* too, as an optimization.
|
|
237
253
|
*/
|
|
238
|
-
makeMap = function (name,
|
|
254
|
+
makeMap = function (name, relParts) {
|
|
239
255
|
var plugin,
|
|
240
256
|
parts = splitPrefix(name),
|
|
241
|
-
prefix = parts[0]
|
|
257
|
+
prefix = parts[0],
|
|
258
|
+
relResourceName = relParts[1];
|
|
242
259
|
|
|
243
260
|
name = parts[1];
|
|
244
261
|
|
|
245
262
|
if (prefix) {
|
|
246
|
-
prefix = normalize(prefix,
|
|
263
|
+
prefix = normalize(prefix, relResourceName);
|
|
247
264
|
plugin = callDep(prefix);
|
|
248
265
|
}
|
|
249
266
|
|
|
250
267
|
//Normalize according
|
|
251
268
|
if (prefix) {
|
|
252
269
|
if (plugin && plugin.normalize) {
|
|
253
|
-
name = plugin.normalize(name, makeNormalize(
|
|
270
|
+
name = plugin.normalize(name, makeNormalize(relResourceName));
|
|
254
271
|
} else {
|
|
255
|
-
name = normalize(name,
|
|
272
|
+
name = normalize(name, relResourceName);
|
|
256
273
|
}
|
|
257
274
|
} else {
|
|
258
|
-
name = normalize(name,
|
|
275
|
+
name = normalize(name, relResourceName);
|
|
259
276
|
parts = splitPrefix(name);
|
|
260
277
|
prefix = parts[0];
|
|
261
278
|
name = parts[1];
|
|
@@ -302,13 +319,14 @@ var requirejs, require, define;
|
|
|
302
319
|
};
|
|
303
320
|
|
|
304
321
|
main = function (name, deps, callback, relName) {
|
|
305
|
-
var cjsModule, depName, ret, map, i,
|
|
322
|
+
var cjsModule, depName, ret, map, i, relParts,
|
|
306
323
|
args = [],
|
|
307
324
|
callbackType = typeof callback,
|
|
308
325
|
usingExports;
|
|
309
326
|
|
|
310
327
|
//Use name if no relName
|
|
311
328
|
relName = relName || name;
|
|
329
|
+
relParts = makeRelParts(relName);
|
|
312
330
|
|
|
313
331
|
//Call the callback to define the module, if necessary.
|
|
314
332
|
if (callbackType === 'undefined' || callbackType === 'function') {
|
|
@@ -317,7 +335,7 @@ var requirejs, require, define;
|
|
|
317
335
|
//Default to [require, exports, module] if no deps
|
|
318
336
|
deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
|
|
319
337
|
for (i = 0; i < deps.length; i += 1) {
|
|
320
|
-
map = makeMap(deps[i],
|
|
338
|
+
map = makeMap(deps[i], relParts);
|
|
321
339
|
depName = map.f;
|
|
322
340
|
|
|
323
341
|
//Fast path CommonJS standard dependencies.
|
|
@@ -373,7 +391,7 @@ var requirejs, require, define;
|
|
|
373
391
|
//deps arg is the module name, and second arg (if passed)
|
|
374
392
|
//is just the relName.
|
|
375
393
|
//Normalize module name, if it contains . or ..
|
|
376
|
-
return callDep(makeMap(deps, callback).f);
|
|
394
|
+
return callDep(makeMap(deps, makeRelParts(callback)).f);
|
|
377
395
|
} else if (!deps.splice) {
|
|
378
396
|
//deps is a config object, not an array.
|
|
379
397
|
config = deps;
|
|
@@ -1837,7 +1855,7 @@ S2.define('select2/selection/search',[
|
|
|
1837
1855
|
var $search = $(
|
|
1838
1856
|
'<li class="select2-search select2-search--inline">' +
|
|
1839
1857
|
'<input class="select2-search__field" type="search" tabindex="-1"' +
|
|
1840
|
-
' autocomplete="off" autocorrect="off" autocapitalize="
|
|
1858
|
+
' autocomplete="off" autocorrect="off" autocapitalize="none"' +
|
|
1841
1859
|
' spellcheck="false" role="textbox" aria-autocomplete="list" />' +
|
|
1842
1860
|
'</li>'
|
|
1843
1861
|
);
|
|
@@ -3191,7 +3209,7 @@ S2.define('select2/data/select',[
|
|
|
3191
3209
|
}
|
|
3192
3210
|
}
|
|
3193
3211
|
|
|
3194
|
-
if (data.id) {
|
|
3212
|
+
if (data.id !== undefined) {
|
|
3195
3213
|
option.value = data.id;
|
|
3196
3214
|
}
|
|
3197
3215
|
|
|
@@ -3550,7 +3568,10 @@ S2.define('select2/data/tags',[
|
|
|
3550
3568
|
}, true)
|
|
3551
3569
|
);
|
|
3552
3570
|
|
|
3553
|
-
var
|
|
3571
|
+
var optionText = (option.text || '').toUpperCase();
|
|
3572
|
+
var paramsTerm = (params.term || '').toUpperCase();
|
|
3573
|
+
|
|
3574
|
+
var checkText = optionText === paramsTerm;
|
|
3554
3575
|
|
|
3555
3576
|
if (checkText || checkChildren) {
|
|
3556
3577
|
if (child) {
|
|
@@ -3888,7 +3909,7 @@ S2.define('select2/dropdown/search',[
|
|
|
3888
3909
|
var $search = $(
|
|
3889
3910
|
'<span class="select2-search select2-search--dropdown">' +
|
|
3890
3911
|
'<input class="select2-search__field" type="search" tabindex="-1"' +
|
|
3891
|
-
' autocomplete="off" autocorrect="off" autocapitalize="
|
|
3912
|
+
' autocomplete="off" autocorrect="off" autocapitalize="none"' +
|
|
3892
3913
|
' spellcheck="false" role="textbox" />' +
|
|
3893
3914
|
'</span>'
|
|
3894
3915
|
);
|
|
@@ -3941,7 +3962,7 @@ S2.define('select2/dropdown/search',[
|
|
|
3941
3962
|
});
|
|
3942
3963
|
|
|
3943
3964
|
container.on('focus', function () {
|
|
3944
|
-
if (container.isOpen()) {
|
|
3965
|
+
if (!container.isOpen()) {
|
|
3945
3966
|
self.$search.focus();
|
|
3946
3967
|
}
|
|
3947
3968
|
});
|