pg_rails 7.0.8.pre.alpha → 7.0.8.pre.alpha.6
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/README.md +3 -0
- data/pg_associable/app/assets/stylesheets/pg_associable.scss +39 -40
- data/pg_associable/app/helpers/pg_associable/form_builder_methods.rb +45 -1
- data/pg_associable/app/helpers/pg_associable/helpers.rb +6 -4
- data/pg_associable/app/javascript/asociable_controller.tsx +96 -20
- data/pg_associable/app/javascript/modal_controller.js +4 -95
- data/pg_associable/app/views/pg_associable/_resultados_inline.html.slim +6 -8
- data/pg_associable/app/views/pg_engine/base/_pg_associable_modal.html.slim +5 -32
- data/pg_engine/app/assets/stylesheets/pg_rails_b5.scss +49 -41
- data/pg_engine/app/controllers/pg_engine/resource_helper.rb +6 -2
- data/pg_engine/app/decorators/pg_engine/base_decorator.rb +2 -2
- data/pg_engine/app/helpers/pg_engine/flash_helper.rb +2 -2
- data/pg_engine/app/helpers/pg_engine/form_helper.rb +70 -0
- data/pg_engine/app/helpers/pg_engine/route_helper.rb +14 -6
- data/pg_engine/app/views/admin/accounts/_form.html.slim +1 -1
- data/pg_engine/app/views/admin/user_accounts/_form.html.slim +1 -1
- data/pg_engine/app/views/admin/users/_form.html.slim +1 -1
- data/pg_engine/app/views/pg_engine/base/index.html.slim +3 -3
- data/pg_engine/config/simple_form/simple_form_bootstrap.rb +17 -9
- data/pg_engine/db/migrate/20240222115722_create_active_storage_tables.active_storage.rb +57 -0
- data/pg_engine/lib/pg_engine/engine.rb +1 -1
- data/pg_engine/lib/pg_engine/route_helpers.rb +1 -0
- data/pg_engine/lib/pg_engine/utils/pdf_preview_generator.rb +50 -0
- data/pg_engine/lib/pg_engine.rb +3 -0
- data/pg_engine/spec/fixtures/test.pdf +0 -0
- data/pg_engine/spec/pg_engine/pdf_preview_generator_spec.rb +12 -0
- data/pg_layout/app/assets/stylesheets/sidebar.scss +10 -2
- data/pg_layout/app/javascript/nested_controller.js +48 -0
- data/pg_layout/app/javascript/pg_form_controller.js +13 -0
- data/pg_layout/app/javascript/utils.ts +34 -0
- data/pg_layout/app/views/layouts/pg_layout/devise.html.slim +1 -1
- data/pg_layout/app/views/layouts/pg_layout/layout.html.slim +14 -11
- data/pg_layout/app/views/pg_layout/_flash.html.slim +1 -1
- data/pg_layout/app/views/pg_layout/_navbar.html.erb +10 -0
- data/pg_layout/app/views/pg_layout/_sidebar.html.erb +3 -3
- data/pg_layout/index.js +4 -0
- data/pg_rails/lib/version.rb +1 -1
- data/pg_scaffold/lib/generators/pg_slim/templates/_form.html.slim +2 -2
- metadata +9 -3
- data/pg_associable/app/views/pg_associable/_resultados.html.slim +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 54b808ee15e453ddfc9031c04c599eea58099615a03b4d23abadec9ee3951d8c
|
4
|
+
data.tar.gz: 552aabdd132314da31928c4fcb2b59969ad7afe21c7a239f45fbc7738a1356ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5dddf3ab456741e7f671be016484caf643c1ad09a76ba96900707ab4e992049c5eb7da1273ab82b3fd83975278b72797cf4f9c0a178da5097f6343103e7968e7
|
7
|
+
data.tar.gz: 87c679f069138a579790599626636fcf31c44ea9a1393bd13314cb2c5268c6add6c46dc89eabcb742739a2d19179d0cf475860bdf108cd981e743183f0ae1a30
|
data/README.md
CHANGED
@@ -86,3 +86,6 @@ be rails pg_engine_engine:install:migrations
|
|
86
86
|
"build:css:prefix": "postcss ./pg_rails/builds/application.css --use=autoprefixer --output=./pg_rails/builds/application.css",
|
87
87
|
"build:css": "yarn build:css:compile && yarn build:css:prefix",
|
88
88
|
|
89
|
+
|
90
|
+
ruby-vips
|
91
|
+
pdftoppm
|
@@ -1,44 +1,47 @@
|
|
1
1
|
@use 'sass:color';
|
2
2
|
|
3
|
-
[data-state=select-item] .show-on-new-item {
|
4
|
-
display: none;
|
5
|
-
}
|
6
|
-
[data-state=new-item] .show-on-select-item {
|
7
|
-
display: none;
|
8
|
-
}
|
9
3
|
.pg-form {
|
10
4
|
.pg_associable {
|
11
5
|
.limpiar {
|
12
6
|
display: none;
|
13
7
|
position: absolute;
|
14
|
-
|
15
|
-
|
8
|
+
right: 0.6em;
|
9
|
+
top: 0;
|
10
|
+
bottom: 0;
|
11
|
+
|
16
12
|
i {
|
13
|
+
align-self: center;
|
17
14
|
color: #6f7071;
|
18
15
|
}
|
19
16
|
}
|
20
17
|
.pencil {
|
18
|
+
display: flex;
|
21
19
|
position: absolute;
|
22
|
-
|
23
|
-
|
20
|
+
right: 0.6em;
|
21
|
+
top: 0;
|
22
|
+
bottom: 0;
|
24
23
|
color: #6f7071;
|
25
24
|
cursor: pointer;
|
26
25
|
}
|
26
|
+
.pencil::before {
|
27
|
+
align-self: center;
|
28
|
+
}
|
27
29
|
&.focus .pencil {
|
28
30
|
display: none;
|
29
31
|
}
|
30
32
|
input[type=text] {
|
31
33
|
background-color: white;
|
34
|
+
padding-right: 2em;
|
32
35
|
}
|
33
36
|
&.filled {
|
34
37
|
.pencil {
|
35
38
|
display: none;
|
36
39
|
}
|
37
40
|
.limpiar {
|
38
|
-
display:
|
41
|
+
display: flex;
|
39
42
|
}
|
40
|
-
|
41
|
-
|
43
|
+
.resultados-wrapper {
|
44
|
+
display:none!important;
|
42
45
|
}
|
43
46
|
}
|
44
47
|
.resultados-wrapper {
|
@@ -46,11 +49,6 @@
|
|
46
49
|
position: relative;
|
47
50
|
}
|
48
51
|
&:focus-within {
|
49
|
-
.search-box {
|
50
|
-
// outline: 1px solid color.adjust(#a7b7bb, $saturation: +30%);
|
51
|
-
// border-radius: 3px;
|
52
|
-
}
|
53
|
-
|
54
52
|
&:has(.resultados) {
|
55
53
|
input[type=text] {
|
56
54
|
border-bottom-left-radius: 0!important;
|
@@ -64,36 +62,37 @@
|
|
64
62
|
display: block;
|
65
63
|
}
|
66
64
|
}
|
67
|
-
.resultados {
|
68
|
-
position: absolute;
|
69
|
-
// top: 30px;
|
70
|
-
background-color: white;
|
71
|
-
border: 1px solid #a7b7bb;
|
72
|
-
border-top: none;
|
73
|
-
border-radius: 4px;
|
74
|
-
padding: 5px 11px;
|
75
|
-
width: 100%;
|
76
|
-
|
77
|
-
border-top-left-radius: 0;
|
78
|
-
border-top-right-radius: 0;
|
79
|
-
}
|
80
|
-
}
|
81
|
-
}
|
82
|
-
.modal-asociable {
|
83
|
-
.buscar input[type=text] {
|
84
|
-
max-width: 180px;
|
85
|
-
}
|
86
|
-
.resultados {
|
87
|
-
margin-top: 16px;
|
88
|
-
border: 1px solid #c8c8c8;
|
89
65
|
}
|
90
66
|
}
|
67
|
+
// .modal-asociable {
|
68
|
+
// .buscar input[type=text] {
|
69
|
+
// max-width: 180px;
|
70
|
+
// }
|
71
|
+
// .resultados {
|
72
|
+
// margin-top: 16px;
|
73
|
+
// border: 1px solid #c8c8c8;
|
74
|
+
// }
|
75
|
+
// }
|
91
76
|
.resultados {
|
92
77
|
.list-group-item:hover {
|
93
78
|
background-color: color.adjust(#a7b7bb, $saturation: +10%, $lightness: +20%);
|
94
79
|
}
|
95
80
|
}
|
81
|
+
.sub-wrapper {
|
82
|
+
overflow: auto;
|
83
|
+
box-shadow: 0px 9px 13px -3px rgba(0, 0, 0, 0.5);
|
84
|
+
// position: absolute;
|
85
|
+
// z-index: 1;
|
86
|
+
background-color: white;
|
87
|
+
border: 1px solid #a7b7bb;
|
88
|
+
border-top: none;
|
89
|
+
border-radius: 4px;
|
90
|
+
padding: 5px 11px;
|
91
|
+
width: 100%;
|
96
92
|
|
93
|
+
border-top-left-radius: 0;
|
94
|
+
border-top-right-radius: 0;
|
95
|
+
}
|
97
96
|
.modal-asociable .modal-footer {
|
98
97
|
justify-content: space-between;
|
99
98
|
}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# TODO: mover a form_builder
|
1
2
|
module PgAssociable
|
2
3
|
module FormBuilderMethods
|
3
4
|
def self.included(mod)
|
@@ -5,10 +6,53 @@ module PgAssociable
|
|
5
6
|
mod.include PgEngine::RouteHelper
|
6
7
|
end
|
7
8
|
|
9
|
+
MAXIMO_PARA_SELECT = 10
|
10
|
+
# TODO: si está entre 10 y 50, habilitar un buscador por js
|
11
|
+
|
8
12
|
def pg_associable(atributo, options = {})
|
13
|
+
return input(atributo, options) if options[:disabled]
|
14
|
+
|
15
|
+
collection, puede_crear = collection_pc(atributo, options)
|
16
|
+
options.deep_merge!({ wrapper_html: { 'data-puede-crear': 'true' } }) if puede_crear
|
17
|
+
|
18
|
+
if !puede_crear && collection.count <= MAXIMO_PARA_SELECT
|
19
|
+
select_comun(atributo, options, collection)
|
20
|
+
else
|
21
|
+
select_pro(atributo, options, collection)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def collection_pc(atributo, _options)
|
26
|
+
klass = clase_asociacion(atributo)
|
27
|
+
user = template.controller.current_user
|
28
|
+
in_modal = options[:asociable].present?
|
29
|
+
puede_crear = !in_modal && Pundit::PolicyFinder.new(klass).policy.new(user, klass).new?
|
30
|
+
collection = Pundit::PolicyFinder.new(klass).scope.new(user, klass).resolve
|
31
|
+
[collection, puede_crear]
|
32
|
+
end
|
33
|
+
|
34
|
+
def select_pro(atributo, options, collection)
|
35
|
+
if (preload = options.delete(:preload))
|
36
|
+
collection = preload.is_a?(Integer) ? collection.limit(preload) : preload
|
37
|
+
options.deep_merge!({ wrapper_html: { 'data-preload': collection.decorate.to_json } })
|
38
|
+
end
|
39
|
+
# TODO: usar una clase más precisa para el modal?
|
40
|
+
options.deep_merge!({ wrapper_html: { data: { controller: 'asociable',
|
41
|
+
'asociable-modal-outlet': '.modal' } } })
|
9
42
|
options[:as] = 'pg_associable'
|
10
|
-
options[:wrapper_html] = { data: { controller: 'asociable', 'asociable-modal-outlet': '.modal' } }
|
11
43
|
association atributo, options
|
12
44
|
end
|
45
|
+
|
46
|
+
def select_comun(atributo, options, collection)
|
47
|
+
options[:collection] = collection
|
48
|
+
association atributo, options
|
49
|
+
end
|
50
|
+
|
51
|
+
def clase_asociacion(atributo)
|
52
|
+
asociacion = object.class.reflect_on_all_associations.find { |a| a.name == atributo.to_sym }
|
53
|
+
nombre_clase = asociacion.options[:class_name]
|
54
|
+
nombre_clase = asociacion.name.to_s.camelize if nombre_clase.nil?
|
55
|
+
Object.const_get(nombre_clase)
|
56
|
+
end
|
13
57
|
end
|
14
58
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module PgAssociable
|
2
2
|
module Helpers
|
3
|
+
MAX_RESULTS = 8
|
4
|
+
|
3
5
|
def pg_respond_abrir_modal
|
4
6
|
respond_to do |format|
|
5
7
|
format.turbo_stream do
|
@@ -9,11 +11,11 @@ module PgAssociable
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def pg_respond_buscar
|
12
|
-
partial =
|
13
|
-
|
14
|
-
@collection = policy_scope(@clase_modelo).kept.query(params[:query]).limit(
|
14
|
+
partial = 'pg_associable/resultados_inline'
|
15
|
+
resultados_prefix = 'resultados-inline'
|
16
|
+
@collection = policy_scope(@clase_modelo).kept.query(params[:query]).limit(MAX_RESULTS)
|
15
17
|
render turbo_stream:
|
16
|
-
turbo_stream.update("#{
|
18
|
+
turbo_stream.update("#{resultados_prefix}-#{params[:id]}",
|
17
19
|
partial:, locals: { collection: @collection })
|
18
20
|
end
|
19
21
|
end
|
@@ -6,13 +6,11 @@ export default class extends Controller {
|
|
6
6
|
static outlets = ['modal']
|
7
7
|
|
8
8
|
lastValue = null
|
9
|
-
|
9
|
+
subWrapper = null
|
10
10
|
elemId = null
|
11
11
|
input = null
|
12
12
|
|
13
13
|
connect () {
|
14
|
-
console.log('connect asociable')
|
15
|
-
|
16
14
|
// ID único para identificar el campo y el modal
|
17
15
|
this.elemId = Math.trunc(Math.random() * 1000000000)
|
18
16
|
|
@@ -21,14 +19,22 @@ export default class extends Controller {
|
|
21
19
|
this.element.setAttribute('data-asociable-modal-outlet', `.modal-${this.elemId}`)
|
22
20
|
this.element.classList.add(`asociable-${this.elemId}`)
|
23
21
|
|
24
|
-
|
25
|
-
|
26
|
-
this.
|
27
|
-
this.
|
22
|
+
const result = document.createElement('div')
|
23
|
+
result.classList.add('resultados-wrapper')
|
24
|
+
this.subWrapper = document.createElement('div')
|
25
|
+
this.subWrapper.setAttribute('id', `resultados-inline-${this.elemId}`)
|
26
|
+
this.subWrapper.classList.add('sub-wrapper')
|
27
|
+
this.subWrapper.classList.add('position-absolute')
|
28
|
+
this.subWrapper.classList.add('z-1')
|
29
|
+
result.appendChild(this.subWrapper)
|
30
|
+
this.input.parentNode.appendChild(result)
|
31
|
+
|
32
|
+
this.resetResultados()
|
28
33
|
|
29
34
|
const input = this.element.querySelector('input[type=text]')
|
30
35
|
if (input.value) {
|
31
36
|
this.element.classList.add('filled')
|
37
|
+
input.setAttribute('readonly', 'true')
|
32
38
|
}
|
33
39
|
this.element.querySelector('.pencil').onclick = () => {
|
34
40
|
input.focus()
|
@@ -55,6 +61,20 @@ export default class extends Controller {
|
|
55
61
|
if (this.input.value.length === 0) {
|
56
62
|
this.escribiAlgo()
|
57
63
|
}
|
64
|
+
|
65
|
+
if (!this.element.closest('.modal')) {
|
66
|
+
const wHeight = window.visualViewport.height
|
67
|
+
const scrollTop = document.scrollingElement.scrollTop
|
68
|
+
const viewPortBottom = scrollTop + wHeight
|
69
|
+
const swHeight = parseInt(this.subWrapper.style.maxHeight) + 20
|
70
|
+
const elementTop = this.element.getBoundingClientRect().top + scrollTop
|
71
|
+
const inputBottom = this.input.getBoundingClientRect().bottom + scrollTop
|
72
|
+
const swBottom = inputBottom + swHeight
|
73
|
+
|
74
|
+
if (swBottom > viewPortBottom) {
|
75
|
+
document.scrollingElement.scroll({ top: elementTop })
|
76
|
+
}
|
77
|
+
}
|
58
78
|
}
|
59
79
|
this.input.onkeyup = (e) => {
|
60
80
|
if (this.input.value.length === 0) {
|
@@ -72,6 +92,61 @@ export default class extends Controller {
|
|
72
92
|
return false
|
73
93
|
}
|
74
94
|
}
|
95
|
+
this.setMaxHeight()
|
96
|
+
}
|
97
|
+
|
98
|
+
resetResultados () {
|
99
|
+
const rows = []
|
100
|
+
if (this.element.dataset.puedeCrear) {
|
101
|
+
rows.push(
|
102
|
+
<a key="new" href="javascript:void(0)"
|
103
|
+
className="list-group-item"
|
104
|
+
data-action="asociable#crearItem"
|
105
|
+
>
|
106
|
+
Nuevo
|
107
|
+
</a>
|
108
|
+
)
|
109
|
+
}
|
110
|
+
if (this.element.dataset.preload) {
|
111
|
+
JSON.parse(this.element.dataset.preload).forEach((object) => {
|
112
|
+
rows.push(
|
113
|
+
<a key={object.id} href="javascript:void(0)"
|
114
|
+
className="list-group-item"
|
115
|
+
data-action="asociable#selectItem"
|
116
|
+
data-id={object.id}
|
117
|
+
data-object={JSON.stringify(object)}
|
118
|
+
>
|
119
|
+
{object.to_s}
|
120
|
+
</a>
|
121
|
+
)
|
122
|
+
})
|
123
|
+
}
|
124
|
+
this.subWrapper.innerHTML = renderToStaticMarkup(
|
125
|
+
<div className="resultados" tabIndex={-1}>
|
126
|
+
<ul className="list-group list-group-flush">
|
127
|
+
{rows}
|
128
|
+
</ul>
|
129
|
+
</div>
|
130
|
+
)
|
131
|
+
}
|
132
|
+
|
133
|
+
setMaxHeight () {
|
134
|
+
let maxHeight
|
135
|
+
if (!this.element.closest('.modal')) {
|
136
|
+
const scrollTop = document.scrollingElement.scrollTop
|
137
|
+
const inputY = this.input.getBoundingClientRect().bottom + scrollTop
|
138
|
+
const bodyHeight = document.body.getBoundingClientRect().height
|
139
|
+
maxHeight = bodyHeight - inputY
|
140
|
+
if (maxHeight < 200) {
|
141
|
+
maxHeight = 200
|
142
|
+
}
|
143
|
+
if (bodyHeight < inputY + maxHeight) {
|
144
|
+
document.body.style.height = `${inputY + maxHeight}px`
|
145
|
+
}
|
146
|
+
} else {
|
147
|
+
maxHeight = 200
|
148
|
+
}
|
149
|
+
this.subWrapper.style.maxHeight = `${maxHeight - 20}px`
|
75
150
|
}
|
76
151
|
|
77
152
|
crearItem () {
|
@@ -82,7 +157,7 @@ export default class extends Controller {
|
|
82
157
|
}
|
83
158
|
|
84
159
|
const elem = (
|
85
|
-
<form method="get" action={this.input.dataset.
|
160
|
+
<form method="get" action={this.input.dataset.urlModal} data-turbo-stream="true">
|
86
161
|
<input type="hidden" name="id" value={this.elemId} />
|
87
162
|
</form>
|
88
163
|
)
|
@@ -98,7 +173,7 @@ export default class extends Controller {
|
|
98
173
|
}
|
99
174
|
|
100
175
|
buscando () {
|
101
|
-
this.
|
176
|
+
this.subWrapper.innerHTML = renderToStaticMarkup(
|
102
177
|
<div className="resultados" tabIndex={-1}>
|
103
178
|
<div className="fst-italic text-secondary">Buscando...</div>
|
104
179
|
</div>
|
@@ -111,11 +186,14 @@ export default class extends Controller {
|
|
111
186
|
} else {
|
112
187
|
this.completarCampo(null)
|
113
188
|
}
|
114
|
-
this.result.innerHTML = ''
|
115
189
|
}
|
116
190
|
|
117
191
|
doSearch (force = false) {
|
192
|
+
if (this.element.classList.contains('filled')) {
|
193
|
+
return
|
194
|
+
}
|
118
195
|
if (!force && this.input.value.length < 3) {
|
196
|
+
this.resetResultados()
|
119
197
|
return
|
120
198
|
}
|
121
199
|
if (!force && this.input.value === this.lastValue) {
|
@@ -128,13 +206,13 @@ export default class extends Controller {
|
|
128
206
|
}, 200)
|
129
207
|
document.addEventListener('turbo:before-stream-render', function () {
|
130
208
|
clearTimeout(timerId)
|
131
|
-
|
209
|
+
// TODO: testear
|
210
|
+
}, { once: true })
|
132
211
|
const elem = (
|
133
|
-
<form method="post" action={this.input.dataset.
|
212
|
+
<form method="post" action={this.input.dataset.urlSearch} data-turbo-stream="true">
|
134
213
|
<input type="hidden" name="id" value={this.elemId} />
|
135
|
-
<input type="hidden" name="partial" value="pg_associable/resultados_inline" />
|
136
|
-
<input type="hidden" name="resultados" value="resultados-inline" />
|
137
214
|
<input type="hidden" name="query" value={this.input.value} />
|
215
|
+
<input type="hidden" name="puede_crear" value={this.element.dataset.puedeCrear} />
|
138
216
|
</form>
|
139
217
|
)
|
140
218
|
const form = document.createElement('div')
|
@@ -150,22 +228,20 @@ export default class extends Controller {
|
|
150
228
|
if (object) {
|
151
229
|
hiddenField.value = object.id
|
152
230
|
textField.value = object.to_s
|
231
|
+
textField.setAttribute('readonly', 'true')
|
153
232
|
this.element.classList.add('filled')
|
154
233
|
this.element.dataset.object = object
|
155
234
|
const event = new CustomEvent('pg_associable:changed', { detail: object })
|
156
235
|
this.element.dispatchEvent(event)
|
157
236
|
} else {
|
158
|
-
textField.value = null
|
159
237
|
hiddenField.value = null
|
238
|
+
textField.value = null
|
239
|
+
textField.removeAttribute('readonly')
|
160
240
|
this.element.classList.remove('filled')
|
161
241
|
this.element.dataset.object = null
|
162
242
|
const event = new CustomEvent('pg_associable:changed')
|
163
243
|
this.element.dispatchEvent(event)
|
164
244
|
}
|
165
|
-
this.
|
166
|
-
}
|
167
|
-
|
168
|
-
disconnect () {
|
169
|
-
console.log('disconnect asociable')
|
245
|
+
this.resetResultados()
|
170
246
|
}
|
171
247
|
}
|
@@ -3,118 +3,27 @@ import * as bootstrap from 'bootstrap'
|
|
3
3
|
|
4
4
|
export default class extends Controller {
|
5
5
|
static outlets = ['asociable']
|
6
|
-
static targets = ['response'
|
6
|
+
static targets = ['response']
|
7
7
|
|
8
8
|
modalPuntero = null
|
9
|
-
lastValue = ''
|
10
9
|
|
11
10
|
connect (e) {
|
12
|
-
|
13
|
-
const modal = this.targets.element
|
14
|
-
this.modalPuntero = new bootstrap.Modal(modal)
|
11
|
+
this.modalPuntero = new bootstrap.Modal(this.element)
|
15
12
|
this.modalPuntero.show()
|
16
|
-
|
17
|
-
if (this.searchInputTargets.length > 0) {
|
18
|
-
this.bindSearchInput()
|
19
|
-
}
|
20
|
-
}
|
21
|
-
|
22
|
-
debounce (callback, wait) {
|
23
|
-
let timerId
|
24
|
-
return (...args) => {
|
25
|
-
clearTimeout(timerId)
|
26
|
-
timerId = setTimeout(() => {
|
27
|
-
callback(...args)
|
28
|
-
}, wait)
|
29
|
-
}
|
30
|
-
}
|
31
|
-
|
32
|
-
bindSearchInput () {
|
33
|
-
const doSearchBounce = this.debounce((force) => {
|
34
|
-
this.doSearch(force)
|
35
|
-
}, 200)
|
36
|
-
this.searchInputTarget.onkeydown = (e) => {
|
37
|
-
if (e.keyCode === 13) {
|
38
|
-
e.preventDefault()
|
39
|
-
return false
|
40
|
-
}
|
41
|
-
}
|
42
|
-
this.searchInputTarget.onkeyup = (e) => {
|
43
|
-
if (e.keyCode === 13) {
|
44
|
-
doSearchBounce(true)
|
45
|
-
} else {
|
46
|
-
doSearchBounce()
|
47
|
-
}
|
48
|
-
}
|
49
|
-
}
|
50
|
-
|
51
|
-
buscando () {
|
52
|
-
this.resultTarget.innerHTML = `
|
53
|
-
<ul class="resultados list-group list-group-flush" tabindex="-1">
|
54
|
-
<li class="list-group-item">
|
55
|
-
<span class="fst-italic text-secondary">Buscando...</span>
|
56
|
-
</li>
|
57
|
-
</ul>
|
58
|
-
`
|
59
|
-
}
|
60
|
-
|
61
|
-
doSearch (force = false) {
|
62
|
-
if (!force && this.searchInputTarget.value.length < 3) {
|
63
|
-
return
|
64
|
-
}
|
65
|
-
if (!force && this.searchInputTarget.value === this.lastValue) {
|
66
|
-
return
|
67
|
-
}
|
68
|
-
this.lastValue = this.searchInputTarget.value
|
69
|
-
|
70
|
-
const timerId = setTimeout(() => {
|
71
|
-
this.buscando()
|
72
|
-
}, 200)
|
73
|
-
document.addEventListener('turbo:before-stream-render', function (e) {
|
74
|
-
clearTimeout(timerId)
|
75
|
-
})
|
76
|
-
this.searchFormTarget.requestSubmit()
|
77
|
-
}
|
78
|
-
|
79
|
-
selectItem (e) {
|
80
|
-
const asociable = this.asociableOutlet
|
81
|
-
if (e.target.dataset.object) {
|
82
|
-
asociable.completarCampo(JSON.parse(e.target.dataset.object))
|
83
|
-
} else {
|
84
|
-
asociable.completarCampo(null)
|
85
|
-
}
|
86
|
-
this.remove()
|
87
13
|
}
|
88
14
|
|
89
15
|
responseTargetConnected (e) {
|
90
16
|
const newObject = JSON.parse(e.dataset.response)
|
91
|
-
|
92
|
-
|
93
|
-
this.remove()
|
94
|
-
}
|
95
|
-
|
96
|
-
remove () {
|
97
|
-
this.targets.element.remove()
|
17
|
+
this.asociableOutlet.completarCampo(newObject)
|
18
|
+
this.element.remove()
|
98
19
|
}
|
99
20
|
|
100
21
|
openModal () {
|
101
22
|
this.modalPuntero.show()
|
102
23
|
}
|
103
24
|
|
104
|
-
toggleCrearElegir (e) {
|
105
|
-
const content = this.element.querySelector('.modal-content')
|
106
|
-
const state = content.dataset.state
|
107
|
-
const newValue = state === 'new-item' ? 'select-item' : 'new-item'
|
108
|
-
content.setAttribute('data-state', newValue)
|
109
|
-
}
|
110
|
-
|
111
25
|
disconnect (e) {
|
112
|
-
console.log('ModalController disconnected')
|
113
26
|
this.modalPuntero.dispose()
|
114
27
|
document.querySelectorAll('.modal-backdrop').forEach(e => { e.remove() })
|
115
28
|
}
|
116
|
-
|
117
|
-
buscar () {
|
118
|
-
alert('buscar')
|
119
|
-
}
|
120
29
|
}
|
@@ -1,15 +1,13 @@
|
|
1
|
-
.resultados tabindex="-1"
|
2
|
-
-
|
3
|
-
|
4
|
-
= link_to '
|
1
|
+
.resultados.inline tabindex="-1"
|
2
|
+
ul.list-group.list-group-flush
|
3
|
+
- if params[:puede_crear].present?
|
4
|
+
= link_to 'Nuevo', 'javascript:void(0)',
|
5
5
|
class: 'list-group-item', data: { action: 'asociable#crearItem' }
|
6
|
-
|
7
|
-
class: 'list-group-item', data: { action: 'asociable#selectItem' }
|
6
|
+
- if collection.any?
|
8
7
|
- collection.each do |object|
|
9
8
|
= link_to object.to_s, 'javascript:void(0)',
|
10
9
|
class: 'list-group-item',
|
11
10
|
data: { action: 'asociable#selectItem',
|
12
11
|
id: object.id, object: object.decorate.to_json }
|
13
|
-
|
14
|
-
ul.list-group.list-group-flush
|
12
|
+
- else
|
15
13
|
li.list-group-item No hay resultados para "#{params[:query]}"
|
@@ -2,40 +2,13 @@
|
|
2
2
|
tabindex="-1" data-controller="modal"
|
3
3
|
data-modal-asociable-outlet=".asociable-#{params[:id]}"]
|
4
4
|
.modal-dialog
|
5
|
-
|
5
|
+
/ TODO: pg_associable no va
|
6
|
+
.modal-content.pg_associable
|
6
7
|
.modal-header
|
7
|
-
.modal-title
|
8
|
+
.modal-title
|
9
|
+
/ TODO: género "Nuevo/a"
|
8
10
|
h3 Nuevo #{@clase_modelo.nombre_singular.downcase}
|
9
|
-
.modal-title.show-on-select-item
|
10
|
-
h3 Buscar #{@clase_modelo.nombre_singular.downcase}
|
11
11
|
a.btn-close[type="button" data-bs-dismiss="modal" aria-label="Close"]
|
12
12
|
.modal-body
|
13
|
-
.
|
14
|
-
- if policy_scope(@clase_modelo).kept.count.zero?
|
15
|
-
p No hay #{@clase_modelo.nombre_plural.downcase} aún
|
16
|
-
= link_to "Crear el primer #{@clase_modelo.nombre_singular.downcase}",
|
17
|
-
'javascript:void(0)', data: { action: 'modal#toggleCrearElegir' }
|
18
|
-
- else
|
19
|
-
= form_tag namespaced_path(@clase_modelo, prefix: :buscar),
|
20
|
-
data: { 'modal-target': 'searchForm' },
|
21
|
-
method: :post, class: 'pg-form buscar' do
|
22
|
-
= hidden_field_tag :id, params[:id]
|
23
|
-
= text_field_tag :query, '', class: 'form-control',
|
24
|
-
placeholder: 'Escribí algo para buscar',
|
25
|
-
autocomplete: 'off',
|
26
|
-
data: { 'modal-target': 'searchInput' }
|
27
|
-
/ = button_tag 'Buscar'
|
28
|
-
.resultados-wrapper id="resultados-#{params[:id]}" data-modal-target="result"
|
29
|
-
#pg-associable-form.show-on-new-item
|
13
|
+
.pg-associable-form
|
30
14
|
= render partial: 'form', locals: { object: @clase_modelo.new, asociable: true }
|
31
|
-
|
32
|
-
.modal-footer
|
33
|
-
= link_to "Buscar #{@clase_modelo.nombre_singular.downcase} existente",
|
34
|
-
'javascript:void(0)', class: 'btn btn-primary show-on-new-item',
|
35
|
-
data: { action: 'modal#toggleCrearElegir' }
|
36
|
-
= link_to "Nuevo #{@clase_modelo.nombre_singular.downcase}",
|
37
|
-
'javascript:void(0)', class: 'btn btn-primary show-on-select-item',
|
38
|
-
data: { action: 'modal#toggleCrearElegir' }
|
39
|
-
= link_to "Sin #{@clase_modelo.nombre_singular.downcase}",
|
40
|
-
'javascript:void(0)', class: 'btn btn-secondary',
|
41
|
-
data: { action: 'modal#selectItem' }
|