Skip to content

Commit dfb1e8b

Browse files
authored
Merge pull request #2331 from tf/target-top
Add target top to external links in embed mode
2 parents 2911a65 + b7b4bf2 commit dfb1e8b

File tree

20 files changed

+379
-178
lines changed

20 files changed

+379
-178
lines changed

app/controllers/pageflow/entries_controller.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,10 @@ def entry_redirect(entry)
119119
end
120120

121121
def delegate_to_entry_type_frontend_app!(entry, override_status: nil)
122-
EntriesControllerEnvHelper.add_entry_info_to_env(request.env, entry:, mode: :published)
122+
EntriesControllerEnvHelper.add_entry_info_to_env(request.env,
123+
entry:,
124+
mode: :published,
125+
embed: params[:embed].present?)
123126

124127
delegate_to_rack_app!(entry.entry_type.frontend_app) do |result|
125128
status, headers, body = result

entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ def show
2121
render(
2222
locals: {
2323
entry:,
24-
widget_scope: get_entry_mode_from_env
24+
widget_scope: get_entry_mode_from_env,
25+
seed_options: {
26+
embed: get_embed_from_env,
27+
origin_url: request.original_url
28+
}
2529
}
2630
)
2731
end

entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ module ReactServerSideRenderingHelper
44
include Pageflow::RenderJsonHelper
55
include PageflowScrolled::EntryJsonSeedHelper
66

7-
def render_scrolled_entry(entry)
7+
def render_scrolled_entry(entry, options = {})
88
seed_json = render_json do |json|
9-
scrolled_entry_json_seed(json, entry)
9+
scrolled_entry_json_seed(json, entry, options)
1010
end
1111

1212
ReactServerSideRenderingHelper.renderer.render('Root', "{seed: #{seed_json}}", {})

entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
</script>
3636
<% end %>
3737

38-
<% ssr_html = local_assigns[:skip_ssr] ? '' : render_scrolled_entry(entry) %>
38+
<% ssr_html = local_assigns[:skip_ssr] ? '' : render_scrolled_entry(entry, local_assigns[:seed_options] || {}) %>
3939

4040
<% if !local_assigns[:skip_ssr] && (params[:frontend] == 'v2' || entry.feature_state('frontend_v2')) %>
4141
<%= generated_media_queries_tags_for(ssr_html) %>

entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ json.config do
4848
)
4949

5050
json.cut_off entry.cutoff_mode_enabled_for?(request)
51+
json.embed options.fetch(:embed, false)
52+
json.origin_url options[:origin_url] if options[:origin_url]
5153
end
5254

5355
unless options[:skip_i18n]
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {useEmbedOriginUrl} from 'entryState';
2+
3+
import {renderHookInEntry} from 'support';
4+
5+
describe('useEmbedOriginUrl', () => {
6+
it('returns undefined when embed is false', () => {
7+
const {result} = renderHookInEntry(
8+
() => useEmbedOriginUrl(), {
9+
seed: {
10+
embed: false,
11+
originUrl: 'https://example.com/my-entry'
12+
}
13+
}
14+
);
15+
16+
expect(result.current).toBeUndefined();
17+
});
18+
19+
it('returns undefined when embed is true but originUrl not set', () => {
20+
const {result} = renderHookInEntry(
21+
() => useEmbedOriginUrl(), {
22+
seed: {
23+
embed: true
24+
}
25+
}
26+
);
27+
28+
expect(result.current).toBeUndefined();
29+
});
30+
31+
it('returns originUrl when embed is true and originUrl is set', () => {
32+
const {result} = renderHookInEntry(
33+
() => useEmbedOriginUrl(), {
34+
seed: {
35+
embed: true,
36+
originUrl: 'https://example.com/my-entry'
37+
}
38+
}
39+
);
40+
41+
expect(result.current).toEqual('https://example.com/my-entry');
42+
});
43+
});

entry_types/scrolled/package/spec/frontend/EditableLink-spec.js

Lines changed: 5 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,91 +2,27 @@ import React from 'react';
22

33
import {EditableLink} from 'frontend';
44

5-
import {render} from '@testing-library/react';
65
import {renderInEntry} from 'support';
76
import '@testing-library/jest-dom/extend-expect'
87

