Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion app/helpers/pageflow/files_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,20 @@ def file_duration(file)
#
# @param [JBuilder] json
# @param [PublishedEntry] entry
# @param [#include?] referenced_files
# Render `is_referenced` flags for files by calling
# `include?(collection_name, perma_id)`.
# @since 15.1
def files_json_seed(json, entry)
def files_json_seed(json, entry, referenced_files: nil)
Pageflow.config.file_types.each do |file_type|
json.set!(file_type.collection_name) do
json.array!(entry.find_files(file_type.model)) do |file|
json.partial!('pageflow/files/file', file:, file_type:)

if referenced_files
json.is_referenced(referenced_files.include?(file_type.collection_name,
file.perma_id))
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def scrolled_entry_editor_json_seed(json, scrolled_entry)
skip_i18n: true,
include_hidden_sections: true,
include_unused_additional_seed_data: true,
include_unused_file_reference_locations: true,
include_file_reference_locations: true,
include_theme_translations: true)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ def seed_html(entry, **seed_options)
seed_options: {
skip_collections: true,
include_unused_additional_seed_data: true,
include_unused_file_reference_locations: true,
include_theme_translations: true,
**seed_options
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,30 @@ def scrolled_entry_json_seed(json, scrolled_entry, options = {})
cutoff: scrolled_entry.cutoff_mode_enabled_for?(request))
widgets = scrolled_entry.resolve_widgets(insert_point: :react)
entry_config = Pageflow.config_for(scrolled_entry)
file_reference_locations = EntryFileReferenceLocations.new(entry_config)

json.partial!('pageflow_scrolled/entry_json_seed/entry',
entry: scrolled_entry,
entry_config:,
content:,
file_reference_locations: EntryFileReferenceLocations.new(
entry_config,
content.content_elements,
include_unused: options[:include_unused_file_reference_locations]
file_reference_locations:,
referenced_files: scrolled_entry_json_seed_referenced_files(
scrolled_entry, entry_config, content, file_reference_locations
),
widgets:,
options:)
end

private

def scrolled_entry_json_seed_referenced_files(scrolled_entry, entry_config,
content, locations)
return unless entry_config.features.enabled?('file_rights_from_references')

ReferencedFiles.new(scrolled_entry,
sections: content.sections,
content_elements: content.content_elements,
locations:)
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def valid_links

def links
@configurations.each_with_object([]) do |configuration, result|
each_href(configuration) do |href|
ConfigurationHrefs.each(configuration) do |href|
entry_id = to_id(href['entry'])
next unless entry_id

Expand All @@ -41,16 +41,6 @@ def links
end
end

def each_href(value, &block)
case value
when Hash
yield value['href'] if value['href'].is_a?(Hash)
value.each_value { |item| each_href(item, &block) }
when Array
value.each { |item| each_href(item, &block) }
end
end

def to_id(value)
id = Integer(value, exception: false)
id if id&.positive?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ json.config do
config_file_model_types_seed(json, entry_config)
end

json.file_reference_locations do
json.content_elements file_reference_locations.content_element_locations
json.sections file_reference_locations.section_locations
json.entry file_reference_locations.entry_locations
if options[:include_file_reference_locations]
json.file_reference_locations do
json.content_elements file_reference_locations.content_element_locations
json.sections file_reference_locations.section_locations
json.entry file_reference_locations.entry_locations
end
end

json.pretty_url pretty_entry_url(entry)
Expand Down Expand Up @@ -101,6 +103,6 @@ unless options[:skip_collections]
end
end

files_json_seed(json, entry) unless options[:skip_files]
files_json_seed(json, entry, referenced_files:) unless options[:skip_files]
end
end
10 changes: 10 additions & 0 deletions entry_types/scrolled/config/locales/de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,9 @@ de:
general: Diagramm
externalLinkList:
add: Hinzufügen
configuration_places:
itemLinks: Link des Eintrags
itemTexts: Link im Text des Eintrags
attributes:
thumbnail:
inline_help: Dem Link zugeordnertes Bild für die Darstellung im Beitrag.
Expand Down Expand Up @@ -620,6 +623,8 @@ de:
Zeigt die aktuelle Bildposition und die Gesamtzahl der
Bilder an, um die Navigation durch die Galerie zu
erleichtern.
configuration_places:
captions: Link in Bildunterschrift
description: Eine Serie von Bildern zum Durchblättern
items:
add: Hinzufügen
Expand Down Expand Up @@ -887,6 +892,8 @@ de:
unmutedText:
label: "'Ton aktiviert' Text"
textBlock:
configuration_places:
link: 'Link „%{text}“'
attributes:
color:
label: Farbe
Expand Down Expand Up @@ -1016,6 +1023,9 @@ de:
description: Interaktives Panorama aus Bild mit rektangularer Projektion
name: 360°-Bild
hotspots:
configuration_places:
tooltipLinks: Tooltip-Link
tooltipTexts: Link im Tooltip-Text
edit_area:
back: Zurück
confirm_destroy: Soll der Hotspot-Bereich wirklich gelöscht werden?
Expand Down
10 changes: 10 additions & 0 deletions entry_types/scrolled/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,9 @@ en:
general: Chart
externalLinkList:
add: Add
configuration_places:
itemLinks: Item link
itemTexts: Link in item text
attributes:
thumbnail:
inline_help: Link thumbnail image for display in entry.
Expand Down Expand Up @@ -606,6 +609,8 @@ en:
Displays the current image position and the total
number of images to make navigating the gallery
easier.
configuration_places:
captions: Link in caption
description: A series of images to flip through
items:
add: Add
Expand Down Expand Up @@ -871,6 +876,8 @@ en:
unmutedText:
label: "Unmuted Text"
textBlock:
configuration_places:
link: 'Link "%{text}"'
attributes:
color:
label: Color
Expand Down Expand Up @@ -1000,6 +1007,9 @@ en:
description: Interactive panorama using an image with rectangular projection
name: 360° Image
hotspots:
configuration_places:
tooltipLinks: Tooltip link
tooltipTexts: Link in tooltip text
edit_area:
back: Back
confirm_destroy: Are you sure you want to delete this area?
Expand Down
44 changes: 21 additions & 23 deletions entry_types/scrolled/doc/internal/configuration_schemas.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@ schema file and follow the terms below through both languages.
`{model: 'section'}` and `{model: 'entry'}`. Declared as `x-subject`.
- **File reference location** — a place in a configuration where a file
*can* be referenced. Declared by `x-fileCollection`, flattened by
`FileReferenceLocations` and shipped in the entry seed as
`FileReferenceLocations` and shipped in the editor's entry seed as
`fileReferenceLocations`.
- **File reference** — a location resolved against actual configuration
data, as `{subject, path, active}`. Produced by
`collectFileReferences`, indexed by file by
`collectEntryFileReferences`.
- **Referenced file** — a file some configuration points at. Not the
same as a *used* file, see below.
`collectFileReferences` and `FileReferences`, indexed by file by
`watchFileReferences` in the editor and by `ReferencedFiles` on the
server. Links to files (`href: {file: {permaId,
collectionName}}`) are found anywhere in a configuration, in rich
text and link properties alike, and need no location.
- **Referenced file** — a file some active reference points at. Not the
same as a *used* file, see below. Flagged as `isReferenced` in entry
state.
- **Configuration place** — the editor's presentation of a reference,
as `{label, detail, pictogram, select}`. Built by
`getConfigurationPlace(path)` on the referencing model.
Expand Down Expand Up @@ -74,21 +78,21 @@ open, yet credits must list those files whether or not a visitor opened
them. Render time collection under-reports exactly the files that are
easiest to forget.

### Computing the answer on the server
### Computing the editor's answer on the server

A server computed list of referenced files is a cache whose
invalidation trigger is "any configuration change" - and the editor is
where configuration changes. So the seed carries locations and the
algorithm ships in the bundle. Server side rendering is unaffected,
since the same JavaScript runs in Node with the seed in hand.

Bundling the schemas into the JavaScript packages instead would undo
the seed's pruning: the seed already carries only the content element
types an entry uses, so an entry using five of thirty types pays for
five, while a bundle import pays for all of them in every entry and
grows with every plugin pack. The editor is the exception and receives
all types, since content elements can be added there without reloading
the seed.
where configuration changes. So the editor seed carries locations and
the editor computes references itself, rescanning only the subject
whose configuration changed, and passes `is_referenced` to the preview
with the other file attributes. Published revisions never change, so
their seed carries `isReferenced` flags computed by `ReferencedFiles`
instead of locations. Both sides walk configurations with the same
algorithm, kept aligned by `spec/fixtures/file_references.json`.

Bundling the schemas into the JavaScript packages instead would make
every published entry pay for them, although only the editor reads
them, and would grow with every plugin pack.

### Structured references in the data

Expand Down Expand Up @@ -126,9 +130,3 @@ which requires the schema.
another file (text tracks belonging to their parent video) and file
configurations (video poster images). Each produces a false
"unreferenced" verdict on its own.

* **The attribute mapping wants to exist twice.**
`collectEntryFileReferences` takes entry state collections rather
than Backbone models so that the snake cased to camel cased mapping
is shared with the preview. When it existed twice it drifted - the
share image reached the published entry before it reached the editor.
25 changes: 25 additions & 0 deletions entry_types/scrolled/lib/pageflow_scrolled/configuration_hrefs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module PageflowScrolled
# Find link targets in configurations, both in slate link nodes and
# in link objects of content elements.
#
# @api private
module ConfigurationHrefs
class << self
def each(value, path = [], &block)
case value
when Hash
each_in_hash(value, path, &block)
when Array
value.each_with_index { |item, index| each(item, path + [index], &block) }
end
end

private

def each_in_hash(hash, path, &block)
yield hash['href'], path if hash['href'].is_a?(Hash)
hash.each { |key, item| each(item, path + [key], &block) }
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,32 @@ module PageflowScrolled
#
# @api private
class EntryFileReferenceLocations
def initialize(entry_config, content_elements, include_unused: false)
def initialize(entry_config)
@entry_config = entry_config
@content_elements = content_elements
@include_unused = include_unused
@content_element_locations = {}
end

def content_element_locations
content_element_type_names.each_with_object({}) do |type_name, result|
schema = schemas.find(model: 'contentElement', type_name:)

if schema
result[type_name] = locations.for(schema)
else
log_missing_schema(type_name)
end
schemas.type_names(model: 'contentElement').index_with do |type_name|
content_element_locations_for(type_name)
end
end

def content_element_locations_for(type_name)
return @content_element_locations[type_name] if @content_element_locations.key?(type_name)

schema = schemas.find(model: 'contentElement', type_name:)
log_missing_schema(type_name) unless schema

@content_element_locations[type_name] = schema ? locations.for(schema) : []
end

def section_locations
locations_for(model: 'section')
@section_locations ||= locations_for(model: 'section')
end

def entry_locations
locations_for(model: 'entry')
@entry_locations ||= locations_for(model: 'entry')
end

private
Expand All @@ -44,16 +46,6 @@ def locations_for(model:)
locations.for(schema)
end

# Content elements of any type can be added in the editor without
# reloading the seed.
def content_element_type_names
if @include_unused
schemas.type_names(model: 'contentElement')
else
@content_elements.map(&:type_name).uniq
end
end

def log_missing_schema(type_name)
return unless @entry_config.features.enabled?('file_rights_from_references')

Expand Down
Loading
Loading