Merge pull request #12433 from edx/bjacobel/upgrade-jquery

Upgrade jQuery to 2.2
This commit is contained in:
Brian Jacobel
2016-05-25 09:07:07 -04:00
72 changed files with 430 additions and 362 deletions

View File

@@ -27,7 +27,8 @@
"mustache": "js/vendor/mustache",
"codemirror": "js/vendor/codemirror-compressed",
"codemirror/stex": "js/vendor/CodeMirror/stex",
"jquery": "js/vendor/jquery.min",
"jquery": "common/js/vendor/jquery",
"jquery-migrate": "common/js/vendor/jquery-migrate",
"jquery.ui": "js/vendor/jquery-ui.min",
"jquery.form": "js/vendor/jquery.form",
"jquery.markitup": "js/vendor/markitup/jquery.markitup",
@@ -37,7 +38,7 @@
"jquery.timepicker": "js/vendor/timepicker/jquery.timepicker",
"jquery.cookie": "js/vendor/jquery.cookie",
"jquery.qtip": "js/vendor/jquery.qtip.min",
"jquery.scrollTo": "js/vendor/jquery.scrollTo-1.4.2-min",
"jquery.scrollTo": "common/js/vendor/jquery.scrollTo",
"jquery.flot": "js/vendor/flot/jquery.flot.min",
"jquery.fileupload": "js/vendor/jQuery-File-Upload/js/jquery.fileupload",
"jquery.fileupload-process": "js/vendor/jQuery-File-Upload/js/jquery.fileupload-process",
@@ -112,6 +113,7 @@
"date": {
exports: "Date"
},
"jquery-migrate": ['jquery'],
"jquery.ui": {
deps: ["jquery"],
exports: "jQuery.ui"
@@ -146,7 +148,7 @@
},
"jquery.scrollTo": {
deps: ["jquery"],
exports: "jQuery.fn.scrollTo",
exports: "jQuery.fn.scrollTo"
},
"jquery.flot": {
deps: ["jquery"],

View File

@@ -4,14 +4,15 @@ requirejs.config({
"gettext": "xmodule_js/common_static/js/test/i18n",
"mustache": "xmodule_js/common_static/js/vendor/mustache",
"codemirror": "xmodule_js/common_static/js/vendor/CodeMirror/codemirror",
"jquery": "xmodule_js/common_static/js/vendor/jquery.min",
"jquery": "xmodule_js/common_static/common/js/vendor/jquery",
"jquery-migrate": "xmodule_js/common_static/common/js/vendor/jquery-migrate",
"jquery.ui": "xmodule_js/common_static/js/vendor/jquery-ui.min",
"jquery.form": "xmodule_js/common_static/js/vendor/jquery.form",
"jquery.markitup": "xmodule_js/common_static/js/vendor/markitup/jquery.markitup",
"jquery.leanModal": "xmodule_js/common_static/js/vendor/jquery.leanModal",
"jquery.ajaxQueue": "xmodule_js/common_static/js/vendor/jquery.ajaxQueue",
"jquery.smoothScroll": "xmodule_js/common_static/js/vendor/jquery.smooth-scroll.min",
"jquery.scrollTo": "xmodule_js/common_static/js/vendor/jquery.scrollTo-1.4.2-min",
"jquery.scrollTo": "common/js/vendor/jquery.scrollTo",
"jquery.timepicker": "xmodule_js/common_static/js/vendor/timepicker/jquery.timepicker",
"jquery.cookie": "xmodule_js/common_static/js/vendor/jquery.cookie",
"jquery.qtip": "xmodule_js/common_static/js/vendor/jquery.qtip.min",
@@ -65,6 +66,7 @@ requirejs.config({
"date": {
exports: "Date"
},
"jquery-migrate": ['jquery'],
"jquery.ui": {
deps: ["jquery"],
exports: "jQuery.ui"

View File

@@ -33,7 +33,7 @@ require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_h
server && server.restore()
it "successful AJAX request does not pop an error notification", ->
server = AjaxHelpers.server([200, {}, ''])
server = AjaxHelpers.server([200, {"Content-Type": "application/json"}, "{}"])
expect($("#page-notification")).toBeEmpty()
$.ajax("/test")
@@ -42,7 +42,7 @@ require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_h
expect($("#page-notification")).toBeEmpty()
it "AJAX request with error should pop an error notification", ->
server = AjaxHelpers.server([500, {}, ''])
server = AjaxHelpers.server([500, {"Content-Type": "application/json"}, "{}"])
$.ajax("/test")
server.respond()
@@ -50,7 +50,7 @@ require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_h
expect($("#page-notification")).toContainElement('div.wrapper-notification-error')
it "can override AJAX request with error so it does not pop an error notification", ->
server = AjaxHelpers.server([500, {}, ''])
server = AjaxHelpers.server([500, {"Content-Type": "application/json"}, "{}"])
$.ajax
url: "/test"

View File

@@ -5,13 +5,14 @@ requirejs.config({
"gettext": "xmodule_js/common_static/js/test/i18n",
"mustache": "xmodule_js/common_static/js/vendor/mustache",
"codemirror": "xmodule_js/common_static/js/vendor/CodeMirror/codemirror",
"jquery": "xmodule_js/common_static/js/vendor/jquery.min",
"jquery": "common/js/vendor/jquery",
"jquery-migrate": "common/js/vendor/jquery-migrate",
"jquery.ui": "xmodule_js/common_static/js/vendor/jquery-ui.min",
"jquery.form": "xmodule_js/common_static/js/vendor/jquery.form",
"jquery.markitup": "xmodule_js/common_static/js/vendor/markitup/jquery.markitup",
"jquery.leanModal": "xmodule_js/common_static/js/vendor/jquery.leanModal",
"jquery.smoothScroll": "xmodule_js/common_static/js/vendor/jquery.smooth-scroll.min",
"jquery.scrollTo": "xmodule_js/common_static/js/vendor/jquery.scrollTo-1.4.2-min",
"jquery.scrollTo": "common/js/vendor/jquery.scrollTo",
"jquery.timepicker": "xmodule_js/common_static/js/vendor/timepicker/jquery.timepicker",
"jquery.cookie": "xmodule_js/common_static/js/vendor/jquery.cookie",
"jquery.qtip": "xmodule_js/common_static/js/vendor/jquery.qtip.min",

View File

@@ -34,7 +34,7 @@ define ["js/models/section", "common/js/spec_helpers/ajax_helpers", "js/utils/mo
})
it "show/hide a notification when it saves to the server", ->
server = AjaxHelpers.server([200, {}, ''])
server = AjaxHelpers.server([200, {"Content-Type": "application/json"}, "{}"])
@model.save()
expect(Section.prototype.showNotification).toHaveBeenCalled()
@@ -43,7 +43,7 @@ define ["js/models/section", "common/js/spec_helpers/ajax_helpers", "js/utils/mo
it "don't hide notification when saving fails", ->
# this is handled by the global AJAX error handler
server = AjaxHelpers.server([500, {}, ''])
server = AjaxHelpers.server([500, {"Content-Type": "application/json"}, "{}"])
@model.save()
server.respond()

View File

@@ -84,7 +84,7 @@ define ["jquery", "common/js/spec_helpers/ajax_helpers", "squire"],
expect(@confirmationSpies.constructor).not.toHaveBeenCalled()
expect(@collection.contains(@model)).toBeTruthy()
# return a success response
requests[0].respond(200)
requests[0].respond(204)
expect(@confirmationSpies.constructor).toHaveBeenCalled()
expect(@confirmationSpies.show).toHaveBeenCalled()
savingOptions = @confirmationSpies.constructor.calls.mostRecent().args[0]
@@ -118,7 +118,7 @@ define ["jquery", "common/js/spec_helpers/ajax_helpers", "squire"],
expect(savingOptions.title).toMatch("Saving")
expect(@model.get("locked")).toBeFalsy()
# return a success response
requests[0].respond(200)
requests[0].respond(204)
expect(@savingSpies.hide).toHaveBeenCalled()
expect(@model.get("locked")).toBeTruthy()

View File

@@ -87,7 +87,7 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js
savingOptions = @savingSpies.constructor.calls.mostRecent().args[0]
expect(savingOptions.title).toMatch(/Deleting/)
# return a success response
requests[0].respond(200)
requests[0].respond(204)
expect(@savingSpies.hide).toHaveBeenCalled()
expect(@collection.contains(@model)).toBeFalsy()

View File

@@ -58,6 +58,20 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
};
beforeEach(function() {
window.course = new Course({
id: '5',
name: 'Course Name',
url_name: 'course_name',
org: 'course_org',
num: 'course_num',
revision: 'course_rev'
});
window.certWebPreview = new CertificatePreview({
course_modes: ['honor', 'test'],
certificate_web_view_url: '/users/1/courses/orgX/009/2016'
});
window.CMS.User = {isGlobalStaff: true};
TemplateHelpers.installTemplates(['certificate-details', 'signatory-details', 'signatory-editor', 'signatory-actions'], true);
window.course = new Course({
@@ -99,6 +113,12 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
delete window.CMS.User;
});
afterEach(function() {
delete window.course;
delete window.CMS.User;
});
describe('The Certificate Details view', function() {
it('should parse a JSON string collection into a Backbone model collection', function () {
@@ -234,7 +254,7 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails
this.view.$(SELECTORS.signatory_panel_save).click();
ViewHelpers.verifyNotificationShowing(notificationSpy, /Saving/);
requests[0].respond(200);
requests[0].respond(204);
ViewHelpers.verifyNotificationHidden(notificationSpy);
expect(this.view.$(SELECTORS.signatory_name_value)).toContainText('New Signatory Test Name');

View File

@@ -28,8 +28,6 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel
};
beforeEach(function() {
appendSetFixtures('<div class="preview-certificate nav-actions"></div>');
window.course = new Course({
id: '5',
name: 'Course Name',
@@ -40,6 +38,8 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel
});
window.CMS.User = {isGlobalStaff: true};
TemplateHelpers.installTemplate('certificate-web-preview', true);
appendSetFixtures('<div class="preview-certificate nav-actions"></div>');
this.view = new CertificatePreview({
el: $('.preview-certificate'),
course_modes: ['test1', 'test2', 'test3'],

View File

@@ -331,7 +331,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
expect(savingOptions.title).toMatch(/Saving/);
expect($('#unit-1')).toHaveClass('was-dropped');
expect(request.requestBody).toEqual('{"children":["fourth-unit-id","first-unit-id"]}');
request.respond(200);
request.respond(204);
expect(this.savingSpies.hide).toHaveBeenCalled();
this.clock.tick(1001);
expect($('#unit-1')).not.toHaveClass('was-dropped');
@@ -360,7 +360,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat
expect(request.requestBody).toEqual(
'{"children":["second-unit-id","first-unit-id","third-unit-id"]}'
);
request.respond(200);
request.respond(204);
this.clock.tick(1001);
expect($('#unit-1')).not.toHaveClass('was-dropped');
// parent

View File

@@ -491,21 +491,6 @@ define([
AjaxHelpers.expectNoRequests(requests);
});
it('should have appropriate class names on focus/blur', function (done) {
var groupInput = this.view.$(SELECTORS.inputGroupName).first(),
groupFields = this.view.$(SELECTORS.groupFields);
groupInput.focus();
jasmine.waitUntil(function() {
return groupFields.hasClass('is-focused');
}).then(function () {
groupInput.blur();
jasmine.waitUntil(function() {
return !groupFields.hasClass('is-focused');
}).then(done);
});
});
describe('removes all newly created groups on cancel', function () {
it('if the model has a non-empty groups', function() {
var groups = this.model.get('groups');

View File

@@ -253,6 +253,16 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
])
]);
// Create a mock Course object as the JS now expects it.
window.course = new Course({
id: '333',
name: 'Course Name',
url_name: 'course_name',
org: 'course_org',
num: 'course_num',
revision: 'course_rev'
});
});
afterEach(function () {

View File

@@ -101,7 +101,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers
var values_with_blank = values.slice();
values_with_blank[i] = '';
fillInLibraryFields.apply(this, values_with_blank);
expect($('.create-library li.field.text input[value=]').parent()).toHaveClass('error');
expect($('.create-library li.field.text input').parent()).toHaveClass('error');
expect($('.new-library-save')).toHaveClass('is-disabled');
expect($('.new-library-save')).toHaveAttr('aria-disabled', 'true');
$('.new-library-save').click();

View File

@@ -5,11 +5,11 @@ define([
function ($, AjaxHelpers, ViewHelpers, ManageUsersFactory, ViewUtils) {
"use strict";
describe("Library Instructor Access Page", function () {
const changeRoleUrl = "dummy_change_role_url/@@EMAIL@@";
var changeRoleUrl = "dummy_change_role_url/@@EMAIL@@";
var team_member_fixture = readFixtures("team-member.underscore");
function setRole(email, role){
var user_li = $("li.user-item[data-email="+ email + "]");
var user_li = $('li.user-item[data-email="'+ email + '"]');
var role_action = $("li.action-role a.make-"+role, user_li);
expect(role_action).toBeVisible();
role_action.click();
@@ -48,7 +48,7 @@ function ($, AjaxHelpers, ViewHelpers, ManageUsersFactory, ViewUtils) {
});
it("can give a user permission to use the library", function () {
const email = 'other@example.com';
var email = 'other@example.com';
var requests = AjaxHelpers.requests(this);
var reloadSpy = spyOn(ViewUtils, 'reload');
$('.create-user-button').click();
@@ -61,7 +61,7 @@ function ($, AjaxHelpers, ViewHelpers, ManageUsersFactory, ViewUtils) {
});
it("can promote user", function() {
const email = "staff@example.com";
var email = "staff@example.com";
var requests = AjaxHelpers.requests(this);
var reloadSpy = spyOn(ViewUtils, 'reload');
setRole("staff@example.com", 'staff');

View File

@@ -144,7 +144,7 @@ define([
// select the entrance-exam-enabled checkbox. grade requirement section should be visible.
entrance_exam_enabled_field
.attr('checked', 'true')
.prop('checked', true)
.trigger('change');
this.view.render();
@@ -152,7 +152,7 @@ define([
// deselect the entrance-exam-enabled checkbox. grade requirement section should be hidden.
entrance_exam_enabled_field
.removeAttr('checked')
.prop('checked', false)
.trigger('change');
expect(this.view.$(SELECTORS.grade_requirement_div)).toBeHidden();
@@ -173,7 +173,7 @@ define([
// select the entrance-exam-enabled checkbox.
entrance_exam_enabled_field
.attr('checked', 'true')
.prop('checked', true)
.trigger('change');
// input a valid value for entrance exam minimum score.

View File

@@ -99,7 +99,7 @@ define(["jquery", "URI", "common/js/spec_helpers/ajax_helpers", "common/js/compo
mimetype: "application/javascript", kind: "url", data: missingJavaScriptUrl
}]
]);
expect(promise.isRejected()).toBe(true);
expect(promise.state()).toBe("rejected");
});
it('Triggers an event to the runtime when a notification-action-button is clicked', function () {

View File

@@ -10,8 +10,8 @@ define(["js/views/validation", "codemirror", "js/models/course_update",
// collection is CourseUpdateCollection
events: {
"click .new-update-button" : "onNew",
"click #course-update-view .save-button" : "onSave",
"click #course-update-view .cancel-button" : "onCancel",
"click .save-button" : "onSave",
"click .cancel-button" : "onCancel",
"click .post-actions > .edit-button" : "onEdit",
"click .post-actions > .delete-button" : "onDelete"
},

View File

@@ -12,8 +12,8 @@ function(BaseView, _, str, gettext, groupEditTemplate) {
events: {
'click .action-close': 'removeGroup',
'change .group-name': 'changeName',
'focus .groups-fields input': 'onFocus',
'blur .groups-fields input': 'onBlur'
'focus .group-name': 'onFocus',
'blur .group-name': 'onBlur'
},
className: function() {

View File

@@ -215,7 +215,6 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
}
});
AbstractEditor = BaseView.extend({
tagName: 'section',
templateName: null,
@@ -328,6 +327,7 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
};
}
});
TimedExaminationPreferenceEditor = AbstractEditor.extend({
templateName: 'timed-examination-preference-editor',
className: 'edit-settings-timed-examination',
@@ -496,6 +496,7 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
};
}
});
AccessEditor = AbstractEditor.extend({
templateName: 'access-editor',
className: 'edit-settings-access',
@@ -548,13 +549,14 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
};
}
});
GradingEditor = AbstractEditor.extend({
templateName: 'grading-editor',
className: 'edit-settings-grading',
afterRender: function () {
AbstractEditor.prototype.afterRender.call(this);
this.setValue(this.model.get('format'));
this.setValue(this.model.get('format') || 'notgraded');
},
setValue: function (value) {

View File

@@ -89,7 +89,7 @@ function($, _, AbstractEditor, FileUpload, UploadDialog) {
items = this.$el.find('ol').find('.list-settings-item');
_.each(items, function(element, index) {
var key = $(element).find('select').val(),
var key = $(element).find('select option:selected').val(),
value = $(element).find('.input').val();
// Keys should be unique, so if our keys are duplicated and

View File

@@ -13,6 +13,11 @@ var options = {
libraryFiles: [],
libraryFilesToInclude: [
{pattern: 'common/js/vendor/jquery.js', included: true},
{pattern: 'common/js/vendor/jquery-migrate.js', included: true}
],
// Make sure the patterns in sourceFiles and specFiles do not match the same file.
// Otherwise Istanbul which is used for coverage tracking will cause tests to not run.
sourceFiles: [

View File

@@ -13,6 +13,11 @@ var options = {
libraryFiles: [],
libraryFilesToInclude: [
{pattern: 'common/js/vendor/jquery.js', included: true},
{pattern: 'common/js/vendor/jquery-migrate.js', included: true}
],
// Make sure the patterns in sourceFiles and specFiles do not match the same file.
// Otherwise Istanbul which is used for coverage tracking will cause tests to not run.
sourceFiles: [

View File

@@ -93,12 +93,12 @@ def render_require_js_path_overrides(path_overrides): # pylint: disable=invalid
For example:
"js/vendor/jquery.min.js" --> "js/vendor/jquery.min.abcd1234"
"js/vendor/jquery.js" --> "js/vendor/jquery.abcd1234"
To achive this we will add overrided paths in requirejs config at runtime.
So that any reference to 'jquery' in a JavaScript module
will cause RequireJS to load '/static/js/vendor/jquery.min.abcd1234.js'
will cause RequireJS to load '/static/js/vendor/jquery.abcd1234.js'
If running in DEBUG mode (as in devstack), the resolved JavaScript URLs
won't contain hashes, so the new paths will match the original paths.

View File

@@ -14,7 +14,7 @@ class RequireJSPathOverridesTest(TestCase):
"""Test RequireJS path overrides. """
OVERRIDES = {
'jquery': 'js/vendor/jquery.min.js',
'jquery': 'common/js/vendor/jquery.js',
'backbone': 'common/js/vendor/backbone.js',
'text': 'js/vendor/text.js'
}
@@ -24,7 +24,7 @@ class RequireJSPathOverridesTest(TestCase):
"(function (require) {",
"require.config({",
"paths: {",
"'jquery': 'js/vendor/jquery.min',",
"'jquery': 'common/js/vendor/jquery',",
"'text': 'js/vendor/text',",
"'backbone': 'common/js/vendor/backbone'",
"}",

View File

@@ -28,7 +28,8 @@ var options = {
{pattern: 'common_static/edx-ui-toolkit/js/utils/global-loader.js', included: true},
{pattern: 'common_static/js/vendor/CodeMirror/codemirror.js', included: true},
{pattern: 'common_static/js/vendor/draggabilly.js'},
{pattern: 'common_static/js/vendor/jquery.min.js', included: true},
{pattern: 'common_static/common/js/vendor/jquery.js', included: true},
{pattern: 'common_static/common/js/vendor/jquery-migrate.js', included: true},
{pattern: 'common_static/js/vendor/jquery.cookie.js', included: true},
{pattern: 'common_static/js/vendor/jquery.leanModal.js', included: true},
{pattern: 'common_static/js/vendor/jquery.timeago.js', included: true},

View File

@@ -289,9 +289,9 @@ describe 'Problem', ->
$('#input_example_1').replaceWith(html)
@problem.checkAnswersAndCheckButton true
@checkDisabled true
$('#input_1_1_1').attr('checked', true).trigger('click')
$('#input_1_1_1').click()
@checkDisabled false
$('#input_1_1_1').attr('checked', false).trigger('click')
$('#input_1_1_1').click()
@checkDisabled true
it 'should become enabled after a radiobutton is checked', ->

View File

@@ -343,7 +343,7 @@
expect(parseIntAttribute(item, 'data-index')).toEqual(index);
expect(parseIntAttribute(item, 'data-start')).toEqual(captionsData.start[index]);
expect(item.attr('tabindex')).toEqual(0);
expect(item.attr('tabindex')).toEqual('0');
expect(item.text().trim()).toEqual(captionsData.text[index]);
});
});
@@ -432,7 +432,7 @@
expect(parseIntAttribute(item, 'data-index')).toEqual(index);
expect(parseIntAttribute(item, 'data-start')).toEqual(captionsData.start[index]);
expect(item.attr('tabindex')).toEqual(0);
expect(item.attr('tabindex')).toEqual('0');
expect(item.text().trim()).toEqual(text);
});
}).always(done);
@@ -842,7 +842,7 @@
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).attr('tabindex')).toEqual('0');
expect($(item).text().trim()).toEqual(captionsData.text[index]);
});
});

View File

@@ -49,8 +49,8 @@
});
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);
expect(state.focusGrabber.elFirst.attr('tabindex')).toBe('-1');
expect(state.focusGrabber.elLast.attr('tabindex')).toBe('-1');
});
it(

View File

@@ -55,7 +55,7 @@
expect(btnPlay).not.toHaveClass('is-hidden');
expect(btnPlay).toHaveAttrs({
'aria-hidden': 'false',
'tabindex': 0
'tabindex': '0'
});
state.videoPlayPlaceholder.hide();
@@ -63,7 +63,7 @@
expect(btnPlay).toHaveClass('is-hidden');
expect(btnPlay).toHaveAttrs({
'aria-hidden': 'true',
'tabindex': -1
'tabindex': '-1'
});
});

View File

@@ -39,15 +39,15 @@ class @Annotatable
# the associated problem. The reply buttons are part of the tooltip
# content. It's important that the tooltips be configured to render
# as descendants of the annotation module and *not* the document.body.
@$el.delegate @replySelector, 'click', @onClickReply
@$el.on 'click', @replySelector, @onClickReply
# Initialize handler for 'return to annotation' events triggered from problems.
# 1) There are annotationinput capa problems rendered on the page
# 2) Each one has an embedded return link (see annotation capa problem template).
# Since the capa problem injects HTML content via AJAX, the best we can do is
# is let the click events bubble up to the body and handle them there.
$('body').delegate @problemReturnSelector, 'click', @onClickReturn
# is let the click events bubble up to the body and handle them there.
$(document).on 'click', @problemReturnSelector, @onClickReturn
initTips: () ->
# tooltips are used to display annotations for highlighted text spans
@$(@spanSelector).each (index, el) =>
@@ -91,8 +91,9 @@ class @Annotatable
onMoveTip: (event, api, position) =>
###
This method handles an edge case in which a tooltip is displayed above
a non-overlapping span like this:
This method handles a vertical positioning bug in Firefox as
well as an edge case in which a tooltip is displayed above a
non-overlapping span like this:
(( TOOLTIP ))
\/
@@ -115,28 +116,33 @@ class @Annotatable
# we want to choose the largest of the two non-overlapping spans and display
# the tooltip above the center of it (see api.options.position settings)
focus_rect = (if rects[0].width > rects[1].width then rects[0] else rects[1])
rect_center = focus_rect.left + (focus_rect.width / 2)
rect_top = focus_rect.top
tip_width = $(tip).width()
tip_height = $(tip).height()
else
# always compute the new position because Firefox doesn't
# properly vertically position the tooltip
focus_rect = rects[0]
# tooltip is positioned relative to its container, so we need to factor in offsets
container_offset = $(container).offset()
offset_left = -container_offset.left
offset_top = $(document).scrollTop() - container_offset.top
rect_center = focus_rect.left + (focus_rect.width / 2)
rect_top = focus_rect.top
tip_width = $(tip).width()
tip_height = $(tip).height()
tip_left = offset_left + rect_center - (tip_width / 2)
tip_top = offset_top + rect_top - tip_height + adjust_y
# tooltip is positioned relative to its container, so we need to factor in offsets
container_offset = $(container).offset()
offset_left = -container_offset.left
offset_top = $(document).scrollTop() - container_offset.top
# make sure the new tip position doesn't clip the edges of the screen
win_width = $(window).width()
if tip_left < offset_left
tip_left = offset_left
else if tip_left + tip_width > win_width + offset_left
tip_left = win_width + offset_left - tip_width
tip_left = offset_left + rect_center - (tip_width / 2)
tip_top = offset_top + rect_top - tip_height + adjust_y
# final step: update the position object (used by qtip2 to show the tip after the move event)
$.extend position, 'left': tip_left, 'top': tip_top
# make sure the new tip position doesn't clip the edges of the screen
win_width = $(window).width()
if tip_left < offset_left
tip_left = offset_left
else if tip_left + tip_width > win_width + offset_left
tip_left = win_width + offset_left - tip_width
# final step: update the position object (used by qtip2 to show the tip after the move event)
$.extend position, 'left': tip_left, 'top': tip_top
getSpanForProblemReturn: (el) ->
problem_id = $(@problemReturnSelector).index(el)
@@ -144,7 +150,7 @@ class @Annotatable
getProblem: (el) ->
problem_id = @getProblemId(el)
$(@problemSelector).has(@problemInputSelector).eq(problem_id)
$(@problemInputSelector).eq(problem_id)
getProblemId: (el) ->
$(el).data('problem-id')
@@ -208,7 +214,7 @@ class @Annotatable
onAfter: @_once => after?.call this, el
offset: offset
}) if $(el).length > 0
afterScrollToProblem: (problem_el) ->
problem_el.effect 'highlight', {}, 500

View File

@@ -129,7 +129,8 @@ if Backbone?
isPrivilegedUser: DiscussionUtil.isPrivilegedUser()
})
)
@$(".forum-nav-sort-control").val(@collection.sort_preference)
@$(".forum-nav-sort-control option").removeProp("selected")
@$(".forum-nav-sort-control option[value=#{@collection.sort_preference}]").prop("selected", true)
$(window).bind "load scroll resize", @updateSidebar
@@ -524,5 +525,3 @@ if Backbone?
type: "POST"
error: () =>
$('input.email-setting').attr('checked','checked')

View File

@@ -3,6 +3,7 @@ define([
'edx-ui-toolkit/js/utils/html-utils',
'domReady!',
'jquery',
'jquery-migrate',
'backbone',
'underscore',
'gettext'

View File

@@ -1,9 +1,12 @@
(function(requirejs, define) {
'use strict';
requirejs.config({
baseUrl: '/base/',
paths: {
'gettext': 'js/test/i18n',
'jquery': 'js/vendor/jquery.min',
'jquery': 'common/js/vendor/jquery',
'jquery-migrate': 'common/js/vendor/jquery-migrate',
'jquery.ui': 'js/vendor/jquery-ui.min',
'jquery.flot': 'js/vendor/flot/jquery.flot.min',
'jquery.form': 'js/vendor/jquery.form',
@@ -11,7 +14,7 @@
'jquery.leanModal': 'js/vendor/jquery.leanModal',
'jquery.ajaxQueue': 'js/vendor/jquery.ajaxQueue',
'jquery.smoothScroll': 'js/vendor/jquery.smooth-scroll.min',
'jquery.scrollTo': 'js/vendor/jquery.scrollTo-1.4.2-min',
'jquery.scrollTo': 'common/js/vendor/jquery.scrollTo',
'jquery.timepicker': 'js/vendor/timepicker/jquery.timepicker',
'jquery.cookie': 'js/vendor/jquery.cookie',
'jquery.qtip': 'js/vendor/jquery.qtip.min',

File diff suppressed because one or more lines are too long

View File

@@ -1,11 +0,0 @@
/**
* jQuery.ScrollTo - Easy element scrolling using jQuery.
* Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
* Dual licensed under MIT and GPL.
* Date: 5/25/2009
* @author Ariel Flesler
* @version 1.4.2
*
* http://flesler.blogspot.com/2007/10/jqueryscrollto.html
*/
;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);

View File

@@ -19,7 +19,8 @@ var options = {
libraryFilesToInclude: [
{pattern: 'coffee/src/ajax_prefix.js', included: true},
{pattern: 'js/vendor/draggabilly.js', included: true},
{pattern: 'js/vendor/jquery.min.js', included: true},
{pattern: 'common/js/vendor/jquery.js', included: true},
{pattern: 'common/js/vendor/jquery-migrate.js', included: true},
{pattern: 'coffee/src/jquery.immediateDescendents.js', included: true},
{pattern: 'js/vendor/jquery.leanModal.js', included: true},
{pattern: 'js/vendor/jquery.timeago.js', included: true},

View File

@@ -229,10 +229,9 @@ Feature: LMS.Answer problems
Given I am viewing a "<ProblemType>" problem
When I answer a "<ProblemType>" problem "<InitialCorrectness>ly"
Then my "<ProblemType>" answer is marked "<InitialCorrectness>"
And I input an answer on a "<ProblemType>" problem "<OtherCorrectness>ly"
And I reset the problem
Then my "<ProblemType>" answer is NOT marked "<InitialCorrectness>"
And my "<ProblemType>" answer is NOT marked "<OtherCorrectness>"
And I reset the problem
Examples:
| ProblemType | InitialCorrectness | OtherCorrectness |

View File

@@ -1240,7 +1240,8 @@ proctoring_js = (
# In the future, we will likely refactor this to use
# RequireJS and an optimizer.
base_vendor_js = [
'js/vendor/jquery.min.js',
'common/js/vendor/jquery.js',
'common/js/vendor/jquery-migrate.js',
'js/vendor/jquery.cookie.js',
'js/vendor/url.min.js',
'common/js/vendor/underscore.js',
@@ -1352,14 +1353,16 @@ incourse_reverify_js = [
ccx_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/ccx/**/*.js'))
certificates_web_view_js = [
'js/vendor/jquery.min.js',
'common/js/vendor/jquery.js',
'common/js/vendor/jquery-migrate.js',
'js/vendor/jquery.cookie.js',
'js/src/logger.js',
'js/utils/facebook.js',
]
credit_web_view_js = [
'js/vendor/jquery.min.js',
'common/js/vendor/jquery.js',
'common/js/vendor/jquery-migrate.js',
'js/vendor/jquery.cookie.js',
'js/src/logger.js',
]

View File

@@ -8,9 +8,6 @@ describe 'FeedbackForm', ->
spyOn($, 'postWithPrefix').and.callFake (url, data, callback, format) ->
callback()
it 'binds to the #feedback_button', ->
expect($('#feedback_button')).toHandle 'click'
it 'post data to /send_feedback on click', ->
$('#feedback_subject').val 'Awesome!'
$('#feedback_message').val 'This site is really good.'

View File

@@ -3,12 +3,6 @@ describe 'AutoEnrollment', ->
loadFixtures 'coffee/fixtures/autoenrollment.html'
@autoenrollment = new AutoEnrollmentViaCsv $('.auto_enroll_csv')
it 'binds to the enrollment_signup_button on click event', ->
expect(@autoenrollment.$enrollment_signup_button).toHandle 'click'
it 'binds to the browse button on change event', ->
expect(@autoenrollment.$browse_button).toHandle 'change'
it 'binds the ajax call and the result will be success', ->
spyOn($, "ajax").and.callFake((params) =>
params.success({row_errors: [], general_errors: [], warnings: []})

View File

@@ -1,181 +1,179 @@
# Mostly adapted from math.stackexchange.com: http://cdn.sstatic.net/js/mathjax-editing-new.js
$ ->
class MathJaxProcessor
class MathJaxProcessor
MATHSPLIT = /// (
\$\$? # normal inline or display delimiter
| \\(?:begin|end)\{[a-z]*\*?\} # \begin{} \end{} style
| \\[\\{}$]
| [{}]
| (?:\n\s*)+ # only treat as math when there's single new line
| @@\d+@@ # delimiter similar to the one used internally
) ///i
MATHSPLIT = /// (
\$\$? # normal inline or display delimiter
| \\(?:begin|end)\{[a-z]*\*?\} # \begin{} \end{} style
| \\[\\{}$]
| [{}]
| (?:\n\s*)+ # only treat as math when there's single new line
| @@\d+@@ # delimiter similar to the one used internally
) ///i
CODESPAN = ///
(^|[^\\]) # match beginning or any previous character other than escape delimiter ('/')
(`+) # code span starts
([^\n]*?[^`\n]) # code content
\2 # code span ends
(?!`)
///gm
CODESPAN = ///
(^|[^\\]) # match beginning or any previous character other than escape delimiter ('/')
(`+) # code span starts
([^\n]*?[^`\n]) # code content
\2 # code span ends
(?!`)
///gm
constructor: (inlineMark, displayMark) ->
@inlineMark = inlineMark || "$"
@displayMark = displayMark || "$$"
@math = null
@blocks = null
constructor: (inlineMark, displayMark) ->
@inlineMark = inlineMark || "$"
@displayMark = displayMark || "$$"
@math = null
@blocks = null
processMath: (start, last, preProcess) ->
block = @blocks.slice(start, last + 1).join("").replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
if MathJax.Hub.Browser.isMSIE
block = block.replace /(%[^\n]*)\n/g, "$1<br/>\n"
@blocks[i] = "" for i in [start+1..last]
@blocks[start] = "@@#{@math.length}@@"
block = preProcess(block) if preProcess
@math.push block
processMath: (start, last, preProcess) ->
block = @blocks.slice(start, last + 1).join("").replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
if MathJax.Hub.Browser.isMSIE
block = block.replace /(%[^\n]*)\n/g, "$1<br/>\n"
@blocks[i] = "" for i in [start+1..last]
@blocks[start] = "@@#{@math.length}@@"
block = preProcess(block) if preProcess
@math.push block
removeMath: (text) ->
removeMath: (text) ->
text = text || ""
@math = []
start = end = last = null
braces = 0
text = text || ""
@math = []
start = end = last = null
braces = 0
hasCodeSpans = /`/.test text
if hasCodeSpans
text = text.replace(/~/g, "~T").replace CODESPAN, ($0) -> # replace dollar sign in code span temporarily
$0.replace /\$/g, "~D"
deTilde = (text) ->
text.replace /~([TD])/g, ($0, $1) ->
{T: "~", D: "$"}[$1]
else
deTilde = (text) -> text
hasCodeSpans = /`/.test text
if hasCodeSpans
text = text.replace(/~/g, "~T").replace CODESPAN, ($0) -> # replace dollar sign in code span temporarily
$0.replace /\$/g, "~D"
deTilde = (text) ->
text.replace /~([TD])/g, ($0, $1) ->
{T: "~", D: "$"}[$1]
else
deTilde = (text) -> text
@blocks = _split(text.replace(/\r\n?/g, "\n"), MATHSPLIT)
@blocks = _split(text.replace(/\r\n?/g, "\n"), MATHSPLIT)
for current in [1...@blocks.length] by 2
block = @blocks[current]
if block.charAt(0) == "@"
@blocks[current] = "@@#{@math.length}@@"
@math.push block
else if start
if block == end
if braces
last = current
else
@processMath(start, current, deTilde)
start = end = last = null
else if block.match /\n.*\n/
if last
current = last
@processMath(start, current, deTilde)
for current in [1...@blocks.length] by 2
block = @blocks[current]
if block.charAt(0) == "@"
@blocks[current] = "@@#{@math.length}@@"
@math.push block
else if start
if block == end
if braces
last = current
else
@processMath(start, current, deTilde)
start = end = last = null
braces = 0
else if block == "{"
++braces
else if block == "}" and braces
--braces
else
if block == @inlineMark or block == @displayMark
start = current
end = block
braces = 0
else if block.substr(1, 5) == "begin"
start = current
end = "\\end" + block.substr(6)
braces = 0
else if block.match /\n.*\n/
if last
current = last
@processMath(start, current, deTilde)
start = end = last = null
braces = 0
else if block == "{"
++braces
else if block == "}" and braces
--braces
else
if block == @inlineMark or block == @displayMark
start = current
end = block
braces = 0
else if block.substr(1, 5) == "begin"
start = current
end = "\\end" + block.substr(6)
braces = 0
if last
@processMath(start, last, deTilde)
start = end = last = null
if last
@processMath(start, last, deTilde)
start = end = last = null
deTilde(@blocks.join(""))
deTilde(@blocks.join(""))
@removeMathWrapper: (_this) ->
(text) -> _this.removeMath(text)
@removeMathWrapper: (_this) ->
(text) -> _this.removeMath(text)
replaceMath: (text) ->
text = text.replace /@@(\d+)@@/g, ($0, $1) => @math[$1]
@math = null
text
replaceMath: (text) ->
text = text.replace /@@(\d+)@@/g, ($0, $1) => @math[$1]
@math = null
text
@replaceMathWrapper: (_this) ->
(text) -> _this.replaceMath(text)
@replaceMathWrapper: (_this) ->
(text) -> _this.replaceMath(text)
if Markdown?
if Markdown?
Markdown.getMathCompatibleConverter = (postProcessor) ->
postProcessor ||= ((text) -> text)
converter = Markdown.getSanitizingConverter()
if MathJax?
processor = new MathJaxProcessor()
converter.hooks.chain "preConversion", MathJaxProcessor.removeMathWrapper(processor)
converter.hooks.chain "postConversion", (text) ->
postProcessor(MathJaxProcessor.replaceMathWrapper(processor)(text))
converter
Markdown.getMathCompatibleConverter = (postProcessor) ->
postProcessor ||= ((text) -> text)
converter = Markdown.getSanitizingConverter()
if MathJax?
processor = new MathJaxProcessor()
converter.hooks.chain "preConversion", MathJaxProcessor.removeMathWrapper(processor)
converter.hooks.chain "postConversion", (text) ->
postProcessor(MathJaxProcessor.replaceMathWrapper(processor)(text))
converter
Markdown.makeWmdEditor = (elem, appended_id, imageUploadUrl, postProcessor) ->
$elem = $(elem)
if not $elem.length
console.log "warning: elem for makeWmdEditor doesn't exist"
return
if not $elem.find(".wmd-panel").length
initialText = $elem.html()
$elem.empty()
_append = appended_id || ""
wmdInputId = "wmd-input#{_append}"
$wmdPreviewContainer = $("<div>").addClass("wmd-preview-container")
.append($("<div>").addClass("wmd-preview-label").text(gettext("Preview")))
.append($("<div>").attr("id", "wmd-preview#{_append}").addClass("wmd-panel wmd-preview"))
$wmdPanel = $("<div>").addClass("wmd-panel")
.append($("<div>").attr("id", "wmd-button-bar#{_append}"))
.append($("<label>").addClass("sr").attr("for", wmdInputId).text(gettext("Post body")))
.append($("<textarea>").addClass("wmd-input").attr("id", wmdInputId).html(initialText))
.append($wmdPreviewContainer)
$elem.append($wmdPanel)
Markdown.makeWmdEditor = (elem, appended_id, imageUploadUrl, postProcessor) ->
$elem = $(elem)
if not $elem.length
console.log "warning: elem for makeWmdEditor doesn't exist"
return
if not $elem.find(".wmd-panel").length
initialText = $elem.html()
$elem.empty()
_append = appended_id || ""
wmdInputId = "wmd-input#{_append}"
$wmdPreviewContainer = $("<div>").addClass("wmd-preview-container")
.append($("<div>").addClass("wmd-preview-label").text(gettext("Preview")))
.append($("<div>").attr("id", "wmd-preview#{_append}").addClass("wmd-panel wmd-preview"))
$wmdPanel = $("<div>").addClass("wmd-panel")
.append($("<div>").attr("id", "wmd-button-bar#{_append}"))
.append($("<label>").addClass("sr").attr("for", wmdInputId).text(gettext("Post body")))
.append($("<textarea>").addClass("wmd-input").attr("id", wmdInputId).html(initialText))
.append($wmdPreviewContainer)
$elem.append($wmdPanel)
converter = Markdown.getMathCompatibleConverter(postProcessor)
converter = Markdown.getMathCompatibleConverter(postProcessor)
ajaxFileUpload = (imageUploadUrl, input, startUploadHandler) ->
$("#loading").ajaxStart(-> $(this).show()).ajaxComplete(-> $(this).hide())
$("#upload").ajaxStart(-> $(this).hide()).ajaxComplete(-> $(this).show())
$.ajaxFileUpload
url: imageUploadUrl
secureuri: false
fileElementId: 'file-upload'
dataType: 'json'
success: (data, status) ->
fileURL = data['result']['file_url']
error = data['result']['error']
if error != ''
alert error
if startUploadHandler
$('#file-upload').unbind('change').change(startUploadHandler)
console.log error
else
$(input).attr('value', fileURL)
error: (data, status, e) ->
alert(e)
ajaxFileUpload = (imageUploadUrl, input, startUploadHandler) ->
$("#loading").ajaxStart(-> $(this).show()).ajaxComplete(-> $(this).hide())
$("#upload").ajaxStart(-> $(this).hide()).ajaxComplete(-> $(this).show())
$.ajaxFileUpload
url: imageUploadUrl
secureuri: false
fileElementId: 'file-upload'
dataType: 'json'
success: (data, status) ->
fileURL = data['result']['file_url']
error = data['result']['error']
if error != ''
alert error
if startUploadHandler
$('#file-upload').unbind('change').change(startUploadHandler)
console.log error
else
$(input).attr('value', fileURL)
error: (data, status, e) ->
alert(e)
if startUploadHandler
$('#file-upload').unbind('change').change(startUploadHandler)
imageUploadHandler = (elem, input) ->
ajaxFileUpload(imageUploadUrl, input, imageUploadHandler)
imageUploadHandler = (elem, input) ->
ajaxFileUpload(imageUploadUrl, input, imageUploadHandler)
editor = new Markdown.Editor(
converter,
appended_id, # idPostfix
null, # help handler
imageUploadHandler
)
delayRenderer = new MathJaxDelayRenderer()
editor.hooks.chain "onPreviewPush", (text, previewSet) ->
delayRenderer.render
text: text
previewSetter: previewSet
editor.run()
editor
editor = new Markdown.Editor(
converter,
appended_id, # idPostfix
null, # help handler
imageUploadHandler
)
delayRenderer = new MathJaxDelayRenderer()
editor.hooks.chain "onPreviewPush", (text, previewSet) ->
delayRenderer.render
text: text
previewSetter: previewSet
editor.run()
editor

View File

@@ -15,8 +15,8 @@ ReportDownloads = -> window.InstructorDashboard.util.ReportDownloads
class @DataDownload_Certificate
constructor: (@$container) ->
# gather elements
@$list_issued_certificate_table_btn = @$container.find("input[name='issued-certificates-list']'")
@$list_issued_certificate_csv_btn = @$container.find("input[name='issued-certificates-csv']'")
@$list_issued_certificate_table_btn = @$container.find("input[name='issued-certificates-list']")
@$list_issued_certificate_csv_btn = @$container.find("input[name='issued-certificates-csv']")
@$certificate_display_table = @$container.find '.certificate-data-display-table'
@$certificates_request_response_error = @$container.find '.issued-certificates-error.request-response-error'
@@ -72,18 +72,18 @@ class DataDownload
new DataDownload_Certificate @$section.find '.issued_certificates'
# gather elements
@$list_studs_btn = @$section.find("input[name='list-profiles']'")
@$list_studs_csv_btn = @$section.find("input[name='list-profiles-csv']'")
@$list_proctored_exam_results_csv_btn = @$section.find("input[name='proctored-exam-results-report']'")
@$survey_results_csv_btn = @$section.find("input[name='survey-results-report']'")
@$list_studs_btn = @$section.find("input[name='list-profiles']")
@$list_studs_csv_btn = @$section.find("input[name='list-profiles-csv']")
@$list_proctored_exam_results_csv_btn = @$section.find("input[name='proctored-exam-results-report']")
@$survey_results_csv_btn = @$section.find("input[name='survey-results-report']")
@$list_may_enroll_csv_btn = @$section.find("input[name='list-may-enroll-csv']")
@$list_problem_responses_csv_input = @$section.find("input[name='problem-location']")
@$list_problem_responses_csv_btn = @$section.find("input[name='list-problem-responses-csv']")
@$list_anon_btn = @$section.find("input[name='list-anon-ids']'")
@$grade_config_btn = @$section.find("input[name='dump-gradeconf']'")
@$calculate_grades_csv_btn = @$section.find("input[name='calculate-grades-csv']'")
@$problem_grade_report_csv_btn = @$section.find("input[name='problem-grade-report']'")
@$async_report_btn = @$section.find("input[class='async-report-btn']'")
@$list_anon_btn = @$section.find("input[name='list-anon-ids']")
@$grade_config_btn = @$section.find("input[name='dump-gradeconf']")
@$calculate_grades_csv_btn = @$section.find("input[name='calculate-grades-csv']")
@$problem_grade_report_csv_btn = @$section.find("input[name='problem-grade-report']")
@$async_report_btn = @$section.find("input[class='async-report-btn']")
# response areas
@$download = @$section.find '.data-download-container'

View File

@@ -13,10 +13,10 @@ class ECommerce
# this object to call event handlers like 'onClickTitle'
@$section.data 'wrapper', @
# gather elements
@$list_sale_csv_btn = @$section.find("input[name='list-sale-csv']'")
@$list_order_sale_csv_btn = @$section.find("input[name='list-order-sale-csv']'")
@$download_company_name = @$section.find("input[name='download_company_name']'")
@$active_company_name = @$section.find("input[name='active_company_name']'")
@$list_sale_csv_btn = @$section.find("input[name='list-sale-csv']")
@$list_order_sale_csv_btn = @$section.find("input[name='list-order-sale-csv']")
@$download_company_name = @$section.find("input[name='download_company_name']")
@$active_company_name = @$section.find("input[name='active_company_name']")
@$spent_company_name = @$section.find('input[name="spent_company_name"]')
@$download_coupon_codes = @$section.find('input[name="download-coupon-codes-csv"]')
@@ -89,4 +89,4 @@ class ECommerce
_.defaults window, InstructorDashboard: {}
_.defaults window.InstructorDashboard, sections: {}
_.defaults window.InstructorDashboard.sections,
ECommerce: ECommerce
ECommerce: ECommerce

View File

@@ -19,15 +19,15 @@ class SendEmail
constructor: (@$container) ->
# gather elements
@$emailEditor = XBlock.initializeBlock($('.xblock-studio_view'));
@$send_to = @$container.find("select[name='send_to']'")
@$subject = @$container.find("input[name='subject']'")
@$btn_send = @$container.find("input[name='send']'")
@$send_to = @$container.find("select[name='send_to']")
@$subject = @$container.find("input[name='subject']")
@$btn_send = @$container.find("input[name='send']")
@$task_response = @$container.find(".request-response")
@$request_response_error = @$container.find(".request-response-error")
@$content_request_response_error = @$container.find(".content-request-response-error")
@$history_request_response_error = @$container.find(".history-request-response-error")
@$btn_task_history_email = @$container.find("input[name='task-history-email']'")
@$btn_task_history_email_content = @$container.find("input[name='task-history-email-content']'")
@$btn_task_history_email = @$container.find("input[name='task-history-email']")
@$btn_task_history_email_content = @$container.find("input[name='task-history-email-content']")
@$table_task_history_email = @$container.find(".task-history-email-table")
@$table_email_content_history = @$container.find(".content-history-email-table")
@$email_content_table_inner = @$container.find(".content-history-table-inner")

View File

@@ -32,7 +32,7 @@ $ ->
# fix for ie
if !Array::indexOf
Array::indexOf = (obj, start = 0) ->
for ele, i in this[start..]
if ele is obj
return i + start
for ele, i in this[start..]
if ele is obj
return i + start
return -1

View File

@@ -5,23 +5,6 @@ define([
], function ($, _, Annotator, Utils) {
var _t = Annotator._t;
/**
* We currently run JQuery 1.7.2 in Jasmine tests and LMS.
* AnnotatorJS 1.2.9. uses two calls to addBack (in the two functions
* 'isAnnotator' and 'onHighlightMouseover') which was only defined in
* JQuery 1.8.0. In LMS, it works without throwing an error because
* JQuery.UI 1.10.0 adds support to jQuery<1.8 by augmenting '$.fn' with
* that missing function. It is not the case for all Jasmine unit tests,
* so we add it here if necessary.
**/
if (!$.fn.addBack) {
$.fn.addBack = function (selector) {
return this.add(
selector === null ? this.prevObject : this.prevObject.filter(selector)
);
};
}
/**
* The original _setupDynamicStyle uses a very expensive call to
* Util.maxZIndex(...) that sets the z-index of .annotator-adder,

View File

@@ -56,7 +56,7 @@
if (!groupsEnabled) {
// If the user has chosen 'no', then clear the selection by setting
// it to the first option which represents no selection.
this.$('.input-cohort-group-association').val('None');
this.$('.input-cohort-group-association').val(null);
}
// Enable the select if the user has chosen groups, else disable it
this.$('.input-cohort-group-association').prop('disabled', !groupsEnabled);
@@ -69,7 +69,7 @@
getSelectedContentGroup: function() {
var selectValue = this.$('.input-cohort-group-association').val(),
ids, groupId, userPartitionId, i, contentGroup;
if (!this.hasAssociatedContentGroup() || selectValue === 'None') {
if (!this.hasAssociatedContentGroup() || _.isNull(selectValue)) {
return null;
}
ids = selectValue.split(':');
@@ -107,7 +107,7 @@
errorMessages.push(gettext('You must specify a name for the cohort'));
}
if (this.hasAssociatedContentGroup() && fieldData.group_id === null) {
if (this.$('.input-cohort-group-association').val() === 'None') {
if (_.isNull(this.$('.input-cohort-group-association').val())) {
errorMessages.push(gettext('You did not select a content group'));
} else {
// If a value was selected, then it must be for a non-existent/deleted content group

View File

@@ -17,12 +17,18 @@ var edx = edx || {};
},
clicked: function (event) {
if (event.currentTarget.checked) {
this.$el.find('#coupon_expiration_date').show();
this.show(this.$('#coupon_expiration_date'));
this.$el.find('#coupon_expiration_date').focus();
}
else {
this.$el.find('#coupon_expiration_date').hide();
this.hide(this.$('#coupon_expiration_date'));
}
},
show: function ($el) {
$el.css('display', 'inline');
},
hide: function ($el) {
$el.css('display', 'none');
}
});

View File

@@ -1,5 +1,5 @@
define(['jquery', 'logger', 'js/courseware/toggle_element_visibility'],
function ($, Logger, ToggleElementVisibility) {
define(['jquery', 'logger', 'js/courseware/toggle_element_visibility', 'moment'],
function ($, Logger, ToggleElementVisibility, moment) {
'use strict';
describe('show/hide with mouse click', function () {
@@ -43,7 +43,7 @@ define(['jquery', 'logger', 'js/courseware/toggle_element_visibility'],
$update.siblings('.toggle-visibility-button').trigger('click');
expect(Logger.log).toHaveBeenCalledWith('edx.course.home.course_update.toggled', {
action: 'hide',
publish_date: '2015-12-01T00:00:00+00:00'
publish_date: moment('December 1, 2015', 'MMM DD, YYYY').format()
});
});
});

View File

@@ -107,6 +107,12 @@ define([
'templates/discovery/filter_bar'
]);
DiscoveryFactory(MEANINGS);
jasmine.clock().install();
});
afterEach(function () {
jasmine.clock().uninstall();
});
it('does search', function () {
@@ -121,22 +127,20 @@ define([
it('loads more', function () {
var requests = AjaxHelpers.requests(this);
jasmine.clock().install();
$('.discovery-input').val('test');
$('.discovery-submit').trigger('click');
AjaxHelpers.respondWithJson(requests, JSON_RESPONSE);
expect($('.courses-listing article').length).toEqual(1);
expect($('.courses-listing .course-title')).toContainHtml('edX Demonstration Course');
jasmine.clock().tick(500);
window.scroll(0, $(document).height());
$(window).trigger('scroll');
jasmine.clock().tick(500);
// TODO: determine why the search API is invoked twice
AjaxHelpers.respondWithJson(requests, JSON_RESPONSE);
AjaxHelpers.respondWithJson(requests, JSON_RESPONSE);
expect($('.courses-listing article').length).toEqual(2);
jasmine.clock().uninstall();
});
it('displays not found message', function () {

View File

@@ -223,7 +223,7 @@ define(['backbone', 'jquery', 'common/js/spec_helpers/ajax_helpers', 'common/js/
clearContentGroup = function() {
cohortsView.$('.radio-no').prop('checked', true).change();
expect(cohortsView.$('.input-cohort-group-association').prop('disabled')).toBeTruthy();
expect(cohortsView.$('.input-cohort-group-association').val()).toBe('None');
expect(cohortsView.$('.input-cohort-group-association').val()).toBe(null);
};
verifyMessage = function(expectedTitle, expectedMessageType, expectedAction, hasDetails) {

View File

@@ -22,7 +22,6 @@ define(['backbone', 'jquery', 'js/instructor_dashboard/ecommerce'],
it("shows the input field when the checkbox is checked", function () {
var target = expiryCouponView.$el.find('input[type="checkbox"]');
target.attr("checked","checked");
target.click();
expect(expiryCouponView.$el.find('#coupon_expiration_date').is(':visible')).toBe(true);
});
@@ -30,7 +29,6 @@ define(['backbone', 'jquery', 'js/instructor_dashboard/ecommerce'],
it("hides the input field when the checkbox is unchecked", function () {
var target = expiryCouponView.$el.find('input[type="checkbox"]');
expect(expiryCouponView.$el.find('#coupon_expiration_date')).toHaveAttr('style','display: none;');
});
});
});

View File

@@ -8,7 +8,8 @@
paths: {
'gettext': 'xmodule_js/common_static/js/test/i18n',
'codemirror': 'xmodule_js/common_static/js/vendor/CodeMirror/codemirror',
'jquery': 'xmodule_js/common_static/js/vendor/jquery.min',
'jquery': 'xmodule_js/common_static/common/js/vendor/jquery',
'jquery-migrate': 'xmodule_js/common_static/common/js/vendor/jquery-migrate',
'jquery.ui': 'xmodule_js/common_static/js/vendor/jquery-ui.min',
'jquery.eventDrag': 'xmodule_js/common_static/js/vendor/jquery.event.drag-2.2',
'jquery.flot': 'xmodule_js/common_static/js/vendor/flot/jquery.flot.min',
@@ -18,7 +19,7 @@
'jquery.ajaxQueue': 'xmodule_js/common_static/js/vendor/jquery.ajaxQueue',
'jquery.ajax-retry': 'js/vendor/jquery.ajax-retry',
'jquery.smoothScroll': 'xmodule_js/common_static/js/vendor/jquery.smooth-scroll.min',
'jquery.scrollTo': 'xmodule_js/common_static/js/vendor/jquery.scrollTo-1.4.2-min',
'jquery.scrollTo': 'common/js/vendor/jquery.scrollTo',
'jquery.timepicker': 'xmodule_js/common_static/js/vendor/timepicker/jquery.timepicker',
'jquery.cookie': 'xmodule_js/common_static/js/vendor/jquery.cookie',
'jquery.qtip': 'xmodule_js/common_static/js/vendor/jquery.qtip.min',
@@ -92,7 +93,7 @@
// Discussion classes loaded explicitly until they are converted to use RequireJS
'DiscussionModuleView': 'xmodule_js/common_static/coffee/src/discussion/discussion_module_view',
'js/bookmarks/collections/bookmarks': 'js/bookmarks/collections/bookmarks',
'js/bookmarks/models/bookmark': 'js/bookmarks/models/bookmark',
'js/bookmarks/views/bookmarks_list_button': 'js/bookmarks/views/bookmarks_list_button',
@@ -119,6 +120,7 @@
'date': {
exports: 'Date'
},
"jquery-migrate": ['jquery'],
'jquery.ui': {
deps: ['jquery'],
exports: 'jQuery.ui'
@@ -289,6 +291,10 @@
exports: 'coffee/src/instructor_dashboard/student_admin',
deps: ['jquery', 'underscore', 'coffee/src/instructor_dashboard/util', 'string_utils']
},
'coffee/src/instructor_dashboard/util': {
exports: 'coffee/src/instructor_dashboard/util',
deps: ['jquery', 'underscore', 'slick.core', 'slick.grid']
},
'js/instructor_dashboard/certificates': {
exports: 'js/instructor_dashboard/certificates',
deps: ['jquery', 'gettext', 'underscore']
@@ -492,6 +498,14 @@
exports: 'Annotator',
deps: ['jquery']
},
'slick.core': {
deps: ['jquery'],
exports: 'Slick'
},
'slick.grid': {
deps: ['jquery', 'jquery.eventDrag', 'slick.core'],
exports: 'Slick'
},
// Discussions
'xmodule_js/common_static/coffee/src/discussion/utils': {
deps: [

View File

@@ -132,6 +132,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
});
it("expects all fields to behave correctly", function () {
var i, view;
requests = AjaxHelpers.requests(this);
@@ -146,9 +147,8 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
expect(sectionsData[0].fields.length).toBe(6);
var textFields = [sectionsData[0].fields[1], sectionsData[0].fields[2]];
for (var i = 0; i < textFields.length ; i++) {
var view = textFields[i].view;
for (i = 0; i < textFields.length ; i++) {
view = textFields[i].view;
FieldViewsSpecHelpers.verifyTextField(view, {
title: view.options.title,
valueAttribute: view.options.valueAttribute,

View File

@@ -3,13 +3,14 @@
define([
'jquery',
'underscore',
'sinon',
'common/js/spec_helpers/template_helpers',
'common/js/spec_helpers/ajax_helpers',
'js/student_account/models/LoginModel',
'js/student_account/views/LoginView',
'js/student_account/models/PasswordResetModel'
],
function($, _, TemplateHelpers, AjaxHelpers, LoginModel, LoginView, PasswordResetModel) {
function($, _, sinon, TemplateHelpers, AjaxHelpers, LoginModel, LoginView, PasswordResetModel) {
describe('edx.student.account.LoginView', function() {
var model = null,
@@ -267,13 +268,25 @@
});
it('displays an error if there is no internet connection', function () {
var clock,
oldTimeout,
timeout;
// We're defining "no internet connection" in this case as the
// request timing out. We use a combination of the sinon fake
// timer and jQuery.ajaxSetup() to force a request timeout.
clock = sinon.useFakeTimers();
oldTimeout = $.ajaxSetup().timeout;
timeout = 1;
$.ajaxSetup({timeout: timeout});
createLoginView(this);
// Submit the form, with successful validation
submitForm(true);
// Simulate an error from the LMS servers
AjaxHelpers.respondWithError(requests, 0);
// Simulate a request timeout
clock.tick(timeout + 1);
// Expect that an error is displayed and that auth complete is not triggered
expect(view.$errors).not.toHaveClass('hidden');
@@ -281,7 +294,12 @@
expect(view.$errors.text()).toContain(
'An error has occurred. Check your Internet connection and try again.'
);
// Finally, restore the old timeout and turn off the fake timer.
$.ajaxSetup({timeout: oldTimeout});
clock.restore();
});
it('displays an error if there is a server error', function () {
createLoginView(this);

View File

@@ -54,6 +54,11 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
TemplateHelpers.installTemplate("templates/fields/message_banner");
});
afterEach(function () {
// image_field.js's window.onBeforeUnload breaks Karma in Chrome, clean it up after each test
$(window).off('beforeunload');
});
var createFakeImageFile = function (size) {
var fileFakeData = 'i63ljc6giwoskyb9x5sw0169bdcmcxr3cdz8boqv0lik971972cmd6yknvcxr5sw0nvc169bdcmcxsdf';
return new Blob(
@@ -260,6 +265,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
// Verify image upload progress message
verifyImageUploadButtonMessage(imageView, true);
window.onbeforeunload = null;
$(window).trigger('beforeunload');
expect(imageView.onBeforeUnload).toHaveBeenCalled();
});

View File

@@ -42,7 +42,7 @@ define([
// Simulate the server response
if ( succeeds ) {
AjaxHelpers.respondWithJson( requests, {} );
AjaxHelpers.respondWithJson( requests, {url: '/arbitrary-url/'} );
} else {
AjaxHelpers.respondWithTextError( requests, 400, SERVER_ERROR_MSG );
}

View File

@@ -240,8 +240,8 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
verifyEditableField(view, _.extend({
valueSelector: '.u-field-value',
valueInputSelector: '.u-field-value > input'
}, data
), requests);
}, data),
requests);
};
var verifyDropDownField = function (view, data, requests) {

View File

@@ -28,7 +28,7 @@
},
parse : function(response) {
if (_.isNull(response)) {
if (_.isNull(response) || _.isUndefined(response)) {
return {};
}

View File

@@ -78,7 +78,8 @@
$(this.el).show(); // Show in case the form was hidden for auto-submission
this.errors = _.flatten(
_.map(
JSON.parse(error.responseText),
// Something is passing this 'undefined'. Protect against this.
JSON.parse(error.responseText || "[]"),
function(error_list) {
return _.map(
error_list,

View File

@@ -218,13 +218,13 @@
this.backend = this.backends[obj.backendName] || obj.backend;
this.captureSoundPath = obj.captureSoundPath || "";
_.extend( this.backend, Backbone.Events );
this.backend.initialize({
wrapper: "#camera",
video: '#photo_id_video',
canvas: '#photo_id_canvas'
});
_.extend( this.backend, Backbone.Events );
this.listenTo( this.backend, 'error', this.handleError );
this.listenTo( this.backend, 'webcam-loaded', this.handleWebcamLoaded );
},

View File

@@ -13,6 +13,8 @@ var options = {
// Avoid adding files to this list. Use RequireJS.
libraryFilesToInclude: [
{pattern: 'common/js/vendor/jquery.js', included: true},
{pattern: 'common/js/vendor/jquery-migrate.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.event.drag-2.2.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/slick.core.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/slick.grid.js', included: true}

View File

@@ -25,7 +25,8 @@ var options = {
{pattern: 'xmodule_js/common_static/js/src/logger.js', included: true},
{pattern: 'xmodule_js/common_static/js/test/i18n.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.min.js', included: true},
{pattern: 'common/js/vendor/jquery.js', included: true},
{pattern: 'common/js/vendor/jquery-migrate.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.cookie.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/flot/jquery.flot.js', included: true},
{pattern: 'xmodule_js/common_static/coffee/src/jquery.immediateDescendents.js', included: true},

View File

@@ -66,6 +66,7 @@
'gettext': 'empty:',
'coffee/src/ajax_prefix': 'empty:',
'jquery': 'empty:',
'jquery-migrate': 'empty:',
'jquery.cookie': 'empty:',
'jquery.url': 'empty:',
'backbone': 'empty:',

View File

@@ -28,6 +28,7 @@
}
};
defineDependency("jQuery", "jquery");
defineDependency("jQuery", "jquery-migrate");
defineDependency("_", "underscore");
defineDependency("s", "underscore.string");
// Underscore.string no longer installs itself directly on "_". For compatibility with existing
@@ -64,7 +65,13 @@
"backbone.paginator": "js/vendor/backbone.paginator.min",
"underscore": "common/js/vendor/underscore",
"underscore.string": "common/js/vendor/underscore.string",
"jquery": "js/vendor/jquery.min",
// The jquery-migrate library was added in upgrading from
// jQuery 1.7.x to 2.2.x. This config allows developers
// to depend on "jquery" which opaquely requires both
// libraries.
"jquery": "common/js/vendor/jquery",
"jquery-migrate": "common/js/vendor/jquery-migrate",
"jquery.scrollTo": "common/js/vendor/jquery.scrollTo",
"jquery.cookie": "js/vendor/jquery.cookie",
'jquery.timeago': 'js/vendor/jquery.timeago',
"jquery.url": "js/vendor/url.min",
@@ -111,6 +118,10 @@
"date": {
exports: "Date"
},
"jquery": {
exports: "jQuery"
},
"jquery-migrate": ['jquery'],
"jquery.cookie": {
deps: ["jquery"],
exports: "jQuery.fn.cookie"

View File

@@ -45,7 +45,7 @@ ${static.get_page_title_breadcrumbs(course_name())}
</%block>
<%block name="js_extra">
<script type="text/javascript" src="${static.url('js/vendor/jquery.scrollTo-1.4.2-min.js')}"></script>
<script type="text/javascript" src="${static.url('common/js/vendor/jquery.scrollTo.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script>
## codemirror

View File

@@ -65,7 +65,7 @@ ${static.get_page_title_breadcrumbs(course_name())}
</%block>
<%block name="js_extra">
<script type="text/javascript" src="${static.url('js/vendor/jquery.scrollTo-1.4.2-min.js')}"></script>
<script type="text/javascript" src="${static.url('common/js/vendor/jquery.scrollTo.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/flot/jquery.flot.js')}"></script>
## codemirror

View File

@@ -21,7 +21,7 @@
</body>
</html>
<script type="text/javascript" src="${static.url('js/vendor/jquery.min.js')}"></script>
<script type="text/javascript" src="${static.url('common/js/vendor/jquery.js')}"></script>
<script type="text/javascript">
$(document).ready(function() {

View File

@@ -2,15 +2,18 @@
"name": "edx",
"version": "0.1.0",
"dependencies": {
"backbone": "~1.3.2",
"coffee-script": "1.6.1",
"edx-pattern-library": "~0.12.4",
"edx-ui-toolkit": "~0.9.1",
"jquery": "~2.2.0",
"jquery-migrate": "^1.4.1",
"jquery.scrollto": "~2.1.2",
"picturefill": "~3.0.2",
"requirejs": "~2.1.22",
"uglify-js": "2.4.24",
"underscore": "~1.8.3",
"underscore.string": "~3.3.4",
"picturefill": "~3.0.2",
"backbone": "~1.3.2"
"underscore.string": "~3.3.4"
},
"devDependencies": {
"edx-custom-a11y-rules": "edx/edx-custom-a11y-rules",

View File

@@ -45,6 +45,9 @@ SASS_LOAD_PATHS = [
# A list of NPM installed libraries that should be copied into the common
# static directory.
NPM_INSTALLED_LIBRARIES = [
'jquery/dist/jquery.js',
'jquery-migrate/dist/jquery-migrate.js',
'jquery.scrollto/jquery.scrollTo.js',
'underscore/underscore.js',
'underscore.string/dist/underscore.string.js',
'picturefill/dist/picturefill.js',

View File

@@ -10,7 +10,6 @@
"date": "1.0",
"domready": "2.0.1",
"draggabilly": "1.2.4",
"jquery": "1.7.2",
"jquery-form": "3.18.0",
"jquery-watch": "2.0",
"moment": "2.10.6",

View File

@@ -22,7 +22,6 @@
"domReady": "2.0.1",
"draggabilly": "1.2.4",
// "history": "1.8b2",
"jquery": "1.7.2",
// "jquery.ajaxQueue": "unknown",
// "jquery.ajax-retry": "unknown",
"jquery.colorhelpers": "1.1",