Integrate new React.js-based player

footer-fixes
Marcin Kulik 10 years ago
parent 6ad2a40ab8
commit b6a23222d7

@ -1,2 +0,0 @@
String.prototype.times = (n) ->
Array.prototype.join.call { length: n + 1 }, this

@ -1,10 +0,0 @@
//= require_self
//= require player/workers/common
//= require underscore-min
//= require backbone-min
//= require extensions
//= require player/brush
//= require player/movie
//= require player/workers/main_worker
Asciinema = {};

@ -1,3 +1,6 @@
if not window.Asciinema
window.Asciinema = {}
class Asciinema.Asciicast extends Backbone.Model
url: ->

@ -1,5 +0,0 @@
if (!window.Asciinema){
window.Asciinema = {};
}
Asciinema.Renderer = {};

@ -1,16 +1,5 @@
//= require rAF
//= require extensions
//= require namespace
//= require player/views/renderers/base
//= require_tree ./player/views/renderers
//= require player/views/hud_view
//= require player/abstract_player
//= require player/movie
//= require player/player
//= require player/fallback_player
//= require player/views/player_view
//= require player/workers/worker_object_proxy
//= require player/workers/worker_proxy
//= require player/brush
//= require player/colors
//= require_tree ./models
//= require rAF
//= require react-0.10.0
//= require asciinema-player
//= require screenfull

@ -1,73 +0,0 @@
class Asciinema.AbstractPlayer
constructor: (@options) ->
@model = @options.model
@createView()
@loadFrames()
createView: ->
@view = new Asciinema.PlayerView
el: @options.el
model: @model
cols: @model.get 'width'
lines: @model.get 'height'
hud: @options.hud
rendererClass: @options.rendererClass
snapshot: @model.get 'snapshot'
maxWidth: @options.maxWidth
createMovie: ->
throw 'not implemented'
movieOptions: ->
stdout_frames: @model.get 'stdout_frames'
duration: @model.get 'duration'
speed: @options.speed
benchmark: @options.benchmark
cols: @model.get 'width'
lines: @model.get 'height'
loadFrames: =>
if @model.get('stdout_frames_url')
@fetchFrames()
else
setTimeout(
=> @model.fetch success: @loadFrames,
2000
)
fetchFrames: ->
url = @model.get('stdout_frames_url')
$.getJSON url, (frames) =>
@model.set 'stdout_frames', frames
@onModelReady()
onModelReady: =>
@createMovie()
@bindEvents()
@view.onModelReady()
if @options.autoPlay
@movie.call 'play'
else
@view.showPlayOverlay()
bindEvents: ->
@view.on 'play-clicked', => @movie.call 'togglePlay'
@view.on 'seek-clicked', (percent) => @movie.call 'seek', percent
@movie.on 'started', => @view.onStateChanged 'playing'
@movie.on 'paused', => @view.onStateChanged 'paused'
@movie.on 'finished', => @view.onStateChanged 'finished'
@movie.on 'resumed', => @view.onStateChanged 'resumed'
@movie.on 'wakeup', => @view.restartCursorBlink()
@movie.on 'time', (time) => @view.updateTime time
@movie.on 'render', (state) => @view.renderState state
if @options.benchmark
@movie.on 'started', => @startedAt = (new Date).getTime()
@movie.on 'finished', =>
now = (new Date).getTime()
console.log "finished in #{(now - @startedAt) / 1000.0}s"

@ -1,84 +0,0 @@
class Asciinema.Brush
@default_fg = 7
@default_bg = 0
@cache: {}
@clearCache: ->
@cache = {}
@default: ->
@_default ||= @create()
@hash: (brush) ->
"#{brush.fg}_#{brush.bg}_#{brush.blink}_#{brush.bold}_#{brush.underline}_#{brush.inverse}"
@create: (options = {}) ->
key = @hash options
brush = @cache[key]
if not brush
brush = new Asciinema.Brush(options)
@cache[key] = brush
brush
constructor: (options = {}) ->
@fg = undefined
@bg = undefined
@blink = false
@bold = false
@underline = false
@inverse = false
for name, value of options
this[name] = value
hash: ->
Asciinema.Brush.hash this
attributes: ->
fg : @fg
bg : @bg
blink : @blink
bold : @bold
underline: @underline
inverse : @inverse
fgColor: ->
if @inverse
color = @calculateBgColor()
if color != undefined
color
else
Asciinema.Brush.default_bg
else
@calculateFgColor()
bgColor: ->
if @inverse
color = @calculateFgColor()
if color != undefined
color
else
Asciinema.Brush.default_fg
else
@calculateBgColor()
calculateFgColor: ->
color = @fg
color += 8 if color != undefined && color < 8 && @bold
color
calculateBgColor: ->
color = @bg
color += 8 if color != undefined && color < 8 && @blink
color
hasDefaultFg: ->
color = @fgColor()
color is undefined || color == Asciinema.Brush.default_fg
hasDefaultBg: ->
color = @bgColor()
color is undefined || color == Asciinema.Brush.default_bg

@ -1 +0,0 @@
Asciinema.colors = {"0":"#000000","1":"#CC0000","2":"#4E9A06","3":"#C4A000","4":"#3465A4","5":"#75507B","6":"#06989A","7":"#D3D7CF","8":"#555753","9":"#EF2929","10":"#8AE234","11":"#FCE94F","12":"#729FCF","13":"#AD7FA8","14":"#34E2E2","15":"#EEEEEC","16":"#000000","17":"#00005f","18":"#000087","19":"#0000af","20":"#0000d7","21":"#0000ff","22":"#005f00","23":"#005f5f","24":"#005f87","25":"#005faf","26":"#005fd7","27":"#005fff","28":"#008700","29":"#00875f","30":"#008787","31":"#0087af","32":"#0087d7","33":"#0087ff","34":"#00af00","35":"#00af5f","36":"#00af87","37":"#00afaf","38":"#00afd7","39":"#00afff","40":"#00d700","41":"#00d75f","42":"#00d787","43":"#00d7af","44":"#00d7d7","45":"#00d7ff","46":"#00ff00","47":"#00ff5f","48":"#00ff87","49":"#00ffaf","50":"#00ffd7","51":"#00ffff","52":"#5f0000","53":"#5f005f","54":"#5f0087","55":"#5f00af","56":"#5f00d7","57":"#5f00ff","58":"#5f5f00","59":"#5f5f5f","60":"#5f5f87","61":"#5f5faf","62":"#5f5fd7","63":"#5f5fff","64":"#5f8700","65":"#5f875f","66":"#5f8787","67":"#5f87af","68":"#5f87d7","69":"#5f87ff","70":"#5faf00","71":"#5faf5f","72":"#5faf87","73":"#5fafaf","74":"#5fafd7","75":"#5fafff","76":"#5fd700","77":"#5fd75f","78":"#5fd787","79":"#5fd7af","80":"#5fd7d7","81":"#5fd7ff","82":"#5fff00","83":"#5fff5f","84":"#5fff87","85":"#5fffaf","86":"#5fffd7","87":"#5fffff","88":"#870000","89":"#87005f","90":"#870087","91":"#8700af","92":"#8700d7","93":"#8700ff","94":"#875f00","95":"#875f5f","96":"#875f87","97":"#875faf","98":"#875fd7","99":"#875fff","100":"#878700","101":"#87875f","102":"#878787","103":"#8787af","104":"#8787d7","105":"#8787ff","106":"#87af00","107":"#87af5f","108":"#87af87","109":"#87afaf","110":"#87afd7","111":"#87afff","112":"#87d700","113":"#87d75f","114":"#87d787","115":"#87d7af","116":"#87d7d7","117":"#87d7ff","118":"#87ff00","119":"#87ff5f","120":"#87ff87","121":"#87ffaf","122":"#87ffd7","123":"#87ffff","124":"#af0000","125":"#af005f","126":"#af0087","127":"#af00af","128":"#af00d7","129":"#af00ff","130":"#af5f00","131":"#af5f5f","132":"#af5f87","133":"#af5faf","134":"#af5fd7","135":"#af5fff","136":"#af8700","137":"#af875f","138":"#af8787","139":"#af87af","140":"#af87d7","141":"#af87ff","142":"#afaf00","143":"#afaf5f","144":"#afaf87","145":"#afafaf","146":"#afafd7","147":"#afafff","148":"#afd700","149":"#afd75f","150":"#afd787","151":"#afd7af","152":"#afd7d7","153":"#afd7ff","154":"#afff00","155":"#afff5f","156":"#afff87","157":"#afffaf","158":"#afffd7","159":"#afffff","160":"#d70000","161":"#d7005f","162":"#d70087","163":"#d700af","164":"#d700d7","165":"#d700ff","166":"#d75f00","167":"#d75f5f","168":"#d75f87","169":"#d75faf","170":"#d75fd7","171":"#d75fff","172":"#d78700","173":"#d7875f","174":"#d78787","175":"#d787af","176":"#d787d7","177":"#d787ff","178":"#d7af00","179":"#d7af5f","180":"#d7af87","181":"#d7afaf","182":"#d7afd7","183":"#d7afff","184":"#d7d700","185":"#d7d75f","186":"#d7d787","187":"#d7d7af","188":"#d7d7d7","189":"#d7d7ff","190":"#d7ff00","191":"#d7ff5f","192":"#d7ff87","193":"#d7ffaf","194":"#d7ffd7","195":"#d7ffff","196":"#ff0000","197":"#ff005f","198":"#ff0087","199":"#ff00af","200":"#ff00d7","201":"#ff00ff","202":"#ff5f00","203":"#ff5f5f","204":"#ff5f87","205":"#ff5faf","206":"#ff5fd7","207":"#ff5fff","208":"#ff8700","209":"#ff875f","210":"#ff8787","211":"#ff87af","212":"#ff87d7","213":"#ff87ff","214":"#ffaf00","215":"#ffaf5f","216":"#ffaf87","217":"#ffafaf","218":"#ffafd7","219":"#ffafff","220":"#ffd700","221":"#ffd75f","222":"#ffd787","223":"#ffd7af","224":"#ffd7d7","225":"#ffd7ff","226":"#ffff00","227":"#ffff5f","228":"#ffff87","229":"#ffffaf","230":"#ffffd7","231":"#ffffff","232":"#080808","233":"#121212","234":"#1c1c1c","235":"#262626","236":"#303030","237":"#3a3a3a","238":"#444444","239":"#4e4e4e","240":"#585858","241":"#626262","242":"#6c6c6c","243":"#767676","244":"#808080","245":"#8a8a8a","246":"#949494","247":"#9e9e9e","248":"#a8a8a8","249":"#b2b2b2","250":"#bcbcbc","251":"#c6c6c6","252":"#d0d0d0","253":"#dadada","254":"#e4e4e4","255":"#eeeeee"};

@ -1,4 +0,0 @@
class Asciinema.FallbackPlayer extends Asciinema.AbstractPlayer
createMovie: ->
@movie = new Asciinema.Movie @movieOptions()

@ -1,199 +0,0 @@
class Asciinema.Movie
MIN_DELAY: 0.01
constructor: (@options) ->
_.extend(this, Backbone.Events)
@reset()
@startTimeReporter()
reset: ->
@frameNo = 0
@completedFramesTime = 0
@playing = false
@lastFrameAt = undefined
@clearPauseState()
call: (method, args...) ->
@[method].apply this, args
now: ->
(new Date()).getTime()
stdout_frames: ->
@options.stdout_frames
play: ->
return if @isPlaying()
if @isFinished()
@restart()
else if @isPaused()
@resume()
else
@start()
start: ->
@playing = true
@trigger 'started'
@lastFrameAt = @now()
@nextFrame()
stop: ->
@playing = false
@cancelNextFrameProcessing()
now = @now()
@adjustFrameWaitTime(now)
@pausedAt = now
cancelNextFrameProcessing: ->
clearInterval @nextFrameTimeoutId
adjustFrameWaitTime: (now) ->
resumedAt = @resumedAt or @lastFrameAt
currentWaitTime = now - resumedAt
@totalFrameWaitTime += currentWaitTime
restart: ->
@reset()
@start()
pause: ->
return if @isPaused()
@stop()
@trigger 'paused'
resume: ->
return if @isPlaying()
@playing = true
@resumedAt = @now()
[delay, changes] = @stdout_frames()[@frameNo]
delayMs = delay * 1000
delayLeft = delayMs - @totalFrameWaitTime
@processFrameWithDelay(delayLeft)
@trigger 'resumed'
togglePlay: ->
if @isPlaying() then @pause() else @play()
isPlaying: ->
@playing
isPaused: ->
!@isPlaying() and !@isFinished() and @frameNo > 0
isFinished: ->
!@isPlaying() and @frameNo >= @stdout_frames().length
seek: (percent) ->
@stop()
@rewindTo(percent)
@resume()
rewindTo: (percent) ->
duration = @options.duration
requestedTime = duration * percent / 100
frameNo = 0
time = 0
totalCount = 0
delay = data = undefined
while time < requestedTime
[delay, changes] = @stdout_frames()[frameNo]
if time + delay >= requestedTime
break
@trigger 'render', changes
time += delay
frameNo += 1
@frameNo = frameNo
@completedFramesTime = time * 1000
@lastFrameAt = @now()
wait = requestedTime - time
@totalFrameWaitTime = wait * 1000
startTimeReporter: ->
@timeReportId = setInterval(
=> @trigger('time', @currentTime())
500
)
stopTimeReporter: ->
clearInterval @timeReportId
currentTime: ->
@completedFramesTime + @currentFrameTime()
currentFrameTime: ->
if @isPlaying()
@playingFrameTime()
else if @isPaused()
@pausedFrameTime()
else
0
playingFrameTime: ->
if @frameWasPaused()
@currentFrameWithPauseTime()
else
@currentFrameWithNoPauseTime()
frameWasPaused: ->
!!@pausedAt
currentFrameWithPauseTime: ->
@totalFrameWaitTime + @sinceResumeTime()
currentFrameWithNoPauseTime: ->
@now() - @lastFrameAt
sinceResumeTime: ->
@now() - @resumedAt
pausedFrameTime: ->
@totalFrameWaitTime
clearPauseState: ->
@pausedAt = undefined
@resumedAt = undefined
@totalFrameWaitTime = 0
nextFrame: ->
frame = @stdout_frames()[@frameNo]
if not frame or frame.length is 0
@playing = false
@trigger 'finished'
return false
[delay, changes] = frame
realDelay = delay * 1000 * (1.0 / @options.speed)
@processFrameWithDelay(realDelay)
true
processFrameWithDelay: (delay) ->
@nextFrameTimeoutId = setTimeout(
=>
@trigger 'wakeup'
@processFrame()
delay
)
processFrame: ->
[delay, changes] = @stdout_frames()[@frameNo]
@trigger 'render', changes
@frameNo += 1
@completedFramesTime += delay * 1000
@lastFrameAt = @now()
@clearPauseState()
@nextFrame()

@ -1,18 +0,0 @@
class Asciinema.Player extends Asciinema.AbstractPlayer
constructor: (@options) ->
@createWorkerProxy()
super
createWorkerProxy: ->
@workerProxy = new Asciinema.WorkerProxy(window.mainWorkerPath)
createMovie: ->
@movie = @workerProxy.getObjectProxy 'movie'
onModelReady: ->
@initWorkerProxy()
super
initWorkerProxy: ->
@workerProxy.init @movieOptions()

@ -1,77 +0,0 @@
class Asciinema.HudView extends Backbone.View
tagName: 'pre'
className: 'hud'
events:
'click .toggle': 'togglePlay'
'click .progress span': 'seek'
initialize: (options) ->
@duration = undefined
@cols = options.cols
@lastArrowWidth = undefined
@calculateElementWidths()
@createChildViews()
calculateElementWidths: ->
@toggleWidth = 4
@timeWidth = 7
@progressWidth = @cols - @toggleWidth - @timeWidth
createChildViews: ->
toggle = '<span class="toggle"> <span class="play">=></span><span class="pause">||</span> '
progress = '<span class="progress">'
time = '<span class="time">'
@$el.append(toggle)
@$el.append(progress)
@$el.append(time)
setDuration: (@duration) ->
togglePlay: ->
@trigger('play-click')
seek: (e) ->
index = $(e.target).index()
percent = 100 * index / (@progressWidth - 2)
@trigger('seek-click', percent)
onPause: ->
@$('.toggle').addClass('paused')
onResume: ->
@$('.toggle').removeClass('paused')
updateTime: (time) ->
@$('.time').html(@formattedTime(time))
if @duration
progress = Math.round(100 * time / 1000 / @duration)
progress = 100.0 if progress > 100.0
@setProgress progress
setProgress: (percent) ->
arrowWidth = Math.floor((percent / 100.0) * (@progressWidth - 3))
arrowWidth = 1 if arrowWidth < 1
if arrowWidth != @lastArrowWidth
arrow = '='.times(arrowWidth) + '>'
filler = ' '.times(@progressWidth - 3 - arrowWidth)
bar = arrow + filler
chars = _(bar.split('')).map (c) -> "<span>#{c}</span>"
html = chars.join('')
@$('.progress').html('[' + html + ']')
@lastArrowWidth = arrowWidth
formattedTime: (time) ->
secondsTotal = time / 1000
minutes = Math.floor(secondsTotal / 60)
seconds = Math.floor(secondsTotal % 60)
" #{@pad2(minutes)}:#{@pad2(seconds)} "
pad2: (number) ->
if number < 10
'0' + number
else
number

@ -1,100 +0,0 @@
class Asciinema.PlayerView extends Backbone.View
events:
'click .start-prompt': 'onStartPromptClick'
initialize: (options) ->
@createRendererView()
@setupClipping()
@createHudView() if options.hud
@showLoadingOverlay()
createRendererView: ->
@rendererView = new @options.rendererClass(
cols: @options.cols
lines: @options.lines
)
@$el.append @rendererView.$el
@rendererView.afterInsertedToDom()
@renderSnapshot()
setupClipping: ->
if @options.maxWidth
rendererWidth = @rendererView.elementWidth()
min = Math.min(@options.maxWidth, rendererWidth)
@rightClipWidth = rendererWidth - min
else
@rightClipWidth = 0
createHudView: ->
@hudView = new Asciinema.HudView(cols: @options.cols)
@hudView.on 'play-click', => @onPlayClicked()
@hudView.on 'seek-click', (percent) => @onSeekClicked percent
@$el.append @hudView.$el
onModelReady: ->
@renderSnapshot()
@hideLoadingOverlay()
@hudView.setDuration @model.get('duration') if @hudView
onStartPromptClick: ->
@hidePlayOverlay()
@onPlayClicked()
onPlayClicked: ->
@trigger 'play-clicked'
onSeekClicked: (percent) ->
@trigger 'seek-clicked', percent
renderSnapshot: ->
@rendererView.renderSnapshot @model.get('snapshot')
showOverlay: (html) ->
element = $(html)
element.css('margin-right': "#{@rightClipWidth}px") if @rightClipWidth
@$el.append(element)
showLoadingOverlay: ->
@showOverlay('<div class="loading">')
hideLoadingOverlay: ->
@$('.loading').remove()
showPlayOverlay: ->
@showOverlay('<div class="start-prompt"><div class="play-button"><div class="arrow"><span class="glyphicon glyphicon-play"></span></div></div></div>')
hidePlayOverlay: ->
@$('.start-prompt').remove()
onStateChanged: (state) ->
@$el.removeClass('playing paused')
switch state
when 'playing'
@$el.addClass 'playing'
when 'finished'
@rendererView.stopCursorBlink()
when 'paused'
@$el.addClass 'paused'
@hudView.onPause() if @hudView
when 'resumed'
@$el.addClass 'playing'
@hudView.onResume() if @hudView
renderState: (state) ->
@rendererView.push state
updateTime: (time) ->
@hudView.updateTime time if @hudView
restartCursorBlink: ->
@rendererView.restartCursorBlink()
showCursor: (show) ->
@rendererView.showCursor show

@ -1,104 +0,0 @@
class Asciinema.Renderer.Base extends Backbone.View
events:
'click': 'onClick'
initialize: (options) ->
@cols = options.cols
@lines = options.lines
@showCursor true
@startCursorBlink()
@clearChanges()
@cursor = { x: undefined, y: undefined, visible: true }
requestAnimationFrame @render
width: ->
@cols * @cellWidth
height: ->
@lines * @cellHeight
elementWidth: ->
@$el.outerWidth()
clearChanges: ->
@changes = {}
@dirty = false
onClick: ->
@trigger('terminal-click')
push: (changes) ->
if changes.lines
_(@changes).extend changes.lines
@dirty = true
if changes.cursor
_(@cursor).extend changes.cursor
render: =>
requestAnimationFrame @render
if @dirty
for n, fragments of @changes
c = if @cursor.visible && (parseInt(n) is @cursor.y) then @cursor.x else undefined
@renderLine n, fragments || [], c
@clearChanges()
renderLine: (n, data, cursorX) ->
throw '#renderLine not implemented'
afterInsertedToDom: ->
sample = $('<span class="font-sample"><span class="line"><span>M</span></span></span>')
span = sample.find('span span')
@$el.parent().append sample
@cellWidth = sample.width()
@cellHeight = span.height() +
parseInt(span.css('padding-top')) +
parseInt(span.css('padding-bottom'))
sample.remove()
@fixTerminalElementSize()
@fixPlayerContainerSize()
renderSnapshot: (snapshot) ->
return unless snapshot
i = 0
for line in snapshot
fragments = _(line).map (fragment) ->
fragment[1].bright = fragment[1].bold
[fragment[0], new Asciinema.Brush(fragment[1])]
@renderLine i, fragments, undefined
i++
fixTerminalElementSize: ->
fixPlayerContainerSize: ->
@$el.parent('.player').css(width: @$el.outerWidth() + 'px')
showCursor: (show) ->
throw '#showCursor not implemented'
flipCursor: ->
throw '#flipCursor not implemented'
resetCursorState: ->
startCursorBlink: ->
@cursorTimerId = setInterval(@flipCursor.bind(this), 500)
stopCursorBlink: ->
if @cursorTimerId
clearInterval @cursorTimerId
@cursorTimerId = null
restartCursorBlink: ->
@stopCursorBlink()
@resetCursorState()
@startCursorBlink()
visualBell: ->

@ -1,104 +0,0 @@
class Asciinema.Renderer.Canvas extends Asciinema.Renderer.Base
tagName: 'canvas'
className: 'terminal'
events:
'click': 'onClick'
initialize: (options) ->
super(options)
@ctx = @el.getContext('2d')
@cursorOn = true
@cursorVisible = true
fixTerminalElementSize: ->
@$el.attr('width', @width())
@$el.attr('height', @height())
@setFont()
setFont: ->
size = @$el.css('font-size')
family = @$el.css('font-family')
@font = "#{size} #{family}"
@ctx.font = @font
@prevFont = @font
@ctx.textBaseline = 'bottom'
renderLine: (n, fragments, cursorX) ->
left = 0
width = @cols * @cellWidth
top = n * @cellHeight
cursorText = undefined
rendered = 0
for fragment in fragments
[text, brush] = fragment
brush = Asciinema.Brush.create brush if brush
if cursorX isnt undefined and rendered <= cursorX < rendered + text.length
@cursorBrush = brush
@cursorText = text[cursorX - rendered]
@cursorX = cursorX
@cursorY = n
@setBackgroundAttributes(brush)
@ctx.fillRect left, top, text.length * @cellWidth, @cellHeight
unless text.match(/^\s*$/)
@setTextAttributes(brush)
@ctx.fillText text, left, top + @cellHeight
left += text.length * @cellWidth
rendered += text.length
if cursorX
@renderCursor()
setBackgroundAttributes: (brush) ->
@ctx.fillStyle = Asciinema.colors[brush.bgColor()]
setTextAttributes: (brush) ->
@ctx.fillStyle = Asciinema.colors[brush.fgColor()]
font = @font
if brush.bright or brush.italic
if brush.bright
font = "bold #{font}"
if brush.italic
font = "italic #{font}"
if font != @prevFont
@ctx.font = font
@prevFont = font
renderCursor: ->
return unless @cursorOn and @cursorText
x = @cursorX * @cellWidth
y = @cursorY * @cellHeight
if @cursorVisible
@ctx.fillStyle = Asciinema.colors[7]
@ctx.fillRect x, y, @cellWidth, @cellHeight
@ctx.fillStyle = Asciinema.colors[0]
@ctx.fillText @cursorText, x, y + @cellHeight
else
@ctx.fillStyle = Asciinema.colors[@cursorBrush.bgColor()]
@ctx.fillRect x, y, @cellWidth, @cellHeight
@ctx.fillStyle = Asciinema.colors[@cursorBrush.fgColor()]
@ctx.fillText @cursorText, x, y + @cellHeight
showCursor: (show) ->
@cursorOn = show
flipCursor: ->
@cursorVisible = !@cursorVisible
@renderCursor()
resetCursorState: ->
@cursorVisible = true
@renderCursor()

@ -1,129 +0,0 @@
class Asciinema.Renderer.Pre extends Asciinema.Renderer.Base
tagName: 'pre'
className: 'terminal'
initialize: (options) ->
super(options)
@cachedSpans = {}
@createChildElements()
createChildElements: ->
i = 0
while i < @lines
row = $("<span class=\"line\">")
@$el.append row
@$el.append "\n"
i++
fixTerminalElementSize: ->
@$el.css(width: @width() + 'px', height: @height() + 'px')
render: ->
if @dirty
@$el.find('.cursor').removeClass('cursor').removeClass('flipped')
super
renderLine: (n, fragments, cursorX) ->
html = []
rendered = 0
for fragment in fragments
[text, brush] = fragment
if cursorX isnt undefined and rendered <= cursorX < rendered + text.length
left = text.slice(0, cursorX - rendered)
cursor = text[cursorX - rendered]
right = text.slice(cursorX - rendered + 1)
if left.length > 0
html.push @spanFromBrush(brush)
html.push @escape(left)
html.push '</span>'
html.push @spanFromBrush(brush, true)
html.push @escape(cursor)
html.push '</span>'
if right.length > 0
html.push @spanFromBrush(brush)
html.push @escape(right)
html.push '</span>'
else
html.push @spanFromBrush(brush)
html.push @escape(text)
html.push '</span>'
rendered += text.length
@$el.find(".line:eq(" + n + ")")[0].innerHTML = '<span>' + html.join('') + '</span>'
escape: (text) ->
text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
spanFromBrush: (brush, isCursor) ->
brush = Asciinema.Brush.create brush
key = "#{brush.hash()}_#{isCursor}"
span = @cachedSpans[key]
if not span
span = ""
if brush != Asciinema.Brush.default() || isCursor
if isCursor
span = "<span data-fg=#{brush.fgColor()} data-bg=#{brush.bgColor()} class=\"cursor"
else
span = "<span class=\""
unless brush.hasDefaultFg()
span += " fg" + brush.fgColor()
unless brush.hasDefaultBg()
span += " bg" + brush.bgColor()
if brush.bold
span += " bright"
if brush.underline
span += " underline"
span += "\">"
@cachedSpans[key] = span
span
showCursor: (show) ->
if show
@$el.addClass "cursor-on"
else
@$el.removeClass "cursor-on"
flipCursor: ->
cursor = @$el.find '.cursor'
if cursor.hasClass 'flipped'
@switchCursorColors cursor, false
else
@switchCursorColors cursor, true
resetCursorState: ->
@switchCursorColors @$el.find('.cursor'), false
switchCursorColors: (cursor, flipped) ->
if flipped
fg = cursor.data 'fg'
bg = cursor.data 'bg'
cursor.removeClass "fg#{fg}"
cursor.removeClass "bg#{bg}"
cursor.addClass "fg#{bg} bg#{fg} flipped"
else
fg = cursor.data 'fg'
bg = cursor.data 'bg'
cursor.removeClass "fg#{bg}"
cursor.removeClass "bg#{fg}"
cursor.removeClass 'flipped'
cursor.addClass "fg#{fg} bg#{bg}"

@ -1 +0,0 @@
//= require player/workers/console

@ -1,5 +0,0 @@
console = {
log: function(t) {
postMessage({ message: 'log', text: t });
}
};

@ -1,27 +0,0 @@
movie = undefined
addEventListener 'message', (e) =>
d = e.data
switch d.message
when 'init'
@initialize d.options
when 'call'
switch d.objectName
when 'movie'
movie[d.method](d.args...)
@initialize = (options) ->
movie = new Asciinema.Movie(
stdout_frames: options.stdout_frames
duration: options.duration
speed: options.speed
benchmark: options.benchmark
cols: options.cols
lines: options.lines
)
movie.on 'all', (event, args...) ->
postMessage evt: event, src: 'movie', args: args

@ -1,15 +0,0 @@
class Asciinema.WorkerObjectProxy
constructor: (@webWorker, @objectName) ->
_.extend(this, Backbone.Events)
@webWorker.addEventListener 'message', @onMessage
onMessage: (e) =>
if e.data.evt and e.data.src == @objectName
@trigger e.data.evt, e.data.args...
call: (method, args...) ->
@webWorker.postMessage
message: 'call'
objectName: @objectName
method: method
args: args

@ -1,16 +0,0 @@
class Asciinema.WorkerProxy
constructor: (url) ->
@webWorker = new window.Worker(url)
@webWorker.addEventListener 'message', @onMessage
init: (options) ->
@webWorker.postMessage
message: 'init'
options: options
getObjectProxy: (objectName) ->
new Asciinema.WorkerObjectProxy(@webWorker, objectName)
onMessage: (e) =>
if e.data.message == 'log'
console.log e.data.text

@ -1,27 +0,0 @@
=terminal-font
font-family: 'Bitstream Vera Sans Mono', monospace
font-size: 12px
line-height: 16px
.line
span
padding: 0
display: inline-block
height: 16px
=terminal-font-medium
font-size: 18px
line-height: 24px
.line
span
height: 24px
=terminal-font-big
font-size: 24px
line-height: 32px
.line
span
height: 32px

@ -11,6 +11,7 @@
*= require pages
*= require users
*= require preview
*= require player
*= require asciinema-player
*= require themes/default
*= require contributing
*/

@ -1,6 +1,7 @@
//= require bootstrap
//= require player
//= require source-sans-pro
//= require asciinema-player
//= require themes/default
body.iframe
background-color: transparent

@ -1,5 +0,0 @@
/*
*= require terminal
*= require player/colors
*= require player/player
*/

