Commit 42dd8082 by Prem Sichanugrist

Move CoffeeScripts to asset pipeline

parent 93248a30
......@@ -20,6 +20,7 @@ Longer TODO:
"""
import sys
import tempfile
import glob2
import djcelery
from path import path
......@@ -285,13 +286,12 @@ PIPELINE_CSS = {
PIPELINE_JS = {
'application': {
'source_filenames': [
'coffee/src/calculator.coffee',
'coffee/src/courseware.coffee',
'coffee/src/feedback_form.coffee',
'coffee/src/main.coffee'
],
'source_filenames': [path.replace('static/', '') for path in glob2.glob('static/coffee/src/**/*.coffee')],
'output_filename': 'js/application.js'
},
'spec': {
'source_filenames': [path.replace('static/', '') for path in glob2.glob('static/coffee/spec/**/*.coffee')],
'output_filename': 'js/spec.js'
}
}
......
(function() {
describe('Calculator', function() {
beforeEach(function() {
loadFixtures('calculator.html');
return this.calculator = new Calculator;
});
describe('bind', function() {
beforeEach(function() {
return Calculator.bind();
});
it('bind the calculator button', function() {
return expect($('.calc')).toHandleWith('click', this.calculator.toggle);
});
it('bind the help button', function() {
expect($('div.help-wrapper a')).toHandleWith('mouseenter', this.calculator.helpToggle);
return expect($('div.help-wrapper a')).toHandleWith('mouseleave', this.calculator.helpToggle);
});
it('prevent default behavior on help button', function() {
$('div.help-wrapper a').click(function(e) {
return expect(e.isDefaultPrevented()).toBeTruthy();
});
return $('div.help-wrapper a').click();
});
it('bind the calculator submit', function() {
return expect($('form#calculator')).toHandleWith('submit', this.calculator.calculate);
});
return it('prevent default behavior on form submit', function() {
jasmine.stubRequests();
$('form#calculator').submit(function(e) {
expect(e.isDefaultPrevented()).toBeTruthy();
return e.preventDefault();
});
return $('form#calculator').submit();
});
});
describe('toggle', function() {
it('toggle the calculator and focus the input', function() {
spyOn($.fn, 'focus');
this.calculator.toggle();
expect($('li.calc-main')).toHaveClass('open');
return expect($('#calculator_wrapper #calculator_input').focus).toHaveBeenCalled();
});
return it('toggle the close button on the calculator button', function() {
this.calculator.toggle();
expect($('.calc')).toHaveClass('closed');
this.calculator.toggle();
return expect($('.calc')).not.toHaveClass('closed');
});
});
describe('helpToggle', function() {
return it('toggle the help overlay', function() {
this.calculator.helpToggle();
expect($('.help')).toHaveClass('shown');
this.calculator.helpToggle();
return expect($('.help')).not.toHaveClass('shown');
});
});
return describe('calculate', function() {
beforeEach(function() {
$('#calculator_input').val('1+2');
spyOn($, 'getWithPrefix').andCallFake(function(url, data, callback) {
return callback({
result: 3
});
});
return this.calculator.calculate();
});
it('send data to /calculate', function() {
return expect($.getWithPrefix).toHaveBeenCalledWith('/calculate', {
equation: '1+2'
}, jasmine.any(Function));
});
return it('update the calculator output', function() {
return expect($('#calculator_output').val()).toEqual('3');
});
});
});
}).call(this);
(function() {
describe('Courseware', function() {
describe('start', function() {
it('create the navigation', function() {
spyOn(window, 'Navigation');
Courseware.start();
return expect(window.Navigation).toHaveBeenCalled();
});
it('create the calculator', function() {
spyOn(window, 'Calculator');
Courseware.start();
return expect(window.Calculator).toHaveBeenCalled();
});
it('creates the FeedbackForm', function() {
spyOn(window, 'FeedbackForm');
Courseware.start();
return expect(window.FeedbackForm).toHaveBeenCalled();
});
return it('binds the Logger', function() {
spyOn(Logger, 'bind');
Courseware.start();
return expect(Logger.bind).toHaveBeenCalled();
});
});
describe('bind', function() {
beforeEach(function() {
this.courseware = new Courseware;
return setFixtures("<div class=\"course-content\">\n <div class=\"sequence\"></div>\n</div>");
});
return it('binds the content change event', function() {
this.courseware.bind();
return expect($('.course-content .sequence')).toHandleWith('contentChanged', this.courseware.render);
});
});
return describe('render', function() {
beforeEach(function() {
jasmine.stubRequests();
this.courseware = new Courseware;
spyOn(window, 'Histogram');
spyOn(window, 'Problem');
spyOn(window, 'Video');
setFixtures("<div class=\"course-content\">\n <div id=\"video_1\" class=\"video\" data-streams=\"1.0:abc1234\"></div>\n <div id=\"video_2\" class=\"video\" data-streams=\"1.0:def5678\"></div>\n <div id=\"problem_3\" class=\"problems-wrapper\" data-url=\"/example/url/\">\n <div id=\"histogram_3\" class=\"histogram\" data-histogram=\"[[0, 1]]\" style=\"height: 20px; display: block;\">\n </div>\n</div>");
return this.courseware.render();
});
it('detect the video elements and convert them', function() {
expect(window.Video).toHaveBeenCalledWith('1', '1.0:abc1234');
return expect(window.Video).toHaveBeenCalledWith('2', '1.0:def5678');
});
it('detect the problem element and convert it', function() {
return expect(window.Problem).toHaveBeenCalledWith('3', '/example/url/');
});
return it('detect the histrogram element and convert it', function() {
return expect(window.Histogram).toHaveBeenCalledWith('3', [[0, 1]]);
});
});
});
}).call(this);
(function() {
describe('FeedbackForm', function() {
beforeEach(function() {
return loadFixtures('feedback_form.html');
});
return describe('constructor', function() {
beforeEach(function() {
new FeedbackForm;
return spyOn($, 'postWithPrefix').andCallFake(function(url, data, callback, format) {
return callback();
});
});
it('binds to the #feedback_button', function() {
return expect($('#feedback_button')).toHandle('click');
});
it('post data to /send_feedback on click', function() {
$('#feedback_subject').val('Awesome!');
$('#feedback_message').val('This site is really good.');
$('#feedback_button').click();
return expect($.postWithPrefix).toHaveBeenCalledWith('/send_feedback', {
subject: 'Awesome!',
message: 'This site is really good.',
url: window.location.href
}, jasmine.any(Function), 'json');
});
return it('replace the form with a thank you message', function() {
$('#feedback_button').click();
return expect($('#feedback_div').html()).toEqual('Feedback submitted. Thank you');
});
});
});
}).call(this);
(function() {
jasmine.getFixtures().fixturesPath = "/_jasmine/fixtures/";
jasmine.stubbedMetadata = {
abc123: {
id: 'abc123',
duration: 100
},
def456: {
id: 'def456',
duration: 200
},
bogus: {
duration: 300
}
};
jasmine.stubbedCaption = {
start: [0, 10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000, 100000, 110000, 120000],
text: ['Caption at 0', 'Caption at 10000', 'Caption at 20000', 'Caption at 30000', 'Caption at 40000', 'Caption at 50000', 'Caption at 60000', 'Caption at 70000', 'Caption at 80000', 'Caption at 90000', 'Caption at 100000', 'Caption at 110000', 'Caption at 120000']
};
jasmine.stubRequests = function() {
return spyOn($, 'ajax').andCallFake(function(settings) {
var match;
if (match = settings.url.match(/youtube\.com\/.+\/videos\/(.+)\?v=2&alt=jsonc/)) {
return settings.success({
data: jasmine.stubbedMetadata[match[1]]
});
} else if (match = settings.url.match(/static\/subs\/(.+)\.srt\.sjson/)) {
return settings.success(jasmine.stubbedCaption);
} else if (settings.url === '/calculate' || settings.url === '/6002x/modx/sequential/1/goto_position' || settings.url.match(/event$/) || settings.url.match(/6002x\/modx\/problem\/.+\/problem_(check|reset|show|save)$/)) {
} else {
throw "External request attempted for " + settings.url + ", which is not defined.";
}
});
};
jasmine.stubYoutubePlayer = function() {
return YT.Player = function() {
return jasmine.createSpyObj('YT.Player', ['cueVideoById', 'getVideoEmbedCode', 'getCurrentTime', 'getPlayerState', 'loadVideoById', 'playVideo', 'pauseVideo', 'seekTo']);
};
};
jasmine.stubVideoPlayer = function(context, enableParts) {
var currentPartName, part, suite, _i, _len, _ref;
if (!$.isArray(enableParts)) {
enableParts = [enableParts];
}
suite = context.suite;
while (suite = suite.parentSuite) {
currentPartName = suite.description;
}
enableParts.push(currentPartName);
_ref = ['VideoCaption', 'VideoSpeedControl', 'VideoProgressSlider'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
part = _ref[_i];
if (!($.inArray(part, enableParts) >= 0)) {
spyOn(window, part);
}
}
loadFixtures('video.html');
jasmine.stubRequests();
YT.Player = void 0;
context.video = new Video('example', '.75:abc123,1.0:def456');
jasmine.stubYoutubePlayer();
return new VideoPlayer(context.video);
};
spyOn(window, 'onunload');
window.YT = {
PlayerState: {
UNSTARTED: -1,
ENDED: 0,
PLAYING: 1,
PAUSED: 2,
BUFFERING: 3,
CUED: 5
}
};
$.cookie = jasmine.createSpy('jQuery.cookie').andReturn('1.0');
$.fn.qtip = jasmine.createSpy('jQuery.qtip');
$.fn.scrollTo = jasmine.createSpy('jQuery.scrollTo');
}).call(this);
......@@ -9,6 +9,7 @@ describe 'Video', ->
describe 'constructor', ->
beforeEach ->
@stubVideoPlayer = jasmine.createSpy('VideoPlayer')
$.cookie.andReturn '0.75'
window.player = 100
......@@ -49,7 +50,6 @@ describe 'Video', ->
beforeEach ->
@originalYT = window.YT
window.YT = { Player: true }
@stubVideoPlayer = jasmine.createSpy('VideoPlayer')
spyOn(window, 'VideoPlayer').andReturn(@stubVideoPlayer)
@video = new Video 'example', '.75:abc123,1.0:def456'
......@@ -62,18 +62,27 @@ describe 'Video', ->
describe 'when the Youtube API is not ready', ->
beforeEach ->
@originalYT = window.YT
window.YT = {}
@video = new Video 'example', '.75:abc123,1.0:def456'
afterEach ->
window.YT = @originalYT
it 'set the callback on the window object', ->
expect(window.onYouTubePlayerAPIReady).toEqual jasmine.any(Function)
describe 'when the Youtube API becoming ready', ->
beforeEach ->
@stubVideoPlayer = jasmine.createSpy('VideoPlayer')
@originalYT = window.YT
window.YT = {}
spyOn(window, 'VideoPlayer').andReturn(@stubVideoPlayer)
@video = new Video 'example', '.75:abc123,1.0:def456'
window.onYouTubePlayerAPIReady()
afterEach ->
window.YT = @originalYT
it 'create the Video Player for all video elements', ->
expect(window.VideoPlayer).toHaveBeenCalledWith @video
expect(@video.player).toEqual @stubVideoPlayer
......
......@@ -184,7 +184,18 @@ section.course-content {
float: left;
position: relative;
a {
&.open {
&>a {
background: url('../images/open-arrow.png') 10px center no-repeat;
}
ol.video_speeds {
display: block;
opacity: 1;
}
}
&>a {
background: url('../images/closed-arrow.png') 10px center no-repeat;
border-left: 1px solid #000;
border-right: 1px solid #000;
......@@ -201,15 +212,6 @@ section.course-content {
-webkit-font-smoothing: antialiased;
width: 110px;
&.open {
background: url('../images/open-arrow.png') 10px center no-repeat;
ol.video_speeds {
display: block;
opacity: 1;
}
}
h3 {
color: #999;
float: left;
......
(function() {
describe('Histogram', function() {
beforeEach(function() {
return spyOn($, 'plot');
});
describe('constructor', function() {
return it('instantiate the data arrays', function() {
var histogram;
histogram = new Histogram(1, []);
expect(histogram.xTicks).toEqual([]);
expect(histogram.yTicks).toEqual([]);
return expect(histogram.data).toEqual([]);
});
});
describe('calculate', function() {
beforeEach(function() {
return this.histogram = new Histogram(1, [[1, 1], [2, 2], [3, 3]]);
});
it('store the correct value for data', function() {
return expect(this.histogram.data).toEqual([[1, Math.log(2)], [2, Math.log(3)], [3, Math.log(4)]]);
});
it('store the correct value for x ticks', function() {
return expect(this.histogram.xTicks).toEqual([[1, '1'], [2, '2'], [3, '3']]);
});
return it('store the correct value for y ticks', function() {
return expect(this.histogram.yTicks).toEqual;
});
});
return describe('render', function() {
return it('call flot with correct option', function() {
new Histogram(1, [[1, 1], [2, 2], [3, 3]]);
return expect($.plot).toHaveBeenCalledWith($("#histogram_1"), [
{
data: [[1, Math.log(2)], [2, Math.log(3)], [3, Math.log(4)]],
bars: {
show: true,
align: 'center',
lineWidth: 0,
fill: 1.0
},
color: "#b72121"
}
], {
xaxis: {
min: -1,
max: 4,
ticks: [[1, '1'], [2, '2'], [3, '3']],
tickLength: 0
},
yaxis: {
min: 0.0,
max: Math.log(4) * 1.1,
ticks: [[Math.log(2), '1'], [Math.log(3), '2'], [Math.log(4), '3']],
labelWidth: 50
}
});
});
});
});
}).call(this);
(function() {
describe('Logger', function() {
it('expose window.log_event', function() {
jasmine.stubRequests();
return expect(window.log_event).toBe(Logger.log);
});
describe('log', function() {
return it('send a request to log event', function() {
spyOn($, 'getWithPrefix');
Logger.log('example', 'data');
return expect($.getWithPrefix).toHaveBeenCalledWith('/event', {
event_type: 'example',
event: '"data"',
page: window.location.href
});
});
});
return describe('bind', function() {
beforeEach(function() {
Logger.bind();
return Courseware.prefix = '/6002x';
});
afterEach(function() {
return window.onunload = null;
});
it('bind the onunload event', function() {
return expect(window.onunload).toEqual(jasmine.any(Function));
});
return it('send a request to log event', function() {
spyOn($, 'ajax');
$(window).trigger('onunload');
return expect($.ajax).toHaveBeenCalledWith({
url: "" + Courseware.prefix + "/event",
data: {
event_type: 'page_close',
event: '',
page: window.location.href
},
async: false
});
});
});
});
}).call(this);
(function() {
describe('Sequence', function() {
beforeEach(function() {
window.MathJax = {
Hub: {
Queue: function() {}
}
};
spyOn(Logger, 'log');
loadFixtures('sequence.html');
return this.items = $.parseJSON(readFixtures('items.json'));
});
describe('constructor', function() {
beforeEach(function() {
return this.sequence = new Sequence('1', this.items, 1);
});
it('set the element', function() {
return expect(this.sequence.element).toEqual($('#sequence_1'));
});
it('build the navigation', function() {
var classes, elements, titles;
classes = $('#sequence-list li>a').map(function() {
return $(this).attr('class');
}).get();
elements = $('#sequence-list li>a').map(function() {
return $(this).attr('data-element');
}).get();
titles = $('#sequence-list li>a>p').map(function() {
return $(this).html();
}).get();
expect(classes).toEqual(['seq_video_active', 'seq_video_inactive', 'seq_problem_inactive']);
expect(elements).toEqual(['1', '2', '3']);
return expect(titles).toEqual(['Video 1', 'Video 2', 'Sample Problem']);
});
it('bind the page events', function() {
expect(this.sequence.element).toHandleWith('contentChanged', this.sequence.toggleArrows);
return expect($('#sequence-list a')).toHandleWith('click', this.sequence.goto);
});
return it('render the active sequence content', function() {
return expect($('#seq_content').html()).toEqual('Video 1');
});
});
describe('toggleArrows', function() {
beforeEach(function() {
return this.sequence = new Sequence('1', this.items, 1);
});
describe('when the first tab is active', function() {
beforeEach(function() {
this.sequence.position = 1;
return this.sequence.toggleArrows();
});
it('disable the previous button', function() {
return expect($('.sequence-nav-buttons .prev a')).toHaveClass('disabled');
});
return it('enable the next button', function() {
expect($('.sequence-nav-buttons .next a')).not.toHaveClass('disabled');
return expect($('.sequence-nav-buttons .next a')).toHandleWith('click', this.sequence.next);
});
});
describe('when the middle tab is active', function() {
beforeEach(function() {
this.sequence.position = 2;
return this.sequence.toggleArrows();
});
it('enable the previous button', function() {
expect($('.sequence-nav-buttons .prev a')).not.toHaveClass('disabled');
return expect($('.sequence-nav-buttons .prev a')).toHandleWith('click', this.sequence.previous);
});
return it('enable the next button', function() {
expect($('.sequence-nav-buttons .next a')).not.toHaveClass('disabled');
return expect($('.sequence-nav-buttons .next a')).toHandleWith('click', this.sequence.next);
});
});
return describe('when the last tab is active', function() {
beforeEach(function() {
this.sequence.position = 3;
return this.sequence.toggleArrows();
});
it('enable the previous button', function() {
expect($('.sequence-nav-buttons .prev a')).not.toHaveClass('disabled');
return expect($('.sequence-nav-buttons .prev a')).toHandleWith('click', this.sequence.previous);
});
return it('disable the next button', function() {
return expect($('.sequence-nav-buttons .next a')).toHaveClass('disabled');
});
});
});
describe('render', function() {
beforeEach(function() {
spyOn($, 'postWithPrefix');
this.sequence = new Sequence('1', this.items);
return spyOnEvent(this.sequence.element, 'contentChanged');
});
describe('with a different position than the current one', function() {
beforeEach(function() {
return this.sequence.render(1);
});
describe('with no previous position', function() {
return it('does not save the new position', function() {
return expect($.postWithPrefix).not.toHaveBeenCalled();
});
});
describe('with previous position', function() {
beforeEach(function() {
this.sequence.position = 2;
return this.sequence.render(1);
});
it('mark the previous tab as visited', function() {
return expect($('[data-element="2"]')).toHaveClass('seq_video_visited');
});
return it('save the new position', function() {
return expect($.postWithPrefix).toHaveBeenCalledWith('/modx/sequential/1/goto_position', {
position: 1
});
});
});
it('mark new tab as active', function() {
return expect($('[data-element="1"]')).toHaveClass('seq_video_active');
});
it('render the new content', function() {
return expect($('#seq_content').html()).toEqual('Video 1');
});
it('update the position', function() {
return expect(this.sequence.position).toEqual(1);
});
return it('trigger contentChanged event', function() {
return expect('contentChanged').toHaveBeenTriggeredOn(this.sequence.element);
});
});
return describe('with the same position as the current one', function() {
return it('should not trigger contentChanged event', function() {
this.sequence.position = 2;
this.sequence.render(2);
return expect('contentChanged').not.toHaveBeenTriggeredOn(this.sequence.element);
});
});
});
describe('goto', function() {
beforeEach(function() {
jasmine.stubRequests();
this.sequence = new Sequence('1', this.items, 2);
return $('[data-element="3"]').click();
});
it('log the sequence goto event', function() {
return expect(Logger.log).toHaveBeenCalledWith('seq_goto', {
old: 2,
"new": 3,
id: '1'
});
});
return it('call render on the right sequence', function() {
return expect($('#seq_content').html()).toEqual('Sample Problem');
});
});
describe('next', function() {
beforeEach(function() {
jasmine.stubRequests();
this.sequence = new Sequence('1', this.items, 2);
return $('.sequence-nav-buttons .next a').click();
});
it('log the next sequence event', function() {
return expect(Logger.log).toHaveBeenCalledWith('seq_next', {
old: 2,
"new": 3,
id: '1'
});
});
return it('call render on the next sequence', function() {
return expect($('#seq_content').html()).toEqual('Sample Problem');
});
});
describe('previous', function() {
beforeEach(function() {
jasmine.stubRequests();
this.sequence = new Sequence('1', this.items, 2);
return $('.sequence-nav-buttons .prev a').click();
});
it('log the previous sequence event', function() {
return expect(Logger.log).toHaveBeenCalledWith('seq_prev', {
old: 2,
"new": 1,
id: '1'
});
});
return it('call render on the previous sequence', function() {
return expect($('#seq_content').html()).toEqual('Video 1');
});
});
return describe('link_for', function() {
return it('return a link for specific position', function() {
var sequence;
sequence = new Sequence('1', this.items, 2);
return expect(sequence.link_for(2)).toBe('[data-element="2"]');
});
});
});
}).call(this);
(function() {
describe('Tab', function() {
beforeEach(function() {
loadFixtures('tab.html');
return this.items = $.parseJSON(readFixtures('items.json'));
});
describe('constructor', function() {
beforeEach(function() {
spyOn($.fn, 'tabs');
return this.tab = new Tab(1, this.items);
});
it('set the element', function() {
return expect(this.tab.element).toEqual($('#tab_1'));
});
it('build the tabs', function() {
var links;
links = $('.navigation li>a').map(function() {
return $(this).attr('href');
}).get();
return expect(links).toEqual(['#tab-1-0', '#tab-1-1', '#tab-1-2']);
});
it('build the container', function() {
var containers;
containers = $('section').map(function() {
return $(this).attr('id');
}).get();
return expect(containers).toEqual(['tab-1-0', 'tab-1-1', 'tab-1-2']);
});
return it('bind the tabs', function() {
return expect($.fn.tabs).toHaveBeenCalledWith({
show: this.tab.onShow
});
});
});
return describe('onShow', function() {
beforeEach(function() {
this.tab = new Tab(1, this.items);
return $('[href="#tab-1-0"]').click();
});
it('replace content in the container', function() {
$('[href="#tab-1-1"]').click();
expect($('#tab-1-0').html()).toEqual('');
expect($('#tab-1-1').html()).toEqual('Video 2');
return expect($('#tab-1-2').html()).toEqual('');
});
return it('trigger contentChanged event on the element', function() {
spyOnEvent(this.tab.element, 'contentChanged');
$('[href="#tab-1-1"]').click();
return expect('contentChanged').toHaveBeenTriggeredOn(this.tab.element);
});
});
});
}).call(this);
(function() {
describe('VideoControl', function() {
beforeEach(function() {
return this.player = jasmine.stubVideoPlayer(this);
});
describe('constructor', function() {
beforeEach(function() {
return this.control = new VideoControl(this.player);
});
it('render the video controls', function() {
return expect($('.video-controls').html()).toContain('<div class="slider"></div>\n<div>\n <ul class="vcr">\n <li><a class="video_control play">Play</a></li>\n <li>\n <div class="vidtime">0:00 / 0:00</div>\n </li>\n </ul>\n <div class="secondary-controls">\n <a href="#" class="add-fullscreen" title="Fill browser">Fill Browser</a>\n </div>\n</div>');
});
it('bind player events', function() {
expect($(this.player)).toHandleWith('play', this.control.onPlay);
expect($(this.player)).toHandleWith('pause', this.control.onPause);
return expect($(this.player)).toHandleWith('ended', this.control.onPause);
});
return it('bind the playback button', function() {
return expect($('.video_control')).toHandleWith('click', this.control.togglePlayback);
});
});
describe('onPlay', function() {
beforeEach(function() {
this.control = new VideoControl(this.player);
return this.control.onPlay();
});
return it('switch playback button to play state', function() {
expect($('.video_control')).not.toHaveClass('play');
expect($('.video_control')).toHaveClass('pause');
return expect($('.video_control')).toHaveHtml('Pause');
});
});
describe('onPause', function() {
beforeEach(function() {
this.control = new VideoControl(this.player);
return this.control.onPause();
});
return it('switch playback button to pause state', function() {
expect($('.video_control')).not.toHaveClass('pause');
expect($('.video_control')).toHaveClass('play');
return expect($('.video_control')).toHaveHtml('Play');
});
});
return describe('togglePlayback', function() {
beforeEach(function() {
return this.control = new VideoControl(this.player);
});
describe('when the video is playing', function() {
beforeEach(function() {
spyOn(this.player, 'isPlaying').andReturn(true);
spyOnEvent(this.player, 'pause');
return this.control.togglePlayback(jQuery.Event('click'));
});
return it('trigger the pause event', function() {
return expect('pause').toHaveBeenTriggeredOn(this.player);
});
});
return describe('when the video is paused', function() {
beforeEach(function() {
spyOn(this.player, 'isPlaying').andReturn(false);
spyOnEvent(this.player, 'play');
return this.control.togglePlayback(jQuery.Event('click'));
});
return it('trigger the play event', function() {
return expect('play').toHaveBeenTriggeredOn(this.player);
});
});
});
});
}).call(this);
(function() {
describe('VideoProgressSlider', function() {
beforeEach(function() {
return this.player = jasmine.stubVideoPlayer(this);
});
describe('constructor', function() {
beforeEach(function() {
spyOn($.fn, 'slider').andCallThrough();
return this.slider = new VideoProgressSlider(this.player);
});
it('build the slider', function() {
expect(this.slider.slider).toBe('.slider');
return expect($.fn.slider).toHaveBeenCalledWith({
range: 'min',
change: this.slider.onChange,
slide: this.slider.onSlide,
stop: this.slider.onStop
});
});
it('build the seek handle', function() {
expect(this.slider.handle).toBe('.ui-slider-handle');
return expect($.fn.qtip).toHaveBeenCalledWith({
content: "0:00",
position: {
my: 'bottom center',
at: 'top center',
container: this.slider.handle
},
hide: {
delay: 700
},
style: {
classes: 'ui-tooltip-slider',
widget: true
}
});
});
return it('bind player events', function() {
return expect($(this.player)).toHandleWith('updatePlayTime', this.slider.onUpdatePlayTime);
});
});
describe('onReady', function() {
beforeEach(function() {
spyOn(this.player, 'duration').andReturn(120);
this.slider = new VideoProgressSlider(this.player);
return this.slider.onReady();
});
return it('set the max value to the length of video', function() {
return expect(this.slider.slider.slider('option', 'max')).toEqual(120);
});
});
describe('onUpdatePlayTime', function() {
beforeEach(function() {
this.slider = new VideoProgressSlider(this.player);
spyOn(this.player, 'duration').andReturn(120);
return spyOn($.fn, 'slider').andCallThrough();
});
describe('when frozen', function() {
beforeEach(function() {
this.slider.frozen = true;
return this.slider.onUpdatePlayTime({}, 20);
});
return it('does not update the slider', function() {
return expect($.fn.slider).not.toHaveBeenCalled();
});
});
return describe('when not frozen', function() {
beforeEach(function() {
this.slider.frozen = false;
return this.slider.onUpdatePlayTime({}, 20);
});
it('update the max value of the slider', function() {
return expect($.fn.slider).toHaveBeenCalledWith('option', 'max', 120);
});
return it('update current value of the slider', function() {
return expect($.fn.slider).toHaveBeenCalledWith('value', 20);
});
});
});
describe('onSlide', function() {
beforeEach(function() {
var _this = this;
this.slider = new VideoProgressSlider(this.player);
this.time = null;
$(this.player).bind('seek', function(event, time) {
return _this.time = time;
});
spyOnEvent(this.player, 'seek');
return this.slider.onSlide({}, {
value: 20
});
});
it('freeze the slider', function() {
return expect(this.slider.frozen).toBeTruthy();
});
it('update the tooltip', function() {
return expect($.fn.qtip).toHaveBeenCalled();
});
return it('trigger seek event', function() {
expect('seek').toHaveBeenTriggeredOn(this.player);
return expect(this.time).toEqual(20);
});
});
describe('onChange', function() {
beforeEach(function() {
this.slider = new VideoProgressSlider(this.player);
return this.slider.onChange({}, {
value: 20
});
});
return it('update the tooltip', function() {
return expect($.fn.qtip).toHaveBeenCalled();
});
});
describe('onStop', function() {
beforeEach(function() {
var _this = this;
this.slider = new VideoProgressSlider(this.player);
this.time = null;
$(this.player).bind('seek', function(event, time) {
return _this.time = time;
});
spyOnEvent(this.player, 'seek');
spyOn(window, 'setTimeout');
return this.slider.onStop({}, {
value: 20
});
});
it('freeze the slider', function() {
return expect(this.slider.frozen).toBeTruthy();
});
it('trigger seek event', function() {
expect('seek').toHaveBeenTriggeredOn(this.player);
return expect(this.time).toEqual(20);
});
return it('set timeout to unfreeze the slider', function() {
expect(window.setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 200);
window.setTimeout.mostRecentCall.args[0]();
return expect(this.slider.frozen).toBeFalsy();
});
});
return describe('updateTooltip', function() {
beforeEach(function() {
this.slider = new VideoProgressSlider(this.player);
return this.slider.updateTooltip(90);
});
return it('set the tooltip value', function() {
return expect($.fn.qtip).toHaveBeenCalledWith('option', 'content.text', '1:30');
});
});
});
}).call(this);
(function() {
describe('VideoSpeedControl', function() {
beforeEach(function() {
this.player = jasmine.stubVideoPlayer(this);
return $('.speeds').remove();
});
afterEach(function() {});
describe('constructor', function() {
describe('always', function() {
beforeEach(function() {
return this.speedControl = new VideoSpeedControl(this.player, this.video.speeds);
});
it('add the video speed control to player', function() {
return expect($('.secondary-controls').html()).toContain('<div class="speeds">\n <a href="#">\n <h3>Speed</h3>\n <p class="active">1.0x</p>\n </a>\n <ol class="video_speeds"><li data-speed="1.0" class="active"><a href="#">1.0x</a></li><li data-speed="0.75"><a href="#">0.75x</a></li></ol>\n</div>');
});
it('bind to player speedChange event', function() {
return expect($(this.player)).toHandleWith('speedChange', this.speedControl.onSpeedChange);
});
return it('bind to change video speed link', function() {
return expect($('.video_speeds a')).toHandleWith('click', this.speedControl.changeVideoSpeed);
});
});
describe('when running on touch based device', function() {
beforeEach(function() {
spyOn(window, 'onTouchBasedDevice').andReturn(true);
$('.speeds').removeClass('open');
return this.speedControl = new VideoSpeedControl(this.player, this.video.speeds);
});
return it('open the speed toggle on click', function() {
$('.speeds').click();
expect($('.speeds')).toHaveClass('open');
$('.speeds').click();
return expect($('.speeds')).not.toHaveClass('open');
});
});
return describe('when running on non-touch based device', function() {
beforeEach(function() {
spyOn(window, 'onTouchBasedDevice').andReturn(false);
$('.speeds').removeClass('open');
return this.speedControl = new VideoSpeedControl(this.player, this.video.speeds);
});
it('open the speed toggle on hover', function() {
$('.speeds').mouseover();
expect($('.speeds')).toHaveClass('open');
$('.speeds').mouseout();
return expect($('.speeds')).not.toHaveClass('open');
});
it('close the speed toggle on mouse out', function() {
$('.speeds').mouseover().mouseout();
return expect($('.speeds')).not.toHaveClass('open');
});
return it('close the speed toggle on click', function() {
$('.speeds').mouseover().click();
return expect($('.speeds')).not.toHaveClass('open');
});
});
});
describe('changeVideoSpeed', function() {
beforeEach(function() {
this.speedControl = new VideoSpeedControl(this.player, this.video.speeds);
return this.video.setSpeed('1.0');
});
describe('when new speed is the same', function() {
beforeEach(function() {
spyOnEvent(this.player, 'speedChange');
return $('li[data-speed="1.0"] a').click();
});
return it('does not trigger speedChange event', function() {
return expect('speedChange').not.toHaveBeenTriggeredOn(this.player);
});
});
return describe('when new speed is not the same', function() {
beforeEach(function() {
var _this = this;
this.newSpeed = null;
$(this.player).bind('speedChange', function(event, newSpeed) {
return _this.newSpeed = newSpeed;
});
spyOnEvent(this.player, 'speedChange');
return $('li[data-speed="0.75"] a').click();
});
return it('trigger player speedChange event', function() {
expect('speedChange').toHaveBeenTriggeredOn(this.player);
return expect(this.newSpeed).toEqual(0.75);
});
});
});
return describe('onSpeedChange', function() {
beforeEach(function() {
this.speedControl = new VideoSpeedControl(this.player, this.video.speeds);
$('li[data-speed="1.0"] a').addClass('active');
return this.speedControl.setSpeed('0.75');
});
return it('set the new speed as active', function() {
expect($('.video_speeds li[data-speed="1.0"]')).not.toHaveClass('active');
expect($('.video_speeds li[data-speed="0.75"]')).toHaveClass('active');
return expect($('.speeds p.active')).toHaveHtml('0.75x');
});
});
});
}).call(this);
(function() {
describe('Video', function() {
beforeEach(function() {
loadFixtures('video.html');
return jasmine.stubRequests();
});
afterEach(function() {
window.player = void 0;
return window.onYouTubePlayerAPIReady = void 0;
});
describe('constructor', function() {
beforeEach(function() {
$.cookie.andReturn('0.75');
return window.player = 100;
});
describe('by default', function() {
beforeEach(function() {
return this.video = new Video('example', '.75:abc123,1.0:def456');
});
it('reset the current video player', function() {
return expect(window.player).toBeNull();
});
it('set the elements', function() {
return expect(this.video.element).toBe('#video_example');
});
it('parse the videos', function() {
return expect(this.video.videos).toEqual({
'0.75': 'abc123',
'1.0': 'def456'
});
});
it('fetch the video metadata', function() {
return expect(this.video.metadata).toEqual({
abc123: {
id: 'abc123',
duration: 100
},
def456: {
id: 'def456',
duration: 200
}
});
});
it('parse available video speeds', function() {
return expect(this.video.speeds).toEqual(['0.75', '1.0']);
});
it('set current video speed via cookie', function() {
return expect(this.video.speed).toEqual('0.75');
});
return it('store a reference for this video player in the element', function() {
return expect($('.video').data('video')).toEqual(this.video);
});
});
describe('when the Youtube API is already available', function() {
beforeEach(function() {
this.originalYT = window.YT;
window.YT = {
Player: true
};
this.stubVideoPlayer = jasmine.createSpy('VideoPlayer');
spyOn(window, 'VideoPlayer').andReturn(this.stubVideoPlayer);
return this.video = new Video('example', '.75:abc123,1.0:def456');
});
afterEach(function() {
return window.YT = this.originalYT;
});
return it('create the Video Player', function() {
expect(window.VideoPlayer).toHaveBeenCalledWith(this.video);
return expect(this.video.player).toEqual(this.stubVideoPlayer);
});
});
describe('when the Youtube API is not ready', function() {
beforeEach(function() {
return this.video = new Video('example', '.75:abc123,1.0:def456');
});
return it('set the callback on the window object', function() {
return expect(window.onYouTubePlayerAPIReady).toEqual(jasmine.any(Function));
});
});
return describe('when the Youtube API becoming ready', function() {
beforeEach(function() {
this.stubVideoPlayer = jasmine.createSpy('VideoPlayer');
spyOn(window, 'VideoPlayer').andReturn(this.stubVideoPlayer);
this.video = new Video('example', '.75:abc123,1.0:def456');
return window.onYouTubePlayerAPIReady();
});
return it('create the Video Player for all video elements', function() {
expect(window.VideoPlayer).toHaveBeenCalledWith(this.video);
return expect(this.video.player).toEqual(this.stubVideoPlayer);
});
});
});
describe('youtubeId', function() {
beforeEach(function() {
$.cookie.andReturn('1.0');
return this.video = new Video('example', '.75:abc123,1.0:def456');
});
describe('with speed', function() {
return it('return the video id for given speed', function() {
expect(this.video.youtubeId('0.75')).toEqual('abc123');
return expect(this.video.youtubeId('1.0')).toEqual('def456');
});
});
return describe('without speed', function() {
return it('return the video id for current speed', function() {
return expect(this.video.youtubeId()).toEqual('def456');
});
});
});
describe('setSpeed', function() {
beforeEach(function() {
return this.video = new Video('example', '.75:abc123,1.0:def456');
});
describe('when new speed is available', function() {
beforeEach(function() {
return this.video.setSpeed('0.75');
});
it('set new speed', function() {
return expect(this.video.speed).toEqual('0.75');
});
return it('save setting for new speed', function() {
return expect($.cookie).toHaveBeenCalledWith('video_speed', '0.75', {
expires: 3650,
path: '/'
});
});
});
return describe('when new speed is not available', function() {
beforeEach(function() {
return this.video.setSpeed('1.75');
});
return it('set speed to 1.0x', function() {
return expect(this.video.speed).toEqual('1.0');
});
});
});
return describe('getDuration', function() {
beforeEach(function() {
return this.video = new Video('example', '.75:abc123,1.0:def456');
});
return it('return duration for current video', function() {
return expect(this.video.getDuration()).toEqual(200);
});
});
});
}).call(this);
(function() {
describe('Navigation', function() {
beforeEach(function() {
loadFixtures('accordion.html');
return this.navigation = new Navigation;
});
describe('constructor', function() {
describe('when the #accordion exists', function() {
describe('when there is an active section', function() {
beforeEach(function() {
spyOn($.fn, 'accordion');
$('#accordion').append('<ul><li></li></ul><ul><li class="active"></li></ul>');
return new Navigation;
});
return it('activate the accordion with correct active section', function() {
return expect($('#accordion').accordion).toHaveBeenCalledWith({
active: 1,
header: 'h3',
autoHeight: false
});
});
});
describe('when there is no active section', function() {
beforeEach(function() {
spyOn($.fn, 'accordion');
$('#accordion').append('<ul><li></li></ul><ul><li></li></ul>');
return new Navigation;
});
return it('activate the accordian with section 1 as active', function() {
return expect($('#accordion').accordion).toHaveBeenCalledWith({
active: 1,
header: 'h3',
autoHeight: false
});
});
});
it('binds the accordionchange event', function() {
Navigation.bind();
return expect($('#accordion')).toHandleWith('accordionchange', this.navigation.log);
});
return it('bind the navigation toggle', function() {
Navigation.bind();
return expect($('#open_close_accordion a')).toHandleWith('click', this.navigation.toggle);
});
});
return describe('when the #accordion does not exists', function() {
beforeEach(function() {
return $('#accordion').remove();
});
return it('does not activate the accordion', function() {
spyOn($.fn, 'accordion');
Navigation.bind();
return expect($('#accordion').accordion).wasNotCalled();
});
});
});
describe('toggle', function() {
return it('toggle closed class on the wrapper', function() {
$('.course-wrapper').removeClass('closed');
this.navigation.toggle();
expect($('.course-wrapper')).toHaveClass('closed');
this.navigation.toggle();
return expect($('.course-wrapper')).not.toHaveClass('closed');
});
});
return describe('log', function() {
beforeEach(function() {
window.log_event = function() {};
return spyOn(window, 'log_event');
});
return it('submit event log', function() {
this.navigation.log({}, {
newHeader: {
text: function() {
return "new";
}
},
oldHeader: {
text: function() {
return "old";
}
}
});
return expect(window.log_event).toHaveBeenCalledWith('accordion', {
newheader: 'new',
oldheader: 'old'
});
});
});
});
}).call(this);
(function() {
describe('Time', function() {
describe('format', function() {
describe('with duration more than or equal to 1 hour', function() {
return it('return a correct time format', function() {
expect(Time.format(3600)).toEqual('1:00:00');
return expect(Time.format(7272)).toEqual('2:01:12');
});
});
return describe('with duration less than 1 hour', function() {
return it('return a correct time format', function() {
expect(Time.format(1)).toEqual('0:01');
expect(Time.format(61)).toEqual('1:01');
return expect(Time.format(3599)).toEqual('59:59');
});
});
});
return describe('convert', function() {
return it('return a correct time based on speed modifier', function() {
expect(Time.convert(0, 1, 1.5)).toEqual('0.000');
expect(Time.convert(100, 1, 1.5)).toEqual('66.667');
return expect(Time.convert(100, 1.5, 1)).toEqual('150.000');
});
});
});
}).call(this);
......@@ -16,15 +16,12 @@
<script src="{{ url }}"></script>
{% endfor %}
{% load compressed %}
{# static files #}
{% for url in suite.static_files %}
<script src="{{ STATIC_URL }}{{ url }}"></script>
{% endfor %}
{% compressed_js 'application' %}
{# spec files #}
{% for file in files %}
<script src="{% url jasmine_test file %}"></script>
{% endfor %}
{% compressed_js 'spec' %}
</head>
<body>
......
......@@ -117,10 +117,6 @@
<script type="text/javascript" src="${static.url('js/schematic.js')}"></script>
<script type="text/javascript" src="${static.url('js/cktsim.js')}"></script>
<script type="text/javascript" src="${static.url('js/jquery.scrollTo-1.4.2-min.js')}"></script>
<script type="text/javascript">
document.write('\x3Cscript type="text/javascript" src="' +
document.location.protocol + '//www.youtube.com/player_api">\x3C/script>');
</script>
<%block name="js_extra"/>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment