express_admin 1.6.4 → 1.6.7
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/app/assets/javascripts/ace/mode-html.js +2437 -0
- data/app/assets/javascripts/express_admin.js +2 -0
- data/app/assets/javascripts/express_admin/admin.js.coffee +8 -2
- data/app/assets/javascripts/express_admin/form_validation.js.coffee +24 -0
- data/app/assets/stylesheets/express_admin/shared/_forms.sass +12 -3
- data/app/assets/stylesheets/express_admin/shared/_tables.sass +41 -0
- data/app/components/express_admin/code_editor.rb +44 -0
- data/{vendor/gems/express_templates/lib/express_templates/components/forms → app/components/express_admin}/country_select.rb +1 -1
- data/app/components/express_admin/smart_form.rb +5 -14
- data/app/components/express_admin/smart_table.rb +65 -26
- data/lib/express_admin/engine.rb +1 -0
- data/lib/express_admin/version.rb +1 -1
- data/test/dummy/test/components/code_editor_test.rb +53 -0
- data/test/dummy/test/components/country_select_test.rb +36 -0
- data/test/test_helper.rb +8 -0
- data/vendor/gems/express_templates/express_templates.gemspec +0 -1
- data/vendor/gems/express_templates/lib/express_templates/components/base.rb +29 -0
- data/vendor/gems/express_templates/lib/express_templates/components/configurable.rb +3 -1
- data/vendor/gems/express_templates/lib/express_templates/components/container.rb +3 -1
- data/vendor/gems/express_templates/lib/express_templates/components/forms.rb +0 -1
- data/vendor/gems/express_templates/lib/express_templates/version.rb +1 -1
- metadata +40 -6
- data/vendor/gems/express_templates/test/components/forms/country_select_test.rb +0 -34
@@ -5,6 +5,9 @@ class AceInput
|
|
5
5
|
@session = @editor.getSession()
|
6
6
|
@renderer = @editor.renderer
|
7
7
|
@textarea = $("##{$(editor).data('target')}")
|
8
|
+
@selectedMode = $(editor).data('mode')
|
9
|
+
if @selectedMode == "et"
|
10
|
+
@selectedMode = "ruby"
|
8
11
|
@setOptions()
|
9
12
|
@updateMode()
|
10
13
|
@updateTheme()
|
@@ -20,7 +23,7 @@ class AceInput
|
|
20
23
|
@session.setFoldStyle "markbeginend"
|
21
24
|
|
22
25
|
updateMode: =>
|
23
|
-
mode = require("ace/mode
|
26
|
+
mode = require("ace/mode/#{@selectedMode}").Mode
|
24
27
|
@session.setMode new mode()
|
25
28
|
|
26
29
|
updateTheme: =>
|
@@ -53,8 +56,11 @@ $(document).ready ->
|
|
53
56
|
e.preventDefault()
|
54
57
|
$('a.close-reveal-modal').trigger 'click'
|
55
58
|
return
|
59
|
+
|
60
|
+
editor = []
|
56
61
|
$('.ace-input').each (index)->
|
57
|
-
editor
|
62
|
+
editor.push(new AceInput(this))
|
63
|
+
window.editor = editor
|
58
64
|
|
59
65
|
String::repeat = (num) ->
|
60
66
|
new Array(num + 1).join this
|
@@ -0,0 +1,24 @@
|
|
1
|
+
$ ->
|
2
|
+
$('form').validate
|
3
|
+
debug: true
|
4
|
+
errorElement: 'span'
|
5
|
+
|
6
|
+
email = $('[name$="[email]"]')
|
7
|
+
|
8
|
+
if email.size() > 0
|
9
|
+
email.rules 'add',
|
10
|
+
required: true
|
11
|
+
email: true
|
12
|
+
|
13
|
+
password = $('[name$="[password]"]')
|
14
|
+
|
15
|
+
if password.size() > 0
|
16
|
+
password.rules 'add',
|
17
|
+
required: true
|
18
|
+
minlength: 8
|
19
|
+
|
20
|
+
password_confirmation = $('[name$="[password_confirmation]"]')
|
21
|
+
|
22
|
+
if password_confirmation.size() > 0
|
23
|
+
password_confirmation.rules 'add',
|
24
|
+
equalTo: $('[name$="[password]"]')
|
@@ -9,9 +9,18 @@
|
|
9
9
|
height: 6rem
|
10
10
|
|
11
11
|
.error
|
12
|
-
border:
|
13
|
-
|
14
|
-
|
12
|
+
border: 1px solid $red
|
13
|
+
margin-bottom: 0
|
14
|
+
|
15
|
+
span.error
|
16
|
+
display: block
|
17
|
+
border: 0
|
18
|
+
background-color: #f04124
|
19
|
+
color: $light
|
20
|
+
padding: 0.33333rem 0.5rem 0.5rem
|
21
|
+
font:
|
22
|
+
size: 0.85rem
|
23
|
+
margin-bottom: 1rem
|
15
24
|
|
16
25
|
.help
|
17
26
|
font:
|
@@ -36,3 +36,44 @@
|
|
36
36
|
tbody
|
37
37
|
td
|
38
38
|
padding: 0.5rem
|
39
|
+
|
40
|
+
.smart-table
|
41
|
+
.ion-checkmark-round
|
42
|
+
color: #1fa67a
|
43
|
+
|
44
|
+
table + nav
|
45
|
+
margin-top: 50px
|
46
|
+
text-align: center
|
47
|
+
|
48
|
+
nav.pagination
|
49
|
+
span
|
50
|
+
transition: background-color 300ms ease-out
|
51
|
+
display: inline-block
|
52
|
+
height: 1.33333rem
|
53
|
+
margin-left: 0.27778rem
|
54
|
+
line-height: 20px
|
55
|
+
font:
|
56
|
+
weight: normal
|
57
|
+
size: 0.77778rem
|
58
|
+
|
59
|
+
&.gap:hover
|
60
|
+
background: inherit
|
61
|
+
border-radius: none
|
62
|
+
&:hover
|
63
|
+
background: #e6e6e6
|
64
|
+
border-radius: 3px
|
65
|
+
a
|
66
|
+
color: #999
|
67
|
+
display: block
|
68
|
+
padding: 0.05556rem 0.55556rem 0.05556rem
|
69
|
+
|
70
|
+
|
71
|
+
.current
|
72
|
+
font-weight: bold
|
73
|
+
background: #008cba
|
74
|
+
border-radius: 3px
|
75
|
+
color: #fff
|
76
|
+
padding: 0.05556rem 0.55556rem 0.05556rem
|
77
|
+
&:hover
|
78
|
+
background: #008cba
|
79
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ExpressAdmin
|
2
|
+
class CodeEditor < ExpressTemplates::Components::Forms::FormComponent
|
3
|
+
|
4
|
+
has_option :mode, "Language of the editor", type: :string
|
5
|
+
has_option :rows, "Define the number of rows", type: :int, default: 10
|
6
|
+
|
7
|
+
contains -> {
|
8
|
+
base_styles = "position: relative; height: 300px;"
|
9
|
+
text_area_tag object, object.send(field), field_helper_options.merge( id: field_id, name: field_name ) #field_name_attribute, field_helper_options
|
10
|
+
content_tag(:div, '', id: "ace_#{field_name}",
|
11
|
+
class: "ace-input", style: base_styles,
|
12
|
+
data: { target: field_id, mode: config[:mode] })
|
13
|
+
}
|
14
|
+
|
15
|
+
def field_helper_options
|
16
|
+
{rows: rows, class: "hide", hidden: true}.merge(super)
|
17
|
+
end
|
18
|
+
|
19
|
+
def object
|
20
|
+
self.send resource_name
|
21
|
+
end
|
22
|
+
|
23
|
+
def field
|
24
|
+
config[:id]
|
25
|
+
end
|
26
|
+
|
27
|
+
def rows
|
28
|
+
config[:rows]
|
29
|
+
end
|
30
|
+
|
31
|
+
def field_name
|
32
|
+
"#{object_type}[#{field}]"
|
33
|
+
end
|
34
|
+
|
35
|
+
def field_id
|
36
|
+
"#{object_type}_#{field}_#{object.id}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def object_type
|
40
|
+
object.class.to_s.demodulize.underscore
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -38,7 +38,6 @@ module ExpressAdmin
|
|
38
38
|
submit(class: 'button')
|
39
39
|
}
|
40
40
|
|
41
|
-
|
42
41
|
def form_field_for(attrib)
|
43
42
|
field_type_substitutions = {'text_area' => 'textarea',
|
44
43
|
'datetime_select' => 'datetime',
|
@@ -46,19 +45,11 @@ module ExpressAdmin
|
|
46
45
|
field_type = attrib.field_type.to_s.sub(/_field$/,'')
|
47
46
|
field_type = "password" if attrib.name.match(/password/)
|
48
47
|
if relation = attrib.name.match(/(\w+)_id$/).try(:[], 1)
|
49
|
-
|
50
|
-
|
48
|
+
# TODO: should allow select2 override
|
49
|
+
select(attrib.name.to_sym, options: config["#{relation}_collection".to_sym], select2: true)
|
51
50
|
else
|
52
51
|
if field_type == 'text_area'
|
53
|
-
|
54
|
-
# TODO allow other fields aside from layout.definition
|
55
|
-
base_styles = "position: relative; height: 300px;"
|
56
|
-
target = [attributes[:class].to_a.last, attrib.name].join("_")
|
57
|
-
textarea attrib.name.to_sym, rows: 10, class: "hide", hidden: true
|
58
|
-
content_tag(:div, '', id: "ace_#{attrib.name}", class: "ace-input", style: base_styles, data: { target: target })
|
59
|
-
else
|
60
|
-
textarea attrib.name.to_sym, rows: 10
|
61
|
-
end
|
52
|
+
textarea attrib.name.to_sym, rows: 10
|
62
53
|
else
|
63
54
|
self.send((field_type_substitutions[field_type] || field_type), attrib.name.to_sym)
|
64
55
|
end
|
@@ -118,8 +109,8 @@ module ExpressAdmin
|
|
118
109
|
attribs
|
119
110
|
end.reject {|attrib| (excluded_attributes).map(&:to_s).include? attrib.name }
|
120
111
|
end
|
121
|
-
|
122
112
|
end
|
123
113
|
end
|
124
114
|
end
|
125
|
-
end
|
115
|
+
end
|
116
|
+
|
@@ -4,9 +4,10 @@ module ExpressAdmin
|
|
4
4
|
class SmartTable < ExpressTemplates::Components::Configurable
|
5
5
|
include ExpressTemplates::Components::Capabilities::Resourceful
|
6
6
|
|
7
|
-
tag :
|
7
|
+
tag :div
|
8
8
|
|
9
9
|
MAX_COLS_TO_SHOW_IDX = 5
|
10
|
+
MAX_ROWS_TO_SHOW_IDX = 10
|
10
11
|
|
11
12
|
attr :columns
|
12
13
|
|
@@ -32,44 +33,70 @@ module ExpressAdmin
|
|
32
33
|
end
|
33
34
|
options = options + resource_class.instance_methods.grep(/_count$/).map(&:to_s)
|
34
35
|
}
|
36
|
+
has_option :rows, 'Specify the number of rows to show', type: :integer
|
37
|
+
|
38
|
+
has_option :pagination, 'Add pagination to the bottom of the table', type: :string, default: 'bottom'
|
35
39
|
|
36
40
|
contains -> {
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
column.title
|
42
|
-
}
|
43
|
-
end
|
44
|
-
actions_header if should_show_actions?
|
45
|
-
hidden_columns_header_indicator if columns_hidden?
|
46
|
-
}
|
47
|
-
}
|
48
|
-
tbody {
|
49
|
-
stored_member_assigns = assigns[collection_member_name.to_sym]
|
50
|
-
collection.each do |item|
|
51
|
-
assigns[collection_member_name.to_sym] = item
|
52
|
-
tr(id: row_id(item), class: row_class(item)) {
|
41
|
+
pagination if config[:pagination] == 'top'
|
42
|
+
table(class: table_classes) {
|
43
|
+
thead {
|
44
|
+
tr {
|
53
45
|
display_columns.each do |column|
|
54
|
-
|
55
|
-
|
46
|
+
th(class: column.name) {
|
47
|
+
column.title
|
56
48
|
}
|
57
49
|
end
|
58
|
-
|
59
|
-
|
50
|
+
actions_header if should_show_actions?
|
51
|
+
hidden_columns_header_indicator if columns_hidden?
|
60
52
|
}
|
61
|
-
|
62
|
-
|
53
|
+
}
|
54
|
+
tbody {
|
55
|
+
stored_member_assigns = assigns[collection_member_name.to_sym]
|
56
|
+
collection.each do |item|
|
57
|
+
assigns[collection_member_name.to_sym] = item
|
58
|
+
tr(id: row_id(item), class: row_class(item)) {
|
59
|
+
display_columns.each do |column|
|
60
|
+
td(class: column.name) {
|
61
|
+
cell_value(item, column.accessor)
|
62
|
+
}
|
63
|
+
end
|
64
|
+
actions_column(item) if should_show_actions?
|
65
|
+
hidden_column_cell if columns_hidden?
|
66
|
+
}
|
67
|
+
assigns[collection_member_name.to_sym] = stored_member_assigns
|
68
|
+
end; nil
|
69
|
+
}
|
63
70
|
}
|
64
|
-
|
65
71
|
scroll_table if !!config[:scrollable]
|
72
|
+
pagination if config[:pagination] == 'bottom'
|
66
73
|
}
|
67
74
|
|
68
75
|
before_build -> {
|
69
76
|
_initialize_columns
|
70
|
-
add_class 'table striped'
|
71
77
|
}
|
72
78
|
|
79
|
+
def pagination
|
80
|
+
paginate collection, :route_set => route_set
|
81
|
+
end
|
82
|
+
|
83
|
+
def table_classes
|
84
|
+
'table striped'
|
85
|
+
end
|
86
|
+
|
87
|
+
def route_set
|
88
|
+
namespace.nil? ? namespace : eval(namespace)
|
89
|
+
end
|
90
|
+
|
91
|
+
def collection
|
92
|
+
collections = super.kind_of?(Array) ? Kaminari.paginate_array(super) : super
|
93
|
+
collections.page(index_page).per(specified_rows)
|
94
|
+
end
|
95
|
+
|
96
|
+
def index_page
|
97
|
+
helpers.params[:page] || 1 # Default page is 1
|
98
|
+
end
|
99
|
+
|
73
100
|
def scroll_table
|
74
101
|
script {
|
75
102
|
%Q($('\##{config[:id]}').scrollTableBody())
|
@@ -124,12 +151,14 @@ module ExpressAdmin
|
|
124
151
|
elsif attrib = accessor.to_s.match(/(\w+)_link$/).try(:[], 1)
|
125
152
|
# TODO: only works with non-namespaced routes
|
126
153
|
helpers.link_to item.send(attrib), resource_path(item)
|
154
|
+
elsif attrib = accessor.to_s.match(/(\w+)_checkmark/).try(:[], 1)
|
155
|
+
"<i class='ion-checkmark-round'></i>".html_safe if item.send(attrib)
|
127
156
|
elsif attrib = accessor.to_s.match(/(\w+)_in_words/).try(:[], 1)
|
128
157
|
if item.send(attrib)
|
129
158
|
if item.send(attrib) < DateTime.now
|
130
159
|
"#{helpers.time_ago_in_words(item.send(attrib))} ago"
|
131
160
|
else
|
132
|
-
helpers.time_ago_in_words(item.send(attrib))
|
161
|
+
"in #{helpers.time_ago_in_words(item.send(attrib))}"
|
133
162
|
end
|
134
163
|
else
|
135
164
|
'never'
|
@@ -184,6 +213,16 @@ module ExpressAdmin
|
|
184
213
|
td(class: 'more-columns-indicator')
|
185
214
|
end
|
186
215
|
|
216
|
+
def specified_rows
|
217
|
+
config[:rows] || MAX_ROWS_TO_SHOW_IDX
|
218
|
+
end
|
219
|
+
|
220
|
+
def hidden_columns_header_indicator
|
221
|
+
th(class: 'more-columns-indicator') {
|
222
|
+
"..."
|
223
|
+
}
|
224
|
+
end
|
225
|
+
|
187
226
|
private
|
188
227
|
def _initialize_columns
|
189
228
|
@columns =
|
data/lib/express_admin/engine.rb
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Foo
|
4
|
+
def self.columns; [] ; end
|
5
|
+
end
|
6
|
+
|
7
|
+
module Components
|
8
|
+
|
9
|
+
class CodeEditorTest < ActiveSupport::TestCase
|
10
|
+
|
11
|
+
def compiled_code_editor(*args)
|
12
|
+
arbre {
|
13
|
+
express_form(:foo){
|
14
|
+
code_editor :name, *args
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def assigns
|
20
|
+
{ foo: resource }
|
21
|
+
end
|
22
|
+
|
23
|
+
def helpers
|
24
|
+
mock_action_view do
|
25
|
+
def foos_path
|
26
|
+
'/foos'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
test "renders the code editor" do
|
32
|
+
assert compiled_code_editor
|
33
|
+
end
|
34
|
+
|
35
|
+
test "div displays the ace editor" do
|
36
|
+
assert_match 'class="ace-input"', compiled_code_editor
|
37
|
+
end
|
38
|
+
|
39
|
+
test "text area is hidden" do
|
40
|
+
assert_match /textarea(.*?)class="hide" hidden="hidden"/, compiled_code_editor
|
41
|
+
end
|
42
|
+
|
43
|
+
test "rows can be changed" do
|
44
|
+
assert_match 'rows="15"', compiled_code_editor(rows: 15)
|
45
|
+
end
|
46
|
+
|
47
|
+
test "language mode can be changed" do
|
48
|
+
assert_match 'data-mode="html"', compiled_code_editor(mode: "html")
|
49
|
+
assert_match 'data-mode="et"', compiled_code_editor(mode: "et")
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
class CountrySelectTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
def resource_assigns
|
6
|
+
{example_engine: ExampleEngine::MockRouteProxy.new}
|
7
|
+
end
|
8
|
+
|
9
|
+
def helpers
|
10
|
+
view = mock_action_view
|
11
|
+
class << view
|
12
|
+
def widgets_path
|
13
|
+
"/widgets"
|
14
|
+
end
|
15
|
+
alias collection_path widgets_path
|
16
|
+
end
|
17
|
+
view
|
18
|
+
end
|
19
|
+
|
20
|
+
test "country_select renders without an error" do
|
21
|
+
assert arbre(widget: Widget.new) {
|
22
|
+
express_form(:widget) {
|
23
|
+
country_select :column6
|
24
|
+
}
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
test "can change label for country_select" do
|
29
|
+
html = arbre(widget: Widget.new) {
|
30
|
+
express_form(:widget) {
|
31
|
+
country_select :column6, label: "Country"
|
32
|
+
}
|
33
|
+
}
|
34
|
+
assert_match(/<label.*Country<\/label>/, html)
|
35
|
+
end
|
36
|
+
end
|