From df5520bdf96d39b9299405141a0d45f5ec794476 Mon Sep 17 00:00:00 2001 From: Chris Rodriguez Date: Fri, 5 Feb 2016 09:30:34 -0500 Subject: [PATCH] Video player: adding Dragabilly to closed captions * tests for dragging * icon location reference updates * pattern library usage --- cms/envs/common.py | 1 + cms/static/cms/js/require-config.js | 12 +- cms/static/coffee/spec/main.coffee | 11 +- cms/static/coffee/spec/main_squire.coffee | 11 +- cms/static/js_test.yml | 5 +- .../xmodule/xmodule/css/video/display.scss | 50 ++- common/lib/xmodule/xmodule/html_module.py | 2 +- common/lib/xmodule/xmodule/js/js_test.yml | 4 + .../xmodule/xmodule/js/spec/main_requirejs.js | 12 +- .../xmodule/js/src/video/09_video_caption.js | 28 +- .../static/common/js/spec/main_requirejs.js | 12 +- .../js/vendor/afontgarde/afontgarde.css | 2 +- .../static/js/vendor/afontgarde/afontgarde.js | 287 ------------------ .../static/js/vendor/afontgarde/edx-icons.js | 7 - .../modernizr.fontface-generatedcontent.js | 4 - .../{draggabilly.pkgd.js => draggabilly.js} | 0 common/static/js_test.yml | 4 + .../tests/video/test_video_module.py | 38 +++ lms/envs/common.py | 11 +- lms/static/js/spec/main.js | 12 +- lms/static/lms/js/build.js | 1 + lms/static/lms/js/require-config.js | 14 + package.json | 2 +- 23 files changed, 195 insertions(+), 335 deletions(-) delete mode 100644 common/static/js/vendor/afontgarde/afontgarde.js delete mode 100644 common/static/js/vendor/afontgarde/edx-icons.js delete mode 100644 common/static/js/vendor/afontgarde/modernizr.fontface-generatedcontent.js rename common/static/js/vendor/{draggabilly.pkgd.js => draggabilly.js} (100%) diff --git a/cms/envs/common.py b/cms/envs/common.py index dc65e725e1..588538c958 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -543,6 +543,7 @@ from openedx.core.lib.rooted_paths import rooted_glob PIPELINE_CSS = { 'style-vendor': { 'source_filenames': [ + 'js/vendor/afontgarde/afontgarde.css', 'css/vendor/normalize.css', 'css/vendor/font-awesome.css', 'css/vendor/html5-input-polyfills/number-polyfill.css', diff --git a/cms/static/cms/js/require-config.js b/cms/static/cms/js/require-config.js index 18c76dd2a7..c4f9092123 100644 --- a/cms/static/cms/js/require-config.js +++ b/cms/static/cms/js/require-config.js @@ -63,10 +63,13 @@ "xblock": "coffee/src/xblock", "utility": "js/src/utility", "accessibility": "js/src/accessibility_tools", - "draggabilly": "js/vendor/draggabilly.pkgd", "URI": "js/vendor/URI.min", "ieshim": "js/src/ie_shim", "tooltip_manager": "js/src/tooltip_manager", + "modernizr": "edx-pattern-library/js/modernizr-custom", + "afontgarde": "edx-pattern-library/js/afontgarde", + "edxicons": "edx-pattern-library/js/edx-icons", + "draggabilly": "js/vendor/draggabilly", // Files needed for Annotations feature "annotator": "js/vendor/ova/annotator-full", @@ -241,7 +244,6 @@ exports: "XBlock", deps: ["xblock/core"] }, - "coffee/src/main": { deps: ["coffee/src/ajax_prefix"] }, @@ -249,6 +251,12 @@ exports: "Logger", deps: ["coffee/src/ajax_prefix"] }, + "modernizr": { + exports: "Modernizr" + }, + "afontgarde": { + exports: "AFontGarde" + }, // the following are all needed for annotation tools "video.dev": { diff --git a/cms/static/coffee/spec/main.coffee b/cms/static/coffee/spec/main.coffee index 84621b8eb3..b7efe681c3 100644 --- a/cms/static/coffee/spec/main.coffee +++ b/cms/static/coffee/spec/main.coffee @@ -46,10 +46,13 @@ requirejs.config({ "jasmine-imagediff": "xmodule_js/common_static/js/vendor/jasmine-imagediff", "jasmine-stealth": "xmodule_js/common_static/js/vendor/jasmine-stealth", "jasmine.async": "xmodule_js/common_static/js/vendor/jasmine.async", - "draggabilly": "xmodule_js/common_static/js/vendor/draggabilly.pkgd", + "draggabilly": "xmodule_js/common_static/js/vendor/draggabilly", "domReady": "xmodule_js/common_static/js/vendor/domReady", "URI": "xmodule_js/common_static/js/vendor/URI.min", "mock-ajax": "xmodule_js/common_static/js/vendor/mock-ajax", + "modernizr": "xmodule_js/common_static/edx-pattern-library/js/modernizr-custom", + "afontgarde": "xmodule_js/common_static/edx-pattern-library/js/afontgarde", + "edxicons": "xmodule_js/common_static/edx-pattern-library/js/edx-icons", "mathjax": "//cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured", "youtube": "//www.youtube.com/player_api?noext", @@ -206,6 +209,12 @@ requirejs.config({ }, "coffee/src/ajax_prefix": { deps: ["jquery"] + }, + "modernizr": { + exports: "Modernizr" + }, + "afontgarde": { + exports: "AFontGarde" } } }); diff --git a/cms/static/coffee/spec/main_squire.coffee b/cms/static/coffee/spec/main_squire.coffee index a562cd98e3..afd40603df 100644 --- a/cms/static/coffee/spec/main_squire.coffee +++ b/cms/static/coffee/spec/main_squire.coffee @@ -38,7 +38,10 @@ requirejs.config({ "squire": "xmodule_js/common_static/js/vendor/Squire", "jasmine-stealth": "xmodule_js/common_static/js/vendor/jasmine-stealth", "jasmine.async": "xmodule_js/common_static/js/vendor/jasmine.async", - "draggabilly": "xmodule_js/common_static/js/vendor/draggabilly.pkgd", + "modernizr": "xmodule_js/common_static/edx-pattern-library/js/modernizr-custom", + "afontgarde": "xmodule_js/common_static/edx-pattern-library/js/afontgarde", + "edxicons": "xmodule_js/common_static/edx-pattern-library/js/edx-icons", + "draggabilly": "xmodule_js/common_static/js/vendor/draggabilly", "domReady": "xmodule_js/common_static/js/vendor/domReady", "URI": "xmodule_js/common_static/js/vendor/URI.min", @@ -176,6 +179,12 @@ requirejs.config({ }, "coffee/src/ajax_prefix": { deps: ["jquery"] + }, + "modernizr": { + exports: "Modernizr" + }, + "afontgarde": { + exports: "AFontGarde" } } }); diff --git a/cms/static/js_test.yml b/cms/static/js_test.yml index 169bd088b3..92a8dcfa39 100644 --- a/cms/static/js_test.yml +++ b/cms/static/js_test.yml @@ -56,7 +56,7 @@ lib_paths: - xmodule_js/common_static/js/vendor/jQuery-File-Upload/js - xmodule_js/src/xmodule.js - xmodule_js/common_static/js/test/i18n.js - - xmodule_js/common_static/js/vendor/draggabilly.pkgd.js + - xmodule_js/common_static/js/vendor/draggabilly.js - xmodule_js/common_static/js/vendor/date.js - xmodule_js/common_static/js/vendor/domReady.js - xmodule_js/common_static/js/vendor/URI.min.js @@ -70,6 +70,9 @@ lib_paths: - xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate.js - xmodule_js/common_static/js/vendor/mock-ajax.js - xmodule_js/common_static/js/vendor/requirejs/text.js + - xmodule_js/common_static/edx-pattern-library/js/modernizr-custom.js + - xmodule_js/common_static/edx-pattern-library/js/afontgarde.js + - xmodule_js/common_static/edx-pattern-library/js/edx-icons.js # Paths to source JavaScript files src_paths: diff --git a/common/lib/xmodule/xmodule/css/video/display.scss b/common/lib/xmodule/xmodule/css/video/display.scss index 5de928ab08..a786aebcec 100644 --- a/common/lib/xmodule/xmodule/css/video/display.scss +++ b/common/lib/xmodule/xmodule/css/video/display.scss @@ -10,54 +10,54 @@ // -------- // the html target is necessary for xblocks and xmodules, but works across the board -html:not('.afontgarde') .icon-fallback-img { +.icon-fallback-img { .fa-play { - background: url('#{$static-path}/images/fontawesome/play.svg') center center no-repeat; + background: url('#{$static-path}/edx-pattern-library/fonts/edx-icons/fallback-img/play.svg') center center no-repeat; } .fa-pause { - background: url('#{$static-path}/images/fontawesome/pause.svg') center center no-repeat; + background: url('#{$static-path}/edx-pattern-library/fonts/edx-icons/fallback-img/pause.svg') center center no-repeat; } .fa-step-forward { - background: url('#{$static-path}/images/fontawesome/step-forward.svg') center center no-repeat; + background: url('#{$static-path}/edx-pattern-library/fonts/edx-icons/fallback-img/fast-forward.svg') center center no-repeat; } .fa-arrows-alt { - background: url('#{$static-path}/images/fontawesome/arrows-alt.svg') center center no-repeat; + background: url('#{$static-path}/edx-pattern-library/fonts/edx-icons/fallback-img/fullscreen.svg') center center no-repeat; } .fa-caret-right { - background: url('#{$static-path}/images/fontawesome/caret-right.svg') center center no-repeat; + background: url('#{$static-path}/edx-pattern-library/fonts/edx-icons/fallback-img/caret-right.svg') center center no-repeat; } .fa-caret-left { - background: url('#{$static-path}/images/fontawesome/caret-left.svg') center center no-repeat; + background: url('#{$static-path}/edx-pattern-library/fonts/edx-icons/fallback-img/caret-left.svg') center center no-repeat; } .fa-caret-up { - background: url('#{$static-path}/images/fontawesome/caret-up.svg') center center no-repeat; + background: url('#{$static-path}/edx-pattern-library/fonts/edx-icons/fallback-img/caret-up.svg') center center no-repeat; } .fa-compress { - background: url('#{$static-path}/images/fontawesome/compress.svg') center center no-repeat; + background: url('#{$static-path}/edx-pattern-library/fonts/edx-icons/fallback-img/exit-fullscreen.svg') center center no-repeat; } .fa-quote-left { - background: url('#{$static-path}/images/fontawesome/quote-left.svg') center center no-repeat; + background: url('#{$static-path}/edx-pattern-library/fonts/edx-icons/fallback-img/quote-left.svg') center center no-repeat; } .fa-volume-up { - background: url('#{$static-path}/images/fontawesome/volume-up.svg') center center no-repeat; + background: url('#{$static-path}/edx-pattern-library/fonts/edx-icons/fallback-img/volume-up.svg') center center no-repeat; } .fa-volume-down { - background: url('#{$static-path}/images/fontawesome/volume-down.svg') center center no-repeat; + background: url('#{$static-path}/edx-pattern-library/fonts/edx-icons/fallback-img/volume-down.svg') center center no-repeat; } .fa-volume-off { - background: url('#{$static-path}/images/fontawesome/volume-off.svg') center center no-repeat; + background: url('#{$static-path}/edx-pattern-library/fonts/edx-icons/fallback-img/volume-off.svg') center center no-repeat; } } @@ -261,6 +261,28 @@ html:not('.afontgarde') .icon-fallback-img { padding: 8px ($baseline / 2) 8px ($baseline * 1.5); background: rgba(0, 0, 0, .75); color: $yellow; + + &:before { + position: absolute; + display: inline-block; + top: 50%; + @include left($baseline); + margin-top: -.6em; + font-family: 'FontAwesome'; + content: "\f142"; + color: $white; + opacity: 0.5; + } + + &:hover, + &.is-dragging { + background: rgba(0, 0, 0, 1.0); + cursor: move; + + &:before { + opacity: 1.0; + } + } } .video-player { @@ -289,7 +311,7 @@ html:not('.afontgarde') .icon-fallback-img { width: 100%; } - h3 { + h4 { text-align: center; color: white; diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py index 83a3ab415e..209d6234e3 100644 --- a/common/lib/xmodule/xmodule/html_module.py +++ b/common/lib/xmodule/xmodule/html_module.py @@ -98,7 +98,7 @@ class HtmlModuleMixin(HtmlBlock, XModule): 'js': [ resource_string(__name__, 'js/src/collapsible.js'), resource_string(__name__, 'js/src/html/imageModal.js'), - resource_string(__name__, 'js/common_static/js/vendor/draggabilly.pkgd.js'), + resource_string(__name__, 'js/common_static/js/vendor/draggabilly.js'), ] } js_module_name = "HTMLModule" diff --git a/common/lib/xmodule/xmodule/js/js_test.yml b/common/lib/xmodule/xmodule/js/js_test.yml index 38fd0aa094..305536d996 100644 --- a/common/lib/xmodule/xmodule/js/js_test.yml +++ b/common/lib/xmodule/xmodule/js/js_test.yml @@ -59,6 +59,10 @@ lib_paths: - public/js/split_test_staff.js - common_static/js/src/accessibility_tools.js - common_static/js/vendor/moment.min.js + - common_static/js/vendor/draggabilly.js + - common_static/edx-pattern-library/js/modernizr-custom.js + - common_static/edx-pattern-library/js/afontgarde.js + - common_static/edx-pattern-library/js/edx-icons.js - spec/main_requirejs.js # Paths to spec (test) JavaScript files diff --git a/common/lib/xmodule/xmodule/js/spec/main_requirejs.js b/common/lib/xmodule/xmodule/js/spec/main_requirejs.js index 405c92801d..040d065a72 100644 --- a/common/lib/xmodule/xmodule/js/spec/main_requirejs.js +++ b/common/lib/xmodule/xmodule/js/spec/main_requirejs.js @@ -1,10 +1,20 @@ (function(requirejs) { requirejs.config({ paths: { - "moment": "xmodule/include/common_static/js/vendor/moment.min" + "moment": "xmodule/include/common_static/js/vendor/moment.min", + "modernizr": "xmodule/include/common_static/edx-pattern-library/js/modernizr-custom", + "afontgarde": "xmodule/include/common_static/edx-pattern-library/js/afontgarde", + "edxicons": "xmodule/include/common_static/edx-pattern-library/js/edx-icons", + "draggabilly": "xmodule/include/common_static/js/vendor/draggabilly" }, "moment": { exports: "moment" + }, + "modernizr": { + exports: "Modernizr" + }, + "afontgarde": { + exports: "AFontGarde" } }); diff --git a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js index f41908156d..8d315ad215 100644 --- a/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js +++ b/common/lib/xmodule/xmodule/js/src/video/09_video_caption.js @@ -2,11 +2,14 @@ // VideoCaption module. 'use strict'; - define('video/09_video_caption.js', [ + define('video/09_video_caption.js',[ 'video/00_sjson.js', - 'video/00_async_process.js' - ], - function (Sjson, AsyncProcess) { + 'video/00_async_process.js', + 'draggabilly', + 'modernizr', + 'afontgarde', + 'edxicons' + ], function (Sjson, AsyncProcess, Draggabilly) { /** * @desc VideoCaption module exports a function. @@ -33,12 +36,14 @@ 'handleKeypress', 'handleKeypressLink', 'openLanguageMenu', 'closeLanguageMenu', 'previousLanguageMenuItem', 'nextLanguageMenuItem', 'handleCaptionToggle', 'showClosedCaptions', 'hideClosedCaptions', 'toggleClosedCaptions', - 'updateCaptioningCookie', 'handleCaptioningCookie', 'handleTranscriptToggle' + 'updateCaptioningCookie', 'handleCaptioningCookie', 'handleTranscriptToggle', + 'listenForDragDrop' ); this.state = state; this.state.videoCaption = this; this.renderElements(); this.handleCaptioningCookie(); + this.listenForDragDrop(); return $.Deferred().resolve().promise(); }; @@ -531,7 +536,7 @@ if (state.isTouch) { self.subtitlesEl.find('.subtitles-menu') .text(gettext('Transcript will be displayed when you start playing the video.')) // jshint ignore: line - .wrapInner('
  • '); + .wrapInner('
  • '); } else { self.renderCaption(start, captions); } @@ -1147,6 +1152,17 @@ } }, + listenForDragDrop: function() { + var captions = document.querySelector('.closed-captions'), + draggable; + + if (typeof Draggabilly === "function") { + draggable = new Draggabilly(captions, { containment: true }); + } else { + console.log('Closed captioning available but not draggable'); + } + }, + /** * @desc Shows/Hides captions and updates the cookie. * diff --git a/common/static/common/js/spec/main_requirejs.js b/common/static/common/js/spec/main_requirejs.js index 3318f8657c..eb8f6b0cf1 100644 --- a/common/static/common/js/spec/main_requirejs.js +++ b/common/static/common/js/spec/main_requirejs.js @@ -32,7 +32,11 @@ 'jasmine-imagediff': 'js/vendor/jasmine-imagediff', 'jasmine-stealth': 'js/vendor/jasmine-stealth', 'jasmine.async': 'js/vendor/jasmine.async', - 'URI': 'js/vendor/URI.min' + 'URI': 'js/vendor/URI.min', + 'modernizr': 'edx-pattern-library/js/modernizr-custom', + 'afontgarde': 'edx-pattern-library/js/afontgarde', + 'edxicons': 'edx-pattern-library/js/edx-icons', + 'draggabilly': 'js/vendor/draggabilly', }, shim: { 'gettext': { @@ -149,6 +153,12 @@ }, "sinon": { exports: "sinon" + }, + "modernizr": { + exports: "Modernizr" + }, + "afontgarde": { + exports: "AFontGarde" } } }); diff --git a/common/static/js/vendor/afontgarde/afontgarde.css b/common/static/js/vendor/afontgarde/afontgarde.css index 89c32ea6b0..a8fa9157f2 100644 --- a/common/static/js/vendor/afontgarde/afontgarde.css +++ b/common/static/js/vendor/afontgarde/afontgarde.css @@ -57,4 +57,4 @@ html:not('.afontgarde') .icon-fallback-img .icon:before { /* The img fallback version is not as reliable since it does not check to make sure the fontloaded font has loaded. If we did add the .fontloaded class, it would unnecessarily request the fallback image. */ .fontawesome .icon-fallback-img .icon { background-image: none; -} \ No newline at end of file +} diff --git a/common/static/js/vendor/afontgarde/afontgarde.js b/common/static/js/vendor/afontgarde/afontgarde.js deleted file mode 100644 index 3bf3465c97..0000000000 --- a/common/static/js/vendor/afontgarde/afontgarde.js +++ /dev/null @@ -1,287 +0,0 @@ -/*! afontgarde - v0.1.6 - 2015-03-13 - * https://github.com/filamentgroup/a-font-garde - * Copyright (c) 2015 Filament Group c/o Zach Leatherman - * MIT License */ - -/*! fontfaceonload - v0.1.6 - 2015-03-13 - * https://github.com/zachleat/fontfaceonload - * Copyright (c) 2015 Zach Leatherman (@zachleat) - * MIT License */ - -;(function( win, doc ) { - "use strict"; - - var TEST_STRING = 'AxmTYklsjo190QW', - SANS_SERIF_FONTS = 'sans-serif', - SERIF_FONTS = 'serif', - - // lighter and bolder not supported - weightLookup = { - normal: '400', - bold: '700' - }, - - defaultOptions = { - tolerance: 2, // px - delay: 100, - glyphs: '', - success: function() {}, - error: function() {}, - timeout: 5000, - weight: '400', // normal - style: 'normal' - }, - - // See https://github.com/typekit/webfontloader/blob/master/src/core/fontruler.js#L41 - style = [ - 'display:block', - 'position:absolute', - 'top:-999px', - 'left:-999px', - 'font-size:48px', - 'width:auto', - 'height:auto', - 'line-height:normal', - 'margin:0', - 'padding:0', - 'font-variant:normal', - 'white-space:nowrap' - ], - html = '
    ' + TEST_STRING + '
    '; - - var FontFaceOnloadInstance = function() { - this.fontFamily = ''; - this.appended = false; - this.serif = undefined; - this.sansSerif = undefined; - this.parent = undefined; - this.options = {}; - }; - - FontFaceOnloadInstance.prototype.getMeasurements = function () { - return { - sansSerif: { - width: this.sansSerif.offsetWidth, - height: this.sansSerif.offsetHeight - }, - serif: { - width: this.serif.offsetWidth, - height: this.serif.offsetHeight - } - }; - }; - - FontFaceOnloadInstance.prototype.load = function () { - var startTime = new Date(), - that = this, - serif = that.serif, - sansSerif = that.sansSerif, - parent = that.parent, - appended = that.appended, - dimensions, - options = this.options, - ref = options.reference; - - function getStyle( family ) { - return style - .concat( [ 'font-weight:' + options.weight, 'font-style:' + options.style ] ) - .concat( "font-family:" + family ) - .join( ";" ); - } - - var sansSerifHtml = html.replace( /\%s/, getStyle( SANS_SERIF_FONTS ) ), - serifHtml = html.replace( /\%s/, getStyle( SERIF_FONTS ) ); - - if( !parent ) { - parent = that.parent = doc.createElement( "div" ); - } - - parent.innerHTML = sansSerifHtml + serifHtml; - sansSerif = that.sansSerif = parent.firstChild; - serif = that.serif = sansSerif.nextSibling; - - if( options.glyphs ) { - sansSerif.innerHTML += options.glyphs; - serif.innerHTML += options.glyphs; - } - - function hasNewDimensions( dims, el, tolerance ) { - return Math.abs( dims.width - el.offsetWidth ) > tolerance || - Math.abs( dims.height - el.offsetHeight ) > tolerance; - } - - function isTimeout() { - return ( new Date() ).getTime() - startTime.getTime() > options.timeout; - } - - (function checkDimensions() { - if( !ref ) { - ref = doc.body; - } - if( !appended && ref ) { - ref.appendChild( parent ); - appended = that.appended = true; - - dimensions = that.getMeasurements(); - - // Make sure we set the new font-family after we take our initial dimensions: - // handles the case where FontFaceOnload is called after the font has already - // loaded. - sansSerif.style.fontFamily = that.fontFamily + ', ' + SANS_SERIF_FONTS; - serif.style.fontFamily = that.fontFamily + ', ' + SERIF_FONTS; - } - - if( appended && dimensions && - ( hasNewDimensions( dimensions.sansSerif, sansSerif, options.tolerance ) || - hasNewDimensions( dimensions.serif, serif, options.tolerance ) ) ) { - - options.success(); - } else if( isTimeout() ) { - options.error(); - } else { - if( !appended && "requestAnimationFrame" in window ) { - win.requestAnimationFrame( checkDimensions ); - } else { - win.setTimeout( checkDimensions, options.delay ); - } - } - })(); - }; // end load() - - FontFaceOnloadInstance.prototype.checkFontFaces = function( timeout ) { - var _t = this; - doc.fonts.forEach(function( font ) { - if( font.family.toLowerCase() === _t.fontFamily.toLowerCase() && - ( weightLookup[ font.weight ] || font.weight ) === ''+_t.options.weight && - font.style === _t.options.style ) { - font.load().then(function() { - _t.options.success(); - win.clearTimeout( timeout ); - }); - } - }); - }; - - FontFaceOnloadInstance.prototype.init = function( fontFamily, options ) { - var timeout; - - for( var j in defaultOptions ) { - if( !options.hasOwnProperty( j ) ) { - options[ j ] = defaultOptions[ j ]; - } - } - - this.options = options; - this.fontFamily = fontFamily; - - // For some reason this was failing on afontgarde + icon fonts. - if( !options.glyphs && "fonts" in doc ) { - if( options.timeout ) { - timeout = win.setTimeout(function() { - options.error(); - }, options.timeout ); - } - - this.checkFontFaces( timeout ); - } else { - this.load(); - } - }; - - var FontFaceOnload = function( fontFamily, options ) { - var instance = new FontFaceOnloadInstance(); - instance.init(fontFamily, options); - - return instance; - }; - - // intentional global - win.FontFaceOnload = FontFaceOnload; -})( this, this.document ); - -/* - * A Font Garde - */ - -;(function( w ) { - - var doc = w.document, - ref, - css = ['.FONT_NAME.supports-generatedcontent .icon-fallback-text .icon { display: inline-block; }', - '.FONT_NAME.supports-generatedcontent .icon-fallback-text .text { clip: rect(0 0 0 0); overflow: hidden; position: absolute; height: 1px; width: 1px; }', - '.FONT_NAME .icon-fallback-glyph .icon:before { font-size: 1em; font-size: inherit; line-height: 1; line-height: inherit; }']; - - function addEvent( type, callback ) { - if( 'addEventListener' in w ) { - return w.addEventListener( type, callback, false ); - } else if( 'attachEvent' in w ) { - return w.attachEvent( 'on' + type, callback ); - } - } - - // options can be a string of glyphs or an options object to pass into FontFaceOnload - AFontGarde = function( fontFamily, options ) { - var fontFamilyClassName = fontFamily.toLowerCase().replace( /\s/g, '' ), - executed = false; - - function init() { - if( executed ) { - return; - } - executed = true; - - if( typeof FontFaceOnload === 'undefined' ) { - throw 'FontFaceOnload is a prerequisite.'; - } - - if( !ref ) { - ref = doc.getElementsByTagName( 'script' )[ 0 ]; - } - var style = doc.createElement( 'style' ), - cssContent = css.join( '\n' ).replace( /FONT_NAME/gi, fontFamilyClassName ); - - style.setAttribute( 'type', 'text/css' ); - if( style.styleSheet ) { - style.styleSheet.cssText = cssContent; - } else { - style.appendChild( doc.createTextNode( cssContent ) ); - } - ref.parentNode.insertBefore( style, ref ); - - var opts = { - timeout: 5000, - success: function() { - // If you’re using more than one icon font, change this classname (and in a-font-garde.css) - doc.documentElement.className += ' ' + fontFamilyClassName; - - if( options && options.success ) { - options.success(); - } - } - }; - - // These characters are a few of the glyphs from the font above */ - if( typeof options === "string" ) { - opts.glyphs = options; - } else { - for( var j in options ) { - if( options.hasOwnProperty( j ) && j !== "success" ) { - opts[ j ] = options[ j ]; - } - } - } - - FontFaceOnload( fontFamily, opts ); - } - - // MIT credit: filamentgroup/shoestring - addEvent( "DOMContentLoaded", init ); - addEvent( "readystatechange", init ); - addEvent( "load", init ); - - if( doc.readyState === "complete" ){ - init(); - } - }; - -})( this ); \ No newline at end of file diff --git a/common/static/js/vendor/afontgarde/edx-icons.js b/common/static/js/vendor/afontgarde/edx-icons.js deleted file mode 100644 index dec6d2c935..0000000000 --- a/common/static/js/vendor/afontgarde/edx-icons.js +++ /dev/null @@ -1,7 +0,0 @@ -(function() { - 'use strict'; - - window.AFontGarde('FontAwesome', { - glyphs: '' - }); -}); diff --git a/common/static/js/vendor/afontgarde/modernizr.fontface-generatedcontent.js b/common/static/js/vendor/afontgarde/modernizr.fontface-generatedcontent.js deleted file mode 100644 index 58bf650026..0000000000 --- a/common/static/js/vendor/afontgarde/modernizr.fontface-generatedcontent.js +++ /dev/null @@ -1,4 +0,0 @@ -/* Modernizr 2.7.1 (Custom Build) | MIT & BSD - * Build: http://modernizr.com/download/#-fontface-generatedcontent-cssclasses-teststyles-cssclassprefix:supports! - */ -;window.Modernizr=function(a,b,c){function w(a){j.cssText=a}function x(a,b){return w(prefixes.join(a+";")+(b||""))}function y(a,b){return typeof a===b}function z(a,b){return!!~(""+a).indexOf(b)}function A(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:y(f,"function")?f.bind(d||b):f}return!1}var d="2.7.1",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l=":)",m={}.toString,n={},o={},p={},q=[],r=q.slice,s,t=function(a,c,d,e){var f,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:h+(d+1),l.appendChild(j);return f=["­",'"].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},u={}.hasOwnProperty,v;!y(u,"undefined")&&!y(u.call,"undefined")?v=function(a,b){return u.call(a,b)}:v=function(a,b){return b in a&&y(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=r.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(r.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(r.call(arguments)))};return e}),n.fontface=function(){var a;return t('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},n.generatedcontent=function(){var a;return t(["#",h,"{font:0/0 a}#",h,':after{content:"',l,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a};for(var B in n)v(n,B)&&(s=B.toLowerCase(),e[s]=n[B](),q.push((e[s]?"":"no-")+s));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)v(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" supports-"+(b?"":"no-")+a),e[a]=b}return e},w(""),i=k=null,e._version=d,e.testStyles=t,g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" supports-js supports-"+q.join(" supports-"):""),e}(this,this.document); \ No newline at end of file diff --git a/common/static/js/vendor/draggabilly.pkgd.js b/common/static/js/vendor/draggabilly.js similarity index 100% rename from common/static/js/vendor/draggabilly.pkgd.js rename to common/static/js/vendor/draggabilly.js diff --git a/common/static/js_test.yml b/common/static/js_test.yml index 8491ee18c6..13cea1b163 100644 --- a/common/static/js_test.yml +++ b/common/static/js_test.yml @@ -38,10 +38,14 @@ lib_paths: - js/vendor/backbone-min.js - js/vendor/jquery.timeago.js - js/vendor/URI.min.js + - js/vendor/draggabilly.js - coffee/src/ajax_prefix.js - js/test/add_ajax_prefix.js - js/test/i18n.js - coffee/src/jquery.immediateDescendents.js + - edx-pattern-library/js/modernizr-custom.js + - edx-pattern-library/js/afontgarde.js + - edx-pattern-library/js/edx-icons.js # Paths to source JavaScript files src_paths: diff --git a/common/test/acceptance/tests/video/test_video_module.py b/common/test/acceptance/tests/video/test_video_module.py index bcff620033..09c09344dd 100644 --- a/common/test/acceptance/tests/video/test_video_module.py +++ b/common/test/acceptance/tests/video/test_video_module.py @@ -8,6 +8,8 @@ import os from mock import patch from nose.plugins.attrib import attr from unittest import skipIf, skip +from selenium.webdriver.common.by import By +from selenium.webdriver.common.action_chains import ActionChains from ..helpers import UniqueCourseTest, is_youtube_available, YouTubeStubConfig from ...pages.lms.video.video import VideoPage from ...pages.lms.tab_nav import TabNavPage @@ -1189,6 +1191,42 @@ class YouTubeQualityTest(VideoBaseTest): self.video.wait_for(lambda: self.video.is_quality_button_active, 'waiting for quality button activation') +@attr('shard_4') +class DragAndDropTest(VideoBaseTest): + """ + Tests draggability of closed captions within videos. + """ + def setUp(self): + super(DragAndDropTest, self).setUp() + + def test_if_captions_are_draggable(self): + """ + Loads transcripts so that closed-captioning is available. + Ensures they are draggable by checking start and dropped location. + """ + self.assets.append('subs_3_yD_cEKoCk.srt.sjson') + data = {'sub': '3_yD_cEKoCk'} + + self.metadata = self.metadata_for_mode('html5', additional_data=data) + self.navigate_to_video() + self.assertTrue(self.video.is_video_rendered('html5')) + self.video.show_closed_captions() + self.video.wait_for_closed_captions() + self.assertTrue(self.video.is_closed_captions_visible) + + action = ActionChains(self.browser) + captions = self.browser.find_element(By.CLASS_NAME, 'closed-captions') + + captions_start = captions.location + action.drag_and_drop_by_offset(captions, 0, -15).perform() + captions_end = captions.location + self.assertEqual( + captions_end.get('y') + 15, + captions_start.get('y'), + 'Closed captions did not get dragged.' + ) + + @attr('a11y') class LMSVideoModuleA11yTest(VideoBaseTest): """ diff --git a/lms/envs/common.py b/lms/envs/common.py index 6ad37a6ca9..1a9e310aff 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -1261,7 +1261,8 @@ base_vendor_js = [ 'js/vendor/requirejs/require.js', 'js/RequireJS-namespace-undefine.js', 'js/vendor/URI.min.js', - 'js/vendor/backbone-min.js' + 'js/vendor/backbone-min.js', + 'edx-pattern-library/js/modernizr-custom.js', ] main_vendor_js = base_vendor_js + [ @@ -1269,9 +1270,6 @@ main_vendor_js = base_vendor_js + [ 'js/vendor/jquery-ui.min.js', 'js/vendor/jquery.qtip.min.js', 'js/vendor/jquery.ba-bbq.min.js', - 'js/vendor/afontgarde/modernizr.fontface-generatedcontent.js', - 'js/vendor/afontgarde/afontgarde.js', - 'js/vendor/afontgarde/edx-icons.js' ] # Common files used by both RequireJS code and non-RequireJS code @@ -1670,7 +1668,10 @@ REQUIRE_JS_PATH_OVERRIDES = { 'js/student_account/logistration_factory': 'js/student_account/logistration_factory.js', 'js/student_profile/views/learner_profile_factory': 'js/student_profile/views/learner_profile_factory.js', 'js/bookmarks/bookmarks_factory': 'js/bookmarks/bookmarks_factory.js', - 'js/groups/views/cohorts_dashboard_factory': 'js/groups/views/cohorts_dashboard_factory.js' + 'js/groups/views/cohorts_dashboard_factory': 'js/groups/views/cohorts_dashboard_factory.js', + 'afontgarde': 'edx-pattern-library/js/afontgarde.js', + 'edxicons': 'edx-pattern-library/js/edx-icons.js', + 'draggabilly': 'js/vendor/draggabilly.js' } ################################# CELERY ###################################### diff --git a/lms/static/js/spec/main.js b/lms/static/js/spec/main.js index 8e2b0a3b63..0287a265e7 100644 --- a/lms/static/js/spec/main.js +++ b/lms/static/js/spec/main.js @@ -47,7 +47,6 @@ 'jasmine-imagediff': 'xmodule_js/common_static/js/vendor/jasmine-imagediff', 'jasmine-stealth': 'xmodule_js/common_static/js/vendor/jasmine-stealth', 'jasmine.async': 'xmodule_js/common_static/js/vendor/jasmine.async', - 'draggabilly': 'xmodule_js/common_static/js/vendor/draggabilly.pkgd', 'domReady': 'xmodule_js/common_static/js/vendor/domReady', 'mathjax': '//cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // jshint ignore:line 'youtube': '//www.youtube.com/player_api?noext', @@ -67,6 +66,10 @@ 'mathjax_delay_renderer': 'coffee/src/mathjax_delay_renderer', 'MathJaxProcessor': 'coffee/src/customwmd', 'picturefill': 'common/js/vendor/picturefill.min', + 'draggabilly': 'xmodule_js/common_static/js/vendor/draggabilly', + 'modernizr': 'xmodule_js/common_static/edx-pattern-library/js/modernizr-custom', + 'afontgarde': 'xmodule_js/common_static/edx-pattern-library/js/afontgarde', + 'edxicons': 'xmodule_js/common_static/edx-pattern-library/js/edx-icons', // Manually specify LMS files that are not converted to RequireJS 'history': 'js/vendor/history', @@ -625,8 +628,13 @@ 'xmodule_js/common_static/coffee/src/discussion/utils' ], exports: 'DiscussionSpecHelper' + }, + 'modernizr': { + exports: 'Modernizr' + }, + 'afontgarde': { + exports: 'AFontGarde' } - } }); diff --git a/lms/static/lms/js/build.js b/lms/static/lms/js/build.js index 45afb1dfa3..4ca8fb5dff 100644 --- a/lms/static/lms/js/build.js +++ b/lms/static/lms/js/build.js @@ -72,6 +72,7 @@ 'utility': 'empty:', 'URI': 'empty:', 'DiscussionModuleView': 'empty:', + 'modernizr': 'empty', // Don't bundle UI Toolkit helpers as they are loaded into the "edx" namespace 'edx-ui-toolkit/js/utils/html-utils': 'empty:', diff --git a/lms/static/lms/js/require-config.js b/lms/static/lms/js/require-config.js index c594585d0a..3f6dc119d5 100644 --- a/lms/static/lms/js/require-config.js +++ b/lms/static/lms/js/require-config.js @@ -39,6 +39,7 @@ defineDependency("Logger", "logger"); defineDependency("URI", "URI"); defineDependency("Backbone", "backbone"); + defineDependency("Modernizr", "modernizr"); // Add the UI Toolkit helper classes that have been installed in the "edx" namespace defineDependency("edx.HtmlUtils", "edx-ui-toolkit/js/utils/html-utils"); @@ -73,6 +74,10 @@ "URI": "js/vendor/URI.min", "string_utils": "js/src/string_utils", "utility": "js/src/utility", + "modernizr": "edx-pattern-library/js/modernizr-custom", + "afontgarde": "edx-pattern-library/js/afontgarde", + "edxicons": "edx-pattern-library/js/edx-icons", + "draggabilly": "js/vendor/draggabilly", // Files needed by OVA "annotator": "js/vendor/ova/annotator-full", @@ -200,6 +205,15 @@ }, "moment-with-locales": { exports: "moment" + }, + "afontgarde": { + exports: "AFontGarde" + }, + // Because Draggabilly is being used by video code, the namespaced version of + // require is not being recognized. Therefore the library is being added to the + // global namespace instead of being registered in require. + "draggabilly": { + exports: "Draggabilly" } } }); diff --git a/package.json b/package.json index 12f9c6aae0..bd881d9530 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "dependencies": { "coffee-script": "1.6.1", - "edx-pattern-library": "~0.12.1", + "edx-pattern-library": "~0.12.4", "edx-ui-toolkit": "~0.9.1", "requirejs": "~2.1.22", "uglify-js": "2.4.24",