Skip to content

Commit

Permalink
Merge pull request #1959 from tvdeyen/preview-sources
Browse files Browse the repository at this point in the history
Allow multiple preview sources
  • Loading branch information
tvdeyen committed Nov 6, 2020
2 parents 50f6437 + 03ebb9a commit 210b3d1
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 19 deletions.
Expand Up @@ -38,10 +38,7 @@ Alchemy.ElementEditors =
@onSaveElement(e, data)
# Listen to postMessage messages from the preview frame
window.addEventListener 'message', (e) =>
if e.origin == window.location.origin
@onMessage(e.data)
else
console.warn 'Unsafe message origin!', e.origin
@onMessage(e.data)
true
return

Expand Down
3 changes: 0 additions & 3 deletions app/assets/javascripts/alchemy/alchemy.preview.js.coffee
Expand Up @@ -22,9 +22,6 @@ Alchemy.initAlchemyPreviewMode = ->

init: ->
window.addEventListener "message", (event) =>
if event.origin != window.location.origin
console.warn 'Unsafe message origin!', event.origin
return
switch event.data.message
when "Alchemy.blurElements" then @blurElements()
when "Alchemy.focusElement" then @focusElement(event.data)
Expand Down
33 changes: 29 additions & 4 deletions app/assets/javascripts/alchemy/alchemy.preview_window.js.coffee
Expand Up @@ -4,15 +4,21 @@ Alchemy.PreviewWindow =
MIN_WIDTH: 240
HEIGHT: 75 # Top menu height

init: (url) ->
$iframe = $("<iframe name=\"alchemy_preview_window\" src=\"#{url}\" id=\"alchemy_preview_window\" frameborder=\"0\"/>")
init: (previewUrl) ->
@select = document.querySelector('#preview_url')
@previewUrl = @_getCurrentPreviewUrl() || previewUrl[1]
$iframe = $("<iframe name=\"alchemy_preview_window\" src=\"#{@previewUrl}\" id=\"alchemy_preview_window\" frameborder=\"0\"/>")
$reload = $('#reload_preview_button')
@_showSpinner()
$iframe.load =>
@_hideSpinner()
$('body').append($iframe)
@currentWindow = $iframe
@_bindReloadButton()
if @select
@select.value = @previewUrl
@_bindSelect()
return

resize: (width) ->
width = @MIN_WIDTH if width < @MIN_WIDTH
Expand All @@ -29,12 +35,12 @@ Alchemy.PreviewWindow =
@_hideSpinner()
if callback
callback.call(e, $iframe)
$iframe.attr 'src', $iframe.attr('src')
$iframe.attr('src', @previewUrl)
true

postMessage: (data) ->
frameWindow = @currentWindow[0].contentWindow
frameWindow.postMessage(data, window.location.origin)
frameWindow.postMessage(data, "*")

_showSpinner: ->
@reload = $('#reload_preview_button')
Expand All @@ -53,5 +59,24 @@ Alchemy.PreviewWindow =
e.preventDefault()
@refresh()

_getCurrentPreviewUrl: ->
if @select
option = Array.from(@select.options).find (o) =>
o.text == window.localStorage.getItem("alchemyPreview")
if option
option.value
else
null
else
null

_bindSelect: ->
$(@select).change (e) =>
@previewUrl = e.target.value
option = e.target.querySelector("option[value='#{@previewUrl}']")
window.localStorage.setItem("alchemyPreview", option.text)
@refresh()
return

Alchemy.reloadPreview = ->
Alchemy.PreviewWindow.refresh()
2 changes: 2 additions & 0 deletions app/assets/stylesheets/alchemy/_variables.scss
Expand Up @@ -159,6 +159,8 @@ $datepicker_day_color: $text-color !default;

$select-hover-bg-color: $dark-blue !default;
$select-hover-text-color: $white !default;
$medium-select-box-width: 90px;
$large-select-box-width: 120px;

$thumbnail-background-color: opacify($default-border-color, 1) !default;
$medium-screen-break-point: 700px;
Expand Down
6 changes: 4 additions & 2 deletions app/assets/stylesheets/alchemy/selects.scss
@@ -1,5 +1,3 @@
$medium-select-box-width: 90px;

select {
@include button-defaults(
$background-color: $form-field-background-color,
Expand Down Expand Up @@ -76,6 +74,10 @@ select {
width: $medium-select-box-width;
}

&.large {
width: $large-select-box-width;
}

&.select2-container-active {

.select2-choice, .select2-choices {
Expand Down
7 changes: 6 additions & 1 deletion app/controllers/alchemy/admin/pages_controller.rb
Expand Up @@ -85,7 +85,12 @@ def edit
elsif page_needs_lock?
@page.lock_to!(current_alchemy_user)
end
@preview_url = Alchemy::Admin::PREVIEW_URL.url_for(@page)
@preview_urls = Alchemy.preview_sources.map do |klass|
[
klass.model_name.human,
klass.new(routes: Alchemy::Engine.routes).url_for(@page),
]
end
@layoutpage = @page.layoutpage?
end

Expand Down
10 changes: 9 additions & 1 deletion app/views/alchemy/admin/pages/edit.html.erb
Expand Up @@ -88,6 +88,14 @@
class: 'alchemy_selectbox medium' %>
</div>
<div class="toolbar_spacer"></div>
<% if @preview_urls.many? %>
<div class="select_with_label">
<label><%= Alchemy.t(:preview_url) %></label>
<%= select_tag 'preview_url',
options_for_select(@preview_urls),
class: 'alchemy_selectbox large' %>
</div>
<% end %>
<div class="button_with_label">
<%= link_to render_icon(:redo), nil, {
title: Alchemy.t('Reload Preview'),
Expand Down Expand Up @@ -190,7 +198,7 @@
}
});

Alchemy.PreviewWindow.init('<%= @preview_url %>');
Alchemy.PreviewWindow.init(<%== @preview_urls.first %>);

$('#preview_size').bind('open.selectBoxIt', function (e) {
$('#top_menu').css('z-index', 5000);
Expand Down
2 changes: 2 additions & 0 deletions config/locales/alchemy.en.yml
Expand Up @@ -521,6 +521,7 @@ en:
'768': '768px (iPad - Portrait)'
'1024': '1024px (iPad - Landscape)'
'1280': '1280px (Desktop)'
preview_url: Preview
recently_uploaded_only: 'Recently uploaded only'
"regular method": "Regular method"
remove: "Remove"
Expand Down Expand Up @@ -690,6 +691,7 @@ en:
alchemy/message:
one: Message
other: Messages
alchemy/admin/preview_url: Internal
attributes:
alchemy/message:
salutation: 'Salutation'
Expand Down
37 changes: 37 additions & 0 deletions lib/alchemy.rb
@@ -1,8 +1,45 @@
# frozen_string_literal: true

require "alchemy/admin/preview_url"

module Alchemy
YAML_WHITELIST_CLASSES = %w(Symbol Date Regexp)

# Define page preview sources
#
# A preview source is a Ruby class returning an URL
# that is used as source for the preview frame in the
# admin UI.
#
# == Example
#
# # lib/acme/preview_source.rb
# class Acme::PreviewSource < Alchemy::Admin::PreviewUrl
# def url_for(page)
# if page.site.name == "Next"
# "https://user:#{ENV['PREVIEW_HTTP_PASS']}@next.acme.com"
# else
# "https://www.acme.com"
# end
# end
# end
#
# # config/initializers/alchemy.rb
# require "acme/preview_source"
# Alchemy.preview_sources << Acme::PreviewSource
#
# # config/locales/de.yml
# de:
# activemodel:
# models:
# acme/preview_source: Acme Vorschau
#
def self.preview_sources
@_preview_sources ||= begin
Set.new << Alchemy::Admin::PreviewUrl
end
end

# Define page publish targets
#
# A publish target is a ActiveJob that gets performed
Expand Down
2 changes: 2 additions & 0 deletions lib/alchemy/admin/preview_url.rb
Expand Up @@ -31,6 +31,8 @@ module Admin
# password: <%= ENV["BASIC_AUTH_PASSWORD"] %>
#
class PreviewUrl
extend ActiveModel::Translation

class MissingProtocolError < StandardError; end

def initialize(routes:)
Expand Down
4 changes: 0 additions & 4 deletions lib/alchemy/engine.rb
Expand Up @@ -9,10 +9,6 @@ class Engine < Rails::Engine
Alchemy::LOOKUP_CONTEXT = ActionView::LookupContext.new(Rails.root.join("app", "views", "alchemy"))
end

initializer "alchemy.admin.preview_url" do
Alchemy::Admin::PREVIEW_URL = Alchemy::Admin::PreviewUrl.new(routes: Alchemy::Engine.routes)
end

initializer "alchemy.dependency_tracker" do
[:erb, :slim, :haml].each do |handler|
ActionView::DependencyTracker.register_tracker(handler, CacheDigests::TemplateTracker)
Expand Down
4 changes: 4 additions & 0 deletions spec/dummy/config/locales/alchemy.en.yml
Expand Up @@ -29,3 +29,7 @@ en:
resource_help_texts:
party:
name: Party

activemodel:
models:
foo_preview_source: Foo Preview
22 changes: 22 additions & 0 deletions spec/features/admin/page_editing_feature_spec.rb
Expand Up @@ -19,6 +19,28 @@
expect(page).to have_selector("iframe[src='#{admin_page_path(a_page)}']")
end
end

describe "single preview source", :js do
it "does not show as select" do
visit alchemy.edit_admin_page_path(a_page)
expect(page).to_not have_select("preview_url")
end
end

describe "multiple preview sources", :js do
class FooPreviewSource < Alchemy::Admin::PreviewUrl; end

around do |example|
Alchemy.preview_sources << FooPreviewSource
example.run
Alchemy.instance_variable_set(:@_preview_sources, nil)
end

it "show as select" do
visit alchemy.edit_admin_page_path(a_page)
expect(page).to have_select("preview_url", options: ["Internal", "Foo Preview"])
end
end
end

context "as editor" do
Expand Down

0 comments on commit 210b3d1

Please sign in to comment.