Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
ec399645
Commit
ec399645
authored
Aug 03, 2017
by
Mushtaq Ali
Committed by
muzaffaryousaf
Oct 16, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Course video settings UI - EDUCATOR-1063
parent
9009669c
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
1116 additions
and
28 deletions
+1116
-28
cms/djangoapps/contentstore/views/tests/test_videos.py
+8
-5
cms/djangoapps/contentstore/views/videos.py
+7
-3
cms/static/cms/js/main.js
+2
-1
cms/static/cms/js/spec/main.js
+1
-0
cms/static/js/factories/videos_index.js
+6
-2
cms/static/js/spec/views/active_video_upload_list_spec.js
+24
-7
cms/static/js/spec/views/course_video_settings_spec.js
+263
-0
cms/static/js/views/active_video_upload_list.js
+33
-4
cms/static/js/views/course_video_settings.js
+542
-0
cms/static/sass/partials/cms/base/_variables.scss
+4
-0
cms/static/sass/views/_video-upload.scss
+166
-0
cms/templates/js/course-video-settings.underscore
+53
-0
cms/templates/videos_index.html
+7
-6
No files found.
cms/djangoapps/contentstore/views/tests/test_videos.py
View file @
ec399645
...
...
@@ -982,7 +982,9 @@ class TranscriptPreferencesTestCase(VideoUploadTestBase, CourseTestCase):
@override_settings
(
AWS_ACCESS_KEY_ID
=
'test_key_id'
,
AWS_SECRET_ACCESS_KEY
=
'test_secret'
)
@patch
(
'boto.s3.key.Key'
)
@patch
(
'boto.s3.connection.S3Connection'
)
def
test_transcript_preferences_metadata
(
self
,
transcript_preferences
,
mock_conn
,
mock_key
):
@patch
(
'contentstore.views.videos.get_transcript_preferences'
)
def
test_transcript_preferences_metadata
(
self
,
transcript_preferences
,
mock_transcript_preferences
,
mock_conn
,
mock_key
):
"""
Tests that transcript preference metadata is only set if it is transcript
preferences are present in request data.
...
...
@@ -990,8 +992,7 @@ class TranscriptPreferencesTestCase(VideoUploadTestBase, CourseTestCase):
file_name
=
'test-video.mp4'
request_data
=
{
'files'
:
[{
'file_name'
:
file_name
,
'content_type'
:
'video/mp4'
}]}
if
transcript_preferences
:
request_data
.
update
({
'transcript_preferences'
:
transcript_preferences
})
mock_transcript_preferences
.
return_value
=
transcript_preferences
bucket
=
Mock
()
mock_conn
.
return_value
=
Mock
(
get_bucket
=
Mock
(
return_value
=
bucket
))
...
...
@@ -1009,10 +1010,12 @@ class TranscriptPreferencesTestCase(VideoUploadTestBase, CourseTestCase):
# Ensure `transcript_preferences` was set up in Key correctly if sent through request.
if
transcript_preferences
:
mock_key_instance
.
set_metadata
.
assert_any_call
(
'transcript_preferences'
,
transcript_preferences
)
mock_key_instance
.
set_metadata
.
assert_any_call
(
'transcript_preferences'
,
json
.
dumps
(
transcript_preferences
)
)
else
:
with
self
.
assertRaises
(
AssertionError
):
mock_key_instance
.
set_metadata
.
assert_any_call
(
'transcript_preferences'
,
transcript_preferences
)
mock_key_instance
.
set_metadata
.
assert_any_call
(
'transcript_preferences'
,
json
.
dumps
(
transcript_preferences
)
)
@patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_VIDEO_UPLOAD_PIPELINE"
:
True
})
...
...
cms/djangoapps/contentstore/views/videos.py
View file @
ec399645
...
...
@@ -4,6 +4,7 @@ Views related to the video upload feature
from
contextlib
import
closing
import
csv
import
json
import
logging
from
datetime
import
datetime
,
timedelta
from
uuid
import
uuid4
...
...
@@ -340,6 +341,9 @@ def transcript_preferences_handler(request, course_key_string):
data
=
request
.
json
provider
=
data
.
get
(
'provider'
,
''
)
# TODO: if provider == '': delete course preferences
# i.e call delete api end point like delete_transcript_preferences(course_key_string)
error
,
preferences
=
validate_transcript_preferences
(
provider
=
provider
,
cielo24_fidelity
=
data
.
get
(
'cielo24_fidelity'
,
''
),
...
...
@@ -567,7 +571,7 @@ def videos_index_html(course):
}
context
.
update
({
'
third_party
_transcript_settings'
:
{
'
video
_transcript_settings'
:
{
'transcript_preferences_handler_url'
:
reverse_course_url
(
'transcript_preferences_handler'
,
unicode
(
course
.
id
)
...
...
@@ -658,9 +662,9 @@ def videos_post(course, request):
(
'course_key'
,
unicode
(
course
.
id
)),
]
transcript_preferences
=
data
.
get
(
'transcript_preferences'
,
None
)
transcript_preferences
=
get_transcript_preferences
(
unicode
(
course
.
id
)
)
if
transcript_preferences
is
not
None
:
metadata_list
.
append
((
'transcript_preferences'
,
transcript_preferences
))
metadata_list
.
append
((
'transcript_preferences'
,
json
.
dumps
(
transcript_preferences
)
))
for
metadata_name
,
value
in
metadata_list
:
key
.
set_metadata
(
metadata_name
,
value
)
...
...
cms/static/cms/js/main.js
View file @
ec399645
...
...
@@ -64,7 +64,8 @@
contentType
:
'application/json; charset=utf-8'
,
dataType
:
'json'
,
data
:
JSON
.
stringify
(
data
),
success
:
callback
success
:
callback
,
global
:
data
?
data
.
global
:
true
// Trigger global AJAX error handler or not
});
};
$
.
postJSON
=
function
(
url
,
data
,
callback
)
{
// eslint-disable-line no-param-reassign
...
...
cms/static/cms/js/spec/main.js
View file @
ec399645
...
...
@@ -258,6 +258,7 @@
'js/spec/views/active_video_upload_list_spec'
,
'js/spec/views/previous_video_upload_spec'
,
'js/spec/views/video_thumbnail_spec'
,
'js/spec/views/course_video_settings_spec'
,
'js/spec/views/previous_video_upload_list_spec'
,
'js/spec/views/assets_spec'
,
'js/spec/views/baseview_spec'
,
...
...
cms/static/js/factories/videos_index.js
View file @
ec399645
...
...
@@ -10,19 +10,23 @@ define([
encodingsDownloadUrl
,
defaultVideoImageURL
,
concurrentUploadLimit
,
upload
Button
,
courseVideoSettings
Button
,
previousUploads
,
videoSupportedFileFormats
,
videoUploadMaxFileSizeInGB
,
activeTranscriptPreferences
,
videoTranscriptSettings
,
videoImageSettings
)
{
var
activeView
=
new
ActiveVideoUploadListView
({
postUrl
:
videoHandlerUrl
,
concurrentUploadLimit
:
concurrentUploadLimit
,
uploadButton
:
upload
Button
,
courseVideoSettingsButton
:
courseVideoSettings
Button
,
videoSupportedFileFormats
:
videoSupportedFileFormats
,
videoUploadMaxFileSizeInGB
:
videoUploadMaxFileSizeInGB
,
videoImageSettings
:
videoImageSettings
,
activeTranscriptPreferences
:
activeTranscriptPreferences
,
videoTranscriptSettings
:
videoTranscriptSettings
,
onFileUploadDone
:
function
(
activeVideos
)
{
$
.
ajax
({
url
:
videoHandlerUrl
,
...
...
cms/static/js/spec/views/active_video_upload_list_spec.js
View file @
ec399645
...
...
@@ -32,20 +32,29 @@ define(
describe
(
'ActiveVideoUploadListView'
,
function
()
{
beforeEach
(
function
()
{
setFixtures
(
'<div id="page-prompt"></div><div id="page-notification"></div><div id="reader-feedback"></div>'
'<div id="page-prompt"></div>'
+
'<div id="page-notification"></div>'
+
'<div id="reader-feedback"></div>'
+
'<div class="video-transcript-settings-wrapper"></div>'
+
'<button class="button course-video-settings-button"></button>'
);
TemplateHelpers
.
installTemplate
(
'active-video-upload'
);
TemplateHelpers
.
installTemplate
(
'active-video-upload-list'
);
this
.
postUrl
=
POST_URL
;
this
.
uploadButton
=
$
(
'<button>
'
);
this
.
courseVideoSettingsButton
=
$
(
'.course-video-settings-button
'
);
this
.
videoSupportedFileFormats
=
[
'.mp4'
,
'.mov'
];
this
.
videoUploadMaxFileSizeInGB
=
5
;
this
.
view
=
new
ActiveVideoUploadListView
({
concurrentUploadLimit
:
concurrentUploadLimit
,
postUrl
:
this
.
postUrl
,
uploadButton
:
this
.
upload
Button
,
courseVideoSettingsButton
:
this
.
courseVideoSettings
Button
,
videoSupportedFileFormats
:
this
.
videoSupportedFileFormats
,
videoUploadMaxFileSizeInGB
:
this
.
videoUploadMaxFileSizeInGB
videoUploadMaxFileSizeInGB
:
this
.
videoUploadMaxFileSizeInGB
,
activeTranscriptPreferences
:
{},
videoTranscriptSettings
:
{
transcript_preferences_handler_url
:
''
,
transcription_plans
:
{}
}
});
this
.
view
.
render
();
jasmine
.
Ajax
.
install
();
...
...
@@ -55,6 +64,10 @@ define(
afterEach
(
function
()
{
$
(
window
).
off
(
'beforeunload'
);
jasmine
.
Ajax
.
uninstall
();
if
(
this
.
view
.
courseVideoSettingsView
)
{
this
.
view
.
courseVideoSettingsView
=
null
;
}
});
it
(
'renders correct text in file drag/drop area'
,
function
()
{
...
...
@@ -71,15 +84,19 @@ define(
});
});
it
(
'should trigger file selection when
either the upload button or
the drop zone is clicked'
,
function
()
{
it
(
'should trigger file selection when the drop zone is clicked'
,
function
()
{
var
clickSpy
=
jasmine
.
createSpy
();
clickSpy
.
and
.
callFake
(
function
(
event
)
{
event
.
preventDefault
();
});
this
.
view
.
$
(
'.js-file-input'
).
on
(
'click'
,
clickSpy
);
this
.
view
.
$
(
'.file-drop-area'
).
click
();
expect
(
clickSpy
).
toHaveBeenCalled
();
clickSpy
.
calls
.
reset
();
this
.
uploadButton
.
click
();
expect
(
clickSpy
).
toHaveBeenCalled
();
});
it
(
'shows course video settings pane when course video settings button is clicked'
,
function
()
{
expect
(
$
(
'.course-video-settings-container'
)).
not
.
toExist
();
this
.
courseVideoSettingsButton
.
click
();
expect
(
$
(
'.course-video-settings-container'
)).
toExist
();
});
it
(
'should not show a notification message if there are no active video uploads'
,
function
()
{
...
...
cms/static/js/spec/views/course_video_settings_spec.js
0 → 100644
View file @
ec399645
define
(
[
'jquery'
,
'underscore'
,
'backbone'
,
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers'
,
'js/views/course_video_settings'
,
'common/js/spec_helpers/template_helpers'
],
function
(
$
,
_
,
Backbone
,
AjaxHelpers
,
CourseVideoSettingsView
,
TemplateHelpers
)
{
'use strict'
;
describe
(
'CourseVideoSettingsView'
,
function
()
{
var
$courseVideoSettingsEl
,
courseVideoSettingsView
,
renderCourseVideoSettingsView
,
destroyCourseVideoSettingsView
,
verifyPreferanceErrorState
,
transcriptPreferencesUrl
=
'/transcript_preferences/course-v1:edX+DemoX+Demo_Course'
,
activeTranscriptPreferences
=
{
provider
:
'Cielo24'
,
cielo24_fidelity
:
'PROFESSIONAL'
,
cielo24_turnaround
:
'PRIORITY'
,
three_play_turnaround
:
''
,
preferred_languages
:
[
'fr'
,
'en'
],
modified
:
'2017-08-27T12:28:17.421260Z'
},
transcriptionPlans
=
{
'3PlayMedia'
:
{
languages
:
{
fr
:
'French'
,
en
:
'English'
},
turnaround
:
{
default
:
'4-Day/Default'
,
same_day_service
:
'Same Day'
,
rush_service
:
'24-hour/Rush'
,
extended_service
:
'10-Day/Extended'
,
expedited_service
:
'2-Day/Expedited'
},
display_name
:
'3PlayMedia'
},
Cielo24
:
{
turnaround
:
{
PRIORITY
:
'Priority, 24h'
,
STANDARD
:
'Standard, 48h'
},
fidelity
:
{
PROFESSIONAL
:
{
languages
:
{
ru
:
'Russian'
,
fr
:
'French'
,
en
:
'English'
},
display_name
:
'Professional, 99% Accuracy'
},
PREMIUM
:
{
languages
:
{
en
:
'English'
},
display_name
:
'Premium, 95% Accuracy'
},
MECHANICAL
:
{
languages
:
{
fr
:
'French'
,
en
:
'English'
,
nl
:
'Dutch'
},
display_name
:
'Mechanical, 75% Accuracy'
}
},
display_name
:
'Cielo24'
}
};
renderCourseVideoSettingsView
=
function
(
activeTranscriptPreferencesData
,
transcriptionPlansData
)
{
courseVideoSettingsView
=
new
CourseVideoSettingsView
({
activeTranscriptPreferences
:
activeTranscriptPreferencesData
||
null
,
videoTranscriptSettings
:
{
transcript_preferences_handler_url
:
transcriptPreferencesUrl
,
transcription_plans
:
transcriptionPlansData
||
null
}
});
$courseVideoSettingsEl
=
courseVideoSettingsView
.
render
().
$el
;
};
destroyCourseVideoSettingsView
=
function
()
{
if
(
courseVideoSettingsView
)
{
courseVideoSettingsView
.
closeCourseVideoSettings
();
courseVideoSettingsView
=
null
;
}
};
verifyPreferanceErrorState
=
function
(
$preferanceContainerEl
,
hasError
)
{
var
$errorIconHtml
=
hasError
?
'<span class="icon fa fa-info-circle" aria-hidden="true"></span>'
:
''
,
requiredText
=
hasError
?
'Required'
:
''
;
expect
(
$preferanceContainerEl
.
hasClass
(
'error'
)).
toEqual
(
hasError
);
expect
(
$preferanceContainerEl
.
find
(
'.error-icon'
).
html
()).
toEqual
(
$errorIconHtml
);
expect
(
$preferanceContainerEl
.
find
(
'.error-info'
).
html
()).
toEqual
(
requiredText
);
};
beforeEach
(
function
()
{
setFixtures
(
'<div class="video-transcript-settings-wrapper"></div>'
+
'<button class="button course-video-settings-button"></button>'
);
TemplateHelpers
.
installTemplate
(
'course-video-settings'
);
renderCourseVideoSettingsView
(
activeTranscriptPreferences
,
transcriptionPlans
);
});
afterEach
(
function
()
{
destroyCourseVideoSettingsView
();
});
it
(
'renders as expected'
,
function
()
{
expect
(
$courseVideoSettingsEl
.
find
(
'.course-video-settings-container'
)).
toExist
();
});
it
(
'closes course video settings pane when close button is clicked'
,
function
()
{
expect
(
$courseVideoSettingsEl
.
find
(
'.course-video-settings-container'
)).
toExist
();
$courseVideoSettingsEl
.
find
(
'.action-close-course-video-settings'
).
click
();
expect
(
$courseVideoSettingsEl
.
find
(
'.course-video-settings-container'
)).
not
.
toExist
();
});
it
(
'closes course video settings pane when clicked outside course video settings pane'
,
function
()
{
expect
(
$courseVideoSettingsEl
.
find
(
'.course-video-settings-container'
)).
toExist
();
$
(
'body'
).
click
();
expect
(
$courseVideoSettingsEl
.
find
(
'.course-video-settings-container'
)).
not
.
toExist
();
});
it
(
'does not close course video settings pane when clicked inside course video settings pane'
,
function
()
{
expect
(
$courseVideoSettingsEl
.
find
(
'.course-video-settings-container'
)).
toExist
();
$courseVideoSettingsEl
.
find
(
'.transcript-provider-group'
).
click
();
expect
(
$courseVideoSettingsEl
.
find
(
'.course-video-settings-container'
)).
toExist
();
});
it
(
'does not populate transcription plans if transcription plans are not provided'
,
function
()
{
// First detroy old referance to the view.
destroyCourseVideoSettingsView
();
// Create view with empty data.
renderCourseVideoSettingsView
(
null
,
null
);
expect
(
$courseVideoSettingsEl
.
find
(
'.transcript-provider-group'
).
html
()).
toEqual
(
''
);
expect
(
$courseVideoSettingsEl
.
find
(
'#transcript-turnaround'
).
html
()).
toEqual
(
''
);
expect
(
$courseVideoSettingsEl
.
find
(
'#transcript-fidelity'
).
html
()).
toEqual
(
''
);
expect
(
$courseVideoSettingsEl
.
find
(
'#transcript-language'
).
html
()).
toEqual
(
''
);
});
it
(
'populates transcription plans correctly'
,
function
()
{
// Only check transcript-provider radio buttons for now, because other preferances are based on either
// user selection or activeTranscriptPreferences.
expect
(
$courseVideoSettingsEl
.
find
(
'.transcript-provider-group'
).
html
()).
not
.
toEqual
(
''
);
});
it
(
'populates active preferances correctly'
,
function
()
{
// First check preferance are selected correctly in HTML.
expect
(
$courseVideoSettingsEl
.
find
(
'.transcript-provider-group input:checked'
).
val
()).
toEqual
(
activeTranscriptPreferences
.
provider
);
expect
(
$courseVideoSettingsEl
.
find
(
'#transcript-turnaround'
).
val
()).
toEqual
(
activeTranscriptPreferences
.
cielo24_turnaround
);
expect
(
$courseVideoSettingsEl
.
find
(
'#transcript-fidelity'
).
val
()).
toEqual
(
activeTranscriptPreferences
.
cielo24_fidelity
);
expect
(
$courseVideoSettingsEl
.
find
(
'.transcript-language-container'
).
length
).
toEqual
(
activeTranscriptPreferences
.
preferred_languages
.
length
);
// Now check values are assigned correctly.
expect
(
courseVideoSettingsView
.
selectedProvider
,
activeTranscriptPreferences
.
provider
);
expect
(
courseVideoSettingsView
.
selectedTurnaroundPlan
,
activeTranscriptPreferences
.
cielo24_turnaround
);
expect
(
courseVideoSettingsView
.
selectedFidelityPlan
,
activeTranscriptPreferences
.
cielo24_fidelity
);
expect
(
courseVideoSettingsView
.
selectedLanguages
,
activeTranscriptPreferences
.
preferred_languages
);
});
it
(
'saves transcript settings on update settings button click if preferances are selected'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
$courseVideoSettingsEl
.
find
(
'.action-update-course-video-settings'
).
click
();
AjaxHelpers
.
expectRequest
(
requests
,
'POST'
,
transcriptPreferencesUrl
,
JSON
.
stringify
({
provider
:
activeTranscriptPreferences
.
provider
,
cielo24_fidelity
:
activeTranscriptPreferences
.
cielo24_fidelity
,
cielo24_turnaround
:
activeTranscriptPreferences
.
cielo24_turnaround
,
three_play_turnaround
:
activeTranscriptPreferences
.
three_play_turnaround
,
preferred_languages
:
activeTranscriptPreferences
.
preferred_languages
,
global
:
false
})
);
// Send successful upload response.
AjaxHelpers
.
respondWithJson
(
requests
,
{
transcript_preferences
:
activeTranscriptPreferences
});
// Verify that success message is shown.
expect
(
$courseVideoSettingsEl
.
find
(
'.course-video-settings-message-wrapper.success'
).
html
()).
toEqual
(
'<div class="course-video-settings-message">'
+
'<span class="icon fa fa-check-circle" aria-hidden="true"></span>'
+
'<span>Settings updated</span>'
+
'</div>'
);
});
it
(
'shows error message if server sends error'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
$courseVideoSettingsEl
.
find
(
'.action-update-course-video-settings'
).
click
();
AjaxHelpers
.
expectRequest
(
requests
,
'POST'
,
transcriptPreferencesUrl
,
JSON
.
stringify
({
provider
:
activeTranscriptPreferences
.
provider
,
cielo24_fidelity
:
activeTranscriptPreferences
.
cielo24_fidelity
,
cielo24_turnaround
:
activeTranscriptPreferences
.
cielo24_turnaround
,
three_play_turnaround
:
activeTranscriptPreferences
.
three_play_turnaround
,
preferred_languages
:
activeTranscriptPreferences
.
preferred_languages
,
global
:
false
})
);
// Send error response.
AjaxHelpers
.
respondWithError
(
requests
,
400
,
{
error
:
'Error message'
});
// Verify that error message is shown.
expect
(
$courseVideoSettingsEl
.
find
(
'.course-video-settings-message-wrapper.error'
).
html
()).
toEqual
(
'<div class="course-video-settings-message">'
+
'<span class="icon fa fa-info-circle" aria-hidden="true"></span>'
+
'<span>Error message</span>'
+
'</div>'
);
});
it
(
'implies preferences are required if not selected when saving preferances'
,
function
()
{
// Reset so that no preferance is selected.
courseVideoSettingsView
.
selectedTurnaroundPlan
=
''
;
courseVideoSettingsView
.
selectedFidelityPlan
=
''
;
courseVideoSettingsView
.
selectedLanguages
=
[];
$courseVideoSettingsEl
.
find
(
'.action-update-course-video-settings'
).
click
();
verifyPreferanceErrorState
(
$courseVideoSettingsEl
.
find
(
'.transcript-turnaround-wrapper'
),
true
);
verifyPreferanceErrorState
(
$courseVideoSettingsEl
.
find
(
'.transcript-fidelity-wrapper'
),
true
);
verifyPreferanceErrorState
(
$courseVideoSettingsEl
.
find
(
'.transcript-languages-wrapper'
),
true
);
});
it
(
'removes error state on preferances if selected'
,
function
()
{
// Provide values for preferances.
$courseVideoSettingsEl
.
find
(
'#transcript-turnaround'
).
val
(
'test-value'
);
$courseVideoSettingsEl
.
find
(
'#transcript-fidelity'
).
val
(
'test-value'
);
$courseVideoSettingsEl
.
find
(
'#transcript-language-menu'
).
val
(
'test-value'
);
verifyPreferanceErrorState
(
$courseVideoSettingsEl
.
find
(
'.transcript-turnaround-wrapper'
),
false
);
verifyPreferanceErrorState
(
$courseVideoSettingsEl
.
find
(
'.transcript-fidelity-wrapper'
),
false
);
verifyPreferanceErrorState
(
$courseVideoSettingsEl
.
find
(
'.transcript-languages-wrapper'
),
false
);
});
// TODO: Add more tests like clicking on add language, remove and their scenarios and some other tests
// like N/A selected, specific provider selected tests, specific preferance selected tests etc.
});
}
);
cms/static/js/views/active_video_upload_list.js
View file @
ec399645
...
...
@@ -5,12 +5,13 @@ define([
'js/models/active_video_upload'
,
'js/views/baseview'
,
'js/views/active_video_upload'
,
'js/views/course_video_settings'
,
'edx-ui-toolkit/js/utils/html-utils'
,
'edx-ui-toolkit/js/utils/string-utils'
,
'text!templates/active-video-upload-list.underscore'
,
'jquery.fileupload'
],
function
(
$
,
_
,
Backbone
,
ActiveVideoUpload
,
BaseView
,
ActiveVideoUploadView
,
function
(
$
,
_
,
Backbone
,
ActiveVideoUpload
,
BaseView
,
ActiveVideoUploadView
,
CourseVideoSettingsView
,
HtmlUtils
,
StringUtils
,
activeVideoUploadListTemplate
)
{
'use strict'
;
var
ActiveVideoUploadListView
,
...
...
@@ -40,11 +41,13 @@ define([
this
.
listenTo
(
this
.
collection
,
'add'
,
this
.
addUpload
);
this
.
concurrentUploadLimit
=
options
.
concurrentUploadLimit
||
0
;
this
.
postUrl
=
options
.
postUrl
;
this
.
activeTranscriptPreferences
=
options
.
activeTranscriptPreferences
;
this
.
videoTranscriptSettings
=
options
.
videoTranscriptSettings
;
this
.
videoSupportedFileFormats
=
options
.
videoSupportedFileFormats
;
this
.
videoUploadMaxFileSizeInGB
=
options
.
videoUploadMaxFileSizeInGB
;
this
.
onFileUploadDone
=
options
.
onFileUploadDone
;
if
(
options
.
upload
Button
)
{
options
.
uploadButton
.
click
(
this
.
chooseFile
.
bind
(
this
));
if
(
options
.
courseVideoSettings
Button
)
{
options
.
courseVideoSettingsButton
.
click
(
this
.
showCourseVideoSettingsView
.
bind
(
this
));
}
this
.
maxSizeText
=
StringUtils
.
interpolate
(
...
...
@@ -59,6 +62,33 @@ define([
supportedVideoTypes
:
this
.
videoSupportedFileFormats
.
join
(
', '
)
}
);
this
.
listenTo
(
Backbone
,
'coursevideosettings:syncActiveTranscriptPreferences'
,
this
.
syncActiveTranscriptPreferences
);
this
.
listenTo
(
Backbone
,
'coursevideosettings:destroyCourseVideoSettingsView'
,
this
.
destroyCourseVideoSettingsView
);
},
syncActiveTranscriptPreferences
:
function
(
activeTranscriptPreferences
)
{
this
.
activeTranscriptPreferences
=
activeTranscriptPreferences
;
},
showCourseVideoSettingsView
:
function
(
event
)
{
this
.
courseVideoSettingsView
=
new
CourseVideoSettingsView
({
activeTranscriptPreferences
:
this
.
activeTranscriptPreferences
,
videoTranscriptSettings
:
this
.
videoTranscriptSettings
});
this
.
courseVideoSettingsView
.
render
();
event
.
stopPropagation
();
},
destroyCourseVideoSettingsView
:
function
()
{
this
.
courseVideoSettingsView
=
null
;
},
render
:
function
()
{
...
...
@@ -98,7 +128,6 @@ define([
$
(
window
).
on
(
'drop'
,
preventDefault
);
$
(
window
).
on
(
'beforeunload'
,
this
.
onBeforeUnload
.
bind
(
this
));
$
(
window
).
on
(
'unload'
,
this
.
onUnload
.
bind
(
this
));
return
this
;
},
...
...
cms/static/js/views/course_video_settings.js
0 → 100644
View file @
ec399645
/**
* CourseVideoSettingsView shows a sidebar containing course wide video settings which we show on Video Uploads page.
*/
define
([
'jquery'
,
'backbone'
,
'underscore'
,
'gettext'
,
'moment'
,
'edx-ui-toolkit/js/utils/html-utils'
,
'edx-ui-toolkit/js/utils/string-utils'
,
'text!templates/course-video-settings.underscore'
],
function
(
$
,
Backbone
,
_
,
gettext
,
moment
,
HtmlUtils
,
StringUtils
,
TranscriptSettingsTemplate
)
{
'use strict'
;
var
CourseVideoSettingsView
,
CIELO24
=
'Cielo24'
,
THREE_PLAY_MEDIA
=
'3PlayMedia'
;
CourseVideoSettingsView
=
Backbone
.
View
.
extend
({
el
:
'div.video-transcript-settings-wrapper'
,
events
:
{
'change .transcript-provider-group input'
:
'providerSelected'
,
'change #transcript-turnaround'
:
'turnaroundSelected'
,
'change #transcript-fidelity'
:
'fidelitySelected'
,
'click .action-add-language'
:
'languageSelected'
,
'click .action-remove-language'
:
'languageRemoved'
,
'click .action-update-course-video-settings'
:
'updateCourseVideoSettings'
,
'click .action-close-course-video-settings'
:
'closeCourseVideoSettings'
},
initialize
:
function
(
options
)
{
var
videoTranscriptSettings
=
options
.
videoTranscriptSettings
;
this
.
activeTranscriptionPlan
=
options
.
activeTranscriptPreferences
;
this
.
availableTranscriptionPlans
=
videoTranscriptSettings
.
transcription_plans
;
this
.
transcriptHandlerUrl
=
videoTranscriptSettings
.
transcript_preferences_handler_url
;
this
.
template
=
HtmlUtils
.
template
(
TranscriptSettingsTemplate
);
this
.
setActiveTranscriptPlanData
();
this
.
selectedLanguages
=
[];
},
registerCloseClickHandler
:
function
()
{
var
self
=
this
;
// Preventing any parent handlers from being notified of the event. This is to stop from firing the document
// level click handler to execute on course video settings pane click.
self
.
$el
.
click
(
function
(
event
)
{
event
.
stopPropagation
();
});
// Click anywhere outside the course video settings pane would close the pane.
$
(
document
).
click
(
function
(
event
)
{
// if the target of the click isn't the container nor a descendant of the contain
if
(
!
self
.
$el
.
is
(
event
.
target
)
&&
self
.
$el
.
has
(
event
.
target
).
length
===
0
)
{
self
.
closeCourseVideoSettings
();
}
});
},
resetPlanData
:
function
()
{
this
.
selectedProvider
=
''
;
this
.
selectedTurnaroundPlan
=
''
;
this
.
selectedFidelityPlan
=
''
;
this
.
availableLanguages
=
[];
this
.
activeLanguages
=
[];
this
.
selectedLanguages
=
[];
},
setActiveTranscriptPlanData
:
function
()
{
if
(
this
.
activeTranscriptionPlan
)
{
this
.
selectedProvider
=
this
.
activeTranscriptionPlan
.
provider
;
this
.
selectedFidelityPlan
=
this
.
activeTranscriptionPlan
.
cielo24_fidelity
;
this
.
selectedTurnaroundPlan
=
this
.
selectedProvider
===
CIELO24
?
this
.
activeTranscriptionPlan
.
cielo24_turnaround
:
this
.
activeTranscriptionPlan
.
three_play_turnaround
;
this
.
activeLanguages
=
this
.
activeTranscriptionPlan
.
preferred_languages
;
}
else
{
this
.
resetPlanData
();
}
},
getTurnaroundPlan
:
function
()
{
var
turnaroundPlan
=
null
;
if
(
this
.
selectedProvider
)
{
turnaroundPlan
=
this
.
availableTranscriptionPlans
[
this
.
selectedProvider
].
turnaround
;
}
return
turnaroundPlan
;
},
getFidelityPlan
:
function
()
{
var
fidelityPlan
=
null
;
if
(
this
.
selectedProvider
===
CIELO24
)
{
fidelityPlan
=
this
.
availableTranscriptionPlans
[
this
.
selectedProvider
].
fidelity
;
}
return
fidelityPlan
;
},
getPlanLanguages
:
function
()
{
var
selectedPlan
=
this
.
availableTranscriptionPlans
[
this
.
selectedProvider
];
if
(
this
.
selectedProvider
===
CIELO24
)
{
return
selectedPlan
.
fidelity
[
this
.
selectedFidelityPlan
].
languages
;
}
return
selectedPlan
.
languages
;
},
fidelitySelected
:
function
(
event
)
{
var
$fidelityContainer
=
this
.
$el
.
find
(
'.transcript-fidelity-wrapper'
);
this
.
selectedFidelityPlan
=
event
.
target
.
value
;
// Remove any error if present already.
this
.
clearPreferenceErrorState
(
$fidelityContainer
);
// Clear active and selected languages.
this
.
selectedLanguages
=
this
.
activeLanguages
=
[];
this
.
renderLanguages
();
},
turnaroundSelected
:
function
(
event
)
{
var
$turnaroundContainer
=
this
.
$el
.
find
(
'.transcript-turnaround-wrapper'
);
this
.
selectedTurnaroundPlan
=
event
.
target
.
value
;
// Remove any error if present already.
this
.
clearPreferenceErrorState
(
$turnaroundContainer
);
},
providerSelected
:
function
(
event
)
{
this
.
resetPlanData
();
this
.
selectedProvider
=
event
.
target
.
value
;
this
.
renderPreferences
();
},
languageSelected
:
function
(
event
)
{
var
$parentEl
=
$
(
event
.
target
.
parentElement
).
parent
(),
$languagesEl
=
this
.
$el
.
find
(
'.transcript-languages-wrapper'
),
selectedLanguage
=
$parentEl
.
find
(
'select'
).
val
();
// Remove any error if present already.
this
.
clearPreferenceErrorState
(
$languagesEl
);
// Only add if not in the list already.
if
(
selectedLanguage
&&
_
.
indexOf
(
this
.
selectedLanguages
,
selectedLanguage
)
===
-
1
)
{
this
.
selectedLanguages
.
push
(
selectedLanguage
);
this
.
addLanguage
(
selectedLanguage
);
// Populate language menu with latest data.
this
.
populateLanguageMenu
();
}
else
{
this
.
addErrorState
(
$languagesEl
);
}
},
languageRemoved
:
function
(
event
)
{
var
selectedLanguage
=
$
(
event
.
target
).
data
(
'language-code'
);
$
(
event
.
target
.
parentElement
).
parent
().
remove
();
// Remove language from selected languages.
this
.
selectedLanguages
=
_
.
without
(
this
.
selectedLanguages
,
selectedLanguage
);
// Populate menu again to reflect latest changes.
this
.
populateLanguageMenu
();
},
renderProviders
:
function
()
{
var
self
=
this
,
providerPlan
=
self
.
availableTranscriptionPlans
,
$providerEl
=
self
.
$el
.
find
(
'.transcript-provider-group'
);
if
(
providerPlan
)
{
HtmlUtils
.
setHtml
(
$providerEl
,
HtmlUtils
.
interpolateHtml
(
HtmlUtils
.
HTML
(
'<input type="radio" id="transcript-provider-none" name="transcript-provider" value="" {checked}/><label for="transcript-provider-none">{text}</label>'
),
// eslint-disable-line max-len
{
text
:
gettext
(
'N/A'
),
checked
:
self
.
selectedProvider
===
''
?
'checked'
:
''
}
)
);
_
.
each
(
providerPlan
,
function
(
providerObject
,
key
)
{
var
checked
=
self
.
selectedProvider
===
key
?
'checked'
:
''
;
HtmlUtils
.
append
(
$providerEl
,
HtmlUtils
.
interpolateHtml
(
HtmlUtils
.
HTML
(
'<input type="radio" id="transcript-provider-{value}" name="transcript-provider" value="{value}" {checked}/><label for="transcript-provider-{value}">{text}'
),
// eslint-disable-line max-len
{
text
:
providerObject
.
display_name
,
value
:
key
,
checked
:
checked
}
)
);
});
}
},
renderTurnaround
:
function
()
{
var
self
=
this
,
turnaroundPlan
=
self
.
getTurnaroundPlan
(),
$turnaroundContainer
=
self
.
$el
.
find
(
'.transcript-turnaround-wrapper'
),
$turnaround
=
self
.
$el
.
find
(
'#transcript-turnaround'
);
// Clear error state if present any.
this
.
clearPreferenceErrorState
(
$turnaroundContainer
);
if
(
turnaroundPlan
)
{
HtmlUtils
.
setHtml
(
$turnaround
,
HtmlUtils
.
HTML
(
new
Option
(
gettext
(
'Select turnaround'
),
''
))
);
_
.
each
(
turnaroundPlan
,
function
(
value
,
key
)
{
var
option
=
new
Option
(
value
,
key
);
if
(
self
.
selectedTurnaroundPlan
===
key
)
{
option
.
selected
=
true
;
}
HtmlUtils
.
append
(
$turnaround
,
HtmlUtils
.
HTML
(
option
));
});
$turnaroundContainer
.
show
();
}
else
{
$turnaroundContainer
.
hide
();
}
},
renderFidelity
:
function
()
{
var
self
=
this
,
fidelityPlan
=
self
.
getFidelityPlan
(),
$fidelityContainer
=
self
.
$el
.
find
(
'.transcript-fidelity-wrapper'
),
$fidelity
=
self
.
$el
.
find
(
'#transcript-fidelity'
);
// Clear error state if present any.
this
.
clearPreferenceErrorState
(
$fidelityContainer
);
// Fidelity dropdown
if
(
fidelityPlan
)
{
HtmlUtils
.
setHtml
(
$fidelity
,
HtmlUtils
.
HTML
(
new
Option
(
gettext
(
'Select fidelity'
),
''
))
);
_
.
each
(
fidelityPlan
,
function
(
fidelityObject
,
key
)
{
var
option
=
new
Option
(
fidelityObject
.
display_name
,
key
);
if
(
self
.
selectedFidelityPlan
===
key
)
{
option
.
selected
=
true
;
}
HtmlUtils
.
append
(
$fidelity
,
HtmlUtils
.
HTML
(
option
));
});
$fidelityContainer
.
show
();
}
else
{
$fidelityContainer
.
hide
();
}
},
renderLanguages
:
function
()
{
var
self
=
this
,
$languagesPreferenceContainer
=
self
.
$el
.
find
(
'.transcript-languages-wrapper'
),
$languagesContainer
=
self
.
$el
.
find
(
'.languages-container'
);
// Clear error state if present any.
this
.
clearPreferenceErrorState
(
$languagesPreferenceContainer
);
$languagesContainer
.
empty
();
// Show language container if provider is 3PlayMedia, else if fidelity is selected.
if
(
self
.
selectedProvider
===
THREE_PLAY_MEDIA
||
self
.
selectedFidelityPlan
)
{
self
.
availableLanguages
=
self
.
getPlanLanguages
();
_
.
each
(
self
.
activeLanguages
,
function
(
activeLanguage
)
{
// Only add if not in the list already.
if
(
_
.
indexOf
(
self
.
selectedLanguages
,
activeLanguage
)
===
-
1
)
{
self
.
selectedLanguages
.
push
(
activeLanguage
);
self
.
addLanguage
(
activeLanguage
);
}
});
$languagesPreferenceContainer
.
show
();
self
.
populateLanguageMenu
();
}
else
{
self
.
availableLanguages
=
{};
$languagesPreferenceContainer
.
hide
();
}
},
populateLanguageMenu
:
function
()
{
var
availableLanguages
,
$languageMenuEl
=
this
.
$el
.
find
(
'.transcript-language-menu'
),
$languageMenuContainerEl
=
this
.
$el
.
find
(
'.transcript-language-menu-container'
),
selectOptionEl
=
new
Option
(
gettext
(
'Select language'
),
''
);
// Omit out selected languages from selecting again.
availableLanguages
=
_
.
omit
(
this
.
availableLanguages
,
this
.
selectedLanguages
);
// If no available language is left, then don't even show add language box.
if
(
_
.
keys
(
availableLanguages
).
length
)
{
$languageMenuContainerEl
.
show
();
// We need to set id due to a11y aria-labelledby
selectOptionEl
.
id
=
'transcript-language-none'
;
HtmlUtils
.
setHtml
(
$languageMenuEl
,
HtmlUtils
.
HTML
(
selectOptionEl
)
);
_
.
each
(
availableLanguages
,
function
(
value
,
key
)
{
HtmlUtils
.
append
(
$languageMenuEl
,
HtmlUtils
.
HTML
(
new
Option
(
value
,
key
))
);
});
}
else
{
$languageMenuContainerEl
.
hide
();
}
},
renderPreferences
:
function
()
{
this
.
renderProviders
();
this
.
renderTurnaround
();
this
.
renderFidelity
();
this
.
renderLanguages
();
},
addLanguage
:
function
(
language
)
{
var
$languagesContainer
=
this
.
$el
.
find
(
'.languages-container'
);
HtmlUtils
.
append
(
$languagesContainer
,
HtmlUtils
.
joinHtml
(
HtmlUtils
.
HTML
(
'<div class="transcript-language-container">'
),
HtmlUtils
.
interpolateHtml
(
HtmlUtils
.
HTML
(
'<span>{languageDisplayName}</span>'
),
{
languageDisplayName
:
this
.
availableLanguages
[
language
]
}
),
HtmlUtils
.
interpolateHtml
(
HtmlUtils
.
HTML
(
'<div class="remove-language-action"><button class="button-link action-remove-language" data-language-code="{languageCode}">{text}<span class="sr">{srText}</span></button></div>'
),
// eslint-disable-line max-len
{
languageCode
:
language
,
text
:
gettext
(
'Remove'
),
srText
:
gettext
(
'Press Remove to remove language'
)
}
),
HtmlUtils
.
HTML
(
'</div>'
)
)
);
},
clearResponseStatus
:
function
()
{
// Remove parent level state.
var
$messageWrapperEl
=
this
.
$el
.
find
(
'.course-video-settings-message-wrapper'
);
$messageWrapperEl
.
empty
();
$messageWrapperEl
.
removeClass
(
'error'
);
$messageWrapperEl
.
removeClass
(
'success'
);
},
clearPreferenceErrorState
:
function
(
$PreferenceContainer
)
{
$PreferenceContainer
.
removeClass
(
'error'
);
$PreferenceContainer
.
find
(
'.error-icon'
).
empty
();
$PreferenceContainer
.
find
(
'.error-info'
).
empty
();
// Also clear response status if present already
this
.
clearResponseStatus
();
},
addErrorState
:
function
(
$PreferenceContainer
)
{
var
requiredText
=
gettext
(
'Required'
),
infoIconHtml
=
HtmlUtils
.
HTML
(
'<span class="icon fa fa-info-circle" aria-hidden="true"></span>'
);
$PreferenceContainer
.
addClass
(
'error'
);
HtmlUtils
.
setHtml
(
$PreferenceContainer
.
find
(
'.error-icon'
),
infoIconHtml
);
HtmlUtils
.
setHtml
(
$PreferenceContainer
.
find
(
'.error-info'
),
requiredText
);
},
validateCourseVideoSettings
:
function
()
{
var
isValid
=
true
,
$turnaroundEl
=
this
.
$el
.
find
(
'.transcript-turnaround-wrapper'
),
$fidelityEl
=
this
.
$el
.
find
(
'.transcript-fidelity-wrapper'
),
$languagesEl
=
this
.
$el
.
find
(
'.transcript-languages-wrapper'
);
// Explicit None selected case.
if
(
this
.
selectedProvider
===
''
)
{
return
true
;
}
if
(
!
this
.
selectedTurnaroundPlan
)
{
isValid
=
false
;
this
.
addErrorState
(
$turnaroundEl
);
}
else
{
this
.
clearPreferenceErrorState
(
$turnaroundEl
);
}
if
(
this
.
selectedProvider
===
CIELO24
&&
!
this
.
selectedFidelityPlan
)
{
isValid
=
false
;
this
.
addErrorState
(
$fidelityEl
);
}
else
{
this
.
clearPreferenceErrorState
(
$fidelityEl
);
}
if
(
this
.
selectedLanguages
.
length
===
0
)
{
isValid
=
false
;
this
.
addErrorState
(
$languagesEl
);
}
else
{
this
.
clearPreferenceErrorState
(
$languagesEl
);
}
return
isValid
;
},
saveTranscriptPreferences
:
function
()
{
var
self
=
this
,
$messageWrapperEl
=
self
.
$el
.
find
(
'.course-video-settings-message-wrapper'
);
// First clear response status if present already
this
.
clearResponseStatus
();
$
.
postJSON
(
this
.
transcriptHandlerUrl
,
{
provider
:
self
.
selectedProvider
,
cielo24_fidelity
:
self
.
selectedFidelityPlan
,
cielo24_turnaround
:
self
.
selectedProvider
===
CIELO24
?
self
.
selectedTurnaroundPlan
:
''
,
three_play_turnaround
:
self
.
selectedProvider
===
THREE_PLAY_MEDIA
?
self
.
selectedTurnaroundPlan
:
''
,
preferred_languages
:
self
.
selectedLanguages
,
global
:
false
// Do not trigger global AJAX error handler
},
function
(
data
)
{
if
(
data
.
transcript_preferences
)
{
$messageWrapperEl
.
removeClass
(
'error'
);
$messageWrapperEl
.
addClass
(
'success'
);
HtmlUtils
.
setHtml
(
$messageWrapperEl
,
HtmlUtils
.
interpolateHtml
(
HtmlUtils
.
HTML
(
'<div class="course-video-settings-message"><span class="icon fa fa-check-circle" aria-hidden="true"></span><span>{text}</span></div>'
),
// eslint-disable-line max-len
{
text
:
gettext
(
'Settings updated'
)
}
)
);
self
.
activeTranscriptionPlan
=
data
.
transcript_preferences
;
// Sync ActiveUploadListView with latest active plan.
Backbone
.
trigger
(
'coursevideosettings:syncActiveTranscriptPreferences'
,
self
.
activeTranscriptionPlan
);
}
}).
fail
(
function
(
jqXHR
)
{
var
errorMessage
;
if
(
jqXHR
.
responseText
)
{
// Enclose inside try-catch so that if we get erroneous data, we could still show some error to user
try
{
errorMessage
=
$
.
parseJSON
(
jqXHR
.
responseText
).
error
;
}
catch
(
e
)
{}
// eslint-disable-line no-empty
$messageWrapperEl
.
removeClass
(
'success'
);
$messageWrapperEl
.
addClass
(
'error'
);
HtmlUtils
.
setHtml
(
$messageWrapperEl
,
HtmlUtils
.
interpolateHtml
(
HtmlUtils
.
HTML
(
'<div class="course-video-settings-message"><span class="icon fa fa-info-circle" aria-hidden="true"></span><span>{text}</span></div>'
),
// eslint-disable-line max-len
{
text
:
errorMessage
||
gettext
(
'Error saving data'
)
}
)
);
}
});
},
updateCourseVideoSettings
:
function
()
{
var
$messageWrapperEl
=
this
.
$el
.
find
(
'.course-video-settings-message-wrapper'
);
if
(
this
.
validateCourseVideoSettings
())
{
this
.
saveTranscriptPreferences
();
}
else
{
$messageWrapperEl
.
empty
();
}
},
render
:
function
()
{
var
dateModified
=
this
.
activeTranscriptionPlan
?
moment
.
utc
(
this
.
activeTranscriptionPlan
.
modified
).
format
(
'll'
)
:
''
;
HtmlUtils
.
setHtml
(
this
.
$el
,
this
.
template
({
dateModified
:
dateModified
})
);
this
.
renderPreferences
();
this
.
registerCloseClickHandler
();
this
.
setFixedCourseVideoSettingsPane
();
return
this
;
},
setFixedCourseVideoSettingsPane
:
function
()
{
var
windowWidth
=
$
(
window
).
width
(),
windowHeight
=
$
(
window
).
height
(),
$courseVideoSettingsButton
=
$
(
'.course-video-settings-button'
),
$courseVideoSettingsContainer
=
this
.
$el
.
find
(
'.course-video-settings-container'
),
initialPositionTop
=
$courseVideoSettingsContainer
.
offset
().
top
,
courseVideoSettingsButtonLeft
=
$courseVideoSettingsButton
.
offset
().
left
,
fixedOffsetRight
=
windowWidth
-
courseVideoSettingsButtonLeft
-
$courseVideoSettingsButton
.
width
()
-
25
;
// set windows total height
$courseVideoSettingsContainer
.
css
(
'height'
,
windowHeight
);
$courseVideoSettingsContainer
.
css
(
'right'
,
20
);
// Make sticky when scroll reaches top.
$
(
window
).
scroll
(
function
()
{
// Remove transition when we start scrolling.
// Why we do this? The settings pane come back and forth when it is switched between
// position:fixed and position:absolute, it's right and top position are then being changed wrt to their
// position layout.
$courseVideoSettingsContainer
.
css
(
'transition'
,
'none'
);
if
(
$
(
window
).
scrollTop
()
>=
initialPositionTop
)
{
$courseVideoSettingsContainer
.
addClass
(
'fixed-container'
);
// TODO: Removes these js calculations and try to do through CSS way.
$courseVideoSettingsContainer
.
css
(
'right'
,
fixedOffsetRight
);
}
else
{
$courseVideoSettingsContainer
.
removeClass
(
'fixed-container'
);
$courseVideoSettingsContainer
.
css
(
'right'
,
20
);
}
});
},
closeCourseVideoSettings
:
function
()
{
// Trigger destroy transcript event.
Backbone
.
trigger
(
'coursevideosettings:destroyCourseVideoSettingsView'
);
// Unbind any events associated
this
.
undelegateEvents
();
this
.
stopListening
();
// Empty this.$el content from DOM
this
.
$el
.
empty
();
// Reset everything.
this
.
resetPlanData
();
}
});
return
CourseVideoSettingsView
;
});
cms/static/sass/partials/cms/base/_variables.scss
View file @
ec399645
...
...
@@ -83,6 +83,8 @@ $gray-d1: shade($gray, 20%) !default;
$gray-d2
:
shade
(
$gray
,
40%
)
!
default
;
$gray-d3
:
shade
(
$gray
,
60%
)
!
default
;
$gray-d4
:
shade
(
$gray
,
80%
)
!
default
;
$gray-u1
:
#ECF0F1
;
// These define button styles similar to LMS
// The goal here is consistency (until we can overhaul all of this...)
...
...
@@ -302,3 +304,5 @@ $state-warning-border: darken($state-warning-bg, 5%) !default;
$state-danger-text
:
$black
!
default
;
$state-danger-bg
:
#f2dede
!
default
;
$state-danger-border
:
darken
(
$state-danger-bg
,
5%
)
!
default
;
$text-dark-black-blue
:
#2C3E50
;
cms/static/sass/views/_video-upload.scss
View file @
ec399645
...
...
@@ -12,6 +12,172 @@
}
}
.fixed-container
{
position
:
fixed
!
important
;
top
:
0
!
important
;
}
.course-video-settings-container
{
position
:
absolute
;
overflow
:
scroll
;
top
:
0
;
right
:
-100%
;
z-index
:
1000
;
width
:
352px
;
transition
:
all
0
.3s
ease
;
background-color
:
$white
;
-webkit-box-shadow
:
-3px
0px
3px
0px
rgba
(
153
,
153
,
153
,
0
.3
);
-moz-box-shadow
:
-3px
0px
3px
0px
rgba
(
153
,
153
,
153
,
0
.3
);
box-shadow
:
-3px
0px
3px
0px
rgba
(
153
,
153
,
153
,
0
.3
);
.button-link
{
background
:none
;
border
:none
;
padding
:
0
;
color
:
$ui-link-color
;
cursor
:pointer
}
.action-close-wrapper
{
.action-close-course-video-settings
{
width
:
100%
;
padding
:
(
$baseline
/
2
)
(
$baseline
*
0
.8
);
background-color
:
$gray-u1
;
border
:
transparent
;
height
:
(
$baseline
*
2
.4
);
color
:
$text-dark-black-blue
;
@include
font-size
(
16
);
@include
text-align
(
left
);
}
}
.course-video-settings-wrapper
{
margin-top
:
(
$baseline
*
1
.60
);
padding
:
(
$baseline
)
(
$baseline
*
0
.8
);
.course-video-settings-title
{
color
:
$black-t4
;
margin
:
(
$baseline
*
1
.6
)
0
(
$baseline
*
0
.8
)
0
;
font-weight
:
font-weight
(
semi-bold
);
@include
font-size
(
24
);
}
.course-video-settings-message
{
padding
:
(
$baseline
/
2
);
margin-bottom
:
(
$baseline
*
0
.8
);
max-height
:
(
$baseline
*
2
.4
);
color
:
$black
;
@include
font-size
(
16
);
.icon
{
@include
margin-right
(
$baseline
/
4
);
}
}
.course-video-settings-message-wrapper.success
.course-video-settings-message
{
background-color
:
$state-success-bg
;
border
:
solid
1px
$state-success-border
;
}
.course-video-settings-message-wrapper.error
.course-video-settings-message
{
background-color
:
$state-danger-bg
;
border
:
solid
1px
$state-danger-border
;
}
.transcript-preferance-wrapper
{
margin-top
:
(
$baseline
*
1
.6
);
.icon.fa-info-circle
{
@include
margin-left
(
$baseline
*
0
.75
);
}
}
.transcript-preferance-wrapper.error
.transcript-preferance-label
{
color
:
$color-error
;
}
.error-info
,
.error-icon
.fa-info-circle
{
color
:
$color-error
;
}
.error-info
{
@include
font-size
(
16
);
}
.transcript-preferance-label
{
color
:
$black-t4
;
@include
font-size
(
15
);
font-weight
:
font-weight
(
semi-bold
);
}
.transcript-provider-group
,
.transcript-turnaround
,
.transcript-fidelity
{
margin-top
:
(
$baseline
*
0
.8
);
}
.transcript-provider-group
{
input
[
type
=
radio
]
{
margin
:
0
(
$baseline
/
2
);
}
label
{
font-weight
:
normal
;
color
:
$black-t4
;
@include
font-size
(
15
);
}
}
.transcript-turnaround-wrapper
,
.transcript-fidelity-wrapper
,
.transcript-languages-wrapper
{
display
:
none
;
}
.transcript-languages-container
.languages-container
{
margin-top
:
(
$baseline
*
0
.8
);
.transcript-language-container
{
padding
:
(
$baseline
/
4
);
background-color
:
$gray-l6
;
border-top
:
solid
1px
$gray-l4
;
border-bottom
:
solid
1px
$gray-l4
;
.remove-language-action
{
display
:
inline-block
;
@include
float
(
right
);
}
}
}
.transcript-language-menu-container
{
margin-top
:
(
$baseline
*
0
.8
);
.transcript-language-menu
{
width
:
65%
;
}
.add-language-action
{
display
:
inline-block
;
.action-add-language
{
@include
margin-left
(
$baseline
/
4
);
}
}
}
}
.course-video-settings-footer
{
margin-top
:
(
$baseline
*
1
.6
);
.last-updated-text
{
@include
font-size
(
12
);
@include
margin-left
(
$baseline
/
4
);
}
}
.button
{
@extend
%btn-primary-blue
;
@extend
%sizing
;
.action-button-text
{
display
:
inline-block
;
vertical-align
:
baseline
;
}
.icon
{
display
:
inline-block
;
vertical-align
:
baseline
;
}
}
}
.file-upload-form
{
@include
clearfix
();
...
...
cms/templates/js/course-video-settings.underscore
0 → 100644
View file @
ec399645
<div class='course-video-settings-container'>
<div class="course-video-settings-header">
<div class="action-close-wrapper">
<button class="action-close-course-video-settings">
<span class="icon fa fa-times" aria-hidden="true"></span>
<%-gettext('Close') %>
<span class='sr'><%-gettext('Press close to hide course video settings') %></span>
</button>
</div>
</div>
<div class='course-video-settings-wrapper'>
<div class='course-video-settings-message-wrapper'></div>
<span class="course-video-settings-title"><%- gettext('Transcript Settings') %></span>
<div class='transcript-preferance-wrapper transcript-provider-wrapper'>
<label class='transcript-preferance-label' for='transcript-provider'><%- gettext('Transcript Provider') %><span class='error-icon' aria-hidden="true"></span></label>
<div class='transcript-provider-group' id='transcript-provider'></div>
<span class='error-info' aria-hidden="true"></span>
</div>
<div class='transcript-preferance-wrapper transcript-turnaround-wrapper'>
<label class='transcript-preferance-label' for='transcript-turnaround'><%- gettext('Transcript Turnaround') %><span class='error-icon' aria-hidden="true"></span></label>
<select id='transcript-turnaround' class='transcript-turnaround'></select>
<span class='error-info' aria-hidden="true"></span>
</div>
<div class='transcript-preferance-wrapper transcript-fidelity-wrapper'>
<label class='transcript-preferance-label' for='transcript-fidelity'><%- gettext('Transcript Fidelity') %><span class='error-icon' aria-hidden="true"></span></label>
<select id='transcript-fidelity' class='transcript-fidelity'></select>
<span class='error-info' aria-hidden="true"></span>
</div>
<div class='transcript-preferance-wrapper transcript-languages-wrapper'>
<span class='transcript-preferance-label'><%- gettext('Transcript Languages') %></span>
<span class='error-icon' aria-hidden="true"></span>
<div class='transcript-languages-container'>
<div class='languages-container'></div>
<div class="transcript-language-menu-container">
<select class="transcript-language-menu" id="transcript-language" aria-labelledby="transcript-language-none"></select>
<div class="add-language-action">
<button class="button-link action-add-language"><%- gettext('Add') %><span class="sr"><%- gettext('Press Add to language') %></span></button>
<span class="error-info" aria-hidden="true"></span>
</div>
</div>
</div>
</div>
<div class='course-video-settings-footer'>
<button class="button button action-update-course-video-settings" aria-describedby='update-button-text'>
<%- gettext('Update Settings') %>
<span id='update-button-text' class='sr'><%-gettext('Press update settings to update course video settings') %></span>
</button>
<%if (dateModified) { %>
<span class='last-updated-text'><%- gettext('Last updated')%> <%- dateModified %></span>
<% } %>
</div>
</div>
</div>
cms/templates/videos_index.html
View file @
ec399645
...
...
@@ -34,10 +34,12 @@
"${encodings_download_url | n, js_escaped_string}",
"${default_video_image_url | n, js_escaped_string}",
${concurrent_upload_limit | n, dump_js_escaped_json},
$(".nav-actions .
upload
-button"),
$(".nav-actions .
course-video-settings
-button"),
$contentWrapper.data("previous-uploads"),
${video_supported_file_formats | n, dump_js_escaped_json},
${video_upload_max_file_size | n, dump_js_escaped_json},
${active_transcript_preferences | n, dump_js_escaped_json},
${video_transcript_settings | n, dump_js_escaped_json},
${video_image_settings | n, dump_js_escaped_json}
);
});
...
...
@@ -46,6 +48,7 @@
<
%
block
name=
"content"
>
<div
class=
"wrapper-mast wrapper"
>
<div
class=
"video-transcript-settings-wrapper"
></div>
<header
class=
"mast has-actions has-subtitle"
>
<h1
class=
"page-header"
>
<small
class=
"subtitle"
>
${_("Content")}
</small>
...
...
@@ -54,11 +57,9 @@
<nav
class=
"nav-actions"
aria-label=
"${_('Page Actions')}"
>
<h3
class=
"sr"
>
${_("Page Actions")}
</h3>
<ul>
<li
class=
"nav-item"
>
<a
href=
"#"
class=
"button upload-button new-button"
><span
class=
"icon fa fa-plus"
aria-hidden=
"true"
></span>
${_("Upload New File")}
</a>
</li>
</ul>
<div
class=
"nav-item"
>
<button
class=
"button course-video-settings-button"
><span
class=
"icon fa fa-cog"
aria-hidden=
"true"
></span>
${_("Course Video Settings")}
</button>
</div>
</nav>
</header>
</div>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment