From d1dcd08861ce23803fcac47b02cfc95190088cb3 Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Wed, 12 Jun 2013 21:33:30 +0200 Subject: [PATCH 1/8] Initial version of iframe-based embedding --- app/assets/stylesheets/player/player.css.sass | 3 +++ app/controllers/asciicasts_controller.rb | 6 ++++- app/views/asciicasts/raw.html.erb | 10 ++++++++ app/views/asciicasts/show.js.erb | 21 ++++++++++++++++ app/views/layouts/raw.html.erb | 25 ------------------- app/views/layouts/raw.html.slim | 13 ++++++++++ 6 files changed, 52 insertions(+), 26 deletions(-) create mode 100644 app/views/asciicasts/show.js.erb delete mode 100644 app/views/layouts/raw.html.erb create mode 100644 app/views/layouts/raw.html.slim diff --git a/app/assets/stylesheets/player/player.css.sass b/app/assets/stylesheets/player/player.css.sass index adaa9ce..1d72597 100644 --- a/app/assets/stylesheets/player/player.css.sass +++ b/app/assets/stylesheets/player/player.css.sass @@ -18,6 +18,9 @@ $color5: #edc951 right: 0 bottom: 0 +body.iframe + background-color: transparent + .player // float: left; display: block diff --git a/app/controllers/asciicasts_controller.rb b/app/controllers/asciicasts_controller.rb index a92b81c..e895f8c 100644 --- a/app/controllers/asciicasts_controller.rb +++ b/app/controllers/asciicasts_controller.rb @@ -6,7 +6,7 @@ class AsciicastsController < ApplicationController before_filter :ensure_authenticated!, :only => [:edit, :update, :destroy] before_filter :ensure_owner!, :only => [:edit, :update, :destroy] - respond_to :html, :json + respond_to :html, :json, :js def index @asciicasts = PaginatingDecorator.new( @@ -41,6 +41,10 @@ class AsciicastsController < ApplicationController respond_with AsciicastJSONDecorator.new(@asciicast) end end + + format.js do + respond_with @asciicast + end end end diff --git a/app/views/asciicasts/raw.html.erb b/app/views/asciicasts/raw.html.erb index c2ff8c7..f8ddfa3 100644 --- a/app/views/asciicasts/raw.html.erb +++ b/app/views/asciicasts/raw.html.erb @@ -1 +1,11 @@ <%= player @asciicast %> + diff --git a/app/views/asciicasts/show.js.erb b/app/views/asciicasts/show.js.erb new file mode 100644 index 0000000..9309bb9 --- /dev/null +++ b/app/views/asciicasts/show.js.erb @@ -0,0 +1,21 @@ +// ascii.io - embeddable widget + +(function() { + function receiveSize(e) { + if (e.origin === document.location.protocol + "//<%= request.host %>") { + var event = e.data[0]; + var data = e.data[1]; + if (event == 'asciicast:size' && data.id == <%= @asciicast.id %>) { + var player = document.getElementById("asciicast-player-<%= @asciicast.id %>"); + if (player) { + player.style.width = data.width; + player.style.height = data.height; + } + } + } + } + + window.addEventListener("message", receiveSize, false); + + document.writeln('
'); +})(); diff --git a/app/views/layouts/raw.html.erb b/app/views/layouts/raw.html.erb deleted file mode 100644 index ecad73b..0000000 --- a/app/views/layouts/raw.html.erb +++ /dev/null @@ -1,25 +0,0 @@ - - - - - <%= page_title %> - - - - - <%= stylesheet_link_tag "player", :media => "all" %> - <%= javascript_include_tag "application" %> - <%= javascript_include_tag "player" %> - - - - - - <%= yield %> - - diff --git a/app/views/layouts/raw.html.slim b/app/views/layouts/raw.html.slim new file mode 100644 index 0000000..097b8e4 --- /dev/null +++ b/app/views/layouts/raw.html.slim @@ -0,0 +1,13 @@ +doctype html +html[lang="en"] + head + meta[charset="utf-8"] + title = page_title + = stylesheet_link_tag "player", :media => "all" + = javascript_include_tag "application" + = javascript_include_tag "player" + script + | window.unpackWorkerPath = '#{javascript_path "unpack_worker"}'; + window.mainWorkerPath = '#{javascript_path "main_worker"}'; + body.iframe + = yield From f22837f4e9eef3e31d83caec272e8d06cf9bde52 Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Wed, 12 Jun 2013 21:52:15 +0200 Subject: [PATCH 2/8] Add "embed" css/js bundles --- app/assets/javascripts/embed.js | 2 ++ app/assets/stylesheets/embed.sass | 4 ++++ app/assets/stylesheets/player/player.css.sass | 3 --- app/views/asciicasts/{raw.html.erb => raw.html.slim} | 8 ++++---- app/views/layouts/raw.html.slim | 5 ++--- config/environments/production.rb | 2 +- 6 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 app/assets/javascripts/embed.js create mode 100644 app/assets/stylesheets/embed.sass rename app/views/asciicasts/{raw.html.erb => raw.html.slim} (66%) diff --git a/app/assets/javascripts/embed.js b/app/assets/javascripts/embed.js new file mode 100644 index 0000000..35e2f9d --- /dev/null +++ b/app/assets/javascripts/embed.js @@ -0,0 +1,2 @@ +//= require application +//= require player diff --git a/app/assets/stylesheets/embed.sass b/app/assets/stylesheets/embed.sass new file mode 100644 index 0000000..65e7b5a --- /dev/null +++ b/app/assets/stylesheets/embed.sass @@ -0,0 +1,4 @@ +//= require player + +body.iframe + background-color: transparent diff --git a/app/assets/stylesheets/player/player.css.sass b/app/assets/stylesheets/player/player.css.sass index 1d72597..adaa9ce 100644 --- a/app/assets/stylesheets/player/player.css.sass +++ b/app/assets/stylesheets/player/player.css.sass @@ -18,9 +18,6 @@ $color5: #edc951 right: 0 bottom: 0 -body.iframe - background-color: transparent - .player // float: left; display: block diff --git a/app/views/asciicasts/raw.html.erb b/app/views/asciicasts/raw.html.slim similarity index 66% rename from app/views/asciicasts/raw.html.erb rename to app/views/asciicasts/raw.html.slim index f8ddfa3..c37b094 100644 --- a/app/views/asciicasts/raw.html.erb +++ b/app/views/asciicasts/raw.html.slim @@ -1,11 +1,11 @@ -<%= player @asciicast %> - diff --git a/app/views/layouts/raw.html.slim b/app/views/layouts/raw.html.slim index 097b8e4..a544e07 100644 --- a/app/views/layouts/raw.html.slim +++ b/app/views/layouts/raw.html.slim @@ -3,9 +3,8 @@ html[lang="en"] head meta[charset="utf-8"] title = page_title - = stylesheet_link_tag "player", :media => "all" - = javascript_include_tag "application" - = javascript_include_tag "player" + = stylesheet_link_tag 'embed', :media => 'all' + = javascript_include_tag 'embed' script | window.unpackWorkerPath = '#{javascript_path "unpack_worker"}'; window.mainWorkerPath = '#{javascript_path "main_worker"}'; diff --git a/config/environments/production.rb b/config/environments/production.rb index 0058c5d..2bf8689 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -43,7 +43,7 @@ AsciiIo::Application.configure do # config.action_controller.asset_host = "http://assets.example.com" # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) - config.assets.precompile += %w( player.css player.js unpack_worker.js main_worker.js ) + config.assets.precompile += %w( player.css player.js unpack_worker.js main_worker.js embed.css embed.js ) config.action_mailer.delivery_method = :sendmail From e182cce8eeaa23c924caa50d2f668dc85e078d3d Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Wed, 12 Jun 2013 22:47:39 +0200 Subject: [PATCH 3/8] Don't use document.write to insert the player into the DOM --- app/views/asciicasts/show.js.erb | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/app/views/asciicasts/show.js.erb b/app/views/asciicasts/show.js.erb index 9309bb9..b3975a0 100644 --- a/app/views/asciicasts/show.js.erb +++ b/app/views/asciicasts/show.js.erb @@ -1,4 +1,4 @@ -// ascii.io - embeddable widget +// ascii.io - embeddable player (function() { function receiveSize(e) { @@ -6,7 +6,7 @@ var event = e.data[0]; var data = e.data[1]; if (event == 'asciicast:size' && data.id == <%= @asciicast.id %>) { - var player = document.getElementById("asciicast-player-<%= @asciicast.id %>"); + var player = document.getElementById("asciicast-iframe-<%= @asciicast.id %>"); if (player) { player.style.width = data.width; player.style.height = data.height; @@ -15,7 +15,20 @@ } } + function insertAfter(referenceNode, newNode) { + referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); + } + window.addEventListener("message", receiveSize, false); - document.writeln('
'); + var scriptTag = document.getElementById("asciicast-<%= @asciicast.id %>"); + if (scriptTag) { + var container = document.createElement('div'); + container.className = 'asciicast'; + container.style.display = 'block'; + container.style.float = 'none'; + container.style.overflow = 'hidden'; + container.innerHTML = ''; + insertAfter(scriptTag, container); + } })(); From f0b66b63990074cf8b08020c5e53383d268e06e0 Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Wed, 12 Jun 2013 23:50:31 +0200 Subject: [PATCH 4/8] Center overlays according to viewport/container width --- .../player/abstract_player.js.coffee | 1 + .../player/views/player_view.js.coffee | 18 ++++++++++++++++-- app/helpers/asciicasts_helper.rb | 1 + app/views/asciicasts/_player.html.erb | 1 + app/views/asciicasts/show.js.erb | 8 +++++--- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/player/abstract_player.js.coffee b/app/assets/javascripts/player/abstract_player.js.coffee index 48776e6..864b85b 100644 --- a/app/assets/javascripts/player/abstract_player.js.coffee +++ b/app/assets/javascripts/player/abstract_player.js.coffee @@ -14,6 +14,7 @@ class AsciiIo.AbstractPlayer hud: @options.hud rendererClass: @options.rendererClass snapshot: @options.snapshot + containerWidth: @options.containerWidth createVT: -> throw 'not implemented' diff --git a/app/assets/javascripts/player/views/player_view.js.coffee b/app/assets/javascripts/player/views/player_view.js.coffee index b4d4065..fe0b834 100644 --- a/app/assets/javascripts/player/views/player_view.js.coffee +++ b/app/assets/javascripts/player/views/player_view.js.coffee @@ -4,6 +4,7 @@ class AsciiIo.PlayerView extends Backbone.View initialize: (options) -> @createRendererView() + @setupClipping() @createHudView() if options.hud @showLoadingOverlay() @@ -17,6 +18,14 @@ class AsciiIo.PlayerView extends Backbone.View @rendererView.afterInsertedToDom() @rendererView.renderSnapshot @options.snapshot + setupClipping: -> + if @options.containerWidth + rendererWidth = @rendererView.$el.outerWidth() + min = Math.min(@options.containerWidth, rendererWidth) + @rightClipWidth = rendererWidth - min + else + @rightClipWidth = 0 + createHudView: -> @hudView = new AsciiIo.HudView(cols: @options.cols) @@ -39,14 +48,19 @@ class AsciiIo.PlayerView extends Backbone.View onSeekClicked: (percent) -> @trigger 'seek-clicked', percent + showOverlay: (html) -> + element = $(html) + element.css('margin-right': "#{@rightClipWidth}px") if @rightClipWidth + @$el.append(element) + showLoadingOverlay: -> - @$el.append('
') + @showOverlay('
') hideLoadingOverlay: -> @$('.loading').remove() showPlayOverlay: -> - @$el.append('
') + @showOverlay('
') hidePlayOverlay: -> @$('.start-prompt').remove() diff --git a/app/helpers/asciicasts_helper.rb b/app/helpers/asciicasts_helper.rb index 24b98a2..66dbfeb 100644 --- a/app/helpers/asciicasts_helper.rb +++ b/app/helpers/asciicasts_helper.rb @@ -20,6 +20,7 @@ module AsciicastsHelper speed: (options[:speed] || params[:speed] || 1).to_f, benchmark: !!params[:bm], asciicast_id: asciicast.id, + container_width: params[:container_width], renderer_class: renderer_class, auto_play: options.key?(:auto_play) ? !!options[:auto_play] : false, hud: options.key?(:hud) ? !!options[:hud] : true, diff --git a/app/views/asciicasts/_player.html.erb b/app/views/asciicasts/_player.html.erb index 74e3360..9ee9d43 100644 --- a/app/views/asciicasts/_player.html.erb +++ b/app/views/asciicasts/_player.html.erb @@ -9,6 +9,7 @@ speed: <%= speed %>, benchmark: <%= benchmark %>, model: new AsciiIo.Asciicast({ id: <%= asciicast_id %> }), + containerWidth: <%= container_width || 'null' %>, rendererClass: <%= renderer_class.html_safe %>, autoPlay: <%= auto_play %>, hud: <%= hud %>, diff --git a/app/views/asciicasts/show.js.erb b/app/views/asciicasts/show.js.erb index b3975a0..32dd830 100644 --- a/app/views/asciicasts/show.js.erb +++ b/app/views/asciicasts/show.js.erb @@ -19,16 +19,18 @@ referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); } - window.addEventListener("message", receiveSize, false); - var scriptTag = document.getElementById("asciicast-<%= @asciicast.id %>"); + if (scriptTag) { + window.addEventListener("message", receiveSize, false); var container = document.createElement('div'); container.className = 'asciicast'; container.style.display = 'block'; container.style.float = 'none'; container.style.overflow = 'hidden'; - container.innerHTML = ''; + container.style.padding = '0'; insertAfter(scriptTag, container); + var containerWidth = container.offsetWidth; + container.innerHTML = ''; } })(); From 20cf58e89b339abac726f28d5c7587d4ff9a797e Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Wed, 12 Jun 2013 23:58:24 +0200 Subject: [PATCH 5/8] Make the render expose its width and height --- .../javascripts/player/views/player_view.js.coffee | 2 +- .../javascripts/player/views/renderers/base.js.coffee | 9 +++++++++ .../javascripts/player/views/renderers/canvas.js.coffee | 7 ++----- .../javascripts/player/views/renderers/pre.js.coffee | 5 +---- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/player/views/player_view.js.coffee b/app/assets/javascripts/player/views/player_view.js.coffee index fe0b834..c96205e 100644 --- a/app/assets/javascripts/player/views/player_view.js.coffee +++ b/app/assets/javascripts/player/views/player_view.js.coffee @@ -20,7 +20,7 @@ class AsciiIo.PlayerView extends Backbone.View setupClipping: -> if @options.containerWidth - rendererWidth = @rendererView.$el.outerWidth() + rendererWidth = @rendererView.elementWidth() min = Math.min(@options.containerWidth, rendererWidth) @rightClipWidth = rendererWidth - min else diff --git a/app/assets/javascripts/player/views/renderers/base.js.coffee b/app/assets/javascripts/player/views/renderers/base.js.coffee index 878cae0..59c8b58 100644 --- a/app/assets/javascripts/player/views/renderers/base.js.coffee +++ b/app/assets/javascripts/player/views/renderers/base.js.coffee @@ -10,6 +10,15 @@ class AsciiIo.Renderer.Base extends Backbone.View @clearState() requestAnimationFrame @render + width: -> + @cols * @cellWidth + + height: -> + @lines * @cellHeight + + elementWidth: -> + @$el.outerWidth() + clearState: -> @state = changes: {} diff --git a/app/assets/javascripts/player/views/renderers/canvas.js.coffee b/app/assets/javascripts/player/views/renderers/canvas.js.coffee index ff5c7bb..bc3cf88 100644 --- a/app/assets/javascripts/player/views/renderers/canvas.js.coffee +++ b/app/assets/javascripts/player/views/renderers/canvas.js.coffee @@ -12,11 +12,8 @@ class AsciiIo.Renderer.Canvas extends AsciiIo.Renderer.Base @cursorVisible = true fixTerminalElementSize: -> - width = @cols * @cellWidth - height = @lines * @cellHeight - - @$el.attr('width', width) - @$el.attr('height', height) + @$el.attr('width', @width()) + @$el.attr('height', @height()) @setFont() diff --git a/app/assets/javascripts/player/views/renderers/pre.js.coffee b/app/assets/javascripts/player/views/renderers/pre.js.coffee index 33aa448..03da5b8 100644 --- a/app/assets/javascripts/player/views/renderers/pre.js.coffee +++ b/app/assets/javascripts/player/views/renderers/pre.js.coffee @@ -18,10 +18,7 @@ class AsciiIo.Renderer.Pre extends AsciiIo.Renderer.Base i++ fixTerminalElementSize: -> - width = @cols * @cellWidth - height = @lines * @cellHeight - - @$el.css(width: width + 'px', height: height + 'px') + @$el.css(width: @width() + 'px', height: @height() + 'px') render: -> if @state.dirty From feec862f99ba2afc764286c850c4423ff9c252cd Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Thu, 13 Jun 2013 11:45:00 +0200 Subject: [PATCH 6/8] Display embed link on the asciicast's page --- app/assets/javascripts/application.js | 4 ++++ app/assets/stylesheets/asciicasts.css.sass | 5 +++++ app/decorators/asciicast_decorator.rb | 4 ++++ app/views/asciicasts/_share.html.erb | 7 ------ app/views/asciicasts/_share.html.slim | 6 ++++++ app/views/asciicasts/show.html.erb | 25 ---------------------- app/views/asciicasts/show.html.slim | 15 +++++++++++++ 7 files changed, 34 insertions(+), 32 deletions(-) delete mode 100644 app/views/asciicasts/_share.html.erb create mode 100644 app/views/asciicasts/_share.html.slim delete mode 100644 app/views/asciicasts/show.html.erb create mode 100644 app/views/asciicasts/show.html.slim diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 95c305e..476c88d 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -15,4 +15,8 @@ $(function() { $('abbr.timeago').timeago(); + + $("input[data-behavior=auto-select]").click(function() { + this.select(); + }); }); diff --git a/app/assets/stylesheets/asciicasts.css.sass b/app/assets/stylesheets/asciicasts.css.sass index b8a780f..cb5be4e 100644 --- a/app/assets/stylesheets/asciicasts.css.sass +++ b/app/assets/stylesheets/asciicasts.css.sass @@ -96,3 +96,8 @@ div.presentation .other-asciicasts margin-top: 70px + +.extras + .embed-script + width: 100% + margin: 5px 0 diff --git a/app/decorators/asciicast_decorator.rb b/app/decorators/asciicast_decorator.rb index df7caba..40fa22b 100644 --- a/app/decorators/asciicast_decorator.rb +++ b/app/decorators/asciicast_decorator.rb @@ -99,6 +99,10 @@ class AsciicastDecorator < ApplicationDecorator end end + def embed_script + %() + end + private def prepare_lines(lines, width, height) diff --git a/app/views/asciicasts/_share.html.erb b/app/views/asciicasts/_share.html.erb deleted file mode 100644 index 1b24740..0000000 --- a/app/views/asciicasts/_share.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -

Share

- -
    -
  • - Twitter -
  • -
diff --git a/app/views/asciicasts/_share.html.slim b/app/views/asciicasts/_share.html.slim new file mode 100644 index 0000000..9e4f26a --- /dev/null +++ b/app/views/asciicasts/_share.html.slim @@ -0,0 +1,6 @@ +h1 Share + +ul.delimited + li + ' Embed on your page + input[type="text" class="embed-script" value=@asciicast.embed_script data-behavior="auto-select" readonly] diff --git a/app/views/asciicasts/show.html.erb b/app/views/asciicasts/show.html.erb deleted file mode 100644 index df6a073..0000000 --- a/app/views/asciicasts/show.html.erb +++ /dev/null @@ -1,25 +0,0 @@ -
-
- <%= player @asciicast %> -
-
- -
-
-
-

<%= @asciicast.title %>

- -
- <%= @asciicast.description %> -
- - <%= render :partial => 'other_by_user' %> -
- -
- <%= render :partial => 'author' %> - <%= render :partial => 'actions' %> - <%= render :partial => 'info' %> -
-
-
diff --git a/app/views/asciicasts/show.html.slim b/app/views/asciicasts/show.html.slim new file mode 100644 index 0000000..73c5f76 --- /dev/null +++ b/app/views/asciicasts/show.html.slim @@ -0,0 +1,15 @@ +section#presentation.feature + .asciicast-wrapper + = player @asciicast + +section.supplimental + .wrapper + .main + h1 = @asciicast.title + .description = @asciicast.description + = render :partial => 'other_by_user' + .extras + = render :partial => 'author' + = render :partial => 'actions' + = render :partial => 'info' + = render :partial => 'share' From 8a52605266f40c967265e925ae4950653d028392 Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Thu, 13 Jun 2013 22:39:34 +0200 Subject: [PATCH 7/8] Add spec for AsciicastDecorator#embed_script --- app/decorators/asciicast_decorator.rb | 4 +++- spec/decorators/asciicast_decorator_spec.rb | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/decorators/asciicast_decorator.rb b/app/decorators/asciicast_decorator.rb index 40fa22b..aa1bffb 100644 --- a/app/decorators/asciicast_decorator.rb +++ b/app/decorators/asciicast_decorator.rb @@ -100,7 +100,9 @@ class AsciicastDecorator < ApplicationDecorator end def embed_script - %() + src = h.asciicast_url(model, :format => :js) + id = "asciicast-#{id}" + %() end private diff --git a/spec/decorators/asciicast_decorator_spec.rb b/spec/decorators/asciicast_decorator_spec.rb index 7da77a8..016d9c5 100644 --- a/spec/decorators/asciicast_decorator_spec.rb +++ b/spec/decorators/asciicast_decorator_spec.rb @@ -240,4 +240,14 @@ describe AsciicastDecorator do describe '#other_by_user' do pending end + + describe '#embed_script' do + before do + asciicast.stub!(:id => 123) + end + + it 'should be an async script tag including asciicast id' do + expect(decorated.embed_script).to match(/^]+\b123\b[^>]+><\/script>/) + end + end end From 0f99198a1af719a49a1f10c620a4b746ecc0b280 Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Thu, 13 Jun 2013 22:41:06 +0200 Subject: [PATCH 8/8] Add spec for asciicasts#show as js --- spec/controllers/asciicasts_controller_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spec/controllers/asciicasts_controller_spec.rb b/spec/controllers/asciicasts_controller_spec.rb index 0803143..c9fc242 100644 --- a/spec/controllers/asciicasts_controller_spec.rb +++ b/spec/controllers/asciicasts_controller_spec.rb @@ -94,6 +94,18 @@ describe AsciicastsController do it { should be_success } end + + context 'for js request' do + let(:asciicast) { FactoryGirl.build(:asciicast, :id => 666) } + + before do + ViewCounter.should_not_receive(:new) + + get :show, :id => asciicast.id, :format => :js + end + + it { should be_success } + end end describe '#edit' do