diff --git a/app/coffeescripts/models/Assignment.coffee b/app/coffeescripts/models/Assignment.coffee
index bd4595adffd..13f687e4cb7 100644
--- a/app/coffeescripts/models/Assignment.coffee
+++ b/app/coffeescripts/models/Assignment.coffee
@@ -238,6 +238,9 @@ export default class Assignment extends Model
acceptsOnlineUpload: =>
!! _.includes @_submissionTypes(), 'online_upload'
+ acceptsAnnotatedDocument: =>
+ !! _.includes @_submissionTypes(), 'annotated_document'
+
acceptsOnlineURL: =>
!! _.includes @_submissionTypes(), 'online_url'
@@ -250,7 +253,7 @@ export default class Assignment extends Model
isOnlineSubmission: =>
_.some @_submissionTypes(), (thing) ->
thing in ['online', 'online_text_entry',
- 'media_recording', 'online_url', 'online_upload']
+ 'media_recording', 'online_url', 'online_upload', 'annotated_document']
postToSIS: (postToSisBoolean) =>
return @get 'post_to_sis' unless arguments.length > 0
@@ -557,6 +560,7 @@ export default class Assignment extends Model
toView: =>
fields = [
+ 'acceptsAnnotatedDocument',
'acceptsMediaRecording', 'acceptsOnlineTextEntries', 'acceptsOnlineURL',
'acceptsOnlineUpload', 'allDates', 'allowedExtensions', 'anonymousGrading',
'anonymousInstructorAnnotations', 'anonymousPeerReviews', 'assignmentGroupId',
diff --git a/app/coffeescripts/views/assignments/EditView.coffee b/app/coffeescripts/views/assignments/EditView.coffee
index cc2fbf5b8b4..6296277daef 100644
--- a/app/coffeescripts/views/assignments/EditView.coffee
+++ b/app/coffeescripts/views/assignments/EditView.coffee
@@ -50,6 +50,7 @@ import 'jqueryui/dialog'
import 'jquery.toJSON'
import '../../jquery.rails_flash_notifications'
import '../../behaviors/tooltip'
+import {FileBrowserWrapper} from 'jsx/assignments/EditAssignment'
###
xsslint safeString.identifier srOnly
@@ -69,9 +70,11 @@ export default class EditView extends ValidatedFormView
ONLINE_SUBMISSION_TYPES = '#assignment_online_submission_types'
NAME = '[name="name"]'
ALLOW_FILE_UPLOADS = '#assignment_online_upload'
+ ALLOW_ANNOTATED_DOCUMENT = '#assignment_annotated_document'
ALLOW_TEXT_ENTRY = '#assignment_text_entry'
RESTRICT_FILE_UPLOADS = '#assignment_restrict_file_extensions'
RESTRICT_FILE_UPLOADS_OPTIONS = '#restrict_file_extensions_container'
+ ANNOTATED_DOCUMENT_OPTIONS = '#annotated_document_chooser_container'
ALLOWED_EXTENSIONS = '#allowed_extensions_container'
TURNITIN_ENABLED = '#assignment_turnitin_enabled'
VERICITE_ENABLED = '#assignment_vericite_enabled'
@@ -115,8 +118,10 @@ export default class EditView extends ValidatedFormView
els["#{ONLINE_SUBMISSION_TYPES}"] = '$onlineSubmissionTypes'
els["#{NAME}"] = '$name'
els["#{ALLOW_FILE_UPLOADS}"] = '$allowFileUploads'
+ els["#{ALLOW_ANNOTATED_DOCUMENT}"] = '$allowAnnotatedDocument'
els["#{RESTRICT_FILE_UPLOADS}"] = '$restrictFileUploads'
els["#{RESTRICT_FILE_UPLOADS_OPTIONS}"] = '$restrictFileUploadsOptions'
+ els["#{ANNOTATED_DOCUMENT_OPTIONS}"] = '$annotatedDocumentOptions'
els["#{ALLOWED_EXTENSIONS}"] = '$allowedExtensions'
els["#{TURNITIN_ENABLED}"] = '$turnitinEnabled'
els["#{VERICITE_ENABLED}"] = '$vericiteEnabled'
@@ -159,6 +164,7 @@ export default class EditView extends ValidatedFormView
events["change #{TURNITIN_ENABLED}"] = 'toggleAdvancedTurnitinSettings'
events["change #{VERICITE_ENABLED}"] = 'toggleAdvancedTurnitinSettings'
events["change #{ALLOW_FILE_UPLOADS}"] = 'toggleRestrictFileUploads'
+ events["change #{ALLOW_ANNOTATED_DOCUMENT}"] = 'toggleAnnotatedDocument'
events["click #{EXTERNAL_TOOLS_URL}_find"] = 'showExternalToolsDialog'
events["change #assignment_points_possible"] = 'handlePointsChange'
events["change #{PEER_REVIEWS_BOX}"] = 'togglePeerReviewsAndGroupCategoryEnabled'
@@ -322,6 +328,29 @@ export default class EditView extends ValidatedFormView
toggleRestrictFileUploads: =>
@$restrictFileUploadsOptions.toggleAccessibly @$allowFileUploads.prop('checked')
+ toggleAnnotatedDocument: =>
+ @$annotatedDocumentOptions.toggleAccessibly @$allowAnnotatedDocument.prop('checked')
+
+ documentChooserContainer = document.querySelector('#annotated_document_chooser_container')
+
+ if @$allowAnnotatedDocument.prop('checked')
+ fileBrowserProps = {
+ useContextAssets: true,
+ allowUpload: true,
+ selectFile: (fileInfo) =>
+ document.getElementById('annotated_document_id').value = fileInfo.id
+ $.screenReaderFlashMessageExclusive(
+ I18n.t('selected %{filename}', {filename: fileInfo.name})
+ )
+ }
+
+ ReactDOM.render(
+ React.createElement(FileBrowserWrapper, fileBrowserProps),
+ documentChooserContainer
+ )
+ else
+ ReactDOM.unmountComponentAtNode(documentChooserContainer)
+
toggleAdvancedTurnitinSettings: (ev) =>
ev.preventDefault()
@$advancedTurnitinSettings.toggleAccessibly (@$turnitinEnabled.prop('checked') || @$vericiteEnabled.prop('checked'))
@@ -520,6 +549,7 @@ export default class EditView extends ValidatedFormView
lockedItems: @lockedItems
anonymousGradingEnabled: ENV?.ANONYMOUS_GRADING_ENABLED or false
anonymousInstructorAnnotationsEnabled: ENV?.ANONYMOUS_INSTRUCTOR_ANNOTATIONS_ENABLED or false
+ annotatedDocumentSubmissionsEnabled: ENV?.ANNOTATED_DOCUMENT_SUBMISSIONS or false
_attachEditorToDescription: =>
return if @lockedItems.content
diff --git a/app/jsx/assignments/EditAssignment.js b/app/jsx/assignments/EditAssignment.js
new file mode 100644
index 00000000000..444a77580ce
--- /dev/null
+++ b/app/jsx/assignments/EditAssignment.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 - present Instructure, Inc.
+ *
+ * This file is part of Canvas.
+ *
+ * Canvas is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Affero General Public License as published by the Free
+ * Software Foundation, version 3 of the License.
+ *
+ * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Affero General Public License along
+ * with this program. If not, see
<E>
' const view = this.editView({description: '<E>
'}) equal(view.$description.val().match(desc), desc) }) -test('routes to discussion details normally', function() { +test('routes to discussion details normally', function () { const view = this.editView({html_url: 'http://foo'}) equal(view.locationAfterSave({}), 'http://foo') }) -test('routes to return_to', function() { +test('routes to return_to', function () { const view = this.editView({html_url: currentOrigin + '/foo'}) equal(view.locationAfterSave({return_to: currentOrigin + '/bar'}), currentOrigin + '/bar') }) -test('does not route to return_to with javascript protocol', function() { +test('does not route to return_to with javascript protocol', function () { const view = this.editView({html_url: currentOrigin + '/foo'}) // eslint-disable-next-line no-script-url equal(view.locationAfterSave({return_to: 'javascript:alert(1)'}), currentOrigin + '/foo') }) -test('cancels to env normally', function() { +test('cancels to env normally', function () { ENV.CANCEL_TO = currentOrigin + '/foo' const view = this.editView() equal(view.locationAfterCancel({}), currentOrigin + '/foo') }) -test('cancels to return_to', function() { +test('cancels to return_to', function () { ENV.CANCEL_TO = currentOrigin + '/foo' const view = this.editView() equal(view.locationAfterCancel({return_to: currentOrigin + '/bar'}), currentOrigin + '/bar') }) -test('does not cancel to return_to with javascript protocol', function() { +test('does not cancel to return_to with javascript protocol', function () { ENV.CANCEL_TO = currentOrigin + '/foo' const view = this.editView() // eslint-disable-next-line no-script-url equal(view.locationAfterCancel({return_to: 'javascript:alert(1)'}), currentOrigin + '/foo') }) -test('does not follow a cross-origin return_to', function() { +test('does not follow a cross-origin return_to', function () { ENV.CANCEL_TO = currentOrigin + '/foo' const view = this.editView() equal(view.locationAfterCancel({return_to: 'http://evil.com'}), currentOrigin + '/foo') }) -test('disables fields when inClosedGradingPeriod', function() { +test('disables fields when inClosedGradingPeriod', function () { const view = this.editView({in_closed_grading_period: true}) view.$el.appendTo($('#fixtures')) @@ -419,7 +418,7 @@ test('disables fields when inClosedGradingPeriod', function() { equal(view.$el.find('#has_group_category').attr('aria-readonly'), 'true') }) -test('disables grading type field when frozen', function() { +test('disables grading type field when frozen', function () { const view = this.editView({frozen_attributes: ['grading_type']}) view.$el.appendTo($('#fixtures')) @@ -427,14 +426,14 @@ test('disables grading type field when frozen', function() { equal(view.$el.find('input[name="grading_type"]').attr('type'), 'hidden') }) -test('does not disable post to sis when inClosedGradingPeriod', function() { +test('does not disable post to sis when inClosedGradingPeriod', function () { ENV.POST_TO_SIS = true const view = this.editView({in_closed_grading_period: true}) view.$el.appendTo($('#fixtures')) notOk(view.$el.find('#assignment_post_to_sis').attr('disabled')) }) -test('disableCheckbox is called for a disabled checkbox', function() { +test('disableCheckbox is called for a disabled checkbox', function () { const view = this.editView({in_closed_grading_period: true}) view.$el.appendTo($('#fixtures')) $('').appendTo($(view.$el)) @@ -445,7 +444,7 @@ test('disableCheckbox is called for a disabled checkbox', function() { equal(disableCheckboxStub.called, true) }) -test('ignoreClickHandler is called for a disabled radio', function() { +test('ignoreClickHandler is called for a disabled radio', function () { const view = this.editView({in_closed_grading_period: true}) view.$el.appendTo($('#fixtures')) @@ -459,7 +458,7 @@ test('ignoreClickHandler is called for a disabled radio', function() { equal(ignoreClickHandlerStub.calledOnce, true) }) -test('lockSelectValueHandler is called for a disabled select', function() { +test('lockSelectValueHandler is called for a disabled select', function () { const view = this.editView({in_closed_grading_period: true}) view.$el.html('') $('').appendTo( @@ -473,7 +472,7 @@ test('lockSelectValueHandler is called for a disabled select', function() { equal(lockSelectValueHandlerStub.calledOnce, true) }) -test('lockSelectValueHandler freezes selected value', function() { +test('lockSelectValueHandler freezes selected value', function () { const view = this.editView({in_closed_grading_period: true}) view.$el.html('') $('').appendTo( @@ -482,14 +481,11 @@ test('lockSelectValueHandler freezes selected value', function() { view.$el.appendTo($('#fixtures')) const selectedValue = view.$el.find('#fixture_select').val() - view.$el - .find('#fixture_select') - .val(2) - .trigger('change') + view.$el.find('#fixture_select').val(2).trigger('change') equal(view.$el.find('#fixture_select').val(), selectedValue) }) -test('fields are enabled when not inClosedGradingPeriod', function() { +test('fields are enabled when not inClosedGradingPeriod', function () { const view = this.editView() view.$el.appendTo($('#fixtures')) @@ -503,14 +499,14 @@ test('fields are enabled when not inClosedGradingPeriod', function() { notOk(view.$el.find('#has_group_category').attr('aria-readonly')) }) -test('rounds points_possible', function() { +test('rounds points_possible', function () { const view = this.editView() view.$assignmentPointsPossible.val('1.234') const data = view.getFormData() equal(data.points_possible, 1.23) }) -test('sets seconds of due_at to 59 if the new minute value is 59', function() { +test('sets seconds of due_at to 59 if the new minute value is 59', function () { const view = this.editView({ due_at: $.unfudgeDateForProfileTimezone(new Date('2000-08-28T11:58:23')) }) @@ -519,7 +515,7 @@ test('sets seconds of due_at to 59 if the new minute value is 59', function() { strictEqual(view.getFormData().due_at, '2000-08-28T11:59:59.000Z') }) -test('sets seconds of due_at to 00 if the new minute value is not 59', function() { +test('sets seconds of due_at to 00 if the new minute value is not 59', function () { const view = this.editView({ due_at: $.unfudgeDateForProfileTimezone(new Date('2000-08-28T11:59:23')) }) @@ -531,7 +527,7 @@ test('sets seconds of due_at to 00 if the new minute value is not 59', function( // The UI doesn't allow editing the seconds value and always returns 00. If // the seconds value was set to something different prior to the update, keep // that value. -test('keeps original due_at seconds if only the seconds value has changed', function() { +test('keeps original due_at seconds if only the seconds value has changed', function () { const view = this.editView({ due_at: $.unfudgeDateForProfileTimezone(new Date('2000-08-29T11:59:23')) }) @@ -540,7 +536,7 @@ test('keeps original due_at seconds if only the seconds value has changed', func strictEqual(view.getFormData().due_at, '2000-08-29T11:59:23.000Z') }) -test('keeps original due_at seconds if the date has not changed', function() { +test('keeps original due_at seconds if the date has not changed', function () { const view = this.editView({ due_at: $.unfudgeDateForProfileTimezone(new Date('2000-08-28T11:59:23')) }) @@ -549,7 +545,7 @@ test('keeps original due_at seconds if the date has not changed', function() { strictEqual(view.getFormData().due_at, '2000-08-28T11:59:23.000Z') }) -test('sets seconds of unlock_at to 59 if the new minute value is 59', function() { +test('sets seconds of unlock_at to 59 if the new minute value is 59', function () { const view = this.editView({ unlock_at: $.unfudgeDateForProfileTimezone(new Date('2000-08-28T11:58:23')) }) @@ -558,7 +554,7 @@ test('sets seconds of unlock_at to 59 if the new minute value is 59', function() strictEqual(view.getFormData().unlock_at, '2000-08-28T11:59:59.000Z') }) -test('sets seconds of unlock_at to 00 if the new minute value is not 59', function() { +test('sets seconds of unlock_at to 00 if the new minute value is not 59', function () { const view = this.editView({ unlock_at: $.unfudgeDateForProfileTimezone(new Date('2000-08-28T11:59:23')) }) @@ -570,7 +566,7 @@ test('sets seconds of unlock_at to 00 if the new minute value is not 59', functi // The UI doesn't allow editing the seconds value and always returns 00. If // the seconds value was set to something different prior to the update, keep // that value. -test('keeps original unlock_at seconds if only the seconds value has changed', function() { +test('keeps original unlock_at seconds if only the seconds value has changed', function () { const view = this.editView({ unlock_at: $.unfudgeDateForProfileTimezone(new Date('2000-08-29T11:59:23')) }) @@ -579,7 +575,7 @@ test('keeps original unlock_at seconds if only the seconds value has changed', f strictEqual(view.getFormData().unlock_at, '2000-08-29T11:59:23.000Z') }) -test('keeps original unlock_at seconds if the date has not changed', function() { +test('keeps original unlock_at seconds if the date has not changed', function () { const view = this.editView({ unlock_at: $.unfudgeDateForProfileTimezone(new Date('2000-08-28T11:59:23')) }) @@ -588,7 +584,7 @@ test('keeps original unlock_at seconds if the date has not changed', function() strictEqual(view.getFormData().unlock_at, '2000-08-28T11:59:23.000Z') }) -test('sets seconds of lock_at to 59 if the new minute value is 59', function() { +test('sets seconds of lock_at to 59 if the new minute value is 59', function () { const view = this.editView({ lock_at: $.unfudgeDateForProfileTimezone(new Date('2000-08-28T11:58:23')) }) @@ -597,7 +593,7 @@ test('sets seconds of lock_at to 59 if the new minute value is 59', function() { strictEqual(view.getFormData().lock_at, '2000-08-28T11:59:59.000Z') }) -test('sets seconds of lock_at to 00 if the new minute value is not 59', function() { +test('sets seconds of lock_at to 00 if the new minute value is not 59', function () { const view = this.editView({ lock_at: $.unfudgeDateForProfileTimezone(new Date('2000-08-28T11:59:23')) }) @@ -609,7 +605,7 @@ test('sets seconds of lock_at to 00 if the new minute value is not 59', function // The UI doesn't allow editing the seconds value and always returns 00. If // the seconds value was set to something different prior to the update, keep // that value. -test('keeps original lock_at seconds if only the seconds value has changed', function() { +test('keeps original lock_at seconds if only the seconds value has changed', function () { const view = this.editView({ lock_at: $.unfudgeDateForProfileTimezone(new Date('2000-08-29T11:59:23')) }) @@ -618,7 +614,7 @@ test('keeps original lock_at seconds if only the seconds value has changed', fun strictEqual(view.getFormData().lock_at, '2000-08-29T11:59:23.000Z') }) -test('keeps original lock_at seconds if the date has not changed', function() { +test('keeps original lock_at seconds if the date has not changed', function () { const view = this.editView({ lock_at: $.unfudgeDateForProfileTimezone(new Date('2000-08-28T11:59:23')) }) @@ -658,7 +654,7 @@ QUnit.module('EditView: handleGroupCategoryChange', { } }) -test('unchecks the group category checkbox if the anonymous grading checkbox is checked', function() { +test('unchecks the group category checkbox if the anonymous grading checkbox is checked', function () { const view = this.editView() checkCheckbox('assignment_anonymous_grading') checkCheckbox('has_group_category') @@ -667,7 +663,7 @@ test('unchecks the group category checkbox if the anonymous grading checkbox is strictEqual(groupCategoryCheckbox.checked, false) }) -test('disables the anonymous grading checkbox if the group category checkbox is checked', function() { +test('disables the anonymous grading checkbox if the group category checkbox is checked', function () { const view = this.editView() checkCheckbox('has_group_category') view.handleGroupCategoryChange() @@ -675,7 +671,7 @@ test('disables the anonymous grading checkbox if the group category checkbox is strictEqual(anonymousGradingCheckbox.disabled, true) }) -test('enables the anonymous grading checkbox if the group category checkbox is unchecked', function() { +test('enables the anonymous grading checkbox if the group category checkbox is unchecked', function () { const view = this.editView() disableCheckbox('assignment_anonymous_grading') view.handleGroupCategoryChange() @@ -683,7 +679,7 @@ test('enables the anonymous grading checkbox if the group category checkbox is u strictEqual(anonymousGradingCheckbox.disabled, false) }) -test('calls togglePeerReviewsAndGroupCategoryEnabled', function() { +test('calls togglePeerReviewsAndGroupCategoryEnabled', function () { const view = this.editView() sinon.spy(view, 'togglePeerReviewsAndGroupCategoryEnabled') view.handleGroupCategoryChange() @@ -863,7 +859,7 @@ QUnit.module('EditView: group category inClosedGradingPeriod', { } }) -test('lock down group category after students submit', function() { +test('lock down group category after students submit', function () { let view = this.editView({has_submitted_submissions: true}) ok(view.$('.group_category_locked_explanation').length) ok(view.$('#has_group_category').prop('disabled')) @@ -905,7 +901,7 @@ QUnit.module('EditView: enableCheckbox', { } }) -test('enables checkbox', function() { +test('enables checkbox', function () { const view = this.editView() sandbox .stub(view.$('#assignment_peer_reviews'), 'parent') @@ -916,7 +912,7 @@ test('enables checkbox', function() { notOk(view.$('#assignment_peer_reviews').prop('disabled')) }) -test('does nothing if assignment is in closed grading period', function() { +test('does nothing if assignment is in closed grading period', function () { const view = this.editView() sandbox.stub(view.assignment, 'inClosedGradingPeriod').returns(true) @@ -951,21 +947,21 @@ QUnit.module('EditView: setDefaultsIfNew', { } }) -test('returns values from localstorage', function() { +test('returns values from localstorage', function () { sandbox.stub(userSettings, 'contextGet').returns({submission_types: ['foo']}) const view = this.editView() view.setDefaultsIfNew() deepEqual(view.assignment.get('submission_types'), ['foo']) }) -test('returns string booleans as integers', function() { +test('returns string booleans as integers', function () { sandbox.stub(userSettings, 'contextGet').returns({peer_reviews: '1'}) const view = this.editView() view.setDefaultsIfNew() equal(view.assignment.get('peer_reviews'), 1) }) -test('doesnt overwrite existing assignment settings', function() { +test('doesnt overwrite existing assignment settings', function () { sandbox.stub(userSettings, 'contextGet').returns({assignment_group_id: 99}) const view = this.editView() view.assignment.set('assignment_group_id', 22) @@ -973,20 +969,20 @@ test('doesnt overwrite existing assignment settings', function() { equal(view.assignment.get('assignment_group_id'), 22) }) -test('sets assignment submission type to online if not already set', function() { +test('sets assignment submission type to online if not already set', function () { const view = this.editView() view.setDefaultsIfNew() deepEqual(view.assignment.get('submission_types'), ['online']) }) -test('doesnt overwrite assignment submission type', function() { +test('doesnt overwrite assignment submission type', function () { const view = this.editView() view.assignment.set('submission_types', ['external_tool']) view.setDefaultsIfNew() deepEqual(view.assignment.get('submission_types'), ['external_tool']) }) -test('will overwrite empty arrays', function() { +test('will overwrite empty arrays', function () { sandbox.stub(userSettings, 'contextGet').returns({submission_types: ['foo']}) const view = this.editView() view.assignment.set('submission_types', []) @@ -1021,7 +1017,7 @@ QUnit.module('EditView: setDefaultsIfNew: no localStorage', { } }) -test('submission_type is online if no cache', function() { +test('submission_type is online if no cache', function () { const view = this.editView() view.setDefaultsIfNew() deepEqual(view.assignment.get('submission_types'), ['online']) @@ -1053,7 +1049,7 @@ QUnit.module('EditView: cacheAssignmentSettings', { } }) -test('saves valid attributes to localstorage', function() { +test('saves valid attributes to localstorage', function () { const view = this.editView() sandbox.stub(view, 'getFormData').returns({points_possible: 34}) userSettings.contextSet('new_assignment_settings', {}) @@ -1061,7 +1057,7 @@ test('saves valid attributes to localstorage', function() { equal(34, userSettings.contextGet('new_assignment_settings').points_possible) }) -test('rejects invalid attributes when caching', function() { +test('rejects invalid attributes when caching', function () { const view = this.editView() sandbox.stub(view, 'getFormData').returns({invalid_attribute_example: 30}) userSettings.contextSet('new_assignment_settings', {}) @@ -1101,19 +1097,19 @@ QUnit.module('EditView: Conditional Release', { } }) -test('attaches conditional release editor', function() { +test('attaches conditional release editor', function () { const view = this.editView() equal(1, view.$conditionalReleaseTarget.children().size()) }) -test('calls update on first switch', function() { +test('calls update on first switch', function () { const view = this.editView() const stub = sandbox.stub(view.conditionalReleaseEditor, 'updateAssignment') view.updateConditionalRelease() ok(stub.calledOnce) }) -test('calls update when modified once', function() { +test('calls update when modified once', function () { const view = this.editView() const stub = sandbox.stub(view.conditionalReleaseEditor, 'updateAssignment') view.onChange() @@ -1121,7 +1117,7 @@ test('calls update when modified once', function() { ok(stub.calledOnce) }) -test('does not call update when not modified', function() { +test('does not call update when not modified', function () { const view = this.editView() const stub = sandbox.stub(view.conditionalReleaseEditor, 'updateAssignment') view.updateConditionalRelease() @@ -1130,7 +1126,7 @@ test('does not call update when not modified', function() { notOk(stub.called) }) -test('validates conditional release', function() { +test('validates conditional release', function () { const view = this.editView() ENV.ASSIGNMENT = view.assignment const stub = sandbox.stub(view.conditionalReleaseEditor, 'validateBeforeSave').returns('foo') @@ -1138,15 +1134,11 @@ test('validates conditional release', function() { ok(errors.conditional_release === 'foo') }) -test('calls save in conditional release', function(assert) { +test('calls save in conditional release', function (assert) { const resolved = assert.async() const view = this.editView() - const superPromise = $.Deferred() - .resolve() - .promise() - const crPromise = $.Deferred() - .resolve() - .promise() + const superPromise = $.Deferred().resolve().promise() + const crPromise = $.Deferred().resolve().promise() const mockSuper = sinon.mock(EditView.__super__) mockSuper.expects('saveFormData').returns(superPromise) const stub = sandbox.stub(view.conditionalReleaseEditor, 'save').returns(crPromise) @@ -1158,7 +1150,7 @@ test('calls save in conditional release', function(assert) { }) }) -test('focuses in conditional release editor if conditional save validation fails', function() { +test('focuses in conditional release editor if conditional save validation fails', function () { const view = this.editView() const focusOnError = sandbox.stub(view.conditionalReleaseEditor, 'focusOnError') view.showErrors({conditional_release: {type: 'foo'}}) @@ -1191,7 +1183,7 @@ QUnit.module('Editview: Intra-Group Peer Review toggle', { } }) -test('only appears for group assignments', function() { +test('only appears for group assignments', function () { sandbox.stub(userSettings, 'contextGet').returns({ peer_reviews: '1', group_category_id: 1, @@ -1202,7 +1194,7 @@ test('only appears for group assignments', function() { ok(view.$('#intra_group_peer_reviews').is(':visible')) }) -test('does not appear when reviews are being assigned manually', function() { +test('does not appear when reviews are being assigned manually', function () { sandbox.stub(userSettings, 'contextGet').returns({ peer_reviews: '1', group_category_id: 1 @@ -1212,7 +1204,7 @@ test('does not appear when reviews are being assigned manually', function() { notOk(view.$('#intra_group_peer_reviews').is(':visible')) }) -test('toggle does not appear when there is no group', function() { +test('toggle does not appear when there is no group', function () { sandbox.stub(userSettings, 'contextGet').returns({peer_reviews: '1'}) const view = this.editView() view.$el.appendTo($('#fixtures')) @@ -1248,12 +1240,12 @@ QUnit.module('EditView: Assignment Configuration Tools', { } }) -test('it attaches assignment configuration component', function() { +test('it attaches assignment configuration component', function () { const view = this.editView() equal(view.$similarityDetectionTools.children().size(), 1) }) -test('it is hidden if submission type is not online with a file upload', function() { +test('it is hidden if submission type is not online with a file upload', function () { const view = this.editView() view.$el.appendTo($('#fixtures')) equal(view.$('#similarity_detection_tools').css('display'), 'none') @@ -1288,7 +1280,7 @@ test('it is hidden if submission type is not online with a file upload', functio equal(view.$('#similarity_detection_tools').css('display'), 'block') }) -test('it is hidden if the plagiarism_detection_platform flag is disabled', function() { +test('it is hidden if the plagiarism_detection_platform flag is disabled', function () { ENV.PLAGIARISM_DETECTION_PLATFORM = false const view = this.editView() view.$('#assignment_submission_type').val('online') @@ -1316,7 +1308,7 @@ QUnit.module('EditView: Assignment External Tools', { } }) -test('it attaches assignment external tools component', function() { +test('it attaches assignment external tools component', function () { const view = this.editView() equal(view.$assignmentExternalTools.children().size(), 1) }) @@ -1347,7 +1339,7 @@ QUnit.module('EditView: Quizzes 2', { } }) -test('does not show the description textarea', function() { +test('does not show the description textarea', function () { equal(this.view.$description.length, 0) }) @@ -1355,7 +1347,7 @@ test('does not show the moderated grading checkbox', () => { equal(document.getElementById('assignment_moderated_grading'), null) }) -test('does not show the load in new tab checkbox', function() { +test('does not show the load in new tab checkbox', function () { equal(this.view.$externalToolsNewTab.length, 0) }) @@ -1917,3 +1909,51 @@ QUnit.module('EditView#uncheckAndHideGraderAnonymousToGraders', hooks => { strictEqual(isHidden, true) }) }) + +QUnit.module('EditView annotatable document submission', hooks => { + let server + let view + + hooks.beforeEach(() => { + fixtures.innerHTML = '' + fakeENV.setup({ + AVAILABLE_MODERATORS: [], + current_user_roles: ['teacher'], + HAS_GRADED_SUBMISSIONS: false, + LOCALE: 'en', + MODERATED_GRADING_ENABLED: true, + MODERATED_GRADING_MAX_GRADER_COUNT: 2, + VALID_DATE_RANGE: {}, + use_rce_enhancements: true, + COURSE_ID: 1, + ANNOTATED_DOCUMENT_SUBMISSIONS: true + }) + server = sinon.fakeServer.create() + sandbox.fetch.mock('path:/api/v1/courses/1/lti_apps/launch_definitions', 200) + RCELoader.RCE = null + return RCELoader.loadRCE() + }) + + hooks.afterEach(() => { + server.restore() + fakeENV.teardown() + tinymce.remove() // Make sure we clean stuff up + $('.ui-dialog').remove() + $('ul[id^=ui-id-]').remove() + $('.form-dialog').remove() + document.getElementById('fixtures').innerHTML = '' + }) + + test('does not render annotatable document option (flag missing)', function () { + ENV.ANNOTATED_DOCUMENT_SUBMISSIONS = false + view = editView() + equal(view.$('#assignment_annotated_document').length, 0) + }) + + test('renders annotatable document option (flag turned on)', function () { + ENV.ANNOTATED_DOCUMENT_SUBMISSIONS = true + view = editView() + const label = view.$('#assignment_annotated_document').parent() + ok(label.text().includes('Annotated Document')) + }) +})