diff --git a/app/controllers/pageflow/entries_controller.rb b/app/controllers/pageflow/entries_controller.rb
index a68a079279..aca03922da 100644
--- a/app/controllers/pageflow/entries_controller.rb
+++ b/app/controllers/pageflow/entries_controller.rb
@@ -119,7 +119,10 @@ def entry_redirect(entry)
end
def delegate_to_entry_type_frontend_app!(entry, override_status: nil)
- EntriesControllerEnvHelper.add_entry_info_to_env(request.env, entry:, mode: :published)
+ EntriesControllerEnvHelper.add_entry_info_to_env(request.env,
+ entry:,
+ mode: :published,
+ embed: params[:embed].present?)
delegate_to_rack_app!(entry.entry_type.frontend_app) do |result|
status, headers, body = result
diff --git a/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb b/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb
index dce013eef3..a62fdbaaab 100644
--- a/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb
+++ b/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb
@@ -21,7 +21,11 @@ def show
render(
locals: {
entry:,
- widget_scope: get_entry_mode_from_env
+ widget_scope: get_entry_mode_from_env,
+ seed_options: {
+ embed: get_embed_from_env,
+ origin_url: request.original_url
+ }
}
)
end
diff --git a/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb b/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb
index e7f4b1349e..362814f2a5 100644
--- a/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb
+++ b/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb
@@ -4,9 +4,9 @@ module ReactServerSideRenderingHelper
include Pageflow::RenderJsonHelper
include PageflowScrolled::EntryJsonSeedHelper
- def render_scrolled_entry(entry)
+ def render_scrolled_entry(entry, options = {})
seed_json = render_json do |json|
- scrolled_entry_json_seed(json, entry)
+ scrolled_entry_json_seed(json, entry, options)
end
ReactServerSideRenderingHelper.renderer.render('Root', "{seed: #{seed_json}}", {})
diff --git a/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb b/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb
index e3c1b04c40..ab1cab5b01 100644
--- a/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb
+++ b/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb
@@ -35,7 +35,7 @@
<% end %>
- <% ssr_html = local_assigns[:skip_ssr] ? '' : render_scrolled_entry(entry) %>
+ <% ssr_html = local_assigns[:skip_ssr] ? '' : render_scrolled_entry(entry, local_assigns[:seed_options] || {}) %>
<% if !local_assigns[:skip_ssr] && (params[:frontend] == 'v2' || entry.feature_state('frontend_v2')) %>
<%= generated_media_queries_tags_for(ssr_html) %>
diff --git a/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder b/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder
index a0d3000505..c4c369b64b 100644
--- a/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder
+++ b/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder
@@ -48,6 +48,8 @@ json.config do
)
json.cut_off entry.cutoff_mode_enabled_for?(request)
+ json.embed options.fetch(:embed, false)
+ json.origin_url options[:origin_url] if options[:origin_url]
end
unless options[:skip_i18n]
diff --git a/entry_types/scrolled/package/spec/entryState/embedOriginUrl-spec.js b/entry_types/scrolled/package/spec/entryState/embedOriginUrl-spec.js
new file mode 100644
index 0000000000..a18449faf0
--- /dev/null
+++ b/entry_types/scrolled/package/spec/entryState/embedOriginUrl-spec.js
@@ -0,0 +1,43 @@
+import {useEmbedOriginUrl} from 'entryState';
+
+import {renderHookInEntry} from 'support';
+
+describe('useEmbedOriginUrl', () => {
+ it('returns undefined when embed is false', () => {
+ const {result} = renderHookInEntry(
+ () => useEmbedOriginUrl(), {
+ seed: {
+ embed: false,
+ originUrl: 'https://example.com/my-entry'
+ }
+ }
+ );
+
+ expect(result.current).toBeUndefined();
+ });
+
+ it('returns undefined when embed is true but originUrl not set', () => {
+ const {result} = renderHookInEntry(
+ () => useEmbedOriginUrl(), {
+ seed: {
+ embed: true
+ }
+ }
+ );
+
+ expect(result.current).toBeUndefined();
+ });
+
+ it('returns originUrl when embed is true and originUrl is set', () => {
+ const {result} = renderHookInEntry(
+ () => useEmbedOriginUrl(), {
+ seed: {
+ embed: true,
+ originUrl: 'https://example.com/my-entry'
+ }
+ }
+ );
+
+ expect(result.current).toEqual('https://example.com/my-entry');
+ });
+});
diff --git a/entry_types/scrolled/package/spec/frontend/EditableLink-spec.js b/entry_types/scrolled/package/spec/frontend/EditableLink-spec.js
index 6f8248e17d..a16a9e611e 100644
--- a/entry_types/scrolled/package/spec/frontend/EditableLink-spec.js
+++ b/entry_types/scrolled/package/spec/frontend/EditableLink-spec.js
@@ -2,91 +2,27 @@ import React from 'react';
import {EditableLink} from 'frontend';
-import {render} from '@testing-library/react';
import {renderInEntry} from 'support';
import '@testing-library/jest-dom/extend-expect'
+// Link behavior is tested in Link-spec.js.
+// These tests verify EditableLink correctly passes props to Link.
+
describe('EditableLink', () => {
it('renders link', () => {
- const {getByRole} = render(
+ const {getByRole} = renderInEntry(
Some link
);
expect(getByRole('link')).toHaveTextContent('Some link')
expect(getByRole('link')).toHaveAttribute('href', 'https://example.com')
- expect(getByRole('link')).not.toHaveAttribute('target')
- expect(getByRole('link')).not.toHaveAttribute('rel')
});
it('supports className', () => {
- const {getByRole} = render(
+ const {getByRole} = renderInEntry(
Some link
);
expect(getByRole('link')).toHaveClass('custom')
});
-
- it('supports rendering link with target blank', () => {
- const {getByRole} = render(
- Some link
- );
-
- expect(getByRole('link')).toHaveTextContent('Some link')
- expect(getByRole('link')).toHaveAttribute('target', '_blank')
- expect(getByRole('link')).toHaveAttribute('rel', 'noopener noreferrer')
- });
-
- it('supports rendering internal chapter links', () => {
- const seed = {
- chapters: [{id: 1, permaId: 10, configuration: {title: 'The Intro'}}]
- };
-
- const {getByRole} = renderInEntry(
- Some link,
- {seed}
- );
-
- expect(getByRole('link')).toHaveTextContent('Some link')
- expect(getByRole('link')).toHaveAttribute('href', '#the-intro')
- expect(getByRole('link')).not.toHaveAttribute('target')
- expect(getByRole('link')).not.toHaveAttribute('rel')
- });
-
- it('supports rendering internal section links', () => {
- const seed = {
- sections: [{id: 1, permaId: 10}]
- };
-
- const {getByRole} = renderInEntry(
- Some link,
- {seed}
- );
-
- expect(getByRole('link')).toHaveTextContent('Some link')
- expect(getByRole('link')).toHaveAttribute('href', '#section-10')
- expect(getByRole('link')).not.toHaveAttribute('target')
- expect(getByRole('link')).not.toHaveAttribute('rel')
- });
-
- it('supports rendering file links', () => {
- const seed = {
- imageFileUrlTemplates: {
- original: ':id_partition/original/:basename.:extension'
- },
- sections: [{id: 1, permaId: 10}],
- imageFiles: [{id: 1, permaId: 100, displayName: 'Some File.jpg'}]
- };
-
- const {getByRole} = renderInEntry(
-
- Some link
- ,
- {seed}
- );
-
- expect(getByRole('link')).toHaveTextContent('Some link')
- expect(getByRole('link')).toHaveAttribute('href', '000/000/001/original/image.jpg?download=Some%20File.jpg')
- expect(getByRole('link')).toHaveAttribute('target', '_blank')
- expect(getByRole('link')).toHaveAttribute('rel', 'noopener noreferrer')
- });
});
diff --git a/entry_types/scrolled/package/spec/frontend/EditableTable-spec.js b/entry_types/scrolled/package/spec/frontend/EditableTable-spec.js
index 3b8a6e597f..32411b32b7 100644
--- a/entry_types/scrolled/package/spec/frontend/EditableTable-spec.js
+++ b/entry_types/scrolled/package/spec/frontend/EditableTable-spec.js
@@ -4,6 +4,7 @@ import {EditableTable} from 'frontend';
import * as phoneLayout from 'frontend/usePhoneLayout';
import {render, screen} from '@testing-library/react';
+import {renderInEntry} from 'support';
import '@testing-library/jest-dom/extend-expect'
describe('EditableTable', () => {
@@ -74,7 +75,7 @@ describe('EditableTable', () => {
]
}];
- const {getByRole} = render();
+ const {getByRole} = renderInEntry();
expect(getByRole('link')).toHaveTextContent('here')
expect(getByRole('link')).toHaveAttribute('href', 'https://example.com')
@@ -111,7 +112,7 @@ describe('EditableTable', () => {
]
}];
- const {getByRole} = render();
+ const {getByRole} = renderInEntry();
expect(getByRole('link')).toHaveTextContent('here')
expect(getByRole('link')).toHaveAttribute('target', '_blank')
diff --git a/entry_types/scrolled/package/spec/frontend/EditableText-spec.js b/entry_types/scrolled/package/spec/frontend/EditableText-spec.js
index 4f7f285a22..fc35025ae4 100644
--- a/entry_types/scrolled/package/spec/frontend/EditableText-spec.js
+++ b/entry_types/scrolled/package/spec/frontend/EditableText-spec.js
@@ -97,6 +97,9 @@ describe('EditableText', () => {
expect(getByRole('listitem')).toHaveTextContent('List item')
});
+ // Link behavior is tested in Link-spec.js.
+ // These tests verify EditableText correctly renders links via Link.
+
it('renders links', () => {
const value = [{
type: 'paragraph',
@@ -113,37 +116,11 @@ describe('EditableText', () => {
]
}]
- const {getByRole} = render();
+ const {getByRole} = renderInEntry();
expect(getByRole('link')).toHaveTextContent('here')
expect(getByRole('link')).toHaveAttribute('href', 'https://example.com')
expect(getByRole('link')).toHaveClass('typography-contentLink')
- expect(getByRole('link')).not.toHaveAttribute('target')
- expect(getByRole('link')).not.toHaveAttribute('rel')
- });
-
- it('supports rendering links with target blank', () => {
- const value = [{
- type: 'paragraph',
- children: [
- {text: 'Find more '},
- {
- type: 'link',
- href: 'https://example.com',
- openInNewTab: true,
- children: [
- {text: 'here'}
- ]
- },
- {text: '.'}
- ]
- }]
-
- const {getByRole} = render();
-
- expect(getByRole('link')).toHaveTextContent('here')
- expect(getByRole('link')).toHaveAttribute('target', '_blank')
- expect(getByRole('link')).toHaveAttribute('rel', 'noopener noreferrer')
});
it('supports rendering internal chapter links', () => {
@@ -170,68 +147,6 @@ describe('EditableText', () => {
expect(getByRole('link')).toHaveTextContent('here')
expect(getByRole('link')).toHaveAttribute('href', '#the-intro')
expect(getByRole('link')).toHaveClass('typography-contentLink')
- expect(getByRole('link')).not.toHaveAttribute('target')
- expect(getByRole('link')).not.toHaveAttribute('rel')
- });
-
- it('supports rendering internal section links', () => {
- const value = [{
- type: 'paragraph',
- children: [
- {text: 'Find more '},
- {
- type: 'link',
- href: {section: 10},
- children: [
- {text: 'here'}
- ]
- },
- {text: '.'}
- ]
- }];
- const seed = {
- sections: [{id: 1, permaId: 10}]
- };
-
- const {getByRole} = renderInEntry(, {seed});
-
- expect(getByRole('link')).toHaveTextContent('here')
- expect(getByRole('link')).toHaveAttribute('href', '#section-10')
- expect(getByRole('link')).toHaveClass('typography-contentLink')
- expect(getByRole('link')).not.toHaveAttribute('target')
- expect(getByRole('link')).not.toHaveAttribute('rel')
- });
-
- it('supports rendering file links', () => {
- const value = [{
- type: 'paragraph',
- children: [
- {text: 'Find more '},
- {
- type: 'link',
- href: {file: {permaId: 100, collectionName: 'imageFiles'}},
- children: [
- {text: 'here'}
- ]
- },
- {text: '.'}
- ]
- }];
- const seed = {
- imageFileUrlTemplates: {
- original: ':id_partition/original/:basename.:extension'
- },
- sections: [{id: 1, permaId: 10}],
- imageFiles: [{id: 1, permaId: 100, displayName: 'MyImage.jpg'}]
- };
-
- const {getByRole} = renderInEntry(, {seed});
-
- expect(getByRole('link')).toHaveTextContent('here')
- expect(getByRole('link')).toHaveAttribute('href', '000/000/001/original/image.jpg?download=MyImage.jpg')
- expect(getByRole('link')).toHaveClass('typography-contentLink')
- expect(getByRole('link')).toHaveAttribute('target', '_blank')
- expect(getByRole('link')).toHaveAttribute('rel', 'noopener noreferrer')
});
it('renders zero width no break space in empty leafs to prevent empty paragraphs from collapsing', () => {
diff --git a/entry_types/scrolled/package/spec/frontend/Link-spec.js b/entry_types/scrolled/package/spec/frontend/Link-spec.js
new file mode 100644
index 0000000000..67e62a1875
--- /dev/null
+++ b/entry_types/scrolled/package/spec/frontend/Link-spec.js
@@ -0,0 +1,140 @@
+import {Link} from 'frontend/Link';
+
+import React from 'react';
+
+import {renderInEntry} from 'support';
+import '@testing-library/jest-dom/extend-expect';
+
+describe('Link', () => {
+ describe('with string href', () => {
+ it('does not set target by default', () => {
+ const {getByRole} = renderInEntry(
+ Click
+ );
+
+ expect(getByRole('link')).toHaveAttribute('href', 'http://example.com');
+ expect(getByRole('link')).not.toHaveAttribute('target');
+ });
+
+ it('sets target _blank when openInNewTab is true', () => {
+ const {getByRole} = renderInEntry(
+ Click
+ );
+
+ expect(getByRole('link')).toHaveAttribute('target', '_blank');
+ });
+
+ describe('in embed mode', () => {
+ it('sets target _top for external link', () => {
+ const {getByRole} = renderInEntry(
+ Click,
+ {
+ seed: {
+ embed: true,
+ originUrl: 'http://example.com/my-entry'
+ }
+ }
+ );
+
+ expect(getByRole('link')).toHaveAttribute('target', '_top');
+ });
+
+ it('does not set target for link starting with origin url', () => {
+ const {getByRole} = renderInEntry(
+ Click,
+ {
+ seed: {
+ embed: true,
+ originUrl: 'http://example.com/my-entry'
+ }
+ }
+ );
+
+ expect(getByRole('link')).not.toHaveAttribute('target');
+ });
+
+ it('does not set target for fragment-only link', () => {
+ const {getByRole} = renderInEntry(
+ Click,
+ {
+ seed: {
+ embed: true,
+ originUrl: 'http://example.com/my-entry'
+ }
+ }
+ );
+
+ expect(getByRole('link')).not.toHaveAttribute('target');
+ });
+
+ it('prefers openInNewTab over embed mode target', () => {
+ const {getByRole} = renderInEntry(
+ Click,
+ {
+ seed: {
+ embed: true,
+ originUrl: 'http://example.com/my-entry'
+ }
+ }
+ );
+
+ expect(getByRole('link')).toHaveAttribute('target', '_blank');
+ });
+ });
+ });
+
+ describe('with chapter href', () => {
+ it('renders link to chapter slug', () => {
+ const {getByRole} = renderInEntry(
+ Click,
+ {
+ seed: {
+ chapters: [{id: 1, permaId: 10, configuration: {title: 'The Intro'}}]
+ }
+ }
+ );
+
+ expect(getByRole('link')).toHaveAttribute('href', '#the-intro');
+ expect(getByRole('link')).not.toHaveAttribute('target');
+ });
+ });
+
+ describe('with section href', () => {
+ it('renders link to section anchor', () => {
+ const {getByRole} = renderInEntry(
+ Click,
+ {
+ seed: {
+ sections: [{id: 1, permaId: 10}]
+ }
+ }
+ );
+
+ expect(getByRole('link')).toHaveAttribute('href', '#section-10');
+ expect(getByRole('link')).not.toHaveAttribute('target');
+ });
+ });
+
+ describe('with file href', () => {
+ it('renders download link with target blank', () => {
+ const {getByRole} = renderInEntry(
+ Click,
+ {
+ seed: {
+ imageFileUrlTemplates: {
+ original: ':id_partition/original/:basename.:extension'
+ },
+ imageFiles: [{id: 1, permaId: 100, displayName: 'Some File.jpg'}]
+ }
+ }
+ );
+
+ expect(getByRole('link')).toHaveAttribute(
+ 'href',
+ '000/000/001/original/image.jpg?download=Some%20File.jpg'
+ );
+ expect(getByRole('link')).toHaveAttribute('target', '_blank');
+ expect(getByRole('link')).toHaveAttribute('rel', 'noopener noreferrer');
+ });
+ });
+});
diff --git a/entry_types/scrolled/package/src/entryState/embedOriginUrl.js b/entry_types/scrolled/package/src/entryState/embedOriginUrl.js
new file mode 100644
index 0000000000..5222c70364
--- /dev/null
+++ b/entry_types/scrolled/package/src/entryState/embedOriginUrl.js
@@ -0,0 +1,6 @@
+import {useEntryStateConfig} from "./EntryStateProvider";
+
+export function useEmbedOriginUrl() {
+ const config = useEntryStateConfig();
+ return config.embed ? config.originUrl : undefined;
+}
diff --git a/entry_types/scrolled/package/src/entryState/index.js b/entry_types/scrolled/package/src/entryState/index.js
index 2251a8aefb..18d6c47545 100644
--- a/entry_types/scrolled/package/src/entryState/index.js
+++ b/entry_types/scrolled/package/src/entryState/index.js
@@ -1,6 +1,7 @@
export {useAdditionalSeedData} from './additionalSeedData';
export {useContentElementConsentVendor} from './consentVendors';
export {useCutOff} from './cutoff';
+export {useEmbedOriginUrl} from './embedOriginUrl';
export {useShareProviders, useShareUrl} from './sharing';
export {useEntryTranslations} from './entryTranslations';
export {
diff --git a/entry_types/scrolled/package/src/frontend/Link.js b/entry_types/scrolled/package/src/frontend/Link.js
index 164870b782..ca1c14b9db 100644
--- a/entry_types/scrolled/package/src/frontend/Link.js
+++ b/entry_types/scrolled/package/src/frontend/Link.js
@@ -1,8 +1,10 @@
import React from 'react';
-import {useChapter, useDownloadableFile} from '../entryState';
+import {useChapter, useDownloadableFile, useEmbedOriginUrl} from '../entryState';
export function Link({attributes, children, href, openInNewTab}) {
+ const embedOriginUrl = useEmbedOriginUrl();
+
if (href?.chapter) {
return (
;
}
+
+function getTargetAttributes({href, openInNewTab, embedOriginUrl}) {
+ if (openInNewTab) {
+ return {target: '_blank', rel: 'noopener noreferrer'};
+ }
+
+ if (embedOriginUrl &&
+ typeof href === 'string' &&
+ !href.startsWith('#') &&
+ !href.startsWith(embedOriginUrl)) {
+ return {target: '_top'};
+ }
+
+ return {};
+}
diff --git a/entry_types/scrolled/package/src/testHelpers/normalizeSeed.js b/entry_types/scrolled/package/src/testHelpers/normalizeSeed.js
index 66f8bee139..c4ebf1a808 100644
--- a/entry_types/scrolled/package/src/testHelpers/normalizeSeed.js
+++ b/entry_types/scrolled/package/src/testHelpers/normalizeSeed.js
@@ -49,6 +49,8 @@ export function normalizeSeed({
consentVendors,
contentElementConsentVendors,
cutOff,
+ embed,
+ originUrl,
fileLicenses,
entryTranslations
} = {}) {
@@ -96,6 +98,8 @@ export function normalizeSeed({
consentVendors: consentVendors || [],
contentElementConsentVendors: contentElementConsentVendors || {},
cutOff,
+ embed,
+ originUrl,
fileLicenses: fileLicenses || {},
entryTranslations: entryTranslations || []
},
diff --git a/entry_types/scrolled/spec/controllers/pageflow_scrolled/entries_controller_spec.rb b/entry_types/scrolled/spec/controllers/pageflow_scrolled/entries_controller_spec.rb
index 720850e7fa..9939dcc17c 100644
--- a/entry_types/scrolled/spec/controllers/pageflow_scrolled/entries_controller_spec.rb
+++ b/entry_types/scrolled/spec/controllers/pageflow_scrolled/entries_controller_spec.rb
@@ -37,6 +37,31 @@ module PageflowScrolled
expect(response.body).to have_selector('figcaption', text: 'Some caption')
end
+ it 'server side renders external links with target top in embed mode' do
+ entry = create(:entry, :published, type_name: 'scrolled')
+ chapter = create(:scrolled_chapter, revision: entry.published_revision)
+ section = create(:section, chapter:)
+ create(:content_element,
+ section:,
+ type_name: 'textBlock',
+ configuration: {
+ value: [{
+ type: 'paragraph',
+ children: [
+ {
+ type: 'link',
+ href: 'https://example.com',
+ children: [{text: 'External link'}]
+ }
+ ]
+ }]
+ })
+
+ get_with_entry_env(:show, entry:, embed: true)
+
+ expect(response.body).to have_selector('a[href="https://example.com"][target="_top"]')
+ end
+
it 'renders generated media queries if frontend v2' do
entry = create(:entry, :published, type_name: 'scrolled')
@@ -150,6 +175,30 @@ module PageflowScrolled
expect(response.body).to have_selector('link[type="application/atom+xml"]',
visible: false)
end
+
+ it 'includes embed false in seed data by default' do
+ entry = create(:entry, :published, type_name: 'scrolled')
+
+ get_with_entry_env(:show, entry:)
+
+ expect(response.body).to include('"embed":false')
+ end
+
+ it 'includes embed true in seed data for embed requests' do
+ entry = create(:entry, :published, type_name: 'scrolled')
+
+ get_with_entry_env(:show, entry:, embed: true)
+
+ expect(response.body).to include('"embed":true')
+ end
+
+ it 'includes origin_url in seed data' do
+ entry = create(:entry, :published, type_name: 'scrolled')
+
+ get_with_entry_env(:show, entry:)
+
+ expect(response.body).to include('"originUrl":"http://test.host/test/entry"')
+ end
end
end
end
diff --git a/entry_types/scrolled/spec/helpers/pageflow_scrolled/entry_json_seed_helper_spec.rb b/entry_types/scrolled/spec/helpers/pageflow_scrolled/entry_json_seed_helper_spec.rb
index 6a8b169582..9ba604acb7 100644
--- a/entry_types/scrolled/spec/helpers/pageflow_scrolled/entry_json_seed_helper_spec.rb
+++ b/entry_types/scrolled/spec/helpers/pageflow_scrolled/entry_json_seed_helper_spec.rb
@@ -1408,6 +1408,46 @@ def render(helper, entry, options = {})
end
end
+ context 'embed' do
+ it 'renders false by default' do
+ entry = create(:published_entry,
+ type_name: 'scrolled')
+
+ result = render(helper, entry)
+
+ expect(result).to include_json(config: {embed: false})
+ end
+
+ it 'renders true when embed option is true' do
+ entry = create(:published_entry,
+ type_name: 'scrolled')
+
+ result = render(helper, entry, embed: true)
+
+ expect(result).to include_json(config: {embed: true})
+ end
+ end
+
+ context 'origin_url' do
+ it 'is not rendered by default' do
+ entry = create(:published_entry,
+ type_name: 'scrolled')
+
+ result = render(helper, entry)
+
+ expect(JSON.parse(result)['config']).not_to have_key('originUrl')
+ end
+
+ it 'renders origin_url when option is provided' do
+ entry = create(:published_entry,
+ type_name: 'scrolled')
+
+ result = render(helper, entry, origin_url: 'https://example.com/my-entry')
+
+ expect(result).to include_json(config: {originUrl: 'https://example.com/my-entry'})
+ end
+ end
+
context 'cutoff' do
it 'renders false by default' do
entry = create(:published_entry,
diff --git a/lib/pageflow/entries_controller_env_helper.rb b/lib/pageflow/entries_controller_env_helper.rb
index 4cbefced89..89a5e270b9 100644
--- a/lib/pageflow/entries_controller_env_helper.rb
+++ b/lib/pageflow/entries_controller_env_helper.rb
@@ -28,9 +28,19 @@ def get_entry_mode_from_env(env = request.env)
EntriesControllerEnvHelper.get_pageflow_hash(env)['entry_mode']
end
+ # Returns `true` if the entry is being rendered as an embed. The
+ # information will be placed in the request env by the Pageflow
+ # engine before delegating to the entry type's frontend app.
+ #
+ # Use {EntriesControllerTestHelper} to set up the request
+ # environment in controller tests.
+ def get_embed_from_env(env = request.env)
+ EntriesControllerEnvHelper.get_pageflow_hash(env)['embed']
+ end
+
# @api private
- def self.add_entry_info_to_env(env, entry:, mode: nil)
- env['pageflow'] = {'published_entry' => entry, 'entry_mode' => mode}
+ def self.add_entry_info_to_env(env, entry:, mode: nil, embed: false)
+ env['pageflow'] = {'published_entry' => entry, 'entry_mode' => mode, 'embed' => embed}
end
# @api private
diff --git a/spec/pageflow/entries_controller_env_helper_spec.rb b/spec/pageflow/entries_controller_env_helper_spec.rb
index a37e3c8f1d..337818a811 100644
--- a/spec/pageflow/entries_controller_env_helper_spec.rb
+++ b/spec/pageflow/entries_controller_env_helper_spec.rb
@@ -37,5 +37,23 @@ module Pageflow
}.to raise_error(/Use Pageflow::EntriesControllerTestHelper/)
end
end
+
+ describe '#get_embed_from_env' do
+ it 'reads embed from where add_entry_info_to_env puts it' do
+ env = {}
+ entry = build(:entry)
+
+ EntriesControllerEnvHelper.add_entry_info_to_env(env, entry:, embed: true)
+ result = EntriesControllerEnvHelper.get_embed_from_env(env)
+
+ expect(result).to be(true)
+ end
+
+ it 'fails with a helpful message when info is missing in env' do
+ expect {
+ EntriesControllerEnvHelper.get_embed_from_env({})
+ }.to raise_error(/Use Pageflow::EntriesControllerTestHelper/)
+ end
+ end
end
end
diff --git a/spec/requests/pageflow/entries_show_request_spec.rb b/spec/requests/pageflow/entries_show_request_spec.rb
index fbcd89a61d..9b1297fe2a 100644
--- a/spec/requests/pageflow/entries_show_request_spec.rb
+++ b/spec/requests/pageflow/entries_show_request_spec.rb
@@ -6,10 +6,11 @@ module Pageflow
lambda do |env|
entry = EntriesControllerEnvHelper.get_published_entry_from_env(env)
mode = EntriesControllerEnvHelper.get_entry_mode_from_env(env)
+ embed = EntriesControllerEnvHelper.get_embed_from_env(env)
['200',
{'Content-Type' => 'text/html'},
- ["#{entry.title} #{mode} rendered by entry type frontend app."]]
+ ["#{entry.title} #{mode} embed=#{embed} rendered by entry type frontend app."]]
end
end
@@ -59,7 +60,16 @@ module Pageflow
get(short_entry_url(entry))
expect(response.status).to eq(200)
- expect(response.body).to include('some-entry published rendered by entry type frontend app')
+ expect(response.body).to include('some-entry published embed=false rendered by entry type frontend app')
+ end
+
+ it 'passes embed=true for embed requests' do
+ entry = create(:entry, :published, type_name: 'test', title: 'some-entry')
+
+ get(entry_embed_url(entry))
+
+ expect(response.status).to eq(200)
+ expect(response.body).to include('some-entry published embed=true rendered by entry type frontend app')
end
it 'supports finding published entry based on permalink' do
@@ -79,7 +89,7 @@ module Pageflow
expect(response.status).to eq(200)
expect(response.body)
- .to include('some-entry published rendered by entry type frontend app')
+ .to include('some-entry published embed=false rendered by entry type frontend app')
end
it 'supports finding published entry based on permalink with directory' do
@@ -100,7 +110,7 @@ module Pageflow
expect(response.status).to eq(200)
expect(response.body)
- .to include('some-entry published rendered by entry type frontend app')
+ .to include('some-entry published embed=false rendered by entry type frontend app')
end
it 'redirects to renamed permalink' do
@@ -227,7 +237,7 @@ module Pageflow
get('http://my.example.com/non-existent-entry')
expect(response.status).to eq(404)
- expect(response.body).to include('Custom 404 published rendered by entry type frontend app')
+ expect(response.body).to include('Custom 404 published embed=false rendered by entry type frontend app')
end
it 'falls back to default 404 when site has no custom_404_entry' do
diff --git a/spec/support/pageflow/entries_controller_test_helper.rb b/spec/support/pageflow/entries_controller_test_helper.rb
index e8eed0d380..6197992f37 100644
--- a/spec/support/pageflow/entries_controller_test_helper.rb
+++ b/spec/support/pageflow/entries_controller_test_helper.rb
@@ -32,7 +32,10 @@ module EntriesControllerTestHelper
#
# @param mode [:published|:preview] Whether to render the
# published revision or the draft.
- def get_with_entry_env(action, entry:, mode: :published, params: {})
+ #
+ # @param embed [Boolean] Whether the entry is being rendered as an
+ # embed.
+ def get_with_entry_env(action, entry:, mode: :published, embed: false, params: {})
revision =
if mode == :published
entry.published_revision
@@ -43,7 +46,8 @@ def get_with_entry_env(action, entry:, mode: :published, params: {})
published_entry = PublishedEntry.new(entry, revision)
EntriesControllerEnvHelper.add_entry_info_to_env(request.env,
entry: published_entry,
- mode:)
+ mode:,
+ embed:)
get(action, params: {**params})
end
end