para 0.7.1 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/para/admin/tabs.coffee +20 -1
- data/app/assets/javascripts/para/admin.coffee +1 -0
- data/app/assets/javascripts/para/inputs/multi-select-input.coffee +5 -3
- data/app/assets/javascripts/para/inputs/nested_many.coffee +35 -1
- data/app/assets/javascripts/para/lib/remote-file-forms.coffee +6 -7
- data/app/assets/javascripts/para/lib/turbolinks-loading.coffee +1 -1
- data/app/assets/stylesheets/para/admin/main.sass +1 -0
- data/app/assets/stylesheets/para/admin/src/_affix.sass +4 -0
- data/app/assets/stylesheets/para/admin/src/_base.sass +4 -1
- data/app/assets/stylesheets/para/admin/src/_breadcrumb.sass +12 -2
- data/app/assets/stylesheets/para/admin/src/_form.sass +22 -3
- data/app/assets/stylesheets/para/admin/src/_navtabs.sass +23 -6
- data/app/assets/stylesheets/para/admin/src/_nested-many.sass +5 -0
- data/app/assets/stylesheets/para/admin/src/_nested_one.sass +6 -5
- data/app/controllers/para/admin/base_controller.rb +5 -0
- data/app/controllers/para/admin/crud_resources_controller.rb +1 -1
- data/app/controllers/para/admin/exports_controller.rb +2 -1
- data/app/controllers/para/admin/nested_forms_controller.rb +13 -0
- data/app/controllers/para/admin/resources_controller.rb +14 -3
- data/app/controllers/para/admin/search_controller.rb +7 -5
- data/app/decorators/para/component/base_decorator.rb +7 -2
- data/app/decorators/para/component/crud_decorator.rb +4 -0
- data/app/decorators/para/component/form_decorator.rb +6 -0
- data/app/exporters/call_for_projects_votes_exporter.rb +79 -0
- data/app/helpers/para/admin/base_helper.rb +2 -3
- data/app/helpers/para/admin/history_helper.rb +16 -0
- data/app/helpers/para/form_helper.rb +9 -1
- data/app/helpers/para/model_helper.rb +0 -2
- data/app/models/para/cache/item.rb +4 -0
- data/app/models/para/component/base.rb +4 -0
- data/app/models/para/component/crud.rb +1 -0
- data/app/models/para/component/form.rb +2 -0
- data/app/models/para/library/file.rb +40 -12
- data/app/models/para/page/section.rb +13 -1
- data/app/views/admin/para/exporter/bases/_completed.html.haml +1 -1
- data/app/views/layouts/para/admin.html.haml +5 -5
- data/app/views/para/admin/form_resources/show.html.haml +6 -2
- data/app/views/para/admin/nested_forms/show.html.haml +9 -0
- data/app/views/para/admin/resources/_exports_menu.html.haml +2 -2
- data/app/views/para/admin/resources/_list.html.haml +26 -21
- data/app/views/para/admin/resources/_remote_nested_form.html.haml +1 -0
- data/app/views/para/admin/resources/edit.html.haml +7 -2
- data/app/views/para/admin/resources/history/_index.html.haml +3 -0
- data/app/views/para/admin/shared/_header.html.haml +3 -3
- data/app/views/para/admin/shared/_navigation.html.haml +1 -1
- data/app/views/para/form/_tabs.html.haml +12 -9
- data/app/views/para/inputs/_multi_select.html.haml +6 -2
- data/app/views/para/inputs/_nested_many.html.haml +4 -4
- data/app/views/para/inputs/_nested_one.html.haml +12 -1
- data/app/views/para/inputs/multi_select/_no_items.html.haml +8 -4
- data/app/views/para/inputs/nested_many/_add.html.haml +2 -2
- data/app/views/para/inputs/nested_many/_add_with_subclasses.html.haml +3 -3
- data/app/views/para/inputs/nested_many/_container.html.haml +10 -7
- data/lib/generators/para/exporter/templates/csv_exporter.rb +24 -0
- data/lib/generators/para/exporter/templates/xls_exporter.rb +24 -0
- data/lib/para/attribute_field/belongs_to.rb +4 -1
- data/lib/para/attribute_field/nested_field.rb +4 -2
- data/lib/para/attribute_field/nested_many.rb +1 -1
- data/lib/para/attribute_field/nested_one.rb +1 -1
- data/lib/para/cache/database_store.rb +14 -1
- data/lib/para/cloneable.rb +44 -2
- data/lib/para/component/history.rb +15 -0
- data/lib/para/component.rb +1 -0
- data/lib/para/components_configuration.rb +8 -3
- data/lib/para/engine.rb +8 -0
- data/lib/para/exporter/base.rb +49 -1
- data/lib/para/ext/request_iframe_xhr.rb +17 -0
- data/lib/para/ext.rb +1 -0
- data/lib/para/form_builder/attributes_mappings_tracker.rb +15 -3
- data/lib/para/form_builder/containers.rb +6 -1
- data/lib/para/form_builder/nested_form.rb +7 -4
- data/lib/para/form_builder/tabs.rb +49 -8
- data/lib/para/iframe_transport/middleware.rb +58 -0
- data/lib/para/iframe_transport.rb +7 -0
- data/lib/para/importer/base.rb +1 -0
- data/lib/para/inputs/multi_select_input.rb +27 -8
- data/lib/para/inputs/nested_base_input.rb +26 -0
- data/lib/para/inputs/nested_many_input.rb +43 -18
- data/lib/para/inputs/nested_one_input.rb +18 -4
- data/lib/para/inputs.rb +1 -0
- data/lib/para/log_config.rb +14 -0
- data/lib/para/markup/resources_table.rb +2 -2
- data/lib/para/model_field_parsers/relations.rb +12 -1
- data/lib/para/page/model.rb +2 -1
- data/lib/para/postgres_extensions_checker.rb +15 -11
- data/lib/para/routes.rb +3 -3
- data/lib/para/search/distinct.rb +1 -1
- data/lib/para/version.rb +1 -1
- data/lib/para.rb +2 -0
- data/lib/rails/routing_mapper.rb +19 -27
- data/vendor/assets/javascripts/jquery.iframe-transport.js +260 -0
- data/vendor/assets/javascripts/jquery.remote-modal-form.coffee +80 -2
- metadata +23 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f2e4cc7267a3d024fb9690cf426b0064bdb5da8
|
4
|
+
data.tar.gz: eea345a2e6a7b354420b6fb27d8bcef5bda8d5b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75f8375384ace99363c1d518f82df23c7261cc96d86b925d743dcf6052b8d9d79a767eb2c2d21ebbe549798cf22caa429ca7cd88d1bb32acd96f497bf9afc9b0
|
7
|
+
data.tar.gz: ea104d47ae45e079a54d0af2c2af8212dc2d5148722ee432f54764594d09cfff86988ec4ff2b4bdb15f96938c668fbb817e6c19f6774519c3ddcf5f99c96f0a5
|
@@ -10,13 +10,17 @@ class Para.Tabs extends Vertebra.View
|
|
10
10
|
@$anchorInput = options.$anchorInput
|
11
11
|
@showActiveTab()
|
12
12
|
@refreshTabsErrors()
|
13
|
+
@initializeAffix()
|
13
14
|
|
14
15
|
showActiveTab: ->
|
15
16
|
if (hash = (location.hash or @$anchorInput?.val()))
|
16
17
|
@findTab(hash).tab('show')
|
17
18
|
|
18
19
|
onTabShown: (e) =>
|
19
|
-
|
20
|
+
$tab = $(e.target)
|
21
|
+
return unless $tab.closest('[data-form-tabs]').is('[data-top-level-tabs]')
|
22
|
+
|
23
|
+
tabHash = $tab.attr('href')
|
20
24
|
history.pushState(null, null, tabHash)
|
21
25
|
@updateAnchorInput()
|
22
26
|
|
@@ -31,6 +35,21 @@ class Para.Tabs extends Vertebra.View
|
|
31
35
|
$panel = @$($tab.attr('href'))
|
32
36
|
$tab.addClass('has-error') if $panel.find('.has-error').length
|
33
37
|
|
38
|
+
#
|
39
|
+
initializeAffix: ->
|
40
|
+
return unless (@$nav = @$('[data-tabs-nav-affix]')).length
|
41
|
+
|
42
|
+
headerHeight = $('[data-header]').outerHeight()
|
43
|
+
offsetTop = @$nav.offset().top - headerHeight
|
44
|
+
sidebarWidth = $('[data-admin-left-sidebar]').outerWidth()
|
45
|
+
|
46
|
+
@$nav.affix(offset: { top: offsetTop })
|
47
|
+
.css(top: headerHeight, left: sidebarWidth)
|
48
|
+
|
49
|
+
# Fix parent wrapper height to maintain the same scroll position when the
|
50
|
+
# nav tabs are fixed to top
|
51
|
+
@$nav.closest('[data-nav-tabs-wrapper]').height(@$nav.outerHeight())
|
52
|
+
|
34
53
|
onFormInputUpdate: (e) ->
|
35
54
|
$tab = @findTab($(e.currentTarget).attr('id'))
|
36
55
|
@refreshTabErrors($tab)
|
@@ -12,6 +12,7 @@ class Para.MultiSelectInput extends Vertebra.View
|
|
12
12
|
|
13
13
|
@searchURL = @$el.data('search-url')
|
14
14
|
@orderable = @$el.is('[data-orderable]')
|
15
|
+
@searchParam = @$searchField.attr('name')
|
15
16
|
|
16
17
|
@noSelectedItemsTemplate = @$('[data-no-selected-items]').data('no-selected-items')
|
17
18
|
@noAvailableItemsTemplate = @$('[data-no-available-items]').data('no-available-items')
|
@@ -31,13 +32,14 @@ class Para.MultiSelectInput extends Vertebra.View
|
|
31
32
|
|
32
33
|
searchFor: (terms) ->
|
33
34
|
terms = trim(terms)
|
34
|
-
return if terms is @terms
|
35
|
+
return if terms is @terms or (!terms and !@terms)
|
35
36
|
@terms = terms
|
36
37
|
@setLoading(true)
|
37
38
|
@_currentSearchXHR?.abort()
|
38
|
-
|
39
|
+
data = @$('[data-search-field-input]').serialize()
|
40
|
+
@_currentSearchXHR = $.get(@searchURL, data).done(@onSearchReturn)
|
39
41
|
|
40
|
-
onSearchReturn: (results
|
42
|
+
onSearchReturn: (results) =>
|
41
43
|
@_currentSearchXHR = null
|
42
44
|
@setLoading(false)
|
43
45
|
@$('[data-available-items] tbody').html(results)
|
@@ -48,11 +48,45 @@ class Para.NestedManyField
|
|
48
48
|
|
49
49
|
collapseShown: (e) ->
|
50
50
|
$target = $(e.target)
|
51
|
+
|
52
|
+
if $target.is("[data-rendered]") or $target.data("rendered")
|
53
|
+
@initializeCollapseContent($target)
|
54
|
+
else
|
55
|
+
@loadCollapseContent($target)
|
56
|
+
@scrollToTarget($target)
|
57
|
+
|
58
|
+
initializeCollapseContent: ($target) ->
|
59
|
+
@scrollToTarget($target)
|
60
|
+
@focusFirstField($target)
|
61
|
+
|
62
|
+
scrollToTarget: ($target) ->
|
51
63
|
$field = @$field.find("[data-toggle='collapse'][href='##{ $target.attr('id') }']")
|
52
|
-
scrollOffset = -($('[data-header]').outerHeight() +
|
64
|
+
scrollOffset = -($('[data-header]').outerHeight() + 30)
|
65
|
+
|
66
|
+
if ($affixNavTabs = $("[data-tabs-nav-affix]:eq(0)")).length
|
67
|
+
scrollOffset -= $affixNavTabs.outerHeight()
|
68
|
+
|
53
69
|
$.scrollTo($field, 200, offset: scrollOffset)
|
70
|
+
|
71
|
+
focusFirstField: ($target) ->
|
54
72
|
$target.find('input, textarea, select').eq('0').focus()
|
55
73
|
|
74
|
+
loadCollapseContent: ($target) ->
|
75
|
+
targetUrl = $target.data("render-path")
|
76
|
+
return unless targetUrl
|
77
|
+
|
78
|
+
data = {
|
79
|
+
"id": $target.data("id")
|
80
|
+
"object_name": $target.data("object-name")
|
81
|
+
"model_name": $target.data("model-name")
|
82
|
+
}
|
83
|
+
|
84
|
+
$.get(targetUrl, data).then (resp) =>
|
85
|
+
$content = $(resp)
|
86
|
+
$target.find("[data-nested-form-container]:eq(0)").html($content)
|
87
|
+
$content.simpleForm()
|
88
|
+
@focusFirstField($target)
|
89
|
+
$target.data("rendered", true)
|
56
90
|
|
57
91
|
$.simpleForm.onDomReady ($document) ->
|
58
92
|
$document.find('.nested-many-field').each (i, el) -> new Para.NestedManyField($(el))
|
@@ -6,9 +6,10 @@
|
|
6
6
|
# of original rails' remote form requests, to allow existing handling code
|
7
7
|
# to run without any modification.
|
8
8
|
#
|
9
|
-
class RemoteFileForm
|
10
|
-
|
11
|
-
|
9
|
+
class @RemoteFileForm extends Vertebra.View
|
10
|
+
@supported = FormData isnt undefined
|
11
|
+
|
12
|
+
initialize: (options = {}) ->
|
12
13
|
@submitForm() if $.rails.fire(@$el, 'ajax:before')
|
13
14
|
|
14
15
|
submitForm: ->
|
@@ -28,7 +29,7 @@ class RemoteFileForm
|
|
28
29
|
success: @success
|
29
30
|
complete: @complete
|
30
31
|
error: @error
|
31
|
-
crossDomain: $.rails.isCrossDomain(url)
|
32
|
+
crossDomain: $.rails.isCrossDomain?(url)
|
32
33
|
|
33
34
|
buildXHR: =>
|
34
35
|
xhr = $.ajaxSettings.xhr()
|
@@ -50,10 +51,8 @@ class RemoteFileForm
|
|
50
51
|
error: (xhr, status, error) =>
|
51
52
|
@$el.trigger('ajax:error', [xhr, status, error])
|
52
53
|
|
53
|
-
# TODO : Implement an upload progress bar for heavy files
|
54
|
-
#
|
55
54
|
progress: (e) =>
|
56
|
-
|
55
|
+
@trigger('progress', e)
|
57
56
|
|
58
57
|
$(document).on 'ajax:aborted:file', (e) ->
|
59
58
|
new RemoteFileForm(el: e.target)
|
@@ -22,4 +22,4 @@ $(document).on('page:fetch', Para.loadingManager.start)
|
|
22
22
|
|
23
23
|
$(document).on 'page:change turbolinks:load', ->
|
24
24
|
Para.loadingManager.stop()
|
25
|
-
$('body').on('submit', '[data-para-form]', Para.loadingManager.start)
|
25
|
+
$('body').on('submit', '[data-para-form]:not([data-remote])', Para.loadingManager.start)
|
@@ -40,9 +40,12 @@ body
|
|
40
40
|
float: left
|
41
41
|
line-height: 34px
|
42
42
|
|
43
|
+
.admin-main-page-content
|
44
|
+
position: relative
|
45
|
+
|
43
46
|
.page-content-wrap
|
44
|
-
background-color: #fff
|
45
47
|
margin: 25px 10px 25px 10px
|
48
|
+
background-color: #fff
|
46
49
|
+border-radius($border-radius-small)
|
47
50
|
+material-box-shadow-soft
|
48
51
|
padding: 25px
|
@@ -7,11 +7,21 @@
|
|
7
7
|
//## Just a override of bootstrap
|
8
8
|
|
9
9
|
.breadcrumb
|
10
|
+
float: left
|
11
|
+
width: calc(100% - 90px)
|
12
|
+
max-height: 60px
|
13
|
+
margin: 0
|
14
|
+
|
10
15
|
border: none
|
11
16
|
+border-radius(0)
|
12
|
-
|
13
|
-
float: left
|
17
|
+
|
14
18
|
li
|
19
|
+
max-width: 30%
|
20
|
+
height: 60px
|
21
|
+
overflow: hidden
|
22
|
+
text-overflow: ellipsis
|
23
|
+
white-space: nowrap
|
24
|
+
|
15
25
|
a
|
16
26
|
color: $breadcrumb-color
|
17
27
|
font-size: 1em
|
@@ -57,20 +57,24 @@ legend
|
|
57
57
|
//
|
58
58
|
//##
|
59
59
|
|
60
|
+
.form-control
|
61
|
+
font-size: 14px
|
62
|
+
|
60
63
|
.form-inputs,
|
61
64
|
.nested-one-field,
|
62
65
|
.tab-pane
|
63
66
|
+clearfix
|
64
67
|
.form-group:last-of-type,
|
65
68
|
.form-group:only-child,
|
66
|
-
.nested-one-field:last-of-type
|
69
|
+
.nested-one-field:last-of-type
|
67
70
|
margin-bottom: 0
|
68
71
|
|
69
72
|
.nested-one-field
|
70
73
|
margin-bottom: $form-group-margin-bottom
|
71
74
|
|
72
|
-
.
|
73
|
-
|
75
|
+
.nested-input-title
|
76
|
+
&.has-error
|
77
|
+
color: $brand-danger
|
74
78
|
|
75
79
|
|
76
80
|
//== Inputs outline
|
@@ -165,6 +169,21 @@ legend
|
|
165
169
|
&:active:focus
|
166
170
|
+box-shadow(none)
|
167
171
|
|
172
|
+
//== Color picker
|
173
|
+
//
|
174
|
+
//##
|
175
|
+
|
176
|
+
.input-group
|
177
|
+
&.color
|
178
|
+
max-width: 300px
|
179
|
+
.input-group-addon
|
180
|
+
padding: 0
|
181
|
+
padding-left: 5px
|
182
|
+
i
|
183
|
+
border: 1px solid #ccc
|
184
|
+
width: 25px
|
185
|
+
height: 25px
|
186
|
+
|
168
187
|
//== Search form filter
|
169
188
|
//
|
170
189
|
//##
|
@@ -7,22 +7,39 @@
|
|
7
7
|
//##
|
8
8
|
|
9
9
|
//** Add negative margin top if the nav tab is the frst content of the page
|
10
|
-
.page-content-wrap
|
11
|
-
.nav-tabs
|
10
|
+
.page-content-wrap
|
11
|
+
.nav-tabs-wrapper
|
12
12
|
margin-top: -25px
|
13
|
+
|
14
|
+
.nav-tabs
|
13
15
|
+border-radius($border-radius-small)
|
14
|
-
|
15
|
-
|
16
|
+
|
17
|
+
&.affix
|
18
|
+
margin-top: 0
|
19
|
+
width: 100%
|
20
|
+
z-index: $zindex-navbar-fixed - 1
|
21
|
+
+material-box-shadow-soft(3)
|
22
|
+
|
23
|
+
.form-inputs
|
24
|
+
.nav-tabs-wrapper
|
16
25
|
margin-top: 0
|
26
|
+
|
27
|
+
.nav-tabs
|
17
28
|
+border-radius(0)
|
18
29
|
|
30
|
+
.panel-body
|
31
|
+
.nav-tabs-wrapper
|
32
|
+
margin-top: -25px
|
33
|
+
|
19
34
|
//** Override bootstrap nav tabs
|
20
|
-
.nav-tabs
|
21
|
-
background-color: $gray-lighter
|
35
|
+
.nav-tabs-wrapper
|
22
36
|
margin-right: -25px
|
23
37
|
margin-left: -25px
|
24
38
|
margin-bottom: 25px
|
25
39
|
|
40
|
+
.nav-tabs
|
41
|
+
background-color: $gray-lighter
|
42
|
+
|
26
43
|
> li > a
|
27
44
|
color: $text-color
|
28
45
|
border: none
|
@@ -8,14 +8,15 @@
|
|
8
8
|
|
9
9
|
.form-group.nested_one
|
10
10
|
label.control-label.nested_one
|
11
|
-
|
12
|
-
font-size: 21px
|
13
|
-
color: $blue-darker
|
14
|
-
text-transform: inherit
|
11
|
+
width: 100%
|
15
12
|
margin-top: 15px
|
16
13
|
margin-bottom: 15px
|
14
|
+
padding-bottom: 10px
|
15
|
+
border-bottom: 1px solid $gray-light
|
16
|
+
font-weight: 600
|
17
|
+
font-size: 18px
|
17
18
|
|
18
19
|
.tab-pane
|
19
20
|
> .form-group.nested_one
|
20
21
|
label.control-label.nested_one
|
21
|
-
margin-top: 0
|
22
|
+
margin-top: 0
|
@@ -12,6 +12,7 @@ module Para
|
|
12
12
|
layout 'para/admin'
|
13
13
|
|
14
14
|
helper_method :current_admin
|
15
|
+
helper_method :admin_body_class
|
15
16
|
|
16
17
|
def current_admin
|
17
18
|
@current_admin ||= if Para.config.current_admin_method
|
@@ -27,6 +28,10 @@ module Para
|
|
27
28
|
|
28
29
|
private
|
29
30
|
|
31
|
+
def admin_body_class
|
32
|
+
'admin'
|
33
|
+
end
|
34
|
+
|
30
35
|
# Override cancan controlelr resource class to avoid attributes
|
31
36
|
# assignation issues with resources
|
32
37
|
#
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Para
|
2
|
+
module Admin
|
3
|
+
class NestedFormsController < ComponentController
|
4
|
+
def show
|
5
|
+
@model = params[:model_name].constantize
|
6
|
+
@object = params[:id] ? @model.find(params[:id]) : @model.new
|
7
|
+
@object_name = params[:object_name]
|
8
|
+
|
9
|
+
render layout: false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -49,7 +49,7 @@ module Para
|
|
49
49
|
def destroy
|
50
50
|
resource.destroy
|
51
51
|
flash_message(:success, resource)
|
52
|
-
redirect_to
|
52
|
+
redirect_to after_form_submit_path
|
53
53
|
end
|
54
54
|
|
55
55
|
def order
|
@@ -83,14 +83,25 @@ module Para
|
|
83
83
|
|
84
84
|
def after_form_submit_path
|
85
85
|
if params[:_save_and_edit]
|
86
|
-
|
86
|
+
host_redirect_params.merge(
|
87
|
+
action: 'edit',
|
88
|
+
id: resource.id,
|
89
|
+
anchor: current_anchor
|
90
|
+
)
|
87
91
|
elsif params[:_save_and_add_another]
|
88
|
-
|
92
|
+
host_redirect_params.merge(
|
93
|
+
action: 'new',
|
94
|
+
type: resource.try(:type)
|
95
|
+
)
|
89
96
|
else
|
90
97
|
params.delete(:return_to).presence || @component.path
|
91
98
|
end
|
92
99
|
end
|
93
100
|
|
101
|
+
def host_redirect_params
|
102
|
+
{ subdomain: request.subdomain, domain: request.domain }
|
103
|
+
end
|
104
|
+
|
94
105
|
def resource_model
|
95
106
|
@resource_model ||= self.class.resource_model
|
96
107
|
end
|
@@ -1,13 +1,15 @@
|
|
1
1
|
module Para
|
2
2
|
module Admin
|
3
3
|
class SearchController < ApplicationController
|
4
|
-
include Para::ModelHelper
|
5
|
-
include Para::SearchHelper
|
6
|
-
|
7
4
|
def index
|
5
|
+
# Parse ids that are provided as string into array
|
6
|
+
if params[:q] && params[:q][:id_in].is_a?(String)
|
7
|
+
params[:q][:id_in] = params[:q][:id_in].split(',')
|
8
|
+
end
|
9
|
+
|
8
10
|
model = params[:model_name].constantize
|
9
|
-
|
10
|
-
|
11
|
+
@results = model.ransack(params[:q]).result
|
12
|
+
|
11
13
|
render layout: false
|
12
14
|
end
|
13
15
|
end
|
@@ -9,15 +9,20 @@ module Para
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def relation_path(controller_or_resource, options = {})
|
12
|
-
if Hash
|
12
|
+
if controller_or_resource.is_a?(Hash)
|
13
13
|
options = controller_or_resource
|
14
14
|
controller_or_resource = nil
|
15
15
|
end
|
16
16
|
|
17
17
|
components = [:admin, self, controller_or_resource].compact
|
18
|
+
|
18
19
|
find_path(components, options)
|
19
20
|
end
|
20
21
|
|
22
|
+
def page_container_class
|
23
|
+
'col-xs-12'
|
24
|
+
end
|
25
|
+
|
21
26
|
private
|
22
27
|
|
23
28
|
# Try to find a polymorphic path for the given arguments
|
@@ -28,7 +33,7 @@ module Para
|
|
28
33
|
#
|
29
34
|
def find_path(path, options)
|
30
35
|
safe_polymorphic_path(path, options).tap do |result|
|
31
|
-
raise result
|
36
|
+
raise result if result.is_a?(Exception)
|
32
37
|
end
|
33
38
|
end
|
34
39
|
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class CallForProjectsVotesExporter < Para::Exporter::Xls
|
2
|
+
attr_reader :call_for_projects
|
3
|
+
|
4
|
+
def name
|
5
|
+
'votes-appel-projets'
|
6
|
+
end
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
def self.params_whitelist
|
11
|
+
[:call_for_projects_id]
|
12
|
+
end
|
13
|
+
|
14
|
+
def resources
|
15
|
+
resources = ActsAsVotable::Vote.joins(
|
16
|
+
"LEFT JOIN call_for_projects_applications " +
|
17
|
+
"ON call_for_projects_applications.id = votes.votable_id " +
|
18
|
+
"AND votes.votable_type = 'CallForProjectsApplication'"
|
19
|
+
).includes(:voter, votable: :call_for_projects)
|
20
|
+
|
21
|
+
# Filter if available
|
22
|
+
resources = resources.where(
|
23
|
+
call_for_projects_applications: {
|
24
|
+
call_for_projects_id: params[:call_for_projects_id]
|
25
|
+
}
|
26
|
+
) if params[:call_for_projects_id]
|
27
|
+
|
28
|
+
resources
|
29
|
+
end
|
30
|
+
|
31
|
+
# Defining the fields that you want to export will export all those fields
|
32
|
+
# directly to the XLS file
|
33
|
+
#
|
34
|
+
def headers
|
35
|
+
['Appel à projets', 'Projet', 'E-mail', 'Nom', 'Prénom', 'Date du vote']
|
36
|
+
end
|
37
|
+
|
38
|
+
# If you need special behavior in the row generation (rendering associated
|
39
|
+
# models or other specific logic), you can return an array here that will
|
40
|
+
# be written to the XLS
|
41
|
+
#
|
42
|
+
# For safe XLS writing, use the #encode method on every string in the
|
43
|
+
# returned array.
|
44
|
+
#
|
45
|
+
# Example :
|
46
|
+
#
|
47
|
+
# fields = [...]
|
48
|
+
# fields.map!(&:encode)
|
49
|
+
#
|
50
|
+
def row_for(resource)
|
51
|
+
[
|
52
|
+
resource.votable.call_for_projects.title,
|
53
|
+
resource.votable.name,
|
54
|
+
resource.voter.email,
|
55
|
+
resource.voter.last_name,
|
56
|
+
resource.voter.first_name,
|
57
|
+
I18n.l(resource.created_at)
|
58
|
+
]
|
59
|
+
end
|
60
|
+
|
61
|
+
# If you need complete control over you XLS generation, use the following
|
62
|
+
# method instead of the #fields or #row_for methods, and return a valid XLS
|
63
|
+
# StringIO object.
|
64
|
+
#
|
65
|
+
# A `#generate_workbook` method is provided, which will yield the workbook to
|
66
|
+
# you so you can just fill it, and then returns a StringIO that can be
|
67
|
+
# directly written to the Excel file.
|
68
|
+
#
|
69
|
+
# Please check the [Spreadsheet](https://github.com/zdavatz/spreadsheet) gem
|
70
|
+
# documentation for more informations about how to build your Excel document.
|
71
|
+
#
|
72
|
+
# def generate
|
73
|
+
# generate_workbook do |workbook|
|
74
|
+
# sheet = workbook.create_worksheet
|
75
|
+
# sheet.row(0).concat ['data', 'row']
|
76
|
+
# sheet.row(1).concat ['other', 'row']
|
77
|
+
# end
|
78
|
+
# end
|
79
|
+
end
|
@@ -39,9 +39,8 @@ module Para
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def template_path_lookup(*paths)
|
42
|
-
paths.find
|
43
|
-
|
44
|
-
end
|
42
|
+
path = paths.find { |path| lookup_context.find_all(path).any? }
|
43
|
+
path&.gsub(/\/_([^\/]+)\z/, '/\1')
|
45
44
|
end
|
46
45
|
|
47
46
|
def resource_title_for(resource)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Para
|
2
|
+
module Admin
|
3
|
+
module HistoryHelper
|
4
|
+
def history_for(component, action:, **options)
|
5
|
+
return unless component.history?
|
6
|
+
|
7
|
+
partial_path = find_partial_for(
|
8
|
+
(options[:resource] || options[:relation]),
|
9
|
+
"history/#{ action }"
|
10
|
+
)
|
11
|
+
|
12
|
+
render partial: partial_path, locals: options
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -6,7 +6,15 @@ module Para
|
|
6
6
|
wrapper: :vertical_form,
|
7
7
|
wrapper_mappings: Para::SimpleFormConfig.wrapper_mappings,
|
8
8
|
track_attribute_mappings: true,
|
9
|
-
html: {
|
9
|
+
html: {
|
10
|
+
class: '',
|
11
|
+
data: { :'para-form' => true },
|
12
|
+
# Force multipart forms to allow forms with no file input on creation
|
13
|
+
# to fetch nested fields with image inputs through the remote nested
|
14
|
+
# form loading system. Without this option, rails does not create a
|
15
|
+
# multipart form when there is no file input during the form creation.
|
16
|
+
multipart: true
|
17
|
+
}
|
10
18
|
}
|
11
19
|
|
12
20
|
options = default_options.deep_merge(options)
|