lato_cms 3.0.10 → 3.0.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 +4 -4
- data/app/assets/javascripts/lato_cms/controllers/lato_cms_video_field_controller.js +164 -0
- data/app/assets/stylesheets/lato_cms/application.scss +22 -0
- data/app/controllers/lato_cms/pages_controller.rb +19 -0
- data/app/helpers/lato_cms/pages_helper.rb +1 -1
- data/app/jobs/lato_cms/generate_video_poster_job.rb +12 -0
- data/app/models/lato_cms/page_field.rb +44 -0
- data/app/views/lato_cms/pages/fields/_video.html.erb +68 -0
- data/config/locales/en.yml +3 -0
- data/config/locales/it.yml +3 -0
- data/lib/lato_cms/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 18323c23906137ac104d760d833ca76cd64041f254372a8a7e037bee23a5d5c5
|
|
4
|
+
data.tar.gz: 5324f43d1305e9aea41bcf19b2b41c96e555edd70ace601b788e649f5cb80b7d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d1c86cbe7a2a9dc66ffad24bb681f5a9022243c86f39ea4f2e8273c5500efec5f5ea20f610979a2f1bc49a4e85e96f1c5471faf00a5d42011b5df02da18cff5a
|
|
7
|
+
data.tar.gz: eebc417e788f0275c9b6daf1e50777487008358f8b080b75b48cab6f192f1cea94d70f177da537f881ee723b90cf58d365bdcf51f197dc2f9dc0c88c072c9919
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static targets = ["input", "newPreview", "newPreviewContainer", "newPreviewName", "newPreviewSize", "currentContainer", "currentVideo", "removedNotice"]
|
|
5
|
+
|
|
6
|
+
connect() {
|
|
7
|
+
this.afterSave = this.afterSave.bind(this)
|
|
8
|
+
this.element.closest('form')?.addEventListener('lato-cms:fields-save-success', this.afterSave)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
disconnect() {
|
|
12
|
+
this.element.closest('form')?.removeEventListener('lato-cms:fields-save-success', this.afterSave)
|
|
13
|
+
this.revokeObjectUrl()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
preview() {
|
|
17
|
+
const file = this.inputTarget.files[0]
|
|
18
|
+
if (!file || !file.type.startsWith('video/')) return
|
|
19
|
+
|
|
20
|
+
// Object URL instead of FileReader: videos can be large and the browser
|
|
21
|
+
// streams from the original file without loading it in memory.
|
|
22
|
+
this.revokeObjectUrl()
|
|
23
|
+
this.objectUrl = URL.createObjectURL(file)
|
|
24
|
+
this.newPreviewTarget.src = this.objectUrl
|
|
25
|
+
this.newPreviewNameTarget.textContent = file.name
|
|
26
|
+
this.newPreviewSizeTarget.textContent = `(${this.humanSize(file.size)})`
|
|
27
|
+
this.newPreviewContainerTarget.classList.remove('d-none')
|
|
28
|
+
this.undo()
|
|
29
|
+
if (this.hasCurrentContainerTarget) this.currentContainerTarget.classList.add('d-none')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
removeNew() {
|
|
33
|
+
this.inputTarget.value = ''
|
|
34
|
+
this.revokeObjectUrl()
|
|
35
|
+
this.newPreviewTarget.removeAttribute('src')
|
|
36
|
+
this.newPreviewNameTarget.textContent = ''
|
|
37
|
+
this.newPreviewSizeTarget.textContent = ''
|
|
38
|
+
this.newPreviewContainerTarget.classList.add('d-none')
|
|
39
|
+
if (this.hasCurrentContainerTarget) this.currentContainerTarget.classList.remove('d-none')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
remove() {
|
|
43
|
+
if (!this.hasCurrentContainerTarget) return
|
|
44
|
+
|
|
45
|
+
this.currentContainerTarget.classList.add('lato-cms-file-field__item--removing')
|
|
46
|
+
this.removedNoticeTarget.classList.remove('d-none')
|
|
47
|
+
this.ensureRemoveInput()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
undo() {
|
|
51
|
+
if (!this.hasCurrentContainerTarget) return
|
|
52
|
+
|
|
53
|
+
this.currentContainerTarget.classList.remove('lato-cms-file-field__item--removing')
|
|
54
|
+
this.removedNoticeTarget.classList.add('d-none')
|
|
55
|
+
this.removeInput?.remove()
|
|
56
|
+
this.removeInput = null
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
ensureRemoveInput() {
|
|
60
|
+
if (this.removeInput) return
|
|
61
|
+
|
|
62
|
+
const input = document.createElement('input')
|
|
63
|
+
input.type = 'hidden'
|
|
64
|
+
input.name = this.inputTarget.name.replace(/\[files\]\[\]$/, '[remove_file_ids][]')
|
|
65
|
+
input.value = this.currentContainerTarget.dataset.attachmentId
|
|
66
|
+
this.element.appendChild(input)
|
|
67
|
+
this.removeInput = input
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
afterSave(event) {
|
|
71
|
+
if (!event.detail.success) return
|
|
72
|
+
|
|
73
|
+
this.inputTarget.value = ''
|
|
74
|
+
this.removeInput = null
|
|
75
|
+
this.revokeObjectUrl()
|
|
76
|
+
const field = this.findSavedField(event.detail.data?.fields || [])
|
|
77
|
+
if (!field) return
|
|
78
|
+
|
|
79
|
+
const attachment = field.attachments[0]
|
|
80
|
+
this.element.querySelector('[data-lato-cms-video-field-target="currentContainer"]')?.remove()
|
|
81
|
+
this.newPreviewContainerTarget.classList.add('d-none')
|
|
82
|
+
|
|
83
|
+
if (attachment) {
|
|
84
|
+
this.element.insertBefore(this.buildCurrentContainer(attachment), this.newPreviewContainerTarget)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
findSavedField(fields) {
|
|
89
|
+
return fields.find(field => {
|
|
90
|
+
return field.persisted_field_id === this.fieldId || field.field_id === this.fieldId
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
buildCurrentContainer(attachment) {
|
|
95
|
+
const container = document.createElement('div')
|
|
96
|
+
container.className = 'lato-cms-file-field__item lato-cms-video-field__item'
|
|
97
|
+
container.dataset.latoCmsVideoFieldTarget = 'currentContainer'
|
|
98
|
+
container.dataset.attachmentId = attachment.id
|
|
99
|
+
// poster_url is usually still null right after save: the poster is
|
|
100
|
+
// generated by a background job and shows up on the next page load.
|
|
101
|
+
const poster = attachment.poster_url ? ` poster="${attachment.poster_url}"` : ''
|
|
102
|
+
container.innerHTML = `
|
|
103
|
+
<div class="lato-cms-video-field__preview">
|
|
104
|
+
<video controls preload="metadata" class="lato-cms-video-field__player" src="${attachment.url}"${poster} data-lato-cms-video-field-target="currentVideo"></video>
|
|
105
|
+
</div>
|
|
106
|
+
<div class="lato-cms-file-field__info">
|
|
107
|
+
<i class="bi bi-film"></i>
|
|
108
|
+
<span>${this.escapeHtml(attachment.filename)}</span>
|
|
109
|
+
<span class="text-muted small">(${this.humanSize(attachment.byte_size || 0)})</span>
|
|
110
|
+
</div>
|
|
111
|
+
<button type="button" class="lato-cms-attachment-field__remove" title="${this.removeLabel}" aria-label="${this.removeLabel}" data-action="lato-cms-video-field#remove">
|
|
112
|
+
<i class="bi bi-trash"></i>
|
|
113
|
+
</button>
|
|
114
|
+
<div class="lato-cms-file-field__removed d-none" data-lato-cms-video-field-target="removedNotice">
|
|
115
|
+
<span class="text-danger small">
|
|
116
|
+
<i class="bi bi-trash me-1"></i>${this.removePendingLabel}
|
|
117
|
+
</span>
|
|
118
|
+
<button type="button" class="btn btn-link btn-sm p-0" data-action="lato-cms-video-field#undo">
|
|
119
|
+
${this.undoLabel}
|
|
120
|
+
</button>
|
|
121
|
+
</div>
|
|
122
|
+
`
|
|
123
|
+
return container
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
revokeObjectUrl() {
|
|
127
|
+
if (!this.objectUrl) return
|
|
128
|
+
|
|
129
|
+
URL.revokeObjectURL(this.objectUrl)
|
|
130
|
+
this.objectUrl = null
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
humanSize(size) {
|
|
134
|
+
if (size < 1024) return `${size} B`
|
|
135
|
+
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`
|
|
136
|
+
return `${(size / 1024 / 1024).toFixed(1)} MB`
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
escapeHtml(value) {
|
|
140
|
+
return value.replace(/[&<>"']/g, char => ({
|
|
141
|
+
'&': '&',
|
|
142
|
+
'<': '<',
|
|
143
|
+
'>': '>',
|
|
144
|
+
'"': '"',
|
|
145
|
+
"'": '''
|
|
146
|
+
}[char]))
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
get fieldId() {
|
|
150
|
+
return this.element.dataset.fieldId
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
get removeLabel() {
|
|
154
|
+
return this.element.dataset.removeLabel || 'Remove'
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
get removePendingLabel() {
|
|
158
|
+
return this.element.dataset.removePendingLabel || 'Video will be removed on save'
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
get undoLabel() {
|
|
162
|
+
return this.element.dataset.undoLabel || 'Undo'
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -268,6 +268,7 @@ body.controller-pages.action-show {
|
|
|
268
268
|
|
|
269
269
|
.lato-cms-file-field__info,
|
|
270
270
|
.lato-cms-image-field__preview,
|
|
271
|
+
.lato-cms-video-field__preview,
|
|
271
272
|
.lato-cms-attachment-field__remove,
|
|
272
273
|
> .btn {
|
|
273
274
|
display: none;
|
|
@@ -339,6 +340,27 @@ body.controller-pages.action-show {
|
|
|
339
340
|
font-size: 10px;
|
|
340
341
|
}
|
|
341
342
|
|
|
343
|
+
// ── Video field ────────────────────────────────────────────────────────────────
|
|
344
|
+
.lato-cms-video-field__item {
|
|
345
|
+
align-items: stretch;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.lato-cms-video-field__preview {
|
|
349
|
+
align-self: center;
|
|
350
|
+
background: #000;
|
|
351
|
+
border: 1px solid rgba(33, 37, 41, 0.08);
|
|
352
|
+
border-radius: 6px;
|
|
353
|
+
flex: 0 0 auto;
|
|
354
|
+
overflow: hidden;
|
|
355
|
+
width: 180px;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.lato-cms-video-field__player {
|
|
359
|
+
display: block;
|
|
360
|
+
max-height: 110px;
|
|
361
|
+
width: 100%;
|
|
362
|
+
}
|
|
363
|
+
|
|
342
364
|
// ── Gallery field ──────────────────────────────────────────────────────────────
|
|
343
365
|
.lato-cms-gallery-field__grid {
|
|
344
366
|
display: flex;
|
|
@@ -299,6 +299,9 @@ module LatoCms
|
|
|
299
299
|
when 'image'
|
|
300
300
|
field.save if field.new_record?
|
|
301
301
|
replace_field_image(field, field_data)
|
|
302
|
+
when 'video'
|
|
303
|
+
field.save if field.new_record?
|
|
304
|
+
replace_field_video(field, field_data)
|
|
302
305
|
when 'gallery'
|
|
303
306
|
field.save if field.new_record?
|
|
304
307
|
attach_field_files(field, field_data)
|
|
@@ -354,6 +357,22 @@ module LatoCms
|
|
|
354
357
|
end
|
|
355
358
|
end
|
|
356
359
|
|
|
360
|
+
# Single-video semantics: uploading a new video replaces both the previous
|
|
361
|
+
# video and its auto-generated poster; removing the video drops the poster
|
|
362
|
+
# too. Poster generation runs in a background job to keep the save fast.
|
|
363
|
+
def replace_field_video(field, field_data)
|
|
364
|
+
if field_data[:files].present?
|
|
365
|
+
new_file = Array(field_data[:files]).compact.first
|
|
366
|
+
return unless new_file
|
|
367
|
+
|
|
368
|
+
field.files.each(&:purge)
|
|
369
|
+
field.files.attach(new_file)
|
|
370
|
+
LatoCms::GenerateVideoPosterJob.perform_later(field.id)
|
|
371
|
+
elsif field_data[:remove_file_ids].present?
|
|
372
|
+
field.files.each(&:purge)
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
|
|
357
376
|
def create_params
|
|
358
377
|
params.require(:page).permit(:title, :locale)
|
|
359
378
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module LatoCms
|
|
2
2
|
module PagesHelper
|
|
3
|
-
BUILTIN_FIELD_TYPES = %w[string textarea text number date datetime boolean select multiselect color json file image gallery].freeze
|
|
3
|
+
BUILTIN_FIELD_TYPES = %w[string textarea text number date datetime boolean select multiselect color json file image video gallery].freeze
|
|
4
4
|
|
|
5
5
|
# Returns the path for an Active Storage attachment.
|
|
6
6
|
# Using main_app avoids the missing `attachment_path` error inside the engine.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module LatoCms
|
|
2
|
+
# Generates the poster image for a video field in the background so the save
|
|
3
|
+
# request is not blocked by ffmpeg processing. Failures are swallowed by the
|
|
4
|
+
# model (logged as warnings): a missing poster must never break the field.
|
|
5
|
+
class GenerateVideoPosterJob < ApplicationJob
|
|
6
|
+
queue_as :default
|
|
7
|
+
|
|
8
|
+
def perform(page_field_id)
|
|
9
|
+
LatoCms::PageField.find_by(id: page_field_id)&.generate_video_poster!
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -75,6 +75,38 @@ module LatoCms
|
|
|
75
75
|
field_config&.dig('settings') || {}
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
+
# A video field stores two attachments in `files`: the video itself and an
|
|
79
|
+
# optional auto-generated poster image. Content type is the discriminator,
|
|
80
|
+
# so no extra column or naming convention is needed.
|
|
81
|
+
def video_attachment
|
|
82
|
+
files.find { |file| file.content_type.to_s.start_with?("video/") }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def poster_attachment
|
|
86
|
+
files.find { |file| file.content_type.to_s.start_with?("image/") }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Generates a poster image from the video via Active Storage previews
|
|
90
|
+
# (ffmpeg) and attaches it alongside the video. Best effort: any failure is
|
|
91
|
+
# logged and the video keeps working without a poster.
|
|
92
|
+
def generate_video_poster!
|
|
93
|
+
video = video_attachment
|
|
94
|
+
return unless video
|
|
95
|
+
return if poster_attachment
|
|
96
|
+
|
|
97
|
+
unless video.previewable?
|
|
98
|
+
Rails.logger.warn("LatoCms: video preview unavailable (ffmpeg missing?) for attachment #{video.id}, skipping poster generation")
|
|
99
|
+
return
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
preview = video.preview(resize_to_limit: [1280, 720]).processed
|
|
103
|
+
preview.image.blob.open do |file|
|
|
104
|
+
files.attach(io: file, filename: "#{video.filename.base}_poster.jpg", content_type: preview.image.blob.content_type)
|
|
105
|
+
end
|
|
106
|
+
rescue StandardError => e
|
|
107
|
+
Rails.logger.warn("LatoCms: failed to generate video poster for field #{id}: #{e.message}")
|
|
108
|
+
end
|
|
109
|
+
|
|
78
110
|
def as_json(_options = {})
|
|
79
111
|
result = {
|
|
80
112
|
id: id,
|
|
@@ -93,6 +125,9 @@ module LatoCms
|
|
|
93
125
|
when 'image'
|
|
94
126
|
attached = files.first
|
|
95
127
|
result[:attachments] = attached ? [attachment_as_json(attached, with_variants: true)] : []
|
|
128
|
+
when 'video'
|
|
129
|
+
attached = video_attachment
|
|
130
|
+
result[:attachments] = attached ? [video_attachment_as_json(attached)] : []
|
|
96
131
|
when 'gallery'
|
|
97
132
|
order = value ? (JSON.parse(value) rescue []) : []
|
|
98
133
|
all_files = files.to_a
|
|
@@ -119,6 +154,15 @@ module LatoCms
|
|
|
119
154
|
json
|
|
120
155
|
end
|
|
121
156
|
|
|
157
|
+
# Video attachment json gains a `poster_url` key (nil until the poster job
|
|
158
|
+
# runs) so API consumers get video and poster URLs in a single object.
|
|
159
|
+
def video_attachment_as_json(attachment)
|
|
160
|
+
poster = poster_attachment
|
|
161
|
+
attachment_as_json(attachment).merge(
|
|
162
|
+
poster_url: poster && Rails.application.routes.url_helpers.rails_blob_path(poster, only_path: true)
|
|
163
|
+
)
|
|
164
|
+
end
|
|
165
|
+
|
|
122
166
|
# Builds a map of { size_name => variant_url } from the field's `settings.sizes`.
|
|
123
167
|
# Variants are processed lazily by Active Storage on first request to their URL.
|
|
124
168
|
def attachment_variant_urls(attachment)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<% label = field_config['name'] || field_id.humanize %>
|
|
2
|
+
<% required = field_config['required'] == true %>
|
|
3
|
+
<% settings = field_config['settings'] || {} %>
|
|
4
|
+
<% accept = settings['accept'] || 'video/*' %>
|
|
5
|
+
<% current_file = page_field&.video_attachment %>
|
|
6
|
+
<% poster_file = page_field&.poster_attachment %>
|
|
7
|
+
<% files_input_name = lato_cms_field_input_name(field_id, 'files', input_name_prefix: local_assigns[:input_name_prefix], multiple: true) %>
|
|
8
|
+
<% remove_input_name = lato_cms_field_input_name(field_id, 'remove_file_ids', input_name_prefix: local_assigns[:input_name_prefix], multiple: true) %>
|
|
9
|
+
<% input_id = lato_cms_field_dom_id(field_id, 'files', dom_id_prefix: local_assigns[:dom_id_prefix]) %>
|
|
10
|
+
|
|
11
|
+
<label class="form-label">
|
|
12
|
+
<%= label %><%= ' *' if required %>
|
|
13
|
+
</label>
|
|
14
|
+
|
|
15
|
+
<div data-controller="lato-cms-video-field"
|
|
16
|
+
data-field-id="<%= field_id %>"
|
|
17
|
+
data-new-badge-label="<%= t('lato_cms.field_video_new_badge') %>"
|
|
18
|
+
data-remove-label="<%= t('lato_cms.field_video_remove') %>"
|
|
19
|
+
data-remove-pending-label="<%= t('lato_cms.field_video_remove_pending') %>"
|
|
20
|
+
data-undo-label="<%= t('lato_cms.field_file_remove_undo') %>">
|
|
21
|
+
<% if current_file %>
|
|
22
|
+
<div class="lato-cms-file-field__item lato-cms-video-field__item" data-lato-cms-video-field-target="currentContainer" data-attachment-id="<%= current_file.id %>">
|
|
23
|
+
<div class="lato-cms-video-field__preview">
|
|
24
|
+
<video controls preload="metadata" class="lato-cms-video-field__player" src="<%= lato_cms_attachment_path(current_file) %>" <% if poster_file %>poster="<%= lato_cms_attachment_path(poster_file) %>"<% end %> data-lato-cms-video-field-target="currentVideo"></video>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="lato-cms-file-field__info">
|
|
27
|
+
<i class="bi bi-film"></i>
|
|
28
|
+
<span><%= current_file.blob.filename %></span>
|
|
29
|
+
<span class="text-muted small">(<%= number_to_human_size(current_file.blob.byte_size) %>)</span>
|
|
30
|
+
</div>
|
|
31
|
+
<button type="button" class="lato-cms-attachment-field__remove" title="<%= t('lato_cms.field_video_remove') %>" aria-label="<%= t('lato_cms.field_video_remove') %>" data-action="lato-cms-video-field#remove">
|
|
32
|
+
<i class="bi bi-trash"></i>
|
|
33
|
+
</button>
|
|
34
|
+
<div class="lato-cms-file-field__removed d-none" data-lato-cms-video-field-target="removedNotice">
|
|
35
|
+
<span class="text-danger small">
|
|
36
|
+
<i class="bi bi-trash me-1"></i><%= t('lato_cms.field_video_remove_pending') %>
|
|
37
|
+
</span>
|
|
38
|
+
<button type="button" class="btn btn-link btn-sm p-0" data-action="lato-cms-video-field#undo">
|
|
39
|
+
<%= t('lato_cms.field_file_remove_undo') %>
|
|
40
|
+
</button>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
<% end %>
|
|
44
|
+
|
|
45
|
+
<div class="lato-cms-file-field__item lato-cms-file-field__item--new lato-cms-video-field__item d-none" data-lato-cms-video-field-target="newPreviewContainer">
|
|
46
|
+
<div class="lato-cms-video-field__preview">
|
|
47
|
+
<video controls preload="metadata" class="lato-cms-video-field__player" data-lato-cms-video-field-target="newPreview"></video>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="lato-cms-file-field__info">
|
|
50
|
+
<i class="bi bi-film"></i>
|
|
51
|
+
<span data-lato-cms-video-field-target="newPreviewName"></span>
|
|
52
|
+
<span class="text-muted small" data-lato-cms-video-field-target="newPreviewSize"></span>
|
|
53
|
+
<span class="badge bg-success"><%= t('lato_cms.field_video_new_badge') %></span>
|
|
54
|
+
</div>
|
|
55
|
+
<button type="button" class="lato-cms-attachment-field__remove" title="<%= t('lato_cms.field_video_remove') %>" aria-label="<%= t('lato_cms.field_video_remove') %>" data-action="lato-cms-video-field#removeNew">
|
|
56
|
+
<i class="bi bi-trash"></i>
|
|
57
|
+
</button>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<input type="file"
|
|
61
|
+
class="form-control"
|
|
62
|
+
name="<%= files_input_name %>"
|
|
63
|
+
id="<%= input_id %>"
|
|
64
|
+
accept="<%= accept %>"
|
|
65
|
+
data-lato-cms-video-field-target="input"
|
|
66
|
+
data-action="change->lato-cms-video-field#preview"
|
|
67
|
+
<%= 'required' if required && !current_file %>>
|
|
68
|
+
</div>
|
data/config/locales/en.yml
CHANGED
|
@@ -94,6 +94,9 @@ en:
|
|
|
94
94
|
field_image_remove: Remove
|
|
95
95
|
field_image_remove_pending: Image will be removed on save
|
|
96
96
|
field_image_new_badge: New
|
|
97
|
+
field_video_remove: Remove
|
|
98
|
+
field_video_remove_pending: Video will be removed on save
|
|
99
|
+
field_video_new_badge: New
|
|
97
100
|
field_multiselect_hint: Hold Ctrl/Cmd to select multiple
|
|
98
101
|
field_select_placeholder: "-- Select --"
|
|
99
102
|
field_text_toolbar_bold: Bold
|
data/config/locales/it.yml
CHANGED
|
@@ -94,6 +94,9 @@ it:
|
|
|
94
94
|
field_image_remove: Rimuovi
|
|
95
95
|
field_image_remove_pending: L'immagine verra rimossa al salvataggio
|
|
96
96
|
field_image_new_badge: Nuovo
|
|
97
|
+
field_video_remove: Rimuovi
|
|
98
|
+
field_video_remove_pending: Il video verra rimosso al salvataggio
|
|
99
|
+
field_video_new_badge: Nuovo
|
|
97
100
|
field_multiselect_hint: Tieni premuto Ctrl/Cmd per selezionare piu opzioni
|
|
98
101
|
field_select_placeholder: "-- Seleziona --"
|
|
99
102
|
field_text_toolbar_bold: Grassetto
|
data/lib/lato_cms/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lato_cms
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.
|
|
4
|
+
version: 3.0.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gregorio Galante
|
|
@@ -103,6 +103,7 @@ files:
|
|
|
103
103
|
- app/assets/javascripts/lato_cms/controllers/lato_cms_page_preview_controller.js
|
|
104
104
|
- app/assets/javascripts/lato_cms/controllers/lato_cms_repeater_controller.js
|
|
105
105
|
- app/assets/javascripts/lato_cms/controllers/lato_cms_text_field_controller.js
|
|
106
|
+
- app/assets/javascripts/lato_cms/controllers/lato_cms_video_field_controller.js
|
|
106
107
|
- app/assets/stylesheets/lato_cms/application.scss
|
|
107
108
|
- app/controllers/lato_cms/api/pages_controller.rb
|
|
108
109
|
- app/controllers/lato_cms/application_controller.rb
|
|
@@ -110,6 +111,7 @@ files:
|
|
|
110
111
|
- app/helpers/lato_cms/application_helper.rb
|
|
111
112
|
- app/helpers/lato_cms/pages_helper.rb
|
|
112
113
|
- app/jobs/lato_cms/application_job.rb
|
|
114
|
+
- app/jobs/lato_cms/generate_video_poster_job.rb
|
|
113
115
|
- app/mailers/lato_cms/application_mailer.rb
|
|
114
116
|
- app/models/lato_cms/page.rb
|
|
115
117
|
- app/models/lato_cms/page_field.rb
|
|
@@ -136,6 +138,7 @@ files:
|
|
|
136
138
|
- app/views/lato_cms/pages/fields/_string.html.erb
|
|
137
139
|
- app/views/lato_cms/pages/fields/_text.html.erb
|
|
138
140
|
- app/views/lato_cms/pages/fields/_textarea.html.erb
|
|
141
|
+
- app/views/lato_cms/pages/fields/_video.html.erb
|
|
139
142
|
- app/views/lato_cms/pages/index.html.erb
|
|
140
143
|
- app/views/lato_cms/pages/show.html.erb
|
|
141
144
|
- app/views/lato_cms/pages/translations.html.erb
|