Commit b8aff513 by Calen Pennington

Merge branch 'master' into cpennington/cms-github

parents e33dce86 841fb8da
$fg-column: 70px; $fg-column: 70px;
$fg-gutter: 26px; $fg-gutter: 26px;
$fg-max-columns: 12; $fg-max-columns: 12;
$body-font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; $body-font-family: "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
$body-font-size: 14px; $body-font-size: 14px;
$body-line-height: 20px; $body-line-height: 20px;
$light-blue: #f0f8fa;
$dark-blue: #50545c;
$bright-blue: #3c8ebf;
$orange: #f96e5b;
$yellow: #fff8af;
// Base html styles // Base html styles
html { html {
height: 100%; height: 100%;
...@@ -13,23 +19,44 @@ html { ...@@ -13,23 +19,44 @@ html {
a { a {
text-decoration: none; text-decoration: none;
color: #888; color: #888;
@include transition;
&:hover {
color: #ccc;
}
} }
input { input {
font-family: $body-font-family; font-family: $body-font-family;
} }
input[type="submit"], .button { button, input[type="submit"], .button {
border: 1px solid #ccc; background-color: $orange;
background: #efefef; color: #fff;
@include border-radius(3px); -webkit-font-smoothing: antialiased;
padding: 6px; padding: 8px 10px;
border: 0;
font-weight: bold;
&:hover {
background-color: shade($orange, 10%);
}
}
#{$all-text-inputs}, textarea {
border: 1px solid $dark-blue;
font: $body-font-size $body-font-family;
padding: 4px 6px;
@include box-shadow(inset 0 3px 6px $light-blue);
} }
textarea { textarea {
@include box-sizing(border-box); @include box-sizing(border-box);
display: block; display: block;
line-height: lh();
padding: 15px;
width: 100%; width: 100%;
} }
// Extends // Extends
...@@ -68,6 +95,15 @@ textarea { ...@@ -68,6 +95,15 @@ textarea {
float: right; float: right;
} }
.editable {
&:hover {
background: lighten($yellow, 10%);
}
button {
padding: 4px 10px;
}
}
.wip { .wip {
outline: 1px solid #f00 !important; outline: 1px solid #f00 !important;
position: relative; position: relative;
......
...@@ -6,8 +6,12 @@ section.cal { ...@@ -6,8 +6,12 @@ section.cal {
> header { > header {
@include clearfix; @include clearfix;
margin-bottom: 10px; margin-bottom: 10px;
background: #efefef; opacity: .4;
border: 1px solid #ddd; @include transition;
&:hover {
opacity: 1;
}
h2 { h2 {
@include inline-block(); @include inline-block();
...@@ -15,7 +19,6 @@ section.cal { ...@@ -15,7 +19,6 @@ section.cal {
letter-spacing: 1px; letter-spacing: 1px;
font-size: 14px; font-size: 14px;
padding: 6px; padding: 6px;
margin-left: 6px;
font-size: 12px; font-size: 12px;
} }
...@@ -25,9 +28,8 @@ section.cal { ...@@ -25,9 +28,8 @@ section.cal {
li { li {
@include inline-block; @include inline-block;
margin-left: 6px; margin-left: 6px;
padding-left: 6px;
border-left: 1px solid #ddd; border-left: 1px solid #ddd;
padding: 6px; padding: 0 6px;
a { a {
@include inline-block(); @include inline-block();
...@@ -49,31 +51,35 @@ section.cal { ...@@ -49,31 +51,35 @@ section.cal {
ol { ol {
list-style: none; list-style: none;
@include clearfix; @include clearfix;
border-left: 1px solid #333; border-left: 1px solid lighten($dark-blue, 40%);
border-top: 1px solid #333; border-top: 1px solid lighten($dark-blue, 40%);
width: 100%; width: 100%;
@include box-sizing(border-box);
> li { > li {
border-right: 1px solid #333; border-right: 1px solid lighten($dark-blue, 40%);
border-bottom: 1px solid; border-bottom: 1px solid lighten($dark-blue, 40%);
@include box-sizing(border-box); @include box-sizing(border-box);
float: left; float: left;
width: flex-grid(3) + ((flex-gutter() * 3) / 4); width: flex-grid(3) + ((flex-gutter() * 3) / 4);
background-color: lighten($light-blue, 2%);
header { header {
border-bottom: 1px solid #000; border-bottom: 1px solid lighten($dark-blue, 40%);
@include box-shadow(0 1px 2px #aaa); @include box-shadow(0 2px 2px $light-blue);
display: block; display: block;
margin-bottom: 2px; margin-bottom: 2px;
background: #FFF;
h1 { h1 {
font-size: 14px; font-size: 14px;
text-transform: uppercase; text-transform: uppercase;
border-bottom: 1px solid #ccc; border-bottom: 1px solid lighten($dark-blue, 60%);
padding: 6px; padding: 6px;
a { a {
color: #000; color: $bright-blue;
display: block; display: block;
} }
} }
...@@ -84,6 +90,10 @@ section.cal { ...@@ -84,6 +90,10 @@ section.cal {
color: #888; color: #888;
border-bottom: 0; border-bottom: 0;
font-size: 12px; font-size: 12px;
&:hover {
background: #fff;
}
} }
} }
} }
...@@ -93,10 +103,17 @@ section.cal { ...@@ -93,10 +103,17 @@ section.cal {
margin-bottom: 1px; margin-bottom: 1px;
li { li {
background: #efefef; border-bottom: 1px solid darken($light-blue, 8%);
border-bottom: 1px solid #666;
padding: 6px; padding: 6px;
&:hover {
background: lighten($yellow, 10%);
}
a {
color: lighten($dark-blue, 10%);
}
&.create-module { &.create-module {
position: relative; position: relative;
......
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: local('Open Sans Bold'), local('OpenSans-Bold'), url(http://themes.googleusercontent.com/static/fonts/opensans/v6/k3k702ZOKiLJc3WVjuplzKRDOzjiPcYnFooOUGCOsRk.woff) format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 300;
src: local('Open Sans Light'), local('OpenSans-Light'), url(http://themes.googleusercontent.com/static/fonts/opensans/v6/DXI1ORHCpsQm3Vp6mXoaTaRDOzjiPcYnFooOUGCOsRk.woff) format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 700;
src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url(http://themes.googleusercontent.com/static/fonts/opensans/v6/PRmiXeptR36kaC0GEAetxhbnBKKEOwRKgsHDreGcocg.woff) format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 300;
src: local('Open Sans Light Italic'), local('OpenSansLight-Italic'), url(http://themes.googleusercontent.com/static/fonts/opensans/v6/PRmiXeptR36kaC0GEAetxvR_54zmj3SbGZQh3vCOwvY.woff) format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 400;
src: local('Open Sans Italic'), local('OpenSans-Italic'), url(http://themes.googleusercontent.com/static/fonts/opensans/v6/xjAJXh38I15wypJXxuGMBrrIa-7acMAeDBVuclsi6Gc.woff) format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: local('Open Sans'), local('OpenSans'), url(http://themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3bO3LdcAZYWl9Si6vvxL-qU.woff) format('woff');
}
...@@ -9,13 +9,14 @@ body { ...@@ -9,13 +9,14 @@ body {
} }
> header { > header {
background: #000; background: $dark-blue;
color: #fff; color: #fff;
display: block; display: block;
float: none; float: none;
padding: 6px 20px; padding: 8px 25px;
width: 100%; width: 100%;
@include box-sizing(border-box); @include box-sizing(border-box);
-webkit-font-smoothing: antialiased;
nav { nav {
@include clearfix; @include clearfix;
...@@ -24,6 +25,23 @@ body { ...@@ -24,6 +25,23 @@ body {
font-size: 14px; font-size: 14px;
text-transform: uppercase; text-transform: uppercase;
float: left; float: left;
margin-right: 15px;
a {
color: #fff;
&:hover {
color: rgba(#fff, .6);
}
}
}
a {
color: rgba(#fff, .8);
&:hover {
color: rgba(#fff, .6);
}
} }
ul { ul {
...@@ -35,7 +53,16 @@ body { ...@@ -35,7 +53,16 @@ body {
li { li {
@include inline-block(); @include inline-block();
margin-left: 15px;
a {
padding: 8px 10px;
display: block;
margin: -8px 0;
&:hover {
background-color: darken($dark-blue, 15%);
}
}
} }
} }
} }
...@@ -43,11 +70,11 @@ body { ...@@ -43,11 +70,11 @@ body {
&.content { &.content {
section.main-content { section.main-content {
border-left: 2px solid #000; border-left: 2px solid $dark-blue;
@include box-sizing(border-box); @include box-sizing(border-box);
width: flex-grid(9); width: flex-grid(9);
float: left; float: left;
@include box-shadow( -2px 0 3px #ddd ); @include box-shadow( -2px 0 0 darken($light-blue, 3%));
} }
} }
} }
...@@ -2,8 +2,12 @@ section#unit-wrapper { ...@@ -2,8 +2,12 @@ section#unit-wrapper {
section.filters { section.filters {
@include clearfix; @include clearfix;
margin-bottom: 10px; margin-bottom: 10px;
background: #efefef; opacity: .4;
border: 1px solid #ddd; @include transition;
&:hover {
opacity: 1;
}
ul { ul {
@include clearfix(); @include clearfix();
...@@ -22,14 +26,16 @@ section#unit-wrapper { ...@@ -22,14 +26,16 @@ section#unit-wrapper {
div.content { div.content {
display: table; display: table;
border: 1px solid; border: 1px solid lighten($dark-blue, 40%);
width: 100%; width: 100%;
section { section {
header { header {
background: #eee; background: #fff;
padding: 6px; padding: 6px;
border-bottom: 1px solid #ccc; border-bottom: 1px solid lighten($dark-blue, 60%);
border-top: 1px solid lighten($dark-blue, 60%);
margin-top: -1px;
@include clearfix; @include clearfix;
h2 { h2 {
...@@ -37,6 +43,7 @@ section#unit-wrapper { ...@@ -37,6 +43,7 @@ section#unit-wrapper {
letter-spacing: 1px; letter-spacing: 1px;
font-size: 12px; font-size: 12px;
float: left; float: left;
color: $bright-blue;
} }
} }
...@@ -44,7 +51,7 @@ section#unit-wrapper { ...@@ -44,7 +51,7 @@ section#unit-wrapper {
@include box-sizing(border-box); @include box-sizing(border-box);
display: table-cell; display: table-cell;
width: flex-grid(6, 9); width: flex-grid(6, 9);
border-right: 1px solid #333; border-right: 1px solid lighten($dark-blue, 40%);
&.empty { &.empty {
text-align: center; text-align: center;
...@@ -59,14 +66,9 @@ section#unit-wrapper { ...@@ -59,14 +66,9 @@ section#unit-wrapper {
ol { ol {
list-style: none; list-style: none;
border-bottom: 1px solid #333;
li { li {
border-bottom: 1px solid #333; border-bottom: 1px solid lighten($dark-blue, 60%);
&:last-child{
border-bottom: 0;
}
a { a {
color: #000; color: #000;
...@@ -78,6 +80,10 @@ section#unit-wrapper { ...@@ -78,6 +80,10 @@ section#unit-wrapper {
li { li {
padding: 6px; padding: 6px;
&:last-child {
border-bottom: 0;
}
&:hover { &:hover {
a.draggable { a.draggable {
opacity: 1; opacity: 1;
...@@ -127,11 +133,10 @@ section#unit-wrapper { ...@@ -127,11 +133,10 @@ section#unit-wrapper {
ol { ol {
list-style: none; list-style: none;
border-bottom: 1px solid #999;
li { li {
border-bottom: 1px solid #999; border-bottom: 1px solid darken($light-blue, 8%);
background: #f9f9f9; background: lighten($light-blue, 2%);
&:last-child { &:last-child {
border-bottom: 0; border-bottom: 0;
......
section#unit-wrapper { section#unit-wrapper {
> header { > header {
border-bottom: 2px solid #333; border-bottom: 2px solid $dark-blue;
@include clearfix(); @include clearfix();
@include box-shadow( 0 2px 0 darken($light-blue, 3%));
padding: 6px 20px; padding: 6px 20px;
section { section {
...@@ -12,6 +13,7 @@ section#unit-wrapper { ...@@ -12,6 +13,7 @@ section#unit-wrapper {
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 1px; letter-spacing: 1px;
@include inline-block(); @include inline-block();
color: $bright-blue;
} }
p { p {
...@@ -28,11 +30,19 @@ section#unit-wrapper { ...@@ -28,11 +30,19 @@ section#unit-wrapper {
color: #666; color: #666;
a { a {
display: block;
@include inline-block;
&.cancel { &.cancel {
margin-right: 20px; margin-right: 20px;
font-style: italic; font-style: italic;
font-size: 12px; font-size: 12px;
} }
&.save-update {
@extend .button;
margin: -6px -25px -6px 0;
}
} }
} }
} }
...@@ -45,16 +55,16 @@ section#unit-wrapper { ...@@ -45,16 +55,16 @@ section#unit-wrapper {
&.status-settings { &.status-settings {
float: left; float: left;
margin-bottom: 10px; margin-bottom: 10px;
color: $dark-blue;
ul { ul {
list-style: none; list-style: none;
@include border-radius(2px); border: 1px solid lighten($dark-blue, 40%);
border: 1px solid #999;
@include inline-block(); @include inline-block();
li { li {
@include inline-block(); @include inline-block();
border-right: 1px solid #999; border-right: 1px solid lighten($dark-blue, 40%);
padding: 6px; padding: 6px;
&:last-child { &:last-child {
...@@ -64,14 +74,19 @@ section#unit-wrapper { ...@@ -64,14 +74,19 @@ section#unit-wrapper {
&.current { &.current {
background: #eee; background: #eee;
} }
a {
color: $dark-blue;
}
} }
} }
a.settings { a.settings {
@include inline-block(); @include inline-block();
margin: 0 20px; margin: 0 20px;
border: 1px solid #999;
padding: 6px; padding: 6px;
border: 1px solid lighten($dark-blue, 40%);
color: $dark-blue;
} }
select { select {
...@@ -81,6 +96,7 @@ section#unit-wrapper { ...@@ -81,6 +96,7 @@ section#unit-wrapper {
&.author { &.author {
float: right; float: right;
color: lighten($dark-blue, 6%);
dl { dl {
dt { dt {
...@@ -94,7 +110,8 @@ section#unit-wrapper { ...@@ -94,7 +110,8 @@ section#unit-wrapper {
} }
&.tags { &.tags {
background: #eee; background: $light-blue;
color: lighten($dark-blue, 6%);
padding: 10px; padding: 10px;
margin: 0 0 20px; margin: 0 0 20px;
@include clearfix(); @include clearfix();
...@@ -118,9 +135,9 @@ section#unit-wrapper { ...@@ -118,9 +135,9 @@ section#unit-wrapper {
} }
//general styles for main content //general styles for main content
div.preview { .preview {
background: #eee;
@include box-sizing(border-box); @include box-sizing(border-box);
border: 1px solid lighten($dark-blue, 40%);
min-height: 40px; min-height: 40px;
padding: 10px; padding: 10px;
width: 100%; width: 100%;
...@@ -153,13 +170,16 @@ section#unit-wrapper { ...@@ -153,13 +170,16 @@ section#unit-wrapper {
//notes //notes
section.notes { section.notes {
margin-top: 20px; margin-top: 40px;
padding: 20px 0 0; padding: 40px 0 0;
border-top: 1px solid #ccc; border-top: 2px solid lighten( $dark-blue, 60% );
h2 { h2 {
font-size: 14px;
margin-bottom: 6px; margin-bottom: 6px;
font-size: $body-font-size;
text-transform: uppercase;
color: $bright-blue;
letter-spacing: 1px;
} }
form { form {
...@@ -194,6 +214,12 @@ section#unit-wrapper { ...@@ -194,6 +214,12 @@ section#unit-wrapper {
@include inline-block(); @include inline-block();
margin-top: 20px; margin-top: 20px;
} }
a.cancel {
float: right;
font-style: italic;
margin-top: 20px;
}
} }
} }
} }
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<form> <form>
<h2>Add a note</h2> <h2>Add a note</h2>
<textarea name="" id= rows="8" cols="40"></textarea> <textarea name="" id= rows="8" cols="40"></textarea>
<input type="submit" name="" id="" value="post" /> <input type="submit" name="" id="" value="Post" />
</form> </form>
</section> </section>
...@@ -12,8 +12,8 @@ describe 'Calculator', -> ...@@ -12,8 +12,8 @@ describe 'Calculator', ->
it 'bind the help button', -> it 'bind the help button', ->
# These events are bind by $.hover() # These events are bind by $.hover()
expect($('div.help-wrapper a')).toHandleWith 'mouseenter', @calculator.helpToggle expect($('div.help-wrapper a')).toHandleWith 'mouseover', @calculator.helpToggle
expect($('div.help-wrapper a')).toHandleWith 'mouseleave', @calculator.helpToggle expect($('div.help-wrapper a')).toHandleWith 'mouseout', @calculator.helpToggle
it 'prevent default behavior on help button', -> it 'prevent default behavior on help button', ->
$('div.help-wrapper a').click (e) -> $('div.help-wrapper a').click (e) ->
......
...@@ -34,7 +34,7 @@ describe 'Courseware', -> ...@@ -34,7 +34,7 @@ describe 'Courseware', ->
<div class="course-content"> <div class="course-content">
<div id="video_1" class="video" data-streams="1.0:abc1234"></div> <div id="video_1" class="video" data-streams="1.0:abc1234"></div>
<div id="video_2" class="video" data-streams="1.0:def5678"></div> <div id="video_2" class="video" data-streams="1.0:def5678"></div>
<div id="problem_3" class="problems-wrapper" data-url="/example/url/"> <div id="problem_3" class="problems-wrapper" data-problem-id="3" data-url="/example/url/">
<div id="histogram_3" class="histogram" data-histogram="[[0, 1]]" style="height: 20px; display: block;"> <div id="histogram_3" class="histogram" data-histogram="[[0, 1]]" style="height: 20px; display: block;">
</div> </div>
</div> </div>
...@@ -46,7 +46,7 @@ describe 'Courseware', -> ...@@ -46,7 +46,7 @@ describe 'Courseware', ->
expect(window.Video).toHaveBeenCalledWith('2', '1.0:def5678') expect(window.Video).toHaveBeenCalledWith('2', '1.0:def5678')
it 'detect the problem element and convert it', -> it 'detect the problem element and convert it', ->
expect(window.Problem).toHaveBeenCalledWith('3', '/example/url/') expect(window.Problem).toHaveBeenCalledWith(3, 'problem_3', '/example/url/')
it 'detect the histrogram element and convert it', -> it 'detect the histrogram element and convert it', ->
expect(window.Histogram).toHaveBeenCalledWith('3', [[0, 1]]) expect(window.Histogram).toHaveBeenCalledWith('3', [[0, 1]])
jasmine.getFixtures().fixturesPath = "/_jasmine/fixtures/" jasmine.getFixtures().fixturesPath = "/_jasmine/fixtures/"
jasmine.stubbedMetadata = jasmine.stubbedMetadata =
abc123: slowerSpeedYoutubeId:
id: 'abc123' id: 'slowerSpeedYoutubeId'
duration: 100 duration: 300
def456: normalSpeedYoutubeId:
id: 'def456' id: 'normalSpeedYoutubeId'
duration: 200 duration: 200
bogus: bogus:
duration: 300 duration: 100
jasmine.stubbedCaption = jasmine.stubbedCaption =
start: [0, 10000, 20000, 30000] start: [0, 10000, 20000, 30000]
...@@ -20,12 +20,12 @@ jasmine.stubRequests = -> ...@@ -20,12 +20,12 @@ jasmine.stubRequests = ->
settings.success data: jasmine.stubbedMetadata[match[1]] settings.success data: jasmine.stubbedMetadata[match[1]]
else if match = settings.url.match /static\/subs\/(.+)\.srt\.sjson/ else if match = settings.url.match /static\/subs\/(.+)\.srt\.sjson/
settings.success jasmine.stubbedCaption settings.success jasmine.stubbedCaption
else if settings.url.match /modx\/problem\/.+\/problem_get$/ else if settings.url.match /modx\/.+\/problem_get$/
settings.success html: readFixtures('problem_content.html') settings.success html: readFixtures('problem_content.html')
else if settings.url == '/calculate' || else if settings.url == '/calculate' ||
settings.url == '/6002x/modx/sequence/1/goto_position' || settings.url.match(/modx\/.+\/goto_position$/) ||
settings.url.match(/event$/) || settings.url.match(/event$/) ||
settings.url.match(/modx\/problem\/.+\/problem_(check|reset|show|save)$/) settings.url.match(/modx\/.+\/problem_(check|reset|show|save)$/)
# do nothing # do nothing
else else
throw "External request attempted for #{settings.url}, which is not defined." throw "External request attempted for #{settings.url}, which is not defined."
...@@ -49,10 +49,10 @@ jasmine.stubVideoPlayer = (context, enableParts, createPlayer=true) -> ...@@ -49,10 +49,10 @@ jasmine.stubVideoPlayer = (context, enableParts, createPlayer=true) ->
loadFixtures 'video.html' loadFixtures 'video.html'
jasmine.stubRequests() jasmine.stubRequests()
YT.Player = undefined YT.Player = undefined
context.video = new Video 'example', '.75:abc123,1.0:def456' context.video = new Video 'example', '.75:slowerSpeedYoutubeId,1.0:normalSpeedYoutubeId'
jasmine.stubYoutubePlayer() jasmine.stubYoutubePlayer()
if createPlayer if createPlayer
return new VideoPlayer context.video return new VideoPlayer(video: context.video)
spyOn(window, 'onunload') spyOn(window, 'onunload')
......
...@@ -25,7 +25,7 @@ describe 'Logger', -> ...@@ -25,7 +25,7 @@ describe 'Logger', ->
it 'send a request to log event', -> it 'send a request to log event', ->
spyOn($, 'ajax') spyOn($, 'ajax')
$(window).trigger('onunload') window.onunload()
expect($.ajax).toHaveBeenCalledWith expect($.ajax).toHaveBeenCalledWith
url: "#{Courseware.prefix}/event", url: "#{Courseware.prefix}/event",
data: data:
......
...@@ -17,16 +17,16 @@ describe 'Problem', -> ...@@ -17,16 +17,16 @@ describe 'Problem', ->
describe 'constructor', -> describe 'constructor', ->
beforeEach -> beforeEach ->
@problem = new Problem 1, '/problem/url/' @problem = new Problem 1, "problem_1", "/problem/url/"
it 'set the element', -> it 'set the element', ->
expect(@problem.element).toBe '#problem_1' expect(@problem.el).toBe '#problem_1'
describe 'bind', -> describe 'bind', ->
beforeEach -> beforeEach ->
spyOn window, 'update_schematics' spyOn window, 'update_schematics'
MathJax.Hub.getAllJax.andReturn [@stubbedJax] MathJax.Hub.getAllJax.andReturn [@stubbedJax]
@problem = new Problem 1, '/problem/url/' @problem = new Problem 1, "problem_1", "/problem/url/"
it 'set mathjax typeset', -> it 'set mathjax typeset', ->
expect(MathJax.Hub.Queue).toHaveBeenCalled() expect(MathJax.Hub.Queue).toHaveBeenCalled()
...@@ -60,7 +60,7 @@ describe 'Problem', -> ...@@ -60,7 +60,7 @@ describe 'Problem', ->
describe 'render', -> describe 'render', ->
beforeEach -> beforeEach ->
@problem = new Problem 1, '/problem/url/' @problem = new Problem 1, "problem_1", "/problem/url/"
@bind = @problem.bind @bind = @problem.bind
spyOn @problem, 'bind' spyOn @problem, 'bind'
...@@ -69,7 +69,7 @@ describe 'Problem', -> ...@@ -69,7 +69,7 @@ describe 'Problem', ->
@problem.render 'Hello World' @problem.render 'Hello World'
it 'render the content', -> it 'render the content', ->
expect(@problem.element.html()).toEqual 'Hello World' expect(@problem.el.html()).toEqual 'Hello World'
it 're-bind the content', -> it 're-bind the content', ->
expect(@problem.bind).toHaveBeenCalled() expect(@problem.bind).toHaveBeenCalled()
...@@ -81,14 +81,14 @@ describe 'Problem', -> ...@@ -81,14 +81,14 @@ describe 'Problem', ->
@problem.render() @problem.render()
it 'load the content via ajax', -> it 'load the content via ajax', ->
expect(@problem.element.html()).toEqual 'Hello World' expect(@problem.el.html()).toEqual 'Hello World'
it 're-bind the content', -> it 're-bind the content', ->
expect(@problem.bind).toHaveBeenCalled() expect(@problem.bind).toHaveBeenCalled()
describe 'check', -> describe 'check', ->
beforeEach -> beforeEach ->
@problem = new Problem 1, '/problem/url/' @problem = new Problem 1, "problem_1", "/problem/url/"
@problem.answers = 'foo=1&bar=2' @problem.answers = 'foo=1&bar=2'
it 'log the problem_check event', -> it 'log the problem_check event', ->
...@@ -98,19 +98,19 @@ describe 'Problem', -> ...@@ -98,19 +98,19 @@ describe 'Problem', ->
it 'submit the answer for check', -> it 'submit the answer for check', ->
spyOn $, 'postWithPrefix' spyOn $, 'postWithPrefix'
@problem.check() @problem.check()
expect($.postWithPrefix).toHaveBeenCalledWith '/modx/problem/1/problem_check', 'foo=1&bar=2', jasmine.any(Function) expect($.postWithPrefix).toHaveBeenCalledWith '/modx/1/problem_check', 'foo=1&bar=2', jasmine.any(Function)
describe 'when the response is correct', -> describe 'when the response is correct', ->
it 'call render with returned content', -> it 'call render with returned content', ->
spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> callback(success: 'correct', contents: 'Correct!') spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> callback(success: 'correct', contents: 'Correct!')
@problem.check() @problem.check()
expect(@problem.element.html()).toEqual 'Correct!' expect(@problem.el.html()).toEqual 'Correct!'
describe 'when the response is incorrect', -> describe 'when the response is incorrect', ->
it 'call render with returned content', -> it 'call render with returned content', ->
spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> callback(success: 'incorrect', contents: 'Correct!') spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> callback(success: 'incorrect', contents: 'Correct!')
@problem.check() @problem.check()
expect(@problem.element.html()).toEqual 'Correct!' expect(@problem.el.html()).toEqual 'Correct!'
describe 'when the response is undetermined', -> describe 'when the response is undetermined', ->
it 'alert the response', -> it 'alert the response', ->
...@@ -121,7 +121,7 @@ describe 'Problem', -> ...@@ -121,7 +121,7 @@ describe 'Problem', ->
describe 'reset', -> describe 'reset', ->
beforeEach -> beforeEach ->
@problem = new Problem 1, '/problem/url/' @problem = new Problem 1, "problem_1", "/problem/url/"
it 'log the problem_reset event', -> it 'log the problem_reset event', ->
@problem.answers = 'foo=1&bar=2' @problem.answers = 'foo=1&bar=2'
...@@ -131,22 +131,22 @@ describe 'Problem', -> ...@@ -131,22 +131,22 @@ describe 'Problem', ->
it 'POST to the problem reset page', -> it 'POST to the problem reset page', ->
spyOn $, 'postWithPrefix' spyOn $, 'postWithPrefix'
@problem.reset() @problem.reset()
expect($.postWithPrefix).toHaveBeenCalledWith '/modx/problem/1/problem_reset', { id: 1 }, jasmine.any(Function) expect($.postWithPrefix).toHaveBeenCalledWith '/modx/1/problem_reset', { id: 1 }, jasmine.any(Function)
it 'render the returned content', -> it 'render the returned content', ->
spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) -> spyOn($, 'postWithPrefix').andCallFake (url, answers, callback) ->
callback html: "Reset!" callback html: "Reset!"
@problem.reset() @problem.reset()
expect(@problem.element.html()).toEqual 'Reset!' expect(@problem.el.html()).toEqual 'Reset!'
describe 'show', -> describe 'show', ->
beforeEach -> beforeEach ->
@problem = new Problem 1, '/problem/url/' @problem = new Problem 1, "problem_1", "/problem/url/"
@problem.element.prepend '<div id="answer_1_1" /><div id="answer_1_2" />' @problem.el.prepend '<div id="answer_1_1" /><div id="answer_1_2" />'
describe 'when the answer has not yet shown', -> describe 'when the answer has not yet shown', ->
beforeEach -> beforeEach ->
@problem.element.removeClass 'showed' @problem.el.removeClass 'showed'
it 'log the problem_show event', -> it 'log the problem_show event', ->
@problem.show() @problem.show()
...@@ -155,7 +155,7 @@ describe 'Problem', -> ...@@ -155,7 +155,7 @@ describe 'Problem', ->
it 'fetch the answers', -> it 'fetch the answers', ->
spyOn $, 'postWithPrefix' spyOn $, 'postWithPrefix'
@problem.show() @problem.show()
expect($.postWithPrefix).toHaveBeenCalledWith '/modx/problem/1/problem_show', jasmine.any(Function) expect($.postWithPrefix).toHaveBeenCalledWith '/modx/1/problem_show', jasmine.any(Function)
it 'show the answers', -> it 'show the answers', ->
spyOn($, 'postWithPrefix').andCallFake (url, callback) -> spyOn($, 'postWithPrefix').andCallFake (url, callback) ->
...@@ -172,11 +172,11 @@ describe 'Problem', -> ...@@ -172,11 +172,11 @@ describe 'Problem', ->
it 'add the showed class to element', -> it 'add the showed class to element', ->
spyOn($, 'postWithPrefix').andCallFake (url, callback) -> callback(answers: {}) spyOn($, 'postWithPrefix').andCallFake (url, callback) -> callback(answers: {})
@problem.show() @problem.show()
expect(@problem.element).toHaveClass 'showed' expect(@problem.el).toHaveClass 'showed'
describe 'multiple choice question', -> describe 'multiple choice question', ->
beforeEach -> beforeEach ->
@problem.element.prepend ''' @problem.el.prepend '''
<label for="input_1_1_1"><input type="checkbox" name="input_1_1" id="input_1_1_1" value="1"> One</label> <label for="input_1_1_1"><input type="checkbox" name="input_1_1" id="input_1_1_1" value="1"> One</label>
<label for="input_1_1_2"><input type="checkbox" name="input_1_1" id="input_1_1_2" value="2"> Two</label> <label for="input_1_1_2"><input type="checkbox" name="input_1_1" id="input_1_1_2" value="2"> Two</label>
<label for="input_1_1_3"><input type="checkbox" name="input_1_1" id="input_1_1_3" value="3"> Three</label> <label for="input_1_1_3"><input type="checkbox" name="input_1_1" id="input_1_1_3" value="3"> Three</label>
...@@ -194,8 +194,8 @@ describe 'Problem', -> ...@@ -194,8 +194,8 @@ describe 'Problem', ->
describe 'when the answers are alreay shown', -> describe 'when the answers are alreay shown', ->
beforeEach -> beforeEach ->
@problem.element.addClass 'showed' @problem.el.addClass 'showed'
@problem.element.prepend ''' @problem.el.prepend '''
<label for="input_1_1_1" correct_answer="true"> <label for="input_1_1_1" correct_answer="true">
<input type="checkbox" name="input_1_1" id="input_1_1_1" value="1" /> <input type="checkbox" name="input_1_1" id="input_1_1_1" value="1" />
One One
...@@ -216,11 +216,11 @@ describe 'Problem', -> ...@@ -216,11 +216,11 @@ describe 'Problem', ->
it 'remove the showed class from element', -> it 'remove the showed class from element', ->
@problem.show() @problem.show()
expect(@problem.element).not.toHaveClass 'showed' expect(@problem.el).not.toHaveClass 'showed'
describe 'save', -> describe 'save', ->
beforeEach -> beforeEach ->
@problem = new Problem 1, '/problem/url/' @problem = new Problem 1, "problem_1", "/problem/url/"
@problem.answers = 'foo=1&bar=2' @problem.answers = 'foo=1&bar=2'
it 'log the problem_save event', -> it 'log the problem_save event', ->
...@@ -230,7 +230,7 @@ describe 'Problem', -> ...@@ -230,7 +230,7 @@ describe 'Problem', ->
it 'POST to save problem', -> it 'POST to save problem', ->
spyOn $, 'postWithPrefix' spyOn $, 'postWithPrefix'
@problem.save() @problem.save()
expect($.postWithPrefix).toHaveBeenCalledWith '/modx/problem/1/problem_save', 'foo=1&bar=2', jasmine.any(Function) expect($.postWithPrefix).toHaveBeenCalledWith '/modx/1/problem_save', 'foo=1&bar=2', jasmine.any(Function)
it 'alert to the user', -> it 'alert to the user', ->
spyOn window, 'alert' spyOn window, 'alert'
...@@ -240,7 +240,7 @@ describe 'Problem', -> ...@@ -240,7 +240,7 @@ describe 'Problem', ->
describe 'refreshMath', -> describe 'refreshMath', ->
beforeEach -> beforeEach ->
@problem = new Problem 1, '/problem/url/' @problem = new Problem 1, "problem_1", "/problem/url/"
$('#input_example_1').val 'E=mc^2' $('#input_example_1').val 'E=mc^2'
@problem.refreshMath target: $('#input_example_1').get(0) @problem.refreshMath target: $('#input_example_1').get(0)
...@@ -250,7 +250,7 @@ describe 'Problem', -> ...@@ -250,7 +250,7 @@ describe 'Problem', ->
describe 'updateMathML', -> describe 'updateMathML', ->
beforeEach -> beforeEach ->
@problem = new Problem 1, '/problem/url/' @problem = new Problem 1, "problem_1", "/problem/url/"
@stubbedJax.root.toMathML.andReturn '<MathML>' @stubbedJax.root.toMathML.andReturn '<MathML>'
describe 'when there is no exception', -> describe 'when there is no exception', ->
...@@ -270,8 +270,8 @@ describe 'Problem', -> ...@@ -270,8 +270,8 @@ describe 'Problem', ->
describe 'refreshAnswers', -> describe 'refreshAnswers', ->
beforeEach -> beforeEach ->
@problem = new Problem 1, '/problem/url/' @problem = new Problem 1, "problem_1", "/problem/url/"
@problem.element.html ''' @problem.el.html '''
<textarea class="CodeMirror" /> <textarea class="CodeMirror" />
<input id="input_1_1" name="input_1_1" class="schematic" value="one" /> <input id="input_1_1" name="input_1_1" class="schematic" value="one" />
<input id="input_1_2" name="input_1_2" value="two" /> <input id="input_1_2" name="input_1_2" value="two" />
......
...@@ -9,10 +9,10 @@ describe 'Sequence', -> ...@@ -9,10 +9,10 @@ describe 'Sequence', ->
describe 'constructor', -> describe 'constructor', ->
beforeEach -> beforeEach ->
@sequence = new Sequence '1', @items, 'sequence', 1 @sequence = new Sequence '1', 'sequence_1', @items, 'sequence', 1
it 'set the element', -> it 'set the element', ->
expect(@sequence.element).toEqual $('#sequence_1') expect(@sequence.el).toEqual $('#sequence_1')
it 'build the navigation', -> it 'build the navigation', ->
classes = $('#sequence-list li>a').map(-> $(this).attr('class')).get() classes = $('#sequence-list li>a').map(-> $(this).attr('class')).get()
...@@ -31,7 +31,7 @@ describe 'Sequence', -> ...@@ -31,7 +31,7 @@ describe 'Sequence', ->
describe 'toggleArrows', -> describe 'toggleArrows', ->
beforeEach -> beforeEach ->
@sequence = new Sequence '1', @items, 'sequence', 1 @sequence = new Sequence '1', 'sequence_1', @items, 'sequence', 1
describe 'when the first tab is active', -> describe 'when the first tab is active', ->
beforeEach -> beforeEach ->
...@@ -73,8 +73,8 @@ describe 'Sequence', -> ...@@ -73,8 +73,8 @@ describe 'Sequence', ->
describe 'render', -> describe 'render', ->
beforeEach -> beforeEach ->
spyOn $, 'postWithPrefix' spyOn $, 'postWithPrefix'
@sequence = new Sequence '1', @items, 'sequence' @sequence = new Sequence '1', 'sequence_1', @items, 'sequence'
spyOnEvent @sequence.element, 'contentChanged' spyOnEvent @sequence.el, 'contentChanged'
spyOn(@sequence, 'toggleArrows').andCallThrough() spyOn(@sequence, 'toggleArrows').andCallThrough()
describe 'with a different position than the current one', -> describe 'with a different position than the current one', ->
...@@ -94,7 +94,7 @@ describe 'Sequence', -> ...@@ -94,7 +94,7 @@ describe 'Sequence', ->
expect($('[data-element="2"]')).toHaveClass 'seq_video_visited' expect($('[data-element="2"]')).toHaveClass 'seq_video_visited'
it 'save the new position', -> it 'save the new position', ->
expect($.postWithPrefix).toHaveBeenCalledWith '/modx/sequence/1/goto_position', position: 1 expect($.postWithPrefix).toHaveBeenCalledWith '/modx/1/goto_position', position: 1
it 'mark new tab as active', -> it 'mark new tab as active', ->
expect($('[data-element="1"]')).toHaveClass 'seq_video_active' expect($('[data-element="1"]')).toHaveClass 'seq_video_active'
...@@ -109,18 +109,18 @@ describe 'Sequence', -> ...@@ -109,18 +109,18 @@ describe 'Sequence', ->
expect(@sequence.toggleArrows).toHaveBeenCalled() expect(@sequence.toggleArrows).toHaveBeenCalled()
it 'trigger contentChanged event', -> it 'trigger contentChanged event', ->
expect('contentChanged').toHaveBeenTriggeredOn @sequence.element expect('contentChanged').toHaveBeenTriggeredOn @sequence.el
describe 'with the same position as the current one', -> describe 'with the same position as the current one', ->
it 'should not trigger contentChanged event', -> it 'should not trigger contentChanged event', ->
@sequence.position = 2 @sequence.position = 2
@sequence.render 2 @sequence.render 2
expect('contentChanged').not.toHaveBeenTriggeredOn @sequence.element expect('contentChanged').not.toHaveBeenTriggeredOn @sequence.el
describe 'goto', -> describe 'goto', ->
beforeEach -> beforeEach ->
jasmine.stubRequests() jasmine.stubRequests()
@sequence = new Sequence '1', @items, 'sequence', 2 @sequence = new Sequence '1', 'sequence_1', @items, 'sequence', 2
$('[data-element="3"]').click() $('[data-element="3"]').click()
it 'log the sequence goto event', -> it 'log the sequence goto event', ->
...@@ -132,7 +132,7 @@ describe 'Sequence', -> ...@@ -132,7 +132,7 @@ describe 'Sequence', ->
describe 'next', -> describe 'next', ->
beforeEach -> beforeEach ->
jasmine.stubRequests() jasmine.stubRequests()
@sequence = new Sequence '1', @items, 'sequence', 2 @sequence = new Sequence '1', 'sequence_1', @items, 'sequence', 2
$('.sequence-nav-buttons .next a').click() $('.sequence-nav-buttons .next a').click()
it 'log the next sequence event', -> it 'log the next sequence event', ->
...@@ -144,7 +144,7 @@ describe 'Sequence', -> ...@@ -144,7 +144,7 @@ describe 'Sequence', ->
describe 'previous', -> describe 'previous', ->
beforeEach -> beforeEach ->
jasmine.stubRequests() jasmine.stubRequests()
@sequence = new Sequence '1', @items, 'sequence', 2 @sequence = new Sequence '1', 'sequence_1', @items, 'sequence', 2
$('.sequence-nav-buttons .prev a').click() $('.sequence-nav-buttons .prev a').click()
it 'log the previous sequence event', -> it 'log the previous sequence event', ->
...@@ -155,5 +155,5 @@ describe 'Sequence', -> ...@@ -155,5 +155,5 @@ describe 'Sequence', ->
describe 'link_for', -> describe 'link_for', ->
it 'return a link for specific position', -> it 'return a link for specific position', ->
sequence = new Sequence '1', @items, 2 sequence = new Sequence '1', 'sequence_1', @items, 2
expect(sequence.link_for(2)).toBe '[data-element="2"]' expect(sequence.link_for(2)).toBe '[data-element="2"]'
...@@ -9,7 +9,7 @@ describe 'Tab', -> ...@@ -9,7 +9,7 @@ describe 'Tab', ->
@tab = new Tab 1, @items @tab = new Tab 1, @items
it 'set the element', -> it 'set the element', ->
expect(@tab.element).toEqual $('#tab_1') expect(@tab.el).toEqual $('#tab_1')
it 'build the tabs', -> it 'build the tabs', ->
links = $('.navigation li>a').map(-> $(this).attr('href')).get() links = $('.navigation li>a').map(-> $(this).attr('href')).get()
...@@ -34,6 +34,6 @@ describe 'Tab', -> ...@@ -34,6 +34,6 @@ describe 'Tab', ->
expect($('#tab-1-2').html()).toEqual '' expect($('#tab-1-2').html()).toEqual ''
it 'trigger contentChanged event on the element', -> it 'trigger contentChanged event on the element', ->
spyOnEvent @tab.element, 'contentChanged' spyOnEvent @tab.el, 'contentChanged'
$('[href="#tab-1-1"]').click() $('[href="#tab-1-1"]').click()
expect('contentChanged').toHaveBeenTriggeredOn @tab.element expect('contentChanged').toHaveBeenTriggeredOn @tab.el
describe 'VideoControl', -> describe 'VideoControl', ->
beforeEach -> beforeEach ->
@player = jasmine.stubVideoPlayer @ jasmine.stubVideoPlayer @
$('.video-controls').html '' $('.video-controls').html ''
describe 'constructor', -> describe 'constructor', ->
it 'render the video controls', -> it 'render the video controls', ->
new VideoControl @player new VideoControl(el: $('.video-controls'))
expect($('.video-controls').html()).toContain ''' expect($('.video-controls').html()).toContain '''
<div class="slider"></div> <div class="slider"></div>
<div> <div>
...@@ -21,14 +21,8 @@ describe 'VideoControl', -> ...@@ -21,14 +21,8 @@ describe 'VideoControl', ->
</div> </div>
''' '''
it 'bind player events', ->
control = new VideoControl @player
expect($(@player)).toHandleWith 'play', control.onPlay
expect($(@player)).toHandleWith 'pause', control.onPause
expect($(@player)).toHandleWith 'ended', control.onPause
it 'bind the playback button', -> it 'bind the playback button', ->
control = new VideoControl @player control = new VideoControl(el: $('.video-controls'))
expect($('.video_control')).toHandleWith 'click', control.togglePlayback expect($('.video_control')).toHandleWith 'click', control.togglePlayback
describe 'when on a touch based device', -> describe 'when on a touch based device', ->
...@@ -36,7 +30,7 @@ describe 'VideoControl', -> ...@@ -36,7 +30,7 @@ describe 'VideoControl', ->
spyOn(window, 'onTouchBasedDevice').andReturn true spyOn(window, 'onTouchBasedDevice').andReturn true
it 'does not add the play class to video control', -> it 'does not add the play class to video control', ->
new VideoControl @player new VideoControl(el: $('.video-controls'))
expect($('.video_control')).not.toHaveClass 'play' expect($('.video_control')).not.toHaveClass 'play'
expect($('.video_control')).not.toHaveHtml 'Play' expect($('.video_control')).not.toHaveHtml 'Play'
...@@ -46,24 +40,24 @@ describe 'VideoControl', -> ...@@ -46,24 +40,24 @@ describe 'VideoControl', ->
spyOn(window, 'onTouchBasedDevice').andReturn false spyOn(window, 'onTouchBasedDevice').andReturn false
it 'add the play class to video control', -> it 'add the play class to video control', ->
new VideoControl @player new VideoControl(el: $('.video-controls'))
expect($('.video_control')).toHaveClass 'play' expect($('.video_control')).toHaveClass 'play'
expect($('.video_control')).toHaveHtml 'Play' expect($('.video_control')).toHaveHtml 'Play'
describe 'onPlay', -> describe 'play', ->
beforeEach -> beforeEach ->
@control = new VideoControl @player @control = new VideoControl(el: $('.video-controls'))
@control.onPlay() @control.play()
it 'switch playback button to play state', -> it 'switch playback button to play state', ->
expect($('.video_control')).not.toHaveClass 'play' expect($('.video_control')).not.toHaveClass 'play'
expect($('.video_control')).toHaveClass 'pause' expect($('.video_control')).toHaveClass 'pause'
expect($('.video_control')).toHaveHtml 'Pause' expect($('.video_control')).toHaveHtml 'Pause'
describe 'onPause', -> describe 'pause', ->
beforeEach -> beforeEach ->
@control = new VideoControl @player @control = new VideoControl(el: $('.video-controls'))
@control.onPause() @control.pause()
it 'switch playback button to pause state', -> it 'switch playback button to pause state', ->
expect($('.video_control')).not.toHaveClass 'pause' expect($('.video_control')).not.toHaveClass 'pause'
...@@ -72,7 +66,7 @@ describe 'VideoControl', -> ...@@ -72,7 +66,7 @@ describe 'VideoControl', ->
describe 'togglePlayback', -> describe 'togglePlayback', ->
beforeEach -> beforeEach ->
@control = new VideoControl @player @control = new VideoControl(el: $('.video-controls'))
describe 'when the control does not have play or pause class', -> describe 'when the control does not have play or pause class', ->
beforeEach -> beforeEach ->
...@@ -80,41 +74,36 @@ describe 'VideoControl', -> ...@@ -80,41 +74,36 @@ describe 'VideoControl', ->
describe 'when the video is playing', -> describe 'when the video is playing', ->
beforeEach -> beforeEach ->
spyOn(@player, 'isPlaying').andReturn true $('.video_control').addClass('play')
spyOnEvent @player, 'pause' spyOnEvent @control, 'pause'
@control.togglePlayback jQuery.Event('click') @control.togglePlayback jQuery.Event('click')
it 'does not trigger the pause event', -> it 'does not trigger the pause event', ->
expect('pause').not.toHaveBeenTriggeredOn @player expect('pause').not.toHaveBeenTriggeredOn @control
describe 'when the video is paused', -> describe 'when the video is paused', ->
beforeEach -> beforeEach ->
spyOn(@player, 'isPlaying').andReturn false $('.video_control').addClass('pause')
spyOnEvent @player, 'play' spyOnEvent @control, 'play'
@control.togglePlayback jQuery.Event('click') @control.togglePlayback jQuery.Event('click')
it 'does not trigger the play event', -> it 'does not trigger the play event', ->
expect('play').not.toHaveBeenTriggeredOn @player expect('play').not.toHaveBeenTriggeredOn @control
for className in ['play', 'pause'] describe 'when the video is playing', ->
describe "when the control has #{className} class", ->
beforeEach -> beforeEach ->
$('.video_control').addClass className spyOnEvent @control, 'pause'
$('.video_control').addClass 'pause'
describe 'when the video is playing', -> @control.togglePlayback jQuery.Event('click')
beforeEach ->
spyOn(@player, 'isPlaying').andReturn true
spyOnEvent @player, 'pause'
@control.togglePlayback jQuery.Event('click')
it 'trigger the pause event', -> it 'trigger the pause event', ->
expect('pause').toHaveBeenTriggeredOn @player expect('pause').toHaveBeenTriggeredOn @control
describe 'when the video is paused', -> describe 'when the video is paused', ->
beforeEach -> beforeEach ->
spyOn(@player, 'isPlaying').andReturn false spyOnEvent @control, 'play'
spyOnEvent @player, 'play' $('.video_control').addClass 'play'
@control.togglePlayback jQuery.Event('click') @control.togglePlayback jQuery.Event('click')
it 'trigger the play event', -> it 'trigger the play event', ->
expect('play').toHaveBeenTriggeredOn @player expect('play').toHaveBeenTriggeredOn @control
describe 'VideoProgressSlider', -> describe 'VideoProgressSlider', ->
beforeEach -> beforeEach ->
@player = jasmine.stubVideoPlayer @ jasmine.stubVideoPlayer @
describe 'constructor', -> describe 'constructor', ->
describe 'on a non-touch based device', -> describe 'on a non-touch based device', ->
beforeEach -> beforeEach ->
spyOn($.fn, 'slider').andCallThrough() spyOn($.fn, 'slider').andCallThrough()
spyOn(window, 'onTouchBasedDevice').andReturn false spyOn(window, 'onTouchBasedDevice').andReturn false
@slider = new VideoProgressSlider @player @slider = new VideoProgressSlider el: $('.slider')
it 'build the slider', -> it 'build the slider', ->
expect(@slider.slider).toBe '.slider' expect(@slider.slider).toBe '.slider'
...@@ -18,7 +18,7 @@ describe 'VideoProgressSlider', -> ...@@ -18,7 +18,7 @@ describe 'VideoProgressSlider', ->
stop: @slider.onStop stop: @slider.onStop
it 'build the seek handle', -> it 'build the seek handle', ->
expect(@slider.handle).toBe '.slider .ui-slider-handle' expect(@slider.handle).toBe '.ui-slider-handle'
expect($.fn.qtip).toHaveBeenCalledWith expect($.fn.qtip).toHaveBeenCalledWith
content: "0:00" content: "0:00"
position: position:
...@@ -31,41 +31,24 @@ describe 'VideoProgressSlider', -> ...@@ -31,41 +31,24 @@ describe 'VideoProgressSlider', ->
classes: 'ui-tooltip-slider' classes: 'ui-tooltip-slider'
widget: true widget: true
it 'bind player events', ->
expect($(@player)).toHandleWith 'updatePlayTime', @slider.onUpdatePlayTime
expect($(@player)).toHandleWith 'ready', @slider.onReady
expect($(@player)).toHandleWith 'play', @slider.onPlay
describe 'on a touch-based device', -> describe 'on a touch-based device', ->
beforeEach -> beforeEach ->
spyOn($.fn, 'slider').andCallThrough() spyOn($.fn, 'slider').andCallThrough()
spyOn(window, 'onTouchBasedDevice').andReturn true spyOn(window, 'onTouchBasedDevice').andReturn true
@slider = new VideoProgressSlider @player @slider = new VideoProgressSlider el: $('.slider')
it 'does not build the slider', -> it 'does not build the slider', ->
expect(@slider.slider).toBeUndefined expect(@slider.slider).toBeUndefined
expect($.fn.slider).not.toHaveBeenCalled() expect($.fn.slider).not.toHaveBeenCalled()
it 'bind player events', -> describe 'play', ->
expect($(@player)).toHandleWith 'updatePlayTime', @slider.onUpdatePlayTime
describe 'onReady', ->
beforeEach ->
spyOn(@player, 'duration').andReturn 120
@slider = new VideoProgressSlider @player
@slider.onReady()
it 'set the max value to the length of video', ->
expect(@slider.slider.slider('option', 'max')).toEqual 120
describe 'onPlay', ->
beforeEach -> beforeEach ->
@slider = new VideoProgressSlider @player @slider = new VideoProgressSlider el: $('.slider')
spyOn($.fn, 'slider').andCallThrough() spyOn($.fn, 'slider').andCallThrough()
describe 'when the slider was already built', -> describe 'when the slider was already built', ->
beforeEach -> beforeEach ->
@slider.onPlay() @slider.play()
it 'does not build the slider', -> it 'does not build the slider', ->
expect($.fn.slider).not.toHaveBeenCalled expect($.fn.slider).not.toHaveBeenCalled
...@@ -73,7 +56,7 @@ describe 'VideoProgressSlider', -> ...@@ -73,7 +56,7 @@ describe 'VideoProgressSlider', ->
describe 'when the slider was not already built', -> describe 'when the slider was not already built', ->
beforeEach -> beforeEach ->
@slider.slider = null @slider.slider = null
@slider.onPlay() @slider.play()
it 'build the slider', -> it 'build the slider', ->
expect(@slider.slider).toBe '.slider' expect(@slider.slider).toBe '.slider'
...@@ -97,16 +80,15 @@ describe 'VideoProgressSlider', -> ...@@ -97,16 +80,15 @@ describe 'VideoProgressSlider', ->
classes: 'ui-tooltip-slider' classes: 'ui-tooltip-slider'
widget: true widget: true
describe 'onUpdatePlayTime', -> describe 'updatePlayTime', ->
beforeEach -> beforeEach ->
@slider = new VideoProgressSlider @player @slider = new VideoProgressSlider el: $('.slider')
spyOn(@player, 'duration').andReturn 120
spyOn($.fn, 'slider').andCallThrough() spyOn($.fn, 'slider').andCallThrough()
describe 'when frozen', -> describe 'when frozen', ->
beforeEach -> beforeEach ->
@slider.frozen = true @slider.frozen = true
@slider.onUpdatePlayTime {}, 20 @slider.updatePlayTime 20, 120
it 'does not update the slider', -> it 'does not update the slider', ->
expect($.fn.slider).not.toHaveBeenCalled() expect($.fn.slider).not.toHaveBeenCalled()
...@@ -114,7 +96,7 @@ describe 'VideoProgressSlider', -> ...@@ -114,7 +96,7 @@ describe 'VideoProgressSlider', ->
describe 'when not frozen', -> describe 'when not frozen', ->
beforeEach -> beforeEach ->
@slider.frozen = false @slider.frozen = false
@slider.onUpdatePlayTime {}, 20 @slider.updatePlayTime 20, 120
it 'update the max value of the slider', -> it 'update the max value of the slider', ->
expect($.fn.slider).toHaveBeenCalledWith 'option', 'max', 120 expect($.fn.slider).toHaveBeenCalledWith 'option', 'max', 120
...@@ -124,10 +106,10 @@ describe 'VideoProgressSlider', -> ...@@ -124,10 +106,10 @@ describe 'VideoProgressSlider', ->
describe 'onSlide', -> describe 'onSlide', ->
beforeEach -> beforeEach ->
@slider = new VideoProgressSlider @player @slider = new VideoProgressSlider el: $('.slider')
@time = null @time = null
$(@player).bind 'seek', (event, time) => @time = time $(@slider).bind 'seek', (event, time) => @time = time
spyOnEvent @player, 'seek' spyOnEvent @slider, 'seek'
@slider.onSlide {}, value: 20 @slider.onSlide {}, value: 20
it 'freeze the slider', -> it 'freeze the slider', ->
...@@ -137,12 +119,12 @@ describe 'VideoProgressSlider', -> ...@@ -137,12 +119,12 @@ describe 'VideoProgressSlider', ->
expect($.fn.qtip).toHaveBeenCalled() expect($.fn.qtip).toHaveBeenCalled()
it 'trigger seek event', -> it 'trigger seek event', ->
expect('seek').toHaveBeenTriggeredOn @player expect('seek').toHaveBeenTriggeredOn @slider
expect(@time).toEqual 20 expect(@time).toEqual 20
describe 'onChange', -> describe 'onChange', ->
beforeEach -> beforeEach ->
@slider = new VideoProgressSlider @player @slider = new VideoProgressSlider el: $('.slider')
@slider.onChange {}, value: 20 @slider.onChange {}, value: 20
it 'update the tooltip', -> it 'update the tooltip', ->
...@@ -150,10 +132,10 @@ describe 'VideoProgressSlider', -> ...@@ -150,10 +132,10 @@ describe 'VideoProgressSlider', ->
describe 'onStop', -> describe 'onStop', ->
beforeEach -> beforeEach ->
@slider = new VideoProgressSlider @player @slider = new VideoProgressSlider el: $('.slider')
@time = null @time = null
$(@player).bind 'seek', (event, time) => @time = time $(@slider).bind 'seek', (event, time) => @time = time
spyOnEvent @player, 'seek' spyOnEvent @slider, 'seek'
spyOn(window, 'setTimeout') spyOn(window, 'setTimeout')
@slider.onStop {}, value: 20 @slider.onStop {}, value: 20
...@@ -161,7 +143,7 @@ describe 'VideoProgressSlider', -> ...@@ -161,7 +143,7 @@ describe 'VideoProgressSlider', ->
expect(@slider.frozen).toBeTruthy() expect(@slider.frozen).toBeTruthy()
it 'trigger seek event', -> it 'trigger seek event', ->
expect('seek').toHaveBeenTriggeredOn @player expect('seek').toHaveBeenTriggeredOn @slider
expect(@time).toEqual 20 expect(@time).toEqual 20
it 'set timeout to unfreeze the slider', -> it 'set timeout to unfreeze the slider', ->
...@@ -171,7 +153,7 @@ describe 'VideoProgressSlider', -> ...@@ -171,7 +153,7 @@ describe 'VideoProgressSlider', ->
describe 'updateTooltip', -> describe 'updateTooltip', ->
beforeEach -> beforeEach ->
@slider = new VideoProgressSlider @player @slider = new VideoProgressSlider el: $('.slider')
@slider.updateTooltip 90 @slider.updateTooltip 90
it 'set the tooltip value', -> it 'set the tooltip value', ->
......
describe 'VideoSpeedControl', -> describe 'VideoSpeedControl', ->
beforeEach -> beforeEach ->
@player = jasmine.stubVideoPlayer @ jasmine.stubVideoPlayer @
$('.speeds').remove() $('.speeds').remove()
describe 'constructor', -> describe 'constructor', ->
describe 'always', -> describe 'always', ->
beforeEach -> beforeEach ->
@speedControl = new VideoSpeedControl @player, @video.speeds @speedControl = new VideoSpeedControl el: $('.secondary-controls'), speeds: @video.speeds, currentSpeed: '1.0'
it 'add the video speed control to player', -> it 'add the video speed control to player', ->
expect($('.secondary-controls').html()).toContain ''' expect($('.secondary-controls').html()).toContain '''
...@@ -19,9 +19,6 @@ describe 'VideoSpeedControl', -> ...@@ -19,9 +19,6 @@ describe 'VideoSpeedControl', ->
</div> </div>
''' '''
it 'bind to player speedChange event', ->
expect($(@player)).toHandleWith 'speedChange', @speedControl.onSpeedChange
it 'bind to change video speed link', -> it 'bind to change video speed link', ->
expect($('.video_speeds a')).toHandleWith 'click', @speedControl.changeVideoSpeed expect($('.video_speeds a')).toHandleWith 'click', @speedControl.changeVideoSpeed
...@@ -29,7 +26,7 @@ describe 'VideoSpeedControl', -> ...@@ -29,7 +26,7 @@ describe 'VideoSpeedControl', ->
beforeEach -> beforeEach ->
spyOn(window, 'onTouchBasedDevice').andReturn true spyOn(window, 'onTouchBasedDevice').andReturn true
$('.speeds').removeClass 'open' $('.speeds').removeClass 'open'
@speedControl = new VideoSpeedControl @player, @video.speeds @speedControl = new VideoSpeedControl el: $('.secondary-controls'), speeds: @video.speeds, currentSpeed: '1.0'
it 'open the speed toggle on click', -> it 'open the speed toggle on click', ->
$('.speeds').click() $('.speeds').click()
...@@ -41,7 +38,7 @@ describe 'VideoSpeedControl', -> ...@@ -41,7 +38,7 @@ describe 'VideoSpeedControl', ->
beforeEach -> beforeEach ->
spyOn(window, 'onTouchBasedDevice').andReturn false spyOn(window, 'onTouchBasedDevice').andReturn false
$('.speeds').removeClass 'open' $('.speeds').removeClass 'open'
@speedControl = new VideoSpeedControl @player, @video.speeds @speedControl = new VideoSpeedControl el: $('.secondary-controls'), speeds: @video.speeds, currentSpeed: '1.0'
it 'open the speed toggle on hover', -> it 'open the speed toggle on hover', ->
$('.speeds').mouseenter() $('.speeds').mouseenter()
...@@ -59,31 +56,31 @@ describe 'VideoSpeedControl', -> ...@@ -59,31 +56,31 @@ describe 'VideoSpeedControl', ->
describe 'changeVideoSpeed', -> describe 'changeVideoSpeed', ->
beforeEach -> beforeEach ->
@speedControl = new VideoSpeedControl @player, @video.speeds @speedControl = new VideoSpeedControl el: $('.secondary-controls'), speeds: @video.speeds, currentSpeed: '1.0'
@video.setSpeed '1.0' @video.setSpeed '1.0'
describe 'when new speed is the same', -> describe 'when new speed is the same', ->
beforeEach -> beforeEach ->
spyOnEvent @player, 'speedChange' spyOnEvent @speedControl, 'speedChange'
$('li[data-speed="1.0"] a').click() $('li[data-speed="1.0"] a').click()
it 'does not trigger speedChange event', -> it 'does not trigger speedChange event', ->
expect('speedChange').not.toHaveBeenTriggeredOn @player expect('speedChange').not.toHaveBeenTriggeredOn @speedControl
describe 'when new speed is not the same', -> describe 'when new speed is not the same', ->
beforeEach -> beforeEach ->
@newSpeed = null @newSpeed = null
$(@player).bind 'speedChange', (event, newSpeed) => @newSpeed = newSpeed $(@speedControl).bind 'speedChange', (event, newSpeed) => @newSpeed = newSpeed
spyOnEvent @player, 'speedChange' spyOnEvent @speedControl, 'speedChange'
$('li[data-speed="0.75"] a').click() $('li[data-speed="0.75"] a').click()
it 'trigger player speedChange event', -> it 'trigger speedChange event', ->
expect('speedChange').toHaveBeenTriggeredOn @player expect('speedChange').toHaveBeenTriggeredOn @speedControl
expect(@newSpeed).toEqual 0.75 expect(@newSpeed).toEqual 0.75
describe 'onSpeedChange', -> describe 'onSpeedChange', ->
beforeEach -> beforeEach ->
@speedControl = new VideoSpeedControl @player, @video.speeds @speedControl = new VideoSpeedControl el: $('.secondary-controls'), speeds: @video.speeds, currentSpeed: '1.0'
$('li[data-speed="1.0"] a').addClass 'active' $('li[data-speed="1.0"] a').addClass 'active'
@speedControl.setSpeed '0.75' @speedControl.setSpeed '0.75'
......
describe 'VideoVolumeControl', -> describe 'VideoVolumeControl', ->
beforeEach -> beforeEach ->
@player = jasmine.stubVideoPlayer @ jasmine.stubVideoPlayer @
$('.volume').remove() $('.volume').remove()
describe 'constructor', -> describe 'constructor', ->
beforeEach -> beforeEach ->
spyOn($.fn, 'slider') spyOn($.fn, 'slider')
@volumeControl = new VideoVolumeControl @player @volumeControl = new VideoVolumeControl el: $('.secondary-controls')
it 'initialize previousVolume to 100', -> it 'initialize currentVolume to 100', ->
expect(@volumeControl.previousVolume).toEqual 100 expect(@volumeControl.currentVolume).toEqual 100
it 'render the volume control', -> it 'render the volume control', ->
expect($('.secondary-controls').html()).toContain """ expect($('.secondary-controls').html()).toContain """
...@@ -32,7 +32,6 @@ describe 'VideoVolumeControl', -> ...@@ -32,7 +32,6 @@ describe 'VideoVolumeControl', ->
slide: @volumeControl.onChange slide: @volumeControl.onChange
it 'bind the volume control', -> it 'bind the volume control', ->
expect($(@player)).toHandleWith 'ready', @volumeControl.onReady
expect($('.volume>a')).toHandleWith 'click', @volumeControl.toggleMute expect($('.volume>a')).toHandleWith 'click', @volumeControl.toggleMute
expect($('.volume')).not.toHaveClass 'open' expect($('.volume')).not.toHaveClass 'open'
...@@ -41,27 +40,19 @@ describe 'VideoVolumeControl', -> ...@@ -41,27 +40,19 @@ describe 'VideoVolumeControl', ->
$('.volume').mouseleave() $('.volume').mouseleave()
expect($('.volume')).not.toHaveClass 'open' expect($('.volume')).not.toHaveClass 'open'
describe 'onReady', ->
beforeEach ->
@volumeControl = new VideoVolumeControl @player
spyOn $.fn, 'slider'
spyOn(@player, 'volume').andReturn 60
@volumeControl.onReady()
it 'set the max value of the slider', ->
expect($.fn.slider).toHaveBeenCalledWith 'option', 'max', 60
describe 'onChange', -> describe 'onChange', ->
beforeEach -> beforeEach ->
spyOn @player, 'volume' spyOnEvent @volumeControl, 'volumeChange'
@volumeControl = new VideoVolumeControl @player @newVolume = undefined
@volumeControl = new VideoVolumeControl el: $('.secondary-controls')
$(@volumeControl).bind 'volumeChange', (event, volume) => @newVolume = volume
describe 'when the new volume is more than 0', -> describe 'when the new volume is more than 0', ->
beforeEach -> beforeEach ->
@volumeControl.onChange undefined, value: 60 @volumeControl.onChange undefined, value: 60
it 'set the player volume', -> it 'set the player volume', ->
expect(@player.volume).toHaveBeenCalledWith 60 expect(@newVolume).toEqual 60
it 'remote muted class', -> it 'remote muted class', ->
expect($('.volume')).not.toHaveClass 'muted' expect($('.volume')).not.toHaveClass 'muted'
...@@ -71,32 +62,33 @@ describe 'VideoVolumeControl', -> ...@@ -71,32 +62,33 @@ describe 'VideoVolumeControl', ->
@volumeControl.onChange undefined, value: 0 @volumeControl.onChange undefined, value: 0
it 'set the player volume', -> it 'set the player volume', ->
expect(@player.volume).toHaveBeenCalledWith 0 expect(@newVolume).toEqual 0
it 'add muted class', -> it 'add muted class', ->
expect($('.volume')).toHaveClass 'muted' expect($('.volume')).toHaveClass 'muted'
describe 'toggleMute', -> describe 'toggleMute', ->
beforeEach -> beforeEach ->
spyOn @player, 'volume' @newVolume = undefined
@volumeControl = new VideoVolumeControl @player @volumeControl = new VideoVolumeControl el: $('.secondary-controls')
$(@volumeControl).bind 'volumeChange', (event, volume) => @newVolume = volume
describe 'when the current volume is more than 0', -> describe 'when the current volume is more than 0', ->
beforeEach -> beforeEach ->
@player.volume.andReturn 60 @volumeControl.currentVolume = 60
@volumeControl.toggleMute() @volumeControl.toggleMute()
it 'save the previous volume', -> it 'save the previous volume', ->
expect(@volumeControl.previousVolume).toEqual 60 expect(@volumeControl.previousVolume).toEqual 60
it 'set the player volume', -> it 'set the player volume', ->
expect(@player.volume).toHaveBeenCalledWith 0 expect(@newVolume).toEqual 0
describe 'when the current volume is 0', -> describe 'when the current volume is 0', ->
beforeEach -> beforeEach ->
@player.volume.andReturn 0 @volumeControl.currentVolume = 0
@volumeControl.previousVolume = 60 @volumeControl.previousVolume = 60
@volumeControl.toggleMute() @volumeControl.toggleMute()
it 'set the player volume to previous volume', -> it 'set the player volume to previous volume', ->
expect(@player.volume).toHaveBeenCalledWith 60 expect(@newVolume).toEqual 60
...@@ -3,6 +3,10 @@ describe 'Video', -> ...@@ -3,6 +3,10 @@ describe 'Video', ->
loadFixtures 'video.html' loadFixtures 'video.html'
jasmine.stubRequests() jasmine.stubRequests()
@videosDefinition = '.75:slowerSpeedYoutubeId,1.0:normalSpeedYoutubeId'
@slowerSpeedYoutubeId = 'slowerSpeedYoutubeId'
@normalSpeedYoutubeId = 'normalSpeedYoutubeId'
afterEach -> afterEach ->
window.player = undefined window.player = undefined
window.onYouTubePlayerAPIReady = undefined window.onYouTubePlayerAPIReady = undefined
...@@ -15,26 +19,26 @@ describe 'Video', -> ...@@ -15,26 +19,26 @@ describe 'Video', ->
describe 'by default', -> describe 'by default', ->
beforeEach -> beforeEach ->
@video = new Video 'example', '.75:abc123,1.0:def456' @video = new Video 'example', @videosDefinition
it 'reset the current video player', -> it 'reset the current video player', ->
expect(window.player).toBeNull() expect(window.player).toBeNull()
it 'set the elements', -> it 'set the elements', ->
expect(@video.element).toBe '#video_example' expect(@video.el).toBe '#video_example'
it 'parse the videos', -> it 'parse the videos', ->
expect(@video.videos).toEqual expect(@video.videos).toEqual
'0.75': 'abc123' '0.75': @slowerSpeedYoutubeId
'1.0': 'def456' '1.0': @normalSpeedYoutubeId
it 'fetch the video metadata', -> it 'fetch the video metadata', ->
expect(@video.metadata).toEqual expect(@video.metadata).toEqual
abc123: slowerSpeedYoutubeId:
id: 'abc123' id: @slowerSpeedYoutubeId
duration: 100 duration: 300
def456: normalSpeedYoutubeId:
id: 'def456' id: @normalSpeedYoutubeId
duration: 200 duration: 200
it 'parse available video speeds', -> it 'parse available video speeds', ->
...@@ -51,20 +55,20 @@ describe 'Video', -> ...@@ -51,20 +55,20 @@ describe 'Video', ->
@originalYT = window.YT @originalYT = window.YT
window.YT = { Player: true } window.YT = { Player: true }
spyOn(window, 'VideoPlayer').andReturn(@stubVideoPlayer) spyOn(window, 'VideoPlayer').andReturn(@stubVideoPlayer)
@video = new Video 'example', '.75:abc123,1.0:def456' @video = new Video 'example', @videosDefinition
afterEach -> afterEach ->
window.YT = @originalYT window.YT = @originalYT
it 'create the Video Player', -> it 'create the Video Player', ->
expect(window.VideoPlayer).toHaveBeenCalledWith @video expect(window.VideoPlayer).toHaveBeenCalledWith(video: @video)
expect(@video.player).toEqual @stubVideoPlayer expect(@video.player).toEqual @stubVideoPlayer
describe 'when the Youtube API is not ready', -> describe 'when the Youtube API is not ready', ->
beforeEach -> beforeEach ->
@originalYT = window.YT @originalYT = window.YT
window.YT = {} window.YT = {}
@video = new Video 'example', '.75:abc123,1.0:def456' @video = new Video 'example', @videosDefinition
afterEach -> afterEach ->
window.YT = @originalYT window.YT = @originalYT
...@@ -77,33 +81,33 @@ describe 'Video', -> ...@@ -77,33 +81,33 @@ describe 'Video', ->
@originalYT = window.YT @originalYT = window.YT
window.YT = {} window.YT = {}
spyOn(window, 'VideoPlayer').andReturn(@stubVideoPlayer) spyOn(window, 'VideoPlayer').andReturn(@stubVideoPlayer)
@video = new Video 'example', '.75:abc123,1.0:def456' @video = new Video 'example', @videosDefinition
window.onYouTubePlayerAPIReady() window.onYouTubePlayerAPIReady()
afterEach -> afterEach ->
window.YT = @originalYT window.YT = @originalYT
it 'create the Video Player for all video elements', -> it 'create the Video Player for all video elements', ->
expect(window.VideoPlayer).toHaveBeenCalledWith @video expect(window.VideoPlayer).toHaveBeenCalledWith(video: @video)
expect(@video.player).toEqual @stubVideoPlayer expect(@video.player).toEqual @stubVideoPlayer
describe 'youtubeId', -> describe 'youtubeId', ->
beforeEach -> beforeEach ->
$.cookie.andReturn '1.0' $.cookie.andReturn '1.0'
@video = new Video 'example', '.75:abc123,1.0:def456' @video = new Video 'example', @videosDefinition
describe 'with speed', -> describe 'with speed', ->
it 'return the video id for given speed', -> it 'return the video id for given speed', ->
expect(@video.youtubeId('0.75')).toEqual 'abc123' expect(@video.youtubeId('0.75')).toEqual @slowerSpeedYoutubeId
expect(@video.youtubeId('1.0')).toEqual 'def456' expect(@video.youtubeId('1.0')).toEqual @normalSpeedYoutubeId
describe 'without speed', -> describe 'without speed', ->
it 'return the video id for current speed', -> it 'return the video id for current speed', ->
expect(@video.youtubeId()).toEqual 'def456' expect(@video.youtubeId()).toEqual @normalSpeedYoutubeId
describe 'setSpeed', -> describe 'setSpeed', ->
beforeEach -> beforeEach ->
@video = new Video 'example', '.75:abc123,1.0:def456' @video = new Video 'example', @videosDefinition
describe 'when new speed is available', -> describe 'when new speed is available', ->
beforeEach -> beforeEach ->
...@@ -124,7 +128,22 @@ describe 'Video', -> ...@@ -124,7 +128,22 @@ describe 'Video', ->
describe 'getDuration', -> describe 'getDuration', ->
beforeEach -> beforeEach ->
@video = new Video 'example', '.75:abc123,1.0:def456' @video = new Video 'example', @videosDefinition
it 'return duration for current video', -> it 'return duration for current video', ->
expect(@video.getDuration()).toEqual 200 expect(@video.getDuration()).toEqual 200
describe 'log', ->
beforeEach ->
@video = new Video 'example', @videosDefinition
@video.setSpeed '1.0'
spyOn Logger, 'log'
@video.player = { currentTime: 25 }
@video.log 'someEvent'
it 'call the logger with valid parameters', ->
expect(Logger.log).toHaveBeenCalledWith 'someEvent',
id: 'example'
code: @normalSpeedYoutubeId
currentTime: 25
speed: '1.0'
class @Subview
constructor: (options) ->
$.each options, (key, value) =>
@[key] = value
@initialize()
@render()
@bind()
$: (selector) ->
$(selector, @el)
initialize: ->
render: ->
bind: ->
...@@ -20,7 +20,7 @@ class @Courseware ...@@ -20,7 +20,7 @@ class @Courseware
id = $(this).attr('id').replace(/video_/, '') id = $(this).attr('id').replace(/video_/, '')
new Video id, $(this).data('streams') new Video id, $(this).data('streams')
$('.course-content .problems-wrapper').each -> $('.course-content .problems-wrapper').each ->
id = $(this).attr('problem-id') id = $(this).data('problem-id')
new Problem id, $(this).attr('id'), $(this).data('url') new Problem id, $(this).attr('id'), $(this).data('url')
$('.course-content .histogram').each -> $('.course-content .histogram').each ->
id = $(this).attr('id').replace(/histogram_/, '') id = $(this).attr('id').replace(/histogram_/, '')
......
...@@ -24,8 +24,8 @@ $ -> ...@@ -24,8 +24,8 @@ $ ->
# Preserved for backward compatibility # Preserved for backward compatibility
window.submit_circuit = (circuit_id) -> window.submit_circuit = (circuit_id) ->
$("input.schematic").each (index, element) -> $("input.schematic").each (index, el) ->
element.schematic.update_value() el.schematic.update_value()
schematic_value $("#schematic_#{circuit_id}").attr("value") schematic_value $("#schematic_#{circuit_id}").attr("value")
$.postWithPrefix "/save_circuit/#{circuit_id}", schematic: schematic_value, (data) -> $.postWithPrefix "/save_circuit/#{circuit_id}", schematic: schematic_value, (data) ->
......
class @Problem class @Problem
constructor: (@id, @element_id, url) -> constructor: (@id, @element_id, url) ->
@element = $("##{element_id}") @el = $("##{@element_id}")
@render() @render()
$: (selector) -> $: (selector) ->
$(selector, @element) $(selector, @el)
bind: => bind: =>
MathJax.Hub.Queue ["Typeset", MathJax.Hub] MathJax.Hub.Queue ["Typeset", MathJax.Hub]
...@@ -18,16 +18,16 @@ class @Problem ...@@ -18,16 +18,16 @@ class @Problem
updateProgress: (response) => updateProgress: (response) =>
if response.progress_changed if response.progress_changed
@element.attr progress: response.progress_status @el.attr progress: response.progress_status
@element.trigger('progressChanged') @el.trigger('progressChanged')
render: (content) -> render: (content) ->
if content if content
@element.html(content) @el.html(content)
@bind() @bind()
else else
$.postWithPrefix "/modx/#{@id}/problem_get", (response) => $.postWithPrefix "/modx/#{@id}/problem_get", (response) =>
@element.html(response.html) @el.html(response.html)
@bind() @bind()
check: => check: =>
...@@ -47,7 +47,7 @@ class @Problem ...@@ -47,7 +47,7 @@ class @Problem
@updateProgress response @updateProgress response
show: => show: =>
if !@element.hasClass 'showed' if !@el.hasClass 'showed'
Logger.log 'problem_show', problem: @id Logger.log 'problem_show', problem: @id
$.postWithPrefix "/modx/#{@id}/problem_show", (response) => $.postWithPrefix "/modx/#{@id}/problem_show", (response) =>
answers = response.answers answers = response.answers
...@@ -59,12 +59,12 @@ class @Problem ...@@ -59,12 +59,12 @@ class @Problem
@$("#answer_#{key}, #solution_#{key}").html(value) @$("#answer_#{key}, #solution_#{key}").html(value)
MathJax.Hub.Queue ["Typeset", MathJax.Hub] MathJax.Hub.Queue ["Typeset", MathJax.Hub]
@$('.show').val 'Hide Answer' @$('.show').val 'Hide Answer'
@element.addClass 'showed' @el.addClass 'showed'
@updateProgress response @updateProgress response
else else
@$('[id^=answer_], [id^=solution_]').text '' @$('[id^=answer_], [id^=solution_]').text ''
@$('[correct_answer]').attr correct_answer: null @$('[correct_answer]').attr correct_answer: null
@element.removeClass 'showed' @el.removeClass 'showed'
@$('.show').val 'Show Answer' @$('.show').val 'Show Answer'
save: => save: =>
......
class @Sequence class @Sequence
constructor: (@id, @element_id, @elements, @tag, position) -> constructor: (@id, @element_id, @elements, @tag, position) ->
@element = $("#sequence_#{@element_id}") @el = $("##{@element_id}")
@buildNavigation() @buildNavigation()
@initProgress() @initProgress()
@bind() @bind()
@render position @render position
$: (selector) -> $: (selector) ->
$(selector, @element) $(selector, @el)
bind: -> bind: ->
@$('#sequence-list a').click @goto @$('#sequence-list a').click @goto
...@@ -57,7 +57,7 @@ class @Sequence ...@@ -57,7 +57,7 @@ class @Sequence
when 'none' then element.addClass('progress-none') when 'none' then element.addClass('progress-none')
when 'in_progress' then element.addClass('progress-some') when 'in_progress' then element.addClass('progress-some')
when 'done' then element.addClass('progress-done') when 'done' then element.addClass('progress-done')
buildNavigation: -> buildNavigation: ->
$.each @elements, (index, item) => $.each @elements, (index, item) =>
link = $('<a>').attr class: "seq_#{item.type}_inactive", 'data-element': index + 1 link = $('<a>').attr class: "seq_#{item.type}_inactive", 'data-element': index + 1
...@@ -65,10 +65,10 @@ class @Sequence ...@@ -65,10 +65,10 @@ class @Sequence
# TODO (vshnayder): add item.progress_detail either to the title or somewhere else. # TODO (vshnayder): add item.progress_detail either to the title or somewhere else.
# Make sure it gets updated after ajax calls. # Make sure it gets updated after ajax calls.
# implementation note: will need to figure out how to handle combining detail # implementation note: will need to figure out how to handle combining detail
# statuses of multiple modules in js. # statuses of multiple modules in js.
list_item = $('<li>').append(link.append(title)) list_item = $('<li>').append(link.append(title))
@setProgress item.progress_status, link @setProgress item.progress_status, link
@$('#sequence-list').append list_item @$('#sequence-list').append list_item
toggleArrows: => toggleArrows: =>
...@@ -89,7 +89,7 @@ class @Sequence ...@@ -89,7 +89,7 @@ class @Sequence
if @position != undefined if @position != undefined
@mark_visited @position @mark_visited @position
$.postWithPrefix "/modx/#{@id}/goto_position", position: new_position $.postWithPrefix "/modx/#{@id}/goto_position", position: new_position
@mark_active new_position @mark_active new_position
@$('#seq_content').html @elements[new_position - 1].content @$('#seq_content').html @elements[new_position - 1].content
...@@ -97,7 +97,7 @@ class @Sequence ...@@ -97,7 +97,7 @@ class @Sequence
@position = new_position @position = new_position
@toggleArrows() @toggleArrows()
@hookUpProgressEvent() @hookUpProgressEvent()
@element.trigger 'contentChanged' @el.trigger 'contentChanged'
goto: (event) => goto: (event) =>
event.preventDefault() event.preventDefault()
......
class @Tab class @Tab
constructor: (@id, @items) -> constructor: (@id, @items) ->
@element = $("#tab_#{id}") @el = $("#tab_#{id}")
@render() @render()
$: (selector) -> $: (selector) ->
$(selector, @element) $(selector, @el)
render: -> render: ->
$.each @items, (index, item) => $.each @items, (index, item) =>
tab = $('<a>').attr(href: "##{@tabId(index)}").html(item.title) tab = $('<a>').attr(href: "##{@tabId(index)}").html(item.title)
@$('.navigation').append($('<li>').append(tab)) @$('.navigation').append($('<li>').append(tab))
@element.append($('<section>').attr(id: @tabId(index))) @el.append($('<section>').attr(id: @tabId(index)))
@element.tabs @el.tabs
show: @onShow show: @onShow
onShow: (element, ui) => onShow: (element, ui) =>
@$('section.ui-tabs-hide').html('') @$('section.ui-tabs-hide').html('')
@$("##{@tabId(ui.index)}").html(@items[ui.index]['content']) @$("##{@tabId(ui.index)}").html(@items[ui.index]['content'])
@element.trigger 'contentChanged' @el.trigger 'contentChanged'
tabId: (index) -> tabId: (index) ->
"tab-#{@id}-#{index}" "tab-#{@id}-#{index}"
class @Video class @Video
constructor: (@id, videos) -> constructor: (@id, videos) ->
window.player = null window.player = null
@element = $("#video_#{@id}") @el = $("#video_#{@id}")
@parseVideos videos @parseVideos videos
@fetchMetadata() @fetchMetadata()
@parseSpeed() @parseSpeed()
...@@ -36,7 +36,7 @@ class @Video ...@@ -36,7 +36,7 @@ class @Video
@speed = '1.0' @speed = '1.0'
embed: -> embed: ->
@player = new VideoPlayer(this) @player = new VideoPlayer video: this
fetchMetadata: (url) -> fetchMetadata: (url) ->
@metadata = {} @metadata = {}
...@@ -45,3 +45,10 @@ class @Video ...@@ -45,3 +45,10 @@ class @Video
getDuration: -> getDuration: ->
@metadata[@youtubeId()].duration @metadata[@youtubeId()].duration
log: (eventName) ->
Logger.log eventName,
id: @id
code: @youtubeId()
currentTime: @player.currentTime
speed: @speed
class @VideoCaption class @VideoCaption extends Subview
constructor: (@player, @youtubeId) ->
@render()
@bind()
$: (selector) ->
@player.$(selector)
bind: -> bind: ->
$(window).bind('resize', @onWindowResize) $(window).bind('resize', @resize)
$(@player).bind('resize', @onWindowResize)
$(@player).bind('updatePlayTime', @onUpdatePlayTime)
$(@player).bind('seek', @onUpdatePlayTime)
$(@player).bind('play', @onPlay)
@$('.hide-subtitles').click @toggle @$('.hide-subtitles').click @toggle
@$('.subtitles').mouseenter(@onMouseEnter).mouseleave(@onMouseLeave) @$('.subtitles').mouseenter(@onMouseEnter).mouseleave(@onMouseLeave)
.mousemove(@onMovement).bind('mousewheel', @onMovement) .mousemove(@onMovement).bind('mousewheel', @onMovement)
...@@ -70,12 +59,16 @@ class @VideoCaption ...@@ -70,12 +59,16 @@ class @VideoCaption
return min return min
onPlay: => play: ->
@renderCaption() unless @rendered @renderCaption() unless @rendered
@playing = true
pause: ->
@playing = false
onUpdatePlayTime: (event, time) => updatePlayTime: (time) ->
# This 250ms offset is required to match the video speed # This 250ms offset is required to match the video speed
time = Math.round(Time.convert(time, @player.currentSpeed(), '1.0') * 1000 + 250) time = Math.round(Time.convert(time, @currentSpeed, '1.0') * 1000 + 250)
newIndex = @search time newIndex = @search time
if newIndex != undefined && @currentIndex != newIndex if newIndex != undefined && @currentIndex != newIndex
...@@ -86,7 +79,7 @@ class @VideoCaption ...@@ -86,7 +79,7 @@ class @VideoCaption
@currentIndex = newIndex @currentIndex = newIndex
@scrollCaption() @scrollCaption()
onWindowResize: => resize: =>
@$('.subtitles').css maxHeight: @captionHeight() @$('.subtitles').css maxHeight: @captionHeight()
@$('.subtitles .spacing:first').height(@topSpacingHeight()) @$('.subtitles .spacing:first').height(@topSpacingHeight())
@$('.subtitles .spacing:last').height(@bottomSpacingHeight()) @$('.subtitles .spacing:last').height(@bottomSpacingHeight())
...@@ -102,7 +95,7 @@ class @VideoCaption ...@@ -102,7 +95,7 @@ class @VideoCaption
onMouseLeave: => onMouseLeave: =>
clearTimeout @frozen if @frozen clearTimeout @frozen if @frozen
@frozen = null @frozen = null
@scrollCaption() if @player.isPlaying() @scrollCaption() if @playing
scrollCaption: -> scrollCaption: ->
if !@frozen && @$('.subtitles .current:first').length if !@frozen && @$('.subtitles .current:first').length
...@@ -111,8 +104,8 @@ class @VideoCaption ...@@ -111,8 +104,8 @@ class @VideoCaption
seekPlayer: (event) => seekPlayer: (event) =>
event.preventDefault() event.preventDefault()
time = Math.round(Time.convert($(event.target).data('start'), '1.0', @player.currentSpeed()) / 1000) time = Math.round(Time.convert($(event.target).data('start'), '1.0', @currentSpeed) / 1000)
$(@player).trigger('seek', time) $(@).trigger('seek', time)
calculateOffset: (element) -> calculateOffset: (element) ->
@captionHeight() / 2 - element.height() / 2 @captionHeight() / 2 - element.height() / 2
...@@ -125,16 +118,16 @@ class @VideoCaption ...@@ -125,16 +118,16 @@ class @VideoCaption
toggle: (event) => toggle: (event) =>
event.preventDefault() event.preventDefault()
if @player.element.hasClass('closed') if @el.hasClass('closed')
@$('.hide-subtitles').attr('title', 'Turn off captions') @$('.hide-subtitles').attr('title', 'Turn off captions')
@player.element.removeClass('closed') @el.removeClass('closed')
@scrollCaption() @scrollCaption()
else else
@$('.hide-subtitles').attr('title', 'Turn on captions') @$('.hide-subtitles').attr('title', 'Turn on captions')
@player.element.addClass('closed') @el.addClass('closed')
captionHeight: -> captionHeight: ->
if @player.element.hasClass('fullscreen') if @el.hasClass('fullscreen')
$(window).height() - @$('.video-controls').height() $(window).height() - @$('.video-controls').height()
else else
@$('.video-wrapper').height() @$('.video-wrapper').height()
class @VideoControl class @VideoControl extends Subview
constructor: (@player) ->
@render()
@bind()
$: (selector) ->
@player.$(selector)
bind: -> bind: ->
$(@player).bind('play', @onPlay)
.bind('pause', @onPause)
.bind('ended', @onPause)
@$('.video_control').click @togglePlayback @$('.video_control').click @togglePlayback
render: -> render: ->
@$('.video-controls').append """ @el.append """
<div class="slider"></div> <div class="slider"></div>
<div> <div>
<ul class="vcr"> <ul class="vcr">
...@@ -31,16 +21,15 @@ class @VideoControl ...@@ -31,16 +21,15 @@ class @VideoControl
unless onTouchBasedDevice() unless onTouchBasedDevice()
@$('.video_control').addClass('play').html('Play') @$('.video_control').addClass('play').html('Play')
onPlay: => play: ->
@$('.video_control').removeClass('play').addClass('pause').html('Pause') @$('.video_control').removeClass('play').addClass('pause').html('Pause')
onPause: => pause: ->
@$('.video_control').removeClass('pause').addClass('play').html('Play') @$('.video_control').removeClass('pause').addClass('play').html('Play')
togglePlayback: (event) => togglePlayback: (event) =>
event.preventDefault() event.preventDefault()
if $('.video_control').hasClass('play') || $('.video_control').hasClass('pause') if @$('.video_control').hasClass('play')
if @player.isPlaying() $(@).trigger('play')
$(@player).trigger('pause') else if @$('.video_control').hasClass('pause')
else $(@).trigger('pause')
$(@player).trigger('play')
class @VideoPlayer class @VideoPlayer extends Subview
constructor: (@video) -> initialize: ->
# Define a missing constant of Youtube API # Define a missing constant of Youtube API
YT.PlayerState.UNSTARTED = -1 YT.PlayerState.UNSTARTED = -1
@currentTime = 0 @currentTime = 0
@element = $("#video_#{@video.id}") @el = $("#video_#{@video.id}")
@render()
@bind()
$: (selector) ->
$(selector, @element)
bind: -> bind: ->
$(@).bind('seek', @onSeek) $(@control).bind('play', @play)
.bind('updatePlayTime', @onUpdatePlayTime) .bind('pause', @pause)
.bind('speedChange', @onSpeedChange) $(@caption).bind('seek', @onSeek)
.bind('play', @onPlay) $(@speedControl).bind('speedChange', @onSpeedChange)
.bind('pause', @onPause) $(@progressSlider).bind('seek', @onSeek)
.bind('ended', @onPause) if @volumeControl
$(@volumeControl).bind('volumeChange', @onVolumeChange)
$(document).keyup @bindExitFullScreen $(document).keyup @bindExitFullScreen
@$('.add-fullscreen').click @toggleFullScreen @$('.add-fullscreen').click @toggleFullScreen
@addToolTip() unless onTouchBasedDevice() @addToolTip() unless onTouchBasedDevice()
bindExitFullScreen: (event) => bindExitFullScreen: (event) =>
if @element.hasClass('fullscreen') && event.keyCode == 27 if @el.hasClass('fullscreen') && event.keyCode == 27
@toggleFullScreen(event) @toggleFullScreen(event)
render: -> render: ->
new VideoControl @ @control = new VideoControl el: @$('.video-controls')
new VideoCaption @, @video.youtubeId('1.0') @caption = new VideoCaption el: @el, youtubeId: @video.youtubeId('1.0'), currentSpeed: @currentSpeed()
new VideoVolumeControl @ unless onTouchBasedDevice() unless onTouchBasedDevice()
new VideoSpeedControl @, @video.speeds @volumeControl = new VideoVolumeControl el: @$('.secondary-controls')
new VideoProgressSlider @ @speedControl = new VideoSpeedControl el: @$('.secondary-controls'), speeds: @video.speeds, currentSpeed: @currentSpeed()
@progressSlider = new VideoProgressSlider el: @$('.slider')
@player = new YT.Player @video.id, @player = new YT.Player @video.id,
playerVars: playerVars:
controls: 0 controls: 0
...@@ -52,90 +49,104 @@ class @VideoPlayer ...@@ -52,90 +49,104 @@ class @VideoPlayer
at: 'top center' at: 'top center'
onReady: => onReady: =>
$(@).trigger('ready')
$(@).trigger('updatePlayTime', 0)
unless onTouchBasedDevice() unless onTouchBasedDevice()
$('.course-content .video:first').data('video').player.play() $('.course-content .video:first').data('video').player.play()
onStateChange: (event) => onStateChange: (event) =>
switch event.data switch event.data
when YT.PlayerState.UNSTARTED
@onUnstarted()
when YT.PlayerState.PLAYING when YT.PlayerState.PLAYING
$(@).trigger('play') @onPlay()
when YT.PlayerState.PAUSED, YT.PlayerState.UNSTARTED when YT.PlayerState.PAUSED
$(@).trigger('pause') @onPause()
when YT.PlayerState.ENDED when YT.PlayerState.ENDED
$(@).trigger('ended') @onEnded()
onUnstarted: =>
@control.pause()
@caption.pause()
onPlay: => onPlay: =>
Logger.log 'play_video', id: @currentTime, code: @player.getVideoEmbedCode() @video.log 'play_video'
window.player.pauseVideo() if window.player && window.player != @player window.player.pauseVideo() if window.player && window.player != @player
window.player = @player window.player = @player
unless @player.interval unless @player.interval
@player.interval = setInterval(@update, 200) @player.interval = setInterval(@update, 200)
@caption.play()
@control.play()
@progressSlider.play()
onPause: => onPause: =>
Logger.log 'pause_video', id: @currentTime, code: @player.getVideoEmbedCode() @video.log 'pause_video'
window.player = null if window.player == @player window.player = null if window.player == @player
clearInterval(@player.interval) clearInterval(@player.interval)
@player.interval = null @player.interval = null
@caption.pause()
@control.pause()
onEnded: =>
@control.pause()
@caption.pause()
onSeek: (event, time) -> onSeek: (event, time) =>
@player.seekTo(time, true) @player.seekTo(time, true)
if @isPlaying() if @isPlaying()
clearInterval(@player.interval) clearInterval(@player.interval)
@player.interval = setInterval(@update, 200) @player.interval = setInterval(@update, 200)
else else
@currentTime = time @currentTime = time
$(@).trigger('updatePlayTime', time) @updatePlayTime time
onSpeedChange: (event, newSpeed) => onSpeedChange: (event, newSpeed) =>
@currentTime = Time.convert(@currentTime, parseFloat(@currentSpeed()), newSpeed) @currentTime = Time.convert(@currentTime, parseFloat(@currentSpeed()), newSpeed)
@video.setSpeed(parseFloat(newSpeed).toFixed(2).replace /\.00$/, '.0') newSpeed = parseFloat(newSpeed).toFixed(2).replace /\.00$/, '.0'
@video.setSpeed(newSpeed)
@caption.currentSpeed = newSpeed
if @isPlaying() if @isPlaying()
@player.loadVideoById(@video.youtubeId(), @currentTime) @player.loadVideoById(@video.youtubeId(), @currentTime)
else else
@player.cueVideoById(@video.youtubeId(), @currentTime) @player.cueVideoById(@video.youtubeId(), @currentTime)
$(@).trigger('updatePlayTime', @currentTime) @updatePlayTime @currentTime
onVolumeChange: (event, volume) =>
@player.setVolume volume
update: => update: =>
if @currentTime = @player.getCurrentTime() if @currentTime = @player.getCurrentTime()
$(@).trigger('updatePlayTime', @currentTime) @updatePlayTime @currentTime
onUpdatePlayTime: (event, time) => updatePlayTime: (time) ->
progress = Time.format(time) + ' / ' + Time.format(@duration()) progress = Time.format(time) + ' / ' + Time.format(@duration())
@$(".vidtime").html(progress) @$(".vidtime").html(progress)
@caption.updatePlayTime(time)
@progressSlider.updatePlayTime(time, @duration())
toggleFullScreen: (event) => toggleFullScreen: (event) =>
event.preventDefault() event.preventDefault()
if @element.hasClass('fullscreen') if @el.hasClass('fullscreen')
@$('.exit').remove() @$('.exit').remove()
@$('.add-fullscreen').attr('title', 'Fill browser') @$('.add-fullscreen').attr('title', 'Fill browser')
@element.removeClass('fullscreen') @el.removeClass('fullscreen')
else else
@element.append('<a href="#" class="exit">Exit</a>').addClass('fullscreen') @el.append('<a href="#" class="exit">Exit</a>').addClass('fullscreen')
@$('.add-fullscreen').attr('title', 'Exit fill browser') @$('.add-fullscreen').attr('title', 'Exit fill browser')
@$('.exit').click @toggleFullScreen @$('.exit').click @toggleFullScreen
$(@).trigger('resize') @caption.resize()
# Delegates # Delegates
play: -> play: =>
@player.playVideo() if @player.playVideo @player.playVideo() if @player.playVideo
isPlaying: -> isPlaying: ->
@player.getPlayerState() == YT.PlayerState.PLAYING @player.getPlayerState() == YT.PlayerState.PLAYING
pause: -> pause: =>
@player.pauseVideo() @player.pauseVideo() if @player.pauseVideo
duration: -> duration: ->
@video.getDuration() @video.getDuration()
currentSpeed: -> currentSpeed: ->
@video.speed @video.speed
volume: (value) ->
if value?
@player.setVolume value
else
@player.getVolume()
class @VideoProgressSlider class @VideoProgressSlider extends Subview
constructor: (@player) -> initialize: ->
@buildSlider() unless onTouchBasedDevice() @buildSlider() unless onTouchBasedDevice()
$(@player).bind('updatePlayTime', @onUpdatePlayTime)
$(@player).bind('ready', @onReady)
$(@player).bind('play', @onPlay)
$: (selector) ->
@player.$(selector)
buildSlider: -> buildSlider: ->
@slider = @$('.slider').slider @slider = @el.slider
range: 'min' range: 'min'
change: @onChange change: @onChange
slide: @onSlide slide: @onSlide
...@@ -17,7 +11,7 @@ class @VideoProgressSlider ...@@ -17,7 +11,7 @@ class @VideoProgressSlider
@buildHandle() @buildHandle()
buildHandle: -> buildHandle: ->
@handle = @$('.slider .ui-slider-handle') @handle = @$('.ui-slider-handle')
@handle.qtip @handle.qtip
content: "#{Time.format(@slider.slider('value'))}" content: "#{Time.format(@slider.slider('value'))}"
position: position:
...@@ -30,28 +24,25 @@ class @VideoProgressSlider ...@@ -30,28 +24,25 @@ class @VideoProgressSlider
classes: 'ui-tooltip-slider' classes: 'ui-tooltip-slider'
widget: true widget: true
onReady: => play: =>
@slider.slider('option', 'max', @player.duration()) if @slider
onPlay: =>
@buildSlider() unless @slider @buildSlider() unless @slider
onUpdatePlayTime: (event, currentTime) => updatePlayTime: (currentTime, duration) ->
if @slider && !@frozen if @slider && !@frozen
@slider.slider('option', 'max', @player.duration()) @slider.slider('option', 'max', duration)
@slider.slider('value', currentTime) @slider.slider('value', currentTime)
onSlide: (event, ui) => onSlide: (event, ui) =>
@frozen = true @frozen = true
@updateTooltip(ui.value) @updateTooltip(ui.value)
$(@player).trigger('seek', ui.value) $(@).trigger('seek', ui.value)
onChange: (event, ui) => onChange: (event, ui) =>
@updateTooltip(ui.value) @updateTooltip(ui.value)
onStop: (event, ui) => onStop: (event, ui) =>
@frozen = true @frozen = true
$(@player).trigger('seek', ui.value) $(@).trigger('seek', ui.value)
setTimeout (=> @frozen = false), 200 setTimeout (=> @frozen = false), 200
updateTooltip: (value)-> updateTooltip: (value)->
......
class @VideoSpeedControl class @VideoSpeedControl extends Subview
constructor: (@player, @speeds) ->
@render()
@bind()
$: (selector) ->
@player.$(selector)
bind: -> bind: ->
$(@player).bind('speedChange', @onSpeedChange)
@$('.video_speeds a').click @changeVideoSpeed @$('.video_speeds a').click @changeVideoSpeed
if onTouchBasedDevice() if onTouchBasedDevice()
@$('.speeds').click (event) -> @$('.speeds').click (event) ->
...@@ -23,7 +15,7 @@ class @VideoSpeedControl ...@@ -23,7 +15,7 @@ class @VideoSpeedControl
$(this).removeClass('open') $(this).removeClass('open')
render: -> render: ->
@$('.secondary-controls').prepend """ @el.prepend """
<div class="speeds"> <div class="speeds">
<a href="#"> <a href="#">
<h3>Speed</h3> <h3>Speed</h3>
...@@ -36,15 +28,14 @@ class @VideoSpeedControl ...@@ -36,15 +28,14 @@ class @VideoSpeedControl
$.each @speeds, (index, speed) => $.each @speeds, (index, speed) =>
link = $('<a>').attr(href: "#").html("#{speed}x") link = $('<a>').attr(href: "#").html("#{speed}x")
@$('.video_speeds').prepend($('<li>').attr('data-speed', speed).html(link)) @$('.video_speeds').prepend($('<li>').attr('data-speed', speed).html(link))
@setSpeed(@player.currentSpeed()) @setSpeed(@currentSpeed)
changeVideoSpeed: (event) => changeVideoSpeed: (event) =>
event.preventDefault() event.preventDefault()
unless $(event.target).parent().hasClass('active') unless $(event.target).parent().hasClass('active')
$(@player).trigger 'speedChange', $(event.target).parent().data('speed') @currentSpeed = $(event.target).parent().data('speed')
$(@).trigger 'speedChange', $(event.target).parent().data('speed')
onSpeedChange: (event, speed) => @setSpeed(parseFloat(@currentSpeed).toFixed(2).replace /\.00$/, '.0')
@setSpeed(parseFloat(speed).toFixed(2).replace /\.00$/, '.0')
setSpeed: (speed) -> setSpeed: (speed) ->
@$('.video_speeds li').removeClass('active') @$('.video_speeds li').removeClass('active')
......
class @VideoVolumeControl class @VideoVolumeControl extends Subview
constructor: (@player) -> initialize: ->
@previousVolume = 100 @currentVolume = 100
@render()
@bind()
$: (selector) ->
@player.$(selector)
bind: -> bind: ->
$(@player).bind('ready', @onReady)
@$('.volume').mouseenter -> @$('.volume').mouseenter ->
$(this).addClass('open') $(this).addClass('open')
@$('.volume').mouseleave -> @$('.volume').mouseleave ->
...@@ -16,7 +10,7 @@ class @VideoVolumeControl ...@@ -16,7 +10,7 @@ class @VideoVolumeControl
@$('.volume>a').click(@toggleMute) @$('.volume>a').click(@toggleMute)
render: -> render: ->
@$('.secondary-controls').prepend """ @el.prepend """
<div class="volume"> <div class="volume">
<a href="#"></a> <a href="#"></a>
<div class="volume-slider-container"> <div class="volume-slider-container">
...@@ -33,16 +27,14 @@ class @VideoVolumeControl ...@@ -33,16 +27,14 @@ class @VideoVolumeControl
change: @onChange change: @onChange
slide: @onChange slide: @onChange
onReady: =>
@slider.slider 'option', 'max', @player.volume()
onChange: (event, ui) => onChange: (event, ui) =>
@player.volume ui.value @currentVolume = ui.value
@$('.secondary-controls .volume').toggleClass 'muted', ui.value == 0 $(@).trigger 'volumeChange', @currentVolume
@$('.volume').toggleClass 'muted', @currentVolume == 0
toggleMute: => toggleMute: =>
if @player.volume() > 0 if @currentVolume > 0
@previousVolume = @player.volume() @previousVolume = @currentVolume
@slider.slider 'option', 'value', 0 @slider.slider 'option', 'value', 0
else else
@slider.slider 'option', 'value', @previousVolume @slider.slider 'option', 'value', @previousVolume
...@@ -137,7 +137,6 @@ section.course-content { ...@@ -137,7 +137,6 @@ section.course-content {
float: left; float: left;
margin-bottom: 0; margin-bottom: 0;
a { a {
border-bottom: none; border-bottom: none;
border-right: 1px solid #000; border-right: 1px solid #000;
...@@ -199,6 +198,8 @@ section.course-content { ...@@ -199,6 +198,8 @@ section.course-content {
ol.video_speeds { ol.video_speeds {
display: block; display: block;
opacity: 1; opacity: 1;
list-style: none;
padding-left: 0;
} }
} }
...@@ -476,6 +477,7 @@ section.course-content { ...@@ -476,6 +477,7 @@ section.course-content {
ol.subtitles { ol.subtitles {
width: 0px; width: 0px;
display: none;
} }
} }
...@@ -498,6 +500,7 @@ section.course-content { ...@@ -498,6 +500,7 @@ section.course-content {
ol.subtitles { ol.subtitles {
right: -(flex-grid(4)); right: -(flex-grid(4));
width: auto; width: auto;
display: block;
} }
} }
......
function ${ id }_content_updated() {
MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
update_schematics();
// dynamic math display: generate MathML on click
$.each($("[id^=display_${ id }_]"), function(index,value){
theid = value.id.replace("display_",""); // ID of the response
if (document.getElementById("input_" + theid)){
MathJax.Hub.queue.Push(function () {
math = MathJax.Hub.getAllJax(value.id)[0];
if (math){
math.Text(document.getElementById("input_" + theid).value);
}
});
};
});
$('#check_${ id }').unbind('click').click(function() {
$("input.schematic").each(function(index,element){ element.schematic.update_value(); });
$(".CodeMirror").each(function(index,element){ if (element.CodeMirror.save) element.CodeMirror.save(); });
// dynamic math display: generate MathML on click
$.each($("[id^=input_${ id }_]"), function(index,value){
theid = value.id.replace("input_",""); // ID of the response
if (document.getElementById("display_" + theid)){
MathJax.Hub.queue.Push(function () {
math = MathJax.Hub.getAllJax("display_" + theid)[0];
if (math){
math.Text(document.getElementById("input_" + theid).value);
UpdateMathML(math,theid);
}
});
};
});
var submit_data={};
$.each($("[id^=input_${ id }_]"), function(index,value){
if (value.type==="checkbox"){
if (value.checked) {
if (typeof submit_data[value.name] == 'undefined'){
submit_data[value.name]=[];
}
submit_data[value.name].push(value.value);
}
}
if (value.type==="radio"){
if (value.checked) {
submit_data[value.name]= value.value;
}
}
else{
submit_data[value.id]=value.value;
}
});
postJSON('${ MITX_ROOT_URL }/modx/problem/${ id }/problem_check',
submit_data,
function(json) {
switch(json.success) {
case 'incorrect': // Worked, but answer not
case 'correct':
$('#main_${ id }').html(json.contents);
${ id }_content_updated();
break;
default:
alert(json.success);
}
}
);
log_event('problem_check', submit_data);
});
$('#reset_${ id }').unbind('click').click(function() {
var submit_data={};
$.each($("[id^=input_${ id }_]"), function(index,value){
submit_data[value.id]=value.value;
});
postJSON('${ MITX_ROOT_URL }/modx/problem/${ id }/problem_reset', {'id':'${ id }'}, function(html_as_json) {
$('#main_${ id }').html(html_as_json);
${ id }_content_updated();
});
log_event('problem_reset', submit_data);
});
// show answer button
// TODO: the button should turn into "hide answer" afterwards
$('#show_${ id }').unbind('click').click(function() {
postJSON('${ MITX_ROOT_URL }/modx/problem/${ id }/problem_show', {}, function(data) {
for (var key in data) {
if ($.isArray(data[key])){
for (var ans_index in data[key]){
var choice_id = 'input_'+key+'_'+data[key][ans_index];
$("label[for="+choice_id+"]").attr("correct_answer", "true");
}
}
// $("#answer_"+key).text(data[key]);
$("#answer_"+key).html(data[key]);
}
});
for (var key in codemirror_set) {
codemirror_set[key].refresh();
}
log_event('problem_show', {'problem':'${ id }'});
});
$('#save_${ id }').unbind('click').click(function() {
$("input.schematic").each(function(index,element){ element.schematic.update_value(); });
var submit_data={};
$.each($("[id^=input_${ id }_]"), function(index,value) {
submit_data[value.id]=value.value;
});
postJSON('${ MITX_ROOT_URL }/modx/problem/${ id }/problem_save',
submit_data,
function(data) {
if(data.success) {
alert('Saved');
}});
log_event('problem_save', submit_data);
});
}
function ${ id }_load() {
$('#main_${ id }').load('${ ajax_url }problem_get?id=${ id }', ${ id }_content_updated);
}
$(function() {
${ id }_load();
});
<section id="problem_${element_id}" class="problems-wrapper" problem-id="${id}" data-url="${ajax_url}"></section> <section id="problem_${element_id}" class="problems-wrapper" data-problem-id="${id}" data-url="${ajax_url}"></section>
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
<%block name="js_extra"> <%block name="js_extra">
<script type="text/javascript"> <script type="text/javascript">
$(function(){ $(function(){
new Sequence('${item_id}', '${element_id}', ${items}, '${tag}', ${position}); new Sequence('${item_id}', 'sequence_${element_id}', ${items}, '${tag}', ${position});
}); });
</script> </script>
</%block> </%block>
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