start integrating flowerbox tests
This commit is contained in:
parent
f0dd789e86
commit
5ac54f8414
|
@ -1,3 +1,6 @@
|
||||||
|
.tmp/
|
||||||
|
chromedriver.log
|
||||||
|
node_modules/
|
||||||
*.gem
|
*.gem
|
||||||
*.rbc
|
*.rbc
|
||||||
.bundle
|
.bundle
|
||||||
|
|
4
Gemfile
4
Gemfile
|
@ -2,3 +2,7 @@ source 'https://rubygems.org'
|
||||||
|
|
||||||
# Specify your gem's dependencies in attentive.gemspec
|
# Specify your gem's dependencies in attentive.gemspec
|
||||||
gemspec
|
gemspec
|
||||||
|
|
||||||
|
gem 'flowerbox', :path => '../flowerbox'
|
||||||
|
gem 'flowerbox-delivery', :path => '../flowerbox-delivery'
|
||||||
|
gem 'guard'
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
require 'guard'
|
||||||
|
require 'guard/guard'
|
||||||
|
|
||||||
|
require 'flowerbox'
|
||||||
|
|
||||||
|
class ::Guard::FlowerboxUnit < ::Guard::Guard
|
||||||
|
def run_all
|
||||||
|
::Flowerbox.run('spec/javascripts')
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_on_change(files)
|
||||||
|
run_all
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ::Guard::FlowerboxIntegration < ::Guard::Guard
|
||||||
|
def run_all
|
||||||
|
::Flowerbox.run('js-features')
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_on_change(files)
|
||||||
|
run_all
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
guard 'flowerbox-unit' do
|
||||||
|
watch(%r{^spec/javascripts})
|
||||||
|
end
|
||||||
|
|
||||||
|
guard 'flowerbox-integration' do
|
||||||
|
watch(%r{^js-features})
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
Feature: Presentation Timer
|
||||||
|
Background:
|
||||||
|
Given I have a presentation counter
|
||||||
|
|
||||||
|
Scenario: Render
|
||||||
|
When I render the counter
|
||||||
|
Then the counter should show the time "00:00"
|
||||||
|
And the counter should not be running
|
||||||
|
|
||||||
|
Scenario: Start the timer
|
||||||
|
When I start the timer
|
||||||
|
Then the counter should be running
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
Flowerbox.configure do |c|
|
||||||
|
c.test_with :cucumber
|
||||||
|
c.run_with :chrome
|
||||||
|
|
||||||
|
c.asset_paths << "lib/assets/javascripts"
|
||||||
|
c.spec_patterns << "**/*.js*"
|
||||||
|
c.spec_patterns << "*.js*"
|
||||||
|
c.spec_patterns << "**/*.feature"
|
||||||
|
c.spec_patterns << "*.feature"
|
||||||
|
|
||||||
|
c.report_with :verbose
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#= require attentive/presentation_timer
|
||||||
|
#
|
||||||
|
Flowerbox.Given /I have a presentation counter/, ->
|
||||||
|
@timer = new Attentive.PresentationTimer()
|
||||||
|
@timer.render()
|
|
@ -0,0 +1,7 @@
|
||||||
|
Flowerbox.Then /^the counter (should|should not) be running$/, (state) ->
|
||||||
|
switch state
|
||||||
|
when 'should'
|
||||||
|
@expect(@timer).toBeRunning()
|
||||||
|
when 'should not'
|
||||||
|
@expect(@timer).not.toBeRunning()
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
Flowerbox.Then /^the counter (should|should not) show the time "([^"]+)"$/, (state, time) ->
|
||||||
|
content = @timer.ensureEl().innerHTML
|
||||||
|
|
||||||
|
switch state
|
||||||
|
when 'should'
|
||||||
|
@expect(content).toEqual(time)
|
||||||
|
when 'should not'
|
||||||
|
@expect(content).not.toEqual(time)
|
|
@ -0,0 +1,3 @@
|
||||||
|
Flowerbox.Then /^it should count up$/, ->
|
||||||
|
@pending()
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Flowerbox.When /^I render the counter$/, ->
|
||||||
|
@timer.render()
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Flowerbox.When /^I start the timer$/, ->
|
||||||
|
@timer.start()
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Flowerbox.When /^I wait (\d+) seconds?$/, (secs) ->
|
||||||
|
Flowerbox.pause(Number(secs) * 1000)
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
Flowerbox.World ->
|
||||||
|
@addMatchers(
|
||||||
|
toBeRunning: () ->
|
||||||
|
@message = "Expected #{@notMessage} be running"
|
||||||
|
@actual._runner?
|
||||||
|
)
|
||||||
|
|
|
@ -1,212 +1,5 @@
|
||||||
|
#= require attentive/presentation
|
||||||
|
#= require attentive/slide
|
||||||
|
#= require attentive/presentation_timer
|
||||||
#= require underscore
|
#= require underscore
|
||||||
#
|
|
||||||
class PresentationTimer
|
|
||||||
constructor: ->
|
|
||||||
@time = 0
|
|
||||||
@el = document.createElement('div')
|
|
||||||
@el.classList.add('timer')
|
|
||||||
|
|
||||||
this.render()
|
|
||||||
|
|
||||||
render: ->
|
|
||||||
@el.innerHTML = this.formattedTime()
|
|
||||||
|
|
||||||
start: ->
|
|
||||||
@_runner = this.runner()
|
|
||||||
@el.classList.add('running')
|
|
||||||
|
|
||||||
runner: ->
|
|
||||||
setTimeout(
|
|
||||||
=>
|
|
||||||
this.render()
|
|
||||||
@time += 1
|
|
||||||
this.runner() if @_runner?
|
|
||||||
, 1000
|
|
||||||
)
|
|
||||||
|
|
||||||
stop: ->
|
|
||||||
clearTimeout(@_runner)
|
|
||||||
@el.classList.remove('running')
|
|
||||||
@_runner = null
|
|
||||||
|
|
||||||
reset: ->
|
|
||||||
this.stop()
|
|
||||||
@time = 0
|
|
||||||
this.render()
|
|
||||||
|
|
||||||
toggle: ->
|
|
||||||
if @_runner?
|
|
||||||
this.stop()
|
|
||||||
else
|
|
||||||
this.start()
|
|
||||||
|
|
||||||
toggleVisible: ->
|
|
||||||
@el.classList.toggle('hide')
|
|
||||||
|
|
||||||
isVisible: ->
|
|
||||||
!@el.classList.contains('hide')
|
|
||||||
|
|
||||||
hide: ->
|
|
||||||
@el.classList.add('hide')
|
|
||||||
|
|
||||||
formattedTime: ->
|
|
||||||
minute = "00#{Math.floor(@time / 60)}".slice(-2)
|
|
||||||
second = "00#{@time % 60}".slice(-2)
|
|
||||||
|
|
||||||
"#{minute}:#{second}"
|
|
||||||
|
|
||||||
class Slide
|
|
||||||
@fromList: (list) ->
|
|
||||||
result = (new Slide(slide) for slide in list)
|
|
||||||
|
|
||||||
constructor: (@dom) ->
|
|
||||||
|
|
||||||
recalculate: =>
|
|
||||||
@dom.style['width'] = "#{window.innerWidth}px"
|
|
||||||
|
|
||||||
currentMarginTop = Number(@dom.style['marginTop'].replace(/[^\d\.]/g, ''))
|
|
||||||
height = (window.innerHeight - @dom.querySelector('.content').clientHeight) / 2
|
|
||||||
|
|
||||||
if height != currentMarginTop
|
|
||||||
@dom.style['marginTop'] = "#{height}px"
|
|
||||||
true
|
|
||||||
|
|
||||||
activate: =>
|
|
||||||
@dom.classList.add('active')
|
|
||||||
|
|
||||||
deactivate: =>
|
|
||||||
@dom.classList.remove('active')
|
|
||||||
|
|
||||||
class this.Attentive
|
|
||||||
@setup: (identifier) ->
|
|
||||||
starter = ->
|
|
||||||
setTimeout(
|
|
||||||
->
|
|
||||||
(new Attentive(identifier)).start()
|
|
||||||
, 250
|
|
||||||
)
|
|
||||||
window.addEventListener('DOMContentLoaded', starter, false)
|
|
||||||
|
|
||||||
constructor: (@identifier) ->
|
|
||||||
@length = @allSlides().length
|
|
||||||
@priorSlide = null
|
|
||||||
@initialRender = true
|
|
||||||
|
|
||||||
@timer = new PresentationTimer()
|
|
||||||
@timer.hide()
|
|
||||||
|
|
||||||
@currentWindowHeight = null
|
|
||||||
|
|
||||||
document.querySelector('body').appendChild(@timer.el)
|
|
||||||
|
|
||||||
bodyClassList: ->
|
|
||||||
@_bodyClassList ||= document.querySelector('body').classList
|
|
||||||
|
|
||||||
allSlides: ->
|
|
||||||
@_allSlides ||= Slide.fromList(@slidesViewer().querySelectorAll('.slide'))
|
|
||||||
|
|
||||||
slidesViewer: ->
|
|
||||||
@_slidesViewer ||= document.querySelector(@identifier)
|
|
||||||
|
|
||||||
start: ->
|
|
||||||
if !this.isFile()
|
|
||||||
window.addEventListener('popstate', @handlePopState, false)
|
|
||||||
|
|
||||||
document.addEventListener('click', @handleClick, false)
|
|
||||||
document.addEventListener('keydown', @handleKeyDown, false)
|
|
||||||
window.addEventListener('resize', _.throttle(@calculate, 500), false)
|
|
||||||
|
|
||||||
imageWait = null
|
|
||||||
imageWait = =>
|
|
||||||
wait = false
|
|
||||||
|
|
||||||
for slide in @allSlides()
|
|
||||||
for img in slide.dom.getElementsByTagName('img')
|
|
||||||
wait = true if !img.complete
|
|
||||||
|
|
||||||
if wait
|
|
||||||
setTimeout(imageWait, 100)
|
|
||||||
else
|
|
||||||
this.advanceTo(this.slideFromLocation())
|
|
||||||
|
|
||||||
imageWait()
|
|
||||||
|
|
||||||
slideFromLocation: ->
|
|
||||||
value = if this.isFile()
|
|
||||||
location.hash
|
|
||||||
else
|
|
||||||
location.pathname
|
|
||||||
|
|
||||||
Number(value.substr(1))
|
|
||||||
|
|
||||||
handlePopState: (e) =>
|
|
||||||
this.advanceTo(if e.state then e.state.index else this.slideFromLocation())
|
|
||||||
|
|
||||||
handleClick: (e) =>
|
|
||||||
this.advance() if e.target.tagName != 'A'
|
|
||||||
|
|
||||||
handleKeyDown: (e) =>
|
|
||||||
switch e.keyCode
|
|
||||||
when 72
|
|
||||||
this.advanceTo(0)
|
|
||||||
when 37
|
|
||||||
this.advance(-1)
|
|
||||||
when 39, 32
|
|
||||||
this.advance()
|
|
||||||
when 220
|
|
||||||
@timer.reset()
|
|
||||||
when 84
|
|
||||||
if e.shiftKey
|
|
||||||
@timer.toggleVisible()
|
|
||||||
else
|
|
||||||
@timer.toggle() if @timer.isVisible()
|
|
||||||
|
|
||||||
advance: (offset = 1) =>
|
|
||||||
this.advanceTo(Math.max(Math.min(@currentSlide + offset, @length - 1), 0))
|
|
||||||
|
|
||||||
isFile: => location.href.slice(0, 4) == 'file'
|
|
||||||
|
|
||||||
advanceTo: (index) =>
|
|
||||||
@priorSlide = @currentSlide
|
|
||||||
@currentSlide = index || 0
|
|
||||||
|
|
||||||
this.calculate()
|
|
||||||
|
|
||||||
if this.isFile()
|
|
||||||
location.hash = @currentSlide
|
|
||||||
else
|
|
||||||
history.pushState({ index: @currentSlide }, '', @currentSlide)
|
|
||||||
|
|
||||||
calculate: =>
|
|
||||||
if @currentWindowHeight != window.innerHeight
|
|
||||||
recalculate = true
|
|
||||||
times = 3
|
|
||||||
|
|
||||||
while recalculate and times > 0
|
|
||||||
recalculate = false
|
|
||||||
times -= 1
|
|
||||||
|
|
||||||
for slide in @allSlides()
|
|
||||||
recalculate = true if slide.recalculate()
|
|
||||||
|
|
||||||
@currentWindowHeight = window.innerHeight
|
|
||||||
|
|
||||||
@slidesViewer().style['width'] = "#{window.innerWidth * @allSlides().length}px"
|
|
||||||
|
|
||||||
this.align()
|
|
||||||
|
|
||||||
getCurrentSlide: =>
|
|
||||||
@allSlides()[@currentSlide]
|
|
||||||
|
|
||||||
align: =>
|
|
||||||
@allSlides()[@priorSlide].deactivate() if @priorSlide
|
|
||||||
this.getCurrentSlide().activate()
|
|
||||||
|
|
||||||
@slidesViewer().style['left'] = "-#{@currentSlide * window.innerWidth}px"
|
|
||||||
|
|
||||||
if @initialRender
|
|
||||||
@bodyClassList().remove('loading')
|
|
||||||
|
|
||||||
@initialRender = false
|
|
||||||
@currentWindowHeight = null
|
|
||||||
this.calculate()
|
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
if !Attentive? then Attentive = {}
|
||||||
|
|
||||||
|
class Attentive.Presentation
|
||||||
|
@setup: (identifier) ->
|
||||||
|
starter = ->
|
||||||
|
setTimeout(
|
||||||
|
->
|
||||||
|
(new Attentive.Presentation(identifier)).start()
|
||||||
|
, 250
|
||||||
|
)
|
||||||
|
window.addEventListener('DOMContentLoaded', starter, false)
|
||||||
|
|
||||||
|
constructor: (@identifier) ->
|
||||||
|
@length = @allSlides().length
|
||||||
|
@priorSlide = null
|
||||||
|
@initialRender = true
|
||||||
|
|
||||||
|
@timer = new Attentive.PresentationTimer()
|
||||||
|
@timer.hide()
|
||||||
|
|
||||||
|
@currentWindowHeight = null
|
||||||
|
|
||||||
|
document.querySelector('body').appendChild(@timer.el)
|
||||||
|
|
||||||
|
bodyClassList: ->
|
||||||
|
@_bodyClassList ||= document.querySelector('body').classList
|
||||||
|
|
||||||
|
allSlides: ->
|
||||||
|
@_allSlides ||= Attentive.Slide.fromList(@slidesViewer().querySelectorAll('.slide'))
|
||||||
|
|
||||||
|
slidesViewer: ->
|
||||||
|
@_slidesViewer ||= document.querySelector(@identifier)
|
||||||
|
|
||||||
|
start: ->
|
||||||
|
if !this.isFile()
|
||||||
|
window.addEventListener('popstate', @handlePopState, false)
|
||||||
|
|
||||||
|
@timer.render()
|
||||||
|
|
||||||
|
document.addEventListener('click', @handleClick, false)
|
||||||
|
document.addEventListener('keydown', @handleKeyDown, false)
|
||||||
|
window.addEventListener('resize', _.throttle(@calculate, 500), false)
|
||||||
|
|
||||||
|
imageWait = null
|
||||||
|
imageWait = =>
|
||||||
|
wait = false
|
||||||
|
|
||||||
|
for slide in @allSlides()
|
||||||
|
for img in slide.dom.getElementsByTagName('img')
|
||||||
|
wait = true if !img.complete
|
||||||
|
|
||||||
|
if wait
|
||||||
|
setTimeout(imageWait, 100)
|
||||||
|
else
|
||||||
|
this.advanceTo(this.slideFromLocation())
|
||||||
|
|
||||||
|
imageWait()
|
||||||
|
|
||||||
|
slideFromLocation: ->
|
||||||
|
value = if this.isFile()
|
||||||
|
location.hash
|
||||||
|
else
|
||||||
|
location.pathname
|
||||||
|
|
||||||
|
Number(value.substr(1))
|
||||||
|
|
||||||
|
handlePopState: (e) =>
|
||||||
|
this.advanceTo(if e.state then e.state.index else this.slideFromLocation())
|
||||||
|
|
||||||
|
handleClick: (e) =>
|
||||||
|
this.advance() if e.target.tagName != 'A'
|
||||||
|
|
||||||
|
handleKeyDown: (e) =>
|
||||||
|
switch e.keyCode
|
||||||
|
when 72
|
||||||
|
this.advanceTo(0)
|
||||||
|
when 37
|
||||||
|
this.advance(-1)
|
||||||
|
when 39, 32
|
||||||
|
this.advance()
|
||||||
|
when 220
|
||||||
|
@timer.reset()
|
||||||
|
when 84
|
||||||
|
if e.shiftKey
|
||||||
|
@timer.toggleVisible()
|
||||||
|
else
|
||||||
|
@timer.toggle() if @timer.isVisible()
|
||||||
|
|
||||||
|
advance: (offset = 1) =>
|
||||||
|
this.advanceTo(Math.max(Math.min(@currentSlide + offset, @length - 1), 0))
|
||||||
|
|
||||||
|
isFile: => location.href.slice(0, 4) == 'file'
|
||||||
|
|
||||||
|
advanceTo: (index) =>
|
||||||
|
@priorSlide = @currentSlide
|
||||||
|
@currentSlide = index || 0
|
||||||
|
|
||||||
|
this.calculate()
|
||||||
|
|
||||||
|
if this.isFile()
|
||||||
|
location.hash = @currentSlide
|
||||||
|
else
|
||||||
|
history.pushState({ index: @currentSlide }, '', @currentSlide)
|
||||||
|
|
||||||
|
calculate: =>
|
||||||
|
if @currentWindowHeight != window.innerHeight
|
||||||
|
recalculate = true
|
||||||
|
times = 3
|
||||||
|
|
||||||
|
while recalculate and times > 0
|
||||||
|
recalculate = false
|
||||||
|
times -= 1
|
||||||
|
|
||||||
|
for slide in @allSlides()
|
||||||
|
recalculate = true if slide.recalculate()
|
||||||
|
|
||||||
|
@currentWindowHeight = window.innerHeight
|
||||||
|
|
||||||
|
@slidesViewer().style['width'] = "#{window.innerWidth * @allSlides().length}px"
|
||||||
|
|
||||||
|
this.align()
|
||||||
|
|
||||||
|
getCurrentSlide: =>
|
||||||
|
@allSlides()[@currentSlide]
|
||||||
|
|
||||||
|
align: =>
|
||||||
|
@allSlides()[@priorSlide].deactivate() if @priorSlide
|
||||||
|
this.getCurrentSlide().activate()
|
||||||
|
|
||||||
|
@slidesViewer().style['left'] = "-#{@currentSlide * window.innerWidth}px"
|
||||||
|
|
||||||
|
if @initialRender
|
||||||
|
@bodyClassList().remove('loading')
|
||||||
|
|
||||||
|
@initialRender = false
|
||||||
|
@currentWindowHeight = null
|
||||||
|
this.calculate()
|
|
@ -0,0 +1,59 @@
|
||||||
|
if !Attentive? then Attentive = {}
|
||||||
|
|
||||||
|
class Attentive.PresentationTimer
|
||||||
|
constructor: ->
|
||||||
|
@time = 0
|
||||||
|
@el = null
|
||||||
|
|
||||||
|
render: ->
|
||||||
|
@ensureEl().innerHTML = this.formattedTime()
|
||||||
|
|
||||||
|
ensureEl: ->
|
||||||
|
if !@el
|
||||||
|
@el = document.createElement('div')
|
||||||
|
@el.classList.add('timer')
|
||||||
|
@el
|
||||||
|
|
||||||
|
start: ->
|
||||||
|
@_runner = this.runner()
|
||||||
|
@ensureEl().classList.add('running')
|
||||||
|
|
||||||
|
runner: ->
|
||||||
|
setTimeout(
|
||||||
|
=>
|
||||||
|
this.render()
|
||||||
|
@time += 1
|
||||||
|
this.runner() if @_runner?
|
||||||
|
, 1000
|
||||||
|
)
|
||||||
|
|
||||||
|
stop: ->
|
||||||
|
clearTimeout(@_runner)
|
||||||
|
@ensureEl().classList.remove('running')
|
||||||
|
@_runner = null
|
||||||
|
|
||||||
|
reset: ->
|
||||||
|
this.stop()
|
||||||
|
@time = 0
|
||||||
|
this.render()
|
||||||
|
|
||||||
|
toggle: ->
|
||||||
|
if @_runner?
|
||||||
|
this.stop()
|
||||||
|
else
|
||||||
|
this.start()
|
||||||
|
|
||||||
|
toggleVisible: ->
|
||||||
|
@ensureEl().classList.toggle('hide')
|
||||||
|
|
||||||
|
isVisible: ->
|
||||||
|
!@ensureEl().classList.contains('hide')
|
||||||
|
|
||||||
|
hide: ->
|
||||||
|
@ensureEl().classList.add('hide')
|
||||||
|
|
||||||
|
formattedTime: ->
|
||||||
|
minute = "00#{Math.floor(@time / 60)}".slice(-2)
|
||||||
|
second = "00#{@time % 60}".slice(-2)
|
||||||
|
|
||||||
|
"#{minute}:#{second}"
|
|
@ -0,0 +1,24 @@
|
||||||
|
if !Attentive? then Attentive = {}
|
||||||
|
|
||||||
|
class Attentive.Slide
|
||||||
|
@fromList: (list) ->
|
||||||
|
result = (new Attentive.Slide(slide) for slide in list)
|
||||||
|
|
||||||
|
constructor: (@dom) ->
|
||||||
|
|
||||||
|
recalculate: =>
|
||||||
|
@dom.style['width'] = "#{window.innerWidth}px"
|
||||||
|
|
||||||
|
currentMarginTop = Number(@dom.style['marginTop'].replace(/[^\d\.]/g, ''))
|
||||||
|
height = (window.innerHeight - @dom.querySelector('.content').clientHeight) / 2
|
||||||
|
|
||||||
|
if height != currentMarginTop
|
||||||
|
@dom.style['marginTop'] = "#{height}px"
|
||||||
|
true
|
||||||
|
|
||||||
|
activate: =>
|
||||||
|
@dom.classList.add('active')
|
||||||
|
|
||||||
|
deactivate: =>
|
||||||
|
@dom.classList.remove('active')
|
||||||
|
|
|
@ -20,6 +20,8 @@ module Attentive
|
||||||
require 'coffee_script'
|
require 'coffee_script'
|
||||||
require 'sass'
|
require 'sass'
|
||||||
|
|
||||||
|
Tilt::CoffeeScriptTemplate.default_bare = true
|
||||||
|
|
||||||
# make sure pygments is ready before starting a new thread
|
# make sure pygments is ready before starting a new thread
|
||||||
Pygments.highlight("attentive")
|
Pygments.highlight("attentive")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
.sass-cache/
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#= require attentive
|
#= require attentive
|
||||||
#
|
#
|
||||||
Attentive.setup('#slides')
|
Attentive.Presentation.setup('#slides')
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#= require attentive/presentation_timer
|
||||||
|
|
||||||
|
describe 'Attentive.PresentationTimer', ->
|
||||||
|
describe '#render', ->
|
||||||
|
it 'should do something', ->
|
|
@ -0,0 +1,9 @@
|
||||||
|
Flowerbox.configure do |c|
|
||||||
|
c.test_with :jasmine
|
||||||
|
c.run_with :node
|
||||||
|
|
||||||
|
c.asset_paths << "lib/assets/javascripts"
|
||||||
|
|
||||||
|
c.report_with :verbose
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue