diff --git a/.coveragerc b/.coveragerc index de7da357c1..260d9c8e50 100644 --- a/.coveragerc +++ b/.coveragerc @@ -44,8 +44,8 @@ output = reports/coverage.xml [paths] jenkins_source = - /home/jenkins/workspace/edx-platform-unit-coverage - /home/jenkins/workspace/edx-platform-test-subset + /home/jenkins/workspace/$JOB_NAME + /home/jenkins/workspace/$SUBSET_JOB devstack_source = /edx/app/edxapp/edx-platform diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000..120dab4bc1 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,60 @@ +# Vendor files and generated test artifacts +**/vendor +test_root/staticfiles + + +# Vendor files living outside the /vendor/ dir +*.min.js +*-min.js +*.nocache.js +**/bootstrap*.js +**/jquery*.js +**/d3*.js + + +# Translations files +**/static/js/i18n + + +# Gitignored xmodule stuff +common/static/xmodule + + +# Coffeescript directories (don't lint autogenerated files) +cms/static/coffee +lms/static/coffee +common/static/coffee +common/lib/capa/capa/tests/test_files/js + + +# Symlinks into common/lib/xmodule/xmodule/js +cms/static/xmodule_js +lms/static/xmodule_js + + +# This directory is about half Coffee and half JS, things get messy here so just ignore all existing coffee paths +common/lib/xmodule/xmodule/js/spec/annotatable/display_spec.js +common/lib/xmodule/xmodule/js/spec/capa/display_spec.js +common/lib/xmodule/xmodule/js/spec/html/edit_spec.js +common/lib/xmodule/xmodule/js/spec/problem/edit_spec.js +common/lib/xmodule/xmodule/js/spec/problem/edit_spec_hint.js +common/lib/xmodule/xmodule/js/spec/tabs/edit.js + +common/lib/xmodule/xmodule/js/src/annotatable/display.js +common/lib/xmodule/xmodule/js/src/capa/display.js +common/lib/xmodule/xmodule/js/src/conditional/display.js +common/lib/xmodule/xmodule/js/src/discussion/display.js +common/lib/xmodule/xmodule/js/src/html/display.js +common/lib/xmodule/xmodule/js/src/html/edit.js +common/lib/xmodule/xmodule/js/src/javascript_loader.js +common/lib/xmodule/xmodule/js/src/problem/edit.js +common/lib/xmodule/xmodule/js/src/raw/edit/json.js +common/lib/xmodule/xmodule/js/src/raw/edit/metadata-only.js +common/lib/xmodule/xmodule/js/src/raw/edit/xml.js +common/lib/xmodule/xmodule/js/src/sequence/display.js +common/lib/xmodule/xmodule/js/src/sequence/edit.js +common/lib/xmodule/xmodule/js/src/tabs/tabs-aggregator.js +common/lib/xmodule/xmodule/js/src/vertical/edit.js + +# This file is responsible for almost half of the repo's total issues. +common/lib/xmodule/xmodule/js/src/capa/schematic.js diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000000..36d4a7a626 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,23 @@ +{ + "extends": "eslint-config-edx", + "globals": { // Try to avoid adding any new globals. + // Old compatibility things and hacks + "edx": true, + "XBlock": true, + + // added by Django i18n tools + "gettext": true, + "ngettext": true, + + // added by jasmine-jquery + "loadFixtures": true, + "appendLoadFixtures": true, + "readFixtures": true, + "setFixtures": true, + "appendSetFixtures": true, + "spyOnEvent": true, + + // used by our requirejs implementation + "RequireJS": true + } +} diff --git a/.gitignore b/.gitignore index 1b55818343..4be2989f47 100644 --- a/.gitignore +++ b/.gitignore @@ -98,6 +98,7 @@ cms/static/sass/*.css cms/static/sass/*.css.map cms/static/themed_sass/ themes/**/css/*.css +themes/**/css/discussion/*.css ### Logging artifacts log/ diff --git a/.jshintignore b/.jshintignore deleted file mode 100644 index 0065f2da20..0000000000 --- a/.jshintignore +++ /dev/null @@ -1,9 +0,0 @@ -**/vendor -cms/static/cms/js/build.js -cms/static/cms/js/spec/main.js -cms/static/js/i18n/**/*.js -lms/static/js/i18n/**/*.js -lms/static/lms/js/build.js -lms/static/lms/js/spec/main.js -node_modules -venv diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 85f5d2013a..0000000000 --- a/.jshintrc +++ /dev/null @@ -1,154 +0,0 @@ -// -------------------------------------------------------------------- -// JSHint Configuration -// -------------------------------------------------------------------- -// -// http://www.jshint.com/ -// http://jshint.com/docs/options/ -{ - // == Enforcing Options =============================================== - "bitwise" : false, // Prohibits the use of bitwise operators such as ^ (XOR), | (OR) and others. Bitwise operators are very rare in JavaScript programs and quite often & is simply a mistyped &&. - "camelcase" : false, // Allows you to force all variable names to use either camelCase style or UPPER_CASE with underscores. - "curly" : true, // Requires you to always put curly braces around blocks in loops and conditionals. JavaScript allows you to omit curly braces when the block consists of only one statement - "eqeqeq" : true, // Prohibits the use of == and != in favor of === and !==. - "es3" : false, // Tells JSHint that your code needs to adhere to ECMAScript 3 specification. Use this option if you need your program to be executable in older browsers—such as Internet Explorer 6/7/8/9. - "forin" : true, // Requires all for in loops to filter object's items. - "freeze" : true, // Prohibits overwriting prototypes of native objects such as Array, Date and so on. - "immed" : true, // Prohibits the use of immediate function invocations without wrapping them in parentheses. - // "indent" : 4, // Enforces specific tab width for your code. Has no effect when "white" option is not used. - "latedef" : "nofunc", // Prohibits the use of a variable before it was defined. Setting this option to "nofunc" will allow function declarations to be ignored. - "newcap" : false, // Requires you to capitalize names of constructor functions. - "noarg" : true, // Prohibits the use of arguments.caller and arguments.callee. - "noempty" : true, // Warns when you have an empty block in your code. - "nonbsp" : true, // Warns about "non-breaking whitespace" characters. - "nonew" : true, // Prohibits the use of constructor functions for side-effects. - "plusplus" : false, // Prohibits the use of unary increment and decrement operators. - "quotmark" : false, // Enforces the consistency of quotation marks used throughout your code. It accepts three values: true, "single", and "double". - "undef" : true, // Prohibits the use of explicitly undeclared variables. - "unused" : true, // Warns when you define and never use your variables. - "strict" : true, // Requires all functions to run in ECMAScript 5's strict mode. - "trailing" : true, // Makes it an error to leave a trailing whitespace in your code. - "maxlen" : 120, // Lets you set the maximum length of a line. - //"maxparams" : 4, // Lets you set the max number of formal parameters allowed per function. - //"maxdepth" : 4, // Lets you control how nested do you want your blocks to be. - //"maxstatements" : 4, // Lets you set the max number of statements allowed per function. - //"maxcomplexity" : 4, // Lets you control cyclomatic complexity throughout your code. - - - // == Relaxing Options ================================================ - "asi" : false, // Suppresses warnings about missing semicolons. - "boss" : false, // Suppresses warnings about the use of assignments in cases where comparisons are expected. - "debug" : false, // Suppresses warnings about the debugger statements in your code. - "eqnull" : false, // Suppresses warnings about == null comparisons. - "esnext" : false, // Tells JSHint that your code uses ECMAScript 6 specific syntax. - "evil" : false, // Suppresses warnings about the use of eval. - "expr" : false, // Suppresses warnings about the use of expressions where normally you would expect to see assignments or function calls. - "funcscope" : false, // Suppresses warnings about declaring variables inside of control structures while accessing them later from the outside. - "gcl" : false, // Makes JSHint compatible with Google Closure Compiler. - "globalstrict" : false, // Suppresses warnings about the use of global strict mode. - "iterator" : false, // Suppresses warnings about the __iterator__ property. - "lastsemic" : false, // Suppresses warnings about missing semicolons, but only when the semicolon is omitted for the last statement in a one-line block. - "laxbreak" : false, // Suppresses most of the warnings about possibly unsafe line breaks in your code. - "laxcomma" : false, // Suppresses warnings about comma-first coding style. - "loopfunc" : false, // Suppresses warnings about functions inside of loops. - "maxerr" : 100, // Set the maximum amount of warnings JSHint will produce before giving up. - "moz" : false, // Tells JSHint that your code uses Mozilla JavaScript extensions. - "notypeof" : false, // Suppresses warnings about invalid typeof operator values. - "proto" : false, // Suppresses warnings about the __proto__ property. - "scripturl" : false, // Suppresses warnings about the use of script-targeted URLs—such as javascript:... - "smarttabs" : false, // Suppresses warnings about mixed tabs and spaces when the latter are used for alignment only. - "shadow" : false, // Suppresses warnings about variable shadowing i.e. declaring a variable that had been already declared somewhere in the outer scope. - "sub" : false, // Suppresses warnings about using [] notation when it can be expressed in dot notation. - "supernew" : false, // Suppresses warnings about "weird" constructions like new function () { ... } and new Object;. - "validthis" : true, // Suppresses warnings about possible strict violations when the code is running in strict mode and you use this in a non-constructor function. - "noyield" : false, // Suppresses warnings about generator functions with no yield statement in them. - - - // == Environments ==================================================== - // - // These options pre-define global variables that are exposed by - // popular JavaScript libraries and runtime environments—such as - // browser or node.js. - "browser" : true, // Defines globals exposed by modern browsers: all the way from good old document and navigator to the HTML5 FileReader and other new developments in the browser world. - "devel" : true, // Defines globals that are usually used for logging poor-man's debugging: console, alert, etc. - // The rest should remain `false`. Please see explanation for the "predef" parameter below. - "couch" : false, // Defines globals exposed by CouchDB. - "dojo" : false, // Defines globals exposed by the Dojo Toolkit - "jquery" : false, // Defines globals exposed by the jQuery JavaScript library. - "mootools" : false, // Defines globals exposed by the MooTools JavaScript framework. - "node" : false, // Defines globals available when your code is running inside of the Node runtime environment. - "nonstandard" : false, // Defines non-standard but widely adopted globals such as escape and unescape. - "phantom" : false, // Defines globals available when your core is running inside of the PhantomJS runtime environment. - "prototypejs" : false, // Defines globals exposed by the Prototype JavaScript framework. - "rhino" : false, // Defines globals available when your code is running inside of the Rhino runtime environment. - "worker" : false, // Defines globals available when your code is running inside of a Web Worker. - "wsh" : false, // Defines globals available when your code is running as a script for the Windows Script Host. - "yui" : false, // Defines globals exposed by the YUI JavaScript framework. - - - // == JSLint Legacy =================================================== - // - // These options are legacy from JSLint. Aside from bug fixes they will - // not be improved in any way and might be removed at any point. - // "nomen" : false, // Disallows the use of dangling _ in variables. - // "onevar" : false, // Allows only one var statement per function. - // "passfail" : false, // Makes JSHint stop on the first error or warning. - // "white" : false, // make JSHint check your source code against Douglas Crockford's JavaScript coding style. - - - // == Undocumented Options ============================================ - // - // If you are using some global variable, for example `define`, or `$`, please - // make it available within your JS file by passing it to the wrapper anonymous - // function like so: - // - // (function (define, $) { - // 'use strict'; - // // Your content goes here which uses `define`, and `$`. - // }).call(this, window.define, window.jQuery); - // - // The parameter "predef" should remain empty for this configuration file - // to remain as general as possible. - "predef": [ - // JavaScript global libraries - "Backbone", - "jQuery", - "$", - "_", - - // RequireJS globals - "define", - "require", - "RequireJS", - - // Jasmine globals - "jasmine", - "describe", "xdescribe", - "it", "xit", - "spyOn", - "beforeEach", - "afterEach", - "expect", - "waitsFor", - "runs", - - // jQuery-Jasmine globals - "loadFixtures", - "appendLoadFixtures", - "readFixtures", - "setFixtures", - "appendSetFixtures", - "spyOnEvent", - - // Django i18n catalog globals - "interpolate", - "gettext", - "ngettext", - - // Miscellaneous globals - "JSON", - - // edX globals - "edx", - "XBlock" - ] -} diff --git a/cms/djangoapps/contentstore/features/course-settings.py b/cms/djangoapps/contentstore/features/course-settings.py index 350eb0392e..df44ef9917 100644 --- a/cms/djangoapps/contentstore/features/course-settings.py +++ b/cms/djangoapps/contentstore/features/course-settings.py @@ -3,7 +3,7 @@ from lettuce import world, step from selenium.webdriver.common.keys import Keys -from common import type_in_codemirror, upload_file +from cms.djangoapps.contentstore.features.common import type_in_codemirror from django.conf import settings from nose.tools import assert_true, assert_false diff --git a/cms/djangoapps/contentstore/features/course-updates.feature b/cms/djangoapps/contentstore/features/course-updates.feature index 79d6445194..f71d6c3d78 100644 --- a/cms/djangoapps/contentstore/features/course-updates.feature +++ b/cms/djangoapps/contentstore/features/course-updates.feature @@ -2,46 +2,6 @@ Feature: CMS.Course updates As a course author, I want to be able to provide updates to my students -# Commenting out as flaky TNL-5051 07/20/2016 - # Internet explorer can't select all so the update appears weirdly -# @skip_internetexplorer -# Scenario: Users can add updates -# Given I have opened a new course in Studio -# And I go to the course updates page -# When I add a new update with the text "Hello" -# Then I should see the update "Hello" -# And I see a "saving" notification - -# Commenting out as flaky TNL-5051 07/20/2016 -# # Internet explorer can't select all so the update appears weirdly -# @skip_internetexplorer -# Scenario: Users can edit updates -# Given I have opened a new course in Studio -# And I go to the course updates page -# When I add a new update with the text "Hello" -# And I modify the text to "Goodbye" -# Then I should see the update "Goodbye" -# And I see a "saving" notification - -# Commenting out as flaky TNL-5051 07/20/2016 -# Scenario: Users can delete updates -# Given I have opened a new course in Studio -# And I go to the course updates page -# And I add a new update with the text "Hello" -# And I delete the update -# And I confirm the prompt -# Then I should not see the update "Hello" -# And I see a "deleting" notification - -# Commenting out as flaky TNL-5051 07/20/2016 -# Scenario: Users can edit update dates -# Given I have opened a new course in Studio -# And I go to the course updates page -# And I add a new update with the text "Hello" -# When I edit the date to "06/01/13" -# Then I should see the date "June 1, 2013" -# And I see a "saving" notification - # Internet explorer can't select all so the update appears weirdly @skip_internetexplorer Scenario: Users can change handouts @@ -51,26 +11,6 @@ Feature: CMS.Course updates Then I see the handout "Test" And I see a "saving" notification - Scenario: Text outside of tags is preserved - Given I have opened a new course in Studio - And I go to the course updates page - When I add a new update with the text "before middle after" - Then I should see the update "before middle after" - And when I reload the page - Then I should see the update "before middle after" - -# Commenting out as flaky TNL-5051 07/22/2016 -# Scenario: Static links are rewritten when previewing a course update -# Given I have opened a new course in Studio -# And I go to the course updates page -# When I add a new update with the text "" -# # Can only do partial text matches because of the quotes with in quotes (and regexp step matching). -# Then I should see the asset update to "my_img.jpg" -# And I change the update from "/static/my_img.jpg" to "" -# Then I should see the asset update to "modified.jpg" -# And when I reload the page -# Then I should see the asset update to "modified.jpg" - Scenario: Static links are rewritten when previewing handouts Given I have opened a new course in Studio And I go to the course updates page diff --git a/cms/djangoapps/contentstore/features/course-updates.py b/cms/djangoapps/contentstore/features/course-updates.py index 90db6bbd53..3a9d0103c6 100644 --- a/cms/djangoapps/contentstore/features/course-updates.py +++ b/cms/djangoapps/contentstore/features/course-updates.py @@ -1,8 +1,7 @@ # pylint: disable=missing-docstring +from cms.djangoapps.contentstore.features.common import type_in_codemirror, get_codemirror_value from lettuce import world, step -from selenium.webdriver.common.keys import Keys -from common import type_in_codemirror, get_codemirror_value from nose.tools import assert_in @@ -15,77 +14,11 @@ def go_to_updates(_step): world.wait_for_visible('#course-handouts-view') -@step(u'I add a new update with the text "([^"]*)"$') -def add_update(_step, text): - update_css = '.new-update-button' - world.css_click(update_css) - world.wait_for_visible('.CodeMirror') - change_text(text) - - -@step(u'I should see the update "([^"]*)"$') -def check_update(_step, text): - update_css = 'div.update-contents' - update_html = world.css_find(update_css).html - assert_in(text, update_html) - - -@step(u'I should see the asset update to "([^"]*)"$') -def check_asset_update(_step, asset_file): - update_css = 'div.update-contents' - update_html = world.css_find(update_css).html - asset_key = world.scenario_dict['COURSE'].id.make_asset_key(asset_type='asset', path=asset_file) - assert_in(unicode(asset_key), update_html) - - -@step(u'I should not see the update "([^"]*)"$') -def check_no_update(_step, text): - update_css = 'div.update-contents' - assert world.is_css_not_present(update_css) - - -@step(u'I modify the text to "([^"]*)"$') -def modify_update(_step, text): - button_css = 'div.post-preview .edit-button' - world.css_click(button_css) - change_text(text) - - -@step(u'I change the update from "([^"]*)" to "([^"]*)"$') -def change_existing_update(_step, before, after): - verify_text_in_editor_and_update('div.post-preview .edit-button', before, after) - - @step(u'I change the handout from "([^"]*)" to "([^"]*)"$') def change_existing_handout(_step, before, after): verify_text_in_editor_and_update('div.course-handouts .edit-button', before, after) -@step(u'I delete the update$') -def click_button(_step): - button_css = 'div.post-preview .delete-button' - world.css_click(button_css) - - -@step(u'I edit the date to "([^"]*)"$') -def change_date(_step, new_date): - button_css = 'div.post-preview .edit-button' - world.css_click(button_css) - date_css = 'input.date' - date = world.css_find(date_css) - for i in range(len(date.value)): - date._element.send_keys(Keys.END, Keys.BACK_SPACE) - date._element.send_keys(new_date) - save_css = '.save-button' - world.css_click(save_css) - - -@step(u'I should see the date "([^"]*)"$') -def check_date(_step, date): - date_css = 'span.date-display' - assert_in(date, world.css_html(date_css)) - - @step(u'I modify the handout to "([^"]*)"$') def edit_handouts(_step, text): edit_css = 'div.course-handouts > .edit-button' diff --git a/cms/djangoapps/contentstore/features/grading.py b/cms/djangoapps/contentstore/features/grading.py index 7f9b315ce0..1ed6855389 100644 --- a/cms/djangoapps/contentstore/features/grading.py +++ b/cms/djangoapps/contentstore/features/grading.py @@ -19,7 +19,7 @@ def view_grading_settings(step): @step(u'I add "([^"]*)" new grade') def add_grade(step, many): grade_css = '.new-grade-button' - for i in range(int(many)): + for __ in range(int(many)): world.css_click(grade_css) @@ -120,7 +120,7 @@ def set_weight(step, weight): weight_id = '#course-grading-assignment-gradeweight' weight_field = world.css_find(weight_id)[-1] old_weight = world.css_value(weight_id, -1) - for count in range(len(old_weight)): + for __ in range(len(old_weight)): weight_field._element.send_keys(Keys.END, Keys.BACK_SPACE) weight_field._element.send_keys(weight) diff --git a/cms/djangoapps/contentstore/features/textbooks.py b/cms/djangoapps/contentstore/features/textbooks.py index cd756b2242..9b46dabc51 100644 --- a/cms/djangoapps/contentstore/features/textbooks.py +++ b/cms/djangoapps/contentstore/features/textbooks.py @@ -89,7 +89,7 @@ def check_textbook(_step, textbook_name, chapter_name): assert_equal(chapter, chapter_name) -@step(u'I should see a textbook named "([^"]*)" with (\d+) chapters') +@step(r'I should see a textbook named "([^"]*)" with (\d+) chapters') def check_textbook_chapters(_step, textbook_name, num_chapters_str): num_chapters = int(num_chapters_str) title = world.css_text(".textbook .view-textbook h3.textbook-title", index=0) diff --git a/cms/djangoapps/contentstore/features/transcripts.py b/cms/djangoapps/contentstore/features/transcripts.py index e9e25958aa..87f41b3a9f 100644 --- a/cms/djangoapps/contentstore/features/transcripts.py +++ b/cms/djangoapps/contentstore/features/transcripts.py @@ -134,7 +134,7 @@ def i_see_button(_step, not_see, button_type): assert world.css_has_text(TRANSCRIPTS_BUTTONS[button][0], TRANSCRIPTS_BUTTONS[button][1]) -@step('I (.*)see (.*)button "([^"]*)" number (\d+)$') +@step(r'I (.*)see (.*)button "([^"]*)" number (\d+)$') def i_see_button_with_custom_text(_step, not_see, button_type, custom_text, index): button = button_type.strip() custom_text = custom_text.strip() @@ -153,7 +153,7 @@ def click_button_transcripts_variant(_step, button_type): world.wait_for_ajax_complete() -@step('I click transcript button "([^"]*)" number (\d+)$') +@step(r'I click transcript button "([^"]*)" number (\d+)$') def click_button_index(_step, button_type, index): button = button_type.strip() index = int(index.strip()) - 1 @@ -178,7 +178,7 @@ def remove_transcripts_from_store(_step, subs_id): print 'Transcript file was NOT found and not removed.' -@step('I enter a "([^"]+)" source to field number (\d+)$') +@step(r'I enter a "([^"]+)" source to field number (\d+)$') def i_enter_a_source(_step, link, index): index = int(index) - 1 diff --git a/cms/djangoapps/contentstore/management/commands/tests/test_create_course.py b/cms/djangoapps/contentstore/management/commands/tests/test_create_course.py index 32fff608a4..02f37e8b16 100644 --- a/cms/djangoapps/contentstore/management/commands/tests/test_create_course.py +++ b/cms/djangoapps/contentstore/management/commands/tests/test_create_course.py @@ -61,3 +61,35 @@ class TestCreateCourse(ModuleStoreTestCase): ) # pylint: disable=protected-access self.assertEqual(store, modulestore()._get_modulestore_for_courselike(new_key).get_modulestore_type()) + + @ddt.data(ModuleStoreEnum.Type.split, ModuleStoreEnum.Type.mongo) + def test_get_course_with_different_case(self, default_store): + """ + Tests that course can not be accessed with different case. + + Scenario: + Create a course with lower case keys inside `bulk_operations` with `ignore_case=True`. + Verify that course is created. + Verify that get course from store using same course id but different case is not accessible. + """ + org = 'org1' + number = 'course1' + run = 'run1' + with self.store.default_store(default_store): + lowercase_course_id = self.store.make_course_key(org, number, run) + with self.store.bulk_operations(lowercase_course_id, ignore_case=True): + # Create course with lowercase key & Verify that store returns course. + self.store.create_course( + lowercase_course_id.org, + lowercase_course_id.course, + lowercase_course_id.run, + self.user.id + ) + course = self.store.get_course(lowercase_course_id) + self.assertIsNotNone(course, 'Course not found using lowercase course key.') + self.assertEqual(unicode(course.id), unicode(lowercase_course_id)) + + # Verify store does not return course with different case. + uppercase_course_id = self.store.make_course_key(org.upper(), number.upper(), run.upper()) + course = self.store.get_course(uppercase_course_id) + self.assertIsNone(course, 'Course should not be accessed with uppercase course id.') diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py index e30ef1ff57..921ca75507 100644 --- a/cms/djangoapps/contentstore/tests/test_contentstore.py +++ b/cms/djangoapps/contentstore/tests/test_contentstore.py @@ -2,7 +2,6 @@ import copy import mock -from mock import patch import shutil import lxml.html from lxml import etree @@ -475,12 +474,12 @@ class ImportRequiredTestCases(ContentStoreTestCase): renamed_chapter = [item for item in all_items if item.location.block_id == 'renamed_chapter'][0] self.assertIsNotNone(renamed_chapter.published_on) self.assertIsNotNone(renamed_chapter.parent) - self.assertTrue(renamed_chapter.location in course_after_rename[0].children) + self.assertIn(renamed_chapter.location, course_after_rename[0].children) original_chapter = [item for item in all_items if item.location.block_id == 'b9870b9af59841a49e6e02765d0e3bbf'][0] self.assertIsNone(original_chapter.published_on) self.assertIsNone(original_chapter.parent) - self.assertFalse(original_chapter.location in course_after_rename[0].children) + self.assertNotIn(original_chapter.location, course_after_rename[0].children) def test_empty_data_roundtrip(self): """ @@ -935,7 +934,7 @@ class MiscCourseTests(ContentStoreTestCase): def test_import_polls(self): items = self.store.get_items(self.course.id, qualifiers={'category': 'poll_question'}) - self.assertTrue(len(items) > 0) + self.assertGreater(len(items), 0) # check that there's actually content in the 'question' field self.assertGreater(len(items[0].question), 0) @@ -1152,6 +1151,9 @@ class ContentStoreTest(ContentStoreTestCase, XssTestMixin): """ Tests for the CMS ContentStore application. """ + duplicate_course_error = ("There is already a course defined with the same organization and course number. " + "Please change either organization or course number to be unique.") + def setUp(self): super(ContentStoreTest, self).setUp() @@ -1204,6 +1206,22 @@ class ContentStoreTest(ContentStoreTestCase, XssTestMixin): self.course_data['run'] = 'run.name' self.assert_created_course() + @ddt.data(ModuleStoreEnum.Type.split, ModuleStoreEnum.Type.mongo) + def test_course_with_different_cases(self, default_store): + """ + Tests that course can not be created with different case using an AJAX request to + course handler. + """ + course_number = '99x' + with self.store.default_store(default_store): + # Verify create a course passes with lower case. + self.course_data['number'] = course_number.lower() + self.assert_created_course() + + # Verify create a course fail when same course number is provided with different case. + self.course_data['number'] = course_number.upper() + self.assert_course_creation_failed(self.duplicate_course_error) + def test_create_course_check_forum_seeding(self): """Test new course creation and verify forum seeding """ test_course_data = self.assert_created_course(number_suffix=uuid4().hex) @@ -1265,7 +1283,7 @@ class ContentStoreTest(ContentStoreTestCase, XssTestMixin): auth.add_users(self.user, instructor_role, self.user) - self.assertTrue(len(instructor_role.users_with_role()) > 0) + self.assertGreater(len(instructor_role.users_with_role()), 0) # Now delete course and check that user not in instructor groups of this course delete_course_and_groups(course_id, self.user.id) @@ -1290,7 +1308,7 @@ class ContentStoreTest(ContentStoreTestCase, XssTestMixin): def test_create_course_duplicate_course(self): """Test new course creation - error path""" self.client.ajax_post('/course/', self.course_data) - self.assert_course_creation_failed('There is already a course defined with the same organization and course number. Please change either organization or course number to be unique.') + self.assert_course_creation_failed(self.duplicate_course_error) def assert_course_creation_failed(self, error_message): """ @@ -1319,21 +1337,38 @@ class ContentStoreTest(ContentStoreTestCase, XssTestMixin): self.course_data['display_name'] = 'Robot Super Course Two' self.course_data['run'] = '2013_Summer' - self.assert_course_creation_failed('There is already a course defined with the same organization and course number. Please change either organization or course number to be unique.') + self.assert_course_creation_failed(self.duplicate_course_error) - def test_create_course_case_change(self): + @ddt.data(ModuleStoreEnum.Type.split, ModuleStoreEnum.Type.mongo) + def test_create_course_case_change(self, default_store): """Test new course creation - error path due to case insensitive name equality""" - self.course_data['number'] = 'capital' - self.client.ajax_post('/course/', self.course_data) - cache_current = self.course_data['org'] - self.course_data['org'] = self.course_data['org'].lower() - self.assert_course_creation_failed('There is already a course defined with the same organization and course number. Please change either organization or course number to be unique.') - self.course_data['org'] = cache_current + self.course_data['number'] = '99x' - self.client.ajax_post('/course/', self.course_data) - cache_current = self.course_data['number'] - self.course_data['number'] = self.course_data['number'].upper() - self.assert_course_creation_failed('There is already a course defined with the same organization and course number. Please change either organization or course number to be unique.') + with self.store.default_store(default_store): + + # Verify that the course was created properly. + self.assert_created_course() + + # Keep the copy of original org + cache_current = self.course_data['org'] + + # Change `org` to lower case and verify that course did not get created + self.course_data['org'] = self.course_data['org'].lower() + self.assert_course_creation_failed(self.duplicate_course_error) + + # Replace the org with its actual value, and keep the copy of course number. + self.course_data['org'] = cache_current + cache_current = self.course_data['number'] + + self.course_data['number'] = self.course_data['number'].upper() + self.assert_course_creation_failed(self.duplicate_course_error) + + # Replace the org with its actual value, and keep the copy of course number. + self.course_data['number'] = cache_current + __ = self.course_data['run'] + + self.course_data['run'] = self.course_data['run'].upper() + self.assert_course_creation_failed(self.duplicate_course_error) def test_course_substring(self): """ diff --git a/cms/djangoapps/contentstore/tests/test_course_settings.py b/cms/djangoapps/contentstore/tests/test_course_settings.py index f18e1c98b3..1efcb8a393 100644 --- a/cms/djangoapps/contentstore/tests/test_course_settings.py +++ b/cms/djangoapps/contentstore/tests/test_course_settings.py @@ -167,13 +167,13 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin): elif field in encoded and encoded[field] is not None: self.fail(field + " included in encoding but missing from details at " + context) - @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True, 'MILESTONES_APP': True}) + @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True}) def test_pre_requisite_course_list_present(self): settings_details_url = get_url(self.course.id) response = self.client.get_html(settings_details_url) self.assertContains(response, "Prerequisite Course") - @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True, 'MILESTONES_APP': True}) + @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True}) def test_pre_requisite_course_update_and_fetch(self): url = get_url(self.course.id) resp = self.client.get_json(url) @@ -200,7 +200,7 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin): course_detail_json = json.loads(resp.content) self.assertEqual([], course_detail_json['pre_requisite_courses']) - @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True, 'MILESTONES_APP': True}) + @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True}) def test_invalid_pre_requisite_course(self): url = get_url(self.course.id) resp = self.client.get_json(url) @@ -219,6 +219,7 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin): (False, True, False), (True, True, True), ) + @override_settings(MKTG_URLS={'ROOT': 'dummy-root'}) def test_visibility_of_entrance_exam_section(self, feature_flags): """ Tests entrance exam section is available if ENTRANCE_EXAMS feature is enabled no matter any other @@ -805,7 +806,7 @@ class CourseMetadataEditingTest(CourseTestCase): user=self.user ) self.assertTrue(is_valid) - self.assertTrue(len(errors) == 0) + self.assertEqual(len(errors), 0) self.update_check(test_model) # Tab gets tested in test_advanced_settings_munge_tabs @@ -1161,6 +1162,7 @@ id=\"course-enrollment-end-time\" value=\"\" placeholder=\"HH:MM\" autocomplete= self._verify_editable(self._get_course_details_response(False)) @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_MKTG_SITE': True}) + @override_settings(MKTG_URLS={'ROOT': 'dummy-root'}) def test_course_details_with_enabled_setting_global_staff(self): """ Test that user enrollment end date is editable in response. @@ -1170,6 +1172,7 @@ id=\"course-enrollment-end-time\" value=\"\" placeholder=\"HH:MM\" autocomplete= self._verify_editable(self._get_course_details_response(True)) @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_MKTG_SITE': True}) + @override_settings(MKTG_URLS={'ROOT': 'dummy-root'}) def test_course_details_with_enabled_setting_non_global_staff(self): """ Test that user enrollment end date is not editable in response. diff --git a/cms/djangoapps/contentstore/tests/test_i18n.py b/cms/djangoapps/contentstore/tests/test_i18n.py index 612b39c76f..82e568cb40 100644 --- a/cms/djangoapps/contentstore/tests/test_i18n.py +++ b/cms/djangoapps/contentstore/tests/test_i18n.py @@ -10,7 +10,6 @@ from contentstore.tests.utils import AjaxEnabledTestClient from xmodule.modulestore.django import ModuleI18nService from django.utils import translation from django.utils.translation import get_language -from django.conf import settings from xmodule.modulestore.tests.factories import ItemFactory, CourseFactory from contentstore.views.preview import _preview_module_system diff --git a/cms/djangoapps/contentstore/tests/test_libraries.py b/cms/djangoapps/contentstore/tests/test_libraries.py index 0e45222f10..6f95cd26da 100644 --- a/cms/djangoapps/contentstore/tests/test_libraries.py +++ b/cms/djangoapps/contentstore/tests/test_libraries.py @@ -14,7 +14,6 @@ from student.roles import ( CourseInstructorRole, CourseStaffRole, CourseCreatorRole, LibraryUserRole, OrgStaffRole, OrgInstructorRole, OrgLibraryUserRole, ) -from xblock.reference.user_service import XBlockUser from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase @@ -65,7 +64,7 @@ class LibraryTestCase(ModuleStoreTestCase): self.assertIsInstance(lib_key, LibraryLocator) return lib_key - def _add_library_content_block(self, course, library_key, other_settings=None): + def _add_library_content_block(self, course, library_key, publish_item=False, other_settings=None): """ Helper method to add a LibraryContent block to a course. The block will be configured to select content from the library @@ -76,7 +75,7 @@ class LibraryTestCase(ModuleStoreTestCase): category='library_content', parent_location=course.location, user_id=self.user.id, - publish_item=False, + publish_item=publish_item, source_library_id=unicode(library_key), **(other_settings or {}) ) @@ -160,7 +159,7 @@ class TestLibraries(LibraryTestCase): with modulestore().default_store(ModuleStoreEnum.Type.split): course = CourseFactory.create() - lc_block = self._add_library_content_block(course, self.lib_key, {'max_count': num_to_select}) + lc_block = self._add_library_content_block(course, self.lib_key, other_settings={'max_count': num_to_select}) self.assertEqual(len(lc_block.children), 0) lc_block = self._refresh_children(lc_block) @@ -490,7 +489,7 @@ class TestLibraryAccess(SignalDisconnectTestMixin, LibraryTestCase): def _assert_cannot_create_library(self, org="org", library="libfail", expected_code=403): """ Ensure the current user is not able to create a library. """ - self.assertTrue(expected_code >= 300) + self.assertGreaterEqual(expected_code, 300) response = self.client.ajax_post( LIBRARY_REST_URL, {'org': org, 'library': library, 'display_name': "Irrelevant"} diff --git a/cms/djangoapps/contentstore/tests/test_utils.py b/cms/djangoapps/contentstore/tests/test_utils.py index c4b9e667e4..7d451f9834 100644 --- a/cms/djangoapps/contentstore/tests/test_utils.py +++ b/cms/djangoapps/contentstore/tests/test_utils.py @@ -2,10 +2,8 @@ import collections from datetime import datetime, timedelta -import mock from pytz import UTC from django.test import TestCase -from django.test.utils import override_settings from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase @@ -20,53 +18,6 @@ from contentstore.tests.utils import CourseTestCase class LMSLinksTestCase(TestCase): """ Tests for LMS links. """ - def about_page_test(self): - """ Get URL for about page, no marketing site """ - # default for ENABLE_MKTG_SITE is False. - self.assertEquals(self.get_about_page_link(), "//localhost:8000/courses/mitX/101/test/about") - - @override_settings(MKTG_URLS={'ROOT': 'dummy-root'}) - def about_page_marketing_site_test(self): - """ Get URL for about page, marketing root present. """ - with mock.patch.dict('django.conf.settings.FEATURES', {'ENABLE_MKTG_SITE': True}): - self.assertEquals(self.get_about_page_link(), "//dummy-root/courses/mitX/101/test/about") - with mock.patch.dict('django.conf.settings.FEATURES', {'ENABLE_MKTG_SITE': False}): - self.assertEquals(self.get_about_page_link(), "//localhost:8000/courses/mitX/101/test/about") - - @override_settings(MKTG_URLS={'ROOT': 'http://www.dummy'}) - def about_page_marketing_site_remove_http_test(self): - """ Get URL for about page, marketing root present, remove http://. """ - with mock.patch.dict('django.conf.settings.FEATURES', {'ENABLE_MKTG_SITE': True}): - self.assertEquals(self.get_about_page_link(), "//www.dummy/courses/mitX/101/test/about") - - @override_settings(MKTG_URLS={'ROOT': 'https://www.dummy'}) - def about_page_marketing_site_remove_https_test(self): - """ Get URL for about page, marketing root present, remove https://. """ - with mock.patch.dict('django.conf.settings.FEATURES', {'ENABLE_MKTG_SITE': True}): - self.assertEquals(self.get_about_page_link(), "//www.dummy/courses/mitX/101/test/about") - - @override_settings(MKTG_URLS={'ROOT': 'www.dummyhttps://x'}) - def about_page_marketing_site_https__edge_test(self): - """ Get URL for about page, only remove https:// at the beginning of the string. """ - with mock.patch.dict('django.conf.settings.FEATURES', {'ENABLE_MKTG_SITE': True}): - self.assertEquals(self.get_about_page_link(), "//www.dummyhttps://x/courses/mitX/101/test/about") - - @override_settings(MKTG_URLS={}) - def about_page_marketing_urls_not_set_test(self): - """ Error case. ENABLE_MKTG_SITE is True, but there is either no MKTG_URLS, or no MKTG_URLS Root property. """ - with mock.patch.dict('django.conf.settings.FEATURES', {'ENABLE_MKTG_SITE': True}): - self.assertEquals(self.get_about_page_link(), None) - - @override_settings(LMS_BASE=None) - def about_page_no_lms_base_test(self): - """ No LMS_BASE, nor is ENABLE_MKTG_SITE True """ - self.assertEquals(self.get_about_page_link(), None) - - def get_about_page_link(self): - """ create mock course and return the about page link """ - course_key = SlashSeparatedCourseKey('mitX', '101', 'test') - return utils.get_lms_link_for_about_page(course_key) - def lms_link_test(self): """ Tests get_lms_link_for_item. """ course_key = SlashSeparatedCourseKey('mitX', '101', 'test') diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py index 03a2b6aae2..605c2b8353 100644 --- a/cms/djangoapps/contentstore/utils.py +++ b/cms/djangoapps/contentstore/utils.py @@ -3,7 +3,6 @@ Common utility functions useful throughout the contentstore """ import logging -import re from datetime import datetime from pytz import UTC @@ -104,42 +103,6 @@ def get_lms_link_for_item(location, preview=False): ) -def get_lms_link_for_about_page(course_key): - """ - Returns the url to the course about page from the location tuple. - """ - - assert isinstance(course_key, CourseKey) - - if settings.FEATURES.get('ENABLE_MKTG_SITE', False): - if not hasattr(settings, 'MKTG_URLS'): - log.exception("ENABLE_MKTG_SITE is True, but MKTG_URLS is not defined.") - return None - - marketing_urls = settings.MKTG_URLS - - # Root will be "https://www.edx.org". The complete URL will still not be exactly correct, - # but redirects exist from www.edx.org to get to the Drupal course about page URL. - about_base = marketing_urls.get('ROOT', None) - - if about_base is None: - log.exception('There is no ROOT defined in MKTG_URLS') - return None - - # Strip off https:// (or http://) to be consistent with the formatting of LMS_BASE. - about_base = re.sub(r"^https?://", "", about_base) - - elif settings.LMS_BASE is not None: - about_base = settings.LMS_BASE - else: - return None - - return u"//{about_base_url}/courses/{course_key}/about".format( - about_base_url=about_base, - course_key=course_key.to_deprecated_string() - ) - - # pylint: disable=invalid-name def get_lms_link_for_certificate_web_view(user_id, course_key, mode): """ diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index fc0cca23f0..7d71f180d3 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -28,7 +28,6 @@ from .component import ( from .item import create_xblock_info from .library import LIBRARIES_ENABLED from ccx_keys.locator import CCXLocator -from contentstore import utils from contentstore.course_group_config import ( COHORT_SCHEME, GroupConfiguration, @@ -58,7 +57,6 @@ from course_action_state.managers import CourseActionStateItemNotFoundError from course_action_state.models import CourseRerunState, CourseRerunUIStateManager from course_creators.views import get_course_creator_status, add_user_with_status_unrequested from edxmako.shortcuts import render_to_response -from microsite_configuration import microsite from models.settings.course_grading import CourseGradingModel from models.settings.course_metadata import CourseMetadata from models.settings.encoder import CourseSettingsEncoder @@ -69,6 +67,7 @@ from openedx.core.djangoapps.models.course_details import CourseDetails from openedx.core.djangoapps.programs.models import ProgramsApiConfig from openedx.core.djangoapps.programs.utils import get_programs from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration +from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.lib.course_tabs import CourseTabPluginManager from openedx.core.lib.courses import course_image_url from openedx.core.djangolib.js_utils import dump_js_escaped_json @@ -77,6 +76,7 @@ from student.auth import has_course_author_access, has_studio_write_access, has_ from student.roles import ( CourseInstructorRole, CourseStaffRole, CourseCreatorRole, GlobalStaff, UserBasedRole ) +from util.course import get_lms_link_for_about_page from util.date_utils import get_default_time_display from util.json_request import JsonResponse, JsonResponseBadRequest, expect_json from util.milestones_helpers import ( @@ -975,14 +975,14 @@ def settings_handler(request, course_key_string): if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET': upload_asset_url = reverse_course_url('assets_handler', course_key) - # see if the ORG of this course can be attributed to a 'Microsite'. In that case, the + # see if the ORG of this course can be attributed to a defined configuration . In that case, the # course about page should be editable in Studio - marketing_site_enabled = microsite.get_value_for_org( + marketing_site_enabled = configuration_helpers.get_value_for_org( course_module.location.org, 'ENABLE_MKTG_SITE', settings.FEATURES.get('ENABLE_MKTG_SITE', False) ) - enable_extended_course_details = microsite.get_value_for_org( + enable_extended_course_details = configuration_helpers.get_value_for_org( course_module.location.org, 'ENABLE_EXTENDED_COURSE_DETAILS', settings.FEATURES.get('ENABLE_EXTENDED_COURSE_DETAILS', False) @@ -996,7 +996,7 @@ def settings_handler(request, course_key_string): settings_context = { 'context_course': course_module, 'course_locator': course_key, - 'lms_link_for_about_page': utils.get_lms_link_for_about_page(course_key), + 'lms_link_for_about_page': get_lms_link_for_about_page(course_key), 'course_image_url': course_image_url(course_module, 'course_image'), 'banner_image_url': course_image_url(course_module, 'banner_image'), 'video_thumbnail_image_url': course_image_url(course_module, 'video_thumbnail_image'), diff --git a/cms/djangoapps/contentstore/views/dev.py b/cms/djangoapps/contentstore/views/dev.py index 7cf69eeb7f..2b2178eaba 100644 --- a/cms/djangoapps/contentstore/views/dev.py +++ b/cms/djangoapps/contentstore/views/dev.py @@ -5,8 +5,6 @@ in a 404 error. """ # pylint: disable=unused-argument from edxmako.shortcuts import render_to_response -from mako.exceptions import TopLevelLookupException -from django.http import HttpResponseNotFound def dev_mode(request): diff --git a/cms/djangoapps/contentstore/views/entrance_exam.py b/cms/djangoapps/contentstore/views/entrance_exam.py index 5bedb11100..9dba4ae261 100644 --- a/cms/djangoapps/contentstore/views/entrance_exam.py +++ b/cms/djangoapps/contentstore/views/entrance_exam.py @@ -131,13 +131,6 @@ def _create_entrance_exam(request, course_key, entrance_exam_minimum_score_pct=N return HttpResponse(status=400) # Create the entrance exam item (currently it's just a chapter) - payload = { - 'category': "chapter", - 'display_name': _("Entrance Exam"), - 'parent_locator': unicode(course.location), - 'is_entrance_exam': True, - 'in_entrance_exam': True, - } parent_locator = unicode(course.location) created_block = create_xblock( parent_locator=parent_locator, diff --git a/cms/djangoapps/contentstore/views/helpers.py b/cms/djangoapps/contentstore/views/helpers.py index 5a0a45ca21..29e571c5b6 100644 --- a/cms/djangoapps/contentstore/views/helpers.py +++ b/cms/djangoapps/contentstore/views/helpers.py @@ -9,10 +9,9 @@ import urllib from django.conf import settings from django.http import HttpResponse -from django.shortcuts import redirect from django.utils.translation import ugettext as _ -from edxmako.shortcuts import render_to_string, render_to_response +from edxmako.shortcuts import render_to_string from opaque_keys.edx.keys import UsageKey from xblock.core import XBlock import dogstats_wrapper as dog_stats_api diff --git a/cms/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py index 2a2aef5a74..c3a185f86d 100644 --- a/cms/djangoapps/contentstore/views/preview.py +++ b/cms/djangoapps/contentstore/views/preview.py @@ -27,7 +27,6 @@ from xblock.runtime import KvsFieldData from xblock.django.request import webob_to_django_response, django_to_webob_request from xblock.exceptions import NoSuchHandlerError from xblock.fragment import Fragment -from student.auth import has_studio_read_access, has_studio_write_access from xblock_django.user_service import DjangoXBlockUserService from lms.djangoapps.lms_xblock.field_data import LmsFieldData diff --git a/cms/djangoapps/contentstore/views/program.py b/cms/djangoapps/contentstore/views/program.py index d95f10b9c5..0ac51d5df0 100644 --- a/cms/djangoapps/contentstore/views/program.py +++ b/cms/djangoapps/contentstore/views/program.py @@ -16,9 +16,8 @@ from openedx.core.lib.token_utils import JwtBuilder class ProgramAuthoringView(View): """View rendering a template which hosts the Programs authoring app. - The Programs authoring app is a Backbone SPA maintained in a separate repository. - The app handles its own routing and provides a UI which can be used to create and - publish new Programs (e.g, XSeries). + The Programs authoring app is a Backbone SPA. The app handles its own routing + and provides a UI which can be used to create and publish new Programs. """ @method_decorator(login_required) diff --git a/cms/djangoapps/contentstore/views/public.py b/cms/djangoapps/contentstore/views/public.py index 98fcc9af0d..1a2ca08511 100644 --- a/cms/djangoapps/contentstore/views/public.py +++ b/cms/djangoapps/contentstore/views/public.py @@ -12,7 +12,7 @@ from edxmako.shortcuts import render_to_response from external_auth.views import (ssl_login_shortcut, ssl_get_cert_from_request, redirect_with_get) -from microsite_configuration import microsite +from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers __all__ = ['signup', 'login_page', 'howitworks'] @@ -61,7 +61,7 @@ def login_page(request): { 'csrf': csrf_token, 'forgot_password_link': "//{base}/login#forgot-password-modal".format(base=settings.LMS_BASE), - 'platform_name': microsite.get_value('platform_name', settings.PLATFORM_NAME), + 'platform_name': configuration_helpers.get_value('platform_name', settings.PLATFORM_NAME), } ) diff --git a/cms/djangoapps/contentstore/views/tests/test_assets.py b/cms/djangoapps/contentstore/views/tests/test_assets.py index 797b76be59..7848f63335 100644 --- a/cms/djangoapps/contentstore/views/tests/test_assets.py +++ b/cms/djangoapps/contentstore/views/tests/test_assets.py @@ -132,7 +132,7 @@ class BasicAssetsTestCase(AssetsTestCase): url = asset_url.replace('"', '') base_url = url.replace(filename, '') - self.assertTrue("/{}".format(filename) in url) + self.assertIn("/{}".format(filename), url) resp = self.client.get(url) self.assertEquals(resp.status_code, 200) @@ -142,7 +142,7 @@ class BasicAssetsTestCase(AssetsTestCase): # browser append relative_path with base_url absolute_path = base_url + relative_path - self.assertTrue("/{}".format(relative_path) in absolute_path) + self.assertIn("/{}".format(relative_path), absolute_path) resp = self.client.get(absolute_path) self.assertEquals(resp.status_code, 200) diff --git a/cms/djangoapps/contentstore/views/tests/test_certificates.py b/cms/djangoapps/contentstore/views/tests/test_certificates.py index e2a1f096c4..49e62c25ee 100644 --- a/cms/djangoapps/contentstore/views/tests/test_certificates.py +++ b/cms/djangoapps/contentstore/views/tests/test_certificates.py @@ -80,7 +80,7 @@ class HelperMethods(object): 'title': 'Title ' + str(i), 'signature_image_path': '/c4x/test/CSS101/asset/Signature{}.png'.format(i), 'id': i - } for i in xrange(0, signatory_count) + } for i in xrange(signatory_count) ] @@ -99,7 +99,7 @@ class HelperMethods(object): 'signatories': signatories, 'version': CERTIFICATE_SCHEMA_VERSION, 'is_active': is_active - } for i in xrange(0, count) + } for i in xrange(count) ] self.course.certificates = {'certificates': certificates} self.save_course() @@ -181,7 +181,7 @@ class CertificatesBaseTestCase(object): with self.assertRaises(Exception) as context: CertificateManager.validate(json_data_1) - self.assertTrue("Unsupported certificate schema version: 100. Expected version: 1." in context.exception) + self.assertIn("Unsupported certificate schema version: 100. Expected version: 1.", context.exception) #Test certificate name is missing json_data_2 = { @@ -192,13 +192,14 @@ class CertificatesBaseTestCase(object): with self.assertRaises(Exception) as context: CertificateManager.validate(json_data_2) - self.assertTrue('must have name of the certificate' in context.exception) + self.assertIn('must have name of the certificate', context.exception) @ddt.ddt @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED) class CertificatesListHandlerTestCase( - EventTestMixin, CourseTestCase, CertificatesBaseTestCase, HelperMethods, UrlResetMixin): + EventTestMixin, CourseTestCase, CertificatesBaseTestCase, HelperMethods, UrlResetMixin +): """ Test cases for certificates_list_handler. """ @@ -423,7 +424,8 @@ class CertificatesListHandlerTestCase( @ddt.ddt @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED) class CertificatesDetailHandlerTestCase( - EventTestMixin, CourseTestCase, CertificatesBaseTestCase, HelperMethods, UrlResetMixin): + EventTestMixin, CourseTestCase, CertificatesBaseTestCase, HelperMethods, UrlResetMixin +): """ Test cases for CertificatesDetailHandlerTestCase. """ diff --git a/cms/djangoapps/contentstore/views/tests/test_course_index.py b/cms/djangoapps/contentstore/views/tests/test_course_index.py index 121c998a69..70b3e6387f 100644 --- a/cms/djangoapps/contentstore/views/tests/test_course_index.py +++ b/cms/djangoapps/contentstore/views/tests/test_course_index.py @@ -10,7 +10,6 @@ import pytz from django.conf import settings from django.core.exceptions import PermissionDenied -from django.test.utils import override_settings from django.utils.translation import ugettext as _ from contentstore.courseware_index import CoursewareSearchIndexer, SearchIndexingError @@ -150,14 +149,14 @@ class TestCourseIndex(CourseTestCase): # Now verify the first child children = json_response['child_info']['children'] - self.assertTrue(len(children) > 0) + self.assertGreater(len(children), 0) first_child_response = children[0] self.assertEqual(first_child_response['category'], 'chapter') self.assertEqual(first_child_response['id'], unicode(chapter.location)) self.assertEqual(first_child_response['display_name'], 'Week 1') self.assertTrue(json_response['published']) self.assertEqual(first_child_response['visibility_state'], VisibilityState.unscheduled) - self.assertTrue(len(first_child_response['child_info']['children']) > 0) + self.assertGreater(len(first_child_response['child_info']['children']), 0) # Finally, validate the entire response for consistency self.assert_correct_json_response(json_response) @@ -352,14 +351,14 @@ class TestCourseOutline(CourseTestCase): # Now verify the first child children = json_response['child_info']['children'] - self.assertTrue(len(children) > 0) + self.assertGreater(len(children), 0) first_child_response = children[0] self.assertEqual(first_child_response['category'], 'chapter') self.assertEqual(first_child_response['id'], unicode(self.chapter.location)) self.assertEqual(first_child_response['display_name'], 'Week 1') self.assertTrue(json_response['published']) self.assertEqual(first_child_response['visibility_state'], VisibilityState.unscheduled) - self.assertTrue(len(first_child_response['child_info']['children']) > 0) + self.assertGreater(len(first_child_response['child_info']['children']), 0) # Finally, validate the entire response for consistency self.assert_correct_json_response(json_response) diff --git a/cms/djangoapps/contentstore/views/tests/test_course_updates.py b/cms/djangoapps/contentstore/views/tests/test_course_updates.py index f9199c005a..1687941a22 100644 --- a/cms/djangoapps/contentstore/views/tests/test_course_updates.py +++ b/cms/djangoapps/contentstore/views/tests/test_course_updates.py @@ -71,7 +71,7 @@ class CourseUpdateTest(CourseTestCase): course_update_url = self.create_update_url() resp = self.client.get_json(course_update_url) payload = json.loads(resp.content) - self.assertTrue(len(payload) == 2) + self.assertEqual(len(payload), 2) # try json w/o required fields self.assertContains( @@ -123,7 +123,7 @@ class CourseUpdateTest(CourseTestCase): url = self.create_update_url(provided_id=this_id) resp = self.client.delete(url) payload = json.loads(resp.content) - self.assertTrue(len(payload) == before_delete - 1) + self.assertEqual(len(payload), before_delete - 1) def test_course_updates_compatibility(self): ''' @@ -149,7 +149,7 @@ class CourseUpdateTest(CourseTestCase): resp = self.client.get_json(course_update_url) payload = json.loads(resp.content) self.assertEqual(payload, [{u'date': update_date, u'content': update_content, u'id': 1}]) - self.assertTrue(len(payload) == 1) + self.assertEqual(len(payload), 1) # test getting single update item @@ -234,7 +234,7 @@ class CourseUpdateTest(CourseTestCase): # now confirm that the bad news and the iframe make up single update resp = self.client.get_json(course_update_url) payload = json.loads(resp.content) - self.assertTrue(len(payload) == 1) + self.assertEqual(len(payload), 1) def post_course_update(self, send_push_notification=False): """ diff --git a/cms/djangoapps/contentstore/views/tests/test_import_export.py b/cms/djangoapps/contentstore/views/tests/test_import_export.py index 34d0225bb1..9fcba609e1 100644 --- a/cms/djangoapps/contentstore/views/tests/test_import_export.py +++ b/cms/djangoapps/contentstore/views/tests/test_import_export.py @@ -15,15 +15,17 @@ from uuid import uuid4 from django.test.utils import override_settings from django.conf import settings + +from contentstore.tests.test_libraries import LibraryTestCase from xmodule.contentstore.django import contentstore from xmodule.modulestore.django import modulestore -from xmodule.modulestore.xml_exporter import export_library_to_xml -from xmodule.modulestore.xml_importer import import_library_from_xml +from xmodule.modulestore.xml_exporter import export_library_to_xml, export_course_to_xml +from xmodule.modulestore.xml_importer import import_library_from_xml, import_course_from_xml from xmodule.modulestore import LIBRARY_ROOT, ModuleStoreEnum from contentstore.utils import reverse_course_url from contentstore.tests.utils import CourseTestCase -from xmodule.modulestore.tests.factories import ItemFactory, LibraryFactory +from xmodule.modulestore.tests.factories import ItemFactory, LibraryFactory, CourseFactory from xmodule.modulestore.tests.utils import ( MongoContentstoreBuilder, SPLIT_MODULESTORE_SETUP, TEST_DATA_DIR ) @@ -335,7 +337,7 @@ class ImportTestCase(CourseTestCase): args = {"name": tarpath, "course-data": [tar]} resp = self.client.post(self.url, args) self.assertEquals(resp.status_code, 400) - self.assertTrue("SuspiciousFileOperation" in resp.content) + self.assertIn("SuspiciousFileOperation", resp.content) try_tar(self._fifo_tar()) try_tar(self._symlink_tar()) @@ -697,3 +699,111 @@ class TestLibraryImportExport(CourseTestCase): # Compare the two content libraries for equality. self.assertCoursesEqual(source_library1_key, source_library2_key) + + +@ddt.ddt +@override_settings(CONTENTSTORE=TEST_DATA_CONTENTSTORE) +class TestCourseExportImport(LibraryTestCase): + """ + Tests for importing after exporting the course containing content libraries from XML. + """ + def setUp(self): + super(TestCourseExportImport, self).setUp() + self.export_dir = tempfile.mkdtemp() + + # Create a problem in library + ItemFactory.create( + category="problem", + parent_location=self.library.location, + user_id=self.user.id, # pylint: disable=no-member + publish_item=False, + display_name='Test Problem', + data="", + ) + + # Create a source course. + self.source_course = CourseFactory.create(default_store=ModuleStoreEnum.Type.split) + self.addCleanup(shutil.rmtree, self.export_dir, ignore_errors=True) + + def _setup_source_course_with_library_content(self, publish=False): + """ + Sets up course with library content. + """ + chapter = ItemFactory.create( + parent_location=self.source_course.location, + category='chapter', + display_name='Test Section' + ) + sequential = ItemFactory.create( + parent_location=chapter.location, + category='sequential', + display_name='Test Sequential' + ) + vertical = ItemFactory.create( + category='vertical', + parent_location=sequential.location, + display_name='Test Unit' + ) + lc_block = self._add_library_content_block(vertical, self.lib_key, publish_item=publish) + self._refresh_children(lc_block) + + def get_lib_content_block_children(self, block_location): + """ + Search for library content block to return its immediate children + """ + if block_location.block_type == 'library_content': + return self.store.get_item(block_location).children + + return self.get_lib_content_block_children(self.store.get_item(block_location).children[0]) + + def assert_problem_display_names(self, source_course_location, dest_course_location): + """ + Asserts that problems' display names in both source and destination courses are same. + """ + source_course_lib_children = self.get_lib_content_block_children(source_course_location) + dest_course_lib_children = self.get_lib_content_block_children(dest_course_location) + + self.assertEquals(len(source_course_lib_children), len(dest_course_lib_children)) + + for source_child_location, dest_child_location in zip(source_course_lib_children, dest_course_lib_children): + source_child = self.store.get_item(source_child_location) + dest_child = self.store.get_item(dest_child_location) + self.assertEquals(source_child.display_name, dest_child.display_name) + + @ddt.data(True, False) + def test_library_content_on_course_export_import(self, publish_item): + """ + Verify that library contents in destination and source courses are same after importing + the source course into destination course. + """ + self._setup_source_course_with_library_content(publish=publish_item) + + # Create a course to import source course. + dest_course = CourseFactory.create(default_store=ModuleStoreEnum.Type.split) + + # Export the source course. + export_course_to_xml( + self.store, + contentstore(), + self.source_course.location.course_key, + self.export_dir, + 'exported_source_course', + ) + + # Now, import it back to dest_course. + import_course_from_xml( + self.store, + self.user.id, # pylint: disable=no-member + self.export_dir, + ['exported_source_course'], + static_content_store=contentstore(), + target_id=dest_course.location.course_key, + load_error_modules=False, + raise_on_failure=True, + create_if_not_present=True, + ) + + self.assert_problem_display_names( + self.source_course.location, + dest_course.location + ) diff --git a/cms/djangoapps/contentstore/views/tests/test_item.py b/cms/djangoapps/contentstore/views/tests/test_item.py index 41c8650491..4fc88e5c45 100644 --- a/cms/djangoapps/contentstore/views/tests/test_item.py +++ b/cms/djangoapps/contentstore/views/tests/test_item.py @@ -607,7 +607,7 @@ class TestDuplicateItem(ItemTest, DuplicateHelper): parent = self.get_item_from_modulestore(parent_usage_key) children = parent.children if source_position is None: - self.assertFalse(source_usage_key in children, 'source item not expected in children array') + self.assertNotIn(source_usage_key, children, 'source item not expected in children array') self.assertEqual( children[len(children) - 1], usage_key, @@ -2102,7 +2102,7 @@ class TestXBlockPublishingInfo(ItemTest): Returns the child xblock info at the specified index. """ children = xblock_info['child_info']['children'] - self.assertTrue(len(children) > index) + self.assertGreater(len(children), index) return children[index] def _get_xblock_info(self, location): diff --git a/cms/djangoapps/contentstore/views/tests/test_tabs.py b/cms/djangoapps/contentstore/views/tests/test_tabs.py index fde68931a3..f440d44f91 100644 --- a/cms/djangoapps/contentstore/views/tests/test_tabs.py +++ b/cms/djangoapps/contentstore/views/tests/test_tabs.py @@ -80,7 +80,7 @@ class TabsPageTests(CourseTestCase): num_orig_tabs = len(orig_tab_ids) # make sure we have enough tabs to play around with - self.assertTrue(num_orig_tabs >= 5) + self.assertGreaterEqual(num_orig_tabs, 5) # reorder the last two tabs tab_ids[num_orig_tabs - 1], tab_ids[num_orig_tabs - 2] = tab_ids[num_orig_tabs - 2], tab_ids[num_orig_tabs - 1] @@ -88,7 +88,7 @@ class TabsPageTests(CourseTestCase): # remove the middle tab # (the code needs to handle the case where tabs requested for re-ordering is a subset of the tabs in the course) removed_tab = tab_ids.pop(num_orig_tabs / 2) - self.assertTrue(len(tab_ids) == num_orig_tabs - 1) + self.assertEqual(len(tab_ids), num_orig_tabs - 1) # post the request resp = self.client.ajax_post( @@ -205,7 +205,7 @@ class PrimitiveTabEdit(ModuleStoreTestCase): with self.assertRaises(IndexError): tabs.primitive_delete(course, 6) tabs.primitive_delete(course, 2) - self.assertFalse({u'type': u'textbooks'} in course.tabs) + self.assertNotIn({u'type': u'textbooks'}, course.tabs) # Check that discussion has shifted up self.assertEquals(course.tabs[2], {'type': 'discussion', 'name': 'Discussion'}) diff --git a/cms/djangoapps/course_creators/tests/test_views.py b/cms/djangoapps/course_creators/tests/test_views.py index fca8e7faaa..9ece71c8a2 100644 --- a/cms/djangoapps/course_creators/tests/test_views.py +++ b/cms/djangoapps/course_creators/tests/test_views.py @@ -4,7 +4,7 @@ Tests course_creators.views.py. from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied -from django.test import TestCase, RequestFactory +from django.test import TestCase from django.core.urlresolvers import reverse from course_creators.views import add_user_with_status_unrequested, add_user_with_status_granted diff --git a/cms/djangoapps/models/settings/course_metadata.py b/cms/djangoapps/models/settings/course_metadata.py index 157bb3c7d1..5d6f42c097 100644 --- a/cms/djangoapps/models/settings/course_metadata.py +++ b/cms/djangoapps/models/settings/course_metadata.py @@ -100,6 +100,9 @@ class CourseMetadata(object): if not XBlockStudioConfigurationFlag.is_enabled(): filtered_list.append('allow_unsupported_xblocks') + if not settings.FEATURES.get('ENABLE_SUBSECTION_GRADES_SAVED'): + filtered_list.append('enable_subsection_grades_saved') + return filtered_list @classmethod diff --git a/cms/envs/aws.py b/cms/envs/aws.py index 8c0f75a8dd..b2b536926c 100644 --- a/cms/envs/aws.py +++ b/cms/envs/aws.py @@ -138,6 +138,7 @@ EMAIL_PORT = ENV_TOKENS.get('EMAIL_PORT', EMAIL_PORT) EMAIL_USE_TLS = ENV_TOKENS.get('EMAIL_USE_TLS', EMAIL_USE_TLS) LMS_BASE = ENV_TOKENS.get('LMS_BASE') +LMS_ROOT_URL = ENV_TOKENS.get('LMS_ROOT_URL') # Note that FEATURES['PREVIEW_LMS_BASE'] gets read in from the environment file. SITE_NAME = ENV_TOKENS['SITE_NAME'] @@ -209,9 +210,6 @@ COURSES_WITH_UNSAFE_CODE = ENV_TOKENS.get("COURSES_WITH_UNSAFE_CODE", []) ASSET_IGNORE_REGEX = ENV_TOKENS.get('ASSET_IGNORE_REGEX', ASSET_IGNORE_REGEX) -# Theme overrides -THEME_NAME = ENV_TOKENS.get('THEME_NAME', None) - # following setting is for backward compatibility if ENV_TOKENS.get('COMPREHENSIVE_THEME_DIR', None): COMPREHENSIVE_THEME_DIR = ENV_TOKENS.get('COMPREHENSIVE_THEME_DIR') diff --git a/cms/envs/bok_choy.env.json b/cms/envs/bok_choy.env.json index 8abd2fad4c..5697c729e0 100644 --- a/cms/envs/bok_choy.env.json +++ b/cms/envs/bok_choy.env.json @@ -88,6 +88,7 @@ "STORAGE_TYPE": "localfs" }, "LMS_BASE": "localhost:8003", + "LMS_ROOT_URL": "http://localhost:8003", "LOCAL_LOGLEVEL": "INFO", "LOGGING_ENV": "sandbox", "LOG_DIR": "** OVERRIDDEN **", @@ -101,7 +102,6 @@ "STATIC_URL_BASE": "/static/", "SYSLOG_SERVER": "", "TECH_SUPPORT_EMAIL": "technical@example.com", - "THEME_NAME": "", "TIME_ZONE": "America/New_York", "WIKI_ENABLED": true, "OAUTH_OIDC_ISSUER": "https://www.example.com/oauth2" diff --git a/cms/envs/bok_choy.py b/cms/envs/bok_choy.py index 3b370254fa..ad547db949 100644 --- a/cms/envs/bok_choy.py +++ b/cms/envs/bok_choy.py @@ -93,6 +93,9 @@ FEATURES['LICENSING'] = True FEATURES['ENABLE_MOBILE_REST_API'] = True # Enable video bumper in Studio FEATURES['ENABLE_VIDEO_BUMPER'] = True # Enable video bumper in Studio settings +# Enable persistent subsection grades, so that feature can be tested. +FEATURES['ENABLE_SUBSECTION_GRADES_SAVED'] = True + # Enable partner support link in Studio footer PARTNER_SUPPORT_EMAIL = 'partner-support@example.com' @@ -120,6 +123,8 @@ MOCK_SEARCH_BACKING_FILE = ( # this secret key should be the same as lms/envs/bok_choy.py's SECRET_KEY = "very_secret_bok_choy_key" +LMS_ROOT_URL = "http://localhost:8000" + ##################################################################### # Lastly, see if the developer has any local overrides. try: diff --git a/cms/envs/common.py b/cms/envs/common.py index 7408b55f7b..a7c0a3b39d 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -208,6 +208,12 @@ FEATURES = { # Show Language selector 'SHOW_LANGUAGE_SELECTOR': False, + + # Temporary feature flag for disabling saving of subsection grades. + # There is also an advanced setting in the course module. The + # feature flag and the advanced setting must both be true for + # a course to use saved grades. + 'ENABLE_SUBSECTION_GRADES_SAVED': False, } ENABLE_JASMINE = False @@ -296,6 +302,7 @@ AUTHENTICATION_BACKENDS = ( ) LMS_BASE = None +LMS_ROOT_URL = "http://localhost:8000" # These are standard regexes for pulling out info like course_ids, usage_ids, etc. # They are used so that URLs with deprecated-format strings still work. @@ -914,6 +921,7 @@ INSTALLED_APPS = ( # other apps that are. Django 1.8 wants to have imported models supported # by installed apps. 'lms.djangoapps.verify_student', + 'lms.djangoapps.grades', # Microsite configuration application 'microsite_configuration', @@ -929,6 +937,9 @@ INSTALLED_APPS = ( # Enables default site and redirects 'django_sites_extensions', + + # additional release utilities to ease automation + 'release_util' ) diff --git a/cms/envs/dev.py b/cms/envs/dev.py index c72d5c2d41..6d04a115a0 100644 --- a/cms/envs/dev.py +++ b/cms/envs/dev.py @@ -60,6 +60,7 @@ DATABASES = { } LMS_BASE = "localhost:8000" +LMS_ROOT_URL = "http://{}".format(LMS_BASE) FEATURES['PREVIEW_LMS_BASE'] = "localhost:8000" REPOS = { diff --git a/cms/envs/devstack.py b/cms/envs/devstack.py index 7c127dc639..a3bdd31537 100644 --- a/cms/envs/devstack.py +++ b/cms/envs/devstack.py @@ -31,6 +31,7 @@ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' ################################# LMS INTEGRATION ############################# LMS_BASE = "localhost:8000" +LMS_ROOT_URL = "http://{}".format(LMS_BASE) FEATURES['PREVIEW_LMS_BASE'] = "preview." + LMS_BASE ########################### PIPELINE ################################# diff --git a/cms/envs/test.py b/cms/envs/test.py index bf3f5e2b0c..e7d511ee0d 100644 --- a/cms/envs/test.py +++ b/cms/envs/test.py @@ -141,6 +141,7 @@ if os.environ.get('DISABLE_MIGRATIONS'): MIGRATION_MODULES = NoOpMigrationModules() LMS_BASE = "localhost:8000" +LMS_ROOT_URL = "http://{}".format(LMS_BASE) FEATURES['PREVIEW_LMS_BASE'] = "preview.localhost" @@ -223,54 +224,54 @@ FEATURES['EMBARGO'] = True # set up some testing for microsites FEATURES['USE_MICROSITES'] = True -MICROSITE_ROOT_DIR = COMMON_ROOT / 'test' / 'test_microsites' +MICROSITE_ROOT_DIR = COMMON_ROOT / 'test' / 'test_sites' MICROSITE_CONFIGURATION = { - "test_microsite": { - "domain_prefix": "testmicrosite", - "university": "test_microsite", - "platform_name": "Test Microsite", - "logo_image_url": "test_microsite/images/header-logo.png", - "email_from_address": "test_microsite@edx.org", - "payment_support_email": "test_microsite@edx.org", + "test_site": { + "domain_prefix": "test-site", + "university": "test_site", + "platform_name": "Test Site", + "logo_image_url": "test_site/images/header-logo.png", + "email_from_address": "test_site@edx.org", + "payment_support_email": "test_site@edx.org", "ENABLE_MKTG_SITE": False, - "SITE_NAME": "test_microsite.localhost", - "course_org_filter": "TestMicrositeX", + "SITE_NAME": "test_site.localhost", + "course_org_filter": "TestSiteX", "course_about_show_social_links": False, - "css_overrides_file": "test_microsite/css/test_microsite.css", + "css_overrides_file": "test_site/css/test_site.css", "show_partners": False, "show_homepage_promo_video": False, - "course_index_overlay_text": "This is a Test Microsite Overlay Text.", - "course_index_overlay_logo_file": "test_microsite/images/header-logo.png", - "homepage_overlay_html": "

This is a Test Microsite Overlay HTML

", + "course_index_overlay_text": "This is a Test Site Overlay Text.", + "course_index_overlay_logo_file": "test_site/images/header-logo.png", + "homepage_overlay_html": "

This is a Test Site Overlay HTML

", "ALWAYS_REDIRECT_HOMEPAGE_TO_DASHBOARD_FOR_AUTHENTICATED_USER": False, "COURSE_CATALOG_VISIBILITY_PERMISSION": "see_in_catalog", "COURSE_ABOUT_VISIBILITY_PERMISSION": "see_about_page", "ENABLE_SHOPPING_CART": True, "ENABLE_PAID_COURSE_REGISTRATION": True, - "SESSION_COOKIE_DOMAIN": "test_microsite.localhost", + "SESSION_COOKIE_DOMAIN": "test_site.localhost", "urls": { - 'ABOUT': 'testmicrosite/about', - 'PRIVACY': 'testmicrosite/privacy', - 'TOS_AND_HONOR': 'testmicrosite/tos-and-honor', + 'ABOUT': 'test-site/about', + 'PRIVACY': 'test-site/privacy', + 'TOS_AND_HONOR': 'test-site/tos-and-honor', }, }, - "microsite_with_logistration": { + "site_with_logistration": { "domain_prefix": "logistration", "university": "logistration", "platform_name": "Test logistration", - "logo_image_url": "test_microsite/images/header-logo.png", - "email_from_address": "test_microsite@edx.org", - "payment_support_email": "test_microsite@edx.org", + "logo_image_url": "test_site/images/header-logo.png", + "email_from_address": "test_site@edx.org", + "payment_support_email": "test_site@edx.org", "ENABLE_MKTG_SITE": False, "ENABLE_COMBINED_LOGIN_REGISTRATION": True, - "SITE_NAME": "test_microsite.localhost", + "SITE_NAME": "test_site.localhost", "course_org_filter": "LogistrationX", "course_about_show_social_links": False, - "css_overrides_file": "test_microsite/css/test_microsite.css", + "css_overrides_file": "test_site/css/test_site.css", "show_partners": False, "show_homepage_promo_video": False, "course_index_overlay_text": "Logistration.", - "course_index_overlay_logo_file": "test_microsite/images/header-logo.png", + "course_index_overlay_logo_file": "test_site/images/header-logo.png", "homepage_overlay_html": "

This is a Logistration HTML

", "ALWAYS_REDIRECT_HOMEPAGE_TO_DASHBOARD_FOR_AUTHENTICATED_USER": False, "COURSE_CATALOG_VISIBILITY_PERMISSION": "see_in_catalog", @@ -284,7 +285,7 @@ MICROSITE_CONFIGURATION = { "domain_prefix": "www", } } -MICROSITE_TEST_HOSTNAME = 'testmicrosite.testserver' +MICROSITE_TEST_HOSTNAME = 'test-site.testserver' MICROSITE_LOGISTRATION_HOSTNAME = 'logistration.testserver' TEST_THEME = COMMON_ROOT / "test" / "test-theme" @@ -321,6 +322,9 @@ SEARCH_ENGINE = "search.tests.mock_search_engine.MockSearchEngine" # teams feature FEATURES['ENABLE_TEAMS'] = True +# Enable persistent subsection grades, so that feature can be tested. +FEATURES['ENABLE_SUBSECTION_GRADES_SAVED'] = True + # Dummy secret key for dev/test SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd' diff --git a/cms/startup.py b/cms/startup.py index f51b3c1325..66de90bd8f 100644 --- a/cms/startup.py +++ b/cms/startup.py @@ -5,6 +5,7 @@ Module with code executed during Studio startup from django.conf import settings # Force settings to run so that the python path is modified + settings.INSTALLED_APPS # pylint: disable=pointless-statement from openedx.core.lib.django_startup import autostartup @@ -18,6 +19,7 @@ from openedx.core.lib.xblock_utils import xblock_local_resource_url import xmodule.x_module import cms.lib.xblock.runtime +from startup_configurations.validate_config import validate_cms_config from openedx.core.djangoapps.theming.core import enable_theming from openedx.core.djangoapps.theming.helpers import is_comprehensive_theming_enabled @@ -40,9 +42,6 @@ def run(): add_mimetypes() - if settings.FEATURES.get('USE_CUSTOM_THEME', False): - enable_theme() - # In order to allow descriptors to use a handler url, we need to # monkey-patch the x_module library. # TODO: Remove this code when Runtimes are no longer created by modulestores @@ -50,6 +49,9 @@ def run(): xmodule.x_module.descriptor_global_handler_url = cms.lib.xblock.runtime.handler_url xmodule.x_module.descriptor_global_local_resource_url = xblock_local_resource_url + # validate configurations on startup + validate_cms_config(settings) + def add_mimetypes(): """ @@ -63,34 +65,3 @@ def add_mimetypes(): mimetypes.add_type('application/x-font-opentype', '.otf') mimetypes.add_type('application/x-font-ttf', '.ttf') mimetypes.add_type('application/font-woff', '.woff') - - -def enable_theme(): - """ - Enable the settings for a custom theme, whose files should be stored - in ENV_ROOT/themes/THEME_NAME (e.g., edx_all/themes/stanford). - At this moment this is actually just a fix for collectstatic, - (see https://openedx.atlassian.net/browse/TNL-726), - but can be improved with a full theming option also for Studio - in the future (see lms.startup) - """ - # Workaround for setting THEME_NAME to an empty - # string which is the default due to this ansible - # bug: https://github.com/ansible/ansible/issues/4812 - if settings.THEME_NAME == "": - settings.THEME_NAME = None - return - - assert settings.FEATURES['USE_CUSTOM_THEME'] - settings.FAVICON_PATH = 'themes/{name}/images/favicon.ico'.format( - name=settings.THEME_NAME - ) - - # Calculate the location of the theme's files - theme_root = settings.ENV_ROOT / "themes" / settings.THEME_NAME - - # Namespace the theme's static files to 'themes/' to - # avoid collisions with default edX static files - settings.STATICFILES_DIRS.append( - (u'themes/{}'.format(settings.THEME_NAME), theme_root / 'static') - ) diff --git a/cms/static/cms/js/build.js b/cms/static/cms/js/build.js index f6a3c1534c..fd90513c2a 100644 --- a/cms/static/cms/js/build.js +++ b/cms/static/cms/js/build.js @@ -16,7 +16,7 @@ var getModulesList = function(modules) { var result = [getModule(commonLibrariesPath)]; - return result.concat(modules.map(function (moduleName) { + return result.concat(modules.map(function(moduleName) { return getModule(moduleName, true); })); }; @@ -53,7 +53,8 @@ 'js/factories/settings_graders', 'js/factories/textbooks', 'js/factories/videos_index', - 'js/factories/xblock_validation' + 'js/factories/xblock_validation', + 'js/programs/program_admin_app' ]), /** * By default all the configuration for optimization happens from the command @@ -170,4 +171,5 @@ */ logLevel: 1 }; -}()) +}()) // eslint-disable-line semi +// A semicolon on the line above will break the requirejs optimizer diff --git a/cms/static/cms/js/main.js b/cms/static/cms/js/main.js index 0cae898de3..219f362a7f 100644 --- a/cms/static/cms/js/main.js +++ b/cms/static/cms/js/main.js @@ -1,3 +1,5 @@ +/* globals AjaxPrefix */ + (function(AjaxPrefix) { 'use strict'; define(['domReady', 'jquery', 'underscore.string', 'backbone', 'gettext', @@ -34,7 +36,7 @@ message = str.truncate(jqXHR.responseText, 300); } } else { - message = gettext('This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.'); //jshint ignore:line + message = gettext('This may be happening because of an error with our server or your internet connection. Try refreshing the page or making sure you are online.'); // eslint-disable-line max-len } msg = new NotificationView.Error({ 'title': gettext("Studio's having trouble saving your work"), @@ -65,5 +67,4 @@ main(); return main; }); - -}).call(this, AjaxPrefix); //jshint ignore:line +}).call(this, AjaxPrefix); diff --git a/cms/static/cms/js/require-config.js b/cms/static/cms/js/require-config.js index 7f9e526e51..45aadf6498 100644 --- a/cms/static/cms/js/require-config.js +++ b/cms/static/cms/js/require-config.js @@ -1,4 +1,4 @@ -;(function(require, define) { +(function(require, define) { 'use strict'; if (window) { @@ -94,7 +94,7 @@ // end of Annotation tool files // externally hosted files - 'mathjax': '//cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // jshint ignore:line + mathjax: '//cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len 'youtube': [ // youtube URL does not end in '.js'. We add '?noext' to the path so // that require.js adds the '.js' to the query component of the URL, @@ -210,12 +210,12 @@ window.MathJax.Hub.Config({ tex2jax: { inlineMath: [ - ['\\(','\\)'], - ['[mathjaxinline]','[/mathjaxinline]'] + ['\\(', '\\)'], + ['[mathjaxinline]', '[/mathjaxinline]'] ], displayMath: [ - ['\\[','\\]'], - ['[mathjax]','[/mathjax]'] + ['\\[', '\\]'], + ['[mathjax]', '[/mathjax]'] ] } }); diff --git a/cms/static/cms/js/spec/main.js b/cms/static/cms/js/spec/main.js index 223a25b564..a74bf1cb9f 100644 --- a/cms/static/cms/js/spec/main.js +++ b/cms/static/cms/js/spec/main.js @@ -1,3 +1,5 @@ +/* globals requirejs, requireSerial */ + (function(requirejs, requireSerial) { 'use strict'; @@ -22,9 +24,9 @@ 'jquery.cookie': 'xmodule_js/common_static/js/vendor/jquery.cookie', 'jquery.qtip': 'xmodule_js/common_static/js/vendor/jquery.qtip.min', 'jquery.fileupload': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload', - 'jquery.fileupload-process': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-process', // jshint ignore:line - 'jquery.fileupload-validate': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate', // jshint ignore:line - 'jquery.iframe-transport': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport', // jshint ignore:line + 'jquery.fileupload-process': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-process', // eslint-disable-line max-len + 'jquery.fileupload-validate': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate', // eslint-disable-line max-len + 'jquery.iframe-transport': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport', // eslint-disable-line max-len 'jquery.inputnumber': 'xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill', 'jquery.immediateDescendents': 'xmodule_js/common_static/coffee/src/jquery.immediateDescendents', 'jquery.simulate': 'xmodule_js/common_static/js/vendor/jquery.simulate', @@ -54,7 +56,7 @@ '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', - 'mathjax': '//cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // jshint ignore:line + mathjax: '//cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len 'youtube': '//www.youtube.com/player_api?noext', 'coffee/src/ajax_prefix': 'xmodule_js/common_static/coffee/src/ajax_prefix', 'js/spec/test_utils': 'js/spec/test_utils' @@ -290,5 +292,4 @@ requireSerial(specHelpers.concat(testFiles), function() { return window.__karma__.start(); }); - -}).call(this, requirejs, requireSerial); // jshint ignore:line +}).call(this, requirejs, requireSerial); diff --git a/cms/static/cms/js/spec/main_spec.js b/cms/static/cms/js/spec/main_spec.js index 235ce31e96..ed01a312b2 100644 --- a/cms/static/cms/js/spec/main_spec.js +++ b/cms/static/cms/js/spec/main_spec.js @@ -1,81 +1,82 @@ +/* globals sandbox */ + (function(sandbox) { 'use strict'; - require(["jquery", "backbone", "cms/js/main", "edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers", "jquery.cookie"], + require(['jquery', 'backbone', 'cms/js/main', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers', 'jquery.cookie'], function($, Backbone, main, AjaxHelpers) { - describe("CMS", function() { - it("should initialize URL", function() { - expect(window.CMS.URL).toBeDefined(); - }); - }); - describe("main helper", function() { - beforeEach(function() { - this.previousAjaxSettings = $.extend(true, {}, $.ajaxSettings); - spyOn($, "cookie").and.callFake(function(param) { - if (param === "csrftoken") { - return "stubCSRFToken"; - } + describe('CMS', function() { + it('should initialize URL', function() { + expect(window.CMS.URL).toBeDefined(); + }); }); - return main(); - }); - afterEach(function() { - $.ajaxSettings = this.previousAjaxSettings; - return $.ajaxSettings; - }); - it("turn on Backbone emulateHTTP", function() { - expect(Backbone.emulateHTTP).toBeTruthy(); - }); - it("setup AJAX CSRF token", function() { - expect($.ajaxSettings.headers["X-CSRFToken"]).toEqual("stubCSRFToken"); - }); - }); - describe("AJAX Errors", function() { - var server; - server = null; - beforeEach(function() { - appendSetFixtures(sandbox({ - id: "page-notification" - })); - }); - afterEach(function() { - return server && server.restore(); - }); - it("successful AJAX request does not pop an error notification", function() { - server = AjaxHelpers.server([ - 200, { - "Content-Type": "application/json" - }, "{}" - ]); - expect($("#page-notification")).toBeEmpty(); - $.ajax("/test"); - expect($("#page-notification")).toBeEmpty(); - server.respond(); - expect($("#page-notification")).toBeEmpty(); - }); - it("AJAX request with error should pop an error notification", function() { - server = AjaxHelpers.server([ - 500, { - "Content-Type": "application/json" - }, "{}" - ]); - $.ajax("/test"); - server.respond(); - expect($("#page-notification")).not.toBeEmpty(); - expect($("#page-notification")).toContainElement('div.wrapper-notification-error'); - }); - it("can override AJAX request with error so it does not pop an error notification", function() { - server = AjaxHelpers.server([ - 500, { - "Content-Type": "application/json" - }, "{}" - ]); - $.ajax({ - url: "/test", - notifyOnError: false + describe('main helper', function() { + beforeEach(function() { + this.previousAjaxSettings = $.extend(true, {}, $.ajaxSettings); + spyOn($, 'cookie').and.callFake(function(param) { + if (param === 'csrftoken') { + return 'stubCSRFToken'; + } + }); + return main(); + }); + afterEach(function() { + $.ajaxSettings = this.previousAjaxSettings; + return $.ajaxSettings; + }); + it('turn on Backbone emulateHTTP', function() { + expect(Backbone.emulateHTTP).toBeTruthy(); + }); + it('setup AJAX CSRF token', function() { + expect($.ajaxSettings.headers['X-CSRFToken']).toEqual('stubCSRFToken'); + }); + }); + describe('AJAX Errors', function() { + var server; + server = null; + beforeEach(function() { + appendSetFixtures(sandbox({ + id: 'page-notification' + })); + }); + afterEach(function() { + return server && server.restore(); + }); + it('successful AJAX request does not pop an error notification', function() { + server = AjaxHelpers.server([ + 200, { + 'Content-Type': 'application/json' + }, '{}' + ]); + expect($('#page-notification')).toBeEmpty(); + $.ajax('/test'); + expect($('#page-notification')).toBeEmpty(); + server.respond(); + expect($('#page-notification')).toBeEmpty(); + }); + it('AJAX request with error should pop an error notification', function() { + server = AjaxHelpers.server([ + 500, { + 'Content-Type': 'application/json' + }, '{}' + ]); + $.ajax('/test'); + server.respond(); + expect($('#page-notification')).not.toBeEmpty(); + expect($('#page-notification')).toContainElement('div.wrapper-notification-error'); + }); + it('can override AJAX request with error so it does not pop an error notification', function() { + server = AjaxHelpers.server([ + 500, { + 'Content-Type': 'application/json' + }, '{}' + ]); + $.ajax({ + url: '/test', + notifyOnError: false + }); + server.respond(); + expect($('#page-notification')).toBeEmpty(); + }); }); - server.respond(); - expect($("#page-notification")).toBeEmpty(); }); - }); - }); - -}).call(this, sandbox); //jshint ignore:line +}).call(this, sandbox); diff --git a/cms/static/cms/js/spec/main_squire.js b/cms/static/cms/js/spec/main_squire.js index 867047263d..b4eb462775 100644 --- a/cms/static/cms/js/spec/main_squire.js +++ b/cms/static/cms/js/spec/main_squire.js @@ -1,3 +1,5 @@ +/* globals requirejs, requireSerial */ + (function(requirejs, requireSerial) { 'use strict'; @@ -21,9 +23,9 @@ 'jquery.cookie': 'xmodule_js/common_static/js/vendor/jquery.cookie', 'jquery.qtip': 'xmodule_js/common_static/js/vendor/jquery.qtip.min', 'jquery.fileupload': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload', - 'jquery.fileupload-process': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-process', // jshint ignore:line - 'jquery.fileupload-validate': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate', // jshint ignore:line - 'jquery.iframe-transport': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport', // jshint ignore:line + 'jquery.fileupload-process': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-process', // eslint-disable-line max-len + 'jquery.fileupload-validate': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate', // eslint-disable-line max-len + 'jquery.iframe-transport': 'xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport', // eslint-disable-line max-len 'jquery.inputnumber': 'xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill', 'jquery.immediateDescendents': 'xmodule_js/common_static/coffee/src/jquery.immediateDescendents', 'datepair': 'xmodule_js/common_static/js/vendor/timepicker/datepair', @@ -46,7 +48,7 @@ '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', - 'mathjax': '//cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // jshint ignore:line + mathjax: '//cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len 'youtube': '//www.youtube.com/player_api?noext', 'coffee/src/ajax_prefix': 'xmodule_js/common_static/coffee/src/ajax_prefix' }, @@ -206,5 +208,4 @@ requireSerial(specHelpers.concat(testFiles), function() { return window.__karma__.start(); }); - -}).call(this, requirejs, requireSerial); // jshint ignore:line +}).call(this, requirejs, requireSerial); diff --git a/cms/static/cms/js/xblock/cms.runtime.v1.js b/cms/static/cms/js/xblock/cms.runtime.v1.js index 6c5e73aaf3..6b07ec80e1 100644 --- a/cms/static/cms/js/xblock/cms.runtime.v1.js +++ b/cms/static/cms/js/xblock/cms.runtime.v1.js @@ -24,7 +24,6 @@ define(['jquery', 'backbone', 'xblock/runtime.v1', 'URI', 'gettext', 'js/utils/m StudioRuntime = {}; BaseRuntime.v1 = (function(_super) { - __extends(v1, _super); v1.prototype.handlerUrl = function(element, handlerName, suffix, query) { @@ -150,11 +149,9 @@ define(['jquery', 'backbone', 'xblock/runtime.v1', 'URI', 'gettext', 'js/utils/m }; return v1; - })(XBlock.Runtime.v1); PreviewRuntime.v1 = (function(_super) { - __extends(v1, _super); function v1() { @@ -164,11 +161,9 @@ define(['jquery', 'backbone', 'xblock/runtime.v1', 'URI', 'gettext', 'js/utils/m v1.prototype.handlerPrefix = '/preview/xblock'; return v1; - })(BaseRuntime.v1); StudioRuntime.v1 = (function(_super) { - __extends(v1, _super); function v1() { @@ -178,7 +173,6 @@ define(['jquery', 'backbone', 'xblock/runtime.v1', 'URI', 'gettext', 'js/utils/m v1.prototype.handlerPrefix = '/xblock'; return v1; - })(BaseRuntime.v1); // Install the runtime's into the global namespace diff --git a/cms/static/js/base.js b/cms/static/js/base.js index 94c6cc2648..ed2c75f7bf 100644 --- a/cms/static/js/base.js +++ b/cms/static/js/base.js @@ -1,19 +1,19 @@ require([ - "domReady", - "jquery", - "underscore", - "gettext", - "common/js/components/views/feedback_notification", - "common/js/components/views/feedback_prompt", - "js/utils/date_utils", - "js/utils/module", - "js/utils/handle_iframe_binding", - "edx-ui-toolkit/js/dropdown-menu/dropdown-menu-view", - "jquery.ui", - "jquery.leanModal", - "jquery.form", - "jquery.smoothScroll" - ], + 'domReady', + 'jquery', + 'underscore', + 'gettext', + 'common/js/components/views/feedback_notification', + 'common/js/components/views/feedback_prompt', + 'js/utils/date_utils', + 'js/utils/module', + 'js/utils/handle_iframe_binding', + 'edx-ui-toolkit/js/dropdown-menu/dropdown-menu-view', + 'jquery.ui', + 'jquery.leanModal', + 'jquery.form', + 'jquery.smoothScroll' +], function( domReady, $, @@ -27,113 +27,110 @@ require([ DropdownMenuView ) { + var $body; -var $body; + domReady(function() { + var dropdownMenuView; -domReady(function() { - var dropdownMenuView; - - $body = $('body'); + $body = $('body'); - $body.on('click', '.embeddable-xml-input', function() { - $(this).select(); - }); + $body.on('click', '.embeddable-xml-input', function() { + $(this).select(); + }); - $body.addClass('js'); + $body.addClass('js'); - // alerts/notifications - manual close - $('.action-alert-close, .alert.has-actions .nav-actions a').bind('click', hideAlert); - $('.action-notification-close').bind('click', hideNotification); + // alerts/notifications - manual close + $('.action-alert-close, .alert.has-actions .nav-actions a').bind('click', hideAlert); + $('.action-notification-close').bind('click', hideNotification); - // nav - dropdown related - $body.click(function(e) { - $('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown'); - $('.nav-dd .nav-item .title').removeClass('is-selected'); - }); + // nav - dropdown related + $body.click(function(e) { + $('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown'); + $('.nav-dd .nav-item .title').removeClass('is-selected'); + }); - $('.nav-dd .nav-item, .filterable-column .nav-item').click(function(e) { + $('.nav-dd .nav-item, .filterable-column .nav-item').click(function(e) { + $subnav = $(this).find('.wrapper-nav-sub'); + $title = $(this).find('.title'); - $subnav = $(this).find('.wrapper-nav-sub'); - $title = $(this).find('.title'); - - if ($subnav.hasClass('is-shown')) { - $subnav.removeClass('is-shown'); - $title.removeClass('is-selected'); - } else { - $('.nav-dd .nav-item .title').removeClass('is-selected'); - $('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown'); - $title.addClass('is-selected'); - $subnav.addClass('is-shown'); + if ($subnav.hasClass('is-shown')) { + $subnav.removeClass('is-shown'); + $title.removeClass('is-selected'); + } else { + $('.nav-dd .nav-item .title').removeClass('is-selected'); + $('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown'); + $title.addClass('is-selected'); + $subnav.addClass('is-shown'); // if propagation is not stopped, the event will bubble up to the // body element, which will close the dropdown. - e.stopPropagation(); - } - }); + e.stopPropagation(); + } + }); - // general link management - new window/tab - $('a[rel="external"]:not([title])').attr('title', gettext('This link will open in a new browser window/tab')); - $('a[rel="external"]').attr('target', '_blank'); + // general link management - new window/tab + $('a[rel="external"]:not([title])').attr('title', gettext('This link will open in a new browser window/tab')); + $('a[rel="external"]').attr('target', '_blank'); - // general link management - lean modal window - $('a[rel="modal"]').attr('title', gettext('This link will open in a modal window')).leanModal({ - overlay: 0.50, - closeButton: '.action-modal-close' - }); - $('.action-modal-close').click(function(e) { - (e).preventDefault(); - }); + // general link management - lean modal window + $('a[rel="modal"]').attr('title', gettext('This link will open in a modal window')).leanModal({ + overlay: 0.50, + closeButton: '.action-modal-close' + }); + $('.action-modal-close').click(function(e) { + (e).preventDefault(); + }); - // general link management - smooth scrolling page links - $('a[rel*="view"][href^="#"]').bind('click', smoothScrollLink); + // general link management - smooth scrolling page links + $('a[rel*="view"][href^="#"]').bind('click', smoothScrollLink); - IframeUtils.iframeBinding(); + IframeUtils.iframeBinding(); - // disable ajax caching in IE so that backbone fetches work - if ($.browser.msie) { - $.ajaxSetup({ cache: false }); - } + // disable ajax caching in IE so that backbone fetches work + if ($.browser.msie) { + $.ajaxSetup({cache: false}); + } - //Initiate the edx tool kit dropdown menu - if ($('.js-header-user-menu').length){ - dropdownMenuView = new DropdownMenuView({ - el: '.js-header-user-menu' + // Initiate the edx tool kit dropdown menu + if ($('.js-header-user-menu').length) { + dropdownMenuView = new DropdownMenuView({ + el: '.js-header-user-menu' + }); + dropdownMenuView.postRender(); + } }); - dropdownMenuView.postRender(); - } -}); -function smoothScrollLink(e) { - (e).preventDefault(); + function smoothScrollLink(e) { + (e).preventDefault(); - $.smoothScroll({ - offset: -200, - easing: 'swing', - speed: 1000, - scrollElement: null, - scrollTarget: $(this).attr('href') - }); -} + $.smoothScroll({ + offset: -200, + easing: 'swing', + speed: 1000, + scrollElement: null, + scrollTarget: $(this).attr('href') + }); + } -function smoothScrollTop(e) { - (e).preventDefault(); + function smoothScrollTop(e) { + (e).preventDefault(); - $.smoothScroll({ - offset: -200, - easing: 'swing', - speed: 1000, - scrollElement: null, - scrollTarget: $('#view-top') - }); -} + $.smoothScroll({ + offset: -200, + easing: 'swing', + speed: 1000, + scrollElement: null, + scrollTarget: $('#view-top') + }); + } -function hideNotification(e) { - (e).preventDefault(); - $(this).closest('.wrapper-notification').removeClass('is-shown').addClass('is-hiding').attr('aria-hidden', 'true'); -} + function hideNotification(e) { + (e).preventDefault(); + $(this).closest('.wrapper-notification').removeClass('is-shown').addClass('is-hiding').attr('aria-hidden', 'true'); + } -function hideAlert(e) { - (e).preventDefault(); - $(this).closest('.wrapper-alert').removeClass('is-shown'); -} - -}); // end require() + function hideAlert(e) { + (e).preventDefault(); + $(this).closest('.wrapper-alert').removeClass('is-shown'); + } + }); // end require() diff --git a/cms/static/js/certificates/collections/certificates.js b/cms/static/js/certificates/collections/certificates.js index 234dd0098b..e567514d21 100644 --- a/cms/static/js/certificates/collections/certificates.js +++ b/cms/static/js/certificates/collections/certificates.js @@ -1,6 +1,6 @@ // Backbone.js Application Collection: Certificates -define([ // jshint ignore:line +define([ 'backbone', 'gettext', 'js/certificates/models/certificate' @@ -29,7 +29,7 @@ function(Backbone, gettext, Certificate) { } catch (ex) { // If it didn't parse, and `certificate_info` is an object then return as it is // otherwise return empty array - if (typeof certificate_info === 'object'){ + if (typeof certificate_info === 'object') { return_array = certificate_info; } else { @@ -44,28 +44,28 @@ function(Backbone, gettext, Certificate) { return return_array; }, - onModelRemoved: function () { + onModelRemoved: function() { // remove the certificate web preview UI. - if(window.certWebPreview && this.length === 0) { + if (window.certWebPreview && this.length === 0) { window.certWebPreview.remove(); } this.toggleAddNewItemButtonState(); }, - onModelAdd: function () { + onModelAdd: function() { this.toggleAddNewItemButtonState(); }, toggleAddNewItemButtonState: function() { // user can create a new item e.g certificate; if not exceeded the maxAllowed limit. - if(this.length >= this.maxAllowed) { - $(".action-add").addClass('action-add-hidden'); + if (this.length >= this.maxAllowed) { + $('.action-add').addClass('action-add-hidden'); } else { - $(".action-add").removeClass('action-add-hidden'); + $('.action-add').removeClass('action-add-hidden'); } }, - parse: function (certificatesJson) { + parse: function(certificatesJson) { // Transforms the provided JSON into a Certificates collection var modelArray = this.certificate_array(certificatesJson); diff --git a/cms/static/js/certificates/collections/signatories.js b/cms/static/js/certificates/collections/signatories.js index 3205fab41f..cd76e1c502 100644 --- a/cms/static/js/certificates/collections/signatories.js +++ b/cms/static/js/certificates/collections/signatories.js @@ -1,6 +1,6 @@ // Backbone.js Application Collection: Certificate Signatories -define([ // jshint ignore:line +define([ 'backbone', 'js/certificates/models/signatory' ], diff --git a/cms/static/js/certificates/factories/certificates_page_factory.js b/cms/static/js/certificates/factories/certificates_page_factory.js index a3943dfe78..cb935ddb06 100644 --- a/cms/static/js/certificates/factories/certificates_page_factory.js +++ b/cms/static/js/certificates/factories/certificates_page_factory.js @@ -11,7 +11,7 @@ The RequireJS Optimizer is only enabled in Studio at present, so the page factor We do intend to enable page factories on the LMS too. */ -define([ // jshint ignore:line +define([ 'jquery', 'js/certificates/collections/certificates', 'js/certificates/models/certificate', @@ -20,7 +20,7 @@ define([ // jshint ignore:line ], function($, CertificatesCollection, Certificate, CertificatesPage, CertificatePreview) { 'use strict'; - return function (certificatesJson, certificateUrl, courseOutlineUrl, course_modes, certificate_web_view_url, + return function(certificatesJson, certificateUrl, courseOutlineUrl, course_modes, certificate_web_view_url, is_active, certificate_activation_handler_url) { // Initialize the model collection, passing any necessary options to the constructor var certificatesCollection = new CertificatesCollection(certificatesJson, { @@ -31,7 +31,7 @@ function($, CertificatesCollection, Certificate, CertificatesPage, CertificatePr // associating the certificate_preview globally. // need to show / hide this view in some other places. - if(!window.certWebPreview && certificate_web_view_url) { + if (!window.certWebPreview && certificate_web_view_url) { window.certWebPreview = new CertificatePreview({ course_modes: course_modes, certificate_web_view_url: certificate_web_view_url, diff --git a/cms/static/js/certificates/models/certificate.js b/cms/static/js/certificates/models/certificate.js index 5518867312..a440d569d6 100644 --- a/cms/static/js/certificates/models/certificate.js +++ b/cms/static/js/certificates/models/certificate.js @@ -1,15 +1,15 @@ // Backbone.js Application Model: Certificate define([ - 'underscore', - 'backbone', - 'backbone-relational', - 'backbone.associations', - 'gettext', - 'cms/js/main', - 'js/certificates/models/signatory', - 'js/certificates/collections/signatories' - ], + 'underscore', + 'backbone', + 'backbone-relational', + 'backbone.associations', + 'gettext', + 'cms/js/main', + 'js/certificates/models/signatory', + 'js/certificates/collections/signatories' +], function(_, Backbone, BackboneRelational, BackboneAssociations, gettext, CoffeeSrcMain, SignatoryModel, SignatoryCollection) { 'use strict'; @@ -78,7 +78,7 @@ define([ attributes: {name: true} }; } - var allSignatoriesValid = _.every(attrs.signatories.models, function(signatory){ + var allSignatoriesValid = _.every(attrs.signatories.models, function(signatory) { return signatory.isValid(); }); if (!allSignatoriesValid) { diff --git a/cms/static/js/certificates/models/signatory.js b/cms/static/js/certificates/models/signatory.js index 445743cfc5..499ff3467a 100644 --- a/cms/static/js/certificates/models/signatory.js +++ b/cms/static/js/certificates/models/signatory.js @@ -1,6 +1,6 @@ // Backbone.js Application Model: Certificate Signatory -define([ // jshint ignore:line +define([ 'underscore', 'backbone', 'backbone-relational' diff --git a/cms/static/js/certificates/spec/custom_matchers.js b/cms/static/js/certificates/spec/custom_matchers.js index 43b11bff37..cd960f469f 100644 --- a/cms/static/js/certificates/spec/custom_matchers.js +++ b/cms/static/js/certificates/spec/custom_matchers.js @@ -1,15 +1,15 @@ // Custom matcher library for Jasmine test assertions // http://tobyho.com/2012/01/30/write-a-jasmine-matcher/ -define(['jquery'], function($) { // jshint ignore:line +define(['jquery'], function($) { // eslint-disable-line no-unused-vars 'use strict'; - return function () { + return function() { jasmine.addMatchers({ - toBeCorrectValuesInModel: function () { + toBeCorrectValuesInModel: function() { // Assert the value being tested has key values which match the provided values return { - compare: function (actual, values) { - var passed = _.every(values, function (value, key) { + compare: function(actual, values) { + var passed = _.every(values, function(value, key) { return actual.get(key) === value; }.bind(this)); diff --git a/cms/static/js/certificates/spec/models/certificate_spec.js b/cms/static/js/certificates/spec/models/certificate_spec.js index 5197209e2a..6c37488859 100644 --- a/cms/static/js/certificates/spec/models/certificate_spec.js +++ b/cms/static/js/certificates/spec/models/certificate_spec.js @@ -1,6 +1,6 @@ // Jasmine Test Suite: Certifiate Model -define([ // jshint ignore:line +define([ 'js/certificates/models/certificate', 'js/certificates/collections/certificates' ], @@ -11,7 +11,7 @@ function(CertificateModel, CertificateCollection) { beforeEach(function() { this.newModelOptions = {add: true}; this.model = new CertificateModel({editing: true}, this.newModelOptions); - this.collection = new CertificateCollection([ this.model ], {certificateUrl: '/outline'}); + this.collection = new CertificateCollection([this.model], {certificateUrl: '/outline'}); }); describe('Basic', function() { @@ -39,18 +39,16 @@ function(CertificateModel, CertificateCollection) { describe('Validation', function() { it('requires a name', function() { - var model = new CertificateModel({ name: '' }, this.newModelOptions); + var model = new CertificateModel({name: ''}, this.newModelOptions); expect(model.isValid()).toBeFalsy(); }); it('can pass validation', function() { - var model = new CertificateModel({ name: 'foo' }, this.newModelOptions); + var model = new CertificateModel({name: 'foo'}, this.newModelOptions); expect(model.isValid()).toBeTruthy(); }); - }); }); - }); diff --git a/cms/static/js/certificates/spec/views/certificate_details_spec.js b/cms/static/js/certificates/spec/views/certificate_details_spec.js index 7c02d4ef14..4a58c5d97e 100644 --- a/cms/static/js/certificates/spec/views/certificate_details_spec.js +++ b/cms/static/js/certificates/spec/views/certificate_details_spec.js @@ -1,6 +1,6 @@ // Jasmine Test Suite: Certifiate Details View -define([ // jshint ignore:line +define([ 'underscore', 'js/models/course', 'js/certificates/collections/certificates', @@ -41,15 +41,15 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails inputSignatoryTitle: '.signatory-title-input', inputSignatoryOrganization: '.signatory-organization-input' }; - var verifyAndConfirmPrompt = function(promptSpy, promptText){ + var verifyAndConfirmPrompt = function(promptSpy, promptText) { ViewHelpers.verifyPromptShowing(promptSpy, gettext(promptText)); ViewHelpers.confirmPrompt(promptSpy); ViewHelpers.verifyPromptHidden(promptSpy); }; describe('Certificate Details Spec:', function() { - var setValuesToInputs = function (view, values) { - _.each(values, function (value, selector) { + var setValuesToInputs = function(view, values) { + _.each(values, function(value, selector) { if (SELECTORS[selector]) { view.$(SELECTORS[selector]).val(value); view.$(SELECTORS[selector]).trigger('change'); @@ -96,15 +96,15 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails is_active: true }, this.newModelOptions); - this.collection = new CertificatesCollection([ this.model ], { - certificateUrl: '/certificates/'+ window.course.id + this.collection = new CertificatesCollection([this.model], { + certificateUrl: '/certificates/' + window.course.id }); this.model.set('id', 0); this.view = new CertificateDetailsView({ model: this.model }); appendSetFixtures(this.view.render().el); - CustomMatchers(); // jshint ignore:line + CustomMatchers(); }); afterEach(function() { @@ -120,44 +120,43 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails describe('The Certificate Details view', function() { - - it('should parse a JSON string collection into a Backbone model collection', function () { - var course_title = "Test certificate course title override 2"; + it('should parse a JSON string collection into a Backbone model collection', function() { + var course_title = 'Test certificate course title override 2'; var CERTIFICATE_JSON = '[{"course_title": "' + course_title + '", "signatories":"[]"}]'; this.collection.parse(CERTIFICATE_JSON); var model = this.collection.at(1); expect(model.get('course_title')).toEqual(course_title); }); - it('should parse a JSON object collection into a Backbone model collection', function () { - var course_title = "Test certificate course title override 2"; + it('should parse a JSON object collection into a Backbone model collection', function() { + var course_title = 'Test certificate course title override 2'; var CERTIFICATE_JSON_OBJECT = [{ - "course_title" : course_title, - "signatories" : "[]" + 'course_title': course_title, + 'signatories': '[]' }]; this.collection.parse(CERTIFICATE_JSON_OBJECT); var model = this.collection.at(1); expect(model.get('course_title')).toEqual(course_title); }); - it('should have empty certificate collection if there is an error parsing certifcate JSON', function () { - var CERTIFICATE_INVALID_JSON = '[{"course_title": Test certificate course title override, "signatories":"[]"}]'; // jshint ignore:line + it('should have empty certificate collection if there is an error parsing certifcate JSON', function() { + var CERTIFICATE_INVALID_JSON = '[{"course_title": Test certificate course title override, "signatories":"[]"}]'; // eslint-disable-line max-len var collection_length = this.collection.length; this.collection.parse(CERTIFICATE_INVALID_JSON); - //collection length should remain the same since we have error parsing JSON + // collection length should remain the same since we have error parsing JSON expect(this.collection.length).toEqual(collection_length); }); - it('should display the certificate course title override', function () { + it('should display the certificate course title override', function() { expect(this.view.$(SELECTORS.course_title)).toExist(); expect(this.view.$(SELECTORS.course_title)).toContainText('Test Course Title Override'); }); - it('should present an Edit action', function () { + it('should present an Edit action', function() { expect(this.view.$('.edit')).toExist(); }); - it('should change to "edit" mode when clicking the Edit button and confirming the prompt', function(){ + it('should change to "edit" mode when clicking the Edit button and confirming the prompt', function() { expect(this.view.$('.action-edit .edit')).toExist(); var promptSpy = ViewHelpers.createPromptSpy(); this.view.$('.action-edit .edit').click(); @@ -165,67 +164,64 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails expect(this.model.get('editing')).toBe(true); }); - it('should not show confirmation prompt when clicked on "edit" in case of inactive certificate', function(){ + it('should not show confirmation prompt when clicked on "edit" in case of inactive certificate', function() { this.model.set('is_active', false); expect(this.view.$('.action-edit .edit')).toExist(); this.view.$('.action-edit .edit').click(); expect(this.model.get('editing')).toBe(true); }); - it('should not present a Edit action if user is not global staff and certificate is active', function () { + it('should not present a Edit action if user is not global staff and certificate is active', function() { window.CMS.User = {isGlobalStaff: false}; appendSetFixtures(this.view.render().el); expect(this.view.$('.action-edit .edit')).not.toExist(); }); - it('should present a Delete action', function () { + it('should present a Delete action', function() { expect(this.view.$('.action-delete .delete')).toExist(); }); - it('should not present a Delete action if user is not global staff and certificate is active', function () { + it('should not present a Delete action if user is not global staff and certificate is active', function() { window.CMS.User = {isGlobalStaff: false}; appendSetFixtures(this.view.render().el); expect(this.view.$('.action-delete .delete')).not.toExist(); }); - it('should prompt the user when when clicking the Delete button', function(){ + it('should prompt the user when when clicking the Delete button', function() { expect(this.view.$('.action-delete .delete')).toExist(); this.view.$('.action-delete .delete').click(); }); - it('should scroll to top after rendering if necessary', function () { + it('should scroll to top after rendering if necessary', function() { $.smoothScroll = jasmine.createSpy('jQuery.smoothScroll'); appendSetFixtures(this.view.render().el); expect($.smoothScroll).toHaveBeenCalled(); }); - }); - describe('Signatory details', function(){ - + describe('Signatory details', function() { beforeEach(function() { this.view.render(); }); - it('displays certificate signatories details', function(){ + it('displays certificate signatories details', function() { this.view.$('.show-details').click(); expect(this.view.$(SELECTORS.signatory_name_value)).toContainText(''); expect(this.view.$(SELECTORS.signatory_title_value)).toContainText(''); expect(this.view.$(SELECTORS.signatory_organization_value)).toContainText(''); }); - it('should present Edit action on signaotry', function () { + it('should present Edit action on signaotry', function() { expect(this.view.$(SELECTORS.edit_signatory)).toExist(); }); - it('should not present Edit action on signaotry if user is not global staff and certificate is active', function () { + it('should not present Edit action on signaotry if user is not global staff and certificate is active', function() { window.CMS.User = {isGlobalStaff: false}; this.view.render(); expect(this.view.$(SELECTORS.edit_signatory)).not.toExist(); }); it('supports in-line editing of signatory information', function() { - this.view.$(SELECTORS.edit_signatory).click(); expect(this.view.$(SELECTORS.inputSignatoryName)).toExist(); expect(this.view.$(SELECTORS.inputSignatoryTitle)).toExist(); @@ -233,7 +229,6 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails }); it('correctly persists changes made during in-line signatory editing', function() { - var requests = AjaxHelpers.requests(this), notificationSpy = ViewHelpers.createNotificationSpy(); diff --git a/cms/static/js/certificates/spec/views/certificate_editor_spec.js b/cms/static/js/certificates/spec/views/certificate_editor_spec.js index 0cee81f0f7..39416e56a8 100644 --- a/cms/static/js/certificates/spec/views/certificate_editor_spec.js +++ b/cms/static/js/certificates/spec/views/certificate_editor_spec.js @@ -1,6 +1,6 @@ // Jasmine Test Suite: Certifiate Editor View -define([ // jshint ignore:line +define([ 'underscore', 'js/models/course', 'js/certificates/models/certificate', @@ -37,14 +37,14 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce note: '.wrapper-delete-button', addSignatoryButton: '.action-add-signatory', signatoryDeleteButton: '.signatory-panel-delete', - uploadSignatureButton:'.action-upload-signature', + uploadSignatureButton: '.action-upload-signature', uploadDialog: 'form.upload-dialog', uploadDialogButton: '.action-upload', uploadDialogFileInput: 'form.upload-dialog input[type=file]', saveCertificateButton: 'button.action-primary' }; - var clickDeleteItem = function (that, promptText, element, url) { + var clickDeleteItem = function(that, promptText, element, url) { var requests = AjaxHelpers.requests(that), promptSpy = ViewHelpers.createPromptSpy(), notificationSpy = ViewHelpers.createNotificationSpy(); @@ -53,7 +53,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce ViewHelpers.verifyPromptShowing(promptSpy, promptText); ViewHelpers.confirmPrompt(promptSpy); ViewHelpers.verifyPromptHidden(promptSpy); - if (!_.isUndefined(url) && !_.isEmpty(url)){ + if (!_.isUndefined(url) && !_.isEmpty(url)) { AjaxHelpers.expectJsonRequest(requests, 'POST', url); expect(_.last(requests).requestHeaders['X-HTTP-Method-Override']).toBe('DELETE'); ViewHelpers.verifyNotificationShowing(notificationSpy, /Deleting/); @@ -62,7 +62,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce } }; - var showConfirmPromptAndClickCancel = function (view, element, promptText) { + var showConfirmPromptAndClickCancel = function(view, element, promptText) { var promptSpy = ViewHelpers.createPromptSpy(); view.$(element).click(); ViewHelpers.verifyPromptShowing(promptSpy, promptText); @@ -70,15 +70,15 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce ViewHelpers.verifyPromptHidden(promptSpy); }; - var uploadFile = function (file_path, requests){ + var uploadFile = function(file_path, requests) { $(SELECTORS.uploadDialogFileInput).change(); $(SELECTORS.uploadDialogButton).click(); AjaxHelpers.respondWithJson(requests, {asset: {url: file_path}}); }; describe('Certificate editor view', function() { - var setValuesToInputs = function (view, values) { - _.each(values, function (value, selector) { + var setValuesToInputs = function(view, values) { + _.each(values, function(value, selector) { if (SELECTORS[selector]) { view.$(SELECTORS[selector]).val(value); view.$(SELECTORS[selector]).trigger('change'); @@ -86,8 +86,8 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce }); }; var basicModalTpl = readFixtures('basic-modal.underscore'), - modalButtonTpl = readFixtures('modal-button.underscore'), - uploadDialogTpl = readFixtures('upload-dialog.underscore'); + modalButtonTpl = readFixtures('modal-button.underscore'), + uploadDialogTpl = readFixtures('upload-dialog.underscore'); beforeEach(function() { TemplateHelpers.installTemplates(['certificate-editor', 'signatory-editor'], true); @@ -110,8 +110,8 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce }, this.newModelOptions); - this.collection = new CertificatesCollection([ this.model ], { - certificateUrl: '/certificates/'+ window.course.id + this.collection = new CertificatesCollection([this.model], { + certificateUrl: '/certificates/' + window.course.id }); this.model.set('id', 0); this.view = new CertificateEditorView({ @@ -119,7 +119,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce max_signatories_limit: MAX_SIGNATORIES_LIMIT }); appendSetFixtures(this.view.render().el); - CustomMatchers(); // jshint ignore:line + CustomMatchers(); }); afterEach(function() { @@ -127,20 +127,20 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce delete window.CMS.User; }); - describe('Basic', function () { - beforeEach(function(){ + describe('Basic', function() { + beforeEach(function() { appendSetFixtures( - $(""); - } else if (kind === "url") { + } else if (mimetype === 'application/javascript') { + if (kind === 'text') { + head.append(''); + } else if (kind === 'url') { return ViewUtils.loadJavaScript(data); } - } else if (mimetype === "text/html") { - if (placement === "head") { + } else if (mimetype === 'text/html') { + if (placement === 'head') { head.append(data); } } @@ -224,10 +224,10 @@ define(["jquery", "underscore", "common/js/components/utils/view_utils", "js/vie }, fireNotificationActionEvent: function(event) { - var eventName = $(event.currentTarget).data("notification-action"); + var eventName = $(event.currentTarget).data('notification-action'); if (eventName) { event.preventDefault(); - this.notifyRuntime(eventName, this.model.get("id")); + this.notifyRuntime(eventName, this.model.get('id')); } } }); diff --git a/cms/static/js/views/xblock_editor.js b/cms/static/js/views/xblock_editor.js index e549fa6b54..e2a52672ea 100644 --- a/cms/static/js/views/xblock_editor.js +++ b/cms/static/js/views/xblock_editor.js @@ -2,10 +2,9 @@ * XBlockEditorView displays the authoring view of an xblock, and allows the user to switch between * the available modes. */ -define(["jquery", "underscore", "gettext", "js/views/xblock", "js/views/metadata", "js/collections/metadata", - "jquery.inputnumber"], - function ($, _, gettext, XBlockView, MetadataView, MetadataCollection) { - +define(['jquery', 'underscore', 'gettext', 'js/views/xblock', 'js/views/metadata', 'js/collections/metadata', + 'jquery.inputnumber'], + function($, _, gettext, XBlockView, MetadataView, MetadataCollection) { var XBlockEditorView = XBlockView.extend({ // takes XBlockInfo as a model @@ -40,8 +39,8 @@ define(["jquery", "underscore", "gettext", "js/views/xblock", "js/views/metadata getDefaultModes: function() { return [ - { id: 'editor', name: gettext("Editor")}, - { id: 'settings', name: gettext("Settings")} + {id: 'editor', name: gettext('Editor')}, + {id: 'settings', name: gettext('Settings')} ]; }, @@ -134,7 +133,7 @@ define(["jquery", "underscore", "gettext", "js/views/xblock", "js/views/metadata metadataNameElements = this.$('[data-metadata-name]'); for (i = 0; i < metadataNameElements.length; i++) { element = metadataNameElements[i]; - metadataName = $(element).data("metadata-name"); + metadataName = $(element).data('metadata-name'); metadata[metadataName] = element.value; } return metadata; diff --git a/cms/static/js/views/xblock_outline.js b/cms/static/js/views/xblock_outline.js index 2d4e04398d..6e58b1c67d 100644 --- a/cms/static/js/views/xblock_outline.js +++ b/cms/static/js/views/xblock_outline.js @@ -13,10 +13,9 @@ * - scroll_offset - the scroll offset to use for the locator being shown * - edit_display_name - true if the shown xblock's display name should be in inline edit mode */ -define(["jquery", "underscore", "gettext", "js/views/baseview", "common/js/components/utils/view_utils", - "js/views/utils/xblock_utils", "js/views/xblock_string_field_editor"], +define(['jquery', 'underscore', 'gettext', 'js/views/baseview', 'common/js/components/utils/view_utils', + 'js/views/utils/xblock_utils', 'js/views/xblock_string_field_editor'], function($, _, gettext, BaseView, ViewUtils, XBlockViewUtils, XBlockStringFieldEditor) { - var XBlockOutlineView = BaseView.extend({ // takes XBlockInfo as a model @@ -49,7 +48,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "common/js/compo // need to add the current model's id/locator to the set of expanded locators if (this.model.get('is_header_visible') !== null && !this.model.get('is_header_visible')) { var locator = this.model.get('id'); - if(!_.isUndefined(this.expandedLocators) && !this.expandedLocators.contains(locator)) { + if (!_.isUndefined(this.expandedLocators) && !this.expandedLocators.contains(locator)) { this.expandedLocators.add(locator); this.refresh(); } @@ -216,7 +215,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "common/js/compo onSync: function(event) { if (ViewUtils.hasChangedAttributes(this.model, ['visibility_state', 'child_info', 'display_name'])) { - this.onXBlockChange(); + this.onXBlockChange(); } }, @@ -246,7 +245,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "common/js/compo if (locatorElement.length > 0) { ViewUtils.setScrollOffset(locatorElement, scrollOffset); } else { - console.error("Failed to show item with locator " + locatorToShow + ""); + console.error('Failed to show item with locator ' + locatorToShow + ''); } if (editDisplayName) { locatorElement.find('> div[class$="header"] .xblock-field-value-edit').click(); diff --git a/cms/static/js/views/xblock_string_field_editor.js b/cms/static/js/views/xblock_string_field_editor.js index ad9de8fdaa..d9eeb14fce 100644 --- a/cms/static/js/views/xblock_string_field_editor.js +++ b/cms/static/js/views/xblock_string_field_editor.js @@ -5,9 +5,8 @@ * XBlock field's value if it has been changed. If the user presses Escape, then any changes will * be removed and the input hidden again. */ -define(["js/views/baseview", "js/views/utils/xblock_utils"], - function (BaseView, XBlockViewUtils) { - +define(['js/views/baseview', 'js/views/utils/xblock_utils'], + function(BaseView, XBlockViewUtils) { var XBlockStringFieldEditor = BaseView.extend({ events: { 'click .xblock-field-value-edit': 'showInput', @@ -42,7 +41,7 @@ define(["js/views/baseview", "js/views/utils/xblock_utils"], return this.$('.xblock-field-value'); }, - getInput: function () { + getInput: function() { return this.$('.xblock-field-input'); }, diff --git a/cms/static/js/views/xblock_validation.js b/cms/static/js/views/xblock_validation.js index 4733c30f9d..a0e6bcf010 100644 --- a/cms/static/js/views/xblock_validation.js +++ b/cms/static/js/views/xblock_validation.js @@ -1,5 +1,5 @@ -define(["jquery", "underscore", "js/views/baseview", "gettext"], - function ($, _, BaseView, gettext) { +define(['jquery', 'underscore', 'js/views/baseview', 'gettext'], + function($, _, BaseView, gettext) { /** * View for xblock validation messages as displayed in Studio. */ @@ -12,7 +12,7 @@ define(["jquery", "underscore", "js/views/baseview", "gettext"], this.root = options.root; }, - render: function () { + render: function() { this.$el.html(this.template({ validation: this.model, additionalClasses: this.getAdditionalClasses(), @@ -27,7 +27,7 @@ define(["jquery", "underscore", "js/views/baseview", "gettext"], * @param messageType * @returns string representation of css class that will render the correct icon, or null if unknown type */ - getIcon: function (messageType) { + getIcon: function(messageType) { if (messageType === this.model.ERROR) { return 'fa-exclamation-circle'; } @@ -42,16 +42,16 @@ define(["jquery", "underscore", "js/views/baseview", "gettext"], * @param messageType * @returns string display name (translated) */ - getDisplayName: function (messageType) { + getDisplayName: function(messageType) { if (messageType === this.model.WARNING || messageType === this.model.NOT_CONFIGURED) { // Translators: This message will be added to the front of messages of type warning, // e.g. "Warning: this component has not been configured yet". - return gettext("Warning"); + return gettext('Warning'); } else if (messageType === this.model.ERROR) { // Translators: This message will be added to the front of messages of type error, // e.g. "Error: required field is missing". - return gettext("Error"); + return gettext('Error'); } return null; }, @@ -62,13 +62,12 @@ define(["jquery", "underscore", "js/views/baseview", "gettext"], * * @returns string of additional css classes (or empty string) */ - getAdditionalClasses: function () { - if (this.root && this.model.get("summary").type === this.model.NOT_CONFIGURED && - this.model.get("messages").length === 0) { - - return "no-container-content"; + getAdditionalClasses: function() { + if (this.root && this.model.get('summary').type === this.model.NOT_CONFIGURED && + this.model.get('messages').length === 0) { + return 'no-container-content'; } - return ""; + return ''; } }); diff --git a/cms/static/js/xblock/authoring.js b/cms/static/js/xblock/authoring.js index d9abe7d6a6..ffeed552b9 100644 --- a/cms/static/js/xblock/authoring.js +++ b/cms/static/js/xblock/authoring.js @@ -21,7 +21,7 @@ // Cohort partitions (user is allowed to select more than one) element.find('.field-visibility-content-group input:checked').each(function(index, input) { - checkboxValues = $(input).val().split("-"); + checkboxValues = $(input).val().split('-'); partitionId = parseInt(checkboxValues[0], 10); groupId = parseInt(checkboxValues[1], 10); @@ -61,7 +61,7 @@ VisibilityEditorView.prototype.collectFieldData = function collectFieldData() { return { metadata: { - "group_access": this.getGroupAccess() + 'group_access': this.getGroupAccess() } }; }; diff --git a/cms/static/js/xblock_asides/structured_tags.js b/cms/static/js/xblock_asides/structured_tags.js index 2fe124e30a..40e6c3e0a8 100644 --- a/cms/static/js/xblock_asides/structured_tags.js +++ b/cms/static/js/xblock_asides/structured_tags.js @@ -2,10 +2,9 @@ 'use strict'; function StructuredTagsView(runtime, element) { - var $element = $(element); - $element.find("select").each(function() { + $element.find('select').each(function() { var loader = this; var sts = $(this).attr('structured-tags-select-init'); diff --git a/cms/static/karma_cms.conf.js b/cms/static/karma_cms.conf.js index f2ef478cd3..fefda5da29 100644 --- a/cms/static/karma_cms.conf.js +++ b/cms/static/karma_cms.conf.js @@ -1,8 +1,8 @@ +/* eslint-env node */ + // Karma config for cms suite. // Docs and troubleshooting tips in common/static/common/js/karma.common.conf.js -/* jshint node: true */ -/*jshint -W079 */ 'use strict'; var path = require('path'); var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js')); diff --git a/cms/static/karma_cms_squire.conf.js b/cms/static/karma_cms_squire.conf.js index a5c81fceae..d861dc99ca 100644 --- a/cms/static/karma_cms_squire.conf.js +++ b/cms/static/karma_cms_squire.conf.js @@ -1,8 +1,8 @@ +/* eslint-env node */ + // Karma config for cms-squire suite. // Docs and troubleshooting tips in common/static/common/js/karma.common.conf.js -/* jshint node: true */ -/*jshint -W079 */ 'use strict'; var path = require('path'); var configModule = require(path.join(__dirname, '../../common/static/common/js/karma.common.conf.js')); @@ -41,6 +41,6 @@ var options = { ] }; -module.exports = function (config) { +module.exports = function(config) { configModule.configure(config, options); }; diff --git a/cms/static/sass/_base-v2.scss b/cms/static/sass/_base-v2.scss index 14a6c676a1..bc2648872c 100644 --- a/cms/static/sass/_base-v2.scss +++ b/cms/static/sass/_base-v2.scss @@ -6,8 +6,8 @@ html { body { min-width: $fg-min-width; - background: $gray-l5; - color: $gray-d2; + background: $uxpl-grayscale-x-back; + color: $gray-d3; } footer.primary{ diff --git a/cms/static/sass/_base.scss b/cms/static/sass/_base.scss index d86b59869b..61a04afedc 100644 --- a/cms/static/sass/_base.scss +++ b/cms/static/sass/_base.scss @@ -28,8 +28,8 @@ html { body { @extend %t-copy-base; min-width: $fg-min-width; - background: $gray-l5; - color: $gray-d2; + background: $uxpl-grayscale-x-back; + color: $gray-d3; } body, input, button { diff --git a/cms/static/sass/elements-v2/_sock.scss b/cms/static/sass/elements-v2/_sock.scss index c34daf795a..97bab90b75 100644 --- a/cms/static/sass/elements-v2/_sock.scss +++ b/cms/static/sass/elements-v2/_sock.scss @@ -27,10 +27,10 @@ .cta-show-sock { @extend %ui-btn-pill; - background: $gray-l5; + background: $uxpl-grayscale-x-back; font-size: font-size(x-small); padding: ($baseline/2) $baseline; - color: $gray; + color: $gray-d3; .icon { @include margin-right($baseline/4); diff --git a/cms/static/sass/elements/_controls.scss b/cms/static/sass/elements/_controls.scss index 6cc33dd689..4b18144b8a 100644 --- a/cms/static/sass/elements/_controls.scss +++ b/cms/static/sass/elements/_controls.scss @@ -188,14 +188,47 @@ } } +// LMS-style CAPA button for consistency with LMS buttons +%btn-lms-style { + border: 1px solid $btn-lms-border; + border-radius: 3px; + box-shadow: inset 0 1px 0 0 $white; + color: $gray-d3; + display: inline-block; + font-size: inherit; + font-weight: bold; + background-color: $btn-lms-background; + background-image: -webkit-linear-gradient($btn-lms-background,$btn-lms-gradient); + background-image: linear-gradient($btn-lms-background,$btn-lms-gradient); + padding: 7px 18px; + text-decoration: none; + text-shadow: 0 1px 0 $btn-lms-shadow; + background-clip: padding-box; + font-size: 0.8125em; + + &:focus, + &:hover { + box-shadow: inset 0 1px 0 0 $btn-lms-shadow-hover; + cursor: pointer; + background-color: $btn-lms-background-hover; + background-image: -webkit-linear-gradient($btn-lms-background-hover,$btn-lms-gradient-hover); + background-image: linear-gradient($btn-lms-background-hover,$btn-lms-gradient-hover); + } + + &:active { + border: 1px solid $btn-lms-border; + box-shadow: inset 0 0 8px 4px $btn-lms-shadow-active,inset 0 0 8px 4px $btn-lms-shadow-active; + } +} + // +Button Element // ==================== .button { .icon { + @include margin-right($baseline/4); display: inline-block; vertical-align: middle; - margin-right: ($baseline/4); } } @@ -321,9 +354,9 @@ .ui-toggle-expansion { @include transition(all $tmg-f2 ease-in-out 0s); + @include margin-right($baseline/4); @extend %t-action1; display: inline-block; - margin-right: ($baseline/4); color: $gray-l3; vertical-align: middle; } diff --git a/cms/static/sass/elements/_footer.scss b/cms/static/sass/elements/_footer.scss index 76af72920d..c07d3ab8e6 100644 --- a/cms/static/sass/elements/_footer.scss +++ b/cms/static/sass/elements/_footer.scss @@ -14,7 +14,7 @@ min-width: $fg-min-width; width: flex-grid(12); margin: 0 auto; - color: $gray-l1; + color: $gray-d3; .footer-content-primary { @include clearfix(); diff --git a/cms/static/sass/elements/_system-help.scss b/cms/static/sass/elements/_system-help.scss index 5fc64575ca..6d3f04281d 100644 --- a/cms/static/sass/elements/_system-help.scss +++ b/cms/static/sass/elements/_system-help.scss @@ -280,7 +280,7 @@ .nav-item { @extend %wipe-last-child; margin-bottom: ($baseline/4); - border-bottom: 1px dotted $gray-l4; + border-bottom: 1px dotted $gray-l5; padding-bottom: ($baseline/4); } } diff --git a/cms/static/sass/elements/_xblocks.scss b/cms/static/sass/elements/_xblocks.scss index 61940d0b71..52109ded06 100644 --- a/cms/static/sass/elements/_xblocks.scss +++ b/cms/static/sass/elements/_xblocks.scss @@ -248,6 +248,15 @@ color: $color-visibility-set; } } + + .action { + + .save { + // taking styles from LMS for these Save buttons to maintain consistency + // there is no studio-specific style for these LMS-styled buttons + @extend %btn-lms-style; + } + } } // +Messaging - Xblocks diff --git a/cms/static/sass/partials/_variables.scss b/cms/static/sass/partials/_variables.scss index 746be35ea1..1bc0923178 100644 --- a/cms/static/sass/partials/_variables.scss +++ b/cms/static/sass/partials/_variables.scss @@ -41,11 +41,16 @@ $transparent: rgba(0,0,0,0); // used when color value is needed for UI width/tra // +Colors - UXPL new pattern library colors // ==================== -$uxpl-blue-base: rgba(0, 116, 180, 1); // wcag2a compliant -$uxpl-blue-hover-active: lighten($uxpl-blue-base, 7%); // wcag2a compliant +$uxpl-blue-base: rgb(0, 117, 180); // wcag2a compliant +$uxpl-blue-hover-active: rgb(41, 145, 195); // wcag2a compliant -$uxpl-green-base: rgba(0, 129, 0, 1); // wcag2a compliant -$uxpl-green-hover-active: lighten($uxpl-green-base, 7%); // wcag2a compliant +$uxpl-green-base: rgb(0, 129, 0); // wcag2a compliant +$uxpl-green-hover-active: rgb(0, 155, 0); // wcag2a compliant + +$uxpl-pink-base: rgb(194, 56, 125); // wcag2a compliant +$uxpl-pink-hover-active: lighten($uxpl-pink-base, 7%); // wcag2a compliant + +$uxpl-grayscale-x-back: rgb(245, 245, 245); // UXPL grayscale, x-back $uxpl-primary-accent: rgb(14, 166, 236); @@ -77,6 +82,17 @@ $gray-d2: shade($gray,40%); $gray-d3: shade($gray,60%); $gray-d4: shade($gray,80%); +// These define button styles similar to LMS +// The goal here is consistency (until we can overhaul all of this...) +$btn-lms-border: #d2c9c9; +$btn-lms-background: #f1f1f1; +$btn-lms-gradient: #d9d1d1; +$btn-lms-shadow: #fcfbfb; +$btn-lms-shadow-hover: #fefefe; +$btn-lms-background-hover: #e4e4e4; +$btn-lms-gradient-hover: #d1c9c9; +$btn-lms-shadow-active: #cac2c2; + $blue: rgb(0, 159, 230); $blue-l1: tint($blue,20%); $blue-l2: tint($blue,40%); diff --git a/cms/static/sass/programs/_components.scss b/cms/static/sass/programs/_components.scss index b59e018bb9..c14957880f 100644 --- a/cms/static/sass/programs/_components.scss +++ b/cms/static/sass/programs/_components.scss @@ -20,7 +20,7 @@ &:hover, &:focus, &:active { - color: palette(grayscale, black); + color: $black; } } @@ -42,7 +42,7 @@ &:focus, &.is-focused { background: shade($success, 33%); - color: $btn-default-focus-color; + color: palette(primary, accent); } // STATE: is pressed or active @@ -94,6 +94,6 @@ .form-group { &.bg-white { - background-color: palette(grayscale, white); + background-color: $white; } } diff --git a/cms/static/sass/programs/_modals.scss b/cms/static/sass/programs/_modals.scss index 890e609dcc..2e53637776 100644 --- a/cms/static/sass/programs/_modals.scss +++ b/cms/static/sass/programs/_modals.scss @@ -8,14 +8,14 @@ right: 0; bottom: 0; left: 0; - background-color: palette(grayscale-cool, x-dark); + background-color: palette(grayscale, dark); opacity: 0.5; z-index: 1000; } .modal-window { position: absolute; - background-color: palette(grayscale, black); + background-color: $black; width: 80%; left: 10%; top: 40%; @@ -25,15 +25,15 @@ .modal-content { margin: 5px; padding: 20px; - background-color: palette(grayscale-cool, x-dark); - border-top: 5px solid palette(warning, base); + background-color: palette(grayscale, dark); + border-top: 5px solid palette(warning, accent); .copy { - color: palette(grayscale, white); + color: $white; } .emphasized { - color: palette(grayscale, white-t); + color: $white; font-weight: font-weight(bold); } } @@ -42,18 +42,19 @@ padding: 10px 20px; .btn { - color: palette(grayscale, white-t); + color: palette(grayscale, back); } .btn-brand { - background: palette(warning, base); - border-color: palette(warning, base); + background: palette(warning, back); + color: palette(grayscale, dark); + border-color: palette(warning, accent); &:hover, &:focus, &:active { - background: palette(warning, dark); - border-color: palette(warning, dark);; + background: palette(warning, back); + border-color: palette(warning, accent); } } @@ -63,7 +64,7 @@ &:hover, &:focus, &:active { - border-color: palette(grayscale-cool, light) + border-color: palette(grayscale, back) } } } diff --git a/cms/static/sass/views/_dashboard.scss b/cms/static/sass/views/_dashboard.scss index a1614a9dc3..1473d8cd67 100644 --- a/cms/static/sass/views/_dashboard.scss +++ b/cms/static/sass/views/_dashboard.scss @@ -677,6 +677,14 @@ .new-course-run { width: 100%; } + .course-run-text-direction { + direction: ltr; + text-align: right; + } + + .placeholder-text-direction { + direction: rtl; + } .new-course-name { @extend %t-title5; diff --git a/cms/static/sass/views/_settings.scss b/cms/static/sass/views/_settings.scss index fe063fe1f6..40a1ec1226 100644 --- a/cms/static/sass/views/_settings.scss +++ b/cms/static/sass/views/_settings.scss @@ -522,7 +522,7 @@ .current-course-image { margin-bottom: ($baseline/2); padding: ($baseline/2) $baseline; - background: $gray-l5; + background: $gray-l6; text-align: center; .wrapper-course-image { @@ -941,7 +941,7 @@ @extend %t-copy-sub2; display: block; margin-top: ($baseline/2); - color: $gray-l3; + color: $gray-l5; } } diff --git a/cms/templates/darklang/preview_lang.html b/cms/templates/darklang/preview_lang.html new file mode 100644 index 0000000000..3b84513591 --- /dev/null +++ b/cms/templates/darklang/preview_lang.html @@ -0,0 +1,15 @@ +## Override the default styles_version to the Pattern Library version (version 2) +<%! main_css = "style-main-v2" %> +<%page expression_filter="h"/> +<%! +from django.utils.translation import ugettext as _ +%> + +<%inherit file="../base.html" /> +<%block name="title">${_("Preview Language Setting")} +<%block name="bodyclass">is-signedin pattern-library + +<%block name="content"> + <%include file="/darklang/preview_lang_include.html" /> + + diff --git a/cms/templates/js/content-visibility-editor.underscore b/cms/templates/js/content-visibility-editor.underscore index 4c1093461e..e80830ecd0 100644 --- a/cms/templates/js/content-visibility-editor.underscore +++ b/cms/templates/js/content-visibility-editor.underscore @@ -19,7 +19,8 @@
  • <%- gettext('Learners do not see the subsection in the course outline. The subsection is not included in grade calculations.') %>

  • @@ -27,7 +28,11 @@ <% if (hasExplicitStaffLock && !ancestorLocked) { %>

    - <%- gettext('Units inherit the visibility setting of the subsection they are in. If you make this subsection visible to learners, published units that were previously hidden also become visible. Only units that were explicitly hidden remain hidden regardless of the option you select for this subsection.') %> + <%- interpolate( + gettext('If you select an option other than "%(hide_label)s", after the subsection release date has passed, published units in this subsection will become available to learners unless units are explicitly hidden.'), + { hide_label: hide_label }, + true + ) %>

    <% } %> diff --git a/cms/templates/js/programs/program_creator_form.underscore b/cms/templates/js/programs/program_creator_form.underscore index 4fe47ce691..464d08046e 100644 --- a/cms/templates/js/programs/program_creator_form.underscore +++ b/cms/templates/js/programs/program_creator_form.underscore @@ -5,8 +5,8 @@
    diff --git a/cms/templates/maintenance/container.html b/cms/templates/maintenance/container.html index 0b6d22dc7f..c72f6b00e4 100644 --- a/cms/templates/maintenance/container.html +++ b/cms/templates/maintenance/container.html @@ -12,17 +12,22 @@ from openedx.core.djangolib.js_utils import js_escaped_string -<%block name="js_extra"> - - - <%block name="viewcontent">
    <%include file="_${view['slug']}.html"/> - <%block name="requirejs"> - require(["js/maintenance/${view['slug'] | n, js_escaped_string}"], function(MaintenanceFactory) { - MaintenanceFactory("${reverse(view['url']) | n, js_escaped_string}"); - }); -
    + +<%block name="header_extras"> +% for template_name in ["force-published-course-response"]: + +% endfor + + +<%block name="requirejs"> + require(["js/maintenance/${view['slug'] | n, js_escaped_string}"], function(MaintenanceFactory) { + MaintenanceFactory("${reverse(view['url']) | n, js_escaped_string}"); + }); + diff --git a/cms/templates/widgets/user_dropdown.html b/cms/templates/widgets/user_dropdown.html index d118a25c18..773c43d5e0 100644 --- a/cms/templates/widgets/user_dropdown.html +++ b/cms/templates/widgets/user_dropdown.html @@ -13,7 +13,7 @@ ${_("Currently signed in as:")} -
    - Fill Browser - + + diff --git a/common/lib/xmodule/xmodule/js/karma_runner.js b/common/lib/xmodule/xmodule/js/karma_runner.js index 8d416281b7..49da55b190 100644 --- a/common/lib/xmodule/xmodule/js/karma_runner.js +++ b/common/lib/xmodule/xmodule/js/karma_runner.js @@ -1,10 +1,11 @@ +/* eslint-env node */ + // overwrite the loaded method and manually start the karma after a delay // Somehow the code initialized in jQuery's onready doesn't get called before karma auto starts -/* jshint node: true */ 'use strict'; -window.__karma__.loaded = function () { - setTimeout(function () { +window.__karma__.loaded = function() { + setTimeout(function() { window.__karma__.start(); }, 1000); }; diff --git a/common/lib/xmodule/xmodule/js/karma_xmodule.conf.js b/common/lib/xmodule/xmodule/js/karma_xmodule.conf.js index 3f72dcb7b0..deffb00f63 100644 --- a/common/lib/xmodule/xmodule/js/karma_xmodule.conf.js +++ b/common/lib/xmodule/xmodule/js/karma_xmodule.conf.js @@ -1,9 +1,8 @@ +/* eslint-env node */ + // Karma config for xmodule suite. // Docs and troubleshooting tips in common/static/common/js/karma.common.conf.js -/* jshint node: true */ -/*jshint -W079 */ - 'use strict'; var path = require('path'); var configModule = require(path.join(__dirname, 'common_static/common/js/karma.common.conf.js')); @@ -50,7 +49,7 @@ var options = { {pattern: 'common_static/common/js/spec_helpers/jasmine-extensions.js', included: true}, {pattern: 'common_static/js/vendor/sinon-1.17.0.js', included: true}, - {pattern: 'spec/main_requirejs.js', included: true}, + {pattern: 'spec/main_requirejs.js', included: true} ], libraryFiles: [ @@ -79,6 +78,6 @@ var options = { ] }; -module.exports = function (config) { +module.exports = function(config) { configModule.configure(config, options); }; diff --git a/common/lib/xmodule/xmodule/js/spec/capa/imageinput_spec.js b/common/lib/xmodule/xmodule/js/spec/capa/imageinput_spec.js index b58eeb2f3b..770f7814fb 100644 --- a/common/lib/xmodule/xmodule/js/spec/capa/imageinput_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/capa/imageinput_spec.js @@ -5,11 +5,11 @@ * ~ Donald Knuth */ -(function ($, ImageInput, undefined) { - describe('ImageInput', function () { +(function($, ImageInput, undefined) { + describe('ImageInput', function() { var state; - beforeEach(function () { + beforeEach(function() { var el; loadFixtures('imageinput.html'); @@ -20,7 +20,7 @@ state = new ImageInput('12345'); }); - it('initialization', function () { + it('initialization', function() { // Check that object's properties are present, and that the DOM // elements they reference exist. expect(state.el).toBeDefined(); @@ -35,7 +35,7 @@ expect(state.el).toHandle('click'); }); - it('cross becomes visible after first click', function () { + it('cross becomes visible after first click', function() { expect(state.crossEl.css('visibility')).toBe('hidden'); state.el.click(); @@ -43,7 +43,7 @@ expect(state.crossEl.css('visibility')).toBe('visible'); }); - it('coordinates are updated [offsetX is set]', function () { + it('coordinates are updated [offsetX is set]', function() { var event, posX, posY, cssLeft, cssTop; // Set up of 'click' event. @@ -71,7 +71,7 @@ ); }); - it('coordinates are updated [offsetX is NOT set]', function () { + it('coordinates are updated [offsetX is NOT set]', function() { var offset = state.el.offset(), event, posX, posY, cssLeft, cssTop; diff --git a/common/lib/xmodule/xmodule/js/spec/collapsible_spec.js b/common/lib/xmodule/xmodule/js/spec/collapsible_spec.js index b942ee5088..31e24a9568 100644 --- a/common/lib/xmodule/xmodule/js/spec/collapsible_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/collapsible_spec.js @@ -1,21 +1,21 @@ -(function (undefined) { +(function(undefined) { 'use strict'; - describe('Collapsible', function () { + describe('Collapsible', function() { var el, html, html_custom, - initialize = function (template) { + initialize = function(template) { setFixtures(template); el = $('.collapsible'); Collapsible.setCollapsibles(el); }, - disableFx = function () { + disableFx = function() { $.fx.off = true; }, - enableFx = function () { + enableFx = function() { $.fx.off = false; }; - beforeEach(function () { + beforeEach(function() { html = '' + '
    ' + '
    shortform message
    ' + @@ -36,8 +36,8 @@ '
    '; }); - describe('setCollapsibles', function () { - it('Default container initialized correctly', function () { + describe('setCollapsibles', function() { + it('Default container initialized correctly', function() { initialize(html); expect(el.find('.shortform')).toContainElement('.full-top'); @@ -46,7 +46,7 @@ expect(el.find('.full')).toHandle('click'); }); - it('Custom container initialized correctly', function () { + it('Custom container initialized correctly', function() { initialize(html_custom); expect(el.find('.shortform-custom')).toContainElement('.full-custom'); @@ -56,8 +56,8 @@ }); }); - describe('toggleFull', function () { - var assertChanges = function (state, anchorsElClass, showText, hideText) { + describe('toggleFull', function() { + var assertChanges = function(state, anchorsElClass, showText, hideText) { var anchors, text; if (state == null) { @@ -76,20 +76,20 @@ text = hideText; } - $.each(anchors, function (index, el) { + $.each(anchors, function(index, el) { expect(el).toHaveText(text); }); }; - beforeEach(function () { + beforeEach(function() { disableFx(); }); - afterEach(function () { + afterEach(function() { enableFx(); }); - it('Default container', function () { + it('Default container', function() { var event; initialize(html); @@ -105,7 +105,7 @@ assertChanges('closed', 'full', 'See full output', 'Hide output'); }); - it('Custom container', function () { + it('Custom container', function() { var event; initialize(html_custom); diff --git a/common/lib/xmodule/xmodule/js/spec/helper.js b/common/lib/xmodule/xmodule/js/spec/helper.js index 1457c3e3db..d1fbb153dc 100644 --- a/common/lib/xmodule/xmodule/js/spec/helper.js +++ b/common/lib/xmodule/xmodule/js/spec/helper.js @@ -1,9 +1,9 @@ -(function () { +(function() { 'use strict'; var origAjax = $.ajax; var stubbedYT = { - Player: function () { + Player: function() { var Player = jasmine.createSpyObj( 'YT.Player', [ @@ -33,7 +33,7 @@ BUFFERING: 3, CUED: 5 }, - ready: function (f) { + ready: function(f) { return f(); } }; @@ -43,7 +43,7 @@ window.STATUS = window.YT.PlayerState; - window.onTouchBasedDevice = function () { + window.onTouchBasedDevice = function() { return navigator.userAgent.match(/iPhone|iPod|iPad/i); }; @@ -77,31 +77,31 @@ jasmine.stubbedMetadata = { '7tqY6eQzVhE': { - contentDetails : { + contentDetails: { id: '7tqY6eQzVhE', duration: 'PT5M0S' } }, 'cogebirgzzM': { - contentDetails : { + contentDetails: { id: 'cogebirgzzM', duration: 'PT3M20S' } }, 'abcdefghijkl': { - contentDetails : { + contentDetails: { id: 'abcdefghijkl', duration: 'PT6M40S' } }, bogus: { - contentDetails : { + contentDetails: { duration: 'PT1M40S' } } }; - jasmine.fireEvent = function (el, eventName) { + jasmine.fireEvent = function(el, eventName) { var event; if (document.createEvent) { @@ -123,20 +123,20 @@ jasmine.stubbedHtml5Speeds = ['0.75', '1.0', '1.25', '1.50']; - jasmine.stubRequests = function () { + jasmine.stubRequests = function() { var spy = $.ajax; if (!jasmine.isSpy($.ajax)) { spy = spyOn($, 'ajax'); } - return spy.and.callFake(function (settings) { + return spy.and.callFake(function(settings) { var match = settings.url .match(/googleapis\.com\/.+\/videos\/\?id=(.+)&part=contentDetails/), status, callCallback; if (match) { status = match[1].split('_'); if (status && status[0] === 'status') { - callCallback = function (callback) { + callCallback = function(callback) { callback.call(window, {}, status[1]); }; @@ -151,10 +151,10 @@ }); } else { return { - always: function (callback) { + always: function(callback) { return callback.call(window, {}, 'success'); }, - done: function (callback) { + done: function(callback) { return callback.call(window, {}, 'success'); } }; @@ -177,7 +177,7 @@ return; } else if (settings.url === '/save_user_state') { return {success: true}; - } else if(settings.url.match(new RegExp(jasmine.getFixtures().fixturesPath + ".+", 'g'))) { + } else if (settings.url.match(new RegExp(jasmine.getFixtures().fixturesPath + '.+', 'g'))) { return origAjax(settings); } else { $.ajax.and.callThrough(); @@ -196,9 +196,9 @@ // Stub window.Video.loadYouTubeIFrameAPI() window.Video.loadYouTubeIFrameAPI = jasmine.createSpy('window.Video.loadYouTubeIFrameAPI').and.returnValue( - function (scriptTag) { + function(scriptTag) { var event = document.createEvent('Event'); - if (fixture === "video.html") { + if (fixture === 'video.html') { event.initEvent('load', false, false); } else { event.initEvent('error', false, false); @@ -207,7 +207,7 @@ } ); - jasmine.initializePlayer = function (fixture, params) { + jasmine.initializePlayer = function(fixture, params) { var state; if (_.isString(fixture)) { @@ -235,7 +235,7 @@ jasmine.stubRequests(); state = new window.Video('#example'); - state.resizer = (function () { + state.resizer = (function() { var methods = [ 'align', 'alignByWidthOnly', @@ -251,7 +251,7 @@ reset: jasmine.createSpy().and.returnValue(obj) }; - $.each(methods, function (index, method) { + $.each(methods, function(index, method) { obj[method] = jasmine.createSpy(method).and.returnValue(obj); }); @@ -264,7 +264,7 @@ return state; }; - jasmine.initializePlayerYouTube = function (params) { + jasmine.initializePlayerYouTube = function(params) { // "video.html" contains HTML template for a YouTube video. return jasmine.initializePlayer('video.html', params); }; diff --git a/common/lib/xmodule/xmodule/js/spec/main_requirejs.js b/common/lib/xmodule/xmodule/js/spec/main_requirejs.js index 119d4e564f..fcf617490e 100644 --- a/common/lib/xmodule/xmodule/js/spec/main_requirejs.js +++ b/common/lib/xmodule/xmodule/js/spec/main_requirejs.js @@ -4,16 +4,16 @@ // into the optimized files. Therefore load these libraries through script tags and explicitly define them. // Note that when the optimizer executes this code, window will not be defined. if (window) { - var defineDependency = function (globalName, name, noShim) { + var defineDependency = function(globalName, name, noShim) { var getGlobalValue = function(name) { - var globalNamePath = name.split('.'), - result = window, - i; - for (i = 0; i < globalNamePath.length; i++) { - result = result[globalNamePath[i]]; - } - return result; - }, + var globalNamePath = name.split('.'), + result = window, + i; + for (i = 0; i < globalNamePath.length; i++) { + result = result[globalNamePath[i]]; + } + return result; + }, globalValue = getGlobalValue(globalName); if (globalValue) { if (noShim) { @@ -24,22 +24,22 @@ } } else { - console.error("Expected library to be included on page, but not found on window object: " + name); + console.error('Expected library to be included on page, but not found on window object: ' + name); } }; - defineDependency("jQuery", "jquery"); - defineDependency("jQuery", "jquery-migrate"); - defineDependency("_", "underscore"); + defineDependency('jQuery', 'jquery'); + defineDependency('jQuery', 'jquery-migrate'); + defineDependency('_', 'underscore'); } requirejs.config({ baseUrl: '/base/', paths: { - "moment": "common_static/js/vendor/moment.min", - "draggabilly": "common_static/js/vendor/draggabilly", + 'moment': 'common_static/js/vendor/moment.min', + 'draggabilly': 'common_static/js/vendor/draggabilly', 'edx-ui-toolkit': 'common_static/edx-ui-toolkit' }, - "moment": { - exports: "moment" + 'moment': { + exports: 'moment' } }); }).call(this, RequireJS.requirejs, RequireJS.define); diff --git a/common/lib/xmodule/xmodule/js/spec/split_test/staff_view_spec.js b/common/lib/xmodule/xmodule/js/spec/split_test/staff_view_spec.js index e357a7bc06..b221f4eef0 100644 --- a/common/lib/xmodule/xmodule/js/spec/split_test/staff_view_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/split_test/staff_view_spec.js @@ -13,7 +13,7 @@ describe('Tests for split_test staff view switching', function() { delete window.XBlock; }); - it("test that we have only one visible condition", function() { + it('test that we have only one visible condition', function() { var containers = elem.find('.split-test-child-container').length; var conditions_shown = elem.find('.split-test-child-container .condition-text').length; expect(containers).toEqual(1); @@ -21,17 +21,15 @@ describe('Tests for split_test staff view switching', function() { expect(XBlock.initializeBlocks).toHaveBeenCalled(); }); - it("test that the right child is visible when selected", function() { + it('test that the right child is visible when selected', function() { var groups = ['0', '1', '2']; - for(var i = 0; i < groups.length; i++) { + for (var i = 0; i < groups.length; i++) { var to_select = groups[i]; elem.find('.split-test-select').val(to_select).change(); var child_text = elem.find('.split-test-child-container .condition-text').text(); expect(child_text).toContain(to_select); expect(XBlock.initializeBlocks).toHaveBeenCalled(); } - }); - }); diff --git a/common/lib/xmodule/xmodule/js/spec/time_spec.js b/common/lib/xmodule/xmodule/js/spec/time_spec.js index 4790d87d8f..7044805ecb 100644 --- a/common/lib/xmodule/xmodule/js/spec/time_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/time_spec.js @@ -1,24 +1,24 @@ -(function (undefined) { +(function(undefined) { 'use strict'; - describe('Time', function () { - describe('format', function () { - describe('with NAN', function () { - it('return a correct time format', function () { + describe('Time', function() { + describe('format', function() { + describe('with NAN', function() { + it('return a correct time format', function() { expect(Time.format('string')).toEqual('0:00'); expect(Time.format(void(0))).toEqual('0:00'); }); }); - describe('with duration more than or equal to 1 hour', function () { - it('return a correct time format', function () { + describe('with duration more than or equal to 1 hour', function() { + it('return a correct time format', function() { expect(Time.format(3600)).toEqual('1:00:00'); expect(Time.format(7272)).toEqual('2:01:12'); }); }); - describe('with duration less than 1 hour', function () { - it('return a correct time format', function () { + describe('with duration less than 1 hour', function() { + it('return a correct time format', function() { expect(Time.format(1)).toEqual('0:01'); expect(Time.format(61)).toEqual('1:01'); expect(Time.format(3599)).toEqual('59:59'); @@ -26,17 +26,17 @@ }); }); - describe('formatFull', function () { - it('gives correct string for times', function () { + describe('formatFull', function() { + it('gives correct string for times', function() { var testTimes = [ - [0, '00:00:00'], [60, '00:01:00'], - [488, '00:08:08'], [2452, '00:40:52'], - [3600, '01:00:00'], [28800, '08:00:00'], + [0, '00:00:00'], [60, '00:01:00'], + [488, '00:08:08'], [2452, '00:40:52'], + [3600, '01:00:00'], [28800, '08:00:00'], [144532, '40:08:52'], [190360, '52:52:40'], - [294008, '81:40:08'], [-5, '00:00:00'] + [294008, '81:40:08'], [-5, '00:00:00'] ]; - $.each(testTimes, function (index, times) { + $.each(testTimes, function(index, times) { var timeInt = times[0], timeStr = times[1]; @@ -45,13 +45,12 @@ }); }); - describe('convert', function () { - it('return a correct time based on speed modifier', function () { + describe('convert', function() { + it('return a correct time based on speed modifier', function() { expect(Time.convert(0, 1, 1.5)).toEqual('0.000'); expect(Time.convert(100, 1, 1.5)).toEqual('66.667'); expect(Time.convert(100, 1.5, 1)).toEqual('150.000'); }); }); }); - }).call(this); diff --git a/common/lib/xmodule/xmodule/js/spec/video/async_process_spec.js b/common/lib/xmodule/xmodule/js/spec/video/async_process_spec.js index 7fb5bf97d8..917f501313 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/async_process_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/async_process_spec.js @@ -1,8 +1,8 @@ -(function (require) { -require( +(function(require) { + require( ['video/00_async_process.js'], -function (AsyncProcess) { - var getArrayNthLength = function (n, multiplier) { +function(AsyncProcess) { + var getArrayNthLength = function(n, multiplier) { var result = [], mul = multiplier || 1; @@ -14,65 +14,65 @@ function (AsyncProcess) { }, items = getArrayNthLength(1000); - describe('AsyncProcess', function () { - it ('Array is processed successfully', function (done) { + describe('AsyncProcess', function() { + it('Array is processed successfully', function(done) { var processedArray, expectedArray = getArrayNthLength(1000, 2), - process = function (item) { + process = function(item) { return 2 * item; }; - AsyncProcess.array(items, process).done(function (result) { + AsyncProcess.array(items, process).done(function(result) { processedArray = result; }); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return processedArray; - }).then(function () { + }).then(function() { expect(processedArray).toEqual(expectedArray); }).always(done); }); - it ('If non-array is passed, error callback is called', function (done) { + it('If non-array is passed, error callback is called', function(done) { var isError, - process = function () {}; + process = function() {}; - AsyncProcess.array('string', process).fail(function () { + AsyncProcess.array('string', process).fail(function() { isError = true; }); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return isError; - }).then(function () { + }).then(function() { expect(isError).toBeTruthy(); }).always(done); }); - it ('If an empty array is passed, returns initial array', function (done) { + it('If an empty array is passed, returns initial array', function(done) { var processedArray, - process = function () {}; + process = function() {}; - AsyncProcess.array([], process).done(function (result) { + AsyncProcess.array([], process).done(function(result) { processedArray = result; }); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return processedArray; - }).then(function () { + }).then(function() { expect(processedArray).toEqual([]); }).always(done); }); - it ('If no process function passed, returns initial array', function (done) { + it('If no process function passed, returns initial array', function(done) { var processedArray; - AsyncProcess.array(items).done(function (result) { + AsyncProcess.array(items).done(function(result) { processedArray = result; }); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return processedArray; - }).then(function () { + }).then(function() { expect(processedArray).toEqual(items); }).always(done); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/events_spec.js b/common/lib/xmodule/xmodule/js/spec/video/events_spec.js index 8f85970551..a93e762853 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/events_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/events_spec.js @@ -1,9 +1,9 @@ -(function (undefined) { - describe('VideoPlayer Events', function () { +(function(undefined) { + describe('VideoPlayer Events', function() { var state, oldOTBD; - describe('HTML5', function () { - beforeEach(function () { + describe('HTML5', function() { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice') @@ -14,53 +14,53 @@ state.videoEl = $('video, iframe'); }); - afterEach(function () { + afterEach(function() { $('source').remove(); window.onTouchBasedDevice = oldOTBD; state.storage.clear(); state.videoPlayer.destroy(); }); - it('initialize', function (done) { - jasmine.waitUntil(function () { + it('initialize', function(done) { + jasmine.waitUntil(function() { return state.el.hasClass('is-initialized'); - }).then(function () { + }).then(function() { expect('initialize').not.toHaveBeenTriggeredOn('.video'); }).always(done); }); - it('ready', function (done) { - jasmine.waitUntil(function () { + it('ready', function(done) { + jasmine.waitUntil(function() { return state.el.hasClass('is-initialized'); - }).then(function () { + }).then(function() { expect('ready').not.toHaveBeenTriggeredOn('.video'); }).always(done); }); - it('play', function () { + it('play', function() { state.videoPlayer.play(); expect('play').not.toHaveBeenTriggeredOn('.video'); }); - it('pause', function () { + it('pause', function() { state.videoPlayer.play(); state.videoPlayer.pause(); expect('pause').not.toHaveBeenTriggeredOn('.video'); }); - it('volumechange', function () { + it('volumechange', function() { state.videoPlayer.onVolumeChange(60); expect('volumechange').not.toHaveBeenTriggeredOn('.video'); }); - it('speedchange', function () { + it('speedchange', function() { state.videoPlayer.onSpeedChange('2.0'); expect('speedchange').not.toHaveBeenTriggeredOn('.video'); }); - it('seek', function () { + it('seek', function() { state.videoPlayer.onCaptionSeek({ time: 1, type: 'any' @@ -69,15 +69,15 @@ expect('seek').not.toHaveBeenTriggeredOn('.video'); }); - it('ended', function () { + it('ended', function() { state.videoPlayer.onEnded(); expect('ended').not.toHaveBeenTriggeredOn('.video'); }); }); - describe('YouTube', function () { - beforeEach(function () { + describe('YouTube', function() { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice') @@ -86,19 +86,18 @@ state = jasmine.initializePlayerYouTube(); }); - afterEach(function () { + afterEach(function() { $('source').remove(); window.onTouchBasedDevice = oldOTBD; state.storage.clear(); state.videoPlayer.destroy(); }); - it('qualitychange', function () { + it('qualitychange', function() { state.videoPlayer.onPlaybackQualityChange(); expect('qualitychange').not.toHaveBeenTriggeredOn('.video'); }); }); }); - }).call(this); diff --git a/common/lib/xmodule/xmodule/js/spec/video/general_spec.js b/common/lib/xmodule/xmodule/js/spec/video/general_spec.js index cc188d1c34..2392fffd65 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/general_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/general_spec.js @@ -1,40 +1,40 @@ -(function (undefined) { - describe('Video', function () { +(function(undefined) { + describe('Video', function() { var oldOTBD, state; - afterEach(function () { + afterEach(function() { $('source').remove(); window.VideoState = {}; window.VideoState.id = {}; window.YT = jasmine.YT; }); - describe('constructor', function () { - describe('YT', function () { - beforeEach(function () { + describe('constructor', function() { + describe('YT', function() { + beforeEach(function() { loadFixtures('video.html'); $.cookie.and.returnValue('0.50'); }); - describe('by default', function () { - beforeEach(function () { + describe('by default', function() { + beforeEach(function() { this.state = jasmine.initializePlayerYouTube('video_html5.html'); }); - afterEach(function () { + afterEach(function() { this.state.storage.clear(); this.state.videoPlayer.destroy(); }); - it('check videoType', function () { + it('check videoType', function() { expect(this.state.videoType).toEqual('youtube'); }); - it('set the elements', function () { + it('set the elements', function() { expect(this.state.el).toEqual($('#video_id')); }); - it('parse the videos', function () { + it('parse the videos', function() { expect(this.state.videos).toEqual({ '0.50': '7tqY6eQzVhE', '1.0': 'cogebirgzzM', @@ -42,49 +42,49 @@ }); }); - it('parse available video speeds', function () { + it('parse available video speeds', function() { expect(this.state.speeds).toEqual(['0.50', '1.0', '1.50']); }); - it('set current video speed via cookie', function () { + it('set current video speed via cookie', function() { expect(this.state.speed).toEqual('1.50'); }); }); }); - describe('HTML5', function () { + describe('HTML5', function() { var state; - beforeEach(function () { + beforeEach(function() { $.cookie.and.returnValue('0.75'); state = jasmine.initializePlayer('video_html5.html'); }); - afterEach(function () { + afterEach(function() { state.storage.clear(); state.videoPlayer.destroy(); }); - describe('by default', function () { - it('check videoType', function () { + describe('by default', function() { + it('check videoType', function() { expect(state.videoType).toEqual('html5'); }); - it('set the elements', function () { + it('set the elements', function() { expect(state.el).toEqual($('#video_id')); }); - it('doesn\'t have `videos` dictionary', function () { + it('doesn\'t have `videos` dictionary', function() { expect(state.videos).toBeUndefined(); }); - it('parse available video speeds', function () { + it('parse available video speeds', function() { var speeds = jasmine.stubbedHtml5Speeds; expect(state.speeds).toEqual(speeds); }); - it('set current video speed via cookie', function () { + it('set current video speed via cookie', function() { expect(state.speed).toEqual('1.50'); }); }); @@ -93,34 +93,34 @@ // handled by Require JS. When state.videoPlayer is created, // the stand alone HTML5 player object is already loaded, so no // further testing in that case is required. - describe('HTML5 API is available', function () { - it('create the Video Player', function () { + describe('HTML5 API is available', function() { + it('create the Video Player', function() { expect(state.videoPlayer.player).not.toBeUndefined(); }); }); }); }); - describe('YouTube API is not loaded', function () { + describe('YouTube API is not loaded', function() { var state; - beforeEach(function () { + beforeEach(function() { window.YT = undefined; state = jasmine.initializePlayerYouTube(); }); - afterEach(function () { + afterEach(function() { state.storage.clear(); state.videoPlayer.destroy(); }); - it('callback, to be called after YouTube API loads, exists and is called', function (done) { + it('callback, to be called after YouTube API loads, exists and is called', function(done) { window.YT = jasmine.YT; // Call the callback that must be called when YouTube API is // loaded. By specification. window.onYouTubeIframeAPIReady(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.youtubeApiAvailable === true; - }).done(function(){ + }).done(function() { // If YouTube API is not loaded, then the code will should create // a global callback that will be called by API once it is loaded. expect(window.onYouTubeIframeAPIReady).not.toBeUndefined(); @@ -128,7 +128,7 @@ }); }); - describe('checking start and end times', function () { + describe('checking start and end times', function() { var state; var miniTestSuite = [ { @@ -158,19 +158,19 @@ } ]; - afterEach(function () { + afterEach(function() { state.storage.clear(); state.videoPlayer.destroy(); }); - $.each(miniTestSuite, function (index, test) { + $.each(miniTestSuite, function(index, test) { itFabrique(test.itDescription, test.data, test.expectData); }); return; function itFabrique(itDescription, data, expectData) { - it(itDescription, function () { + it(itDescription, function() { state = jasmine.initializePlayer('video.html', { 'start': data.start, 'end': data.end @@ -183,10 +183,10 @@ }); // Disabled 11/25/13 due to flakiness in master - xdescribe('multiple YT on page', function () { + xdescribe('multiple YT on page', function() { var state1, state2, state3; - beforeEach(function () { + beforeEach(function() { loadFixtures('video_yt_multiple.html'); spyOn($, 'ajaxWithPrefix'); @@ -207,32 +207,32 @@ it( 'check for YT availability is performed only once', - function () + function() { - var numAjaxCalls = 0; + var numAjaxCalls = 0; // Total ajax calls made. - numAjaxCalls = $.ajax.calls.length; + numAjaxCalls = $.ajax.calls.length; // Subtract ajax calls to get captions via // state.videoCaption.fetchCaption() function. - numAjaxCalls -= $.ajaxWithPrefix.calls.length; + numAjaxCalls -= $.ajaxWithPrefix.calls.length; // Subtract ajax calls to get metadata for each video via // state.getVideoMetadata() function. - numAjaxCalls -= 3; + numAjaxCalls -= 3; // Subtract ajax calls to log event 'pause_video' via // state.videoPlayer.log() function. - numAjaxCalls -= 3; + numAjaxCalls -= 3; // This should leave just one call. It was made to check // for YT availability. This is done in state.initialize() // function. SPecifically, with the statement // // this.youtubeXhr = this.getVideoMetadata(); - expect(numAjaxCalls).toBe(1); - }); + expect(numAjaxCalls).toBe(1); + }); }); }); }).call(this); diff --git a/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js b/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js index be4929df27..05a57b9295 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/html5_video_spec.js @@ -1,16 +1,15 @@ -(function (undefined) { - describe('Video HTML5Video', function () { +(function(undefined) { + describe('Video HTML5Video', function() { var STATUS = window.STATUS; var state, oldOTBD, playbackRates = [0.75, 1.0, 1.25, 1.5]; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice').and.returnValue(null); - }); - afterEach(function () { + afterEach(function() { state.storage.clear(); state.videoPlayer.destroy(); $.fn.scrollTo.calls.reset(); @@ -18,70 +17,70 @@ window.onTouchBasedDevice = oldOTBD; }); - describe('on non-Touch devices', function () { - beforeEach(function () { + describe('on non-Touch devices', function() { + beforeEach(function() { state = jasmine.initializePlayer('video_html5.html'); state.videoPlayer.player.config.events.onReady = jasmine.createSpy('onReady'); }); - describe('events:', function () { - beforeEach(function () { + describe('events:', function() { + beforeEach(function() { spyOn(state.videoPlayer.player, 'callStateChangeCallback').and.callThrough(); }); - describe('[click]', function () { - describe('when player is paused', function () { - beforeEach(function () { + describe('[click]', function() { + describe('when player is paused', function() { + beforeEach(function() { spyOn(state.videoPlayer.player.video, 'play').and.callThrough(); state.videoPlayer.player.playerState = STATUS.PAUSED; $(state.videoPlayer.player.videoEl).trigger('click'); }); - it('native play event was called', function () { + it('native play event was called', function() { expect(state.videoPlayer.player.video.play).toHaveBeenCalled(); }); - it('player state was changed', function (done) { - jasmine.waitUntil(function () { + it('player state was changed', function(done) { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() === STATUS.PLAYING; }).always(done); }); // Flaky. Checking the parameters of calls to onStateChange() will likely be more reliable. - xit('callback was not called', function (done) { - jasmine.waitUntil(function () { + xit('callback was not called', function(done) { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED; - }).then(function () { + }).then(function() { expect(state.videoPlayer.player.callStateChangeCallback).not.toHaveBeenCalled(); }).always(done); }); }); - describe('[player is playing]', function () { - beforeEach(function () { + describe('[player is playing]', function() { + beforeEach(function() { spyOn(state.videoPlayer.player.video, 'pause').and.callThrough(); - state.videoPlayer.player.playerState = STATUS.PLAYING; + state.videoPlayer.player.playerState = STATUS.PLAYING; $(state.videoPlayer.player.videoEl).trigger('click'); }); - it('native event was called', function () { + it('native event was called', function() { expect(state.videoPlayer.player.video.pause).toHaveBeenCalled(); }); - it('player state was changed', function (done) { - jasmine.waitUntil(function () { + it('player state was changed', function(done) { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING; - }).then(function () { + }).then(function() { expect(state.videoPlayer.player.getPlayerState()) .toBe(STATUS.PAUSED); }).always(done); }); - it('callback was not called', function (done) { - jasmine.waitUntil(function () { + it('callback was not called', function(done) { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING; - }).then(function () { + }).then(function() { expect(state.videoPlayer.player.callStateChangeCallback) .not.toHaveBeenCalled(); }).always(done); @@ -89,82 +88,82 @@ }); }); - describe('[play]', function () { - beforeEach(function () { + describe('[play]', function() { + beforeEach(function() { spyOn(state.videoPlayer.player.video, 'play').and.callThrough(); state.videoPlayer.player.playerState = STATUS.PAUSED; state.videoPlayer.player.playVideo(); }); - it('native event was called', function () { + it('native event was called', function() { expect(state.videoPlayer.player.video.play).toHaveBeenCalled(); }); - it('player state was changed', function (done) { - jasmine.waitUntil(function () { + it('player state was changed', function(done) { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED; - }).then(function () { + }).then(function() { expect(state.videoPlayer.player.getPlayerState()) .toBe(STATUS.BUFFERING); }).always(done); }); - it('callback was called', function (done) { - jasmine.waitUntil(function () { + it('callback was called', function(done) { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() !== STATUS.PAUSED; - }).then(function () { + }).then(function() { expect(state.videoPlayer.player.callStateChangeCallback) .toHaveBeenCalled(); }).always(done); }); }); - describe('[pause]', function () { - beforeEach(function (done) { + describe('[pause]', function() { + beforeEach(function(done) { spyOn(state.videoPlayer.player.video, 'pause').and.callThrough(); state.videoPlayer.player.playerState = STATUS.UNSTARTED; state.videoPlayer.player.playVideo(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() !== STATUS.UNSTARTED; }).done(done); state.videoPlayer.player.pauseVideo(); }); - it('native event was called', function () { + it('native event was called', function() { expect(state.videoPlayer.player.video.pause).toHaveBeenCalled(); }); - it('player state was changed', function (done) { - jasmine.waitUntil(function () { + it('player state was changed', function(done) { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING; - }).then(function () { + }).then(function() { expect(state.videoPlayer.player.getPlayerState()) .toBe(STATUS.PAUSED); }).always(done); }); - it('callback was called', function (done) { - jasmine.waitUntil(function () { + it('callback was called', function(done) { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() !== STATUS.PLAYING; - }).then(function () { + }).then(function() { expect(state.videoPlayer.player.callStateChangeCallback) .toHaveBeenCalled(); }).always(done); }); }); - describe('[loadedmetadata]', function () { + describe('[loadedmetadata]', function() { it( 'player state was changed, start/end was defined, ' + - 'onReady called', function (done) + 'onReady called', function(done) { jasmine.fireEvent(state.videoPlayer.player.video, 'loadedmetadata'); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() !== STATUS.UNSTARTED; - }).then(function () { + }).then(function() { expect(state.videoPlayer.player.getPlayerState()) .toBe(STATUS.PAUSED); expect(state.videoPlayer.player.video.currentTime).toBe(0); @@ -174,20 +173,20 @@ }); }); - describe('[ended]', function () { - beforeEach(function (done) { + describe('[ended]', function() { + beforeEach(function(done) { state.videoPlayer.player.playVideo(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() !== STATUS.UNSTARTED; }).done(done); }); - it('player state was changed', function () { + it('player state was changed', function() { jasmine.fireEvent(state.videoPlayer.player.video, 'ended'); expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.ENDED); }); - it('callback was called', function () { + it('callback was called', function() { jasmine.fireEvent(state.videoPlayer.player.video, 'ended'); expect(state.videoPlayer.player.callStateChangeCallback) .toHaveBeenCalled(); @@ -195,23 +194,23 @@ }); }); - describe('methods', function () { + describe('methods', function() { var volume, seek, duration, playbackRate; - beforeEach(function () { + beforeEach(function() { volume = state.videoPlayer.player.video.volume; }); - it('pauseVideo', function () { + it('pauseVideo', function() { spyOn(state.videoPlayer.player.video, 'pause').and.callThrough(); state.videoPlayer.player.pauseVideo(); expect(state.videoPlayer.player.video.pause).toHaveBeenCalled(); }); - describe('seekTo', function () { - it('set new correct value', function (done) { + describe('seekTo', function() { + it('set new correct value', function(done) { state.videoPlayer.player.playVideo(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() === STATUS.PLAYING; }).then(function() { state.videoPlayer.player.seekTo(2); @@ -219,7 +218,7 @@ }).done(done); }); - it('set new inccorrect values', function () { + it('set new inccorrect values', function() { var seek = state.videoPlayer.player.video.currentTime; state.videoPlayer.player.seekTo(-50); expect(state.videoPlayer.player.getCurrentTime()).toBe(seek); @@ -230,13 +229,13 @@ }); }); - describe('setVolume', function () { - it('set new correct value', function () { + describe('setVolume', function() { + it('set new correct value', function() { state.videoPlayer.player.setVolume(50); expect(state.videoPlayer.player.getVolume()).toBe(50 * 0.01); }); - it('set new incorrect values', function () { + it('set new incorrect values', function() { state.videoPlayer.player.setVolume(-50); expect(state.videoPlayer.player.getVolume()).toBe(volume); state.videoPlayer.player.setVolume('5'); @@ -246,9 +245,9 @@ }); }); - it('getCurrentTime', function (done) { + it('getCurrentTime', function(done) { state.videoPlayer.player.playVideo(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() === STATUS.PLAYING; }).then(function() { state.videoPlayer.player.video.currentTime = 3; @@ -257,42 +256,42 @@ }).done(done); }); - it('playVideo', function () { + it('playVideo', function() { spyOn(state.videoPlayer.player.video, 'play').and.callThrough(); state.videoPlayer.player.playVideo(); expect(state.videoPlayer.player.video.play).toHaveBeenCalled(); }); - it('getPlayerState', function () { + it('getPlayerState', function() { state.videoPlayer.player.playerState = STATUS.PLAYING; expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.PLAYING); state.videoPlayer.player.playerState = STATUS.ENDED; expect(state.videoPlayer.player.getPlayerState()).toBe(STATUS.ENDED); }); - it('getVolume', function () { + it('getVolume', function() { volume = state.videoPlayer.player.video.volume = 0.5; expect(state.videoPlayer.player.getVolume()).toBe(volume); }); - it('getDuration', function (done) { + it('getDuration', function(done) { state.videoPlayer.player.playVideo(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() === STATUS.PLAYING; - }).then(function () { + }).then(function() { duration = state.videoPlayer.player.video.duration; expect(state.videoPlayer.player.getDuration()).toBe(duration); }).always(done); }); - describe('setPlaybackRate', function () { - it('set a correct value', function () { + describe('setPlaybackRate', function() { + it('set a correct value', function() { playbackRate = 1.5; state.videoPlayer.player.setPlaybackRate(playbackRate); expect(state.videoPlayer.player.video.playbackRate).toBe(playbackRate); }); - it('set NaN value', function () { + it('set NaN value', function() { var oldPlaybackRate = state.videoPlayer.player.video.playbackRate; // When we try setting the playback rate to some @@ -304,14 +303,14 @@ }); }); - it('getAvailablePlaybackRates', function () { + it('getAvailablePlaybackRates', function() { expect(state.videoPlayer.player.getAvailablePlaybackRates()) .toEqual(playbackRates); }); - it('_getLogs', function (done) { + it('_getLogs', function(done) { state.videoPlayer.player.playVideo(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoPlayer.player.getPlayerState() === STATUS.PLAYING; }).then(function() { var logs = state.videoPlayer.player._getLogs(); @@ -322,7 +321,7 @@ }); }); - it('native controls are used on iPhone', function () { + it('native controls are used on iPhone', function() { window.onTouchBasedDevice.and.returnValue(['iPhone']); state = jasmine.initializePlayer('video_html5.html'); diff --git a/common/lib/xmodule/xmodule/js/spec/video/initialize_spec.js b/common/lib/xmodule/xmodule/js/spec/video/initialize_spec.js index cc26892bd7..39715d9968 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/initialize_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/initialize_spec.js @@ -1,30 +1,29 @@ -(function (requirejs, require, define, undefined) { +(function(requirejs, require, define, undefined) { + 'use strict'; -'use strict'; - -require( + require( ['video/01_initialize.js'], -function (Initialize) { - describe('Initialize', function () { +function(Initialize) { + describe('Initialize', function() { var state = {}; - afterEach(function () { + afterEach(function() { state = {}; }); - describe('getCurrentLanguage', function () { + describe('getCurrentLanguage', function() { var msg; - beforeEach(function () { + beforeEach(function() { state.config = {}; state.config.transcriptLanguages = { 'de': 'German', 'en': 'English', - 'uk': 'Ukrainian', + 'uk': 'Ukrainian' }; }); - it ('returns current language', function () { + it('returns current language', function() { var expected; state.lang = 'de'; @@ -33,7 +32,7 @@ function (Initialize) { }); msg = 'returns `en`, if language isn\'t available for the video'; - it (msg, function () { + it(msg, function() { var expected; state.lang = 'zh'; @@ -43,19 +42,19 @@ function (Initialize) { msg = 'returns any available language, if current and `en` ' + 'languages aren\'t available for the video'; - it (msg, function () { + it(msg, function() { var expected; state.lang = 'zh'; state.config.transcriptLanguages = { 'de': 'German', - 'uk': 'Ukrainian', + 'uk': 'Ukrainian' }; expected = Initialize.prototype.getCurrentLanguage.call(state); expect(expected).toBe('uk'); }); - it ('returns `null`, if transcript unavailable', function () { + it('returns `null`, if transcript unavailable', function() { var expected; state.lang = 'zh'; @@ -65,8 +64,8 @@ function (Initialize) { }); }); - describe('getDuration', function () { - beforeEach(function () { + describe('getDuration', function() { + beforeEach(function() { state = { speed: '1.50', metadata: { @@ -87,7 +86,7 @@ function (Initialize) { }); var msg = 'returns duration for the 1.0 speed if speed is not 1.0'; - it(msg, function () { + it(msg, function() { var expected; state.speed = '1.50'; @@ -96,8 +95,8 @@ function (Initialize) { expect(expected).toEqual(400); }); - describe('Flash mode', function () { - it('returns duration for current video', function () { + describe('Flash mode', function() { + it('returns duration for current video', function() { var expected; state.isFlashMode.and.returnValue(true); @@ -107,7 +106,7 @@ function (Initialize) { }); var msg = 'returns duration for the 1.0 speed as a fall-back'; - it(msg, function () { + it(msg, function() { var expected; state.isFlashMode.and.returnValue(true); @@ -119,8 +118,8 @@ function (Initialize) { }); }); - describe('youtubeId', function () { - beforeEach(function () { + describe('youtubeId', function() { + beforeEach(function() { state = { speed: '1.50', videos: { @@ -132,8 +131,8 @@ function (Initialize) { }; }); - describe('with speed', function () { - it('return the video id for given speed', function () { + describe('with speed', function() { + it('return the video id for given speed', function() { $.each(state.videos, function(speed, videoId) { var expected = Initialize.prototype.youtubeId.call( state, speed @@ -144,8 +143,8 @@ function (Initialize) { }); }); - describe('without speed for flash mode', function () { - it('return the video id for current speed', function () { + describe('without speed for flash mode', function() { + it('return the video id for current speed', function() { var expected; state.isFlashMode.and.returnValue(true); @@ -155,16 +154,16 @@ function (Initialize) { }); }); - describe('without speed for youtube html5 mode', function () { - it('return the video id for 1.0x speed', function () { + describe('without speed for youtube html5 mode', function() { + it('return the video id for 1.0x speed', function() { var expected = Initialize.prototype.youtubeId.call(state); expect(expected).toEqual('cogebirgzzM'); }); }); - describe('speed is absent in the list of video speeds', function () { - it('return the video id for 1.0x speed', function () { + describe('speed is absent in the list of video speeds', function() { + it('return the video id for 1.0x speed', function() { var expected = Initialize.prototype.youtubeId.call(state, '0.0'); expect(expected).toEqual('cogebirgzzM'); @@ -172,16 +171,16 @@ function (Initialize) { }); }); - describe('setSpeed', function () { - describe('YT', function () { - beforeEach(function () { + describe('setSpeed', function() { + describe('YT', function() { + beforeEach(function() { state = { speeds: ['0.25', '0.50', '1.0', '1.50', '2.0'], storage: jasmine.createSpyObj('storage', ['setItem']) }; }); - it('check mapping', function () { + it('check mapping', function() { var map = { '0.75': '0.50', '1.25': '1.50' @@ -194,35 +193,35 @@ function (Initialize) { }); }); - describe('HTML5', function () { - beforeEach(function () { + describe('HTML5', function() { + beforeEach(function() { state = { speeds: ['0.75', '1.0', '1.25', '1.50'], storage: jasmine.createSpyObj('storage', ['setItem']) }; }); - describe('when new speed is available', function () { - beforeEach(function () { + describe('when new speed is available', function() { + beforeEach(function() { Initialize.prototype.setSpeed.call(state, '0.75'); }); - it('set new speed', function () { + it('set new speed', function() { expect(state.speed).toEqual('0.75'); }); }); - describe('when new speed is not available', function () { - beforeEach(function () { + describe('when new speed is not available', function() { + beforeEach(function() { Initialize.prototype.setSpeed.call(state, '1.75'); }); - it('set speed to 1.0x', function () { + it('set speed to 1.0x', function() { expect(state.speed).toEqual('1.0'); }); }); - it('check mapping', function () { + it('check mapping', function() { var map = { '0.25': '0.75', '0.50': '0.75', @@ -237,14 +236,14 @@ function (Initialize) { }); }); - describe('setPlayerMode', function () { - beforeEach(function () { + describe('setPlayerMode', function() { + beforeEach(function() { state = { - currentPlayerMode: 'flash', + currentPlayerMode: 'flash' }; }); - it('updates player mode', function () { + it('updates player mode', function() { var setPlayerMode = Initialize.prototype.setPlayerMode; setPlayerMode.call(state, 'html5'); @@ -253,7 +252,7 @@ function (Initialize) { expect(state.currentPlayerMode).toBe('flash'); }); - it('sets default mode if passed is not supported', function () { + it('sets default mode if passed is not supported', function() { var setPlayerMode = Initialize.prototype.setPlayerMode; setPlayerMode.call(state, '77html77'); @@ -261,14 +260,14 @@ function (Initialize) { }); }); - describe('getPlayerMode', function () { - beforeEach(function () { + describe('getPlayerMode', function() { + beforeEach(function() { state = { - currentPlayerMode: 'flash', + currentPlayerMode: 'flash' }; }); - it('returns current player mode', function () { + it('returns current player mode', function() { var getPlayerMode = Initialize.prototype.getPlayerMode, actual = getPlayerMode.call(state); @@ -276,10 +275,10 @@ function (Initialize) { }); }); - describe('isFlashMode', function () { - it('returns `true` if player in `flash` mode', function () { + describe('isFlashMode', function() { + it('returns `true` if player in `flash` mode', function() { var state = { - getPlayerMode: jasmine.createSpy().and.returnValue('flash'), + getPlayerMode: jasmine.createSpy().and.returnValue('flash') }, isFlashMode = Initialize.prototype.isFlashMode, actual = isFlashMode.call(state); @@ -287,9 +286,9 @@ function (Initialize) { expect(actual).toBeTruthy(); }); - it('returns `false` if player is not in `flash` mode', function () { + it('returns `false` if player is not in `flash` mode', function() { var state = { - getPlayerMode: jasmine.createSpy().and.returnValue('html5'), + getPlayerMode: jasmine.createSpy().and.returnValue('html5') }, isFlashMode = Initialize.prototype.isFlashMode, actual = isFlashMode.call(state); @@ -298,10 +297,10 @@ function (Initialize) { }); }); - describe('isHtml5Mode', function () { - it('returns `true` if player in `html5` mode', function () { + describe('isHtml5Mode', function() { + it('returns `true` if player in `html5` mode', function() { var state = { - getPlayerMode: jasmine.createSpy().and.returnValue('html5'), + getPlayerMode: jasmine.createSpy().and.returnValue('html5') }, isHtml5Mode = Initialize.prototype.isHtml5Mode, actual = isHtml5Mode.call(state); @@ -309,9 +308,9 @@ function (Initialize) { expect(actual).toBeTruthy(); }); - it('returns `false` if player is not in `html5` mode', function () { + it('returns `false` if player is not in `html5` mode', function() { var state = { - getPlayerMode: jasmine.createSpy().and.returnValue('flash'), + getPlayerMode: jasmine.createSpy().and.returnValue('flash') }, isHtml5Mode = Initialize.prototype.isHtml5Mode, actual = isHtml5Mode.call(state); @@ -321,5 +320,4 @@ function (Initialize) { }); }); }); - }(RequireJS.requirejs, RequireJS.require, RequireJS.define)); diff --git a/common/lib/xmodule/xmodule/js/spec/video/iterator_spec.js b/common/lib/xmodule/xmodule/js/spec/video/iterator_spec.js index ff724812ed..6d689f0544 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/iterator_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/iterator_spec.js @@ -1,8 +1,8 @@ -(function (require) { -require( +(function(require) { + require( ['video/00_iterator.js'], -function (Iterator) { - describe('Iterator', function () { +function(Iterator) { + describe('Iterator', function() { var list = ['a', 'b', 'c', 'd', 'e'], iterator; @@ -10,36 +10,36 @@ function (Iterator) { iterator = new Iterator(list); }); - it('size contains correct list length', function () { + it('size contains correct list length', function() { expect(iterator.size).toBe(list.length); expect(iterator.lastIndex).toBe(list.length - 1); }); - describe('next', function () { - describe('with passed `index`', function () { - it('returns next item in the list', function () { + describe('next', function() { + describe('with passed `index`', function() { + it('returns next item in the list', function() { expect(iterator.next(2)).toBe('d'); expect(iterator.next(0)).toBe('b'); }); - it('returns first item if index equal last item', function () { + it('returns first item if index equal last item', function() { expect(iterator.next(4)).toBe('a'); }); - it('returns next item if index is not valid', function () { + it('returns next item if index is not valid', function() { expect(iterator.next(-4)).toBe('b'); // index < 0 expect(iterator.next(100)).toBe('c'); // index > size expect(iterator.next('99')).toBe('d'); // incorrect Type }); }); - describe('without passed `index`', function () { - it('returns next item in the list', function () { + describe('without passed `index`', function() { + it('returns next item in the list', function() { expect(iterator.next()).toBe('b'); expect(iterator.next()).toBe('c'); }); - it('returns first item if index equal last item', function () { + it('returns first item if index equal last item', function() { expect(iterator.next()).toBe('b'); expect(iterator.next()).toBe('c'); expect(iterator.next()).toBe('d'); @@ -49,45 +49,45 @@ function (Iterator) { }); }); - describe('prev', function () { - describe('with passed `index`', function () { - it('returns previous item in the list', function () { + describe('prev', function() { + describe('with passed `index`', function() { + it('returns previous item in the list', function() { expect(iterator.prev(3)).toBe('c'); expect(iterator.prev(1)).toBe('a'); }); - it('returns last item if index equal first item', function () { + it('returns last item if index equal first item', function() { expect(iterator.prev(0)).toBe('e'); }); - it('returns previous item if index is not valid', function () { + it('returns previous item if index is not valid', function() { expect(iterator.prev(-4)).toBe('e'); // index < 0 expect(iterator.prev(100)).toBe('d'); // index > size expect(iterator.prev('99')).toBe('c'); // incorrect Type }); }); - describe('without passed `index`', function () { - it('returns previous item in the list', function () { + describe('without passed `index`', function() { + it('returns previous item in the list', function() { expect(iterator.prev()).toBe('e'); expect(iterator.prev()).toBe('d'); }); - it('returns last item if index equal first item', function () { + it('returns last item if index equal first item', function() { expect(iterator.prev()).toBe('e'); }); }); }); - it('returns last item in the list', function () { + it('returns last item in the list', function() { expect(iterator.last()).toBe('e'); }); - it('returns first item in the list', function () { + it('returns first item in the list', function() { expect(iterator.first()).toBe('a'); }); - it('isEnd works correctly', function () { + it('isEnd works correctly', function() { expect(iterator.isEnd()).toBeFalsy(); iterator.next(); // => index 1 expect(iterator.isEnd()).toBeFalsy(); diff --git a/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js b/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js index 23e149e824..83ec05db6b 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/resizer_spec.js @@ -1,26 +1,24 @@ -(function (requirejs, require, define, undefined) { - -require( +(function(requirejs, require, define, undefined) { + require( ['video/00_resizer.js'], -function (Resizer) { - - describe('Resizer', function () { +function(Resizer) { + describe('Resizer', function() { var html = [ '
    ', - '
    ', - 'Content', - '
    ', + 'Content', + '
    ', '' ].join(''), config, container, element; - beforeEach(function () { + beforeEach(function() { setFixtures(html); container = $('.rszr-wrapper'); @@ -34,13 +32,13 @@ function (Resizer) { }); it('When Initialize without required parameters, log message is shown', - function () { + function() { new Resizer({ }); expect(console.log).toHaveBeenCalled(); } ); - it('`alignByWidthOnly` works correctly', function () { + it('`alignByWidthOnly` works correctly', function() { var resizer = new Resizer(config).alignByWidthOnly(), expectedWidth = container.width(), realWidth = element.width(); @@ -48,7 +46,7 @@ function (Resizer) { expect(realWidth).toBe(expectedWidth); }); - it('`alignByHeightOnly` works correctly', function () { + it('`alignByHeightOnly` works correctly', function() { var resizer = new Resizer(config).alignByHeightOnly(), expectedHeight = container.height(), realHeight = element.height(); @@ -56,7 +54,7 @@ function (Resizer) { expect(realHeight).toBe(expectedHeight); }); - it('`align` works correctly', function () { + it('`align` works correctly', function() { var resizer = new Resizer(config).align(), expectedHeight = container.height(), realHeight = element.height(), @@ -71,10 +69,9 @@ function (Resizer) { realWidth = element.width(); expect(realWidth).toBe(expectedWidth); - }); - it('`setMode` works correctly', function () { + it('`setMode` works correctly', function() { var resizer = new Resizer(config).setMode('height'), expectedHeight = container.height(), realHeight = element.height(), @@ -91,7 +88,7 @@ function (Resizer) { expect(realWidth).toBe(expectedWidth); }); - it('`setElement` works correctly', function () { + it('`setElement` works correctly', function() { container.append('
    = speedEntries.length-1 ? + return speedEntries.eq(index >= speedEntries.length - 1 ? 0 : index + 1); }; - beforeEach(function () { + beforeEach(function() { state = jasmine.initializePlayer(); videoTracks = $('li.video-tracks'); container = videoTracks.children('div.a11y-menu-container'); @@ -104,7 +104,7 @@ spyOn($.fn, 'focus').and.callThrough(); }); - it('open/close the menu on mouseenter/mouseleave', function () { + it('open/close the menu on mouseenter/mouseleave', function() { container.mouseenter(); expect(container).toHaveClass('open'); container.mouseleave(); @@ -112,72 +112,72 @@ }); it('do not close the menu on mouseleave if a menu item has ' + - 'focus', function () { + 'focus', function() { // Open menu. Focus is on last menu item. container.trigger(keyPressEvent(KEY.ENTER)); container.mouseenter().mouseleave(); expect(container).toHaveClass('open'); }); - it('close the menu on click', function () { + it('close the menu on click', function() { container.mouseenter().click(); expect(container).not.toHaveClass('open'); }); - it('close the menu on outside click', function () { + it('close the menu on outside click', function() { container.trigger(keyPressEvent(KEY.ENTER)); $(window).click(); expect(container).not.toHaveClass('open'); }); - it('open the menu on ENTER keydown', function () { + it('open the menu on ENTER keydown', function() { container.trigger(keyPressEvent(KEY.ENTER)); expect(container).toHaveClass('open'); expect(menuItemsLinks.last().focus).toHaveBeenCalled(); }); - it('open the menu on SPACE keydown', function () { + it('open the menu on SPACE keydown', function() { container.trigger(keyPressEvent(KEY.SPACE)); expect(container).toHaveClass('open'); expect(menuItemsLinks.last().focus).toHaveBeenCalled(); }); - it('open the menu on UP keydown', function () { + it('open the menu on UP keydown', function() { container.trigger(keyPressEvent(KEY.UP)); expect(container).toHaveClass('open'); expect(menuItemsLinks.last().focus).toHaveBeenCalled(); }); - it('close the menu on ESCAPE keydown', function () { + it('close the menu on ESCAPE keydown', function() { container.trigger(keyPressEvent(KEY.ESCAPE)); expect(container).not.toHaveClass('open'); }); it('UP and DOWN keydown function as expected on menu items', - function () { + function() { // Iterate through list in both directions and check if // things wrap up correctly. - var lastEntry = menuItemsLinks.length-1, i; + var lastEntry = menuItemsLinks.length - 1, i; // First open menu - container.trigger(keyPressEvent(KEY.UP)); + container.trigger(keyPressEvent(KEY.UP)); // Iterate with UP key until we have looped. - for (i = lastEntry; i >= 0; i--) { - menuItemsLinks.eq(i).trigger(keyPressEvent(KEY.UP)); - } + for (i = lastEntry; i >= 0; i--) { + menuItemsLinks.eq(i).trigger(keyPressEvent(KEY.UP)); + } // Iterate with DOWN key until we have looped. - for (i = 0; i <= lastEntry; i++) { - menuItemsLinks.eq(i).trigger(keyPressEvent(KEY.DOWN)); - } + for (i = 0; i <= lastEntry; i++) { + menuItemsLinks.eq(i).trigger(keyPressEvent(KEY.DOWN)); + } // Test if each element has been called twice. - expect($.fn.focus.calls.count()) - .toEqual(2*menuItemsLinks.length+1); - }); + expect($.fn.focus.calls.count()) + .toEqual(2 * menuItemsLinks.length + 1); + }); - it('ESC keydown on menu item closes menu', function () { + it('ESC keydown on menu item closes menu', function() { // First open menu. Focus is on last speed entry. container.trigger(keyPressEvent(KEY.UP)); menuItemsLinks.last().trigger(keyPressEvent(KEY.ESCAPE)); @@ -189,12 +189,12 @@ }); it('ENTER keydown on menu item selects its data and closes menu', - function () { + function() { // First open menu. - container.trigger(keyPressEvent(KEY.UP)); + container.trigger(keyPressEvent(KEY.UP)); // Focus on '.txt' - menuItemsLinks.eq(0).focus(); - menuItemsLinks.eq(0).trigger(keyPressEvent(KEY.ENTER)); + menuItemsLinks.eq(0).focus(); + menuItemsLinks.eq(0).trigger(keyPressEvent(KEY.ENTER)); // Menu is closed, focus has been returned to container // and file format is '.txt'. @@ -204,15 +204,15 @@ .toHaveClass('active'); expect($('.speeds p.active')).toHaveHtml('1.50x'); */ - }); + }); it('SPACE keydown on menu item selects its data and closes menu', - function () { + function() { // First open menu. - container.trigger(keyPressEvent(KEY.UP)); + container.trigger(keyPressEvent(KEY.UP)); // Focus on '.txt' - menuItemsLinks.eq(0).focus(); - menuItemsLinks.eq(0).trigger(keyPressEvent(KEY.SPACE)); + menuItemsLinks.eq(0).focus(); + menuItemsLinks.eq(0).trigger(keyPressEvent(KEY.SPACE)); // Menu is closed, focus has been returned to container // and file format is '.txt'. @@ -222,11 +222,11 @@ .toHaveClass('active'); expect($('.speeds p.active')).toHaveHtml('1.50x'); */ - }); + }); // TO DO? No such behavior implemented. xit('TAB + SHIFT keydown on speed entry closes menu and gives ' + - 'focus to Play/Pause control', function () { + 'focus to Play/Pause control', function() { // First open menu. Focus is on last speed entry. speedControl.trigger(keyPressEvent(KEY.UP)); speedEntries.last().trigger(tabBackPressEvent()); @@ -239,7 +239,7 @@ // TO DO? No such behavior implemented. xit('TAB keydown on speed entry closes menu and gives focus ' + - 'to Volume control', function () { + 'to Volume control', function() { // First open menu. Focus is on last speed entry. speedControl.trigger(keyPressEvent(KEY.UP)); speedEntries.last().trigger(tabForwardPressEvent()); @@ -253,9 +253,9 @@ }); // TODO - xdescribe('change file format', function () { - describe('when new file format is not the same', function () { - beforeEach(function () { + xdescribe('change file format', function() { + describe('when new file format is not the same', function() { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoSpeedControl.setSpeed(1.0); spyOn(state.videoPlayer, 'onSpeedChange').and.callThrough(); @@ -263,7 +263,7 @@ $('li[data-speed="0.75"] .speed-link').click(); }); - it('trigger speedChange event', function () { + it('trigger speedChange event', function() { expect(state.videoPlayer.onSpeedChange).toHaveBeenCalled(); expect(state.videoSpeedControl.currentSpeed).toEqual(0.75); }); @@ -271,14 +271,14 @@ }); // TODO - xdescribe('onSpeedChange', function () { - beforeEach(function () { + xdescribe('onSpeedChange', function() { + beforeEach(function() { state = jasmine.initializePlayer(); $('li[data-speed="1.0"] .speed-link').addClass('active'); state.videoSpeedControl.setSpeed(0.75); }); - it('set the new speed as active', function () { + it('set the new speed as active', function() { expect($('.video_speeds li[data-speed="1.0"]')) .not.toHaveClass('active'); expect($('.video_speeds li[data-speed="0.75"]')) diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_bumper_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_bumper_spec.js index f6db02602d..badfb7b6ce 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_bumper_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_bumper_spec.js @@ -1,15 +1,15 @@ -(function (WAIT_TIMEOUT) { +(function(WAIT_TIMEOUT) { 'use strict'; - describe('VideoBumper', function () { + describe('VideoBumper', function() { var state, oldOTBD, waitForPlaying; - waitForPlaying = function (state, done) { - jasmine.waitUntil(function () { + waitForPlaying = function(state, done) { + jasmine.waitUntil(function() { return state.el.hasClass('is-playing'); }).done(done); }; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice').and.returnValue(null); @@ -18,7 +18,7 @@ jasmine.clock().install(); }); - afterEach(function () { + afterEach(function() { $('source').remove(); state.storage.clear(); if (state.bumperState && state.bumperState.videoPlayer) { @@ -31,39 +31,39 @@ jasmine.clock().uninstall(); }); - it('can render the bumper video', function () { + it('can render the bumper video', function() { expect($('.is-bumper')).toExist(); }); - it('can show the main video on error', function (done) { + it('can show the main video on error', function(done) { state.el.triggerHandler('error'); jasmine.clock().tick(20); expect($('.is-bumper')).not.toExist(); waitForPlaying(state, done); }); - it('can show the main video once bumper ends', function (done) { + it('can show the main video once bumper ends', function(done) { state.el.trigger('ended'); jasmine.clock().tick(20); expect($('.is-bumper')).not.toExist(); waitForPlaying(state, done); }); - it('can show the main video on skip', function (done) { + it('can show the main video on skip', function(done) { state.bumperState.videoBumper.skip(); jasmine.clock().tick(20); expect($('.is-bumper')).not.toExist(); waitForPlaying(state, done); }); - it('can stop the bumper video playing if it is too long', function (done) { + it('can stop the bumper video playing if it is too long', function(done) { state.el.trigger('timeupdate', [state.bumperState.videoBumper.maxBumperDuration + 1]); jasmine.clock().tick(20); expect($('.is-bumper')).not.toExist(); waitForPlaying(state, done); }); - it('can save appropriate states correctly on ended', function () { + it('can save appropriate states correctly on ended', function() { var saveState = jasmine.createSpy('saveState'); state.bumperState.videoSaveStatePlugin.saveState = saveState; state.el.trigger('ended'); @@ -72,7 +72,7 @@ bumper_last_view_date: true}); }); - it('can save appropriate states correctly on skip', function () { + it('can save appropriate states correctly on skip', function() { var saveState = jasmine.createSpy('saveState'); state.bumperState.videoSaveStatePlugin.saveState = saveState; state.bumperState.videoBumper.skip(); @@ -82,7 +82,7 @@ bumper_last_view_date: true}); }); - it('can save appropriate states correctly on error', function () { + it('can save appropriate states correctly on error', function() { var saveState = jasmine.createSpy('saveState'); state.bumperState.videoSaveStatePlugin.saveState = saveState; state.el.triggerHandler('error'); @@ -92,7 +92,7 @@ bumper_last_view_date: true}); }); - it('can save appropriate states correctly on skip and do not show again', function () { + it('can save appropriate states correctly on skip and do not show again', function() { var saveState = jasmine.createSpy('saveState'); state.bumperState.videoSaveStatePlugin.saveState = saveState; state.bumperState.videoBumper.skipAndDoNotShowAgain(); @@ -102,7 +102,7 @@ bumper_last_view_date: true, bumper_do_not_show_again: true}); }); - it('can destroy itself', function () { + it('can destroy itself', function() { state.bumperState.videoBumper.destroy(); expect(state.videoBumper).toBeUndefined(); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js index 5d85be2551..1ebff4a5fb 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js @@ -1,11 +1,11 @@ -(function (undefined) { - describe('VideoCaption', function () { +(function(undefined) { + describe('VideoCaption', function() { var state, oldOTBD; - var parseIntAttribute = function (element, attrName) { + var parseIntAttribute = function(element, attrName) { return parseInt(element.attr(attrName)); }; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') .and.returnValue(null); @@ -13,7 +13,7 @@ $.fn.scrollTo.calls.reset(); }); - afterEach(function () { + afterEach(function() { // `source` tags should be removed to avoid memory leak bug that we // had before. Removing of `source` tag, not `video` tag, stops // loading video source and clears the memory. @@ -25,22 +25,20 @@ window.onTouchBasedDevice = oldOTBD; }); - describe('constructor', function () { - - describe('always', function () { - - beforeEach(function () { + describe('constructor', function() { + describe('always', function() { + beforeEach(function() { spyOn($, 'ajaxWithPrefix').and.callThrough(); }); - it('create the transcript element', function () { + it('create the transcript element', function() { state = jasmine.initializePlayer(); expect($('.video')).toContainElement('.subtitles'); }); - + it('has appropriate lang attributes', function() { state = jasmine.initializePlayer(); - + $('.video .toggle-captions').trigger('click'); expect($('.video .subtitles-menu')).toHaveAttrs({ @@ -51,12 +49,12 @@ }); }); - it('add transcript control to video player', function () { + it('add transcript control to video player', function() { state = jasmine.initializePlayer(); expect($('.video')).toContainElement('.toggle-transcript'); }); - it('add ARIA attributes to transcript control', function () { + it('add ARIA attributes to transcript control', function() { state = jasmine.initializePlayer(); var captionControl = $('.toggle-transcript'); expect(captionControl).toHaveAttrs({ @@ -70,12 +68,12 @@ expect($('.video')).toContainElement('.closed-captions'); }); - it('fetch the transcript in HTML5 mode', function (done) { + it('fetch the transcript in HTML5 mode', function(done) { state = jasmine.initializePlayer(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoCaption.loaded; - }).then(function () { + }).then(function() { expect($.ajaxWithPrefix).toHaveBeenCalledWith({ url: '/transcript/translation/en', notifyOnError: false, @@ -88,14 +86,14 @@ }).always(done); }); - it('fetch the transcript in Flash mode', function (done) { + it('fetch the transcript in Flash mode', function(done) { state = jasmine.initializePlayerYouTube(); spyOn(state, 'isFlashMode').and.returnValue(true); state.videoCaption.fetchCaption(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoCaption.loaded; - }).then(function () { + }).then(function() { expect($.ajaxWithPrefix).toHaveBeenCalledWith({ url: '/transcript/translation/en', notifyOnError: false, @@ -110,12 +108,12 @@ }).always(done); }); - it('fetch the transcript in Youtube mode', function (done) { + it('fetch the transcript in Youtube mode', function(done) { state = jasmine.initializePlayerYouTube(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoCaption.loaded; - }).then(function () { + }).then(function() { expect($.ajaxWithPrefix).toHaveBeenCalledWith({ url: '/transcript/translation/en', notifyOnError: false, @@ -130,24 +128,23 @@ }).always(done); }); - it('bind the mouse movement', function () { + it('bind the mouse movement', function() { state = jasmine.initializePlayer(); expect($('.subtitles-menu')).toHandle('mouseover'); expect($('.subtitles-menu')).toHandle('mouseout'); expect($('.subtitles-menu')).toHandle('mousemove'); expect($('.subtitles-menu')).toHandle('mousewheel'); expect($('.subtitles-menu')).toHandle('DOMMouseScroll'); - }); + }); - it('bind the scroll', function () { + it('bind the scroll', function() { state = jasmine.initializePlayer(); expect($('.subtitles-menu')) .toHandleWith('scroll', state.videoControl.showControls); - }); - + }); }); - it('can destroy itself', function () { + it('can destroy itself', function() { spyOn($, 'ajaxWithPrefix'); state = jasmine.initializePlayer(); var plugin = state.videoCaption; @@ -169,13 +166,12 @@ }); describe('renderCaptions', function() { - describe('is rendered', function() { var KEY = $.ui.keyCode, - keyPressEvent = function(key) { - return $.Event('keydown', { keyCode: key }); - }; + keyPressEvent = function(key) { + return $.Event('keydown', {keyCode: key}); + }; it('toggles the captions on control click', function() { state = jasmine.initializePlayer(); @@ -215,16 +211,15 @@ }); }); - describe('renderLanguageMenu', function () { - - describe('is rendered', function () { + describe('renderLanguageMenu', function() { + describe('is rendered', function() { var KEY = $.ui.keyCode, - keyPressEvent = function(key) { - return $.Event('keydown', { keyCode: key }); - }; + keyPressEvent = function(key) { + return $.Event('keydown', {keyCode: key}); + }; - it('if languages more than 1', function () { + it('if languages more than 1', function() { state = jasmine.initializePlayer(); var transcripts = state.config.transcriptLanguages, langCodes = _.keys(transcripts), @@ -244,7 +239,7 @@ }); }); - it('when clicking on link with new language', function () { + it('when clicking on link with new language', function() { state = jasmine.initializePlayer(); var Caption = state.videoCaption, link = $('.langs-list li[data-lang-code="de"] .control-lang'); @@ -269,7 +264,7 @@ expect(link).toHaveAttr('aria-pressed', 'true'); }); - it('when clicking on link with current language', function () { + it('when clicking on link with current language', function() { state = jasmine.initializePlayer(); var Caption = state.videoCaption, link = $('.langs-list li[data-lang-code="en"] .control-lang'); @@ -288,7 +283,7 @@ expect(link).toHaveAttr('aria-pressed', 'true'); }); - it('open the language toggle on hover', function () { + it('open the language toggle on hover', function() { state = jasmine.initializePlayer(); $('.lang').mouseenter(); expect($('.lang')).toHaveClass('is-opened'); @@ -314,10 +309,10 @@ }); }); - describe('is not rendered', function () { - it('if just 1 language', function () { + describe('is not rendered', function() { + it('if just 1 language', function() { state = jasmine.initializePlayer(null, { - 'transcriptLanguages': {"en": "English"} + 'transcriptLanguages': {'en': 'English'} }); expect($('.langs-list')).not.toExist(); @@ -327,20 +322,20 @@ }); }); - describe('when on a non touch-based device', function () { - beforeEach(function (done) { + describe('when on a non touch-based device', function() { + beforeEach(function(done) { state = jasmine.initializePlayer(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoCaption.rendered; }).then(done); }); - it('render the transcript', function () { + it('render the transcript', function() { var captionsData = jasmine.stubbedCaption, - items = $('.subtitles li[data-index]'); + items = $('.subtitles li[data-index]'); - _.each(captionsData.text, function (text, index) { + _.each(captionsData.text, function(text, index) { var item = items.eq(index); expect(parseIntAttribute(item, 'data-index')).toEqual(index); @@ -350,7 +345,7 @@ }); }); - it('add a padding element to transcript', function () { + it('add a padding element to transcript', function() { expect($('.subtitles li:first').hasClass('spacing')) .toBe(true); expect($('.subtitles li:last').hasClass('spacing')) @@ -358,7 +353,7 @@ }); - it('bind all the transcript link', function () { + it('bind all the transcript link', function() { var handlerList = ['captionMouseOverOut', 'captionClick', 'captionMouseDown', 'captionFocus', 'captionBlur', 'captionKeyDown' @@ -368,68 +363,66 @@ spyOn(state.videoCaption, handler); }); $('.subtitles li[data-index]').each( - function (index, link) { + function(index, link) { + $(link).trigger('mouseover'); + expect(state.videoCaption.captionMouseOverOut).toHaveBeenCalled(); + state.videoCaption.captionMouseOverOut.calls.reset(); + $(link).trigger('mouseout'); + expect(state.videoCaption.captionMouseOverOut).toHaveBeenCalled(); - $(link).trigger('mouseover'); - expect(state.videoCaption.captionMouseOverOut).toHaveBeenCalled(); + $(this).click(); + expect(state.videoCaption.captionClick).toHaveBeenCalled(); - state.videoCaption.captionMouseOverOut.calls.reset(); - $(link).trigger('mouseout'); - expect(state.videoCaption.captionMouseOverOut).toHaveBeenCalled(); + $(this).trigger('mousedown'); + expect(state.videoCaption.captionMouseDown).toHaveBeenCalled(); - $(this).click(); - expect(state.videoCaption.captionClick).toHaveBeenCalled(); + $(this).trigger('focus'); + expect(state.videoCaption.captionFocus).toHaveBeenCalled(); - $(this).trigger('mousedown'); - expect(state.videoCaption.captionMouseDown).toHaveBeenCalled(); + $(this).trigger('blur'); + expect(state.videoCaption.captionBlur).toHaveBeenCalled(); - $(this).trigger('focus'); - expect(state.videoCaption.captionFocus).toHaveBeenCalled(); - - $(this).trigger('blur'); - expect(state.videoCaption.captionBlur).toHaveBeenCalled(); - - $(this).trigger('keydown'); - expect(state.videoCaption.captionKeyDown).toHaveBeenCalled(); - }); + $(this).trigger('keydown'); + expect(state.videoCaption.captionKeyDown).toHaveBeenCalled(); + }); }); - it('set rendered to true', function (done) { + it('set rendered to true', function(done) { state = jasmine.initializePlayer(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoCaption.rendered; - }).then(function () { + }).then(function() { expect(state.videoCaption.rendered).toBeTruthy(); }).always(done); }); }); - describe('when on a touch-based device', function () { - beforeEach(function () { + describe('when on a touch-based device', function() { + beforeEach(function() { window.onTouchBasedDevice.and.returnValue(['iPad']); state = jasmine.initializePlayer(); $.fn.scrollTo.calls.reset(); }); - it('show explanation message', function () { + it('show explanation message', function() { expect($('.subtitles .subtitles-menu li')).toHaveText( 'Transcript will be displayed when you start playing the video.' ); }); - it('show transcript on play', function (done) { + it('show transcript on play', function(done) { state.el.trigger('play'); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoCaption.rendered; - }).then(function () { + }).then(function() { var captionsData = jasmine.stubbedCaption, - items = $('.subtitles li[data-index]'); + items = $('.subtitles li[data-index]'); - _.each(captionsData.text, function (text, index) { + _.each(captionsData.text, function(text, index) { var item = items.eq(index); expect(parseIntAttribute(item, 'data-index')).toEqual(index); @@ -440,20 +433,20 @@ }).always(done); }); - it('does not set rendered to true', function () { + it('does not set rendered to true', function() { expect(state.videoCaption.rendered).toBeFalsy(); }); }); - describe('when no transcripts file was specified', function () { - beforeEach(function () { + describe('when no transcripts file was specified', function() { + beforeEach(function() { state = jasmine.initializePlayer('video_all.html', { 'sub': '', - 'transcriptLanguages': {}, + 'transcriptLanguages': {} }); }); - it('transcript panel is not shown', function () { + it('transcript panel is not shown', function() { expect(state.videoCaption.languageChooserEl).toBeHidden(); }); }); @@ -461,12 +454,12 @@ var originalClearTimeout; - describe('mouse movement', function () { - beforeEach(function (done) { + describe('mouse movement', function() { + beforeEach(function(done) { jasmine.clock().install(); state = jasmine.initializePlayer(); jasmine.clock().tick(50); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoCaption.rendered; }).then(done); @@ -475,19 +468,19 @@ window.clearTimeout = jasmine.createSpy().and.callFake(originalClearTimeout); }); - afterEach(function () { + afterEach(function() { window.clearTimeout = originalClearTimeout; jasmine.clock().uninstall(); }); - describe('when cursor is outside of the transcript box', function () { - it('does not set freezing timeout', function () { + describe('when cursor is outside of the transcript box', function() { + it('does not set freezing timeout', function() { expect(state.videoCaption.frozen).toBeFalsy(); }); }); - describe('when cursor is in the transcript box', function () { - beforeEach(function () { + describe('when cursor is in the transcript box', function() { + beforeEach(function() { spyOn(state.videoCaption, 'onMouseLeave'); $(window).trigger(jQuery.Event('mousemove')); jasmine.clock().tick(state.config.captionsFreezeTime); @@ -495,20 +488,20 @@ jasmine.clock().tick(state.config.captionsFreezeTime); }); - it('set the freezing timeout', function () { + it('set the freezing timeout', function() { expect(state.videoCaption.frozen).not.toBeFalsy(); expect(state.videoCaption.onMouseLeave).toHaveBeenCalled(); }); - describe('when the cursor is moving', function () { - it('reset the freezing timeout', function () { + describe('when the cursor is moving', function() { + it('reset the freezing timeout', function() { $('.subtitles-menu').trigger(jQuery.Event('mousemove')); expect(window.clearTimeout).toHaveBeenCalled(); }); }); - describe('when the mouse is scrolling', function () { - it('reset the freezing timeout', function () { + describe('when the mouse is scrolling', function() { + it('reset the freezing timeout', function() { $('.subtitles-menu').trigger(jQuery.Event('mousewheel')); expect(window.clearTimeout).toHaveBeenCalled(); }); @@ -517,57 +510,56 @@ describe( 'when cursor is moving out of the transcript box', - function () { - - beforeEach(function () { - state.videoCaption.frozen = 100; - $.fn.scrollTo.calls.reset(); - }); - - describe('always', function () { - beforeEach(function () { - $('.subtitles-menu').trigger(jQuery.Event('mouseout')); + function() { + beforeEach(function() { + state.videoCaption.frozen = 100; + $.fn.scrollTo.calls.reset(); }); - it('reset the freezing timeout', function () { - expect(window.clearTimeout).toHaveBeenCalledWith(100); + describe('always', function() { + beforeEach(function() { + $('.subtitles-menu').trigger(jQuery.Event('mouseout')); + }); + + it('reset the freezing timeout', function() { + expect(window.clearTimeout).toHaveBeenCalledWith(100); + }); + + it('unfreeze the transcript', function() { + expect(state.videoCaption.frozen).toBeNull(); + }); }); - it('unfreeze the transcript', function () { - expect(state.videoCaption.frozen).toBeNull(); - }); - }); - - describe('when the player is playing', function () { - beforeEach(function () { - state.videoCaption.playing = true; - $('.subtitles-menu li[data-index]:first') + describe('when the player is playing', function() { + beforeEach(function() { + state.videoCaption.playing = true; + $('.subtitles-menu li[data-index]:first') .addClass('current'); - $('.subtitles-menu').trigger(jQuery.Event('mouseout')); + $('.subtitles-menu').trigger(jQuery.Event('mouseout')); + }); + + it('scroll the transcript', function() { + expect($.fn.scrollTo).toHaveBeenCalled(); + }); }); - it('scroll the transcript', function () { - expect($.fn.scrollTo).toHaveBeenCalled(); + describe('when the player is not playing', function() { + beforeEach(function() { + state.videoCaption.playing = false; + $('.subtitles-menu').trigger(jQuery.Event('mouseout')); + }); + + it('does not scroll the transcript', function() { + expect($.fn.scrollTo).not.toHaveBeenCalled(); + }); }); }); - - describe('when the player is not playing', function () { - beforeEach(function () { - state.videoCaption.playing = false; - $('.subtitles-menu').trigger(jQuery.Event('mouseout')); - }); - - it('does not scroll the transcript', function () { - expect($.fn.scrollTo).not.toHaveBeenCalled(); - }); - }); - }); }); - describe('fetchCaption', function () { + describe('fetchCaption', function() { var Caption, msg; - beforeEach(function () { + beforeEach(function() { state = jasmine.initializePlayer(); Caption = state.videoCaption; spyOn($, 'ajaxWithPrefix').and.callThrough(); @@ -578,7 +570,7 @@ spyOn(state, 'youtubeId').and.returnValue('Z5KLxerq05Y'); }); - it('show transcript on language change', function () { + it('show transcript on language change', function() { Caption.loaded = true; Caption.fetchCaption(); @@ -588,7 +580,7 @@ msg = 'use cookie to show/hide transcripts if they have not been ' + 'loaded yet'; - it(msg, function () { + it(msg, function() { Caption.loaded = false; state.hide_captions = false; Caption.fetchCaption(); @@ -605,7 +597,7 @@ expect(Caption.hideCaptions).toHaveBeenCalledWith(true, false); }); - it('on success: on touch devices', function () { + it('on success: on touch devices', function() { state.isTouch = true; Caption.loaded = false; Caption.fetchCaption(); @@ -619,7 +611,7 @@ msg = 'on success: change language on touch devices when ' + 'transcripts have not been rendered yet'; - it(msg, function () { + it(msg, function() { state.isTouch = true; Caption.loaded = true; Caption.rendered = false; @@ -632,7 +624,7 @@ expect(Caption.loaded).toBeTruthy(); }); - it('on success: re-render on touch devices', function () { + it('on success: re-render on touch devices', function() { state.isTouch = true; Caption.loaded = true; Caption.rendered = true; @@ -645,7 +637,7 @@ expect(Caption.loaded).toBeTruthy(); }); - it('on success: rendered correct', function () { + it('on success: rendered correct', function() { Caption.loaded = false; Caption.fetchCaption(); @@ -656,7 +648,7 @@ expect(Caption.loaded).toBeTruthy(); }); - it('on success: re-rendered correct', function () { + it('on success: re-rendered correct', function() { Caption.loaded = true; Caption.rendered = true; Caption.fetchCaption(); @@ -669,9 +661,9 @@ }); msg = 'on error: transcripts are hidden if there are no transcripts'; - it(msg, function () { + it(msg, function() { spyOn(Caption, 'fetchAvailableTranslations'); - $.ajax.and.callFake(function (settings) { + $.ajax.and.callFake(function(settings) { _.result(settings, 'error'); }); @@ -687,10 +679,10 @@ msg = 'on error: for Html5 player an attempt to fetch transcript ' + 'with youtubeId if there are no additional transcripts'; - it(msg, function () { + it(msg, function() { spyOn(Caption, 'fetchAvailableTranslations'); spyOn(Caption, 'fetchCaption').and.callThrough(); - $.ajax.and.callFake(function (settings) { + $.ajax.and.callFake(function(settings) { _.result(settings, 'error'); }); @@ -701,7 +693,7 @@ expect(Caption.fetchAvailableTranslations).not.toHaveBeenCalled(); expect($.ajaxWithPrefix.calls.mostRecent().args[0].data) - .toEqual({'videoId':'Z5KLxerq05Y'}); + .toEqual({'videoId': 'Z5KLxerq05Y'}); expect(Caption.hideCaptions.calls.mostRecent().args) .toEqual([true, false]); expect(Caption.fetchCaption.calls.mostRecent().args[0]).toEqual(true); @@ -710,7 +702,7 @@ msg = 'on success: when fetchCaption called with fetch_with_youtubeId to ' + 'get transcript with youtubeId for html5'; - it(msg, function () { + it(msg, function() { spyOn(Caption, 'fetchAvailableTranslations'); spyOn(Caption, 'fetchCaption').and.callThrough(); @@ -722,7 +714,7 @@ expect(Caption.fetchAvailableTranslations).not.toHaveBeenCalled(); expect($.ajaxWithPrefix.calls.mostRecent().args[0].data) - .toEqual({'videoId':'Z5KLxerq05Y'}); + .toEqual({'videoId': 'Z5KLxerq05Y'}); expect(Caption.hideCaptions).toHaveBeenCalledWith(false); expect(Caption.fetchCaption.calls.mostRecent().args[0]).toEqual(true); expect(Caption.fetchCaption.calls.count()).toEqual(1); @@ -730,15 +722,15 @@ msg = 'on error: fetch available translations if there are ' + 'additional transcripts'; - it(msg, function () { + it(msg, function() { $.ajax - .and.callFake(function (settings) { + .and.callFake(function(settings) { _.result(settings, 'error'); }); state.config.transcriptLanguages = { 'en': 'English', - 'uk': 'Ukrainian', + 'uk': 'Ukrainian' }; spyOn(Caption, 'fetchAvailableTranslations'); @@ -749,10 +741,10 @@ }); }); - describe('fetchAvailableTranslations', function () { + describe('fetchAvailableTranslations', function() { var Caption, msg; - beforeEach(function () { + beforeEach(function() { state = jasmine.initializePlayer(); Caption = state.videoCaption; spyOn($, 'ajaxWithPrefix').and.callThrough(); @@ -761,7 +753,7 @@ spyOn(Caption, 'renderLanguageMenu'); }); - it('request created with correct parameters', function () { + it('request created with correct parameters', function() { Caption.fetchAvailableTranslations(); expect($.ajaxWithPrefix).toHaveBeenCalledWith({ @@ -773,7 +765,7 @@ }); msg = 'on succes: language menu is rendered if translations available'; - it(msg, function () { + it(msg, function() { state.config.transcriptLanguages = { 'en': 'English', 'uk': 'Ukrainian', @@ -794,7 +786,7 @@ }); msg = 'on succes: language menu isn\'t rendered if translations unavailable'; - it(msg, function () { + it(msg, function() { state.config.transcriptLanguages = { 'en': 'English', 'ru': 'Russian' @@ -808,8 +800,8 @@ }); msg = 'on error: transcripts are hidden if there are no transcript'; - it(msg, function () { - $.ajax.and.callFake(function (settings) { + it(msg, function() { + $.ajax.and.callFake(function(settings) { _.result(settings, 'error'); }); Caption.fetchAvailableTranslations(); @@ -820,73 +812,73 @@ }); }); - describe('play', function () { - describe('when the transcript was not rendered', function () { - beforeEach(function (done) { + describe('play', function() { + describe('when the transcript was not rendered', function() { + beforeEach(function(done) { window.onTouchBasedDevice.and.returnValue(['iPad']); state = jasmine.initializePlayer(); state.videoCaption.play(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoCaption.rendered; - }).then(function(){ + }).then(function() { done(); }); }); - it('render the transcript', function () { + it('render the transcript', function() { var captionsData; captionsData = jasmine.stubbedCaption; $('.subtitles li[data-index]').each( - function (index, item) { - expect(parseIntAttribute($(item), 'data-index')).toEqual(index); - expect(parseIntAttribute($(item), 'data-start')).toEqual(captionsData.start[index]); - expect($(item).attr('tabindex')).toEqual('0'); - expect($(item).text().trim()).toEqual(captionsData.text[index]); - }); + function(index, item) { + expect(parseIntAttribute($(item), 'data-index')).toEqual(index); + expect(parseIntAttribute($(item), 'data-start')).toEqual(captionsData.start[index]); + expect($(item).attr('tabindex')).toEqual('0'); + expect($(item).text().trim()).toEqual(captionsData.text[index]); + }); }); - it('add a padding element to transcript', function () { + it('add a padding element to transcript', function() { expect($('.subtitles li:first')).toHaveClass('spacing'); expect($('.subtitles li:last')).toHaveClass('spacing'); }); - it('set rendered to true', function () { + it('set rendered to true', function() { expect(state.videoCaption.rendered).toBeTruthy(); }); - it('set playing to true', function () { + it('set playing to true', function() { expect(state.videoCaption.playing).toBeTruthy(); }); }); }); - describe('pause', function () { - beforeEach(function () { + describe('pause', function() { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoCaption.playing = true; state.videoCaption.pause(); }); - it('set playing to false', function () { + it('set playing to false', function() { expect(state.videoCaption.playing).toBeFalsy(); }); }); - describe('updatePlayTime', function () { - beforeEach(function (done) { + describe('updatePlayTime', function() { + beforeEach(function(done) { state = jasmine.initializePlayer(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoCaption.rendered; }).then(done); }); - describe('when the video speed is 1.0x', function () { - it('search the caption based on time', function () { + describe('when the video speed is 1.0x', function() { + it('search the caption based on time', function() { state.videoCaption.updatePlayTime(25.000); expect(state.videoCaption.currentIndex).toEqual(5); @@ -898,8 +890,8 @@ }); }); - describe('when the video speed is not 1.0x', function () { - it('search the transcript based on 1.0x speed', function () { + describe('when the video speed is not 1.0x', function() { + it('search the transcript based on 1.0x speed', function() { state.videoCaption.updatePlayTime(25.000); expect(state.videoCaption.currentIndex).toEqual(5); @@ -918,34 +910,34 @@ }); }); - describe('when the index is not the same', function () { - beforeEach(function () { + describe('when the index is not the same', function() { + beforeEach(function() { state.videoCaption.currentIndex = 1; $('.subtitles li[data-index=5]').addClass('current'); state.videoCaption.updatePlayTime(25.000); }); - it('deactivate the previous transcript', function () { + it('deactivate the previous transcript', function() { expect($('.subtitles li[data-index=1]')) .not.toHaveClass('current'); }); - it('activate new transcript', function () { + it('activate new transcript', function() { expect($('.subtitles li[data-index=5]')) .toHaveClass('current'); }); - it('save new index', function () { + it('save new index', function() { expect(state.videoCaption.currentIndex).toEqual(5); }); - it('scroll transcript to new position', function () { + it('scroll transcript to new position', function() { expect($.fn.scrollTo).toHaveBeenCalled(); }); }); - describe('when the index is the same', function () { - it('does not change current subtitle', function () { + describe('when the index is the same', function() { + it('does not change current subtitle', function() { state.videoCaption.currentIndex = 1; $('.subtitles li[data-index=3]').addClass('current'); state.videoCaption.updatePlayTime(15.000); @@ -955,21 +947,21 @@ }); }); - describe('resize', function () { - beforeEach(function (done) { + describe('resize', function() { + beforeEach(function(done) { state = jasmine.initializePlayer(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoCaption.rendered; - }).then(function () { + }).then(function() { videoControl = state.videoControl; $('.subtitles li[data-index=1]').addClass('current'); state.videoCaption.onResize(); }).always(done); }); - describe('set the height of transcript container', function () { - it('when transcript button is enabled', function () { + describe('set the height of transcript container', function() { + it('when transcript button is enabled', function() { var realHeight = parseInt( $('.subtitles').css('maxHeight'), 10 ), @@ -980,7 +972,7 @@ expect(realHeight).toBeCloseTo(shouldBeHeight, 2); }); - it('when transcript button is disabled ', function () { + it('when transcript button is disabled ', function() { var realHeight, videoWrapperHeight, progressSliderHeight, controlHeight, shouldBeHeight; @@ -1001,7 +993,7 @@ }); }); - it('set the height of transcript spacing', function () { + it('set the height of transcript spacing', function() { var firstSpacing, lastSpacing; firstSpacing = Math.abs(parseInt( @@ -1017,25 +1009,25 @@ .toBeLessThan(1); }); - it('scroll transcript to new position', function () { + it('scroll transcript to new position', function() { expect($.fn.scrollTo).toHaveBeenCalled(); }); }); - xdescribe('scrollCaption', function () { - beforeEach(function () { - runs(function () { + xdescribe('scrollCaption', function() { + beforeEach(function() { + runs(function() { state = jasmine.initializePlayer(); }); - waitsFor(function () { + waitsFor(function() { return state.videoCaption.rendered; }, 'Transcripts are not rendered', WAIT_TIMEOUT); }); - describe('when frozen', function () { - it('does not scroll the transcript', function () { - runs(function () { + describe('when frozen', function() { + it('does not scroll the transcript', function() { + runs(function() { state.videoCaption.frozen = true; $('.subtitles li[data-index=1]').addClass('current'); state.videoCaption.scrollCaption(); @@ -1044,25 +1036,25 @@ }); }); - describe('when not frozen', function () { - beforeEach(function () { - runs(function () { + describe('when not frozen', function() { + beforeEach(function() { + runs(function() { state.videoCaption.frozen = false; }); }); - describe('when there is no current transcript', function () { - it('does not scroll the transcript', function () { - runs(function () { + describe('when there is no current transcript', function() { + it('does not scroll the transcript', function() { + runs(function() { state.videoCaption.scrollCaption(); expect($.fn.scrollTo).not.toHaveBeenCalled(); }); }); }); - describe('when there is a current transcript', function () { - it('scroll to current transcript', function () { - runs(function () { + describe('when there is a current transcript', function() { + it('scroll to current transcript', function() { + runs(function() { $('.subtitles li[data-index=1]').addClass('current'); state.videoCaption.scrollCaption(); expect($.fn.scrollTo).toHaveBeenCalled(); @@ -1072,13 +1064,13 @@ }); }); - xdescribe('seekPlayer', function () { - beforeEach(function () { - runs(function () { + xdescribe('seekPlayer', function() { + beforeEach(function() { + runs(function() { state = jasmine.initializePlayer(); }); - waitsFor(function () { + waitsFor(function() { var duration = state.videoPlayer.duration(), isRendered = state.videoCaption.rendered; @@ -1086,9 +1078,9 @@ }, 'Transcripts are not rendered', WAIT_TIMEOUT); }); - describe('when the video speed is 1.0x', function () { - it('trigger seek event with the correct time', function () { - runs(function () { + describe('when the video speed is 1.0x', function() { + it('trigger seek event with the correct time', function() { + runs(function() { state.videoSpeedControl.currentSpeed = '1.0'; $('.subtitles li[data-start="14910"]').trigger('click'); expect(state.videoPlayer.currentTime).toEqual(14.91); @@ -1096,9 +1088,9 @@ }); }); - describe('when the video speed is not 1.0x', function () { - it('trigger seek event with the correct time', function () { - runs(function () { + describe('when the video speed is not 1.0x', function() { + it('trigger seek event with the correct time', function() { + runs(function() { state.videoSpeedControl.currentSpeed = '0.75'; $('.subtitles li[data-start="14910"]').trigger('click'); expect(state.videoPlayer.currentTime).toEqual(14.91); @@ -1107,52 +1099,52 @@ }); describe('when the player type is Flash at speed 0.75x', - function () { - it('trigger seek event with the correct time', function () { - runs(function () { - state.videoSpeedControl.currentSpeed = '0.75'; - state.currentPlayerMode = 'flash'; - $('.subtitles li[data-start="14910"]').trigger('click'); - expect(state.videoPlayer.currentTime).toEqual(15); + function() { + it('trigger seek event with the correct time', function() { + runs(function() { + state.videoSpeedControl.currentSpeed = '0.75'; + state.currentPlayerMode = 'flash'; + $('.subtitles li[data-start="14910"]').trigger('click'); + expect(state.videoPlayer.currentTime).toEqual(15); + }); }); }); - }); }); - describe('toggle', function () { - beforeEach(function () { + describe('toggle', function() { + beforeEach(function() { state = jasmine.initializePlayer(); $('.subtitles li[data-index=1]').addClass('current'); }); - describe('when the transcript is visible', function () { - beforeEach(function () { + describe('when the transcript is visible', function() { + beforeEach(function() { state.el.removeClass('closed'); state.videoCaption.toggle(jQuery.Event('click')); }); - it('hide the transcript', function () { + it('hide the transcript', function() { expect(state.el).toHaveClass('closed'); }); }); - describe('when the transcript is hidden', function () { - beforeEach(function () { + describe('when the transcript is hidden', function() { + beforeEach(function() { state.el.addClass('closed'); state.videoCaption.toggle(jQuery.Event('click')); jasmine.clock().install(); }); - afterEach(function () { + afterEach(function() { jasmine.clock().uninstall(); }); - it('show the transcript', function () { + it('show the transcript', function() { expect(state.el).not.toHaveClass('closed'); }); // Test turned off due to flakiness (11/25/13) - xit('scroll the transcript', function () { + xit('scroll the transcript', function() { // After transcripts are shown, and the video plays for a // bit. jasmine.clock().tick(1000); @@ -1161,53 +1153,53 @@ // position. When they advance, the list scrolls. The // current transcript position should be constantly // visible. - runs(function () { + runs(function() { expect($.fn.scrollTo).toHaveBeenCalled(); }); }); }); }); - describe('transcript accessibility', function () { - beforeEach(function (done) { + describe('transcript accessibility', function() { + beforeEach(function(done) { state = jasmine.initializePlayer(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.videoCaption.rendered; }).then(done); }); - describe('when getting focus through TAB key', function () { - beforeEach(function () { + describe('when getting focus through TAB key', function() { + beforeEach(function() { state.videoCaption.isMouseFocus = false; $('.subtitles li[data-index=0]').trigger( jQuery.Event('focus') ); }); - it('shows an outline around the transcript', function () { + it('shows an outline around the transcript', function() { expect($('.subtitles li[data-index=0]')) .toHaveClass('focused'); }); - it('has automatic scrolling disabled', function () { + it('has automatic scrolling disabled', function() { expect(state.videoCaption.autoScrolling).toBe(false); }); }); - describe('when loosing focus through TAB key', function () { - beforeEach(function () { + describe('when loosing focus through TAB key', function() { + beforeEach(function() { $('.subtitles li[data-index=0]').trigger( jQuery.Event('blur') ); }); - it('does not show an outline around the transcript', function () { + it('does not show an outline around the transcript', function() { expect($('.subtitles li[data-index=0]')) .not.toHaveClass('focused'); }); - it('has automatic scrolling enabled', function () { + it('has automatic scrolling enabled', function() { expect(state.videoCaption.autoScrolling).toBe(true); }); }); @@ -1215,60 +1207,57 @@ describe( 'when same transcript gets the focus through mouse after ' + 'having focus through TAB key', - function () { - - beforeEach(function () { - state.videoCaption.isMouseFocus = false; - $('.subtitles li[data-index=0]') + function() { + beforeEach(function() { + state.videoCaption.isMouseFocus = false; + $('.subtitles li[data-index=0]') .trigger(jQuery.Event('focus')); - $('.subtitles li[data-index=0]') + $('.subtitles li[data-index=0]') .trigger(jQuery.Event('mousedown')); - }); + }); - it('does not show an outline around it', function () { - expect($('.subtitles li[data-index=0]')) + it('does not show an outline around it', function() { + expect($('.subtitles li[data-index=0]')) .not.toHaveClass('focused'); - }); + }); - it('has automatic scrolling enabled', function () { - expect(state.videoCaption.autoScrolling).toBe(true); + it('has automatic scrolling enabled', function() { + expect(state.videoCaption.autoScrolling).toBe(true); + }); }); - }); describe( 'when a second transcript gets focus through mouse after ' + 'first had focus through TAB key', - function () { + function() { + var subDataLiIdx__0, subDataLiIdx__1; - var subDataLiIdx__0, subDataLiIdx__1; + beforeEach(function() { + subDataLiIdx__0 = $('.subtitles li[data-index=0]'); + subDataLiIdx__1 = $('.subtitles li[data-index=1]'); - beforeEach(function () { - subDataLiIdx__0 = $('.subtitles li[data-index=0]'); - subDataLiIdx__1 = $('.subtitles li[data-index=1]'); + state.videoCaption.isMouseFocus = false; - state.videoCaption.isMouseFocus = false; + subDataLiIdx__0.trigger(jQuery.Event('focus')); + subDataLiIdx__0.trigger(jQuery.Event('blur')); - subDataLiIdx__0.trigger(jQuery.Event('focus')); - subDataLiIdx__0.trigger(jQuery.Event('blur')); + state.videoCaption.isMouseFocus = true; - state.videoCaption.isMouseFocus = true; + subDataLiIdx__1.trigger(jQuery.Event('mousedown')); + }); - subDataLiIdx__1.trigger(jQuery.Event('mousedown')); + it('does not show an outline around the first', function() { + expect(subDataLiIdx__0).not.toHaveClass('focused'); + }); + + it('does not show an outline around the second', function() { + expect(subDataLiIdx__1).not.toHaveClass('focused'); + }); + + it('has automatic scrolling enabled', function() { + expect(state.videoCaption.autoScrolling).toBe(true); + }); }); - - it('does not show an outline around the first', function () { - expect(subDataLiIdx__0).not.toHaveClass('focused'); - }); - - it('does not show an outline around the second', function () { - expect(subDataLiIdx__1).not.toHaveClass('focused'); - }); - - it('has automatic scrolling enabled', function () { - expect(state.videoCaption.autoScrolling).toBe(true); - }); - }); }); }); - }).call(this); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_context_menu_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_context_menu_spec.js index ef4b20bccb..35db0439f7 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_context_menu_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_context_menu_spec.js @@ -1,10 +1,10 @@ -(function () { +(function() { 'use strict'; - describe('Video Context Menu', function () { + describe('Video Context Menu', function() { var state, openMenu, keyPressEvent, openSubmenuMouse, openSubmenuKeyboard, closeSubmenuMouse, closeSubmenuKeyboard, menu, menuItems, menuSubmenuItem, submenu, submenuItems, overlay, playButton; - openMenu = function () { + openMenu = function() { var container = $('.video'); container.find('video').trigger('contextmenu'); menu = container.children('.contextmenu'); @@ -20,42 +20,42 @@ return $.Event('keydown', {keyCode: key}); }; - openSubmenuMouse = function (menuSubmenuItem) { + openSubmenuMouse = function(menuSubmenuItem) { menuSubmenuItem.mouseover(); jasmine.clock().tick(200); expect(menuSubmenuItem).toHaveClass('is-opened'); }; - openSubmenuKeyboard = function (menuSubmenuItem, keyCode) { + openSubmenuKeyboard = function(menuSubmenuItem, keyCode) { menuSubmenuItem.focus().trigger(keyPressEvent(keyCode || $.ui.keyCode.RIGHT)); expect(menuSubmenuItem).toHaveClass('is-opened'); expect(menuSubmenuItem.children().last().children().first()).toBeFocused(); }; - closeSubmenuMouse = function (menuSubmenuItem) { + closeSubmenuMouse = function(menuSubmenuItem) { menuSubmenuItem.mouseleave(); jasmine.clock().tick(200); expect(menuSubmenuItem).not.toHaveClass('is-opened'); }; - closeSubmenuKeyboard = function (menuSubmenuItem) { + closeSubmenuKeyboard = function(menuSubmenuItem) { menuSubmenuItem.children().first().focus().trigger(keyPressEvent($.ui.keyCode.LEFT)); expect(menuSubmenuItem).not.toHaveClass('is-opened'); expect(menuSubmenuItem).toBeFocused(); }; - beforeEach(function () { + beforeEach(function() { jasmine.clock().install(); // $.cookie is mocked, make sure we have a state with an unmuted volume. $.cookie.and.returnValue('100'); jasmine.addMatchers({ - toHaveCorrectLabels: function () { + toHaveCorrectLabels: function() { return { - compare: function (actual, labelsList) { + compare: function(actual, labelsList) { return { - pass: _.difference(labelsList, _.map(actual, function (item) { - return $(item).text(); - })).length === 0 + pass: _.difference(labelsList, _.map(actual, function(item) { + return $(item).text(); + })).length === 0 }; } }; @@ -63,7 +63,7 @@ }); }); - afterEach(function () { + afterEach(function() { $('source').remove(); _.result(state.storage, 'clear'); _.result($('video').data('contextmenu'), 'destroy'); @@ -71,8 +71,8 @@ jasmine.clock().uninstall(); }); - describe('constructor', function () { - it('the structure should be created on first `contextmenu` call', function () { + describe('constructor', function() { + it('the structure should be created on first `contextmenu` call', function() { state = jasmine.initializePlayer(); expect(menu).not.toExist(); openMenu(); @@ -98,12 +98,12 @@ expect(_.size(submenuItems.filter('.is-selected'))).toBe(1); }); - it('add ARIA attributes to menu, menu items, submenu and submenu items', function () { + it('add ARIA attributes to menu, menu items, submenu and submenu items', function() { state = jasmine.initializePlayer(); openMenu(); // Menu and its items. expect(menu).toHaveAttr('role', 'menu'); - menuItems.each(function () { + menuItems.each(function() { expect($(this)).toHaveAttrs({ 'aria-selected': 'false', 'role': 'menuitem' @@ -118,69 +118,69 @@ // Submenu and its items. expect(submenu).toHaveAttr('role', 'menu'); - submenuItems.each(function () { + submenuItems.each(function() { expect($(this)).toHaveAttr('role', 'menuitem'); expect($(this)).toHaveAttr('aria-selected'); }); }); - it('is not used by Youtube type of video player', function () { + it('is not used by Youtube type of video player', function() { state = jasmine.initializePlayer('video.html'); expect($('video, iframe')).not.toHaveData('contextmenu'); }); }); - describe('methods:', function () { - beforeEach(function () { + describe('methods:', function() { + beforeEach(function() { state = jasmine.initializePlayer(); openMenu(); }); - it('menu can be destroyed successfully', function () { + it('menu can be destroyed successfully', function() { var menuitemEvents = ['click', 'keydown', 'contextmenu', 'mouseover'], menuEvents = ['keydown', 'contextmenu', 'mouseleave', 'mouseover']; menu.data('menu').destroy(); expect(menu).not.toBeInDOM(); expect(overlay).not.toBeInDOM(); - _.each(menuitemEvents, function (eventName) { + _.each(menuitemEvents, function(eventName) { expect(menuItems.first()).not.toHandle(eventName); - }) - _.each(menuEvents, function (eventName) { + }); + _.each(menuEvents, function(eventName) { expect(menuSubmenuItem).not.toHandle(eventName); - }) - _.each(menuEvents, function (eventName) { + }); + _.each(menuEvents, function(eventName) { expect(menu).not.toHandle(eventName); - }) + }); expect($('video')).not.toHandle('contextmenu'); expect($('video')).not.toHaveData('contextmenu'); }); - it('can change label for the submenu', function () { + it('can change label for the submenu', function() { expect(menuSubmenuItem.children('span')).toHaveText('Speed'); menuSubmenuItem.data('menu').setLabel('New Name'); expect(menuSubmenuItem.children('span')).toHaveText('New Name'); }); - it('can change label for the menuitem', function () { + it('can change label for the menuitem', function() { expect(menuItems.first()).toHaveText('Play'); menuItems.first().data('menu').setLabel('Pause'); expect(menuItems.first()).toHaveText('Pause'); }); }); - describe('when video is right-clicked', function () { - beforeEach(function () { + describe('when video is right-clicked', function() { + beforeEach(function() { state = jasmine.initializePlayer(); openMenu(); }); - it('context menu opens', function () { + it('context menu opens', function() { expect(menu).toHaveClass('is-opened'); expect(overlay).toBeInDOM(); }); - it('mouseover and mouseleave behave as expected', function () { + it('mouseover and mouseleave behave as expected', function() { openSubmenuMouse(menuSubmenuItem); expect(menuSubmenuItem).toHaveClass('is-opened'); closeSubmenuMouse(menuSubmenuItem); @@ -189,28 +189,28 @@ expect(submenuItems.eq(1)).toBeFocused(); }); - it('mouse left-clicking outside of the context menu will close it', function () { + it('mouse left-clicking outside of the context menu will close it', function() { // Left-click outside of open menu, for example on Play button playButton.click(); expect(menu).not.toHaveClass('is-opened'); expect(overlay).not.toBeInDOM(); }); - it('mouse right-clicking outside of video will close it', function () { + it('mouse right-clicking outside of video will close it', function() { // Right-click outside of open menu for example on Play button playButton.trigger('contextmenu'); expect(menu).not.toHaveClass('is-opened'); expect(overlay).not.toBeInDOM(); }); - it('mouse right-clicking inside video but outside of context menu will not close it', function () { + it('mouse right-clicking inside video but outside of context menu will not close it', function() { spyOn(menu.data('menu'), 'pointInContainerBox').and.returnValue(true); overlay.trigger('contextmenu'); expect(menu).toHaveClass('is-opened'); expect(overlay).toBeInDOM(); }); - it('mouse right-clicking inside video but outside of context menu will close submenus', function () { + it('mouse right-clicking inside video but outside of context menu will close submenus', function() { spyOn(menu.data('menu'), 'pointInContainerBox').and.returnValue(true); openSubmenuMouse(menuSubmenuItem); expect(menuSubmenuItem).toHaveClass('is-opened'); @@ -218,14 +218,14 @@ expect(menuSubmenuItem).not.toHaveClass('is-opened'); }); - it('mouse left/right-clicking behaves as expected on play/pause menu item', function () { + it('mouse left/right-clicking behaves as expected on play/pause menu item', function() { var menuItem = menuItems.first(); spyOn(state.videoPlayer, 'isPlaying'); - spyOn(state.videoPlayer, 'play').and.callFake(function () { + spyOn(state.videoPlayer, 'play').and.callFake(function() { state.videoPlayer.isPlaying.and.returnValue(true); state.el.trigger('play'); }); - spyOn(state.videoPlayer, 'pause').and.callFake(function () { + spyOn(state.videoPlayer, 'pause').and.callFake(function() { state.videoPlayer.isPlaying.and.returnValue(false); state.el.trigger('pause'); }); @@ -245,7 +245,7 @@ expect(menuItem).toHaveText('Pause'); }); - it('mouse left/right-clicking behaves as expected on mute/unmute menu item', function () { + it('mouse left/right-clicking behaves as expected on mute/unmute menu item', function() { var menuItem = menuItems.eq(1); // Left-click on mute menuItem.click(); @@ -267,7 +267,7 @@ expect(menuItem).toHaveText('Mute'); }); - it('mouse left/right-clicking behaves as expected on go to Exit full browser menu item', function () { + it('mouse left/right-clicking behaves as expected on go to Exit full browser menu item', function() { var menuItem = menuItems.eq(2); // Left-click on Fill browser menuItem.click(); @@ -289,7 +289,7 @@ expect(menuItem).toHaveText('Fill browser'); }); - it('mouse left/right-clicking behaves as expected on speed submenu item', function () { + it('mouse left/right-clicking behaves as expected on speed submenu item', function() { // Set speed to 0.75x state.videoSpeedControl.setSpeed('0.75'); // Left-click on second submenu speed (1.0x) @@ -318,70 +318,70 @@ }); }); - describe('Keyboard interactions', function () { - beforeEach(function () { + describe('Keyboard interactions', function() { + beforeEach(function() { state = jasmine.initializePlayer(); openMenu(); }); - it('focus the first item of the just opened menu on UP keydown', function () { + it('focus the first item of the just opened menu on UP keydown', function() { menu.trigger(keyPressEvent($.ui.keyCode.UP)); expect(menuSubmenuItem).toBeFocused(); }); - it('focus the last item of the just opened menu on DOWN keydown', function () { + it('focus the last item of the just opened menu on DOWN keydown', function() { menu.trigger(keyPressEvent($.ui.keyCode.DOWN)); expect(menuItems.first()).toBeFocused(); }); - it('open the submenu on ENTER keydown', function () { + it('open the submenu on ENTER keydown', function() { openSubmenuKeyboard(menuSubmenuItem, $.ui.keyCode.ENTER); expect(menuSubmenuItem).toHaveClass('is-opened'); expect(submenuItems.first()).toBeFocused(); }); - it('open the submenu on SPACE keydown', function () { + it('open the submenu on SPACE keydown', function() { openSubmenuKeyboard(menuSubmenuItem, $.ui.keyCode.SPACE); expect(menuSubmenuItem).toHaveClass('is-opened'); expect(submenuItems.first()).toBeFocused(); }); - it('open the submenu on RIGHT keydown', function () { + it('open the submenu on RIGHT keydown', function() { openSubmenuKeyboard(menuSubmenuItem, $.ui.keyCode.RIGHT); expect(menuSubmenuItem).toHaveClass('is-opened'); expect(submenuItems.first()).toBeFocused(); }); - it('close the menu on ESCAPE keydown', function () { + it('close the menu on ESCAPE keydown', function() { menu.trigger(keyPressEvent($.ui.keyCode.ESCAPE)); expect(menu).not.toHaveClass('is-opened'); expect(overlay).not.toBeInDOM(); }); - it('close the submenu on ESCAPE keydown', function () { + it('close the submenu on ESCAPE keydown', function() { openSubmenuKeyboard(menuSubmenuItem); menuSubmenuItem.trigger(keyPressEvent($.ui.keyCode.ESCAPE)); expect(menuSubmenuItem).not.toHaveClass('is-opened'); expect(overlay).not.toBeInDOM(); }); - it('close the submenu on LEFT keydown on submenu items', function () { + it('close the submenu on LEFT keydown on submenu items', function() { closeSubmenuKeyboard(menuSubmenuItem); }); - it('do nothing on RIGHT keydown on submenu item', function () { + it('do nothing on RIGHT keydown on submenu item', function() { submenuItems.eq(1).focus().trigger(keyPressEvent($.ui.keyCode.RIGHT)); // Mute // Is still focused. expect(submenuItems.eq(1)).toBeFocused(); }); - it('do nothing on TAB keydown on menu item', function () { + it('do nothing on TAB keydown on menu item', function() { submenuItems.eq(1).focus().trigger(keyPressEvent($.ui.keyCode.TAB)); // Mute // Is still focused. expect(submenuItems.eq(1)).toBeFocused(); }); - it('UP and DOWN keydown function as expected on menu/submenu items', function () { + it('UP and DOWN keydown function as expected on menu/submenu items', function() { menuItems.eq(0).focus(); // Play expect(menuItems.eq(0)).toBeFocused(); menuItems.eq(0).trigger(keyPressEvent($.ui.keyCode.DOWN)); @@ -403,7 +403,7 @@ expect(menuItems.eq(0)).toBeFocused(); // Play }); - it('current item is still focused if all siblings are hidden', function () { + it('current item is still focused if all siblings are hidden', function() { menuItems.eq(0).focus(); // Play expect(menuItems.eq(0)).toBeFocused(); // hide all siblings menuItems.eq(0).siblings().hide(); @@ -413,7 +413,7 @@ expect(menuItems.eq(0)).toBeFocused(); }); - it('ENTER keydown on menu/submenu item selects its data and closes menu', function () { + it('ENTER keydown on menu/submenu item selects its data and closes menu', function() { menuItems.eq(2).focus().trigger(keyPressEvent($.ui.keyCode.ENTER)); // Fullscreen expect(menuItems.eq(2)).toHaveClass('is-selected'); expect(menuItems.eq(2).siblings()).not.toHaveClass('is-selected'); @@ -421,7 +421,7 @@ expect(menuItems.eq(2)).toHaveText('Exit full browser'); }); - it('SPACE keydown on menu/submenu item selects its data and closes menu', function () { + it('SPACE keydown on menu/submenu item selects its data and closes menu', function() { submenuItems.eq(2).focus().trigger(keyPressEvent($.ui.keyCode.SPACE)); // 1.25x expect(submenuItems.eq(2)).toHaveClass('is-selected'); expect(submenuItems.eq(2).siblings()).not.toHaveClass('is-selected'); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js index eb47c399ab..e96d74d092 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_control_spec.js @@ -1,29 +1,29 @@ -(function (WAIT_TIMEOUT) { +(function(WAIT_TIMEOUT) { 'use strict'; - describe('VideoControl', function () { + describe('VideoControl', function() { var state, oldOTBD; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice').and.returnValue(null); }); - afterEach(function () { + afterEach(function() { $('source').remove(); state.storage.clear(); state.videoPlayer.destroy(); window.onTouchBasedDevice = oldOTBD; }); - describe('constructor', function () { - beforeEach(function () { + describe('constructor', function() { + beforeEach(function() { window.VideoState = {}; state = jasmine.initializePlayer(); }); - it('render the video controls', function () { + it('render the video controls', function() { expect($('.video-controls')).toContainElement( [ '.slider', @@ -38,479 +38,479 @@ }); }); - describe('constructor with start-time', function () { + describe('constructor with start-time', function() { it( 'saved position is 0, timer slider and VCR set to start-time', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - savedVideoPosition: 0 + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + savedVideoPosition: 0 + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); + + + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:10 / 1:00'); + + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(10); + }).always(done); }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); - - - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:10 / 1:00'); - - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(10); - }).always(done); - }); it( 'saved position is after start-time, ' + 'timer slider and VCR set to saved position', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - savedVideoPosition: 15 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + savedVideoPosition: 15 + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:15 / 1:00'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:15 / 1:00'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(15); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(15); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); it( 'saved position is negative, ' + 'timer slider and VCR set to start-time', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - savedVideoPosition: -15 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + savedVideoPosition: -15 + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:10 / 1:00'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:10 / 1:00'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(10); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(10); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); it( 'saved position is not a number, ' + 'timer slider and VCR set to start-time', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - savedVideoPosition: 'a' - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + savedVideoPosition: 'a' + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:10 / 1:00'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:10 / 1:00'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(10); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(10); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); it( 'saved position is greater than end-time, ' + 'timer slider and VCR set to start-time', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - savedVideoPosition: 10000 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + savedVideoPosition: 10000 + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:10 / 1:00'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:10 / 1:00'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(10); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(10); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); }); - describe('constructor with end-time', function () { + describe('constructor with end-time', function() { it( 'saved position is 0, timer slider and VCR set to 0:00 ' + 'and ending at specified end-time', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - end: 20, - savedVideoPosition: 0 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + end: 20, + savedVideoPosition: 0 + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:00 / 0:20'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:00 / 0:20'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(0); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(0); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); it( 'saved position is after start-time, ' + 'timer slider and VCR set to saved position', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - end: 20, - savedVideoPosition: 15 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + end: 20, + savedVideoPosition: 15 + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:15 / 0:20'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:15 / 0:20'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(15); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(15); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); // TODO: Fix! it( 'saved position is negative, timer slider and VCR set to 0:00', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - end: 20, - savedVideoPosition: -15 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + end: 20, + savedVideoPosition: -15 + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:00 / 0:20'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:00 / 0:20'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(0); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(0); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); it( 'saved position is not a number, ' + 'timer slider and VCR set to 0:00', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - end: 20, - savedVideoPosition: 'a' - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + end: 20, + savedVideoPosition: 'a' + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:00 / 0:20'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:00 / 0:20'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(0); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(0); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); // TODO: Fix! it( 'saved position is greater than end-time, ' + 'timer slider and VCR set to 0:00', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - end: 20, - savedVideoPosition: 10000 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + end: 20, + savedVideoPosition: 10000 + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:00 / 0:20'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:00 / 0:20'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(0); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(0); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); }); - describe('constructor with start-time and end-time', function () { + describe('constructor with start-time and end-time', function() { it( 'saved position is 0, timer slider and VCR set to appropriate start and end times', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - end: 20, - savedVideoPosition: 0 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + end: 20, + savedVideoPosition: 0 + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:10 / 0:20'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:10 / 0:20'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(10); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(10); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); it( 'saved position is after start-time, ' + 'timer slider and VCR set to saved position', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - end: 20, - savedVideoPosition: 15 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + end: 20, + savedVideoPosition: 15 + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:15 / 0:20'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:15 / 0:20'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(15); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(15); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); it( 'saved position is negative, ' + 'timer slider and VCR set to start-time', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - end: 20, - savedVideoPosition: -15 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + end: 20, + savedVideoPosition: -15 + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:10 / 0:20'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:10 / 0:20'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(10); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(10); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); it( 'saved position is not a number, ' + 'timer slider and VCR set to start-time', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - end: 20, - savedVideoPosition: 'a' - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + end: 20, + savedVideoPosition: 'a' + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:10 / 0:20'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:10 / 0:20'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(10); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(10); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); it( 'saved position is greater than end-time, ' + 'timer slider and VCR set to start-time', - function (done) + function(done) { - var duration, sliderEl, expectedValue; + var duration, sliderEl, expectedValue; - window.VideoState = {}; - state = jasmine.initializePlayer({ - start: 10, - end: 20, - savedVideoPosition: 10000 - }); - sliderEl = state.videoProgressSlider.slider; - spyOn(state.videoPlayer, 'duration').and.returnValue(60); + window.VideoState = {}; + state = jasmine.initializePlayer({ + start: 10, + end: 20, + savedVideoPosition: 10000 + }); + sliderEl = state.videoProgressSlider.slider; + spyOn(state.videoPlayer, 'duration').and.returnValue(60); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return isFinite(duration) && duration > 0 && + return isFinite(duration) && duration > 0 && isFinite(state.videoPlayer.startTime); - }).then(function () { - expectedValue = $('.video-controls').find('.vidtime'); - expect(expectedValue).toHaveText('0:10 / 0:20'); + }).then(function() { + expectedValue = $('.video-controls').find('.vidtime'); + expect(expectedValue).toHaveText('0:10 / 0:20'); - expectedValue = sliderEl.slider('option', 'value'); - expect(expectedValue).toBe(10); + expectedValue = sliderEl.slider('option', 'value'); + expect(expectedValue).toBe(10); - state.storage.clear(); - }).always(done); - }); + state.storage.clear(); + }).always(done); + }); }); - it('show', function () { + it('show', function() { var controls; state = jasmine.initializePlayer(); controls = state.el.find('.video-controls'); @@ -520,19 +520,19 @@ expect(controls).not.toHaveClass('is-hidden'); }); - it('can destroy itself', function () { + it('can destroy itself', function() { state = jasmine.initializePlayer(); state.videoControl.destroy(); expect(state.videoControl).toBeUndefined(); }); - it('can focus the first control', function (done) { + it('can focus the first control', function(done) { var btnPlay; state = jasmine.initializePlayer({focusFirstControl: true}); btnPlay = state.el.find('.video-controls .play'); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.el.hasClass('is-initialized'); - }).then(function () { + }).then(function() { expect(btnPlay).toBeFocused(); }).always(done); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_events_bumper_plugin_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_events_bumper_plugin_spec.js index 4a0f1177e2..2ffdcf1c07 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_events_bumper_plugin_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_events_bumper_plugin_spec.js @@ -1,10 +1,10 @@ -(function (undefined) { +(function(undefined) { 'use strict'; - describe('VideoPlayer Events Bumper plugin', function () { + describe('VideoPlayer Events Bumper plugin', function() { var Logger = window.Logger; var state, oldOTBD; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice') @@ -17,7 +17,7 @@ spyOn(state.bumperState.videoEventsBumperPlugin, 'getDuration').and.returnValue(20); }); - afterEach(function () { + afterEach(function() { $('source').remove(); window.onTouchBasedDevice = oldOTBD; state.storage.clear(); @@ -29,7 +29,7 @@ } }); - it('can emit "edx.video.bumper.loaded" event', function () { + it('can emit "edx.video.bumper.loaded" event', function() { state.el.trigger('ready'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.loaded', { host_component_id: 'id', @@ -39,7 +39,7 @@ }); }); - it('can emit "edx.video.bumper.played" event', function () { + it('can emit "edx.video.bumper.played" event', function() { state.el.trigger('play'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.played', { host_component_id: 'id', @@ -50,7 +50,7 @@ }); }); - it('can emit "edx.video.bumper.stopped" event', function () { + it('can emit "edx.video.bumper.stopped" event', function() { state.el.trigger('ended'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.stopped', { host_component_id: 'id', @@ -71,7 +71,7 @@ }); }); - it('can emit "edx.video.bumper.skipped" event', function () { + it('can emit "edx.video.bumper.skipped" event', function() { state.el.trigger('skip', [false]); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.skipped', { host_component_id: 'id', @@ -82,7 +82,7 @@ }); }); - it('can emit "edx.video.bumper.dismissed" event', function () { + it('can emit "edx.video.bumper.dismissed" event', function() { state.el.trigger('skip', [true]); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.dismissed', { host_component_id: 'id', @@ -93,7 +93,7 @@ }); }); - it('can emit "edx.video.bumper.transcript.menu.shown" event', function () { + it('can emit "edx.video.bumper.transcript.menu.shown" event', function() { state.el.trigger('language_menu:show'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.transcript.menu.shown', { host_component_id: 'id', @@ -103,7 +103,7 @@ }); }); - it('can emit "edx.video.bumper.transcript.menu.hidden" event', function () { + it('can emit "edx.video.bumper.transcript.menu.hidden" event', function() { state.el.trigger('language_menu:hide'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.transcript.menu.hidden', { host_component_id: 'id', @@ -113,7 +113,7 @@ }); }); - it('can emit "edx.video.bumper.transcript.shown" event', function () { + it('can emit "edx.video.bumper.transcript.shown" event', function() { state.el.trigger('captions:show'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.transcript.shown', { host_component_id: 'id', @@ -124,7 +124,7 @@ }); }); - it('can emit "edx.video.bumper.transcript.hidden" event', function () { + it('can emit "edx.video.bumper.transcript.hidden" event', function() { state.el.trigger('captions:hide'); expect(Logger.log).toHaveBeenCalledWith('edx.video.bumper.transcript.hidden', { host_component_id: 'id', @@ -135,7 +135,7 @@ }); }); - it('can destroy itself', function () { + it('can destroy itself', function() { var plugin = state.bumperState.videoEventsBumperPlugin; spyOn($.fn, 'off').and.callThrough(); plugin.destroy(); @@ -153,5 +153,4 @@ }); }); }); - }).call(this); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_events_plugin_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_events_plugin_spec.js index 92a967ff3c..27d260c931 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_events_plugin_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_events_plugin_spec.js @@ -1,9 +1,9 @@ -(function (undefined) { +(function(undefined) { 'use strict'; - describe('VideoPlayer Events plugin', function () { + describe('VideoPlayer Events plugin', function() { var state, oldOTBD, Logger = window.Logger; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice') @@ -14,7 +14,7 @@ spyOn(state.videoEventsPlugin, 'getCurrentTime').and.returnValue(10); }); - afterEach(function () { + afterEach(function() { $('source').remove(); window.onTouchBasedDevice = oldOTBD; state.storage.clear(); @@ -23,7 +23,7 @@ } }); - it('can emit "load_video" event', function () { + it('can emit "load_video" event', function() { state.el.trigger('ready'); expect(Logger.log).toHaveBeenCalledWith('load_video', { id: 'id', @@ -31,7 +31,7 @@ }); }); - it('can emit "play_video" event when emitPlayVideoEvent is true', function () { + it('can emit "play_video" event when emitPlayVideoEvent is true', function() { state.videoEventsPlugin.emitPlayVideoEvent = true; state.el.trigger('play'); expect(Logger.log).toHaveBeenCalledWith('play_video', { @@ -42,13 +42,13 @@ expect(state.videoEventsPlugin.emitPlayVideoEvent).toBeFalsy(); }); - it('can not emit "play_video" event when emitPlayVideoEvent is false', function () { + it('can not emit "play_video" event when emitPlayVideoEvent is false', function() { state.videoEventsPlugin.emitPlayVideoEvent = false; state.el.trigger('play'); expect(Logger.log).not.toHaveBeenCalled(); }); - it('can emit "pause_video" event', function () { + it('can emit "pause_video" event', function() { state.el.trigger('pause'); expect(Logger.log).toHaveBeenCalledWith('pause_video', { id: 'id', @@ -58,7 +58,7 @@ expect(state.videoEventsPlugin.emitPlayVideoEvent).toBeTruthy(); }); - it('can emit "speed_change_video" event', function () { + it('can emit "speed_change_video" event', function() { state.el.trigger('speedchange', ['2.0', '1.0']); expect(Logger.log).toHaveBeenCalledWith('speed_change_video', { id: 'id', @@ -69,7 +69,7 @@ }); }); - it('can emit "seek_video" event', function () { + it('can emit "seek_video" event', function() { state.el.trigger('seek', [1, 0, 'any']); expect(Logger.log).toHaveBeenCalledWith('seek_video', { id: 'id', @@ -80,7 +80,7 @@ }); }); - it('can emit "stop_video" event', function () { + it('can emit "stop_video" event', function() { state.el.trigger('ended'); expect(Logger.log).toHaveBeenCalledWith('stop_video', { id: 'id', @@ -99,7 +99,7 @@ expect(state.videoEventsPlugin.emitPlayVideoEvent).toBeTruthy(); }); - it('can emit "skip_video" event', function () { + it('can emit "skip_video" event', function() { state.el.trigger('skip', [false]); expect(Logger.log).toHaveBeenCalledWith('skip_video', { id: 'id', @@ -108,7 +108,7 @@ }); }); - it('can emit "do_not_show_again_video" event', function () { + it('can emit "do_not_show_again_video" event', function() { state.el.trigger('skip', [true]); expect(Logger.log).toHaveBeenCalledWith('do_not_show_again_video', { id: 'id', @@ -117,7 +117,7 @@ }); }); - it('can emit "edx.video.language_menu.shown" event', function () { + it('can emit "edx.video.language_menu.shown" event', function() { state.el.trigger('language_menu:show'); expect(Logger.log).toHaveBeenCalledWith('edx.video.language_menu.shown', { id: 'id', @@ -125,7 +125,7 @@ }); }); - it('can emit "edx.video.language_menu.hidden" event', function () { + it('can emit "edx.video.language_menu.hidden" event', function() { state.el.trigger('language_menu:hide'); expect(Logger.log).toHaveBeenCalledWith('edx.video.language_menu.hidden', { id: 'id', @@ -134,7 +134,7 @@ }); }); - it('can emit "show_transcript" event', function () { + it('can emit "show_transcript" event', function() { state.el.trigger('transcript:show'); expect(Logger.log).toHaveBeenCalledWith('show_transcript', { id: 'id', @@ -143,7 +143,7 @@ }); }); - it('can emit "hide_transcript" event', function () { + it('can emit "hide_transcript" event', function() { state.el.trigger('transcript:hide'); expect(Logger.log).toHaveBeenCalledWith('hide_transcript', { id: 'id', @@ -152,7 +152,7 @@ }); }); - it('can emit "edx.video.closed_captions.shown" event', function () { + it('can emit "edx.video.closed_captions.shown" event', function() { state.el.trigger('captions:show'); expect(Logger.log).toHaveBeenCalledWith('edx.video.closed_captions.shown', { id: 'id', @@ -161,7 +161,7 @@ }); }); - it('can emit "edx.video.closed_captions.hidden" event', function () { + it('can emit "edx.video.closed_captions.hidden" event', function() { state.el.trigger('captions:hide'); expect(Logger.log).toHaveBeenCalledWith('edx.video.closed_captions.hidden', { id: 'id', @@ -170,7 +170,7 @@ }); }); - it('can destroy itself', function () { + it('can destroy itself', function() { var plugin = state.videoEventsPlugin; spyOn($.fn, 'off').and.callThrough(); state.videoEventsPlugin.destroy(); @@ -193,5 +193,4 @@ }); }); }); - }).call(this); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js index 8d465b15a9..8a9a10410a 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_focus_grabber_spec.js @@ -1,8 +1,8 @@ -(function (undefined) { - describe('Video FocusGrabber', function () { +(function(undefined) { + describe('Video FocusGrabber', function() { var state; - beforeEach(function () { + beforeEach(function() { // https://github.com/pivotal/jasmine/issues/184 // // This is a known issue. jQuery animations depend on setTimeout @@ -24,7 +24,7 @@ spyOn(state.focusGrabber, 'enableFocusGrabber').and.callThrough(); }); - afterEach(function () { + afterEach(function() { // Turn jQuery animations back on. jQuery.fx.off = true; state.storage.clear(); @@ -33,22 +33,21 @@ it( 'check existence of focus grabber elements and their position', - function () { - - var firstFGEl = state.el.find('.focus_grabber.first'), - lastFGEl = state.el.find('.focus_grabber.last'), - tcWrapperEl = state.el.find('.tc-wrapper'); + function() { + var firstFGEl = state.el.find('.focus_grabber.first'), + lastFGEl = state.el.find('.focus_grabber.last'), + tcWrapperEl = state.el.find('.tc-wrapper'); // Existence check. - expect(firstFGEl.length).toBe(1); - expect(lastFGEl.length).toBe(1); + expect(firstFGEl.length).toBe(1); + expect(lastFGEl.length).toBe(1); // Position check. - expect(firstFGEl.index() + 1).toBe(tcWrapperEl.index()); - expect(lastFGEl.index() - 1).toBe(tcWrapperEl.index()); - }); + expect(firstFGEl.index() + 1).toBe(tcWrapperEl.index()); + expect(lastFGEl.index() - 1).toBe(tcWrapperEl.index()); + }); - it('from the start, focus grabbers are disabled', function () { + it('from the start, focus grabbers are disabled', function() { expect(state.focusGrabber.elFirst.attr('tabindex')).toBe('-1'); expect(state.focusGrabber.elLast.attr('tabindex')).toBe('-1'); }); @@ -56,24 +55,22 @@ it( 'when first focus grabber is focused "mousemove" event is ' + 'triggered, grabbers are disabled', - function () { + function() { + state.focusGrabber.elFirst.triggerHandler('focus'); - state.focusGrabber.elFirst.triggerHandler('focus'); - - expect('mousemove').toHaveBeenTriggeredOn(state.el); - expect(state.focusGrabber.disableFocusGrabber).toHaveBeenCalled(); - }); + expect('mousemove').toHaveBeenTriggeredOn(state.el); + expect(state.focusGrabber.disableFocusGrabber).toHaveBeenCalled(); + }); it( 'when last focus grabber is focused "mousemove" event is ' + 'triggered, grabbers are disabled', - function () { + function() { + state.focusGrabber.elLast.triggerHandler('focus'); - state.focusGrabber.elLast.triggerHandler('focus'); - - expect('mousemove').toHaveBeenTriggeredOn(state.el); - expect(state.focusGrabber.disableFocusGrabber).toHaveBeenCalled(); - }); + expect('mousemove').toHaveBeenTriggeredOn(state.el); + expect(state.focusGrabber.disableFocusGrabber).toHaveBeenCalled(); + }); // Disabled on 18.11.2013 due to flakiness on local dev machine. // @@ -85,8 +82,8 @@ // // TODO: Most likely, focusGrabber will be disabled in the future. This // test could become unneeded in the future. - xit('after controls hide focus grabbers are enabled', function () { - runs(function () { + xit('after controls hide focus grabbers are enabled', function() { + runs(function() { // Captions should not be "sticky" for the autohide mechanism // to work. state.videoCaption.hideCaptions(true); @@ -100,7 +97,7 @@ // that there is clearly no race conditions for our expect below. waits(state.videoControl.fadeOutTimeout + 100); - runs(function () { + runs(function() { expect( state.focusGrabber.enableFocusGrabber ).toHaveBeenCalled(); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_full_screen_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_full_screen_spec.js index 1bb36c82b4..57930adbfe 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_full_screen_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_full_screen_spec.js @@ -1,32 +1,32 @@ -(function () { +(function() { 'use strict'; - describe('VideoFullScreen', function () { + describe('VideoFullScreen', function() { var state, oldOTBD; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice').and.returnValue(null); }); - afterEach(function () { + afterEach(function() { $('source').remove(); state.storage.clear(); state.videoPlayer.destroy(); window.onTouchBasedDevice = oldOTBD; }); - describe('constructor', function () { - beforeEach(function () { + describe('constructor', function() { + beforeEach(function() { state = jasmine.initializePlayer(); }); - it('renders the fullscreen control', function () { + it('renders the fullscreen control', function() { expect($('.add-fullscreen')).toExist(); expect(state.videoFullScreen.fullScreenState).toBe(false); }); - it('correctly adds ARIA attributes to fullscreen control', function () { + it('correctly adds ARIA attributes to fullscreen control', function() { var fullScreenControl = $('.add-fullscreen'); expect(fullScreenControl).toHaveAttrs({ @@ -34,7 +34,7 @@ }); }); - it('correctly triggers the event handler to toggle fullscreen mode', function () { + it('correctly triggers the event handler to toggle fullscreen mode', function() { spyOn(state.videoFullScreen, 'exit'); spyOn(state.videoFullScreen, 'enter'); @@ -47,7 +47,7 @@ expect(state.videoFullScreen.exit).toHaveBeenCalled(); }); - it('correctly updates ARIA on state change', function () { + it('correctly updates ARIA on state change', function() { var fullScreenControl = $('.add-fullscreen'); fullScreenControl.click(); expect(fullScreenControl).toHaveAttrs({ @@ -59,7 +59,7 @@ }); }); - it('correctly can out of fullscreen by pressing esc', function () { + it('correctly can out of fullscreen by pressing esc', function() { spyOn(state.videoCommands, 'execute'); var esc = $.Event('keyup'); esc.keyCode = 27; @@ -68,23 +68,23 @@ expect(state.videoCommands.execute).toHaveBeenCalledWith('toggleFullScreen'); }); - it('can update video dimensions on state change', function () { + it('can update video dimensions on state change', function() { state.el.trigger('fullscreen', [true]); expect(state.resizer.setMode).toHaveBeenCalledWith('both'); state.el.trigger('fullscreen', [false]); expect(state.resizer.setMode).toHaveBeenCalledWith('width'); }); - it('can destroy itself', function () { + it('can destroy itself', function() { state.videoFullScreen.destroy(); expect($('.add-fullscreen')).not.toExist(); expect(state.videoFullScreen).toBeUndefined(); }); }); - it('Controls height is actual on switch to fullscreen', function () { - spyOn($.fn, 'height').and.callFake(function (val) { - return _.isUndefined(val) ? 100: this; + it('Controls height is actual on switch to fullscreen', function() { + spyOn($.fn, 'height').and.callFake(function(val) { + return _.isUndefined(val) ? 100 : this; }); state = jasmine.initializePlayer(); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_play_pause_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_play_pause_control_spec.js index dcb1fd4968..be592422f5 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_play_pause_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_play_pause_control_spec.js @@ -1,9 +1,9 @@ -(function () { +(function() { 'use strict'; - describe('VideoPlayPauseControl', function () { + describe('VideoPlayPauseControl', function() { var state, oldOTBD; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice').and.returnValue(null); @@ -12,31 +12,31 @@ spyOn(state.videoSaveStatePlugin, 'saveState'); }); - afterEach(function () { + afterEach(function() { $('source').remove(); state.storage.clear(); state.videoPlayer.destroy(); window.onTouchBasedDevice = oldOTBD; }); - it('can render the control', function () { + it('can render the control', function() { expect($('.video_control.play')).toExist(); }); - it('add ARIA attributes to play control', function () { + it('add ARIA attributes to play control', function() { expect($('.video_control.play')).toHaveAttrs({ 'aria-disabled': 'false' }); }); - it('can update ARIA state on play', function () { + it('can update ARIA state on play', function() { state.el.trigger('play'); expect($('.video_control.pause')).toHaveAttrs({ 'aria-disabled': 'false' }); }); - it('can update ARIA state on video ends', function () { + it('can update ARIA state on video ends', function() { state.el.trigger('play'); state.el.trigger('ended'); expect($('.video_control.play')).toHaveAttrs({ @@ -44,17 +44,17 @@ }); }); - it('can update state on pause', function () { + it('can update state on pause', function() { state.el.trigger('pause'); expect(state.videoSaveStatePlugin.saveState).toHaveBeenCalledWith(true); }); - it('can start video playing on click', function () { + it('can start video playing on click', function() { $('.video_control.play').click(); expect(state.videoCommands.execute).toHaveBeenCalledWith('togglePlayback'); }); - it('can destroy itself', function () { + it('can destroy itself', function() { state.videoPlayPauseControl.destroy(); expect(state.videoPlayPauseControl).toBeUndefined(); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_play_placeholder_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_play_placeholder_spec.js index 4532742dee..5871d47a35 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_play_placeholder_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_play_placeholder_spec.js @@ -1,9 +1,9 @@ -(function () { +(function() { 'use strict'; - describe('VideoPlayPlaceholder', function () { + describe('VideoPlayPlaceholder', function() { var state, oldOTBD; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice').and.returnValue(['iPad']); @@ -12,7 +12,7 @@ spyOn(state.videoCommands, 'execute'); }); - afterEach(function () { + afterEach(function() { $('source').remove(); state.storage.clear(); state.videoPlayer.destroy(); @@ -39,12 +39,12 @@ } ]; - beforeEach(function () { + beforeEach(function() { jasmine.stubRequests(); spyOn(window.YT, 'Player').and.callThrough(); }); - it ('works correctly on calling proper methods', function () { + it('works correctly on calling proper methods', function() { var btnPlay; state = jasmine.initializePlayer(); @@ -67,14 +67,14 @@ }); }); - $.each(cases, function (index, data) { + $.each(cases, function(index, data) { var message = [ (data.isShown) ? 'is' : 'is not', ' shown on', data.name ].join(''); - it(message, function () { + it(message, function() { var btnPlay; window.onTouchBasedDevice.and.returnValue(data.isTouch); @@ -89,61 +89,61 @@ }); }); - $.each(['iPad', 'Android'], function (index, device) { + $.each(['iPad', 'Android'], function(index, device) { it( 'is shown on paused video on ' + device + ' in HTML5 player', - function () + function() { - var btnPlay; + var btnPlay; - window.onTouchBasedDevice.and.returnValue([device]); - state = jasmine.initializePlayer(); - btnPlay = state.el.find('.btn-play'); + window.onTouchBasedDevice.and.returnValue([device]); + state = jasmine.initializePlayer(); + btnPlay = state.el.find('.btn-play'); - state.el.trigger('play'); - state.el.trigger('pause'); - expect(btnPlay).not.toHaveClass('is-hidden'); - }); + state.el.trigger('play'); + state.el.trigger('pause'); + expect(btnPlay).not.toHaveClass('is-hidden'); + }); it( 'is hidden on playing video on ' + device + ' in HTML5 player', - function () + function() { - var btnPlay; + var btnPlay; - window.onTouchBasedDevice.and.returnValue([device]); - state = jasmine.initializePlayer(); - btnPlay = state.el.find('.btn-play'); + window.onTouchBasedDevice.and.returnValue([device]); + state = jasmine.initializePlayer(); + btnPlay = state.el.find('.btn-play'); - state.el.trigger('play'); - expect(btnPlay).toHaveClass('is-hidden'); - }); + state.el.trigger('play'); + expect(btnPlay).toHaveClass('is-hidden'); + }); it( 'is hidden on paused video on ' + device + ' in YouTube player', - function () + function() { - var btnPlay; + var btnPlay; - window.onTouchBasedDevice.and.returnValue([device]); - state = jasmine.initializePlayerYouTube(); - btnPlay = state.el.find('.btn-play'); + window.onTouchBasedDevice.and.returnValue([device]); + state = jasmine.initializePlayerYouTube(); + btnPlay = state.el.find('.btn-play'); - state.el.trigger('play'); - state.el.trigger('pause'); - expect(btnPlay).toHaveClass('is-hidden'); - }); + state.el.trigger('play'); + state.el.trigger('pause'); + expect(btnPlay).toHaveClass('is-hidden'); + }); }); - it('starts play the video on click', function () { + it('starts play the video on click', function() { $('.btn-play').click(); expect(state.videoCommands.execute).toHaveBeenCalledWith('play'); }); - it('can destroy itself', function () { + it('can destroy itself', function() { state.videoPlayPlaceholder.destroy(); expect(state.videoPlayPlaceholder).toBeUndefined(); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_play_skip_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_play_skip_control_spec.js index 479de984ba..f22fc3dba0 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_play_skip_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_play_skip_control_spec.js @@ -1,9 +1,9 @@ -(function () { +(function() { 'use strict'; - describe('VideoPlaySkipControl', function () { + describe('VideoPlaySkipControl', function() { var state, oldOTBD; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice').and.returnValue(null); @@ -12,7 +12,7 @@ spyOn(state.bumperState.videoCommands, 'execute'); }); - afterEach(function () { + afterEach(function() { $('source').remove(); state.storage.clear(); if (state.bumperState && state.bumperState.videoPlayer) { @@ -24,29 +24,29 @@ } }); - it('can render the control', function () { + it('can render the control', function() { expect($('.video_control.play')).toBeInDOM(); }); - it('can update state on play', function () { + it('can update state on play', function() { state.el.trigger('play'); expect($('.video_control.play')).not.toBeInDOM(); expect($('.video_control.skip')).toBeInDOM(); }); - it('can start video playing on click', function () { + it('can start video playing on click', function() { $('.video_control.play').click(); expect(state.bumperState.videoCommands.execute).toHaveBeenCalledWith('play'); }); - it('can skip the video on click', function () { + it('can skip the video on click', function() { state.el.trigger('play'); spyOn(state.bumperState.videoPlayer, 'isPlaying').and.returnValue(true); $('.video_control.skip').first().click(); expect(state.bumperState.videoCommands.execute).toHaveBeenCalledWith('skip'); }); - it('can destroy itself', function () { + it('can destroy itself', function() { var plugin = state.bumperState.videoPlaySkipControl, el = plugin.el; spyOn($.fn, 'off').and.callThrough(); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js index f5f15ba133..7588db9ba4 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js @@ -1,23 +1,23 @@ -(function (requirejs, require, define, undefined) { -'use strict'; +(function(requirejs, require, define, undefined) { + 'use strict'; -require( + require( ['video/03_video_player.js'], -function (VideoPlayer) { - describe('VideoPlayer', function () { +function(VideoPlayer) { + describe('VideoPlayer', function() { var state, oldOTBD, empty_arguments; - (function () { + (function() { empty_arguments = arguments; })(); - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') .and.returnValue(null); }); - afterEach(function () { + afterEach(function() { $('source').remove(); window.onTouchBasedDevice = oldOTBD; window.Video.previousState = null; @@ -29,40 +29,40 @@ function (VideoPlayer) { } }); - describe('constructor', function () { - describe('always', function () { - beforeEach(function () { + describe('constructor', function() { + describe('always', function() { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); }); - it('instanticate current time to zero', function () { + it('instanticate current time to zero', function() { expect(state.videoPlayer.currentTime).toEqual(0); }); - it('set the element', function () { + it('set the element', function() { expect(state.el).toHaveId('video_id'); }); - it('create video control', function () { + it('create video control', function() { expect(state.videoControl).toBeDefined(); expect(state.videoControl.el).toHaveClass('video-controls'); }); - it('create video caption', function () { + it('create video caption', function() { expect(state.videoCaption).toBeDefined(); expect(state.speed).toEqual('1.50'); expect(state.config.transcriptTranslationUrl) .toEqual('/transcript/translation/__lang__'); }); - it('create video speed control', function () { + it('create video speed control', function() { expect(state.videoSpeedControl).toBeDefined(); expect(state.videoSpeedControl.el).toHaveClass('speeds'); expect(state.speed).toEqual('1.50'); }); - it('create video progress slider', function () { + it('create video progress slider', function() { expect(state.videoProgressSlider).toBeDefined(); expect(state.videoProgressSlider.el).toHaveClass('slider'); }); @@ -73,7 +73,7 @@ function (VideoPlayer) { // previous version of Video. }); - it('create Youtube player', function () { + it('create Youtube player', function() { var events; jasmine.stubRequests(); @@ -82,10 +82,10 @@ function (VideoPlayer) { state.videoEl = $('video, iframe'); events = { - onReady: state.videoPlayer.onReady, - onStateChange: state.videoPlayer.onStateChange, + onReady: state.videoPlayer.onReady, + onStateChange: state.videoPlayer.onStateChange, onPlaybackQualityChange: state.videoPlayer.onPlaybackQualityChange, - onError: state.videoPlayer.onError + onError: state.videoPlayer.onError }; expect(YT.Player).toHaveBeenCalledWith('id', { @@ -104,7 +104,7 @@ function (VideoPlayer) { }); }); - it('create Flash player', function () { + it('create Flash player', function() { var player; spyOn($.fn, 'trigger'); @@ -138,9 +138,9 @@ function (VideoPlayer) { // available globally. It is defined within the scope of Require // JS. - describe('when on a touch based device', function () { - $.each(['iPad', 'Android'], function (index, device) { - it('create video volume control on' + device, function () { + describe('when on a touch based device', function() { + $.each(['iPad', 'Android'], function(index, device) { + it('create video volume control on' + device, function() { window.onTouchBasedDevice.and.returnValue([device]); state = jasmine.initializePlayer(); @@ -151,23 +151,23 @@ function (VideoPlayer) { }); }); - describe('when not on a touch based device', function () { + describe('when not on a touch based device', function() { var oldOTBD; - beforeEach(function () { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); }); - it('controls are in paused state', function () { + it('controls are in paused state', function() { expect(state.videoPlayer.isPlaying()).toBe(false); }); }); }); - describe('onReady', function () { - beforeEach(function () { + describe('onReady', function() { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); @@ -175,24 +175,24 @@ function (VideoPlayer) { state.videoPlayer.onReady(); }); - it('autoplay the first video', function () { + it('autoplay the first video', function() { expect(state.videoPlayer.play).not.toHaveBeenCalled(); }); - it('invalid endTime is reset to null', function () { + it('invalid endTime is reset to null', function() { expect(state.videoPlayer.endTime).toBe(null); }); }); - describe('onReady YouTube', function () { - beforeEach(function () { + describe('onReady YouTube', function() { + beforeEach(function() { state = jasmine.initializePlayerYouTube(); state.videoEl = $('video, iframe'); }); - it('multiple speeds and flash mode, change back to html5 mode', function () { + it('multiple speeds and flash mode, change back to html5 mode', function() { var playbackRates = state.videoPlayer.player.getAvailablePlaybackRates(); state.currentPlayerMode = 'flash'; @@ -202,9 +202,9 @@ function (VideoPlayer) { }); }); - describe('onStateChange Youtube', function(){ - describe('when the video is ended', function () { - beforeEach(function () { + describe('onStateChange Youtube', function() { + describe('when the video is ended', function() { + beforeEach(function() { state = jasmine.initializePlayerYouTube(); state.videoEl = $('video, iframe'); @@ -214,20 +214,20 @@ function (VideoPlayer) { }); }); - it('pause the video control', function () { + it('pause the video control', function() { expect($('.video_control')).toHaveClass('play'); }); - it('trigger pause and ended events', function () { + it('trigger pause and ended events', function() { expect($.fn.trigger).toHaveBeenCalledWith('pause', empty_arguments); expect($.fn.trigger).toHaveBeenCalledWith('ended', empty_arguments); }); }); }); - describe('onStateChange', function () { - describe('when the video is unstarted', function () { - beforeEach(function () { + describe('onStateChange', function() { + describe('when the video is unstarted', function() { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); spyOn($.fn, 'trigger').and.callThrough(); @@ -237,19 +237,19 @@ function (VideoPlayer) { }); }); - it('pause the video control', function () { + it('pause the video control', function() { expect($('.video_control')).toHaveClass('play'); }); - it('pause the video caption', function () { + it('pause the video caption', function() { expect($.fn.trigger).toHaveBeenCalledWith('pause', empty_arguments); }); }); - describe('when the video is playing', function () { + describe('when the video is playing', function() { var oldState; - beforeEach(function () { + beforeEach(function() { // Create the first instance of the player. state = jasmine.initializePlayer(); oldState = state; @@ -269,26 +269,26 @@ function (VideoPlayer) { }); }); - it('set update interval', function () { + it('set update interval', function() { expect(window.setInterval).toHaveBeenCalledWith( state.videoPlayer.update, 200 ); expect(state.videoPlayer.updateInterval).toEqual(100); }); - it('play the video control', function () { + it('play the video control', function() { expect($('.video_control')).toHaveClass('pause'); }); - it('play the video caption', function () { + it('play the video caption', function() { expect($.fn.trigger).toHaveBeenCalledWith('play', empty_arguments); }); }); - describe('when the video is paused', function () { + describe('when the video is paused', function() { var currentUpdateIntrval; - beforeEach(function () { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); @@ -305,21 +305,21 @@ function (VideoPlayer) { }); }); - it('clear update interval', function () { + it('clear update interval', function() { expect(state.videoPlayer.updateInterval).toBeUndefined(); }); - it('pause the video control', function () { + it('pause the video control', function() { expect($('.video_control')).toHaveClass('play'); }); - it('pause the video caption', function () { + it('pause the video caption', function() { expect($.fn.trigger).toHaveBeenCalledWith('pause', empty_arguments); }); }); - describe('when the video is ended', function () { - beforeEach(function () { + describe('when the video is ended', function() { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); @@ -329,45 +329,45 @@ function (VideoPlayer) { }); }); - it('pause the video control', function () { + it('pause the video control', function() { expect($('.video_control')).toHaveClass('play'); }); - it('pause the video caption', function () { + it('pause the video caption', function() { expect($.fn.trigger).toHaveBeenCalledWith('ended', empty_arguments); }); }); }); - describe('onSeek Youtube', function(){ - beforeEach(function () { + describe('onSeek Youtube', function() { + beforeEach(function() { state = jasmine.initializePlayerYouTube(); state.videoEl = $('video, iframe'); }); - describe('when the video is playing', function () { - beforeEach(function(){ - state.videoPlayer.onStateChange({ - data: YT.PlayerState.PLAYING - }); - }); + describe('when the video is playing', function() { + beforeEach(function() { + state.videoPlayer.onStateChange({ + data: YT.PlayerState.PLAYING + }); + }); - it('Video has started playing', function () { - expect($('.video_control')).toHaveClass('pause'); - }); + it('Video has started playing', function() { + expect($('.video_control')).toHaveClass('pause'); + }); - it('seek the player', function () { - state.videoPlayer.seekTo(10); - expect(state.videoPlayer.currentTime).toBe(10); - }); - }); + it('seek the player', function() { + state.videoPlayer.seekTo(10); + expect(state.videoPlayer.currentTime).toBe(10); + }); + }); }); - describe('onSeek', function () { - beforeEach(function () { + describe('onSeek', function() { + beforeEach(function() { // jasmine.Clock can't be used to fake out debounce with newer versions of underscore - spyOn(_, 'debounce').and.callFake(function (func) { - return function () { + spyOn(_, 'debounce').and.callFake(function(func) { + return function() { func.apply(this, arguments); }; }); @@ -376,8 +376,8 @@ function (VideoPlayer) { spyOn(state.videoPlayer, 'duration').and.returnValue(120); }); - describe('when the video is playing', function () { - beforeEach(function (done) { + describe('when the video is playing', function() { + beforeEach(function(done) { state.videoPlayer.play(); jasmine.waitUntil(function() { @@ -386,7 +386,7 @@ function (VideoPlayer) { }); - it('call runTimer in seekTo on player', function () { + it('call runTimer in seekTo on player', function() { spyOn(state.videoPlayer, 'stopTimer').and.callThrough(); spyOn(state.videoPlayer, 'runTimer').and.callThrough(); state.videoPlayer.seekTo(10); @@ -395,44 +395,44 @@ function (VideoPlayer) { expect(state.videoPlayer.runTimer).toHaveBeenCalled(); }); - it('seek the player', function () { + it('seek the player', function() { spyOn(state.videoPlayer.player, 'seekTo').and.callThrough(); state.videoProgressSlider.onSlide( - jQuery.Event('slide'), { value: 30 } + jQuery.Event('slide'), {value: 30} ); expect(state.videoPlayer.currentTime).toBe(30); expect(state.videoPlayer.player.seekTo).toHaveBeenCalledWith(30, true); }); - it('call updatePlayTime on player', function () { + it('call updatePlayTime on player', function() { spyOn(state.videoPlayer, 'updatePlayTime').and.callThrough(); state.videoProgressSlider.onSlide( - jQuery.Event('slide'), { value: 30 } + jQuery.Event('slide'), {value: 30} ); expect(state.videoPlayer.currentTime).toBe(30); expect(state.videoPlayer.updatePlayTime).toHaveBeenCalledWith(30, true); }); }); - it('when the player is not playing: set the current time', function () { + it('when the player is not playing: set the current time', function() { state.videoProgressSlider.onSlide( - jQuery.Event('slide'), { value: 20 } + jQuery.Event('slide'), {value: 20} ); state.videoPlayer.pause(); expect(state.videoPlayer.currentTime).toBe(20); state.videoProgressSlider.onSlide( - jQuery.Event('slide'), { value: 10 } + jQuery.Event('slide'), {value: 10} ); expect(state.videoPlayer.currentTime).toBe(10); }); - describe('when the video is not playing', function () { - beforeEach(function () { + describe('when the video is not playing', function() { + beforeEach(function() { spyOn(state.videoPlayer, 'setPlaybackRate') .and.callThrough(); }); - it('video has a correct speed', function () { + it('video has a correct speed', function() { state.speed = '2.0'; state.videoPlayer.onPlay(); expect(state.videoPlayer.setPlaybackRate) @@ -444,26 +444,26 @@ function (VideoPlayer) { }); }); - describe('onVolumeChange', function () { - beforeEach(function () { + describe('onVolumeChange', function() { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoPlayer.onReady(); state.videoEl = $('video, iframe'); }); - it('set the volume on player', function () { + it('set the volume on player', function() { spyOn(state.videoPlayer.player, 'setVolume'); state.videoPlayer.onVolumeChange(60); expect(state.videoPlayer.player.setVolume) .toHaveBeenCalledWith(60); }); - describe('when the video is not playing', function () { - beforeEach(function () { + describe('when the video is not playing', function() { + beforeEach(function() { state.videoPlayer.player.setVolume('1'); }); - it('video has a correct volume', function () { + it('video has a correct volume', function() { spyOn(state.videoPlayer.player, 'setVolume'); state.videoVolumeControl.volume = 26; state.el.trigger('play'); @@ -473,8 +473,8 @@ function (VideoPlayer) { }); }); - describe('update', function () { - beforeEach(function () { + describe('update', function() { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); @@ -484,44 +484,44 @@ function (VideoPlayer) { describe( 'when the current time is unavailable from the player', - function () + function() { - beforeEach(function () { - state.videoPlayer.player.getCurrentTime = function () { - return NaN; - }; - state.videoPlayer.update(); - }); + beforeEach(function() { + state.videoPlayer.player.getCurrentTime = function() { + return NaN; + }; + state.videoPlayer.update(); + }); - it('does not trigger updatePlayTime event', function () { - expect(state.videoPlayer.updatePlayTime) + it('does not trigger updatePlayTime event', function() { + expect(state.videoPlayer.updatePlayTime) .not.toHaveBeenCalled(); + }); }); - }); describe( 'when the current time is available from the player', - function () + function() { - beforeEach(function () { - state.videoPlayer.player.getCurrentTime = function () { - return 60; - }; - state.videoPlayer.update(); - }); + beforeEach(function() { + state.videoPlayer.player.getCurrentTime = function() { + return 60; + }; + state.videoPlayer.update(); + }); - it('trigger updatePlayTime event', function () { - expect(state.videoPlayer.updatePlayTime) + it('trigger updatePlayTime event', function() { + expect(state.videoPlayer.updatePlayTime) .toHaveBeenCalledWith(60); + }); }); - }); }); // Disabled 1/13/14 due to flakiness observed in master - xdescribe('update with start & end time', function () { + xdescribe('update with start & end time', function() { var START_TIME = 1, END_TIME = 2; - beforeEach(function () { + beforeEach(function() { state = jasmine.initializePlayer( { start: START_TIME, @@ -539,41 +539,41 @@ function (VideoPlayer) { it( 'video is paused on first endTime, start & end time are reset', - function (done) + function(done) { - var duration; + var duration; - state.videoProgressSlider.notifyThroughHandleEnd.calls.reset(); - state.videoPlayer.pause.calls.reset(); - state.videoPlayer.play(); + state.videoProgressSlider.notifyThroughHandleEnd.calls.reset(); + state.videoPlayer.pause.calls.reset(); + state.videoPlayer.play(); - jasmine.waitUntil(function () { - duration = Math.round(state.videoPlayer.currentTime); - return state.videoPlayer.pause.calls.count() === 1; - }).then(function () { - expect(state.videoPlayer.startTime).toBe(0); - expect(state.videoPlayer.endTime).toBe(null); + jasmine.waitUntil(function() { + duration = Math.round(state.videoPlayer.currentTime); + return state.videoPlayer.pause.calls.count() === 1; + }).then(function() { + expect(state.videoPlayer.startTime).toBe(0); + expect(state.videoPlayer.endTime).toBe(null); - expect(duration).toBe(END_TIME); + expect(duration).toBe(END_TIME); - expect(state.videoProgressSlider.notifyThroughHandleEnd) + expect(state.videoProgressSlider.notifyThroughHandleEnd) .toHaveBeenCalledWith({end: true}); - }).always(done); - }); + }).always(done); + }); }); - describe('updatePlayTime', function () { - beforeEach(function () { + describe('updatePlayTime', function() { + beforeEach(function() { state = jasmine.initializePlayerYouTube(); state.videoEl = $('video, iframe'); spyOn(state.videoCaption, 'updatePlayTime').and.callThrough(); spyOn(state.videoProgressSlider, 'updatePlayTime').and.callThrough(); }); - it('update the video playback time', function (done) { + it('update the video playback time', function(done) { var duration = 0; - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { duration = state.videoPlayer.duration(); if (duration > 0) { @@ -581,7 +581,7 @@ function (VideoPlayer) { } return false; - }).then(function () { + }).then(function() { state.videoPlayer.goToStartTime = false; state.videoPlayer.updatePlayTime(60); @@ -589,10 +589,10 @@ function (VideoPlayer) { }).always(done); }); - it('update the playback time on caption', function (done) { - jasmine.waitUntil(function () { + it('update the playback time on caption', function(done) { + jasmine.waitUntil(function() { return state.videoPlayer.duration() > 0; - }, 1000).then(function () { + }, 1000).then(function() { state.videoPlayer.goToStartTime = false; state.videoPlayer.updatePlayTime(60); @@ -601,14 +601,14 @@ function (VideoPlayer) { }).always(done); }); - it('update the playback time on progress slider', function (done) { + it('update the playback time on progress slider', function(done) { var duration = 0; - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { duration = state.videoPlayer.duration(); return duration > 0; - }, 1000).then(function () { + }, 1000).then(function() { state.videoPlayer.goToStartTime = false; state.videoPlayer.updatePlayTime(60); @@ -624,65 +624,65 @@ function (VideoPlayer) { // Disabled 1/13/14 due to flakiness observed in master xdescribe( 'updatePlayTime when start & end times are defined', - function () + function() { - var START_TIME = 1, - END_TIME = 2; + var START_TIME = 1, + END_TIME = 2; - beforeEach(function () { - state = jasmine.initializePlayer( - { - start: START_TIME, - end: END_TIME - } + beforeEach(function() { + state = jasmine.initializePlayer( + { + start: START_TIME, + end: END_TIME + } ); - state.videoEl = $('video, iframe'); + state.videoEl = $('video, iframe'); - spyOn(state.videoPlayer, 'updatePlayTime').and.callThrough(); - spyOn(state.videoPlayer.player, 'seekTo').and.callThrough(); - spyOn(state.videoProgressSlider, 'updateStartEndTimeRegion') + spyOn(state.videoPlayer, 'updatePlayTime').and.callThrough(); + spyOn(state.videoPlayer.player, 'seekTo').and.callThrough(); + spyOn(state.videoProgressSlider, 'updateStartEndTimeRegion') .and.callThrough(); - }); + }); - it( + it( 'when duration becomes available, updatePlayTime() is called', - function (done) + function(done) { - var duration; + var duration; - expect(state.videoPlayer.initialSeekToStartTime).toBeTruthy(); - expect(state.videoPlayer.seekToStartTimeOldSpeed).toBe('void'); + expect(state.videoPlayer.initialSeekToStartTime).toBeTruthy(); + expect(state.videoPlayer.seekToStartTimeOldSpeed).toBe('void'); - state.videoPlayer.play(); + state.videoPlayer.play(); - jasmine.waitUntil(function () { - duration = state.videoPlayer.duration(); + jasmine.waitUntil(function() { + duration = state.videoPlayer.duration(); - return state.videoPlayer.isPlaying() && + return state.videoPlayer.isPlaying() && state.videoPlayer.initialSeekToStartTime === false; - }).then(function () { - expect(state.videoPlayer.startTime).toBe(START_TIME); - expect(state.videoPlayer.endTime).toBe(END_TIME); + }).then(function() { + expect(state.videoPlayer.startTime).toBe(START_TIME); + expect(state.videoPlayer.endTime).toBe(END_TIME); - expect(state.videoPlayer.player.seekTo) + expect(state.videoPlayer.player.seekTo) .toHaveBeenCalledWith(START_TIME); - expect(state.videoProgressSlider.updateStartEndTimeRegion) + expect(state.videoProgressSlider.updateStartEndTimeRegion) .toHaveBeenCalledWith({duration: duration}); - expect(state.videoPlayer.seekToStartTimeOldSpeed) + expect(state.videoPlayer.seekToStartTimeOldSpeed) .toBe(state.speed); - }).always(done); + }).always(done); + }); }); - }); - describe('updatePlayTime with invalid endTime', function () { - beforeEach(function () { + describe('updatePlayTime with invalid endTime', function() { + beforeEach(function() { state = { el: $('#video_id'), videoPlayer: { - duration: function () { + duration: function() { // The video will be 60 seconds long. return 60; }, @@ -690,7 +690,7 @@ function (VideoPlayer) { startTime: undefined, endTime: undefined, player: { - seekTo: function () {} + seekTo: function() {} }, figureOutStartEndTime: jasmine.createSpy(), figureOutStartingTime: jasmine.createSpy().and.returnValue(0) @@ -706,35 +706,35 @@ function (VideoPlayer) { endTime: 10000 }, currentPlayerMode: 'html5', - trigger: function () {}, + trigger: function() {}, browserIsFirefox: false, isFlashMode: jasmine.createSpy().and.returnValue(false) }; }); }); - describe('toggleFullScreen', function () { - describe('when the video player is not full screen', function () { - beforeEach(function () { + describe('toggleFullScreen', function() { + describe('when the video player is not full screen', function() { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); spyOn($.fn, 'trigger').and.callThrough(); $('.add-fullscreen').click(); }); - it('add the video-fullscreen class', function () { + it('add the video-fullscreen class', function() { expect(state.el).toHaveClass('video-fullscreen'); }); - it('tell VideoCaption to resize', function () { + it('tell VideoCaption to resize', function() { expect($.fn.trigger).toHaveBeenCalledWith('fullscreen', [true]); expect(state.resizer.setMode).toHaveBeenCalledWith('both'); expect(state.resizer.delta.substract).toHaveBeenCalled(); }); }); - describe('when the video player already full screen', function () { - beforeEach(function () { + describe('when the video player already full screen', function() { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); spyOn($.fn, 'trigger').and.callThrough(); @@ -745,11 +745,11 @@ function (VideoPlayer) { $('.add-fullscreen').click(); }); - it('remove the video-fullscreen class', function () { + it('remove the video-fullscreen class', function() { expect(state.el).not.toHaveClass('video-fullscreen'); }); - it('tell VideoCaption to resize', function () { + it('tell VideoCaption to resize', function() { expect($.fn.trigger).toHaveBeenCalledWith('fullscreen', [false]); expect(state.resizer.setMode) .toHaveBeenCalledWith('width'); @@ -758,8 +758,8 @@ function (VideoPlayer) { }); }); - describe('duration', function () { - beforeEach(function () { + describe('duration', function() { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); @@ -768,13 +768,13 @@ function (VideoPlayer) { state.videoPlayer.duration(); }); - it('delegate to the player', function () { + it('delegate to the player', function() { expect(state.videoPlayer.player.getDuration).toHaveBeenCalled(); }); }); - describe('getDuration', function () { - beforeEach(function () { + describe('getDuration', function() { + beforeEach(function() { // We need to make sure that metadata is returned via an AJAX // request. Without the jasmine.stubRequests() below we will // get the error: @@ -793,15 +793,15 @@ function (VideoPlayer) { state.videoPlayer.player.getDuration.and.returnValue(0); }); - it('getDuration is called as a fall-back', function () { + it('getDuration is called as a fall-back', function() { state.videoPlayer.duration(); expect(state.getDuration).toHaveBeenCalled(); }); }); - describe('volume', function () { - beforeEach(function () { + describe('volume', function() { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoEl = $('video, iframe'); @@ -809,33 +809,33 @@ function (VideoPlayer) { spyOn(state.videoPlayer.player, 'getVolume').and.callThrough(); }); - it('set the player volume', function () { + it('set the player volume', function() { var expectedValue = 60, - realValue; + realValue; state.videoPlayer.player.setVolume(60); - realValue = Math.round(state.videoPlayer.player.getVolume()*100); + realValue = Math.round(state.videoPlayer.player.getVolume() * 100); expect(realValue).toEqual(expectedValue); }); }); - describe('on Touch devices', function () { - it('`is-touch` class name is added to container', function () { + describe('on Touch devices', function() { + it('`is-touch` class name is added to container', function() { $.each( ['iPad', 'Android', 'iPhone'], - function (index, device) + function(index, device) { - window.onTouchBasedDevice.and.returnValue([device]); - state = jasmine.initializePlayer(); + window.onTouchBasedDevice.and.returnValue([device]); + state = jasmine.initializePlayer(); - state.videoEl = $('video, iframe'); + state.videoEl = $('video, iframe'); - expect(state.el).toHaveClass('is-touch'); - }); + expect(state.el).toHaveClass('is-touch'); + }); }); - it('modules are not initialized on iPhone', function () { + it('modules are not initialized on iPhone', function() { window.onTouchBasedDevice.and.returnValue(['iPhone']); state = jasmine.initializePlayer(); @@ -846,16 +846,16 @@ function (VideoPlayer) { state.videoSpeedControl, state.videoVolumeControl ]; - $.each(modules, function (index, module) { + $.each(modules, function(index, module) { expect(module).toBeUndefined(); }); }); - $.each(['iPad', 'Android'], function (index, device) { + $.each(['iPad', 'Android'], function(index, device) { var message = 'controls become visible after playing starts ' + 'on ' + device; - it(message, function (done) { + it(message, function(done) { var controls; window.onTouchBasedDevice.and.returnValue([device]); @@ -864,17 +864,17 @@ function (VideoPlayer) { state.videoEl = $('video, iframe'); controls = state.el.find('.video-controls'); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { return state.el.hasClass('is-initialized'); - }).then(function () { + }).then(function() { expect(controls).toHaveClass('is-hidden'); state.videoPlayer.play(); - jasmine.waitUntil(function () { + jasmine.waitUntil(function() { // Firefox does not return duration for videos until they have reached the end. // var duration = state.videoPlayer.duration(); // return duration > 0 && state.videoPlayer.isPlaying(); return state.videoPlayer.isPlaying(); - }).then(function () { + }).then(function() { expect(controls).not.toHaveClass('is-hidden'); }).always(done); }); @@ -882,8 +882,8 @@ function (VideoPlayer) { }); }); - describe('onSpeedChange', function () { - beforeEach(function () { + describe('onSpeedChange', function() { + beforeEach(function() { state = { el: $(document), speed: '1.50', @@ -899,14 +899,14 @@ function (VideoPlayer) { }; }); - describe('always', function () { - it('convert the current time to the new speed', function () { + describe('always', function() { + it('convert the current time to the new speed', function() { state.isFlashMode.and.returnValue(true); VideoPlayer.prototype.onSpeedChange.call(state, '0.75', false); expect(state.videoPlayer.currentTime).toBe('120.000'); }); - it('set video speed to the new speed', function () { + it('set video speed to the new speed', function() { VideoPlayer.prototype.onSpeedChange.call(state, '0.75', false); expect(state.setSpeed).toHaveBeenCalledWith('0.75'); expect(state.videoPlayer.setPlaybackRate) @@ -915,8 +915,8 @@ function (VideoPlayer) { }); }); - describe('setPlaybackRate', function () { - beforeEach(function () { + describe('setPlaybackRate', function() { + beforeEach(function() { state = { youtubeId: jasmine.createSpy().and.returnValue('videoId'), isFlashMode: jasmine.createSpy().and.returnValue(false), @@ -938,7 +938,7 @@ function (VideoPlayer) { }; }); - it('in Flash mode and video is playing', function () { + it('in Flash mode and video is playing', function() { state.isFlashMode.and.returnValue(true); state.isHtml5Mode.and.returnValue(false); state.videoPlayer.isPlaying.and.returnValue(true); @@ -948,7 +948,7 @@ function (VideoPlayer) { .toHaveBeenCalledWith('videoId', 60); }); - it('in Flash mode and video not started', function () { + it('in Flash mode and video not started', function() { state.isFlashMode.and.returnValue(true); state.isHtml5Mode.and.returnValue(false); state.videoPlayer.isPlaying.and.returnValue(false); @@ -964,13 +964,13 @@ function (VideoPlayer) { .toHaveBeenCalledWith('videoId', 60); }); - it('in HTML5 mode', function () { + it('in HTML5 mode', function() { state.isYoutubeType.and.returnValue(false); VideoPlayer.prototype.setPlaybackRate.call(state, '0.75'); expect(state.videoPlayer.player.setPlaybackRate).toHaveBeenCalledWith('0.75'); }); - it('Youtube video in FF, with new speed equal 1.0', function () { + it('Youtube video in FF, with new speed equal 1.0', function() { state.browserIsFirefox = true; state.videoPlayer.isPlaying.and.returnValue(false); @@ -982,5 +982,4 @@ function (VideoPlayer) { }); }); }); - }(RequireJS.requirejs, RequireJS.require, RequireJS.define)); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_poster_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_poster_spec.js index d2505a11c7..88e4554524 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_poster_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_poster_spec.js @@ -1,16 +1,16 @@ -(function (WAIT_TIMEOUT) { +(function(WAIT_TIMEOUT) { 'use strict'; - describe('VideoPoster', function () { + describe('VideoPoster', function() { var state, oldOTBD; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice').and.returnValue(null); state = jasmine.initializePlayer('video_with_bumper.html'); }); - afterEach(function () { + afterEach(function() { $('source').remove(); state.storage.clear(); if (state.bumperState && state.bumperState.videoPlayer) { @@ -22,19 +22,19 @@ window.onTouchBasedDevice = oldOTBD; }); - it('can render the poster', function () { + it('can render the poster', function() { expect($('.poster')).toExist(); expect($('.btn-play')).toExist(); }); - it('can start playing the video on click', function (done) { + it('can start playing the video on click', function(done) { $('.btn-play').click(); jasmine.waitUntil(function() { return state.el.hasClass('is-playing'); }).done(done); }); - it('destroy itself on "play" event', function () { + it('destroy itself on "play" event', function() { $('.btn-play').click(); expect($('.poster')).not.toExist(); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js index a9032669ab..1f3d5f728d 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_progress_slider_spec.js @@ -1,29 +1,29 @@ -(function (undefined) { - describe('VideoProgressSlider', function () { +(function(undefined) { + describe('VideoProgressSlider', function() { var state, oldOTBD; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') .and.returnValue(null); }); - afterEach(function () { + afterEach(function() { $('source').remove(); window.onTouchBasedDevice = oldOTBD; state.storage.clear(); state.videoPlayer.destroy(); }); - describe('constructor', function () { - describe('on a non-touch based device', function () { - beforeEach(function () { + describe('constructor', function() { + describe('on a non-touch based device', function() { + beforeEach(function() { spyOn($.fn, 'slider').and.callThrough(); state = jasmine.initializePlayer(); }); - it('build the slider', function () { + it('build the slider', function() { expect($('.slider')).toContain(state.videoProgressSlider.slider); expect($.fn.slider).toHaveBeenCalledWith({ range: 'min', @@ -34,12 +34,12 @@ }); }); - it('build the seek handle', function () { + it('build the seek handle', function() { expect($('.ui-slider-handle')) .toContain(state.videoProgressSlider.handle); }); - it('add ARIA attributes to time control', function () { + it('add ARIA attributes to time control', function() { var timeControl = $('div.slider > .progress-handle'); expect(timeControl).toHaveAttrs({ @@ -52,9 +52,8 @@ }); }); - describe('on a touch-based device', function () { - it('does not build the slider on iPhone', function () { - + describe('on a touch-based device', function() { + it('does not build the slider on iPhone', function() { window.onTouchBasedDevice.and.returnValue(['iPhone']); state = jasmine.initializePlayer(); @@ -64,8 +63,8 @@ // We can't expect $.fn.slider not to have been called, // because sliders are used in other parts of Video. }); - $.each(['iPad', 'Android'], function (index, device) { - it('build the slider on ' + device, function () { + $.each(['iPad', 'Android'], function(index, device) { + it('build the slider on ' + device, function() { window.onTouchBasedDevice.and.returnValue([device]); state = jasmine.initializePlayer(); @@ -76,21 +75,21 @@ }); }); - describe('play', function () { - beforeEach(function () { + describe('play', function() { + beforeEach(function() { state = jasmine.initializePlayer(); }); - describe('when the slider was already built', function () { + describe('when the slider was already built', function() { var spy; - beforeEach(function () { + beforeEach(function() { spy = spyOn(state.videoProgressSlider, 'buildSlider'); spy.and.callThrough(); state.videoPlayer.play(); }); - it('does not build the slider', function () { + it('does not build the slider', function() { expect(spy.calls.count()).toEqual(0); }); }); @@ -98,25 +97,25 @@ // Currently, the slider is not rebuilt if it does not exist. }); - describe('updatePlayTime', function () { - beforeEach(function () { + describe('updatePlayTime', function() { + beforeEach(function() { state = jasmine.initializePlayer(); }); - describe('when frozen', function () { - beforeEach(function () { + describe('when frozen', function() { + beforeEach(function() { spyOn($.fn, 'slider').and.callThrough(); state.videoProgressSlider.frozen = true; state.videoProgressSlider.updatePlayTime(20, 120); }); - it('does not update the slider', function () { + it('does not update the slider', function() { expect($.fn.slider).not.toHaveBeenCalled(); }); }); - describe('when not frozen', function () { - beforeEach(function () { + describe('when not frozen', function() { + beforeEach(function() { spyOn($.fn, 'slider').and.callThrough(); state.videoProgressSlider.frozen = false; state.videoProgressSlider.updatePlayTime({ @@ -125,27 +124,27 @@ }); }); - it('update the max value of the slider', function () { + it('update the max value of the slider', function() { expect($.fn.slider).toHaveBeenCalledWith( 'option', 'max', 120 ); }); - it('update current value of the slider', function () { + it('update current value of the slider', function() { expect($.fn.slider).toHaveBeenCalledWith( 'option', 'value', 20 ); }); - it('required aria values updated', function () { + it('required aria values updated', function() { expect(state.videoProgressSlider.handle.attr('aria-valuenow')).toBe('20'); expect(state.videoProgressSlider.handle.attr('aria-valuemax')).toBe('120'); }); }); }); - describe('onSlide', function () { - beforeEach(function () { + describe('onSlide', function() { + beforeEach(function() { state = jasmine.initializePlayer(); spyOn($.fn, 'slider').and.callThrough(); @@ -153,27 +152,26 @@ }); // Disabled 12/30/13 due to flakiness in master - xit('freeze the slider', function () { + xit('freeze the slider', function() { state.videoProgressSlider.onSlide( - jQuery.Event('slide'), { value: 20 } + jQuery.Event('slide'), {value: 20} ); expect(state.videoProgressSlider.frozen).toBeTruthy(); }); // Disabled 12/30/13 due to flakiness in master - xit('trigger seek event', function () { + xit('trigger seek event', function() { state.videoProgressSlider.onSlide( - jQuery.Event('slide'), { value: 20 } + jQuery.Event('slide'), {value: 20} ); expect(state.videoPlayer.onSlideSeek).toHaveBeenCalled(); }); }); - describe('onStop', function () { - - beforeEach(function () { + describe('onStop', function() { + beforeEach(function() { jasmine.clock().install(); state = jasmine.initializePlayer(); @@ -181,32 +179,32 @@ spyOn(state.videoPlayer, 'onSlideSeek').and.callThrough(); }); - afterEach(function () { + afterEach(function() { jasmine.clock().uninstall(); }); // Disabled 12/30/13 due to flakiness in master - xit('freeze the slider', function () { + xit('freeze the slider', function() { state.videoProgressSlider.onStop( - jQuery.Event('stop'), { value: 20 } + jQuery.Event('stop'), {value: 20} ); expect(state.videoProgressSlider.frozen).toBeTruthy(); }); // Disabled 12/30/13 due to flakiness in master - xit('trigger seek event', function () { + xit('trigger seek event', function() { state.videoProgressSlider.onStop( - jQuery.Event('stop'), { value: 20 } + jQuery.Event('stop'), {value: 20} ); expect(state.videoPlayer.onSlideSeek).toHaveBeenCalled(); }); // Disabled 12/30/13 due to flakiness in master - xit('set timeout to unfreeze the slider', function () { + xit('set timeout to unfreeze the slider', function() { state.videoProgressSlider.onStop( - jQuery.Event('stop'), { value: 20 } + jQuery.Event('stop'), {value: 20} ); jasmine.clock().tick(200); @@ -215,31 +213,31 @@ }); }); - it('getRangeParams' , function () { + it('getRangeParams', function() { var testCases = [ - { - startTime: 10, - endTime: 20, - duration: 150 - }, - { - startTime: 90, - endTime: 100, - duration: 100 - }, - { - startTime: 0, - endTime: 200, - duration: 200 - } - ]; + { + startTime: 10, + endTime: 20, + duration: 150 + }, + { + startTime: 90, + endTime: 100, + duration: 100 + }, + { + startTime: 0, + endTime: 200, + duration: 200 + } + ]; state = jasmine.initializePlayer(); - $.each(testCases, function (index, testCase) { - var step = 100/testCase.duration, - left = testCase.startTime*step, - width = testCase.endTime*step - left, + $.each(testCases, function(index, testCase) { + var step = 100 / testCase.duration, + left = testCase.startTime * step, + width = testCase.endTime * step - left, expectedParams = { left: left + '%', width: width + '%' @@ -252,8 +250,8 @@ }); }); - describe('notifyThroughHandleEnd', function () { - beforeEach(function () { + describe('notifyThroughHandleEnd', function() { + beforeEach(function() { state = jasmine.initializePlayer(); spyOnEvent(state.videoProgressSlider.handle, 'focus'); @@ -261,7 +259,7 @@ .and.callThrough(); }); - it('params.end = true', function () { + it('params.end = true', function() { state.videoProgressSlider.notifyThroughHandleEnd({end: true}); expect(state.videoProgressSlider.handle.attr('title')) @@ -272,7 +270,7 @@ ); }); - it('params.end = false', function () { + it('params.end = false', function() { state.videoProgressSlider.notifyThroughHandleEnd({end: false}); expect(state.videoProgressSlider.handle.attr('title')) @@ -283,18 +281,17 @@ ); }); - it('is called when video plays', function (done) { + it('is called when video plays', function(done) { state.videoPlayer.play(); jasmine.waitUntil(function() { return state.videoPlayer.isPlaying(); }).done(function() { expect(state.videoProgressSlider.notifyThroughHandleEnd).toHaveBeenCalledWith({end: false}); }).always(done); - }); }); - it('getTimeDescription', function () { + it('getTimeDescription', function() { var cases = { '0': '0 seconds', '1': '1 second', @@ -304,7 +301,7 @@ '121': '2 minutes 1 second', '3670': '1 hour 1 minute 10 seconds', - '21541': '5 hours 59 minutes 1 second', + '21541': '5 hours 59 minutes 1 second' }, getTimeDescription; @@ -317,13 +314,11 @@ }); }); - it('can destroy itself', function () { + it('can destroy itself', function() { state = jasmine.initializePlayer(); state.videoProgressSlider.destroy(); expect(state.videoProgressSlider).toBeUndefined(); expect($('.slider')).toBeEmpty(); }); - }); - }).call(this); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js index 251c59e8fa..5ddbe7274c 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_quality_control_spec.js @@ -1,8 +1,8 @@ -(function (undefined) { - describe('VideoQualityControl', function () { +(function(undefined) { + describe('VideoQualityControl', function() { var state, qualityControl, videoPlayer, player; - afterEach(function () { + afterEach(function() { $('source').remove(); if (state.storage) { state.storage.clear(); @@ -10,34 +10,34 @@ state.videoPlayer.destroy(); }); - describe('constructor, YouTube mode', function () { - beforeEach(function () { - state = jasmine.initializePlayerYouTube(); + describe('constructor, YouTube mode', function() { + beforeEach(function() { + state = jasmine.initializePlayerYouTube(); qualityControl = state.videoQualityControl; videoPlayer = state.videoPlayer; player = videoPlayer.player; // Define empty methods in YouTube stub player.quality = 'large'; - player.setPlaybackQuality.and.callFake(function (quality){ + player.setPlaybackQuality.and.callFake(function(quality) { player.quality = quality; }); }); it('contains the quality control and is initially hidden', - function () { - expect(qualityControl.el).toHaveClass( + function() { + expect(qualityControl.el).toHaveClass( 'quality-control is-hidden' ); - }); + }); - it('add ARIA attributes to quality control', function () { + it('add ARIA attributes to quality control', function() { expect(qualityControl.el).toHaveAttrs({ 'aria-disabled': 'false' }); }); - it('bind the quality control', function () { + it('bind the quality control', function() { expect(qualityControl.el).toHandleWith('click', qualityControl.toggleQuality ); @@ -45,7 +45,7 @@ expect(state.el).toHandle('play'); }); - it('calls fetchAvailableQualities only once', function () { + it('calls fetchAvailableQualities only once', function() { expect(player.getAvailableQualityLevels.calls.count()) .toEqual(0); @@ -56,30 +56,30 @@ .toEqual(1); }); - it('initializes with a quality equal to large', function () { + it('initializes with a quality equal to large', function() { videoPlayer.onPlay(); expect(player.setPlaybackQuality).toHaveBeenCalledWith('large'); }); it('shows the quality control on play if HD is available', - function () { - videoPlayer.onPlay(); + function() { + videoPlayer.onPlay(); - expect(qualityControl.el).not.toHaveClass('is-hidden'); - }); + expect(qualityControl.el).not.toHaveClass('is-hidden'); + }); it('leaves quality control hidden on play if HD is not available', - function () { - player.getAvailableQualityLevels.and.returnValue( + function() { + player.getAvailableQualityLevels.and.returnValue( ['large', 'medium', 'small'] ); - videoPlayer.onPlay(); - expect(qualityControl.el).toHaveClass('is-hidden'); - }); + videoPlayer.onPlay(); + expect(qualityControl.el).toHaveClass('is-hidden'); + }); - it('switch to HD if it is available', function () { + it('switch to HD if it is available', function() { videoPlayer.onPlay(); qualityControl.quality = 'large'; @@ -93,27 +93,27 @@ }); it('quality control is active if HD is available', - function () { - player.getAvailableQualityLevels.and.returnValue( + function() { + player.getAvailableQualityLevels.and.returnValue( ['highres', 'hd1080', 'hd720'] ); - qualityControl.quality = 'highres'; + qualityControl.quality = 'highres'; - videoPlayer.onPlay(); - expect(qualityControl.el).toHaveClass('active'); - }); + videoPlayer.onPlay(); + expect(qualityControl.el).toHaveClass('active'); + }); - it('can destroy itself', function () { + it('can destroy itself', function() { state.videoQualityControl.destroy(); expect(state.videoQualityControl).toBeUndefined(); expect($('.quality-control')).not.toExist(); }); }); - describe('constructor, HTML5 mode', function () { - it('does not contain the quality control', function () { - state = jasmine.initializePlayer(); + describe('constructor, HTML5 mode', function() { + it('does not contain the quality control', function() { + state = jasmine.initializePlayer(); expect(state.el.find('.quality-control').length).toBe(0); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_save_state_plugin_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_save_state_plugin_spec.js index 42cdc1dcc8..75fec2555f 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_save_state_plugin_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_save_state_plugin_spec.js @@ -1,9 +1,9 @@ -(function (undefined) { +(function(undefined) { 'use strict'; - describe('VideoPlayer Save State plugin', function () { + describe('VideoPlayer Save State plugin', function() { var state, oldOTBD; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice') @@ -15,8 +15,7 @@ spyOn(state.storage, 'setItem'); }); - afterEach(function () { - + afterEach(function() { $('source').remove(); window.onTouchBasedDevice = oldOTBD; state.storage.clear(); @@ -25,7 +24,7 @@ } }); - describe('saveState function', function () { + describe('saveState function', function() { var videoPlayerCurrentTime, newCurrentTime, speed; // We make sure that `currentTime` is a float. We need to test @@ -41,12 +40,12 @@ newCurrentTime = 5.4; speed = '0.75'; - beforeEach(function () { + beforeEach(function() { state.videoPlayer.currentTime = videoPlayerCurrentTime; spyOn(window.Time, 'formatFull').and.callThrough(); }); - it('data is not an object, async is true', function () { + it('data is not an object, async is true', function() { itSpec({ asyncVal: true, speedVal: undefined, @@ -58,7 +57,7 @@ }); }); - it('data contains speed, async is false', function () { + it('data contains speed, async is false', function() { itSpec({ asyncVal: false, speedVal: speed, @@ -72,7 +71,7 @@ }); }); - it('data contains float position, async is true', function () { + it('data contains float position, async is true', function() { itSpec({ asyncVal: true, speedVal: undefined, @@ -86,7 +85,7 @@ }); }); - it('data contains speed and rounded position, async is false', function () { + it('data contains speed and rounded position, async is false', function() { itSpec({ asyncVal: false, speedVal: speed, @@ -102,7 +101,7 @@ }); }); - it('data contains empty object, async is true', function () { + it('data contains empty object, async is true', function() { itSpec({ asyncVal: true, speedVal: undefined, @@ -112,7 +111,7 @@ }); }); - it('data contains position 0, async is true', function () { + it('data contains position 0, async is true', function() { itSpec({ asyncVal: true, speedVal: undefined, @@ -127,11 +126,11 @@ }); function itSpec(value) { - var asyncVal = value.asyncVal, - speedVal = value.speedVal, + var asyncVal = value.asyncVal, + speedVal = value.speedVal, positionVal = value.positionVal, - data = value.data, - ajaxData = value.ajaxData; + data = value.data, + ajaxData = value.ajaxData; state.videoSaveStatePlugin.saveState(asyncVal, data); @@ -162,7 +161,7 @@ } }); - it('can save state on speed change', function () { + it('can save state on speed change', function() { state.el.trigger('speedchange', ['2.0']); expect($.ajax).toHaveBeenCalledWith({ url: state.config.saveStateUrl, @@ -173,7 +172,7 @@ }); }); - it('can save state on page unload', function () { + it('can save state on page unload', function() { $.ajax.calls.reset(); state.videoSaveStatePlugin.onUnload(); expect($.ajax).toHaveBeenCalledWith({ @@ -185,7 +184,7 @@ }); }); - it('can save state on pause', function () { + it('can save state on pause', function() { state.el.trigger('pause'); expect($.ajax).toHaveBeenCalledWith({ url: state.config.saveStateUrl, @@ -196,12 +195,12 @@ }); }); - it('can save state on language change', function () { + it('can save state on language change', function() { state.el.trigger('language_menu:change', ['ua']); expect(state.storage.setItem).toHaveBeenCalledWith('language', 'ua'); }); - it('can save youtube availability', function () { + it('can save youtube availability', function() { $.ajax.calls.reset(); // Test the cases where we shouldn't send anything at all -- client @@ -236,7 +235,7 @@ }); }); - it('can destroy itself', function () { + it('can destroy itself', function() { var plugin = state.videoSaveStatePlugin; spyOn($.fn, 'off').and.callThrough(); state.videoSaveStatePlugin.destroy(); @@ -252,5 +251,4 @@ expect($.fn.off).toHaveBeenCalledWith('unload', plugin.onUnload); }); }); - }).call(this); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_skip_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_skip_control_spec.js index 2438dce8a2..91cd34dd21 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_skip_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_skip_control_spec.js @@ -1,9 +1,9 @@ -(function () { +(function() { 'use strict'; - describe('VideoSkipControl', function () { + describe('VideoSkipControl', function() { var state, oldOTBD; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine .createSpy('onTouchBasedDevice').and.returnValue(null); @@ -12,7 +12,7 @@ spyOn(state.bumperState.videoCommands, 'execute').and.callThrough(); }); - afterEach(function () { + afterEach(function() { $('source').remove(); state.storage.clear(); if (state.bumperState && state.bumperState.videoPlayer) { @@ -24,13 +24,13 @@ window.onTouchBasedDevice = oldOTBD; }); - it('can render the control when video starts playing', function () { + it('can render the control when video starts playing', function() { expect($('.skip-control')).not.toExist(); state.el.trigger('play'); expect($('.skip-control')).toExist(); }); - it('can skip the video on click', function () { + it('can skip the video on click', function() { spyOn(state.bumperState.videoBumper, 'skipAndDoNotShowAgain'); state.el.trigger('play'); $('.skip-control').click(); @@ -38,7 +38,7 @@ expect(state.bumperState.videoBumper.skipAndDoNotShowAgain).toHaveBeenCalled(); }); - it('can destroy itself', function () { + it('can destroy itself', function() { state.bumperState.videoPlaySkipControl.destroy(); expect(state.bumperState.videoPlaySkipControl).toBeUndefined(); }); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js index f73b1f3c59..7359be0371 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_speed_control_spec.js @@ -1,28 +1,28 @@ -(function (undefined) { +(function(undefined) { 'use strict'; - describe('VideoSpeedControl', function () { + describe('VideoSpeedControl', function() { var state, oldOTBD; - beforeEach(function () { + beforeEach(function() { oldOTBD = window.onTouchBasedDevice; window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') .and.returnValue(null); }); - afterEach(function () { + afterEach(function() { $('source').remove(); window.onTouchBasedDevice = oldOTBD; state.storage.clear(); state.videoPlayer.destroy(); }); - describe('constructor', function () { - describe('always', function () { - beforeEach(function () { + describe('constructor', function() { + describe('always', function() { + beforeEach(function() { state = jasmine.initializePlayer(); }); - it('add the video speed control to player', function () { + it('add the video speed control to player', function() { var secondaryControls = $('.secondary-controls'), li = secondaryControls.find('.video-speeds li'); @@ -35,7 +35,7 @@ ); expect(li.length).toBe(state.speeds.length); - $.each(li.toArray().reverse(), function (index, link) { + $.each(li.toArray().reverse(), function(index, link) { expect($(link).attr('data-speed')).toEqual(state.speeds[index]); expect($(link).find('.speed-option').text()).toBe( state.speeds[index] + 'x' @@ -44,9 +44,9 @@ }); }); - describe('when running on touch based device', function () { - $.each(['iPad', 'Android'], function (index, device) { - it('is not rendered on' + device, function () { + describe('when running on touch based device', function() { + $.each(['iPad', 'Android'], function(index, device) { + it('is not rendered on' + device, function() { window.onTouchBasedDevice.and.returnValue([device]); state = jasmine.initializePlayer(); @@ -55,7 +55,7 @@ }); }); - describe('when running on non-touch based device', function () { + describe('when running on non-touch based device', function() { var speedControl, speedEntries, speedButton, speedsContainer, KEY = $.ui.keyCode, @@ -63,7 +63,7 @@ return $.Event('keydown', {keyCode: key}); }; - beforeEach(function () { + beforeEach(function() { state = jasmine.initializePlayer(); speedControl = $('.speeds'); speedButton = $('.speed-button'); @@ -72,67 +72,67 @@ }); it('open/close the speed menu on mouseenter/mouseleave', - function () { - speedControl.mouseenter(); - expect(speedControl).toHaveClass('is-opened'); - speedControl.mouseleave(); - expect(speedControl).not.toHaveClass('is-opened'); - }); + function() { + speedControl.mouseenter(); + expect(speedControl).toHaveClass('is-opened'); + speedControl.mouseleave(); + expect(speedControl).not.toHaveClass('is-opened'); + }); it('do not close the speed menu on mouseleave if a speed ' + - 'entry has focus', function () { + 'entry has focus', function() { // Open speed meenu. Focus is on last speed entry. speedControl.trigger(keyPressEvent(KEY.ENTER)); speedControl.mouseenter().mouseleave(); expect(speedControl).toHaveClass('is-opened'); }); - it('close the speed menu on outside click', function () { + it('close the speed menu on outside click', function() { speedControl.trigger(keyPressEvent(KEY.ENTER)); $(window).click(); expect(speedControl).not.toHaveClass('is-opened'); }); - it('open the speed menu on ENTER keydown', function () { + it('open the speed menu on ENTER keydown', function() { speedControl.trigger(keyPressEvent(KEY.ENTER)); expect(speedControl).toHaveClass('is-opened'); expect(speedEntries.last()).toBeFocused(); }); - it('open the speed menu on SPACE keydown', function () { + it('open the speed menu on SPACE keydown', function() { speedControl.trigger(keyPressEvent(KEY.SPACE)); expect(speedControl).toHaveClass('is-opened'); expect(speedEntries.last()).toBeFocused(); }); - it('open the speed menu on UP keydown', function () { + it('open the speed menu on UP keydown', function() { speedControl.trigger(keyPressEvent(KEY.UP)); expect(speedControl).toHaveClass('is-opened'); expect(speedEntries.last()).toBeFocused(); }); - it('close the speed menu on ESCAPE keydown', function () { + it('close the speed menu on ESCAPE keydown', function() { speedControl.trigger(keyPressEvent(KEY.ESCAPE)); expect(speedControl).not.toHaveClass('is-opened'); }); it('UP and DOWN keydown function as expected on speed entries', - function () { - var speed_0_75 = speedEntries.filter(':contains("0.75x")'), - speed_1_0 = speedEntries.filter(':contains("1.0x")'); + function() { + var speed_0_75 = speedEntries.filter(':contains("0.75x")'), + speed_1_0 = speedEntries.filter(':contains("1.0x")'); // First open menu - speedControl.trigger(keyPressEvent(KEY.UP)); - expect(speed_0_75).toBeFocused(); + speedControl.trigger(keyPressEvent(KEY.UP)); + expect(speed_0_75).toBeFocused(); - speed_0_75.trigger(keyPressEvent(KEY.UP)); - expect(speed_1_0).toBeFocused(); + speed_0_75.trigger(keyPressEvent(KEY.UP)); + expect(speed_1_0).toBeFocused(); - speed_1_0.trigger(keyPressEvent(KEY.DOWN)); - expect(speed_0_75).toBeFocused(); - }); + speed_1_0.trigger(keyPressEvent(KEY.DOWN)); + expect(speed_0_75).toBeFocused(); + }); - it('ESC keydown on speed entry closes menu', function () { + it('ESC keydown on speed entry closes menu', function() { // First open menu. Focus is on last speed entry. speedControl.trigger(keyPressEvent(KEY.UP)); speedEntries.last().trigger(keyPressEvent(KEY.ESCAPE)); @@ -144,53 +144,53 @@ }); it('ENTER keydown on speed entry selects speed and closes menu', - function () { + function() { // First open menu. - speedControl.trigger(keyPressEvent(KEY.UP)); + speedControl.trigger(keyPressEvent(KEY.UP)); // Focus on 1.50x speed - speedEntries.eq(0).focus(); - speedEntries.eq(0).trigger(keyPressEvent(KEY.ENTER)); + speedEntries.eq(0).focus(); + speedEntries.eq(0).trigger(keyPressEvent(KEY.ENTER)); // Menu is closed, focus has been returned to speed // control and video speed is 1.50x. - expect(speedButton).toBeFocused(); - expect($('.video-speeds li[data-speed="1.50"]')) + expect(speedButton).toBeFocused(); + expect($('.video-speeds li[data-speed="1.50"]')) .toHaveClass('is-active'); - expect($('.speeds .value')).toHaveHtml('1.50x'); - }); + expect($('.speeds .value')).toHaveHtml('1.50x'); + }); it('SPACE keydown on speed entry selects speed and closes menu', - function () { + function() { // First open menu. - speedControl.trigger(keyPressEvent(KEY.UP)); + speedControl.trigger(keyPressEvent(KEY.UP)); // Focus on 1.50x speed - speedEntries.eq(0).focus(); - speedEntries.eq(0).trigger(keyPressEvent(KEY.SPACE)); + speedEntries.eq(0).focus(); + speedEntries.eq(0).trigger(keyPressEvent(KEY.SPACE)); // Menu is closed, focus has been returned to speed // control and video speed is 1.50x. - expect(speedButton).toBeFocused(); - expect($('.video-speeds li[data-speed="1.50"]')) + expect(speedButton).toBeFocused(); + expect($('.video-speeds li[data-speed="1.50"]')) .toHaveClass('is-active'); - expect($('.speeds .value')).toHaveHtml('1.50x'); - }); + expect($('.speeds .value')).toHaveHtml('1.50x'); + }); }); }); - describe('changeVideoSpeed', function () { + describe('changeVideoSpeed', function() { // This is an unnecessary test. The internal browser API, and // YouTube API detect (and do not do anything) if there is a // request for a speed that is already set. // // describe("when new speed is the same") ... - describe('when new speed is not the same', function () { - beforeEach(function () { + describe('when new speed is not the same', function() { + beforeEach(function() { state = jasmine.initializePlayer(); state.videoSpeedControl.setSpeed(1.0); }); - it('trigger speedChange event', function () { + it('trigger speedChange event', function() { spyOnEvent(state.el, 'speedchange'); $('li[data-speed="0.75"] .speed-option').click(); @@ -200,14 +200,14 @@ }); }); - describe('onSpeedChange', function () { - beforeEach(function () { + describe('onSpeedChange', function() { + beforeEach(function() { state = jasmine.initializePlayer(); $('li[data-speed="1.0"]').addClass('is-active').attr('aria-pressed', 'true'); state.videoSpeedControl.setSpeed(0.75); }); - it('set the new speed as active', function () { + it('set the new speed as active', function() { expect($('li[data-speed="1.0"]')).not.toHaveClass('is-active'); expect($('li[data-speed="1.0"] .speed-option').attr('aria-pressed')).not.toEqual('true'); @@ -218,7 +218,7 @@ }); }); - it('can destroy itself', function () { + it('can destroy itself', function() { state = jasmine.initializePlayer(); state.videoSpeedControl.destroy(); expect(state.videoSpeedControl).toBeUndefined(); diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_storage_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_storage_spec.js index 8cbe133dbb..1de049649d 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_storage_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_storage_spec.js @@ -1,24 +1,24 @@ -(function (requirejs, require, define, undefined) { -require( +(function(requirejs, require, define, undefined) { + require( ['video/00_video_storage.js'], -function (VideoStorage) { - describe('VideoStorage', function () { +function(VideoStorage) { + describe('VideoStorage', function() { var namespace = 'test_storage', id = 'video_id'; - afterEach(function () { + afterEach(function() { VideoStorage(namespace, id).clear(); }); - describe('initialize', function () { - it('with namespace and id', function () { + describe('initialize', function() { + it('with namespace and id', function() { var storage = VideoStorage(namespace, id); expect(window[namespace]).toBeDefined(); expect(window[namespace][id]).toBeDefined(); }); - it('without namespace and id', function () { + it('without namespace and id', function() { spyOn(Number.prototype, 'toString').and.returnValue('0.abcdedg'); var storage = VideoStorage(); @@ -27,10 +27,10 @@ function (VideoStorage) { }); }); - describe('methods: ', function () { + describe('methods: ', function() { var data, storage; - beforeEach(function () { + beforeEach(function() { data = { item_2: 'value_2' }; @@ -42,7 +42,7 @@ function (VideoStorage) { storage = VideoStorage(namespace, id); }); - it('setItem', function () { + it('setItem', function() { var expected = $.extend(true, {}, data, {item_4: 'value_4'}); expected[id]['item_3'] = 'value_3'; @@ -51,7 +51,7 @@ function (VideoStorage) { expect(window[namespace]).toEqual(expected); }); - it('getItem', function () { + it('getItem', function() { var data = window[namespace], getItem = storage.getItem; @@ -60,7 +60,7 @@ function (VideoStorage) { expect(getItem('item_3')).toBeUndefined(); }); - it('removeItem', function () { + it('removeItem', function() { var data = window[namespace], removeItem = storage.removeItem; @@ -70,7 +70,7 @@ function (VideoStorage) { expect(data['item_2']).toBeUndefined(); }); - it('clear', function () { + it('clear', function() { var expected = {}; expected[id] = {}; diff --git a/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js b/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js index 21037c2d9c..0ffb35f363 100644 --- a/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/video/video_volume_control_spec.js @@ -1,328 +1,325 @@ -(function () { -'use strict'; -describe('VideoVolumeControl', function () { - var state, oldOTBD, volumeControl; +(function() { + 'use strict'; + describe('VideoVolumeControl', function() { + var state, oldOTBD, volumeControl; - var KEY = $.ui.keyCode, + var KEY = $.ui.keyCode, - keyPressEvent = function(key) { - return $.Event('keydown', { keyCode: key }); - }; + keyPressEvent = function(key) { + return $.Event('keydown', {keyCode: key}); + }; - beforeEach(function () { - oldOTBD = window.onTouchBasedDevice; - window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') + beforeEach(function() { + oldOTBD = window.onTouchBasedDevice; + window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice') .and.returnValue(null); - }); + }); - afterEach(function () { - $('source').remove(); - window.onTouchBasedDevice = oldOTBD; - state.storage.clear(); - state.videoPlayer.destroy(); - }); + afterEach(function() { + $('source').remove(); + window.onTouchBasedDevice = oldOTBD; + state.storage.clear(); + state.videoPlayer.destroy(); + }); - it('Volume level has correct value even if cookie is broken', function () { - $.cookie.and.returnValue('broken_cookie'); - state = jasmine.initializePlayer(); - volumeControl = state.videoVolumeControl; - expect(volumeControl.volume).toEqual(100); - }); - - describe('constructor', function () { - beforeEach(function () { - spyOn($.fn, 'slider').and.callThrough(); - $.cookie.and.returnValue('75'); + it('Volume level has correct value even if cookie is broken', function() { + $.cookie.and.returnValue('broken_cookie'); state = jasmine.initializePlayer(); volumeControl = state.videoVolumeControl; - }); - - it('initialize volume to 75%', function () { - expect(volumeControl.volume).toEqual(75); - }); - - it('render the volume control', function () { - expect($('.volume')).toExist(); - }); - - it('create the slider', function () { - expect($.fn.slider.calls.argsFor(2)).toEqual([{ - orientation: 'vertical', - range: 'min', - min: 0, - max: 100, - slide: jasmine.any(Function) - }]); - expect($.fn.slider).toHaveBeenCalledWith( - 'value', volumeControl.volume - ); - }); - - it('add ARIA attributes to live region', function () { - var liveRegion = $('.video-live-region'); - - expect(liveRegion).toHaveAttrs({ - 'aria-live': 'polite' - }); - }); - - it('add ARIA attributes to volume control', function () { - var button = $('.volume .control'); - - expect(button).toHaveAttrs({ - 'aria-disabled': 'false' - }); - }); - - it('bind the volume control', function () { - var button = $('.volume .control'); - - expect(button).toHandle('keydown'); - expect(button).toHandle('mousedown'); - expect($('.volume')).not.toHaveClass('is-opened'); - - $('.volume').mouseenter(); - expect($('.volume')).toHaveClass('is-opened'); - - $('.volume').mouseleave(); - expect($('.volume')).not.toHaveClass('is-opened'); - }); - }); - - describe('setVolume', function () { - beforeEach(function () { - state = jasmine.initializePlayer(); - volumeControl = state.videoVolumeControl; - - jasmine.addMatchers({ - assertLiveRegionState: function () { - return { - compare: function (actual, volume, expectation) { - var region = $('.video-live-region'); - - var getExpectedText = function (text) { - return text + ' Volume.'; - }; - - actual.setVolume(volume, true, true); - return { - pass: region.text() === getExpectedText(expectation) - }; - - } - }; - } - }); - }); - - it('update is not called, if new volume equals current', function () { - volumeControl.volume = 60; - spyOn(volumeControl, 'updateSliderView'); - volumeControl.setVolume(60, false, true); - expect(volumeControl.updateSliderView).not.toHaveBeenCalled(); - }); - - it('volume is changed on sliding', function () { - volumeControl.onSlideHandler(null, {value: 99}); - expect(volumeControl.volume).toBe(99); - }); - - describe('when the new volume is more than 0', function () { - beforeEach(function () { - volumeControl.setVolume(60, false, true); - }); - - it('set the player volume', function () { - expect(volumeControl.volume).toEqual(60); - }); - - it('remove muted class', function () { - expect($('.volume')).not.toHaveClass('is-muted'); - }); - }); - - describe('when the new volume is more than 0, but was 0', function () { - it('remove muted class', function () { - volumeControl.setVolume(0, false, true); - expect($('.volume')).toHaveClass('is-muted'); - state.el.trigger('volumechange', [20]); - expect($('.volume')).not.toHaveClass('is-muted'); - }); - }); - - describe('when the new volume is 0', function () { - beforeEach(function () { - volumeControl.setVolume(0, false, true); - }); - - it('set the player volume', function () { - expect(volumeControl.volume).toEqual(0); - }); - - it('add muted class', function () { - expect($('.volume')).toHaveClass('is-muted'); - }); - }); - - it('when the new volume is Muted', function () { - expect(volumeControl).assertLiveRegionState(0, 'Muted'); - }); - - it('when the new volume is in ]0,20]', function () { - expect(volumeControl).assertLiveRegionState(10, 'Very low'); - }); - - it('when the new volume is in ]20,40]', function () { - expect(volumeControl).assertLiveRegionState(30, 'Low'); - }); - - it('when the new volume is in ]40,60]', function () { - expect(volumeControl).assertLiveRegionState(50, 'Average'); - }); - - it('when the new volume is in ]60,80]', function () { - expect(volumeControl).assertLiveRegionState(70, 'Loud'); - }); - - it('when the new volume is in ]80,100[', function () { - expect(volumeControl).assertLiveRegionState(90, 'Very loud'); - }); - - it('when the new volume is Maximum', function () { - expect(volumeControl).assertLiveRegionState(100, 'Maximum'); - }); - }); - - describe('increaseVolume', function () { - - beforeEach(function () { - state = jasmine.initializePlayer(); - volumeControl = state.videoVolumeControl; - }); - - it('volume is increased correctly', function () { - var button = $('.volume .control'); - volumeControl.volume = 60; - - // adjust the volume - button.focus(); - button.trigger(keyPressEvent(KEY.UP)); - expect(volumeControl.volume).toEqual(80); - }); - - it('volume level is not changed if it is already max', function () { - volumeControl.volume = 100; - volumeControl.increaseVolume(); expect(volumeControl.volume).toEqual(100); }); - }); - describe('decreaseVolume', function () { + describe('constructor', function() { + beforeEach(function() { + spyOn($.fn, 'slider').and.callThrough(); + $.cookie.and.returnValue('75'); + state = jasmine.initializePlayer(); + volumeControl = state.videoVolumeControl; + }); - beforeEach(function () { - state = jasmine.initializePlayer(); - volumeControl = state.videoVolumeControl; + it('initialize volume to 75%', function() { + expect(volumeControl.volume).toEqual(75); + }); + + it('render the volume control', function() { + expect($('.volume')).toExist(); + }); + + it('create the slider', function() { + expect($.fn.slider.calls.argsFor(2)).toEqual([{ + orientation: 'vertical', + range: 'min', + min: 0, + max: 100, + slide: jasmine.any(Function) + }]); + expect($.fn.slider).toHaveBeenCalledWith( + 'value', volumeControl.volume + ); + }); + + it('add ARIA attributes to live region', function() { + var liveRegion = $('.video-live-region'); + + expect(liveRegion).toHaveAttrs({ + 'aria-live': 'polite' + }); + }); + + it('add ARIA attributes to volume control', function() { + var button = $('.volume .control'); + + expect(button).toHaveAttrs({ + 'aria-disabled': 'false' + }); + }); + + it('bind the volume control', function() { + var button = $('.volume .control'); + + expect(button).toHandle('keydown'); + expect(button).toHandle('mousedown'); + expect($('.volume')).not.toHaveClass('is-opened'); + + $('.volume').mouseenter(); + expect($('.volume')).toHaveClass('is-opened'); + + $('.volume').mouseleave(); + expect($('.volume')).not.toHaveClass('is-opened'); + }); }); - it('volume is decreased correctly', function () { - var button = $('.volume .control'); - volumeControl.volume = 60; + describe('setVolume', function() { + beforeEach(function() { + state = jasmine.initializePlayer(); + volumeControl = state.videoVolumeControl; + + jasmine.addMatchers({ + assertLiveRegionState: function() { + return { + compare: function(actual, volume, expectation) { + var region = $('.video-live-region'); + + var getExpectedText = function(text) { + return text + ' Volume.'; + }; + + actual.setVolume(volume, true, true); + return { + pass: region.text() === getExpectedText(expectation) + }; + } + }; + } + }); + }); + + it('update is not called, if new volume equals current', function() { + volumeControl.volume = 60; + spyOn(volumeControl, 'updateSliderView'); + volumeControl.setVolume(60, false, true); + expect(volumeControl.updateSliderView).not.toHaveBeenCalled(); + }); + + it('volume is changed on sliding', function() { + volumeControl.onSlideHandler(null, {value: 99}); + expect(volumeControl.volume).toBe(99); + }); + + describe('when the new volume is more than 0', function() { + beforeEach(function() { + volumeControl.setVolume(60, false, true); + }); + + it('set the player volume', function() { + expect(volumeControl.volume).toEqual(60); + }); + + it('remove muted class', function() { + expect($('.volume')).not.toHaveClass('is-muted'); + }); + }); + + describe('when the new volume is more than 0, but was 0', function() { + it('remove muted class', function() { + volumeControl.setVolume(0, false, true); + expect($('.volume')).toHaveClass('is-muted'); + state.el.trigger('volumechange', [20]); + expect($('.volume')).not.toHaveClass('is-muted'); + }); + }); + + describe('when the new volume is 0', function() { + beforeEach(function() { + volumeControl.setVolume(0, false, true); + }); + + it('set the player volume', function() { + expect(volumeControl.volume).toEqual(0); + }); + + it('add muted class', function() { + expect($('.volume')).toHaveClass('is-muted'); + }); + }); + + it('when the new volume is Muted', function() { + expect(volumeControl).assertLiveRegionState(0, 'Muted'); + }); + + it('when the new volume is in ]0,20]', function() { + expect(volumeControl).assertLiveRegionState(10, 'Very low'); + }); + + it('when the new volume is in ]20,40]', function() { + expect(volumeControl).assertLiveRegionState(30, 'Low'); + }); + + it('when the new volume is in ]40,60]', function() { + expect(volumeControl).assertLiveRegionState(50, 'Average'); + }); + + it('when the new volume is in ]60,80]', function() { + expect(volumeControl).assertLiveRegionState(70, 'Loud'); + }); + + it('when the new volume is in ]80,100[', function() { + expect(volumeControl).assertLiveRegionState(90, 'Very loud'); + }); + + it('when the new volume is Maximum', function() { + expect(volumeControl).assertLiveRegionState(100, 'Maximum'); + }); + }); + + describe('increaseVolume', function() { + beforeEach(function() { + state = jasmine.initializePlayer(); + volumeControl = state.videoVolumeControl; + }); + + it('volume is increased correctly', function() { + var button = $('.volume .control'); + volumeControl.volume = 60; // adjust the volume - button.focus(); - button.trigger(keyPressEvent(KEY.DOWN)); - expect(volumeControl.volume).toEqual(40); + button.focus(); + button.trigger(keyPressEvent(KEY.UP)); + expect(volumeControl.volume).toEqual(80); + }); + + it('volume level is not changed if it is already max', function() { + volumeControl.volume = 100; + volumeControl.increaseVolume(); + expect(volumeControl.volume).toEqual(100); + }); }); - it('volume level is not changed if it is already min', function () { - volumeControl.volume = 0; - volumeControl.decreaseVolume(); - expect(volumeControl.volume).toEqual(0); - }); - }); + describe('decreaseVolume', function() { + beforeEach(function() { + state = jasmine.initializePlayer(); + volumeControl = state.videoVolumeControl; + }); - describe('toggleMute', function () { - beforeEach(function () { - state = jasmine.initializePlayer(); - volumeControl = state.videoVolumeControl; - }); - - describe('when the current volume is more than 0', function () { - beforeEach(function () { + it('volume is decreased correctly', function() { + var button = $('.volume .control'); volumeControl.volume = 60; - volumeControl.button.trigger('mousedown'); + + // adjust the volume + button.focus(); + button.trigger(keyPressEvent(KEY.DOWN)); + expect(volumeControl.volume).toEqual(40); }); - it('save the previous volume', function () { - expect(volumeControl.storedVolume).toEqual(60); - }); - - it('set the player volume', function () { + it('volume level is not changed if it is already min', function() { + volumeControl.volume = 0; + volumeControl.decreaseVolume(); expect(volumeControl.volume).toEqual(0); }); }); - describe('when the current volume is 0', function () { - beforeEach(function () { - volumeControl.volume = 0; - volumeControl.storedVolume = 60; - volumeControl.button.trigger('mousedown'); + describe('toggleMute', function() { + beforeEach(function() { + state = jasmine.initializePlayer(); + volumeControl = state.videoVolumeControl; }); - it('set the player volume to previous volume', function () { + describe('when the current volume is more than 0', function() { + beforeEach(function() { + volumeControl.volume = 60; + volumeControl.button.trigger('mousedown'); + }); + + it('save the previous volume', function() { + expect(volumeControl.storedVolume).toEqual(60); + }); + + it('set the player volume', function() { + expect(volumeControl.volume).toEqual(0); + }); + }); + + describe('when the current volume is 0', function() { + beforeEach(function() { + volumeControl.volume = 0; + volumeControl.storedVolume = 60; + volumeControl.button.trigger('mousedown'); + }); + + it('set the player volume to previous volume', function() { + expect(volumeControl.volume).toEqual(60); + }); + }); + }); + + describe('keyDownHandler', function() { + beforeEach(function() { + state = jasmine.initializePlayer(); + volumeControl = state.videoVolumeControl; + }); + + var assertVolumeIsNotChanged = function(eventObject) { + volumeControl.volume = 60; + state.el.trigger(jQuery.Event('keydown', eventObject)); expect(volumeControl.volume).toEqual(60); + }; + + it('nothing happens if ALT+keyUp are pushed down', function() { + assertVolumeIsNotChanged({ + keyCode: KEY.UP, + altKey: true + }); + }); + + it('nothing happens if SHIFT+keyUp are pushed down', function() { + assertVolumeIsNotChanged({ + keyCode: KEY.UP, + shiftKey: true + }); + }); + + it('nothing happens if SHIFT+keyDown are pushed down', function() { + assertVolumeIsNotChanged({ + keyCode: KEY.DOWN, + shiftKey: true + }); + }); + }); + + describe('keyDownButtonHandler', function() { + beforeEach(function() { + state = jasmine.initializePlayer(); + volumeControl = state.videoVolumeControl; + }); + + it('nothing happens if ALT+ENTER are pushed down', function() { + var isMuted = volumeControl.getMuteStatus(); + $('.volume .control').trigger(jQuery.Event('keydown', { + keyCode: KEY.ENTER, + altKey: true + })); + expect(volumeControl.getMuteStatus()).toEqual(isMuted); }); }); }); - - describe('keyDownHandler', function () { - beforeEach(function () { - state = jasmine.initializePlayer(); - volumeControl = state.videoVolumeControl; - }); - - var assertVolumeIsNotChanged = function (eventObject) { - volumeControl.volume = 60; - state.el.trigger(jQuery.Event("keydown", eventObject)); - expect(volumeControl.volume).toEqual(60); - }; - - it('nothing happens if ALT+keyUp are pushed down', function () { - assertVolumeIsNotChanged({ - keyCode: KEY.UP, - altKey: true - }); - }); - - it('nothing happens if SHIFT+keyUp are pushed down', function () { - assertVolumeIsNotChanged({ - keyCode: KEY.UP, - shiftKey: true - }); - }); - - it('nothing happens if SHIFT+keyDown are pushed down', function () { - assertVolumeIsNotChanged({ - keyCode: KEY.DOWN, - shiftKey: true - }); - }); - }); - - describe('keyDownButtonHandler', function () { - beforeEach(function () { - state = jasmine.initializePlayer(); - volumeControl = state.videoVolumeControl; - }); - - it('nothing happens if ALT+ENTER are pushed down', function () { - var isMuted = volumeControl.getMuteStatus(); - $('.volume .control').trigger(jQuery.Event("keydown", { - keyCode: KEY.ENTER, - altKey: true - })); - expect(volumeControl.getMuteStatus()).toEqual(isMuted); - }); - }); -}); }).call(this); diff --git a/common/lib/xmodule/xmodule/js/spec/xmodule_spec.js b/common/lib/xmodule/xmodule/js/spec/xmodule_spec.js index 35f21c401f..8dd3efdf16 100644 --- a/common/lib/xmodule/xmodule/js/spec/xmodule_spec.js +++ b/common/lib/xmodule/xmodule/js/spec/xmodule_spec.js @@ -1,14 +1,14 @@ -(function () { +(function() { 'use strict'; - describe('XBlockToXModuleShim', function () { - describe('definition', function () { - it('XBlockToXModuleShim is defined, and is a function', function () { + describe('XBlockToXModuleShim', function() { + describe('definition', function() { + it('XBlockToXModuleShim is defined, and is a function', function() { expect($.isFunction(XBlockToXModuleShim)).toBe(true); }); }); - describe('implementation', function () { + describe('implementation', function() { var el, videoModule = { 'module': 'video_module' @@ -18,7 +18,7 @@ removeNone, removeVideo; - beforeEach(function () { + beforeEach(function() { el = $('
    '); if (window.None) { @@ -47,7 +47,7 @@ spyOnEvent($(document), 'XModule.loaded.display'); }); - afterEach(function () { + afterEach(function() { el = null; if (removeNone) { @@ -58,14 +58,14 @@ } }); - it('if element module is of type None, nothing happens', function () { + it('if element module is of type None, nothing happens', function() { el.data('type', 'None'); expect(XBlockToXModuleShim(null, el)).toBeUndefined(); expect(window.None).not.toHaveBeenCalled(); }); - it('if element module is of type Video, Video module constructor is called', function () { + it('if element module is of type Video, Video module constructor is called', function() { el.data('type', 'Video'); expect(XBlockToXModuleShim(null, el)).toEqual(videoModule); @@ -75,7 +75,7 @@ expect('XModule.loaded.display').not.toHaveBeenTriggeredOn(document); }); - it('if element has class "xmodule_edit"', function () { + it('if element has class "xmodule_edit"', function() { el.data('type', 'Video') .addClass('xmodule_edit'); XBlockToXModuleShim(null, el); @@ -84,7 +84,7 @@ expect('XModule.loaded.display').not.toHaveBeenTriggeredOn($(document)); }); - it('if element has class "xmodule_display"', function () { + it('if element has class "xmodule_display"', function() { el.data('type', 'Video') .addClass('xmodule_display'); XBlockToXModuleShim(null, el); @@ -93,7 +93,7 @@ expect(displayCallback).toHaveBeenCalledWith(jasmine.any($.Event), el, videoModule); }); - it('if element has classes "xmodule_edit", and "xmodule_display"', function () { + it('if element has classes "xmodule_edit", and "xmodule_display"', function() { el.data('type', 'Video') .addClass('xmodule_edit') .addClass('xmodule_display'); @@ -102,7 +102,7 @@ expect('XModule.loaded.display').toHaveBeenTriggeredOn($(document)); }); - it('element is of an unknown Module type, console.error() is called if it is defined', function () { + it('element is of an unknown Module type, console.error() is called if it is defined', function() { var oldConsole = window.console; if (window.console && window.console.error) { @@ -121,9 +121,9 @@ window.console = oldConsole; }); - it('element is of an unknown Module type, JavaScript throws if console.error() is not defined', function () { + it('element is of an unknown Module type, JavaScript throws if console.error() is not defined', function() { var oldConsole = window.console, - testFunction = function () { + testFunction = function() { return XBlockToXModuleShim(null, el); }; @@ -140,55 +140,55 @@ }); }); - describe('XModule.Descriptor', function () { - describe('definition', function () { - it('XModule is defined, and is a plain object', function () { + describe('XModule.Descriptor', function() { + describe('definition', function() { + it('XModule is defined, and is a plain object', function() { expect($.isPlainObject(XModule)).toBe(true); }); - it('XModule.Descriptor is defined, and is a function', function () { + it('XModule.Descriptor is defined, and is a function', function() { expect($.isFunction(XModule.Descriptor)).toBe(true); }); - it('XModule.Descriptor has a complete prototype', function () { + it('XModule.Descriptor has a complete prototype', function() { expect($.isFunction(XModule.Descriptor.prototype.onUpdate)).toBe(true); expect($.isFunction(XModule.Descriptor.prototype.update)).toBe(true); expect($.isFunction(XModule.Descriptor.prototype.save)).toBe(true); }); }); - describe('implementation', function () { + describe('implementation', function() { var el, obj, callback, length; // This is a dummy callback. - callback = function () { + callback = function() { var x = 1; return x + 1; }; - beforeEach(function () { + beforeEach(function() { el = 'dummy object'; obj = new XModule.Descriptor(el); spyOn(obj, 'save').and.callThrough(); }); - afterEach(function () { + afterEach(function() { el = null; obj = null; length = undefined; }); - it('Descriptor is a proper constructor function', function () { + it('Descriptor is a proper constructor function', function() { expect(obj.hasOwnProperty('element')).toBe(true); expect(obj.element).toBe(el); expect(obj.hasOwnProperty('update')).toBe(true); }); - it('Descriptor.onUpdate called for the first time', function () { + it('Descriptor.onUpdate called for the first time', function() { expect(obj.hasOwnProperty('callbacks')).toBe(false); obj.onUpdate(callback); expect(obj.hasOwnProperty('callbacks')).toBe(true); @@ -199,7 +199,7 @@ expect(obj.callbacks[length - 1]).toBe(callback); }); - it('Descriptor.onUpdate called for Nth time', function () { + it('Descriptor.onUpdate called for Nth time', function() { // In this test it doesn't matter what obj.callbacks // consists of. obj.callbacks = ['test1', 'test2', 'test3']; @@ -211,13 +211,13 @@ expect(obj.callbacks[length - 1]).toBe(callback); }); - it('Descriptor.save returns a blank object', function () { + it('Descriptor.save returns a blank object', function() { // NOTE: In the future the implementation of .save() // method may change! expect(obj.save()).toEqual({}); }); - it('Descriptor.update triggers all callbacks with whatever .save() returns', function () { + it('Descriptor.update triggers all callbacks with whatever .save() returns', function() { var callback1 = jasmine.createSpy('callback1'), callback2 = jasmine.createSpy('callback2'), testValue = 'test 123'; diff --git a/common/lib/xmodule/xmodule/js/src/capa/imageinput.js b/common/lib/xmodule/xmodule/js/src/capa/imageinput.js index 1e182cba8d..b5f53366e8 100644 --- a/common/lib/xmodule/xmodule/js/src/capa/imageinput.js +++ b/common/lib/xmodule/xmodule/js/src/capa/imageinput.js @@ -13,7 +13,7 @@ * ~ Chinese Proverb */ -window.ImageInput = (function ($, undefined) { +window.ImageInput = (function($, undefined) { var ImageInput = ImageInputConstructor; ImageInput.prototype = { diff --git a/common/lib/xmodule/xmodule/js/src/capa/schematic.js b/common/lib/xmodule/xmodule/js/src/capa/schematic.js index 9daacca8c5..d0cb25c5e5 100644 --- a/common/lib/xmodule/xmodule/js/src/capa/schematic.js +++ b/common/lib/xmodule/xmodule/js/src/capa/schematic.js @@ -85,7 +85,7 @@ var cktsim = (function() { this.abstol = new Array(this.N); this.solution = new Array(this.N); this.rhs = new Array(this.N); - for (var i = this.N - 1; i >= 0; --i) { + for (var i = this.N - 1; i >= 0; --i) { this.soln_max[i] = 0.0; this.abstol[i] = this.ntypes[i] == T_VOLTAGE ? v_abstol : i_abstol; this.solution[i] = 0.0; @@ -97,7 +97,7 @@ var cktsim = (function() { this.devices[i].load_linear(this) } - // Check for voltage source loops. + // Check for voltage source loops. var n_vsrc = this.voltage_sources.length; if (n_vsrc > 0) { // At least one voltage source var GV = mat_make(n_vsrc, this.N); // Loop check @@ -110,11 +110,11 @@ var cktsim = (function() { if (rGV < n_vsrc) { alert('Warning!!! Circuit has a voltage source loop or a source or current probe shorted by a wire, please remove the source or the wire causing the short.'); alert('Warning!!! Simulator might produce meaningless results or no result with illegal circuits.'); - return false; + return false; } } } - return true; + return true; } // load circuit from JSON netlist (see schematic.js) @@ -209,7 +209,7 @@ var cktsim = (function() { if (this.ntypes[i] == T_VOLTAGE) abssum_rhs += Math.abs(rhs[i]); - if ((iter > 0) && (use_limiting == false) && (abssum_old < abssum_rhs)) { + if ((iter > 0) && (use_limiting == false) && (abssum_old < abssum_rhs)) { // Old rhsnorm was better, undo last iter and turn on limiting for (var i = this.N - 1; i >= 0; --i) soln[i] -= d_sol[i]; @@ -222,7 +222,7 @@ var cktsim = (function() { // If norm going down for ten iters, stop limiting if (abssum_rhs < abssum_old) down_count += 1; - else + else down_count = 0; if (down_count > 10) { use_limiting = false; @@ -230,14 +230,14 @@ var cktsim = (function() { } // Update norm of rhs - abssum_old = abssum_rhs; + abssum_old = abssum_rhs; } // Update the worst case abssum for comparison. if ((iter == 0) || (abssum_rhs > abssum_compare)) abssum_compare = abssum_rhs; - // Check residue convergence, but loosely, and give up + // Check residue convergence, but loosely, and give up // on last iteration if ( (iter < (maxiters - 1)) && (abssum_rhs > (res_check_abs+res_check_rel*abssum_compare))) @@ -263,7 +263,7 @@ var cktsim = (function() { } if (converged == true) { - for (var i = this.N - 1; i >= 0; --i) + for (var i = this.N - 1; i >= 0; --i) if (Math.abs(soln[i]) > this.soln_max[i]) this.soln_max[i] = Math.abs(soln[i]); return iter+1; @@ -338,7 +338,7 @@ var cktsim = (function() { mat_v_mult(ckt.C, soln, ckt.q, 1.0); // -rhs = c - dqdt for (var i = ckt.N-1; i >= 0; --i) { - var dqdt = ckt.alpha0*ckt.q[i] + ckt.alpha1*ckt.oldq[i] + + var dqdt = ckt.alpha0*ckt.q[i] + ckt.alpha1*ckt.oldq[i] + ckt.alpha2*ckt.old2q[i]; rhs[i] = ckt.beta0[i]*ckt.c[i] + ckt.beta1[i]*ckt.oldc[i] - dqdt; } @@ -386,7 +386,7 @@ var cktsim = (function() { lte_step_ratio = Math.min(lte_step_ratio, max_growth_factor); if (lte_step_ratio > 1.2) /* Increase timestep due to lte. */ new_step = (ckt.time - ckt.oldt) * lte_step_ratio / 1.2; - else + else new_step = (ckt.time - ckt.oldt); new_step = Math.min(new_step, ckt.max_step); } @@ -398,9 +398,9 @@ var cktsim = (function() { no_dc = false; if ((this.diddc == false) && (no_dc == false)) { if (this.dc() == undefined) { // DC failed, realloc mats and vects. - alert('DC failed, trying transient analysis from zero.'); + alert('DC failed, trying transient analysis from zero.'); this.finalized = false; // Reset the finalization. - if (this.finalize() == false) + if (this.finalize() == false) return undefined; } } @@ -438,7 +438,7 @@ var cktsim = (function() { // Non-algebraic variables and probe variables get lte this.ltecheck = new Array(this.N); - for (var i = N; i >= 0; --i) + for (var i = N; i >= 0; --i) this.ltecheck[i] = (this.ar[i] == 0); for (var name in this.node_map) { @@ -478,10 +478,10 @@ var cktsim = (function() { this.old3sol[i] = this.solution[i]; this.old2sol[i] = this.solution[i]; this.oldsol[i] = this.solution[i]; - this.old3q[i] = this.q[i]; - this.old2q[i] = this.q[i]; - this.oldq[i] = this.q[i]; - this.oldc[i] = this.c[i]; + this.old3q[i] = this.q[i]; + this.old2q[i] = this.q[i]; + this.oldq[i] = this.q[i]; + this.oldc[i] = this.c[i]; } var beta0,beta1; @@ -506,8 +506,8 @@ var cktsim = (function() { this.old2t = this.oldt - (tstart-this.oldt) this.oldt = tstart - (this.time - this.oldt); this.time = tstart; - beta0 = 1.0; - beta1 = 0.0; + beta0 = 1.0; + beta1 = 0.0; } else { // Take a regular step // Save the time, and rotate time wheel response[this.N].push(this.time); @@ -525,7 +525,7 @@ var cktsim = (function() { // Use trap (average old and new crnts. beta0 = 0.5; - beta1 = 0.5; + beta1 = 0.5; } // For trap rule, turn off current avging for algebraic eqns @@ -547,24 +547,24 @@ var cktsim = (function() { this.beta0[i] = 1.0; this.beta1[i] = 0.0; } - } + } // Use Newton to compute the solution. var iterations = this.find_solution(load_tran,max_tran_iters); // If NR succeeds and stepsize is at min, accept and newstep=maxgrowth*minstep. // Else if Newton Fails, shrink step by a factor and try again // Else LTE picks new step, if bigger accept current step and go on. - if ((iterations != undefined) && + if ((iterations != undefined) && (step_index <= 0 || (this.time-this.oldt) < (1+reltol)*this.min_step)) { if (step_index > 0) new_step = time_step_increase_factor*this.min_step; break; } else if (iterations == undefined) { // NR nonconvergence, shrink by factor - this.time = this.oldt + + this.time = this.oldt + (this.time - this.oldt)/nr_step_decrease_factor; } else { // Check the LTE and shrink step if needed. new_step = pick_step(this, step_index); if (new_step < (1.0 - reltol)*(this.time - this.oldt)) { - this.time = this.oldt + new_step; // Try again + this.time = this.oldt + new_step; // Try again } else break; // LTE okay, new_step for next step @@ -687,7 +687,7 @@ var cktsim = (function() { this.devices.push(d); d.name = name; if (name) { - if (this.device_map[name] === undefined) + if (this.device_map[name] === undefined) this.device_map[name] = d; else { alert('Warning: two circuit elements share the same name ' + name); @@ -793,8 +793,8 @@ var cktsim = (function() { // // Support for creating conductance and capacitance matrices associated with // modified nodal analysis (unknowns are node voltages and inductor and voltage - // source currents). - // The linearized circuit is written as + // source currents). + // The linearized circuit is written as // C d/dt x = G x + rhs // x - vector of node voltages and element currents // rhs - vector of source values @@ -870,10 +870,10 @@ var cktsim = (function() { // Allocate an NxM matrix function mat_make(N,M) { - var mat = new Array(N); - for (var i = N - 1; i >= 0; --i) { + var mat = new Array(N); + for (var i = N - 1; i >= 0; --i) { mat[i] = new Array(M); - for (var j = M - 1; j >= 0; --j) { + for (var j = M - 1; j >= 0; --j) { mat[i][j] = 0.0; } } @@ -1009,7 +1009,7 @@ var cktsim = (function() { // now eliminate this column for all subsequent rows for (var i = row + 1; i < Nr; i++) { temp = M[i][col]/M[row][col]; // multiplier for current row - if (temp != 0) // subtract + if (temp != 0) // subtract for (var j = col; j < Nc; j++) M[i][j] -= M[row][j]*temp; } // Now move on to the next row @@ -1021,7 +1021,7 @@ var cktsim = (function() { return the_rank; } - // Solve Mx=b and return vector x using R^TQ^T factorization. + // Solve Mx=b and return vector x using R^TQ^T factorization. // Multiplication by R^T implicit, should be null-space free soln. // M should have the extra column! // Almost everything is in-lined for speed, sigh. @@ -1038,7 +1038,7 @@ var cktsim = (function() { var mat_scale = 0; // Sets the scale for comparison to zero. var max_nonzero_row = Nr-1; // Assumes M nonsingular. - for (var row = 0; row < Nr; row++) { + for (var row = 0; row < Nr; row++) { // Find largest row with largest 2-norm var max_row = row; var maxsumsq = 0; @@ -1077,7 +1077,7 @@ var cktsim = (function() { for (var rowp = row + 1; rowp < Nr; rowp++) { // Update. var Mrp = M[rowp]; var inner = 0; - for (var col = Nc-2; col >= 0; --col) // Project + for (var col = Nc-2; col >= 0; --col) // Project inner += Mr[col]*Mrp[col]; for (var col = Nc-1; col >= 0; --col) // Ortho (rhs also) Mrp[col] -= inner *Mr[col]; @@ -1122,7 +1122,7 @@ var cktsim = (function() { // if no value found, generate a small conductance to gnd // otherwise swap current row with pivot row - if (max_v == 0) M[col][col] = eps; + if (max_v == 0) M[col][col] = eps; else { temp = M[col]; M[col] = M[max_col]; @@ -1588,12 +1588,12 @@ var cktsim = (function() { // Source voltage added to b. VSource.prototype.load_dc = function(ckt,soln,rhs) { - ckt.add_to_rhs(this.branch,this.src.dc,rhs); + ckt.add_to_rhs(this.branch,this.src.dc,rhs); } // Load time-dependent value for voltage source for tran VSource.prototype.load_tran = function(ckt,soln,rhs,time) { - ckt.add_to_rhs(this.branch,this.src.value(time),rhs); + ckt.add_to_rhs(this.branch,this.src.value(time),rhs); } // return time of next breakpoint for the device @@ -1756,7 +1756,7 @@ var cktsim = (function() { Capacitor.prototype.constructor = Capacitor; Capacitor.prototype.load_linear = function(ckt) { - // MNA stamp for capacitance matrix + // MNA stamp for capacitance matrix ckt.add_capacitance(this.n1,this.n2,this.value); } @@ -1808,7 +1808,7 @@ var cktsim = (function() { /////////////////////////////////////////////////////////////////////////////// // - // Simple Voltage-Controlled Voltage Source Op Amp model + // Simple Voltage-Controlled Voltage Source Op Amp model // /////////////////////////////////////////////////////////////////////////////// @@ -1900,7 +1900,7 @@ var cktsim = (function() { gmgs *= vds; } ckt.add_to_rhs(d,-ids,rhs); // current flows into the drain - ckt.add_to_rhs(s, ids,rhs); // and out the source + ckt.add_to_rhs(s, ids,rhs); // and out the source ckt.add_conductance(d,s,gds); ckt.add_to_G(s,s, gmgs); ckt.add_to_G(d,s,-gmgs); @@ -1939,7 +1939,7 @@ var cktsim = (function() { // Copyright (C) 2011 Massachusetts Institute of Technology -// add schematics to a document with +// add schematics to a document with // // // @@ -2786,7 +2786,7 @@ schematic = (function() { if (ckt === null) return; var results = ckt.ac(npts,fstart,fstop,ac_source_name); - if (typeof results == 'string') + if (typeof results == 'string') this.message(results); else { var x_values = results['_frequencies_']; @@ -2913,7 +2913,7 @@ schematic = (function() { var results = ckt.tran(ckt.parse_number(sch.tran_npts), 0, ckt.parse_number(sch.tran_tstop), probe_names, false); - if (typeof results == 'string') + if (typeof results == 'string') sch.message(results); else { if (sch.submit_analyses != undefined) { @@ -3885,7 +3885,7 @@ schematic = (function() { child = document.createElement('img'); label = document.createElement('span'); hidden = document.createElement('span'); - + tool.style.backgroundImage = 'none'; tool.setAttribute('title', tip); label.innerHTML = tip; @@ -4173,7 +4173,7 @@ schematic = (function() { if (x == x_min) { c.moveTo(temp,top_margin); c.lineTo(temp,end); - } else + } else c.dashedLineTo(temp,top_margin,temp,end,grid_pattern); c.stroke(); @@ -4219,7 +4219,7 @@ schematic = (function() { if (y == y_min) { c.moveTo(left_margin,temp); c.lineTo(left_margin + pwidth,temp); - } else + } else c.dashedLineTo(left_margin,temp,left_margin + pwidth,temp,grid_pattern); c.stroke(); @@ -5137,7 +5137,7 @@ schematic = (function() { this.location = nx + ',' + ny; // add ourselves to the connection list for the new location - if (parent.sch) + if (parent.sch) parent.sch.update_connection_point(this,old_location); } @@ -6069,7 +6069,7 @@ schematic = (function() { var first = true; var value = ''; for (var label in fields) { - if (label == 'name') + if (label == 'name') c.properties['name'] = fields['name'].value; else if (label == 'value') { // if unknown source type @@ -6115,7 +6115,7 @@ schematic = (function() { this.draw_text(c,'\u2588\u2588\u2588',-8,8,4,annotation_size,element_style); c.globalAlpha = 1.0; - // display the element current + // display the element current var i = engineering_notation(v,2) + 'A'; this.draw_text(c,i,-3,5,5,annotation_size,annotation_style); // draw arrow for current @@ -6193,4 +6193,4 @@ schematic = (function() { 'component_slider': component_slider } return module; - }()); +}()); diff --git a/common/lib/xmodule/xmodule/js/src/collapsible.js b/common/lib/xmodule/xmodule/js/src/collapsible.js index e86f30deaf..73d737f098 100644 --- a/common/lib/xmodule/xmodule/js/src/collapsible.js +++ b/common/lib/xmodule/xmodule/js/src/collapsible.js @@ -1,4 +1,4 @@ -(function (undefined) { +(function(undefined) { 'use strict'; // [module Collapsible] @@ -35,14 +35,14 @@ short_custom = el.find('.shortform-custom'); // Set up each one individually. - short_custom.each(function (index, elt) { + short_custom.each(function(index, elt) { var close_text, open_text; open_text = $(elt).data('open-text'); close_text = $(elt).data('close-text'); - $(elt).append("" + open_text + ""); + $(elt).append("" + open_text + ''); - $(elt).find('.full-custom').click(function (event) { + $(elt).find('.full-custom').click(function(event) { Collapsible.toggleFull(event, open_text, close_text); }); }); @@ -51,8 +51,8 @@ el.find('.collapsible header + section').hide(); // Set up triggers. - el.find('.full').click(function (event) { - Collapsible.toggleFull(event, "See full output", "Hide output"); + el.find('.full').click(function(event) { + Collapsible.toggleFull(event, 'See full output', 'Hide output'); }); el.find('.collapsible header a').click(Collapsible.toggleHint); } diff --git a/common/lib/xmodule/xmodule/js/src/html/imageModal.js b/common/lib/xmodule/xmodule/js/src/html/imageModal.js index 5577c57410..e9288bd37d 100644 --- a/common/lib/xmodule/xmodule/js/src/html/imageModal.js +++ b/common/lib/xmodule/xmodule/js/src/html/imageModal.js @@ -1,110 +1,108 @@ var setupFullScreenModal = function() { - // Setup full screen image modal. // Executed from HTMLModule in display.js. - $("a.modal-content").each(function() { - var smallImageObject = $(this).children(); - var largeImageSRC = $(this).attr('href'); - + $('a.modal-content').each(function() { + var smallImageObject = $(this).children(); + var largeImageSRC = $(this).attr('href'); + // if contents of zoomable link is image and large image link exists: setup modal - if (smallImageObject.is('img') && largeImageSRC) { - var data = { - "smallHTML": $(this).html(), - "largeALT": smallImageObject.attr('alt'), - "largeSRC": largeImageSRC - }; - var html = _.template($("#image-modal-tpl").text())(data); - $(this).replaceWith(html); - } - }); - $('.wrapper-modal-image .image-wrapper img').each(function() { - var draggie = new Draggabilly(this, {containment: true}); - draggie.disable(); - $(this).closest('.image-modal').data("draggie", draggie); - }); + if (smallImageObject.is('img') && largeImageSRC) { + var data = { + 'smallHTML': $(this).html(), + 'largeALT': smallImageObject.attr('alt'), + 'largeSRC': largeImageSRC + }; + var html = _.template($('#image-modal-tpl').text())(data); + $(this).replaceWith(html); + } + }); + $('.wrapper-modal-image .image-wrapper img').each(function() { + var draggie = new Draggabilly(this, {containment: true}); + draggie.disable(); + $(this).closest('.image-modal').data('draggie', draggie); + }); // Opening and closing image modal on clicks - $(".wrapper-modal-image .image-link").click(function() { - $(this).siblings(".image-modal").addClass('image-is-fit-to-screen'); - $('body').css('overflow', 'hidden'); - }); - + $('.wrapper-modal-image .image-link').click(function() { + $(this).siblings('.image-modal').addClass('image-is-fit-to-screen'); + $('body').css('overflow', 'hidden'); + }); + // variable to detect when modal is being "hovered". // Done this way as jquery doesn't support the :hover psudo-selector as expected. - var imageModalImageHover = false; - $(".wrapper-modal-image .image-content img, .wrapper-modal-image .image-content .image-controls").hover(function() { - imageModalImageHover = true; - }, function() { - imageModalImageHover = false; - }); - + var imageModalImageHover = false; + $('.wrapper-modal-image .image-content img, .wrapper-modal-image .image-content .image-controls').hover(function() { + imageModalImageHover = true; + }, function() { + imageModalImageHover = false; + }); + // prevent image control button links from scrolling - $(".modal-ui-icon").click(function(event) { - event.preventDefault(); - }); - - //Define function to close modal - function closeModal(imageModal) { - imageModal.removeClass('image-is-fit-to-screen').removeClass('image-is-zoomed'); - $(".wrapper-modal-image .image-content .image-controls .modal-ui-icon.action-zoom-in").removeClass('is-disabled').attr('aria-disabled', false); - $(".wrapper-modal-image .image-content .image-controls .modal-ui-icon.action-zoom-out").addClass('is-disabled').attr('aria-disabled', true); - var currentDraggie = imageModal.data("draggie"); - currentDraggie.disable(); - $('body').css('overflow', 'auto'); - } - - // Click outside of modal to close it. - $(".wrapper-modal-image .image-modal").click(function() { - if (!imageModalImageHover){ - closeModal($(this)); + $('.modal-ui-icon').click(function(event) { + event.preventDefault(); + }); + + // Define function to close modal + function closeModal(imageModal) { + imageModal.removeClass('image-is-fit-to-screen').removeClass('image-is-zoomed'); + $('.wrapper-modal-image .image-content .image-controls .modal-ui-icon.action-zoom-in').removeClass('is-disabled').attr('aria-disabled', false); + $('.wrapper-modal-image .image-content .image-controls .modal-ui-icon.action-zoom-out').addClass('is-disabled').attr('aria-disabled', true); + var currentDraggie = imageModal.data('draggie'); + currentDraggie.disable(); + $('body').css('overflow', 'auto'); } - }); - + + // Click outside of modal to close it. + $('.wrapper-modal-image .image-modal').click(function() { + if (!imageModalImageHover) { + closeModal($(this)); + } + }); + // Click close icon to close modal. - $(".wrapper-modal-image .image-content .action-remove").click(function() { - closeModal($(this).closest(".image-modal")); - }); + $('.wrapper-modal-image .image-content .action-remove').click(function() { + closeModal($(this).closest('.image-modal')); + }); // zooming image in modal and allow it to be dragged // Make sure it always starts zero position for below calcs to work - $(".wrapper-modal-image .image-content .image-controls .modal-ui-icon").click(function() { - if (!$(this).hasClass('is-disabled')) { - var mask = $(this).closest(".image-content"); - - var imageModal = $(this).closest(".image-modal"); - var img = imageModal.find("img"); - var currentDraggie = imageModal.data("draggie"); - - if ($(this).hasClass('action-zoom-in')) { - imageModal.removeClass('image-is-fit-to-screen').addClass('image-is-zoomed'); - - var imgWidth = img.width(); - var imgHeight = img.height(); - - var imgContainerOffsetLeft = imgWidth - mask.width(); - var imgContainerOffsetTop = imgHeight - mask.height(); - var imgContainerWidth = imgWidth + imgContainerOffsetLeft; - var imgContainerHeight = imgHeight + imgContainerOffsetTop; - + $('.wrapper-modal-image .image-content .image-controls .modal-ui-icon').click(function() { + if (!$(this).hasClass('is-disabled')) { + var mask = $(this).closest('.image-content'); + + var imageModal = $(this).closest('.image-modal'); + var img = imageModal.find('img'); + var currentDraggie = imageModal.data('draggie'); + + if ($(this).hasClass('action-zoom-in')) { + imageModal.removeClass('image-is-fit-to-screen').addClass('image-is-zoomed'); + + var imgWidth = img.width(); + var imgHeight = img.height(); + + var imgContainerOffsetLeft = imgWidth - mask.width(); + var imgContainerOffsetTop = imgHeight - mask.height(); + var imgContainerWidth = imgWidth + imgContainerOffsetLeft; + var imgContainerHeight = imgHeight + imgContainerOffsetTop; + // Set the width and height of the image's container so that the dimensions are equal to the image dimensions + view area dimensions to limit dragging // Set image container top and left to center image at load. - img.parent().css({ - left: -imgContainerOffsetLeft, - top: -imgContainerOffsetTop, - width: imgContainerWidth, - height: imgContainerHeight - }); - img.css({top: imgContainerOffsetTop / 2, left: imgContainerOffsetLeft / 2}); - - currentDraggie.enable(); - - } else if ($(this).hasClass('action-zoom-out')) { - imageModal.removeClass('image-is-zoomed').addClass('image-is-fit-to-screen'); - - currentDraggie.disable(); - } - - $(".wrapper-modal-image .image-content .image-controls .modal-ui-icon").toggleClass('is-disabled').attr('aria-disabled', $(this).hasClass('is-disabled')); - } - }); + img.parent().css({ + left: -imgContainerOffsetLeft, + top: -imgContainerOffsetTop, + width: imgContainerWidth, + height: imgContainerHeight + }); + img.css({top: imgContainerOffsetTop / 2, left: imgContainerOffsetLeft / 2}); + + currentDraggie.enable(); + } else if ($(this).hasClass('action-zoom-out')) { + imageModal.removeClass('image-is-zoomed').addClass('image-is-fit-to-screen'); + + currentDraggie.disable(); + } + + $('.wrapper-modal-image .image-content .image-controls .modal-ui-icon').toggleClass('is-disabled').attr('aria-disabled', $(this).hasClass('is-disabled')); + } + }); }; diff --git a/common/lib/xmodule/xmodule/js/src/lti/lti.js b/common/lib/xmodule/xmodule/js/src/lti/lti.js index a1212671ab..408cca9012 100644 --- a/common/lib/xmodule/xmodule/js/src/lti/lti.js +++ b/common/lib/xmodule/xmodule/js/src/lti/lti.js @@ -1,4 +1,4 @@ -(function () { +(function() { 'use strict'; /** * This function will process all the attributes from the DOM element passed, taking all of @@ -8,25 +8,23 @@ * @constructor * @param {jQuery} element DOM element with the lti container. */ - this.LTI = function (element) { + this.LTI = function(element) { var dataAttrs = $(element).find('.lti').data(), askToSendUsername = (dataAttrs.askToSendUsername === 'True'), askToSendEmail = (dataAttrs.askToSendEmail === 'True'); // When the lti button is clicked, provide users the option to // accept or reject sending their information to a third party - $(element).on('click', '.link_lti_new_window', function () { - if(askToSendUsername && askToSendEmail) { - return confirm(gettext("Click OK to have your username and e-mail address sent to a 3rd party application.\n\nClick Cancel to return to this page without sending your information.")); + $(element).on('click', '.link_lti_new_window', function() { + if (askToSendUsername && askToSendEmail) { + return confirm(gettext('Click OK to have your username and e-mail address sent to a 3rd party application.\n\nClick Cancel to return to this page without sending your information.')); } else if (askToSendUsername) { - return confirm(gettext("Click OK to have your username sent to a 3rd party application.\n\nClick Cancel to return to this page without sending your information.")); + return confirm(gettext('Click OK to have your username sent to a 3rd party application.\n\nClick Cancel to return to this page without sending your information.')); } else if (askToSendEmail) { - return confirm(gettext("Click OK to have your e-mail address sent to a 3rd party application.\n\nClick Cancel to return to this page without sending your information.")); + return confirm(gettext('Click OK to have your e-mail address sent to a 3rd party application.\n\nClick Cancel to return to this page without sending your information.')); } else { return true; } }); - }; - }).call(this); diff --git a/common/lib/xmodule/xmodule/js/src/poll/poll.js b/common/lib/xmodule/xmodule/js/src/poll/poll.js index a2ccbc7c03..ea29c84336 100644 --- a/common/lib/xmodule/xmodule/js/src/poll/poll.js +++ b/common/lib/xmodule/xmodule/js/src/poll/poll.js @@ -1,5 +1,5 @@ -window.Poll = function (el) { - RequireJS.require(['PollMain'], function (PollMain) { +window.Poll = function(el) { + RequireJS.require(['PollMain'], function(PollMain) { new PollMain(el); }); }; diff --git a/common/lib/xmodule/xmodule/js/src/poll/poll_main.js b/common/lib/xmodule/xmodule/js/src/poll/poll_main.js index 13542899b4..18b34c4cef 100644 --- a/common/lib/xmodule/xmodule/js/src/poll/poll_main.js +++ b/common/lib/xmodule/xmodule/js/src/poll/poll_main.js @@ -1,56 +1,55 @@ -(function (requirejs, require, define) { -define('PollMain', [], function () { +(function(requirejs, require, define) { + define('PollMain', [], function() { + PollMain.prototype = { -PollMain.prototype = { + 'showAnswerGraph': function(poll_answers, total) { + var _this, totalValue; -'showAnswerGraph': function (poll_answers, total) { - var _this, totalValue; + totalValue = parseFloat(total); + if (isFinite(totalValue) === false) { + return; + } - totalValue = parseFloat(total); - if (isFinite(totalValue) === false) { - return; - } + _this = this; - _this = this; + $.each(poll_answers, function(index, value) { + var numValue, percentValue; - $.each(poll_answers, function (index, value) { - var numValue, percentValue; + numValue = parseFloat(value); + if (isFinite(numValue) === false) { + return; + } - numValue = parseFloat(value); - if (isFinite(numValue) === false) { - return; - } + percentValue = (numValue / totalValue) * 100.0; - percentValue = (numValue / totalValue) * 100.0; + _this.answersObj[index].statsEl.show(); + _this.answersObj[index].numberEl.html('' + value + ' (' + percentValue.toFixed(1) + '%)'); + _this.answersObj[index].percentEl.css({ + 'width': '' + percentValue.toFixed(1) + '%' + }); + }); + }, - _this.answersObj[index].statsEl.show(); - _this.answersObj[index].numberEl.html('' + value + ' (' + percentValue.toFixed(1) + '%)'); - _this.answersObj[index].percentEl.css({ - 'width': '' + percentValue.toFixed(1) + '%' - }); - }); -}, - -'submitAnswer': function (answer, answerObj) { - var _this; + 'submitAnswer': function(answer, answerObj) { + var _this; // Make sure that the user can answer a question only once. - if (this.questionAnswered === true) { - return; - } - this.questionAnswered = true; + if (this.questionAnswered === true) { + return; + } + this.questionAnswered = true; - _this = this; + _this = this; - console.log('submit answer'); + console.log('submit answer'); - answerObj.buttonEl.addClass('answered'); + answerObj.buttonEl.addClass('answered'); // Send the data to the server as an AJAX request. Attach a callback that will // be fired on server's response. - $.postWithPrefix( - _this.ajax_url + '/' + answer, {}, - function (response) { + $.postWithPrefix( + _this.ajax_url + '/' + answer, {}, + function(response) { console.log('success! response = '); console.log(response); @@ -62,29 +61,28 @@ PollMain.prototype = { // Initialize Conditional constructors. if (_this.wrapperSectionEl !== null) { - $(_this.wrapperSectionEl).find('.xmodule_ConditionalModule').each(function (index, value) { + $(_this.wrapperSectionEl).find('.xmodule_ConditionalModule').each(function(index, value) { new window.Conditional(value, _this.id.replace(/^poll_/, '')); }); } } ); - -}, // End-of: 'submitAnswer': function (answer, answerEl) { + }, // End-of: 'submitAnswer': function (answer, answerEl) { -'submitReset': function () { - var _this; + 'submitReset': function() { + var _this; - _this = this; + _this = this; - console.log('submit reset'); + console.log('submit reset'); // Send the data to the server as an AJAX request. Attach a callback that will // be fired on server's response. - $.postWithPrefix( + $.postWithPrefix( this.ajax_url + '/' + 'reset_poll', {}, - function (response) { + function(response) { console.log('success! response = '); console.log(response); @@ -103,200 +101,200 @@ PollMain.prototype = { // Initialize Conditional constructors. We will specify the third parameter as 'true' // notifying the constructor that this is a reset operation. if (_this.wrapperSectionEl !== null) { - $(_this.wrapperSectionEl).find('.xmodule_ConditionalModule').each(function (index, value) { + $(_this.wrapperSectionEl).find('.xmodule_ConditionalModule').each(function(index, value) { new window.Conditional(value, _this.id.replace(/^poll_/, '')); }); } } ); -}, // End-of: 'submitAnswer': function (answer, answerEl) { + }, // End-of: 'submitAnswer': function (answer, answerEl) { -'postInit': function () { - var _this; + 'postInit': function() { + var _this; // Access this object inside inner functions. - _this = this; + _this = this; - if ( + if ( (this.jsonConfig.poll_answer.length > 0) && (this.jsonConfig.answers.hasOwnProperty(this.jsonConfig.poll_answer) === false) ) { - this.questionEl.append( + this.questionEl.append( '

    Error!

    ' + '

    XML data format changed. List of answers was modified, but poll data was not updated.

    ' ); - return; - } + return; + } // Get the DOM id of the question. - this.id = this.questionEl.attr('id'); + this.id = this.questionEl.attr('id'); // Get the URL to which we will post the users answer to the question. - this.ajax_url = this.questionEl.data('ajax-url'); + this.ajax_url = this.questionEl.data('ajax-url'); - this.questionHtmlMarkup = $('
    ').html(this.jsonConfig.question).text(); - this.questionEl.append(this.questionHtmlMarkup); + this.questionHtmlMarkup = $('
    ').html(this.jsonConfig.question).text(); + this.questionEl.append(this.questionHtmlMarkup); // When the user selects and answer, we will set this flag to true. - this.questionAnswered = false; + this.questionAnswered = false; - this.answersObj = {}; - this.shortVersion = true; + this.answersObj = {}; + this.shortVersion = true; - $.each(this.jsonConfig.answers, function (index, value) { - if (value.length >= 18) { - _this.shortVersion = false; - } - }); + $.each(this.jsonConfig.answers, function(index, value) { + if (value.length >= 18) { + _this.shortVersion = false; + } + }); - $.each(this.jsonConfig.answers, function (index, value) { - var answer; + $.each(this.jsonConfig.answers, function(index, value) { + var answer; - answer = {}; + answer = {}; - _this.answersObj[index] = answer; + _this.answersObj[index] = answer; - answer.el = $('
    '); + answer.el = $('
    '); - answer.questionEl = $('
    '); - answer.buttonEl = $('
    '); - answer.textEl = $('
    '); - answer.questionEl.append(answer.buttonEl); - answer.questionEl.append(answer.textEl); + answer.questionEl = $('
    '); + answer.buttonEl = $('
    '); + answer.textEl = $('
    '); + answer.questionEl.append(answer.buttonEl); + answer.questionEl.append(answer.textEl); - answer.el.append(answer.questionEl); + answer.el.append(answer.questionEl); - answer.statsEl = $('
    '); - answer.barEl = $('
    '); - answer.percentEl = $('
    '); - answer.barEl.append(answer.percentEl); - answer.numberEl = $('
    '); - answer.statsEl.append(answer.barEl); - answer.statsEl.append(answer.numberEl); + answer.statsEl = $('
    '); + answer.barEl = $('
    '); + answer.percentEl = $('
    '); + answer.barEl.append(answer.percentEl); + answer.numberEl = $('
    '); + answer.statsEl.append(answer.barEl); + answer.statsEl.append(answer.numberEl); - answer.statsEl.hide(); + answer.statsEl.hide(); - answer.el.append(answer.statsEl); + answer.el.append(answer.statsEl); - answer.textEl.html(value); + answer.textEl.html(value); - if (_this.shortVersion === true) { - $.each(answer, function (index, value) { - if (value instanceof jQuery) { - value.addClass('short'); + if (_this.shortVersion === true) { + $.each(answer, function(index, value) { + if (value instanceof jQuery) { + value.addClass('short'); + } + }); + } + + answer.el.appendTo(_this.questionEl); + + answer.textEl.on('click', function() { + _this.submitAnswer(index, answer); + }); + + answer.buttonEl.on('click', function() { + _this.submitAnswer(index, answer); + }); + + if (index === _this.jsonConfig.poll_answer) { + answer.buttonEl.addClass('answered'); + _this.questionAnswered = true; + } + }); + + console.log(this.jsonConfig.reset); + + if ((typeof this.jsonConfig.reset === 'string') && (this.jsonConfig.reset.toLowerCase() === 'true')) { + this.canReset = true; + + this.resetButton = $('
    Change your vote
    '); + + if (this.questionAnswered === false) { + this.resetButton.hide(); + } + + this.resetButton.appendTo(this.questionEl); + + this.resetButton.on('click', function() { + _this.submitReset(); + }); + } else { + this.canReset = false; } - }); - } - - answer.el.appendTo(_this.questionEl); - - answer.textEl.on('click', function () { - _this.submitAnswer(index, answer); - }); - - answer.buttonEl.on('click', function () { - _this.submitAnswer(index, answer); - }); - - if (index === _this.jsonConfig.poll_answer) { - answer.buttonEl.addClass('answered'); - _this.questionAnswered = true; - } - }); - - console.log(this.jsonConfig.reset); - - if ((typeof this.jsonConfig.reset === 'string') && (this.jsonConfig.reset.toLowerCase() === 'true')) { - this.canReset = true; - - this.resetButton = $('
    Change your vote
    '); - - if (this.questionAnswered === false) { - this.resetButton.hide(); - } - - this.resetButton.appendTo(this.questionEl); - - this.resetButton.on('click', function () { - _this.submitReset(); - }); - } else { - this.canReset = false; - } // If it turns out that the user already answered the question, show the answers graph. - if (this.questionAnswered === true) { - this.showAnswerGraph(this.jsonConfig.poll_answers, this.jsonConfig.total); - } -} // End-of: 'postInit': function () { -}; // End-of: PollMain.prototype = { + if (this.questionAnswered === true) { + this.showAnswerGraph(this.jsonConfig.poll_answers, this.jsonConfig.total); + } + } // End-of: 'postInit': function () { + }; // End-of: PollMain.prototype = { -return PollMain; + return PollMain; -function PollMain(el) { - var _this; + function PollMain(el) { + var _this; - this.questionEl = $(el).find('.poll_question'); - if (this.questionEl.length !== 1) { + this.questionEl = $(el).find('.poll_question'); + if (this.questionEl.length !== 1) { // We require one question DOM element. - console.log('ERROR: PollMain constructor requires one question DOM element.'); + console.log('ERROR: PollMain constructor requires one question DOM element.'); - return; - } + return; + } // Just a safety precussion. If we run this code more than once, multiple 'click' callback handlers will be // attached to the same DOM elements. We don't want this to happen. - if (this.questionEl.attr('poll_main_processed') === 'true') { - console.log( + if (this.questionEl.attr('poll_main_processed') === 'true') { + console.log( 'ERROR: PolMain JS constructor was called on a DOM element that has already been processed once.' ); - return; - } + return; + } // This element was not processed earlier. // Make sure that next time we will not process this element a second time. - this.questionEl.attr('poll_main_processed', 'true'); + this.questionEl.attr('poll_main_processed', 'true'); // Access this object inside inner functions. - _this = this; + _this = this; // DOM element which contains the current poll along with any conditionals. By default we assume that such // element is not present. We will try to find it. - this.wrapperSectionEl = null; + this.wrapperSectionEl = null; - (function (tempEl, c1) { - while (tempEl.tagName.toLowerCase() !== 'body') { - tempEl = $(tempEl).parent()[0]; - c1 += 1; + (function(tempEl, c1) { + while (tempEl.tagName.toLowerCase() !== 'body') { + tempEl = $(tempEl).parent()[0]; + c1 += 1; - if ( + if ( (tempEl.tagName.toLowerCase() === 'div') && ($(tempEl).data('block-type') === 'wrapper') ) { - _this.wrapperSectionEl = tempEl; + _this.wrapperSectionEl = tempEl; - break; - } else if (c1 > 50) { + break; + } else if (c1 > 50) { // In case something breaks, and we enter an endless loop, a sane // limit for loop iterations. - break; - } - } - }($(el)[0], 0)); + break; + } + } + }($(el)[0], 0)); - try { - this.jsonConfig = JSON.parse(this.questionEl.children('.poll_question_div').html()); + try { + this.jsonConfig = JSON.parse(this.questionEl.children('.poll_question_div').html()); - $.postWithPrefix( - '' + this.questionEl.data('ajax-url') + '/' + 'get_state', {}, - function (response) { + $.postWithPrefix( + '' + this.questionEl.data('ajax-url') + '/' + 'get_state', {}, + function(response) { _this.jsonConfig.poll_answer = response.poll_answer; _this.jsonConfig.total = response.total; - $.each(response.poll_answers, function (index, value) { + $.each(response.poll_answers, function(index, value) { _this.jsonConfig.poll_answers[index] = value; }); @@ -306,18 +304,17 @@ function PollMain(el) { } ); - return; - } catch (err) { - console.log( + return; + } catch (err) { + console.log( 'ERROR: Invalid JSON config for poll ID "' + this.id + '".', 'Error messsage: "' + err.message + '".' ); - return; - } -} // End-of: function PollMain(el) { - -}); // End-of: define('PollMain', [], function () { + return; + } + } // End-of: function PollMain(el) { + }); // End-of: define('PollMain', [], function () { // End-of: (function (requirejs, require, define) { }(RequireJS.requirejs, RequireJS.require, RequireJS.define)); diff --git a/common/lib/xmodule/xmodule/js/src/time.js b/common/lib/xmodule/xmodule/js/src/time.js index ab6580e388..2373768e9f 100644 --- a/common/lib/xmodule/xmodule/js/src/time.js +++ b/common/lib/xmodule/xmodule/js/src/time.js @@ -1,4 +1,4 @@ -(function (undefined) { +(function(undefined) { 'use strict'; this.Time = { diff --git a/common/lib/xmodule/xmodule/js/src/video/00_async_process.js b/common/lib/xmodule/xmodule/js/src/video/00_async_process.js index faffff7ca0..0461045a9f 100644 --- a/common/lib/xmodule/xmodule/js/src/video/00_async_process.js +++ b/common/lib/xmodule/xmodule/js/src/video/00_async_process.js @@ -1,9 +1,9 @@ -(function (define) { -define( +(function(define) { + define( 'video/00_async_process.js', [], function() { -"use strict"; + 'use strict'; /** * Provides convenient way to process big amount of data without UI blocking. * @@ -13,7 +13,7 @@ function() { * certain type bound to the collection, queued or not, have finished. */ var AsyncProcess = { - array: function (list, process) { + array: function(list, process) { if (!_.isArray(list)) { return $.Deferred().reject().promise(); } @@ -28,11 +28,11 @@ function() { index = 0, len = list.length; - var getCurrentTime = function () { + var getCurrentTime = function() { return (new Date()).getTime(); }; - var handler = function () { + var handler = function() { var start = getCurrentTime(); do { diff --git a/common/lib/xmodule/xmodule/js/src/video/00_component.js b/common/lib/xmodule/xmodule/js/src/video/00_component.js index 5c3e1d1004..1f72ef72f0 100644 --- a/common/lib/xmodule/xmodule/js/src/video/00_component.js +++ b/common/lib/xmodule/xmodule/js/src/video/00_component.js @@ -1,7 +1,7 @@ -(function (define) { -'use strict'; -define('video/00_component.js', [], -function () { +(function(define) { + 'use strict'; + define('video/00_component.js', [], +function() { /** * Creates a new object with the specified prototype object and properties. * @param {Object} o The object which should be the prototype of the @@ -10,10 +10,10 @@ function () { * @throws {TypeError, Error} * @return {Object} */ - var inherit = Object.create || (function () { - var F = function () {}; + var inherit = Object.create || (function() { + var F = function() {}; - return function (o) { + return function(o) { if (arguments.length > 1) { throw Error('Second argument not supported'); } @@ -36,7 +36,7 @@ function () { * @constructor * @return {jquery Promise} */ - var Component = function () { + var Component = function() { if ($.isFunction(this.initialize)) { return this.initialize.apply(this, arguments); } @@ -49,9 +49,9 @@ function () { * the prototype. * @return {Object} */ - Component.extend = function (protoProps, staticProps) { + Component.extend = function(protoProps, staticProps) { var Parent = this, - Child = function () { + Child = function() { if ($.isFunction(this.initialize)) { return this.initialize.apply(this, arguments); } diff --git a/common/lib/xmodule/xmodule/js/src/video/00_i18n.js b/common/lib/xmodule/xmodule/js/src/video/00_i18n.js index ba9f1f27db..c923a9be9e 100644 --- a/common/lib/xmodule/xmodule/js/src/video/00_i18n.js +++ b/common/lib/xmodule/xmodule/js/src/video/00_i18n.js @@ -1,6 +1,6 @@ -(function (define) { -'use strict'; -define( +(function(define) { + 'use strict'; + define( 'video/00_i18n.js', [], function() { diff --git a/common/lib/xmodule/xmodule/js/src/video/00_iterator.js b/common/lib/xmodule/xmodule/js/src/video/00_iterator.js index c6980b29ac..39bb19bb9b 100644 --- a/common/lib/xmodule/xmodule/js/src/video/00_iterator.js +++ b/common/lib/xmodule/xmodule/js/src/video/00_iterator.js @@ -1,21 +1,21 @@ -(function (define) { -define( +(function(define) { + define( 'video/00_iterator.js', [], function() { -"use strict"; + 'use strict'; /** * Provides convenient way to work with iterable data. * @exports video/00_iterator.js * @constructor * @param {array} list Array to be iterated. */ - var Iterator = function (list) { - this.list = list; - this.index = 0; - this.size = this.list.length; - this.lastIndex = this.list.length - 1; - }; + var Iterator = function(list) { + this.list = list; + this.index = 0; + this.size = this.list.length; + this.lastIndex = this.list.length - 1; + }; Iterator.prototype = { @@ -25,7 +25,7 @@ function() { * @param {numebr} index * @return {boolean} */ - _isValid: function (index) { + _isValid: function(index) { return _.isNumber(index) && index < this.size && index >= 0; }, @@ -34,12 +34,12 @@ function() { * @param {number} [index] Updates current position. * @return {any} */ - next: function (index) { + next: function(index) { if (!(this._isValid(index))) { index = this.index; } - this.index = (index >= this.lastIndex) ? 0: index + 1; + this.index = (index >= this.lastIndex) ? 0 : index + 1; return this.list[this.index]; }, @@ -49,12 +49,12 @@ function() { * @param {number} [index] Updates current position. * @return {any} */ - prev: function (index) { + prev: function(index) { if (!(this._isValid(index))) { index = this.index; } - this.index = (index < 1) ? this.lastIndex: index - 1; + this.index = (index < 1) ? this.lastIndex : index - 1; return this.list[this.index]; }, @@ -63,7 +63,7 @@ function() { * Returns last element in the list. * @return {any} */ - last: function () { + last: function() { return this.list[this.lastIndex]; }, @@ -71,7 +71,7 @@ function() { * Returns first element in the list. * @return {any} */ - first: function () { + first: function() { return this.list[0]; }, @@ -79,7 +79,7 @@ function() { * Returns `true` if current position is last for the iterator. * @return {boolean} */ - isEnd: function () { + isEnd: function() { return this.index === this.lastIndex; } }; diff --git a/common/lib/xmodule/xmodule/js/src/video/00_resizer.js b/common/lib/xmodule/xmodule/js/src/video/00_resizer.js index f0c1debcd0..d477c593f5 100644 --- a/common/lib/xmodule/xmodule/js/src/video/00_resizer.js +++ b/common/lib/xmodule/xmodule/js/src/video/00_resizer.js @@ -1,11 +1,9 @@ -(function (requirejs, require, define) { - -define( +(function(requirejs, require, define) { + define( 'video/00_resizer.js', [], -function () { - - var Resizer = function (params) { +function() { + var Resizer = function(params) { var defaults = { container: window, element: null, @@ -21,7 +19,7 @@ function () { mode = null, config; - var initialize = function (params) { + var initialize = function(params) { if (!config) { config = defaults; } @@ -37,7 +35,7 @@ function () { return module; }; - var getData = function () { + var getData = function() { var container = $(config.container), containerWidth = container.width() + delta.width, containerHeight = container.height() + delta.height, @@ -47,11 +45,11 @@ function () { elementRatio = config.elementRatio; if (!containerRatio) { - containerRatio = containerWidth/containerHeight; + containerRatio = containerWidth / containerHeight; } if (!elementRatio) { - elementRatio = element.width()/element.height(); + elementRatio = element.width() / element.height(); } return { @@ -63,25 +61,25 @@ function () { }; }; - var align = function () { + var align = function() { var data = getData(); switch (mode) { - case 'height': + case 'height': + alignByHeightOnly(); + break; + + case 'width': + alignByWidthOnly(); + break; + + default: + if (data.containerRatio >= data.elementRatio) { alignByHeightOnly(); - break; - - case 'width': + } else { alignByWidthOnly(); - break; - - default: - if (data.containerRatio >= data.elementRatio) { - alignByHeightOnly(); - } else { - alignByWidthOnly(); - } - break; + } + break; } fireCallbacks(); @@ -89,35 +87,35 @@ function () { return module; }; - var alignByWidthOnly = function () { + var alignByWidthOnly = function() { var data = getData(), - height = data.containerWidth/data.elementRatio; + height = data.containerWidth / data.elementRatio; data.element.css({ 'height': height, 'width': data.containerWidth, - 'top': 0.5*(data.containerHeight - height), + 'top': 0.5 * (data.containerHeight - height), 'left': 0 }); return module; }; - var alignByHeightOnly = function () { + var alignByHeightOnly = function() { var data = getData(), - width = data.containerHeight*data.elementRatio; + width = data.containerHeight * data.elementRatio; data.element.css({ 'height': data.containerHeight, - 'width': data.containerHeight*data.elementRatio, + 'width': data.containerHeight * data.elementRatio, 'top': 0, - 'left': 0.5*(data.containerWidth - width) + 'left': 0.5 * (data.containerWidth - width) }); return module; }; - var setMode = function (param) { + var setMode = function(param) { if (_.isString(param)) { mode = param; align(); @@ -126,13 +124,13 @@ function () { return module; }; - var setElement = function (element) { + var setElement = function(element) { config.element = element; return module; }; - var addCallback = function (func) { + var addCallback = function(func) { if ($.isFunction(func)) { callbacksList.push(func); } else { @@ -142,9 +140,9 @@ function () { return module; }; - var addOnceCallback = function (func) { + var addOnceCallback = function(func) { if ($.isFunction(func)) { - var decorator = function () { + var decorator = function() { func(); removeCallback(func); }; @@ -157,19 +155,19 @@ function () { return module; }; - var fireCallbacks = function () { + var fireCallbacks = function() { $.each(callbacksList, function(index, callback) { - callback(); + callback(); }); }; - var removeCallbacks = function () { + var removeCallbacks = function() { callbacksList.length = 0; return module; }; - var removeCallback = function (func) { + var removeCallback = function(func) { var index = $.inArray(func, callbacksList); if (index !== -1) { @@ -177,13 +175,13 @@ function () { } }; - var resetDelta = function () { + var resetDelta = function() { delta['height'] = delta['width'] = 0; return module; }; - var addDelta = function (value, side) { + var addDelta = function(value, side) { if (_.isNumber(value) && _.isNumber(delta[side])) { delta[side] += value; } @@ -191,7 +189,7 @@ function () { return module; }; - var substractDelta = function (value, side) { + var substractDelta = function(value, side) { if (_.isNumber(value) && _.isNumber(delta[side])) { delta[side] -= value; } @@ -199,7 +197,7 @@ function () { return module; }; - var destroy = function () { + var destroy = function() { var data = getData(); data.element.css({ 'height': '', 'width': '', 'top': '', 'left': '' @@ -235,5 +233,4 @@ function () { return Resizer; }); - }(RequireJS.requirejs, RequireJS.require, RequireJS.define)); diff --git a/common/lib/xmodule/xmodule/js/src/video/00_sjson.js b/common/lib/xmodule/xmodule/js/src/video/00_sjson.js index d5163d9a00..954313c278 100644 --- a/common/lib/xmodule/xmodule/js/src/video/00_sjson.js +++ b/common/lib/xmodule/xmodule/js/src/video/00_sjson.js @@ -1,20 +1,19 @@ -(function (define) { - -define( +(function(define) { + define( 'video/00_sjson.js', [], function() { -"use strict"; + 'use strict'; - var Sjson = function (data) { + var Sjson = function(data) { var sjson = { start: data.start.concat(), text: data.text.concat() }, module = {}; - var getter = function (propertyName) { - return function () { + var getter = function(propertyName) { + return function() { return sjson[propertyName]; }; }; @@ -23,7 +22,7 @@ function() { var getCaptions = getter('text'); - var size = function () { + var size = function() { return sjson.text.length; }; @@ -40,11 +39,11 @@ function() { // Else, search the unfiltered list. if (typeof startTime !== 'undefined' && typeof endTime !== 'undefined') { - results = filter(startTime, endTime); - start = results.start; - max = results.captions.length - 1; + results = filter(startTime, endTime); + start = results.start; + max = results.captions.length - 1; } else { - start = getStartTimes(); + start = getStartTimes(); } while (min < max) { index = Math.ceil((max + min) / 2); @@ -59,7 +58,7 @@ function() { } return min; - }; + } function filter(start, end) { /* filters captions that occur between inputs @@ -79,7 +78,7 @@ function() { var captions = getCaptions(); if (startTimes.length !== captions.length) { - console.warn("video caption and start time arrays do not match in length"); + console.warn('video caption and start time arrays do not match in length'); } // if end is null, then it's been set to diff --git a/common/lib/xmodule/xmodule/js/src/video/00_video_storage.js b/common/lib/xmodule/xmodule/js/src/video/00_video_storage.js index 7b1f38a6c6..5b226e5f43 100644 --- a/common/lib/xmodule/xmodule/js/src/video/00_video_storage.js +++ b/common/lib/xmodule/xmodule/js/src/video/00_video_storage.js @@ -1,17 +1,16 @@ -(function (requirejs, require, define) { - -define( +(function(requirejs, require, define) { + define( 'video/00_video_storage.js', [], function() { - "use strict"; + 'use strict'; /** * Provides convenient way to store key value pairs. * * @param {string} namespace Namespace that is used to store data. * @return {object} VideoStorage API. */ - var VideoStorage = function (namespace, id) { + var VideoStorage = function(namespace, id) { /** * Adds new value to the storage or rewrites existent. * @@ -20,7 +19,7 @@ function() { * @param {boolean} instanceSpecific Data with this flag will be added * to instance specific storage. */ - var setItem = function (name, value, instanceSpecific) { + var setItem = function(name, value, instanceSpecific) { if (name) { if (instanceSpecific) { window[namespace][id][name] = value; @@ -40,7 +39,7 @@ function() { * If the given key does not exist in the list * associated with the object then this method must return null. */ - var getItem = function (name, instanceSpecific) { + var getItem = function(name, instanceSpecific) { if (instanceSpecific) { return window[namespace][id][name]; } else { @@ -55,7 +54,7 @@ function() { * @param {boolean} instanceSpecific Data with this flag will be added * to instance specific storage. */ - var removeItem = function (name, instanceSpecific) { + var removeItem = function(name, instanceSpecific) { if (instanceSpecific) { delete window[namespace][id][name]; } else { @@ -67,7 +66,7 @@ function() { * Empties the storage. * */ - var clear = function () { + var clear = function() { window[namespace] = {}; window[namespace][id] = {}; }; diff --git a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js index ac59870d88..679b6d42c9 100644 --- a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js +++ b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js @@ -10,12 +10,11 @@ * @module Initialize */ -(function (requirejs, require, define) { - -define( +(function(requirejs, require, define) { + define( 'video/01_initialize.js', ['video/03_video_player.js', 'video/00_i18n.js', 'moment'], -function (VideoPlayer, i18n, moment) { +function(VideoPlayer, i18n, moment) { var moment = moment || window.moment; /** * @function @@ -27,11 +26,11 @@ function (VideoPlayer, i18n, moment) { * available via this object. * @param {DOM element} element Container of the entire Video DOM element. */ - var Initialize = function (state, element) { - _makeFunctionsPublic(state); + var Initialize = function(state, element) { + _makeFunctionsPublic(state); - state.initialize(element) - .done(function () { + state.initialize(element) + .done(function() { if (state.isYoutubeType()) { state.parseSpeed(); } @@ -44,7 +43,7 @@ function (VideoPlayer, i18n, moment) { } _initializeModules(state, i18n) - .done(function () { + .done(function() { // On iPad ready state occurs just after start playing. // We hide controls before video starts playing. if (/iPad|Android/i.test(state.isTouch[0])) { @@ -60,30 +59,30 @@ function (VideoPlayer, i18n, moment) { state.el.trigger('initialize', arguments); }); }); - }, + }, - methodsDict = { - bindTo: bindTo, - fetchMetadata: fetchMetadata, - getCurrentLanguage: getCurrentLanguage, - getDuration: getDuration, - getPlayerMode: getPlayerMode, - getVideoMetadata: getVideoMetadata, - initialize: initialize, - isHtml5Mode: isHtml5Mode, - isFlashMode: isFlashMode, - isYoutubeType: isYoutubeType, - parseSpeed: parseSpeed, - parseYoutubeStreams: parseYoutubeStreams, - setPlayerMode: setPlayerMode, - setSpeed: setSpeed, - speedToString: speedToString, - trigger: trigger, - youtubeId: youtubeId, - loadHtmlPlayer: loadHtmlPlayer, - loadYoutubePlayer: loadYoutubePlayer, - loadYouTubeIFrameAPI: loadYouTubeIFrameAPI - }, + methodsDict = { + bindTo: bindTo, + fetchMetadata: fetchMetadata, + getCurrentLanguage: getCurrentLanguage, + getDuration: getDuration, + getPlayerMode: getPlayerMode, + getVideoMetadata: getVideoMetadata, + initialize: initialize, + isHtml5Mode: isHtml5Mode, + isFlashMode: isFlashMode, + isYoutubeType: isYoutubeType, + parseSpeed: parseSpeed, + parseYoutubeStreams: parseYoutubeStreams, + setPlayerMode: setPlayerMode, + setSpeed: setSpeed, + speedToString: speedToString, + trigger: trigger, + youtubeId: youtubeId, + loadHtmlPlayer: loadHtmlPlayer, + loadYoutubePlayer: loadYoutubePlayer, + loadYouTubeIFrameAPI: loadYouTubeIFrameAPI + }, _youtubeApiDeferred = null, _oldOnYouTubeIframeAPIReady; @@ -130,7 +129,7 @@ function (VideoPlayer, i18n, moment) { if (state.videoType === 'youtube') { state.youtubeApiAvailable = false; - onYTApiReady = function () { + onYTApiReady = function() { console.log('[Video info]: YouTube API is available and is loaded.'); if (state.htmlPlayerLoaded) { return; } @@ -162,10 +161,10 @@ function (VideoPlayer, i18n, moment) { // // If this global function is already defined, we store it first, and make // sure that it gets executed when our Deferred object is resolved. - setupOnYouTubeIframeAPIReady = function () { + setupOnYouTubeIframeAPIReady = function() { _oldOnYouTubeIframeAPIReady = window.onYouTubeIframeAPIReady || undefined; - window.onYouTubeIframeAPIReady = function () { + window.onYouTubeIframeAPIReady = function() { window.onYouTubeIframeAPIReady.resolve(); }; @@ -194,7 +193,7 @@ function (VideoPlayer, i18n, moment) { // Attach a callback to our Deferred object to be called once the // YouTube API loads. - window.onYouTubeIframeAPIReady.done(function () { + window.onYouTubeIframeAPIReady.done(function() { window.YT.ready(onYTApiReady); }); } @@ -209,7 +208,7 @@ function (VideoPlayer, i18n, moment) { function _waitForYoutubeApi(state) { console.log('[Video info]: Starting to wait for YouTube API to load.'); - window.setTimeout(function () { + window.setTimeout(function() { // If YouTube API will load OK, it will run `onYouTubeIframeAPIReady` // callback, which will set `state.youtubeApiAvailable` to `true`. // If something goes wrong at this stage, `state.youtubeApiAvailable` is @@ -222,7 +221,6 @@ function (VideoPlayer, i18n, moment) { } state.el.trigger('youtube_availability', [state.youtubeApiAvailable]); }, state.config.ytTestTimeout); - } function loadYouTubeIFrameAPI(scriptTag) { @@ -337,7 +335,7 @@ function (VideoPlayer, i18n, moment) { } else if ($.isPlainObject(module)) { return module; } - }); + }); $.when.apply(null, modulesList) .done(dfd.resolve); @@ -346,101 +344,101 @@ function (VideoPlayer, i18n, moment) { } function _getConfiguration(data, storage) { - var isBoolean = function (value) { - var regExp = /^true$/i; - return regExp.test(value.toString()); - }, + var isBoolean = function(value) { + var regExp = /^true$/i; + return regExp.test(value.toString()); + }, // List of keys that will be extracted form the configuration. - extractKeys = [], + extractKeys = [], // Compatibility keys used to change names of some parameters in // the final configuration. - compatKeys = { - 'start': 'startTime', - 'end': 'endTime' - }, + compatKeys = { + 'start': 'startTime', + 'end': 'endTime' + }, // Conversions used to pre-process some configuration data. - conversions = { - 'showCaptions': isBoolean, - 'autoplay': isBoolean, - 'autohideHtml5': isBoolean, - 'savedVideoPosition': function (value) { - return storage.getItem('savedVideoPosition', true) || + conversions = { + 'showCaptions': isBoolean, + 'autoplay': isBoolean, + 'autohideHtml5': isBoolean, + 'savedVideoPosition': function(value) { + return storage.getItem('savedVideoPosition', true) || Number(value) || 0; - }, - 'speed': function (value) { - return storage.getItem('speed', true) || value; - }, - 'generalSpeed': function (value) { - return storage.getItem('general_speed') || + }, + 'speed': function(value) { + return storage.getItem('speed', true) || value; + }, + 'generalSpeed': function(value) { + return storage.getItem('general_speed') || value || '1.0'; - }, - 'transcriptLanguage': function (value) { - return storage.getItem('language') || + }, + 'transcriptLanguage': function(value) { + return storage.getItem('language') || value || 'en'; - }, - 'ytTestTimeout': function (value) { - value = parseInt(value, 10); - - if (!isFinite(value)) { - value = 1500; - } - - return value; - }, - 'startTime': function (value) { - value = parseInt(value, 10); - if (!isFinite(value) || value < 0) { - return 0; - } - - return value; - }, - 'endTime': function (value) { - value = parseInt(value, 10); - - if (!isFinite(value) || value === 0) { - return null; - } - - return value; - } }, - config = {}; + 'ytTestTimeout': function(value) { + value = parseInt(value, 10); - data = _.extend({ - startTime: 0, - endTime: null, - sub: '', - streams: '' - }, data); + if (!isFinite(value)) { + value = 1500; + } - $.each(data, function(option, value) { - // Extract option that is in `extractKeys`. - if ($.inArray(option, extractKeys) !== -1) { - return; + return value; + }, + 'startTime': function(value) { + value = parseInt(value, 10); + if (!isFinite(value) || value < 0) { + return 0; + } + + return value; + }, + 'endTime': function(value) { + value = parseInt(value, 10); + + if (!isFinite(value) || value === 0) { + return null; + } + + return value; } + }, + config = {}; + + data = _.extend({ + startTime: 0, + endTime: null, + sub: '', + streams: '' + }, data); + + $.each(data, function(option, value) { + // Extract option that is in `extractKeys`. + if ($.inArray(option, extractKeys) !== -1) { + return; + } // Change option name to key that is in `compatKeys`. - if (compatKeys[option]) { - option = compatKeys[option]; - } + if (compatKeys[option]) { + option = compatKeys[option]; + } // Pre-process data. - if (conversions[option]) { - if (_.isFunction(conversions[option])) { - value = conversions[option].call(this, value); - } else { - throw new TypeError(option + ' is not a function.'); - } + if (conversions[option]) { + if (_.isFunction(conversions[option])) { + value = conversions[option].call(this, value); + } else { + throw new TypeError(option + ' is not a function.'); } - config[option] = value; - }); + } + config[option] = value; + }); - return config; - } + return config; + } // *************************************************************** // Public functions start here. @@ -456,7 +454,6 @@ function (VideoPlayer, i18n, moment) { function bindTo(methodsDict, obj, context, rewrite) { $.each(methodsDict, function(name, method) { if (_.isFunction(method)) { - if (_.isUndefined(rewrite)) { rewrite = true; } @@ -480,7 +477,6 @@ function (VideoPlayer, i18n, moment) { } function loadHtmlPlayer() { - // When the youtube link doesn't work for any reason // (for example, firewall) any // alternate sources should automatically play. @@ -563,10 +559,8 @@ function (VideoPlayer, i18n, moment) { _setConfigurations(this); if (!(_parseYouTubeIDs(this))) { - // If we do not have YouTube ID's, try parsing HTML5 video sources. if (!_prepareHTML5Video(this)) { - __dfd__.reject(); // Non-YouTube sources were not found either. return __dfd__.promise(); @@ -623,7 +617,7 @@ function (VideoPlayer, i18n, moment) { this.videos = {}; - _.each(youtubeStreams.split(/,/), function (video) { + _.each(youtubeStreams.split(/,/), function(video) { var speed; video = video.split(/:/); speed = this.speedToString(video[0]); @@ -645,8 +639,8 @@ function (VideoPlayer, i18n, moment) { this.metadata = {}; - metadataXHRs = _.map(this.videos, function (url, speed) { - return self.getVideoMetadata(url, function (data) { + metadataXHRs = _.map(this.videos, function(url, speed) { + return self.getVideoMetadata(url, function(data) { if (data.items.length > 0) { var metaDataItem = data.items[0]; self.metadata[metaDataItem.id] = metaDataItem.contentDetails; @@ -654,7 +648,7 @@ function (VideoPlayer, i18n, moment) { }); }); - $.when.apply(this, metadataXHRs).done(function () { + $.when.apply(this, metadataXHRs).done(function() { self.el.trigger('metadata_received'); // Not only do we trigger the "metadata_received" event, we also @@ -664,7 +658,6 @@ function (VideoPlayer, i18n, moment) { // cases when some code will subscribe to the "metadata_received" // event after it has been triggered. self.youtubeMetadataReceived = true; - }); } @@ -715,7 +708,7 @@ function (VideoPlayer, i18n, moment) { function youtubeId(speed) { var currentSpeed = this.isFlashMode() ? this.speed : '1.0'; - return this.videos[speed] || + return this.videos[speed] || this.videos[currentSpeed] || this.videos['1.0']; } @@ -836,5 +829,4 @@ function (VideoPlayer, i18n, moment) { return true; } }); - }(RequireJS.requirejs, RequireJS.require, RequireJS.define)); diff --git a/common/lib/xmodule/xmodule/js/src/video/025_focus_grabber.js b/common/lib/xmodule/xmodule/js/src/video/025_focus_grabber.js index 65b85efebc..b3e47e13cc 100644 --- a/common/lib/xmodule/xmodule/js/src/video/025_focus_grabber.js +++ b/common/lib/xmodule/xmodule/js/src/video/025_focus_grabber.js @@ -25,14 +25,13 @@ * ~ Zen saying */ -(function (requirejs, require, define) { - +(function(requirejs, require, define) { // FocusGrabber module. -define( + define( 'video/025_focus_grabber.js', [], -function () { - return function (state) { +function() { + return function(state) { var dfd = $.Deferred(); state.focusGrabber = {}; @@ -75,7 +74,7 @@ function () { // When the video container element receives programmatic focus, then // on un-focus ('blur' event) we should trigger a 'mousemove' event so // as to reveal autohidden controls. - state.el.on('blur', function () { + state.el.on('blur', function() { state.el.trigger('mousemove'); }); } diff --git a/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js b/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js index 4a6c6096b4..93759ee468 100644 --- a/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js +++ b/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js @@ -13,16 +13,15 @@ * @module HTML5Video */ -(function (requirejs, require, define) { - -define( +(function(requirejs, require, define) { + define( 'video/02_html5_video.js', [], -function () { +function() { var HTML5Video = {}; - HTML5Video.Player = (function () { - Player.prototype.callStateChangeCallback = function () { + HTML5Video.Player = (function() { + Player.prototype.callStateChangeCallback = function() { if ($.isFunction(this.config.events.onStateChange)) { this.config.events.onStateChange({ data: this.playerState @@ -30,11 +29,11 @@ function () { } }; - Player.prototype.pauseVideo = function () { + Player.prototype.pauseVideo = function() { this.video.pause(); }; - Player.prototype.seekTo = function (value) { + Player.prototype.seekTo = function(value) { if ( typeof value === 'number' && value <= this.video.duration && @@ -44,29 +43,29 @@ function () { } }; - Player.prototype.setVolume = function (value) { + Player.prototype.setVolume = function(value) { if (typeof value === 'number' && value <= 100 && value >= 0) { this.video.volume = value * 0.01; } }; - Player.prototype.getCurrentTime = function () { + Player.prototype.getCurrentTime = function() { return this.video.currentTime; }; - Player.prototype.playVideo = function () { + Player.prototype.playVideo = function() { this.video.play(); }; - Player.prototype.getPlayerState = function () { + Player.prototype.getPlayerState = function() { return this.playerState; }; - Player.prototype.getVolume = function () { + Player.prototype.getVolume = function() { return this.video.volume; }; - Player.prototype.getDuration = function () { + Player.prototype.getDuration = function() { if (isNaN(this.video.duration)) { return 0; } @@ -74,7 +73,7 @@ function () { return this.video.duration; }; - Player.prototype.setPlaybackRate = function (value) { + Player.prototype.setPlaybackRate = function(value) { var newSpeed; newSpeed = parseFloat(value); @@ -86,15 +85,15 @@ function () { } }; - Player.prototype.getAvailablePlaybackRates = function () { + Player.prototype.getAvailablePlaybackRates = function() { return [0.75, 1.0, 1.25, 1.5]; }; - Player.prototype._getLogs = function () { + Player.prototype._getLogs = function() { return this.logs; }; - Player.prototype.showErrorMessage = function () { + Player.prototype.showErrorMessage = function() { this.el .find('.video-player div') .addClass('hidden') @@ -110,13 +109,13 @@ function () { }); }; - Player.prototype.onError = function (event) { + Player.prototype.onError = function(event) { if ($.isFunction(this.config.events.onError)) { this.config.events.onError(); } }; - Player.prototype.destroy = function () { + Player.prototype.destroy = function() { this.video.removeEventListener('loadedmetadata', this.onLoadedMetadata, false); this.video.removeEventListener('play', this.onPlay, false); this.video.removeEventListener('playing', this.onPlaying, false); @@ -131,29 +130,29 @@ function () { this.videoEl.remove(); }; - Player.prototype.onLoadedMetadata = function () { + Player.prototype.onLoadedMetadata = function() { this.playerState = HTML5Video.PlayerState.PAUSED; if ($.isFunction(this.config.events.onReady)) { this.config.events.onReady(null); } }; - Player.prototype.onPlay = function () { + Player.prototype.onPlay = function() { this.playerState = HTML5Video.PlayerState.BUFFERING; this.callStateChangeCallback(); }; - Player.prototype.onPlaying = function () { + Player.prototype.onPlaying = function() { this.playerState = HTML5Video.PlayerState.PLAYING; this.callStateChangeCallback(); }; - Player.prototype.onPause = function () { + Player.prototype.onPause = function() { this.playerState = HTML5Video.PlayerState.PAUSED; this.callStateChangeCallback(); }; - Player.prototype.onEnded = function () { + Player.prototype.onEnded = function() { this.playerState = HTML5Video.PlayerState.ENDED; this.callStateChangeCallback(); }; @@ -242,16 +241,16 @@ function () { // Create HTML markup for individual sources of the HTML5
    diff --git a/lms/templates/discussion/_js_body_dependencies.html b/lms/templates/discussion/_js_body_dependencies.html index 447af19652..fda375a109 100644 --- a/lms/templates/discussion/_js_body_dependencies.html +++ b/lms/templates/discussion/_js_body_dependencies.html @@ -1,3 +1,37 @@ -<%page args="disable_fast_preview=True"/> +## mako + +<%namespace name='static' file='/static_content.html'/> + +<%page args="disable_fast_preview=True" expression_filter="h"/> + +<%! +from openedx.core.djangolib.js_utils import js_escaped_string +%> <%include file="/mathjax_include.html" args="disable_fast_preview=disable_fast_preview"/> + +<%static:js group='discussion'/> + +## Add RequireJS definitions for each discussion class +<% +discussion_classes = [ + ['Discussion', 'common/js/discussion/discussion'], + ['DiscussionModuleView', 'common/js/discussion/discussion_module_view'], + ['DiscussionThreadView', 'common/js/discussion/views/discussion_thread_view'], + ['DiscussionThreadListView', 'common/js/discussion/views/discussion_thread_list_view'], + ['DiscussionThreadProfileView', 'common/js/discussion/views/discussion_thread_profile_view'], + ['DiscussionUtil', 'common/js/discussion/utils'], + ['NewPostView', 'common/js/discussion/views/new_post_view'], +] +%> + diff --git a/lms/templates/discussion/_thread_list_template.html b/lms/templates/discussion/_thread_list_template.html index f5f78a1c3a..d0d73f7ce4 100644 --- a/lms/templates/discussion/_thread_list_template.html +++ b/lms/templates/discussion/_thread_list_template.html @@ -1,26 +1,6 @@ <%page expression_filter="h"/> <%! from django.utils.translation import ugettext as _ %> %endif - diff --git a/lms/templates/static_htmlbook.html b/lms/templates/static_htmlbook.html index dafd473b56..c452837370 100644 --- a/lms/templates/static_htmlbook.html +++ b/lms/templates/static_htmlbook.html @@ -126,7 +126,7 @@ from openedx.core.djangolib.js_utils import (
      <%def name="print_entry(entry, index_value)">
    • - + ${entry.get('title')}
    • diff --git a/lms/templates/static_pdfbook.html b/lms/templates/static_pdfbook.html index 4b1079250b..b73d3f15d4 100644 --- a/lms/templates/static_pdfbook.html +++ b/lms/templates/static_pdfbook.html @@ -1,8 +1,14 @@ +<%page expression_filter="h"/> <%! from django.utils.translation import ugettext as _ %> <%inherit file="main.html" /> <%namespace name='static' file='static_content.html'/> -<%block name="pagetitle">${_('{course_number} Textbook').format(course_number=course.display_number_with_default) | h} +<%! +from openedx.core.djangolib.js_utils import ( + js_escaped_string +) +%> +<%block name="pagetitle">${_('{course_number} Textbook').format(course_number=course.display_number_with_default)} <%block name="headextra"> <%static:css group='style-course-vendor'/> <%static:css group='style-course'/> @@ -13,11 +19,11 @@ <%include file="/courseware/course_navigation.html" args="active_page='pdftextbook/{0}'.format(book_index)" /> + + diff --git a/themes/example/lms/templates/course.html b/themes/example/lms/templates/course.html new file mode 100644 index 0000000000..c68f72ff2f --- /dev/null +++ b/themes/example/lms/templates/course.html @@ -0,0 +1,31 @@ +## mako +<%namespace name='static' file='static_content.html'/> +<%! +from django.utils.translation import ugettext as _ +from django.core.urlresolvers import reverse +%> +<%page args="course" expression_filter="h"/> + diff --git a/themes/example/lms/templates/courses_list.html b/themes/example/lms/templates/courses_list.html new file mode 100644 index 0000000000..e8375cf653 --- /dev/null +++ b/themes/example/lms/templates/courses_list.html @@ -0,0 +1,37 @@ +## mako +<%page expression_filter="h"/> +<%namespace name='static' file='static_content.html'/> +<%! from django.utils.translation import ugettext as _ %> + +
      +
      +
      + + % if settings.FEATURES.get('COURSES_ARE_BROWSABLE'): +
      + +
      +
      +
      +

      + Lorem ipsum dolor sit amet +

      +
      +
      + +
      + %for course in courses[:6]: +
      +
      + <%include file="course.html" args="course=course" /> +
      +
      + %endfor +
      +
      +
      + % endif + +
      +
      +
      diff --git a/themes/example/lms/templates/courseware/course_about.html b/themes/example/lms/templates/courseware/course_about.html new file mode 100644 index 0000000000..cc55782851 --- /dev/null +++ b/themes/example/lms/templates/courseware/course_about.html @@ -0,0 +1,428 @@ +## mako +<%page expression_filter="h"/> +<%namespace name='static' file='../static_content.html'/> +<%! +from itertools import izip_longest +from django.utils.translation import ugettext as _ +from django.core.urlresolvers import reverse +from courseware.courses import get_course_about_section +from django.conf import settings +from edxmako.shortcuts import marketing_link +from openedx.core.lib.courses import course_image_url +from openedx.core.djangolib.markup import HTML, Text +from openedx.core.djangolib.js_utils import js_escaped_string + +%> + +<%inherit file="../main.html" /> +<%block name="headextra"> + + ## OG (Open Graph) title and description added below to give social media info to display + ## (https://developers.facebook.com/docs/opengraph/howtos/maximizing-distribution-media-content#tags) + + + + + +<%block name="js_extra"> + ## CourseTalk widget js script + % if show_coursetalk_widget: + + % endif + + + + + <%include file="../about_site.html" /> + + + + + +<%block name="pagetitle">${course.display_name_with_default} + +
      +
      +
      +
      +
      +
      +
      +
      +
      + +
      +
      +
      +

      ${course_details.title or course.display_name}

      +

      ${course_details.subtitle}

      +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      + +
      + Start Date: + ${course_details.start_date.strftime('%b %-d, %Y')} +
      +
      + Duration: + ${course_details.duration} +
      + +
      + Price: + ${course_price} +
      + <% + btn_text = 'Enroll Now' + btn_href = '#' + btn_class = '' + btn_class_bulk = '' + btn_id = '' + %> + + % if user.is_authenticated() and registered: + <% + btn_text = "You are enrolled in this course" + btn_class = "disabled" + %> + + % elif in_cart: + <% + btn_text = "This course is in your cart" + btn_href = cart_link + %> + + % elif is_course_full: + <% + btn_text = "Course is full" + btn_class = "disabled" + btn_class_bulk = btn_class + %> + + % elif invitation_only and not can_enroll: + <% + btn_text = "Enrollment in this course is by invitation only" + btn_class = "disabled" + btn_class_bulk = btn_class + %> + + % elif not is_shib_course and not can_enroll: + <% + btn_text = "Enrollment is Closed" + btn_class = "disabled" + btn_class_bulk = btn_class + %> + + % elif can_add_course_to_cart: + <% + btn_class = "add-to-cart" + btn_text = "Enroll Now" + %> + + % if user.is_authenticated(): + % if user.is_active: + <% + btn_href = "#" + btn_id = "add_to_cart_post" + %> + % else: + <% + btn_text = "Please Activate Your Account" + btn_class = "disabled" + %> + % endif + % else: + <% + btn_href = reg_then_add_to_cart_link + btn_id = "reg_then_add_to_cart" + %> + % endif + + % if ecommerce_checkout and ecommerce_checkout_link and user.is_authenticated(): + <% + btn_href = ecommerce_checkout_link + %> + % endif + + % else: + % if ecommerce_checkout: + % if ecommerce_checkout_link: + <% btn_href = ecommerce_checkout_link %> + % else: + <% btn_href="#" %> + % endif + % if professional_mode: + % if user.is_authenticated(): + <% btn_class = "add-to-cart" %> + % else: + <% + btn_class = "register" + btn_class_bulk = btn_class + %> + % endif + % endif + % endif + % endif + +
      +
      +
      +
      +
      +
      +
      +
      +
      + +

      Course Description

      +
      +

      ${course_details.description}

      +
      + +

      What you'll learn

      +
      +
        + % for item in course_details.learning_info: +
      • ${item}
      • + %endfor +
      +
      +
      + % if can_enroll and not is_course_full: +
      +
      +

      ${_("Want to purchase this course for a group?")}

      +

      ${_("You can purchase enrollment codes for this course to distribute to your team")}

      + + % if ecommerce_bulk_checkout_link: + <% + url = "mailto:harvardxplus@harvard.edu?Subject={course_id}%20{run}%20Bulk%20Discount".format(course_id=course_details.course_id, run=course_details.run) + link_start = HTML("").format(url=Text(url)) + %> + ${_("Purchase for a Group")} +

      + ${Text(_("Bulk discounts may apply for groups larger than 10. Contact {link_start}harvardxplus@harvard.edu{link_end} for more information.")).format( + link_start=HTML(link_start), + link_end=HTML('') + )} +

      + % else: + <% + url = "mailto:harvardxplus@harvard.edu?Subject={course_id}%20{run}%20Group%20Purchase".format( + course_id=course_details.course_id, run=course_details.run) + %> + ${_("Email Us")} + % endif +
      +
      + % endif +
      +

      Instructors

      + <% index = 0 %> + % for instructors in izip_longest(*([iter(course_details.instructor_info['instructors'])] * 2)): +
      + % for instructor in [i for i in instructors if i is not None]: + <% index += 1 %> +
      +
      + ${instructor['name']} +
      +

      ${instructor['name']} ${instructor['title']}

      + +
      + % endfor +
      + % endfor +
      +
      +
      +
      +
      +
      +
      +
      + ${HTML(course_details.overview)} +
      +
      +
      +
      +
      +
      + +
      +
      + +
      + +## Need to put this hidden form on the page so that the registration button works. +## Since it's no harm to display a hidden form, we display it with the most permissive conditional +## which is when the student is not registered. +%if active_reg_button or is_shib_course: +
      +
      +
      + ${_("Enroll")} + + +
      +
      + +
      +
      +
      +%endif + +% if course_details.intro_video and course_details.video_thumbnail_image_name: + +% endif diff --git a/themes/example/lms/templates/courseware/courses.html b/themes/example/lms/templates/courseware/courses.html new file mode 100644 index 0000000000..8f1ca44206 --- /dev/null +++ b/themes/example/lms/templates/courseware/courses.html @@ -0,0 +1,49 @@ +## mako +<%page expression_filter="h"/> +<%! from django.utils.translation import ugettext as _ %> +<%inherit file="../main.html" /> +<%namespace name='static' file='../static_content.html'/> + +
      +
      +
      +
      +
      +
      +

      Lorem ipsum dolor sit amet, sea te quaeque suscipiantur.

      +
      +
      +
      +
      +
      + +
      +
      +
      +
      +
      + +
      +
      +

      + ${_('Lorem ipsum dolor sit amet.')} +

      +
      +
      + +
      + %for course in courses: +
      +
      + <%include file="../course.html" args="course=course"/> +
      +
      + %endfor +
      + +
      +
      +
      +
      +
      +
      diff --git a/themes/example/lms/templates/footer.html b/themes/example/lms/templates/footer.html new file mode 100644 index 0000000000..502b046797 --- /dev/null +++ b/themes/example/lms/templates/footer.html @@ -0,0 +1,58 @@ +## mako +<%page expression_filter="h"/> +<%namespace name='static' file='static_content.html'/> + + diff --git a/themes/example/lms/templates/head-extra.html b/themes/example/lms/templates/head-extra.html new file mode 100644 index 0000000000..239cc9b864 --- /dev/null +++ b/themes/example/lms/templates/head-extra.html @@ -0,0 +1,19 @@ +## mako +<%page expression_filter="h"/> +<%namespace name='static' file='static_content.html'/> + + + + + + diff --git a/themes/example/lms/templates/header.html b/themes/example/lms/templates/header.html new file mode 100644 index 0000000000..5ef36bec10 --- /dev/null +++ b/themes/example/lms/templates/header.html @@ -0,0 +1,72 @@ +## mako +<%page expression_filter="h"/> +<%namespace name='static' file='static_content.html'/> +<%namespace file='main.html' import="login_query"/> +<%! +from django.utils.translation import ugettext as _ +from django.core.urlresolvers import reverse +from openedx.core.djangoapps.user_api.accounts.image_helpers import get_profile_image_urls_for_user +%> + + + + + diff --git a/themes/example/lms/templates/index.html b/themes/example/lms/templates/index.html new file mode 100644 index 0000000000..0e7956dba5 --- /dev/null +++ b/themes/example/lms/templates/index.html @@ -0,0 +1,68 @@ +## mako +<%page expression_filter="h"/> +<%inherit file="main.html" /> +<%namespace name='static' file='static_content.html'/> +<%! +from django.utils.translation import ugettext as _ +from django.core.urlresolvers import reverse +%> + +<%block name="headextra"> + + + +<%block name="js_extra"> + +<%include file="about_site.html" /> + + + +
      +
      +
      +
      +
      +
      +

      Lorem ipsum dolor sit amet, ad mea dictas audiam, nec id graecis explicari hasnain

      + % if show_homepage_promo_video: + Watch video + % endif +
      +
      +
      +
      +
      + + <%include file="${courses_list}" /> + +
      +
      +
      +
      + +% if show_homepage_promo_video: + +% endif + +% if show_signup_immediately is not UNDEFINED: +## NOTE: This won't work in production, because anonymous views are cached, so it will +## show either with or without this extra js for 3 minutes at a time. + +% endif diff --git a/themes/example/lms/templates/static_templates/about.html b/themes/example/lms/templates/static_templates/about.html new file mode 100644 index 0000000000..d0732fc5f1 --- /dev/null +++ b/themes/example/lms/templates/static_templates/about.html @@ -0,0 +1,80 @@ +## mako +<%page expression_filter="h"/> +<%! from django.utils.translation import ugettext as _ %> +<%namespace name='static' file='../static_content.html'/> +<%inherit file="../main.html" /> + +<%block name="pagetitle">${_("About Us")} + +
      +

      ${_("About Us")}

      +
      +
      +
      +
      +
      +
      +

      Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet

      +

      Lorem ipsum dolor sit amet

      +

      Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti sed. + Pro ei bonorum commune, ea impedit pericula cum. Ex mea dolor maiorum. Et oblique vocibus quo, atqui facete + doctus sed an. Ei sed denique periculis, ad error alterum duo. Veritus eligendi pri ne, cibo vocent abhorreant + ad eum, nam iuvaret electram prodesset ea. Sed in detracto pericula..

      + +

      Lorem ipsum dolor sit amet

      +

      Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti sed. + Pro ei bonorum commune, ea impedit pericula cum. Ex mea dolor maiorum. Et oblique vocibus quo, atqui facete + doctus sed an. Ei sed denique periculis, ad error alterum duo. Veritus eligendi pri ne, cibo vocent abhorreant + ad eum, nam iuvaret electram prodesset ea. Sed in detracto pericula..

      + +

      Lorem ipsum dolor sit amet

      +

      Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti sed. + Pro ei bonorum commune, ea impedit pericula cum. Ex mea dolor maiorum. Et oblique vocibus quo, atqui facete + doctus sed an. Ei sed denique periculis, ad error alterum duo. Veritus eligendi pri ne, cibo vocent abhorreant + ad eum, nam iuvaret electram prodesset ea. Sed in detracto pericula..

      + +

      Lorem ipsum dolor sit amet

      +

      Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti sed. + Pro ei bonorum commune, ea impedit pericula cum. Ex mea dolor maiorum. Et oblique vocibus quo, atqui facete + doctus sed an. Ei sed denique periculis, ad error alterum duo. Veritus eligendi pri ne, cibo vocent abhorreant + ad eum, nam iuvaret electram prodesset ea. Sed in detracto pericula..

      + +

      Lorem ipsum dolor sit amet

      +

      Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti sed. + Pro ei bonorum commune, ea impedit pericula cum. Ex mea dolor maiorum. Et oblique vocibus quo, atqui facete + doctus sed an. Ei sed denique periculis, ad error alterum duo. Veritus eligendi pri ne, cibo vocent abhorreant + ad eum, nam iuvaret electram prodesset ea. Sed in detracto pericula..

      + +

      Lorem ipsum dolor sit amet

      +

      Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti sed. + Pro ei bonorum commune, ea impedit pericula cum. Ex mea dolor maiorum. Et oblique vocibus quo, atqui facete + doctus sed an. Ei sed denique periculis, ad error alterum duo. Veritus eligendi pri ne, cibo vocent abhorreant + ad eum, nam iuvaret electram prodesset ea. Sed in detracto pericula..

      + +

      Media Inquiries

      +

      Lorem ipsum dolor sit amet
      + Tel.: 123-456-7890
      + loremIpsem@lorem.edu
      + Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet: + Lorem ipsum dolor sit amet.

      +

      +
      +
      + Mission Statement +

      "Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit."

      +

      + Lorem ipsum
      + Lorem ipsum, Lorem ipsum +

      +
      +
      +
      +
      +
      diff --git a/themes/example/lms/templates/static_templates/contact.html b/themes/example/lms/templates/static_templates/contact.html new file mode 100644 index 0000000000..0d3cc34a42 --- /dev/null +++ b/themes/example/lms/templates/static_templates/contact.html @@ -0,0 +1,96 @@ +## mako +<%page expression_filter="h"/> +<%! +from django.utils.translation import ugettext as _ +from openedx.core.djangolib.markup import Text, HTML +from datetime import datetime +import pytz +from django.conf import settings +%> +<%inherit file="../main.html" /> +<%namespace name='static' file='../static_content.html'/> +<%block name="pagetitle">${_("Contact Us")} + +
      +

      ${_("Contact Us")}

      +
      + +
      +
      +
      +
      +
      +
      +
      + + +
      +
      + + +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      + + +
      + + +
      + +
      +
      +
      +
      +
      +
      +
      + + + + + +<%block name="js_extra"> + + diff --git a/themes/example/lms/templates/static_templates/faq.html b/themes/example/lms/templates/static_templates/faq.html new file mode 100644 index 0000000000..bdd73c1ac8 --- /dev/null +++ b/themes/example/lms/templates/static_templates/faq.html @@ -0,0 +1,147 @@ +<%page expression_filter="h"/> +<%! from django.utils.translation import ugettext as _ %> +<%inherit file="../main.html" /> +<%namespace name='static' file='../static_content.html'/> + +<%block name="pagetitle">${_("FAQ's")} + +
      +

      ${_("General FAQs")}

      +
      +
      + +
      +
      +
      + +
      +

      ${_("Academic Planning")}

      +
      +

      Lorem ipsum dolor sit amet

      +
      +

      + Lorem ipsum dolor sit ametLorem ipsum dolor sit amet +

      +
      +
      + +
      +

      Lorem ipsum dolor sit amet

      +
      +

      + Lorem ipsum dolor sit ametLorem ipsum dolor sit amet +

      +
      +
      + +
      +

      Lorem ipsum dolor sit amet

      +
      +

      + Lorem ipsum dolor sit ametLorem ipsum dolor sit amet +

      +
      +
      + + ${_("Back to top")} + +

      ${_("Registration")}

      +
      +

      Lorem ipsum dolor sit amet

      +
      +

      + Lorem ipsum dolor sit ametLorem ipsum dolor sit amet +

      +
      +
      + +
      +

      Lorem ipsum dolor sit amet

      +
      +

      + Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet +

      +
      +
      + +
      +

      Lorem ipsum dolor sit amet

      +
      +

      + Lorem ipsum dolor sit amet +

      +
        +
      • + Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet +
      • +
      • + Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet +
      • +
      +
      +
      + + ${_("Back to top")} + +

      ${_("Finances")}

      +
      +

      Lorem ipsum dolor sit amet

      +
      +

      + Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet +

      +
      +
      +
      +

      Lorem ipsum dolor sit amet

      +
      +

      + Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet +

      +
      +
      +
      +

      Lorem ipsum dolor sit amet

      +
      +

      + Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet +

      +
      +
      +
      +

      Lorem ipsum dolor sit amet

      +
      +

      + Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet +

      +
      +
      + ${_("Back to top")} + +
      +
      +
      +
      +
      + +<%block name="js_extra"> + + + diff --git a/themes/example/lms/templates/static_templates/honor.html b/themes/example/lms/templates/static_templates/honor.html new file mode 100644 index 0000000000..72d4688477 --- /dev/null +++ b/themes/example/lms/templates/static_templates/honor.html @@ -0,0 +1,93 @@ +## mako +<%page expression_filter="h"/> +<%! from django.utils.translation import ugettext as _ %> +<%namespace name='static' file='../static_content.html'/> +<%inherit file="../main.html" /> + +<%block name="pagetitle">${_("Honor Code")} + +
      +

      ${_("Honor Code")}

      +
      +
      +
      +
      +
      + +
      +

      Effective Date: January 01, 1970

      +

      Lorem ipsum dolor sit amet, sea te quaeque.

      + +

      Lorem ipsum dolor sit amet

      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. +

      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. +

      + ${_("Back to top")} + +

      Lorem ipsum dolor sit amet

      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. +

      + +
        +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue..
      • +          
      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. +

      +
        +              
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue..
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      + ${_("Back to top")} + +

      Lorem ipsum dolor sit amet

      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. +

      + ${_("Back to top")} + +

      Effective Date: Januray 01, 1970

      +
      +
      +
      +
      +
      diff --git a/themes/example/lms/templates/static_templates/privacy.html b/themes/example/lms/templates/static_templates/privacy.html new file mode 100644 index 0000000000..05c71809fe --- /dev/null +++ b/themes/example/lms/templates/static_templates/privacy.html @@ -0,0 +1,89 @@ +## mako +<%page expression_filter="h"/> +<%! from django.utils.translation import ugettext as _ %> +<%namespace name='static' file='../static_content.html'/> +<%inherit file="../main.html" /> + +<%block name="pagetitle">${_("Privacy Policy")} + +
      +

      ${_("Privacy Policy")}

      +
      +
      +
      +
      +
      + +
      +

      Lorem ipsum dolor sit amet

      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. +

      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. +

      + ${_("Back to top")} + +

      Lorem ipsum dolor sit amet

      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. +

      + +
        +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue..
      • +          
      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. +

      +
        +              
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue..
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      + ${_("Back to top")} + +

      Lorem ipsum dolor sit amet

      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. +

      + ${_("Back to top")} + +
      +
      +
      +
      +
      diff --git a/themes/example/lms/templates/static_templates/tos.html b/themes/example/lms/templates/static_templates/tos.html new file mode 100644 index 0000000000..a0548a6fb9 --- /dev/null +++ b/themes/example/lms/templates/static_templates/tos.html @@ -0,0 +1,89 @@ +## mako +<%page expression_filter="h"/> +<%! from django.utils.translation import ugettext as _ %> +<%namespace name='static' file='../static_content.html'/> +<%inherit file="../main.html" /> + +<%block name="pagetitle">${_("Terms of Service")} + +
      +

      ${_("Terms of Service")}

      +
      +
      +
      +
      +
      + +
      +

      Lorem ipsum dolor sit amet

      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. +

      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. +

      + ${_("Back to top")} + +

      Lorem ipsum dolor sit amet

      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. +

      + +
        +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue..
      • +          
      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. +

      +
        +              
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue..
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      • Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue.
      • +
      + ${_("Back to top")} + +

      Lorem ipsum dolor sit amet

      +

      + Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. Lorem ipsum dolor sit amet, sea te quaeque suscipiantur. Nullam vituperata at his, usu ad solum augue. + Mel partem iudicabit te, an sed vocent offendit. Est prompta deserunt senserit et, ex ubique deleniti + sed. +

      + ${_("Back to top")} + +
      +
      +
      +
      +
      diff --git a/themes/example/lms/templates/student_account/login_and_register.html b/themes/example/lms/templates/student_account/login_and_register.html new file mode 100644 index 0000000000..bf523c22e2 --- /dev/null +++ b/themes/example/lms/templates/student_account/login_and_register.html @@ -0,0 +1,38 @@ +<%page expression_filter="h"/> +<%! + import json + from django.utils.translation import ugettext as _ + from openedx.core.djangolib.js_utils import dump_js_escaped_json +%> +<%namespace name='static' file='/static_content.html'/> + +<%inherit file="../main.html" /> + +<%block name="pagetitle">${_("Sign in or Create Account")} + +<%block name="js_extra"> + <%static:require_module module_name="js/student_account/logistration_factory" class_name="LogistrationFactory"> + var options = ${data | n, dump_js_escaped_json}; + LogistrationFactory(options); + if ('newrelic' in window) { + newrelic.finished(); + // Because of a New Relic bug, the finished() event doesn't show up + // in Insights, so we have to make a new PageAction that is basically + // the same thing. We still want newrelic.finished() for session + // traces though. + newrelic.addPageAction('xfinished'); + } + + + +<%block name="header_extras"> + % for template_name in ["account", "access", "form_field", "login", "register", "institution_login", "institution_register", "password_reset", "hinted_login"]: + +% endfor + + +
      + diff --git a/themes/red-theme/lms/templates/footer.html b/themes/red-theme/lms/templates/footer.html index 3570d92901..cb1ca3a070 100755 --- a/themes/red-theme/lms/templates/footer.html +++ b/themes/red-theme/lms/templates/footer.html @@ -53,7 +53,7 @@ from django.utils.translation import ugettext as _

      - + ## Site operators: Please do not remove this paragraph! This attributes back to edX and makes your acknowledgement of edX's trademarks clear.
      +

      + +

      +
      diff --git a/themes/stanford-style/lms/templates/embargo/default_enrollment.html b/themes/stanford-style/lms/templates/embargo/default_enrollment.html new file mode 100644 index 0000000000..cdd199f234 --- /dev/null +++ b/themes/stanford-style/lms/templates/embargo/default_enrollment.html @@ -0,0 +1,11 @@ +<%! from django.utils.translation import ugettext as _ %> +<%inherit file="../main.html" /> + +<%block name="pagetitle">${_("This Course Unavailable In Your Country")} + +
      +

      + +

      +
      diff --git a/themes/stanford-style/lms/templates/footer.html b/themes/stanford-style/lms/templates/footer.html index 645fc80e11..b4afdcd4c6 100644 --- a/themes/stanford-style/lms/templates/footer.html +++ b/themes/stanford-style/lms/templates/footer.html @@ -6,7 +6,7 @@ <%! from datetime import date %> - +