Commit d9ce2b1c authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre

Merge branch 'fj-38015-respect-query-params-in-embed-url' into 'master'

Respect snippet query params when displaying embed urls

Closes #35095 and #38015

See merge request gitlab-org/gitlab!21131
parents 6f0cdd54 15be1452
import { __ } from '~/locale'; import { __ } from '~/locale';
import { parseUrlPathname, parseUrl } from '../lib/utils/common_utils';
function swapActiveState(activateBtn, deactivateBtn) {
activateBtn.classList.add('is-active');
deactivateBtn.classList.remove('is-active');
}
export default () => { export default () => {
const shareBtn = document.querySelector('.js-share-btn'); const shareBtn = document.querySelector('.js-share-btn');
if (shareBtn) { if (shareBtn) {
const { protocol, host, pathname } = window.location;
const embedBtn = document.querySelector('.js-embed-btn'); const embedBtn = document.querySelector('.js-embed-btn');
const snippetUrlArea = document.querySelector('.js-snippet-url-area'); const snippetUrlArea = document.querySelector('.js-snippet-url-area');
const embedAction = document.querySelector('.js-embed-action'); const embedAction = document.querySelector('.js-embed-action');
const url = `${protocol}//${host + pathname}`; const dataUrl = snippetUrlArea.getAttribute('data-url');
snippetUrlArea.addEventListener('click', () => snippetUrlArea.select());
shareBtn.addEventListener('click', () => { shareBtn.addEventListener('click', () => {
shareBtn.classList.add('is-active'); swapActiveState(shareBtn, embedBtn);
embedBtn.classList.remove('is-active'); snippetUrlArea.value = dataUrl;
snippetUrlArea.value = url;
embedAction.innerText = __('Share'); embedAction.innerText = __('Share');
}); });
embedBtn.addEventListener('click', () => { embedBtn.addEventListener('click', () => {
embedBtn.classList.add('is-active'); const parser = parseUrl(dataUrl);
shareBtn.classList.remove('is-active'); const url = `${parser.origin + parseUrlPathname(dataUrl)}`;
const scriptTag = `<script src="${url}.js"></script>`; const params = parser.search;
const scriptTag = `<script src="${url}.js${params}"></script>`;
swapActiveState(embedBtn, shareBtn);
snippetUrlArea.value = scriptTag; snippetUrlArea.value = scriptTag;
embedAction.innerText = __('Embed'); embedAction.innerText = __('Embed');
}); });
......
...@@ -112,6 +112,17 @@ module SnippetsHelper ...@@ -112,6 +112,17 @@ module SnippetsHelper
content_tag(:script, nil, src: gitlab_snippet_url(snippet, format: :js)) content_tag(:script, nil, src: gitlab_snippet_url(snippet, format: :js))
end end
def snippet_embed_input(snippet)
content_tag(:input,
nil,
type: :text,
readonly: true,
class: 'js-snippet-url-area snippet-embed-input form-control',
data: { url: gitlab_snippet_url(snippet) },
value: snippet_embed_tag(snippet),
autocomplete: 'off')
end
def snippet_badge(snippet) def snippet_badge(snippet)
return unless attrs = snippet_badge_attributes(snippet) return unless attrs = snippet_badge_attributes(snippet)
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
%li %li
%button.js-share-btn.btn.btn-transparent{ type: 'button' } %button.js-share-btn.btn.btn-transparent{ type: 'button' }
%strong.embed-toggle-list-item= _("Share") %strong.embed-toggle-list-item= _("Share")
%input.js-snippet-url-area.snippet-embed-input.form-control{ type: "text", autocomplete: 'off', value: snippet_embed_tag(@snippet) } = snippet_embed_input(@snippet)
.input-group-append .input-group-append
= clipboard_button(title: _('Copy'), class: 'js-clipboard-btn snippet-clipboard-btn btn btn-default', target: '.js-snippet-url-area') = clipboard_button(title: _('Copy'), class: 'js-clipboard-btn snippet-clipboard-btn btn btn-default', target: '.js-snippet-url-area')
.clearfix .clearfix
---
title: Respect snippet query params when displaying embed urls
merge_request: 21131
author:
type: fixed
...@@ -16,6 +16,7 @@ describe 'Public Snippets', :js do ...@@ -16,6 +16,7 @@ describe 'Public Snippets', :js do
expect(page).to have_content(public_snippet.content) expect(page).to have_content(public_snippet.content)
expect(page).to have_css('.js-embed-btn', visible: false) expect(page).to have_css('.js-embed-btn', visible: false)
expect(page).to have_css('.js-share-btn', visible: false) expect(page).to have_css('.js-share-btn', visible: false)
expect(page.find('.js-snippet-url-area')).to be_readonly
end end
it 'Unauthenticated user should see raw public snippets' do it 'Unauthenticated user should see raw public snippets' do
......
...@@ -8,7 +8,7 @@ describe SnippetsController, '(JavaScript fixtures)', type: :controller do ...@@ -8,7 +8,7 @@ describe SnippetsController, '(JavaScript fixtures)', type: :controller do
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
let(:project) { create(:project, :repository, namespace: namespace, path: 'branches-project') } let(:project) { create(:project, :repository, namespace: namespace, path: 'branches-project') }
let(:snippet) { create(:personal_snippet, title: 'snippet.md', content: '# snippet', file_name: 'snippet.md', author: admin) } let(:snippet) { create(:personal_snippet, :public, title: 'snippet.md', content: '# snippet', file_name: 'snippet.md', author: admin) }
render_views render_views
......
import snippetEmbed from '~/snippet/snippet_embed';
import { loadHTMLFixture } from './helpers/fixtures';
describe('Snippets', () => {
let embedBtn;
let snippetUrlArea;
let shareBtn;
let scriptTag;
const snippetUrl = 'http://test.host/snippets/1';
beforeEach(() => {
loadHTMLFixture('snippets/show.html');
embedBtn = document.querySelector('.js-embed-btn');
snippetUrlArea = document.querySelector('.js-snippet-url-area');
shareBtn = document.querySelector('.js-share-btn');
});
it('selects the fields content when it is clicked', () => {
jest.spyOn(snippetUrlArea, 'select');
snippetEmbed();
expect(snippetUrlArea.select).not.toHaveBeenCalled();
snippetUrlArea.dispatchEvent(new Event('click'));
expect(snippetUrlArea.select).toHaveBeenCalled();
});
describe('when the snippet url does not include params', () => {
beforeEach(() => {
snippetEmbed();
scriptTag = `<script src="${snippetUrl}.js"></script>`;
});
it('shows the script tag as default', () => {
expect(snippetUrlArea.value).toEqual(scriptTag);
});
it('sets the proper url depending on the button clicked', () => {
shareBtn.dispatchEvent(new Event('click'));
expect(snippetUrlArea.value).toEqual(snippetUrl);
embedBtn.dispatchEvent(new Event('click'));
expect(snippetUrlArea.value).toEqual(scriptTag);
});
});
describe('when the snippet url includes params', () => {
beforeEach(() => {
scriptTag = `<script src="${snippetUrl}.js?foo=bar"></script>`;
snippetUrlArea.value = scriptTag;
snippetUrlArea.dataset.url = `${snippetUrl}?foo=bar`;
snippetEmbed();
});
it('shows the script tag as default', () => {
expect(snippetUrlArea.value).toEqual(scriptTag);
});
it('sets the proper url depending on the button clicked', () => {
shareBtn.dispatchEvent(new Event('click'));
expect(snippetUrlArea.value).toEqual(`${snippetUrl}?foo=bar`);
embedBtn.dispatchEvent(new Event('click'));
expect(snippetUrlArea.value).toEqual(scriptTag);
});
});
});
...@@ -40,6 +40,9 @@ Object.defineProperty(global.Element.prototype, 'innerText', { ...@@ -40,6 +40,9 @@ Object.defineProperty(global.Element.prototype, 'innerText', {
get() { get() {
return this.textContent; return this.textContent;
}, },
set(value) {
this.textContext = value;
},
configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch
}); });
......
...@@ -127,4 +127,28 @@ describe SnippetsHelper do ...@@ -127,4 +127,28 @@ describe SnippetsHelper do
end end
end end
end end
describe '#snippet_embed_input' do
subject { snippet_embed_input(snippet) }
context 'with PersonalSnippet' do
let(:snippet) { public_personal_snippet }
it 'returns the input component' do
expect(subject).to eq embed_input(snippet_url(snippet))
end
end
context 'with ProjectSnippet' do
let(:snippet) { public_project_snippet }
it 'returns the input component' do
expect(subject).to eq embed_input(project_snippet_url(snippet.project, snippet))
end
end
def embed_input(url)
"<input type=\"text\" readonly=\"readonly\" class=\"js-snippet-url-area snippet-embed-input form-control\" data-url=\"#{url}\" value=\"<script src=&quot;#{url}.js&quot;></script>\" autocomplete=\"off\"></input>"
end
end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment