* fix: eslint operator-linebreak issue * fix: eslint quotes issue * fix: react jsx indent and props issues * fix: eslint trailing spaces issues * fix: eslint line around directives issue * fix: eslint semi rule * fix: eslint newline per chain rule * fix: eslint space infix ops rule * fix: eslint space-in-parens issue * fix: eslint space before function paren issue * fix: eslint space before blocks issue * fix: eslint arrow body style issue * fix: eslint dot-location issue * fix: eslint quotes issue * fix: eslint quote props issue * fix: eslint operator assignment issue * fix: eslint new line after import issue * fix: indent issues * fix: operator assignment issue * fix: all autofixable eslint issues * fix: all react related fixable issues * fix: autofixable eslint issues * chore: remove all template literals * fix: remaining autofixable issues * chore: apply amnesty on all existing issues * fix: failing xss-lint issues * refactor: apply amnesty on remaining issues * refactor: apply amnesty on new issues * fix: remove file level suppressions * refactor: apply amnesty on new issues
873 lines
38 KiB
JavaScript
873 lines
38 KiB
JavaScript
/**
|
|
* CourseVideoSettingsView shows a sidebar containing course wide video settings which we show on Video Uploads page.
|
|
*/
|
|
define([
|
|
'jquery', 'backbone', 'underscore', 'gettext', 'moment',
|
|
'common/js/components/utils/view_utils',
|
|
'edx-ui-toolkit/js/utils/html-utils',
|
|
'edx-ui-toolkit/js/utils/string-utils',
|
|
'text!templates/course-video-settings.underscore',
|
|
'text!templates/course-video-transcript-preferences.underscore',
|
|
'text!templates/course-video-transcript-provider-empty.underscore',
|
|
'text!templates/course-video-transcript-provider-selected.underscore',
|
|
'text!templates/transcript-organization-credentials.underscore',
|
|
'text!templates/course-video-settings-update-settings-footer.underscore',
|
|
'text!templates/course-video-settings-update-org-credentials-footer.underscore'
|
|
],
|
|
function($, Backbone, _, gettext, moment, ViewUtils, HtmlUtils, StringUtils, TranscriptSettingsTemplate,
|
|
TranscriptPreferencesTemplate, TranscriptProviderEmptyStateTemplate, TranscriptProviderSelectedStateTemplate,
|
|
OrganizationCredentialsTemplate, UpdateSettingsFooterTemplate, OrganizationCredentialsFooterTemplate) {
|
|
'use strict';
|
|
|
|
var CourseVideoSettingsView,
|
|
CIELO24 = 'Cielo24',
|
|
THREE_PLAY_MEDIA = '3PlayMedia',
|
|
INTERNAL_SERVER_ERROR_MESSAGE = gettext('An error has occurred. Wait a few minutes, and then try again.');
|
|
|
|
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',
|
|
'change #video-source-language': 'videoSourceLanguageSelected',
|
|
'click .action-add-language': 'languageSelected',
|
|
'click .action-remove-language': 'languageRemoved',
|
|
'click .action-change-provider': 'renderOrganizationCredentials',
|
|
'click .action-update-org-credentials': 'updateOrganizationCredentials',
|
|
'click .action-update-course-video-settings': 'updateCourseVideoSettings',
|
|
'click .action-cancel-course-video-settings': 'discardChanges',
|
|
'click .action-close-course-video-settings': 'closeCourseVideoSettings'
|
|
},
|
|
|
|
initialize: function(options) {
|
|
var videoTranscriptSettings = options.videoTranscriptSettings;
|
|
this.activeTranscriptionPlan = options.activeTranscriptPreferences;
|
|
this.transcriptOrganizationCredentials = _.extend({}, options.transcriptOrganizationCredentials);
|
|
this.availableTranscriptionPlans = videoTranscriptSettings.transcription_plans;
|
|
this.transcriptHandlerUrl = videoTranscriptSettings.transcript_preferences_handler_url;
|
|
this.transcriptCredentialsHandlerUrl = videoTranscriptSettings.transcript_credentials_handler_url;
|
|
this.template = HtmlUtils.template(TranscriptSettingsTemplate);
|
|
this.transcriptPreferencesTemplate = HtmlUtils.template(TranscriptPreferencesTemplate);
|
|
this.organizationCredentialsTemplate = HtmlUtils.template(OrganizationCredentialsTemplate);
|
|
this.organizationCredentialsFooterTemplate = HtmlUtils.template(OrganizationCredentialsFooterTemplate);
|
|
this.updateSettingsFooterTemplate = HtmlUtils.template(UpdateSettingsFooterTemplate);
|
|
this.transcriptProviderEmptyStateTemplate = HtmlUtils.template(TranscriptProviderEmptyStateTemplate);
|
|
this.transcriptProviderSelectedStateTemplate = HtmlUtils.template(TranscriptProviderSelectedStateTemplate);
|
|
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.activeLanguages = [];
|
|
this.selectedVideoSourceLanguage = '';
|
|
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;
|
|
this.selectedVideoSourceLanguage = this.activeTranscriptionPlan.video_source_language;
|
|
} 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;
|
|
},
|
|
|
|
getTargetLanguages: function() {
|
|
var availableLanguages,
|
|
selectedPlan = this.selectedProvider ? this.availableTranscriptionPlans[this.selectedProvider] : null;
|
|
if (selectedPlan) {
|
|
if (this.selectedProvider === CIELO24 && this.selectedFidelityPlan) {
|
|
availableLanguages = selectedPlan.fidelity[this.selectedFidelityPlan].languages;
|
|
// If fidelity is mechanical then target language would be same as source language.
|
|
if (this.selectedFidelityPlan === 'MECHANICAL' && this.selectedVideoSourceLanguage) {
|
|
availableLanguages = _.pick(
|
|
availableLanguages,
|
|
this.selectedVideoSourceLanguage
|
|
);
|
|
}
|
|
} else if (this.selectedProvider === THREE_PLAY_MEDIA) {
|
|
availableLanguages = selectedPlan.languages;
|
|
}
|
|
}
|
|
return availableLanguages;
|
|
},
|
|
|
|
getSourceLanguages: function() {
|
|
var sourceLanguages = [];
|
|
if (this.selectedProvider === THREE_PLAY_MEDIA) {
|
|
sourceLanguages = this.availableTranscriptionPlans[this.selectedProvider].translations;
|
|
} else {
|
|
sourceLanguages = this.getTargetLanguages();
|
|
}
|
|
return sourceLanguages;
|
|
},
|
|
|
|
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.
|
|
// eslint-disable-next-line no-multi-assign
|
|
this.selectedLanguages = this.activeLanguages = [];
|
|
// Also clear selected language.
|
|
this.selectedVideoSourceLanguage = '';
|
|
this.renderSourceLanguages();
|
|
this.renderTargetLanguages();
|
|
},
|
|
|
|
videoSourceLanguageSelected: function(event) {
|
|
var $videoSourceLanguageContainer = this.$el.find('.video-source-language-wrapper');
|
|
this.selectedVideoSourceLanguage = event.target.value;
|
|
// Remove any error if present already.
|
|
this.clearPreferenceErrorState($videoSourceLanguageContainer);
|
|
|
|
// Clear active and selected languages.
|
|
// eslint-disable-next-line no-multi-assign
|
|
this.selectedLanguages = this.activeLanguages = [];
|
|
this.renderTargetLanguages();
|
|
},
|
|
|
|
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;
|
|
// Re-render view
|
|
this.reRenderView();
|
|
},
|
|
|
|
reRenderView: function() {
|
|
var $courseVideoSettingsContentEl = this.$el.find('.course-video-settings-content'),
|
|
dateModified = this.activeTranscriptionPlan
|
|
? moment.utc(this.activeTranscriptionPlan.modified).format('ll') : '';
|
|
|
|
if (!this.selectedProvider) {
|
|
// Hide organization credentials and transcript preferences views
|
|
$courseVideoSettingsContentEl.hide();
|
|
|
|
// Render footer
|
|
HtmlUtils.setHtml(
|
|
this.$el.find('.course-video-settings-footer'),
|
|
this.updateSettingsFooterTemplate({
|
|
dateModified: dateModified
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
$courseVideoSettingsContentEl.show();
|
|
// If org provider specific credentials are present
|
|
if (this.transcriptOrganizationCredentials[this.selectedProvider]) {
|
|
this.renderTranscriptPreferences();
|
|
} else {
|
|
this.renderOrganizationCredentials();
|
|
}
|
|
},
|
|
|
|
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.
|
|
// eslint-disable-next-line no-multi-assign
|
|
this.selectedLanguages = this.activeLanguages = _.without(this.selectedLanguages, selectedLanguage);
|
|
|
|
// Populate menu again to reflect latest changes.
|
|
this.populateLanguageMenu();
|
|
},
|
|
|
|
renderProviders: function(state) {
|
|
var $transcriptProviderWrapperEl = this.$el.find('.transcript-provider-wrapper');
|
|
if (!state) {
|
|
state = this.selectedProvider ? 'selected' : 'empty'; // eslint-disable-line no-param-reassign
|
|
}
|
|
|
|
// If no transcription plans are sentm return.
|
|
if (!this.availableTranscriptionPlans) {
|
|
return;
|
|
}
|
|
if (state === 'empty') {
|
|
HtmlUtils.setHtml(
|
|
$transcriptProviderWrapperEl,
|
|
this.transcriptProviderEmptyStateTemplate({
|
|
providers: [
|
|
{
|
|
key: 'none',
|
|
value: '',
|
|
name: gettext('None'),
|
|
checked: this.selectedProvider === '' ? 'checked' : ''
|
|
},
|
|
{
|
|
key: CIELO24,
|
|
value: CIELO24,
|
|
name: this.availableTranscriptionPlans[CIELO24].display_name,
|
|
checked: this.selectedProvider === CIELO24 ? 'checked' : ''
|
|
},
|
|
{
|
|
key: THREE_PLAY_MEDIA,
|
|
value: THREE_PLAY_MEDIA,
|
|
name: this.availableTranscriptionPlans[THREE_PLAY_MEDIA].display_name,
|
|
checked: this.selectedProvider === THREE_PLAY_MEDIA ? 'checked' : ''
|
|
}
|
|
]
|
|
})
|
|
);
|
|
} else {
|
|
HtmlUtils.setHtml(
|
|
$transcriptProviderWrapperEl,
|
|
this.transcriptProviderSelectedStateTemplate({
|
|
selectedProvider: this.availableTranscriptionPlans[this.selectedProvider].display_name
|
|
})
|
|
);
|
|
this.renderTranscriptPreferences();
|
|
}
|
|
},
|
|
|
|
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();
|
|
}
|
|
},
|
|
|
|
renderTargetLanguages: function() {
|
|
var self = this,
|
|
// Merge active and selected languages, this handles the case when active languages are present and
|
|
// user also has selected some languages but not saved, user changes organization credentials,
|
|
// both active and selected languages should be rendered.
|
|
selectedLanguages = _.union(self.activeLanguages, self.selectedLanguages),
|
|
$languagesPreferenceContainer = self.$el.find('.transcript-languages-wrapper'),
|
|
$languagesContainer = self.$el.find('.languages-container');
|
|
|
|
// Clear error state if present any.
|
|
self.clearPreferenceErrorState($languagesPreferenceContainer);
|
|
|
|
$languagesContainer.empty();
|
|
|
|
// Show language container if source language is selected.
|
|
if (self.selectedVideoSourceLanguage) {
|
|
_.each(selectedLanguages, function(language) {
|
|
// Only add if not in the list already.
|
|
if (_.indexOf(self.selectedLanguages, language) === -1) {
|
|
self.selectedLanguages.push(language);
|
|
}
|
|
// Show active/ add language language container
|
|
self.addLanguage(language);
|
|
});
|
|
$languagesPreferenceContainer.show();
|
|
self.populateLanguageMenu();
|
|
} else {
|
|
$languagesPreferenceContainer.hide();
|
|
}
|
|
},
|
|
|
|
renderSourceLanguages: function() {
|
|
var self = this,
|
|
availableLanguages = self.getTargetLanguages(),
|
|
availableTranslations = self.getSourceLanguages(),
|
|
$videoSourceLanguageContainer = self.$el.find('.video-source-language-wrapper'),
|
|
$languageMenuEl = self.$el.find('.video-source-language'),
|
|
selectOptionEl = new Option(gettext('Select language'), '');
|
|
|
|
// Clear error state if present any.
|
|
self.clearPreferenceErrorState($videoSourceLanguageContainer);
|
|
|
|
if (!_.isEmpty(availableTranslations)) {
|
|
$videoSourceLanguageContainer.show();
|
|
|
|
// We need to set id due to a11y aria-labelledby
|
|
selectOptionEl.id = 'video-source-language-none';
|
|
|
|
HtmlUtils.setHtml(
|
|
$languageMenuEl,
|
|
HtmlUtils.HTML(selectOptionEl)
|
|
);
|
|
|
|
_.each(availableTranslations, function(translatableLanguage, key) {
|
|
var option = new Option(availableLanguages[key], key);
|
|
if (self.selectedVideoSourceLanguage === key) {
|
|
option.selected = true;
|
|
}
|
|
HtmlUtils.append(
|
|
$languageMenuEl,
|
|
HtmlUtils.HTML(option)
|
|
);
|
|
});
|
|
} else {
|
|
$videoSourceLanguageContainer.hide();
|
|
}
|
|
},
|
|
|
|
populateLanguageMenu: function() {
|
|
var availableLanguages = this.getTargetLanguages(),
|
|
availableTranslations = this.availableTranscriptionPlans[THREE_PLAY_MEDIA].translations,
|
|
$languageMenuEl = this.$el.find('.transcript-language-menu'),
|
|
$languageMenuContainerEl = this.$el.find('.transcript-language-menu-container'),
|
|
selectOptionEl = new Option(gettext('Select language'), '');
|
|
|
|
if (this.selectedProvider === THREE_PLAY_MEDIA) {
|
|
// Pick out only those languages from plan laguages that also come from video source language.
|
|
availableLanguages = _.pick(
|
|
availableLanguages,
|
|
availableTranslations[this.selectedVideoSourceLanguage]
|
|
);
|
|
}
|
|
|
|
// Omit out selected languages from selecting again.
|
|
availableLanguages = _.omit(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();
|
|
}
|
|
},
|
|
|
|
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.getTargetLanguages()[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>')
|
|
)
|
|
);
|
|
},
|
|
|
|
updateSuccessResponseStatus: function(data, successMessage) {
|
|
var dateModified = data ? moment.utc(data.modified).format('ll') : '';
|
|
successMessage = successMessage ? successMessage : gettext('Settings updated'); // eslint-disable-line no-param-reassign, no-unneeded-ternary, max-len
|
|
|
|
// Update last modified date
|
|
if (dateModified) {
|
|
HtmlUtils.setHtml(
|
|
this.$el.find('.last-updated-text'),
|
|
HtmlUtils.interpolateHtml(
|
|
HtmlUtils.HTML('{lastUpdateText} {dateModified}'),
|
|
{
|
|
lastUpdateText: gettext('Last updated'),
|
|
dateModified: dateModified
|
|
}
|
|
)
|
|
);
|
|
}
|
|
|
|
// Now re-render providers state.
|
|
this.renderProviders();
|
|
|
|
this.renderResponseStatus(successMessage, 'success');
|
|
// Sync ActiveUploadListView with latest active plan.
|
|
this.activeTranscriptionPlan = data;
|
|
Backbone.trigger('coursevideosettings:syncActiveTranscriptPreferences', this.activeTranscriptionPlan);
|
|
},
|
|
|
|
updateFailResponseStatus: function(data) {
|
|
var errorMessage;
|
|
// Enclose inside try-catch so that if we get erroneous data, we could still
|
|
// show some error to user
|
|
try {
|
|
errorMessage = $.parseJSON(data).error;
|
|
} catch (e) {} // eslint-disable-line no-empty
|
|
this.renderResponseStatus(errorMessage || INTERNAL_SERVER_ERROR_MESSAGE, 'error');
|
|
},
|
|
|
|
renderResponseStatus: function(responseText, type) {
|
|
var addClass = type === 'error' ? 'error' : 'success',
|
|
removeClass = type === 'error' ? 'success' : 'error',
|
|
iconClass = type === 'error' ? 'fa-info-circle' : 'fa-check-circle',
|
|
$messageWrapperEl = this.$el.find('.course-video-settings-message-wrapper');
|
|
$messageWrapperEl.removeClass(removeClass);
|
|
$messageWrapperEl.addClass(addClass);
|
|
HtmlUtils.setHtml(
|
|
$messageWrapperEl,
|
|
HtmlUtils.interpolateHtml(
|
|
HtmlUtils.HTML('<div class="course-video-settings-message"><span class="icon fa {iconClass}" aria-hidden="true"></span><span>{text}</span></div>'), // eslint-disable-line max-len
|
|
{
|
|
text: responseText,
|
|
iconClass: iconClass
|
|
}
|
|
)
|
|
);
|
|
},
|
|
|
|
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'),
|
|
$videoSourcelanguageEl = this.$el.find('.video-source-language-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.selectedProvider === THREE_PLAY_MEDIA && !this.selectedVideoSourceLanguage) {
|
|
isValid = false;
|
|
this.addErrorState($videoSourcelanguageEl);
|
|
} else {
|
|
this.clearPreferenceErrorState($videoSourcelanguageEl);
|
|
}
|
|
|
|
if (this.selectedLanguages.length === 0) {
|
|
isValid = false;
|
|
this.addErrorState($languagesEl);
|
|
} else {
|
|
this.clearPreferenceErrorState($languagesEl);
|
|
}
|
|
|
|
return isValid;
|
|
},
|
|
|
|
validateOrganizationCredentials: function() {
|
|
var $OrganizationApiSecretWrapperEl,
|
|
$OrganizationUsernameWrapperEl,
|
|
isValid = true,
|
|
$OrganizationApiKeyWrapperEl = this.$el.find('.' + this.selectedProvider + '-api-key-wrapper');
|
|
|
|
// Explicit None selected case.
|
|
if (this.selectedProvider === '') {
|
|
return false;
|
|
}
|
|
|
|
if ($OrganizationApiKeyWrapperEl.find('input').val() === '') {
|
|
isValid = false;
|
|
this.addErrorState($OrganizationApiKeyWrapperEl);
|
|
} else {
|
|
this.clearPreferenceErrorState($OrganizationApiKeyWrapperEl);
|
|
}
|
|
|
|
if (this.selectedProvider === THREE_PLAY_MEDIA) {
|
|
$OrganizationApiSecretWrapperEl = this.$el.find('.' + this.selectedProvider + '-api-secret-wrapper');
|
|
if ($OrganizationApiSecretWrapperEl.find('input').val() === '') {
|
|
isValid = false;
|
|
this.addErrorState($OrganizationApiSecretWrapperEl);
|
|
} else {
|
|
this.clearPreferenceErrorState($OrganizationApiSecretWrapperEl);
|
|
}
|
|
} else {
|
|
$OrganizationUsernameWrapperEl = this.$el.find('.' + this.selectedProvider + '-username-wrapper');
|
|
if ($OrganizationUsernameWrapperEl.find('input').val() === '') {
|
|
isValid = false;
|
|
this.addErrorState($OrganizationUsernameWrapperEl);
|
|
} else {
|
|
this.clearPreferenceErrorState($OrganizationUsernameWrapperEl);
|
|
}
|
|
}
|
|
|
|
return isValid;
|
|
},
|
|
|
|
saveTranscriptPreferences: function() {
|
|
var self = this,
|
|
responseTranscriptPreferences;
|
|
// First clear response status if present already
|
|
this.clearResponseStatus();
|
|
|
|
if (self.selectedProvider) {
|
|
$.postJSON(self.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 : '', // eslint-disable-line max-len
|
|
preferred_languages: self.selectedLanguages,
|
|
video_source_language: self.selectedVideoSourceLanguage,
|
|
global: false // Do not trigger global AJAX error handler
|
|
}, function(data) {
|
|
responseTranscriptPreferences = data ? data.transcript_preferences : null;
|
|
self.updateSuccessResponseStatus(responseTranscriptPreferences);
|
|
}).fail(function(jqXHR) {
|
|
self.updateFailResponseStatus(jqXHR.responseText);
|
|
});
|
|
} else {
|
|
$.ajax({
|
|
type: 'DELETE',
|
|
url: self.transcriptHandlerUrl
|
|
}).done(function() {
|
|
responseTranscriptPreferences = null;
|
|
self.updateSuccessResponseStatus(
|
|
responseTranscriptPreferences,
|
|
gettext('Automatic transcripts are disabled.')
|
|
);
|
|
}).fail(function(jqXHR) {
|
|
self.updateFailResponseStatus(jqXHR.responseText);
|
|
});
|
|
}
|
|
},
|
|
|
|
saveOrganizationCredentials: function() {
|
|
var self = this,
|
|
username,
|
|
apiSecret,
|
|
apiKey = this.$el.find('.' + this.selectedProvider + '-api-key').val();
|
|
|
|
// First clear response status if present already
|
|
this.clearResponseStatus();
|
|
|
|
if (this.selectedProvider === THREE_PLAY_MEDIA) {
|
|
apiSecret = this.$el.find('.' + this.selectedProvider + '-api-secret').val();
|
|
} else {
|
|
username = this.$el.find('.' + this.selectedProvider + '-username').val();
|
|
}
|
|
|
|
$.postJSON(self.transcriptCredentialsHandlerUrl, {
|
|
provider: self.selectedProvider,
|
|
api_key: apiKey,
|
|
api_secret_key: apiSecret,
|
|
username: username,
|
|
global: false // Do not trigger global AJAX error handler
|
|
}, function() {
|
|
self.$el.find('.organization-credentials-wrapper').hide();
|
|
|
|
// Update org credentials for selected provider
|
|
self.transcriptOrganizationCredentials[self.selectedProvider] = true;
|
|
|
|
self.updateSuccessResponseStatus(
|
|
self.activeTranscriptionPlan,
|
|
gettext('{selectedProvider} credentials saved').replace(
|
|
'{selectedProvider}',
|
|
self.availableTranscriptionPlans[self.selectedProvider].display_name
|
|
)
|
|
);
|
|
}).fail(function(jqXHR) {
|
|
self.updateFailResponseStatus(jqXHR.responseText);
|
|
});
|
|
},
|
|
|
|
updateOrganizationCredentials: function() {
|
|
if (this.validateOrganizationCredentials()) {
|
|
this.saveOrganizationCredentials();
|
|
}
|
|
},
|
|
|
|
updateCourseVideoSettings: function() {
|
|
var $messageWrapperEl = this.$el.find('.course-video-settings-message-wrapper');
|
|
if (this.validateCourseVideoSettings()) {
|
|
this.saveTranscriptPreferences();
|
|
} else {
|
|
$messageWrapperEl.empty();
|
|
}
|
|
},
|
|
|
|
discardChanges: function() {
|
|
this.setActiveTranscriptPlanData();
|
|
// Re-render views
|
|
this.renderProviders();
|
|
this.reRenderView();
|
|
},
|
|
|
|
renderOrganizationCredentials: function() {
|
|
var $courseVideoSettingsContentEl = this.$el.find('.course-video-settings-content');
|
|
|
|
// Render empty state providers view.
|
|
this.renderProviders('empty');
|
|
|
|
HtmlUtils.setHtml(
|
|
$courseVideoSettingsContentEl,
|
|
this.organizationCredentialsTemplate({
|
|
selectedProvider: {
|
|
key: this.selectedProvider,
|
|
name: this.availableTranscriptionPlans[this.selectedProvider].display_name
|
|
},
|
|
organizationCredentialsExists: this.transcriptOrganizationCredentials[this.selectedProvider],
|
|
CIELO24: CIELO24,
|
|
THREE_PLAY_MEDIA: THREE_PLAY_MEDIA
|
|
})
|
|
);
|
|
// Render footer
|
|
HtmlUtils.setHtml(
|
|
this.$el.find('.course-video-settings-footer'),
|
|
this.organizationCredentialsFooterTemplate({})
|
|
);
|
|
},
|
|
|
|
renderTranscriptPreferences: function() {
|
|
var $courseVideoSettingsContentEl = this.$el.find('.course-video-settings-content'),
|
|
dateModified = this.activeTranscriptionPlan
|
|
? moment.utc(this.activeTranscriptionPlan.modified).format('ll') : '';
|
|
|
|
HtmlUtils.setHtml(
|
|
$courseVideoSettingsContentEl,
|
|
this.transcriptPreferencesTemplate({
|
|
selectedProvider: this.selectedProvider,
|
|
THREE_PLAY_MEDIA: THREE_PLAY_MEDIA
|
|
})
|
|
);
|
|
|
|
// Render transcript preferences.
|
|
this.renderTurnaround();
|
|
this.renderFidelity();
|
|
this.renderSourceLanguages();
|
|
this.renderTargetLanguages();
|
|
|
|
// Render footer
|
|
HtmlUtils.setHtml(
|
|
this.$el.find('.course-video-settings-footer'),
|
|
this.updateSettingsFooterTemplate({
|
|
dateModified: dateModified
|
|
})
|
|
);
|
|
},
|
|
|
|
render: function() {
|
|
var dateModified = this.activeTranscriptionPlan
|
|
? moment.utc(this.activeTranscriptionPlan.modified).format('ll') : '';
|
|
|
|
HtmlUtils.setHtml(this.$el, this.template({}));
|
|
|
|
// Render footer
|
|
HtmlUtils.setHtml(
|
|
this.$el.find('.course-video-settings-footer'),
|
|
this.updateSettingsFooterTemplate({
|
|
dateModified: dateModified
|
|
})
|
|
);
|
|
|
|
this.renderProviders();
|
|
|
|
this.registerCloseClickHandler();
|
|
this.setFixedCourseVideoSettingsPane();
|
|
return this;
|
|
},
|
|
|
|
setFixedCourseVideoSettingsPane: function() {
|
|
var $courseVideoSettingsButton = $('.course-video-settings-button'),
|
|
$courseVideoSettingsContainer = this.$el.find('.course-video-settings-container'),
|
|
initialPositionTop = $courseVideoSettingsContainer.offset().top,
|
|
// Button right position = width of window - button left position - button width - paddings - border.
|
|
$courseVideoSettingsButtonRight = $(window).width()
|
|
- $courseVideoSettingsButton.offset().left
|
|
- $courseVideoSettingsButton.width()
|
|
- $courseVideoSettingsButton.css('padding-left').replace('px', '')
|
|
- $courseVideoSettingsButton.css('padding-right').replace('px', '')
|
|
- $courseVideoSettingsButton.css('border-width').replace('px', '') - 5; // Extra pixles for slack;
|
|
|
|
// Set to windows total height
|
|
$courseVideoSettingsContainer.css('height', $(window).height());
|
|
|
|
// Start settings pane adjascent to 'course video settings' button.
|
|
$courseVideoSettingsContainer.css('right', $courseVideoSettingsButtonRight);
|
|
|
|
// Make sticky when scroll reaches top.
|
|
$(window).scroll(function() {
|
|
if ($(window).scrollTop() >= initialPositionTop) {
|
|
$courseVideoSettingsContainer.addClass('fixed-container');
|
|
} else {
|
|
$courseVideoSettingsContainer.removeClass('fixed-container');
|
|
}
|
|
});
|
|
},
|
|
|
|
closeCourseVideoSettings: function() {
|
|
// TODO: Slide out when closing settings pane. See EDUCATOR-1477
|
|
|
|
// 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;
|
|
});
|