8+
// Link behavior is tested in Link-spec.js.
9+
// These tests verify EditableLink correctly passes props to Link.
10+
911
describe('EditableLink', () => {
1012
it('renders link', () => {
11-
const {getByRole} = render(
13+
const {getByRole} = renderInEntry(
1214
<EditableLink href="https://example.com">Some link</EditableLink>
1315
);
1416

1517
expect(getByRole('link')).toHaveTextContent('Some link')
1618
expect(getByRole('link')).toHaveAttribute('href', 'https://example.com')
17-
expect(getByRole('link')).not.toHaveAttribute('target')
18-
expect(getByRole('link')).not.toHaveAttribute('rel')
1919
});
2020

2121
it('supports className', () => {
22-
const {getByRole} = render(
22+
const {getByRole} = renderInEntry(
2323
<EditableLink className="custom" href="https://example.com">Some link</EditableLink>
2424
);
2525

2626
expect(getByRole('link')).toHaveClass('custom')
2727
});
28-
29-
it('supports rendering link with target blank', () => {
30-
const {getByRole} = render(
31-
<EditableLink href="https://example.com" openInNewTab>Some link</EditableLink>
32-
);
33-
34-
expect(getByRole('link')).toHaveTextContent('Some link')
35-
expect(getByRole('link')).toHaveAttribute('target', '_blank')
36-
expect(getByRole('link')).toHaveAttribute('rel', 'noopener noreferrer')
37-
});
38-
39-
it('supports rendering internal chapter links', () => {
40-
const seed = {
41-
chapters: [{id: 1, permaId: 10, configuration: {title: 'The Intro'}}]
42-
};
43-
44-
const {getByRole} = renderInEntry(
45-
<EditableLink href={{chapter: 10}}>Some link</EditableLink>,
46-
{seed}
47-
);
48-
49-
expect(getByRole('link')).toHaveTextContent('Some link')
50-
expect(getByRole('link')).toHaveAttribute('href', '#the-intro')
51-
expect(getByRole('link')).not.toHaveAttribute('target')
52-
expect(getByRole('link')).not.toHaveAttribute('rel')
53-
});
54-
55-
it('supports rendering internal section links', () => {
56-
const seed = {
57-
sections: [{id: 1, permaId: 10}]
58-
};
59-
60-
const {getByRole} = renderInEntry(
61-
<EditableLink href={{section: 10}}>Some link</EditableLink>,
62-
{seed}
63-
);
64-
65-
expect(getByRole('link')).toHaveTextContent('Some link')
66-
expect(getByRole('link')).toHaveAttribute('href', '#section-10')
67-
expect(getByRole('link')).not.toHaveAttribute('target')
68-
expect(getByRole('link')).not.toHaveAttribute('rel')
69-
});
70-
71-
it('supports rendering file links', () => {
72-
const seed = {
73-
imageFileUrlTemplates: {
74-
original: ':id_partition/original/:basename.:extension'
75-
},
76-
sections: [{id: 1, permaId: 10}],
77-
imageFiles: [{id: 1, permaId: 100, displayName: 'Some File.jpg'}]
78-
};
79-
80-
const {getByRole} = renderInEntry(
81-
<EditableLink href={{file: {permaId: 100, collectionName: 'imageFiles'}}}>
82-
Some link
83-
</EditableLink>,
84-
{seed}
85-
);
86-
87-
expect(getByRole('link')).toHaveTextContent('Some link')
88-
expect(getByRole('link')).toHaveAttribute('href', '000/000/001/original/image.jpg?download=Some%20File.jpg')
89-
expect(getByRole('link')).toHaveAttribute('target', '_blank')
90-
expect(getByRole('link')).toHaveAttribute('rel', 'noopener noreferrer')
91-
});
9228
});

entry_types/scrolled/package/spec/frontend/EditableTable-spec.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {EditableTable} from 'frontend';
44
import * as phoneLayout from 'frontend/usePhoneLayout';
55

66
import {render, screen} from '@testing-library/react';
7+
import {renderInEntry} from 'support';
78
import '@testing-library/jest-dom/extend-expect'
89

910
describe('EditableTable', () => {
@@ -74,7 +75,7 @@ describe('EditableTable', () => {
7475
]
7576
}];
7677

77-
const {getByRole} = render(<EditableTable value={value} />);
78+
const {getByRole} = renderInEntry(<EditableTable value={value} />);
7879

7980
expect(getByRole('link')).toHaveTextContent('here')
8081
expect(getByRole('link')).toHaveAttribute('href', 'https://example.com')
@@ -111,7 +112,7 @@ describe('EditableTable', () => {
111112
]
112113
}];
113114

114-
const {getByRole} = render(<EditableTable value={value} />);
115+
const {getByRole} = renderInEntry(<EditableTable value={value} />);
115116

116117
expect(getByRole('link')).toHaveTextContent('here')
117118
expect(getByRole('link')).toHaveAttribute('target', '_blank')

entry_types/scrolled/package/spec/frontend/EditableText-spec.js

Lines changed: 4 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ describe('EditableText', () => {
9797
expect(getByRole('listitem')).toHaveTextContent('List item')
9898
});
9999

100+
// Link behavior is tested in Link-spec.js.
101+
// These tests verify EditableText correctly renders links via Link.
102+
100103
it('renders links', () => {
101104
const value = [{
102105
type: 'paragraph',
@@ -113,37 +116,11 @@ describe('EditableText', () => {
113116
]
114117
}]
115118

116-
const {getByRole} = render(<EditableText value={value} />);
119+
const {getByRole} = renderInEntry(<EditableText value={value} />);
117120

118121
expect(getByRole('link')).toHaveTextContent('here')
119122
expect(getByRole('link')).toHaveAttribute('href', 'https://example.com')
120123
expect(getByRole('link')).toHaveClass('typography-contentLink')
121-
expect(getByRole('link')).not.toHaveAttribute('target')
122-
expect(getByRole('link')).not.toHaveAttribute('rel')
123-
});
124-
125-
it('supports rendering links with target blank', () => {
126-
const value = [{
127-
type: 'paragraph',
128-
children: [
129-
{text: 'Find more '},
130-
{
131-
type: 'link',
132-
href: 'https://example.com',
133-
openInNewTab: true,
134-
children: [
135-
{text: 'here'}
136-
]
137-
},
138-
{text: '.'}
139-
]
140-
}]
141-
142-
const {getByRole} = render(<EditableText value={value} />);
143-
144-
expect(getByRole('link')).toHaveTextContent('here')
145-
expect(getByRole('link')).toHaveAttribute('target', '_blank')
146-
expect(getByRole('link')).toHaveAttribute('rel', 'noopener noreferrer')
147124
});
148125

149126
it('supports rendering internal chapter links', () => {
@@ -170,68 +147,6 @@ describe('EditableText', () => {
170147
expect(getByRole('link')).toHaveTextContent('here')
171148
expect(getByRole('link')).toHaveAttribute('href', '#the-intro')
172149
expect(getByRole('link')).toHaveClass('typography-contentLink')
173-
expect(getByRole('link')).not.toHaveAttribute('target')
174-
expect(getByRole('link')).not.toHaveAttribute('rel')
175-
});
176-
177-
it('supports rendering internal section links', () => {
178-
const value = [{
179-
type: 'paragraph',
180-
children: [
181-
{text: 'Find more '},
182-
{
183-
type: 'link',
184-
href: {section: 10},
185-
children: [
186-
{text: 'here'}
187-
]
188-
},
189-
{text: '.'}
190-
]
191-
}];
192-
const seed = {
193-
sections: [{id: 1, permaId: 10}]
194-
};
195-
196-
const {getByRole} = renderInEntry(<EditableText value={value} />, {seed});
197-
198-
expect(getByRole('link')).toHaveTextContent('here')
199-
expect(getByRole('link')).toHaveAttribute('href', '#section-10')
200-
expect(getByRole('link')).toHaveClass('typography-contentLink')
201-
expect(getByRole('link')).not.toHaveAttribute('target')
202-
expect(getByRole('link')).not.toHaveAttribute('rel')
203-
});
204-
205-
it('supports rendering file links', () => {
206-
const value = [{
207-
type: 'paragraph',
208-
children: [
209-
{text: 'Find more '},
210-
{
211-
type: 'link',
212-
href: {file: {permaId: 100, collectionName: 'imageFiles'}},
213-
children: [
214-
{text: 'here'}
215-
]
216-
},
217-
{text: '.'}
218-
]
219-
}];
220-
const seed = {
221-
imageFileUrlTemplates: {
222-
original: ':id_partition/original/:basename.:extension'
223-
},
224-
sections: [{id: 1, permaId: 10}],
225-
imageFiles: [{id: 1, permaId: 100, displayName: 'MyImage.jpg'}]
226-
};
227-
228-
const {getByRole} = renderInEntry(<EditableText value={value} />, {seed});
229-
230-
expect(getByRole('link')).toHaveTextContent('here')
231-
expect(getByRole('link')).toHaveAttribute('href', '000/000/001/original/image.jpg?download=MyImage.jpg')
232-
expect(getByRole('link')).toHaveClass('typography-contentLink')
233-
expect(getByRole('link')).toHaveAttribute('target', '_blank')
234-
expect(getByRole('link')).toHaveAttribute('rel', 'noopener noreferrer')
235150
});
236151

237152
it('renders zero width no break space in empty leafs to prevent empty paragraphs from collapsing', () => {

0 commit comments

Comments
 (0)