@ -1,512 +0,0 @@
.fg0 { color: #000000 }
.bg0 { background-color: #000000 }
.fg1 { color: #CC0000 }
.bg1 { background-color: #CC0000 }
.fg2 { color: #4E9A06 }
.bg2 { background-color: #4E9A06 }
.fg3 { color: #C4A000 }
.bg3 { background-color: #C4A000 }
.fg4 { color: #3465A4 }
.bg4 { background-color: #3465A4 }
.fg5 { color: #75507B }
.bg5 { background-color: #75507B }
.fg6 { color: #06989A }
.bg6 { background-color: #06989A }
.fg7 { color: #D3D7CF }
.bg7 { background-color: #D3D7CF }
.fg8 { color: #555753 }
.bg8 { background-color: #555753 }
.fg9 { color: #EF2929 }
.bg9 { background-color: #EF2929 }
.fg10 { color: #8AE234 }
.bg10 { background-color: #8AE234 }
.fg11 { color: #FCE94F }
.bg11 { background-color: #FCE94F }
.fg12 { color: #729FCF }
.bg12 { background-color: #729FCF }
.fg13 { color: #AD7FA8 }
.bg13 { background-color: #AD7FA8 }
.fg14 { color: #34E2E2 }
.bg14 { background-color: #34E2E2 }
.fg15 { color: #EEEEEC }
.bg15 { background-color: #EEEEEC }
.fg16 { color: #000000 }
.bg16 { background-color: #000000 }
.fg17 { color: #00005f }
.bg17 { background-color: #00005f }
.fg18 { color: #000087 }
.bg18 { background-color: #000087 }
.fg19 { color: #0000af }
.bg19 { background-color: #0000af }
.fg20 { color: #0000d7 }
.bg20 { background-color: #0000d7 }
.fg21 { color: #0000ff }
.bg21 { background-color: #0000ff }
.fg22 { color: #005f00 }
.bg22 { background-color: #005f00 }
.fg23 { color: #005f5f }
.bg23 { background-color: #005f5f }
.fg24 { color: #005f87 }
.bg24 { background-color: #005f87 }
.fg25 { color: #005faf }
.bg25 { background-color: #005faf }
.fg26 { color: #005fd7 }
.bg26 { background-color: #005fd7 }
.fg27 { color: #005fff }
.bg27 { background-color: #005fff }
.fg28 { color: #008700 }
.bg28 { background-color: #008700 }
.fg29 { color: #00875f }
.bg29 { background-color: #00875f }
.fg30 { color: #008787 }
.bg30 { background-color: #008787 }
.fg31 { color: #0087af }
.bg31 { background-color: #0087af }
.fg32 { color: #0087d7 }
.bg32 { background-color: #0087d7 }
.fg33 { color: #0087ff }
.bg33 { background-color: #0087ff }
.fg34 { color: #00af00 }
.bg34 { background-color: #00af00 }
.fg35 { color: #00af5f }
.bg35 { background-color: #00af5f }
.fg36 { color: #00af87 }
.bg36 { background-color: #00af87 }
.fg37 { color: #00afaf }
.bg37 { background-color: #00afaf }
.fg38 { color: #00afd7 }
.bg38 { background-color: #00afd7 }
.fg39 { color: #00afff }
.bg39 { background-color: #00afff }
.fg40 { color: #00d700 }
.bg40 { background-color: #00d700 }
.fg41 { color: #00d75f }
.bg41 { background-color: #00d75f }
.fg42 { color: #00d787 }
.bg42 { background-color: #00d787 }
.fg43 { color: #00d7af }
.bg43 { background-color: #00d7af }
.fg44 { color: #00d7d7 }
.bg44 { background-color: #00d7d7 }
.fg45 { color: #00d7ff }
.bg45 { background-color: #00d7ff }
.fg46 { color: #00ff00 }
.bg46 { background-color: #00ff00 }
.fg47 { color: #00ff5f }
.bg47 { background-color: #00ff5f }
.fg48 { color: #00ff87 }
.bg48 { background-color: #00ff87 }
.fg49 { color: #00ffaf }
.bg49 { background-color: #00ffaf }
.fg50 { color: #00ffd7 }
.bg50 { background-color: #00ffd7 }
.fg51 { color: #00ffff }
.bg51 { background-color: #00ffff }
.fg52 { color: #5f0000 }
.bg52 { background-color: #5f0000 }
.fg53 { color: #5f005f }
.bg53 { background-color: #5f005f }
.fg54 { color: #5f0087 }
.bg54 { background-color: #5f0087 }
.fg55 { color: #5f00af }
.bg55 { background-color: #5f00af }
.fg56 { color: #5f00d7 }
.bg56 { background-color: #5f00d7 }
.fg57 { color: #5f00ff }
.bg57 { background-color: #5f00ff }
.fg58 { color: #5f5f00 }
.bg58 { background-color: #5f5f00 }
.fg59 { color: #5f5f5f }
.bg59 { background-color: #5f5f5f }
.fg60 { color: #5f5f87 }
.bg60 { background-color: #5f5f87 }
.fg61 { color: #5f5faf }
.bg61 { background-color: #5f5faf }
.fg62 { color: #5f5fd7 }
.bg62 { background-color: #5f5fd7 }
.fg63 { color: #5f5fff }
.bg63 { background-color: #5f5fff }
.fg64 { color: #5f8700 }
.bg64 { background-color: #5f8700 }
.fg65 { color: #5f875f }
.bg65 { background-color: #5f875f }
.fg66 { color: #5f8787 }
.bg66 { background-color: #5f8787 }
.fg67 { color: #5f87af }
.bg67 { background-color: #5f87af }
.fg68 { color: #5f87d7 }
.bg68 { background-color: #5f87d7 }
.fg69 { color: #5f87ff }
.bg69 { background-color: #5f87ff }
.fg70 { color: #5faf00 }
.bg70 { background-color: #5faf00 }
.fg71 { color: #5faf5f }
.bg71 { background-color: #5faf5f }
.fg72 { color: #5faf87 }
.bg72 { background-color: #5faf87 }
.fg73 { color: #5fafaf }
.bg73 { background-color: #5fafaf }
.fg74 { color: #5fafd7 }
.bg74 { background-color: #5fafd7 }
.fg75 { color: #5fafff }
.bg75 { background-color: #5fafff }
.fg76 { color: #5fd700 }
.bg76 { background-color: #5fd700 }
.fg77 { color: #5fd75f }
.bg77 { background-color: #5fd75f }
.fg78 { color: #5fd787 }
.bg78 { background-color: #5fd787 }
.fg79 { color: #5fd7af }
.bg79 { background-color: #5fd7af }
.fg80 { color: #5fd7d7 }
.bg80 { background-color: #5fd7d7 }
.fg81 { color: #5fd7ff }
.bg81 { background-color: #5fd7ff }
.fg82 { color: #5fff00 }
.bg82 { background-color: #5fff00 }
.fg83 { color: #5fff5f }
.bg83 { background-color: #5fff5f }
.fg84 { color: #5fff87 }
.bg84 { background-color: #5fff87 }
.fg85 { color: #5fffaf }
.bg85 { background-color: #5fffaf }
.fg86 { color: #5fffd7 }
.bg86 { background-color: #5fffd7 }
.fg87 { color: #5fffff }
.bg87 { background-color: #5fffff }
.fg88 { color: #870000 }
.bg88 { background-color: #870000 }
.fg89 { color: #87005f }
.bg89 { background-color: #87005f }
.fg90 { color: #870087 }
.bg90 { background-color: #870087 }
.fg91 { color: #8700af }
.bg91 { background-color: #8700af }
.fg92 { color: #8700d7 }
.bg92 { background-color: #8700d7 }
.fg93 { color: #8700ff }
.bg93 { background-color: #8700ff }
.fg94 { color: #875f00 }
.bg94 { background-color: #875f00 }
.fg95 { color: #875f5f }
.bg95 { background-color: #875f5f }
.fg96 { color: #875f87 }
.bg96 { background-color: #875f87 }
.fg97 { color: #875faf }
.bg97 { background-color: #875faf }
.fg98 { color: #875fd7 }
.bg98 { background-color: #875fd7 }
.fg99 { color: #875fff }
.bg99 { background-color: #875fff }
.fg100 { color: #878700 }
.bg100 { background-color: #878700 }
.fg101 { color: #87875f }
.bg101 { background-color: #87875f }
.fg102 { color: #878787 }
.bg102 { background-color: #878787 }
.fg103 { color: #8787af }
.bg103 { background-color: #8787af }
.fg104 { color: #8787d7 }
.bg104 { background-color: #8787d7 }
.fg105 { color: #8787ff }
.bg105 { background-color: #8787ff }
.fg106 { color: #87af00 }
.bg106 { background-color: #87af00 }
.fg107 { color: #87af5f }
.bg107 { background-color: #87af5f }
.fg108 { color: #87af87 }
.bg108 { background-color: #87af87 }
.fg109 { color: #87afaf }
.bg109 { background-color: #87afaf }
.fg110 { color: #87afd7 }
.bg110 { background-color: #87afd7 }
.fg111 { color: #87afff }
.bg111 { background-color: #87afff }
.fg112 { color: #87d700 }
.bg112 { background-color: #87d700 }
.fg113 { color: #87d75f }
.bg113 { background-color: #87d75f }
.fg114 { color: #87d787 }
.bg114 { background-color: #87d787 }
.fg115 { color: #87d7af }
.bg115 { background-color: #87d7af }
.fg116 { color: #87d7d7 }
.bg116 { background-color: #87d7d7 }
.fg117 { color: #87d7ff }
.bg117 { background-color: #87d7ff }
.fg118 { color: #87ff00 }
.bg118 { background-color: #87ff00 }
.fg119 { color: #87ff5f }
.bg119 { background-color: #87ff5f }
.fg120 { color: #87ff87 }
.bg120 { background-color: #87ff87 }
.fg121 { color: #87ffaf }
.bg121 { background-color: #87ffaf }
.fg122 { color: #87ffd7 }
.bg122 { background-color: #87ffd7 }
.fg123 { color: #87ffff }
.bg123 { background-color: #87ffff }
.fg124 { color: #af0000 }
.bg124 { background-color: #af0000 }
.fg125 { color: #af005f }
.bg125 { background-color: #af005f }
.fg126 { color: #af0087 }
.bg126 { background-color: #af0087 }
.fg127 { color: #af00af }
.bg127 { background-color: #af00af }
.fg128 { color: #af00d7 }
.bg128 { background-color: #af00d7 }
.fg129 { color: #af00ff }
.bg129 { background-color: #af00ff }
.fg130 { color: #af5f00 }
.bg130 { background-color: #af5f00 }
.fg131 { color: #af5f5f }
.bg131 { background-color: #af5f5f }
.fg132 { color: #af5f87 }
.bg132 { background-color: #af5f87 }
.fg133 { color: #af5faf }
.bg133 { background-color: #af5faf }
.fg134 { color: #af5fd7 }
.bg134 { background-color: #af5fd7 }
.fg135 { color: #af5fff }
.bg135 { background-color: #af5fff }
.fg136 { color: #af8700 }
.bg136 { background-color: #af8700 }
.fg137 { color: #af875f }
.bg137 { background-color: #af875f }
.fg138 { color: #af8787 }
.bg138 { background-color: #af8787 }
.fg139 { color: #af87af }
.bg139 { background-color: #af87af }
.fg140 { color: #af87d7 }
.bg140 { background-color: #af87d7 }
.fg141 { color: #af87ff }
.bg141 { background-color: #af87ff }
.fg142 { color: #afaf00 }
.bg142 { background-color: #afaf00 }
.fg143 { color: #afaf5f }
.bg143 { background-color: #afaf5f }
.fg144 { color: #afaf87 }
.bg144 { background-color: #afaf87 }
.fg145 { color: #afafaf }
.bg145 { background-color: #afafaf }
.fg146 { color: #afafd7 }
.bg146 { background-color: #afafd7 }
.fg147 { color: #afafff }
.bg147 { background-color: #afafff }
.fg148 { color: #afd700 }
.bg148 { background-color: #afd700 }
.fg149 { color: #afd75f }
.bg149 { background-color: #afd75f }
.fg150 { color: #afd787 }
.bg150 { background-color: #afd787 }
.fg151 { color: #afd7af }
.bg151 { background-color: #afd7af }
.fg152 { color: #afd7d7 }
.bg152 { background-color: #afd7d7 }
.fg153 { color: #afd7ff }
.bg153 { background-color: #afd7ff }
.fg154 { color: #afff00 }
.bg154 { background-color: #afff00 }
.fg155 { color: #afff5f }
.bg155 { background-color: #afff5f }
.fg156 { color: #afff87 }
.bg156 { background-color: #afff87 }
.fg157 { color: #afffaf }
.bg157 { background-color: #afffaf }
.fg158 { color: #afffd7 }
.bg158 { background-color: #afffd7 }
.fg159 { color: #afffff }
.bg159 { background-color: #afffff }
.fg160 { color: #d70000 }
.bg160 { background-color: #d70000 }
.fg161 { color: #d7005f }
.bg161 { background-color: #d7005f }
.fg162 { color: #d70087 }
.bg162 { background-color: #d70087 }
.fg163 { color: #d700af }
.bg163 { background-color: #d700af }
.fg164 { color: #d700d7 }
.bg164 { background-color: #d700d7 }
.fg165 { color: #d700ff }
.bg165 { background-color: #d700ff }
.fg166 { color: #d75f00 }
.bg166 { background-color: #d75f00 }
.fg167 { color: #d75f5f }
.bg167 { background-color: #d75f5f }
.fg168 { color: #d75f87 }
.bg168 { background-color: #d75f87 }
.fg169 { color: #d75faf }
.bg169 { background-color: #d75faf }
.fg170 { color: #d75fd7 }
.bg170 { background-color: #d75fd7 }
.fg171 { color: #d75fff }
.bg171 { background-color: #d75fff }
.fg172 { color: #d78700 }
.bg172 { background-color: #d78700 }
.fg173 { color: #d7875f }
.bg173 { background-color: #d7875f }
.fg174 { color: #d78787 }
.bg174 { background-color: #d78787 }
.fg175 { color: #d787af }
.bg175 { background-color: #d787af }
.fg176 { color: #d787d7 }
.bg176 { background-color: #d787d7 }
.fg177 { color: #d787ff }
.bg177 { background-color: #d787ff }
.fg178 { color: #d7af00 }
.bg178 { background-color: #d7af00 }
.fg179 { color: #d7af5f }
.bg179 { background-color: #d7af5f }
.fg180 { color: #d7af87 }
.bg180 { background-color: #d7af87 }
.fg181 { color: #d7afaf }
.bg181 { background-color: #d7afaf }
.fg182 { color: #d7afd7 }
.bg182 { background-color: #d7afd7 }
.fg183 { color: #d7afff }
.bg183 { background-color: #d7afff }
.fg184 { color: #d7d700 }
.bg184 { background-color: #d7d700 }
.fg185 { color: #d7d75f }
.bg185 { background-color: #d7d75f }
.fg186 { color: #d7d787 }
.bg186 { background-color: #d7d787 }
.fg187 { color: #d7d7af }
.bg187 { background-color: #d7d7af }
.fg188 { color: #d7d7d7 }
.bg188 { background-color: #d7d7d7 }
.fg189 { color: #d7d7ff }
.bg189 { background-color: #d7d7ff }
.fg190 { color: #d7ff00 }
.bg190 { background-color: #d7ff00 }
.fg191 { color: #d7ff5f }
.bg191 { background-color: #d7ff5f }
.fg192 { color: #d7ff87 }
.bg192 { background-color: #d7ff87 }
.fg193 { color: #d7ffaf }
.bg193 { background-color: #d7ffaf }
.fg194 { color: #d7ffd7 }
.bg194 { background-color: #d7ffd7 }
.fg195 { color: #d7ffff }
.bg195 { background-color: #d7ffff }
.fg196 { color: #ff0000 }
.bg196 { background-color: #ff0000 }
.fg197 { color: #ff005f }
.bg197 { background-color: #ff005f }
.fg198 { color: #ff0087 }
.bg198 { background-color: #ff0087 }
.fg199 { color: #ff00af }
.bg199 { background-color: #ff00af }
.fg200 { color: #ff00d7 }
.bg200 { background-color: #ff00d7 }
.fg201 { color: #ff00ff }
.bg201 { background-color: #ff00ff }
.fg202 { color: #ff5f00 }
.bg202 { background-color: #ff5f00 }
.fg203 { color: #ff5f5f }
.bg203 { background-color: #ff5f5f }
.fg204 { color: #ff5f87 }
.bg204 { background-color: #ff5f87 }
.fg205 { color: #ff5faf }
.bg205 { background-color: #ff5faf }
.fg206 { color: #ff5fd7 }
.bg206 { background-color: #ff5fd7 }
.fg207 { color: #ff5fff }
.bg207 { background-color: #ff5fff }
.fg208 { color: #ff8700 }
.bg208 { background-color: #ff8700 }
.fg209 { color: #ff875f }
.bg209 { background-color: #ff875f }
.fg210 { color: #ff8787 }
.bg210 { background-color: #ff8787 }
.fg211 { color: #ff87af }
.bg211 { background-color: #ff87af }
.fg212 { color: #ff87d7 }
.bg212 { background-color: #ff87d7 }
.fg213 { color: #ff87ff }
.bg213 { background-color: #ff87ff }
.fg214 { color: #ffaf00 }
.bg214 { background-color: #ffaf00 }
.fg215 { color: #ffaf5f }
.bg215 { background-color: #ffaf5f }
.fg216 { color: #ffaf87 }
.bg216 { background-color: #ffaf87 }
.fg217 { color: #ffafaf }
.bg217 { background-color: #ffafaf }
.fg218 { color: #ffafd7 }
.bg218 { background-color: #ffafd7 }
.fg219 { color: #ffafff }
.bg219 { background-color: #ffafff }
.fg220 { color: #ffd700 }
.bg220 { background-color: #ffd700 }
.fg221 { color: #ffd75f }
.bg221 { background-color: #ffd75f }
.fg222 { color: #ffd787 }
.bg222 { background-color: #ffd787 }
.fg223 { color: #ffd7af }
.bg223 { background-color: #ffd7af }
.fg224 { color: #ffd7d7 }
.bg224 { background-color: #ffd7d7 }
.fg225 { color: #ffd7ff }
.bg225 { background-color: #ffd7ff }
.fg226 { color: #ffff00 }
.bg226 { background-color: #ffff00 }
.fg227 { color: #ffff5f }
.bg227 { background-color: #ffff5f }
.fg228 { color: #ffff87 }
.bg228 { background-color: #ffff87 }
.fg229 { color: #ffffaf }
.bg229 { background-color: #ffffaf }
.fg230 { color: #ffffd7 }
.bg230 { background-color: #ffffd7 }
.fg231 { color: #ffffff }
.bg231 { background-color: #ffffff }
.fg232 { color: #080808 }
.bg232 { background-color: #080808 }
.fg233 { color: #121212 }
.bg233 { background-color: #121212 }
.fg234 { color: #1c1c1c }
.bg234 { background-color: #1c1c1c }
.fg235 { color: #262626 }
.bg235 { background-color: #262626 }
.fg236 { color: #303030 }
.bg236 { background-color: #303030 }
.fg237 { color: #3a3a3a }
.bg237 { background-color: #3a3a3a }
.fg238 { color: #444444 }
.bg238 { background-color: #444444 }
.fg239 { color: #4e4e4e }
.bg239 { background-color: #4e4e4e }
.fg240 { color: #585858 }
.bg240 { background-color: #585858 }
.fg241 { color: #626262 }
.bg241 { background-color: #626262 }
.fg242 { color: #6c6c6c }
.bg242 { background-color: #6c6c6c }
.fg243 { color: #767676 }
.bg243 { background-color: #767676 }
.fg244 { color: #808080 }
.bg244 { background-color: #808080 }
.fg245 { color: #8a8a8a }
.bg245 { background-color: #8a8a8a }
.fg246 { color: #949494 }
.bg246 { background-color: #949494 }
.fg247 { color: #9e9e9e }
.bg247 { background-color: #9e9e9e }
.fg248 { color: #a8a8a8 }
.bg248 { background-color: #a8a8a8 }
.fg249 { color: #b2b2b2 }
.bg249 { background-color: #b2b2b2 }
.fg250 { color: #bcbcbc }
.bg250 { background-color: #bcbcbc }
.fg251 { color: #c6c6c6 }
.bg251 { background-color: #c6c6c6 }
.fg252 { color: #d0d0d0 }
.bg252 { background-color: #d0d0d0 }
.fg253 { color: #dadada }
.bg253 { background-color: #dadada }
.fg254 { color: #e4e4e4 }
.bg254 { background-color: #e4e4e4 }
.fg255 { color: #eeeeee }
.bg255 { background-color: #eeeeee }

@ -1,109 +0,0 @@
@import ../terminal-font
$color4: #eb6841
=player-overlay
z-index: 10
background-repeat: no-repeat
background-position: center
position: absolute
top: 0
left: 0
right: 0
bottom: 0
.player
// float: left;
display: block
padding: 0px
position: relative
border: 3px solid black
box-sizing: content-box
-moz-box-sizing: content-box
-webkit-box-sizing: content-box
.font-sample, .hud
+terminal-font
&.medium-font
border: 4px solid black
.font-sample, .hud
+terminal-font-medium
.hud
height: 24px
&.big-font
border: 6px solid black
.font-sample, .hud
+terminal-font-big
.hud
height: 32px
.loading
+player-overlay
background-image: url(image-path("loader.gif"))
.start-prompt
+player-overlay
z-index: 20
cursor: pointer
.play-button
font-size: 100px
.hud
padding: 0
margin: 0
border: 0
background-color: #eee
opacity: 0
position: absolute
left: 0
right: 0
bottom: 0
height: 16px
overflow: hidden
color: black
-webkit-transition: opacity 0.3s ease-in-out
.toggle
background-color: black
color: white
cursor: pointer
.play
display: inline
.pause
display: none
.progress
color: black
cursor: pointer
span:hover
background-color: #777
.time
background-color: black
color: white
&.playing
.hud .toggle
background-color: $color4
.play
display: none
.pause
display: inline
&:hover .hud
opacity: 1.0
pre
border-radius: 0

@ -56,3 +56,21 @@
abbr
border-bottom: 0
.play-button
position: absolute
left: 0
top: 0
right: 0
bottom: 0
text-align: center
color: white
.arrow
width: 100%
height: 100%
display: table
span
vertical-align: middle
display: table-cell

@ -1,64 +0,0 @@
@import terminal-font
pre.terminal
+terminal-font
box-sizing: content-box
-moz-box-sizing: content-box
-webkit-box-sizing: content-box
overflow: hidden
padding: 0
margin: 0px
display: block
white-space: pre
background-color: black
color: #ccc
border: 0
word-wrap: normal
word-break: normal
// bootstrap overrides
border-radius: 0
&.cursor-on
.line
.cursor.visible
background-color: #D3D7CF
.bright
font-weight: bold
.underline
text-decoration: underline
.italic
font-style: italic
.fg8, .fg9, .fg10, .fg11, .fg12, .fg13, .fg14, .fg15
font-weight: bold
.medium-font
pre.terminal
+terminal-font-medium
.big-font
pre.terminal
+terminal-font-big
.play-button
position: absolute
left: 0
top: 0
right: 0
bottom: 0
text-align: center
color: white
.arrow
width: 100%
height: 100%
display: table
span
vertical-align: middle
display: table-cell

@ -12,11 +12,11 @@ class BrushDecorator < ApplicationDecorator
private
def fg_class
"fg#{model.fg}" if model.fg
"fg-#{model.fg}" if model.fg
end
def bg_class
"bg#{model.bg}" if model.bg
"bg-#{model.bg}" if model.bg
end
def bold_class

@ -5,22 +5,8 @@ class PlaybackOptions
attribute :speed, Float, default: 1.0
attribute :size, String, default: 'small'
attribute :autoplay, Boolean, default: false
attribute :max_width, Integer
attribute :hide_hud, Boolean, default: false
attribute :fallback, Boolean, default: false
attribute :renderer, String, default: 'Pre'
attribute :benchmark, Boolean, default: false
def player_class
if fallback
"Asciinema.FallbackPlayer"
else
"window.Worker ? Asciinema.Player : Asciinema.FallbackPlayer"
end
end
def renderer_class
"Asciinema.Renderer.#{renderer}"
end
end

@ -7,7 +7,7 @@ javascript:
$(function() {
var target = parent.postMessage ? parent : (parent.document.postMessage ? parent.document : undefined);
if (typeof target != "undefined" && window !== window.parent) {
var w = $(document).width();
var w = $('.asciinema-player').width();
var h = $(document).height();
target.postMessage(['asciicast:size', { id: #{page.asciicast_id}, width: w, height: h }], '*');
}

@ -21,22 +21,22 @@
}
function params(container, script) {
var params = '?max_width=' + container.offsetWidth;
var params = [];
var size = script.getAttribute('data-size');
if (size) {
params += '&size=' + size;
params = params.concat(['size=' + size]);
}
var speed = script.getAttribute('data-speed');
if (speed) {
params += '&speed=' + speed;
params = params.concat(['speed=' + speed]);
}
var autoplay = script.getAttribute('data-autoplay');
if (autoplay === '1') {
params += '&autoplay=' + autoplay;
params = params.concat(['autoplay=' + autoplay]);
}
return params;
return '?' + params.join('&');
}
function insertPlayer(script) {
@ -59,7 +59,8 @@
iframe.style.overflow = "hidden";
iframe.style.margin = 0;
iframe.style.border = 0;
iframe.style.display = "block";
iframe.style.display = "inline-block";
iframe.style.width = "100%";
iframe.style.float = "none";
iframe.style.visibility = "hidden";
iframe.onload = function() { this.style.visibility = 'visible' };

@ -1,18 +1,34 @@
.player class="#{options.size}-font"
.player
p.processing-info style="display: none"
| This recording is being pre-processed at the moment. It will open automatically in a few seconds.
javascript:
$(function() {
var playerClass = #{options.player_class};
var maxWidth = #{options.max_width || 'null'};
var model = new Asciinema.Asciicast(#{asciicast.html_safe});
function createPlayer() {
var source = new asciinema.HttpArraySource(model.get('stdout_frames_url'), #{options.speed});
var snapshot = model.get('snapshot');
var movie = new asciinema.Movie(model.get('width'), model.get('height'), source, snapshot, model.get('duration'));
React.renderComponent(
asciinema.Player({ fontSize: '#{options.size}', autoPlay: #{options.autoplay}, movie: movie }),
$('.player')[0]
);
}
function tryCreatePlayer() {
if (model.get('stdout_frames_url')) {
$('.processing-info').remove();
createPlayer();
} else {
$('.processing-info').show();
setTimeout(function() {
model.fetch({ success: tryCreatePlayer });
}, 2000);
}
}
window.player = new playerClass({
el: $('.player'),
speed: #{options.speed},
benchmark: #{options.benchmark},
model: new Asciinema.Asciicast(#{asciicast.html_safe}),
maxWidth: maxWidth || $('.cinema .player').parent().width(),
rendererClass: #{options.renderer_class},
autoPlay: #{options.autoplay},
hud: #{!options.hide_hud}
});
tryCreatePlayer();
});

@ -4,7 +4,7 @@
.play-button
span.arrow
span.glyphicon.glyphicon-play
.thumbnail
.thumbnail.asciinema-theme-default
= asciicast.thumbnail(100, 15)
.info.clearfix

@ -1,4 +1,4 @@
pre.terminal
pre.asciinema-terminal.font-small
- for line in thumbnail.lines
span.line
- for cell in line

@ -5,7 +5,7 @@ p
Some pilots get picked and become television programs. Some don't, become
nothing. She starred in one of the ones that became nothing.
script[type="text/javascript" src=asciicast_url(@asciicast, format: 'js') id="asciicast-#{@asciicast.id}" async]
script[type="text/javascript" src=asciicast_url(@asciicast, format: 'js') id="asciicast-#{@asciicast.id}" async data-speed="2"]
p
' Now that there is the Tec-9, a crappy spray gun from South Miami. This gun is

@ -1,3 +1,5 @@
require 'spec_helper'
describe BrushDecorator do
let(:decorator) { described_class.new(brush) }
let(:brush) { double('brush', :fg => nil, :bg => nil, :bold? => false,
@ -32,7 +34,7 @@ describe BrushDecorator do
allow(brush).to receive(:fg) { 1 }
end
it { should match(/\bfg1\b/) }
it { should match(/\bfg-1\b/) }
end
context "when bg is default" do
@ -48,7 +50,7 @@ describe BrushDecorator do
allow(brush).to receive(:bg) { 2 }
end
it { should match(/\bbg2\b/) }
it { should match(/\bbg-2\b/) }
end
context "when both fg and bg are non-default" do
@ -57,8 +59,8 @@ describe BrushDecorator do
allow(brush).to receive(:bg) { 2 }
end
it { should match(/\bfg1\b/) }
it { should match(/\bbg2\b/) }
it { should match(/\bfg-1\b/) }
it { should match(/\bbg-2\b/) }
end
context "when it's bold" do

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,143 @@
/*!
* screenfull
* v1.1.1 - 2013-11-20
* https://github.com/sindresorhus/screenfull.js
* (c) Sindre Sorhus; MIT License
*/
/*global Element */
(function (window, document) {
'use strict';
var keyboardAllowed = typeof Element !== 'undefined' && 'ALLOW_KEYBOARD_INPUT' in Element, // IE6 throws without typeof check
fn = (function () {
var val, valLength;
var fnMap = [
[
'requestFullscreen',
'exitFullscreen',
'fullscreenElement',
'fullscreenEnabled',
'fullscreenchange',
'fullscreenerror'
],
// new WebKit
[
'webkitRequestFullscreen',
'webkitExitFullscreen',
'webkitFullscreenElement',
'webkitFullscreenEnabled',
'webkitfullscreenchange',
'webkitfullscreenerror'
],
// old WebKit (Safari 5.1)
[
'webkitRequestFullScreen',
'webkitCancelFullScreen',
'webkitCurrentFullScreenElement',
'webkitCancelFullScreen',
'webkitfullscreenchange',
'webkitfullscreenerror'
],
[
'mozRequestFullScreen',
'mozCancelFullScreen',
'mozFullScreenElement',
'mozFullScreenEnabled',
'mozfullscreenchange',
'mozfullscreenerror'
],
[
'msRequestFullscreen',
'msExitFullscreen',
'msFullscreenElement',
'msFullscreenEnabled',
'MSFullscreenChange',
'MSFullscreenError'
]
];
var i = 0;
var l = fnMap.length;
var ret = {};
for (; i < l; i++) {
val = fnMap[i];
if (val && val[1] in document) {
for (i = 0, valLength = val.length; i < valLength; i++) {
ret[fnMap[0][i]] = val[i];
}
return ret;
}
}
return false;
})(),
screenfull = {
request: function (elem) {
var request = fn.requestFullscreen;
elem = elem || document.documentElement;
// Work around Safari 5.1 bug: reports support for
// keyboard in fullscreen even though it doesn't.
// Browser sniffing, since the alternative with
// setTimeout is even worse.
if (/5\.1[\.\d]* Safari/.test(navigator.userAgent)) {
elem[request]();
} else {
elem[request](keyboardAllowed && Element.ALLOW_KEYBOARD_INPUT);
}
},
exit: function () {
document[fn.exitFullscreen]();
},
toggle: function (elem) {
if (this.isFullscreen) {
this.exit();
} else {
this.request(elem);
}
},
onchange: function () {},
onerror: function () {},
raw: fn
};
if (!fn) {
window.screenfull = false;
return;
}
Object.defineProperties(screenfull, {
isFullscreen: {
get: function () {
return !!document[fn.fullscreenElement];
}
},
element: {
enumerable: true,
get: function () {
return document[fn.fullscreenElement];
}
},
enabled: {
enumerable: true,
get: function () {
// Coerce to boolean in case of old WebKit
return !!document[fn.fullscreenEnabled];
}
}
});
document.addEventListener(fn.fullscreenchange, function (e) {
screenfull.onchange.call(screenfull, e);
});
document.addEventListener(fn.fullscreenerror, function (e) {
screenfull.onerror.call(screenfull, e);
});
window.screenfull = screenfull;
})(window, document);

File diff suppressed because it is too large Load Diff

@ -0,0 +1,35 @@
.asciinema-theme-default .asciinema-terminal {color: #CCCCCC;background-color: #121314}
.asciinema-theme-default .fg-bg {color: #121314}
.asciinema-theme-default .bg-fg {background-color: #CCCCCC}
.asciinema-theme-default .fg-0 { color: #000000 }
.asciinema-theme-default .bg-0 { background-color: #000000 }
.asciinema-theme-default .fg-1 { color: #CC0000 }
.asciinema-theme-default .bg-1 { background-color: #CC0000 }
.asciinema-theme-default .fg-2 { color: #4E9A06 }
.asciinema-theme-default .bg-2 { background-color: #4E9A06 }
.asciinema-theme-default .fg-3 { color: #C4A000 }
.asciinema-theme-default .bg-3 { background-color: #C4A000 }
.asciinema-theme-default .fg-4 { color: #3465A4 }
.asciinema-theme-default .bg-4 { background-color: #3465A4 }
.asciinema-theme-default .fg-5 { color: #75507B }
.asciinema-theme-default .bg-5 { background-color: #75507B }
.asciinema-theme-default .fg-6 { color: #06989A }
.asciinema-theme-default .bg-6 { background-color: #06989A }
.asciinema-theme-default .fg-7 { color: #D3D7CF }
.asciinema-theme-default .bg-7 { background-color: #D3D7CF }
.asciinema-theme-default .fg-8 { color: #555753 }
.asciinema-theme-default .bg-8 { background-color: #555753 }
.asciinema-theme-default .fg-9 { color: #EF2929 }
.asciinema-theme-default .bg-9 { background-color: #EF2929 }
.asciinema-theme-default .fg-10 { color: #8AE234 }
.asciinema-theme-default .bg-10 { background-color: #8AE234 }
.asciinema-theme-default .fg-11 { color: #FCE94F }
.asciinema-theme-default .bg-11 { background-color: #FCE94F }
.asciinema-theme-default .fg-12 { color: #729FCF }
.asciinema-theme-default .bg-12 { background-color: #729FCF }
.asciinema-theme-default .fg-13 { color: #AD7FA8 }
.asciinema-theme-default .bg-13 { background-color: #AD7FA8 }
.asciinema-theme-default .fg-14 { color: #34E2E2 }
.asciinema-theme-default .bg-14 { background-color: #34E2E2 }
.asciinema-theme-default .fg-15 { color: #EEEEEC }
.asciinema-theme-default .bg-15 { background-color: #EEEEEC }
Loading…
Cancel
Save