475 lines
22 KiB
JavaScript
475 lines
22 KiB
JavaScript
/*
|
|
* Copyright (C) 2011 - 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import INST from './INST'
|
|
import I18n from 'i18n!select_content_dialog'
|
|
import $ from 'jquery'
|
|
import React from 'react'
|
|
import ReactDOM from 'react-dom'
|
|
import FileSelectBox from 'jsx/context_modules/FileSelectBox'
|
|
import _ from 'underscore'
|
|
import htmlEscape from 'str/htmlEscape'
|
|
import './jquery.instructure_date_and_time' /* datetime_field */
|
|
import './jquery.ajaxJSON'
|
|
import './jquery.instructure_forms' /* formSubmit, ajaxJSONFiles, getFormData, errorBox */
|
|
import 'jqueryui/dialog'
|
|
import 'compiled/jquery/fixDialogButtons'
|
|
import './jquery.instructure_misc_helpers' /* replaceTags, getUserServices, findLinkForService */
|
|
import './jquery.instructure_misc_plugins' /* showIf */
|
|
import './jquery.keycodes'
|
|
import './jquery.loadingImg'
|
|
import './jquery.templateData'
|
|
|
|
var SelectContentDialog = {};
|
|
|
|
SelectContentDialog.Events = {
|
|
init: function() {
|
|
$("#context_external_tools_select .tools").on('click', '.tool', this.onContextExternalToolSelect);
|
|
},
|
|
|
|
onContextExternalToolSelect : function(e) {
|
|
e.preventDefault();
|
|
var $tool = $(this);
|
|
if($(this).hasClass('selected') && !$(this).hasClass('resource_selection')) {
|
|
$(this).removeClass('selected');
|
|
return;
|
|
}
|
|
$tool.parents(".tools").find(".tool.selected").removeClass('selected');
|
|
$tool.addClass('selected');
|
|
if($tool.hasClass('resource_selection')) {
|
|
var tool = $tool.data('tool');
|
|
var frameHeight = Math.max(Math.min($(window).height() - 100, 550), 100);
|
|
var placement_type = (tool.placements.resource_selection && 'resource_selection') ||
|
|
(tool.placements.assignment_selection && 'assignment_selection') ||
|
|
(tool.placements.link_selection && 'link_selection');
|
|
var placement = tool.placements[placement_type]
|
|
var width = placement.selection_width;
|
|
var height = placement.selection_height;
|
|
var $dialog = $("#resource_selection_dialog");
|
|
var beforeUnloadHandler = function(e) {
|
|
return (e.returnValue = I18n.t("Changes you made may not be saved."));
|
|
};
|
|
var dialogCancelHandler = function(event, ui) {
|
|
var r = confirm(I18n.t("Are you sure you want to cancel? Changes you made may not be saved."));
|
|
if (r == false){
|
|
event.preventDefault();
|
|
}
|
|
};
|
|
if($dialog.length == 0) {
|
|
$dialog = $("<div/>", {id: 'resource_selection_dialog', style: 'padding: 0; overflow-y: hidden;'});
|
|
$dialog.append(`<div class="before_external_content_info_alert screenreader-only" tabindex="0">
|
|
<div class="ic-flash-info">
|
|
<div class="ic-flash__icon" aria-hidden="true">
|
|
<i class="icon-info"></i>
|
|
</div>
|
|
${htmlEscape(I18n.t('The following content is partner provided'))}
|
|
</div>
|
|
</div>`)
|
|
$dialog.append($("<iframe/>", {
|
|
id: 'resource_selection_iframe',
|
|
style: 'width: 800px; height: ' + frameHeight + 'px; border: 0;',
|
|
src: '/images/ajax-loader-medium-444.gif',
|
|
borderstyle: '0',
|
|
tabindex: '0'
|
|
}));
|
|
$dialog.append(`<div class="after_external_content_info_alert screenreader-only" tabindex="0">
|
|
<div class="ic-flash-info">
|
|
<div class="ic-flash__icon" aria-hidden="true">
|
|
<i class="icon-info"></i>
|
|
</div>
|
|
${htmlEscape(I18n.t('The preceding content is partner provided'))}
|
|
</div>
|
|
</div>`)
|
|
|
|
const $external_content_info_alerts = $dialog
|
|
.find('.before_external_content_info_alert, .after_external_content_info_alert');
|
|
|
|
const $iframe = $dialog.find('iframe');
|
|
|
|
$external_content_info_alerts.on('focus', function(e) {
|
|
const iframeWidth = $iframe.outerWidth(true);
|
|
const iframeHeight = $iframe.outerHeight(true);
|
|
$iframe.css('border', '2px solid #008EE2');
|
|
$(this).removeClass('screenreader-only');
|
|
const alertHeight = $(this).outerHeight(true);
|
|
$iframe.css('height', `${(iframeHeight - alertHeight - 4)}px`)
|
|
.css('width', `${(iframeWidth - 4)}px`);
|
|
$dialog.scrollLeft(0).scrollTop(0)
|
|
});
|
|
|
|
$external_content_info_alerts.on('blur', function(e) {
|
|
var iframeWidth = $iframe.outerWidth(true);
|
|
var iframeHeight = $iframe.outerHeight(true);
|
|
var alertHeight = $(this).outerHeight(true);
|
|
$dialog.find('iframe').css('border', 'none');
|
|
$(this).addClass('screenreader-only');
|
|
$iframe.css('height', `${(iframeHeight + alertHeight)}px`)
|
|
.css('width', `${iframeWidth}px`);
|
|
$dialog.scrollLeft(0).scrollTop(0)
|
|
});
|
|
|
|
$("body").append($dialog.hide());
|
|
$dialog.on("dialogbeforeclose", dialogCancelHandler);
|
|
$dialog
|
|
.dialog({
|
|
autoOpen: false,
|
|
width: 'auto',
|
|
resizable: true,
|
|
close: function() {
|
|
$(window).off('beforeunload', beforeUnloadHandler);
|
|
$dialog.find("iframe").attr('src', '/images/ajax-loader-medium-444.gif');
|
|
},
|
|
title: I18n.t('link_from_external_tool', "Link Resource from External Tool")
|
|
})
|
|
.bind('dialogresize', function() {
|
|
$(this).find('iframe').add('.fix_for_resizing_over_iframe').height($(this).height()).width($(this).width());
|
|
})
|
|
.bind('dialogresizestop', function() {
|
|
$(".fix_for_resizing_over_iframe").remove();
|
|
})
|
|
.bind('dialogresizestart', function() {
|
|
$(this).find('iframe').each(function(){
|
|
$('<div class="fix_for_resizing_over_iframe" style="background: #fff;"></div>')
|
|
.css({
|
|
width: this.offsetWidth+"px", height: this.offsetHeight+"px",
|
|
position: "absolute", opacity: "0.001", zIndex: 10000000
|
|
})
|
|
.css($(this).offset())
|
|
.appendTo("body");
|
|
});
|
|
})
|
|
.bind('selection', function(event) {
|
|
var item = event.contentItems[0];
|
|
if(item["@type"] === 'LtiLinkItem' && item.url) {
|
|
$("#external_tool_create_url").val(item.url);
|
|
$("#external_tool_create_title").val(item.title || tool.name);
|
|
$("#context_external_tools_select .domain_message").hide();
|
|
} else {
|
|
alert(I18n.t('invalid_lti_resource_selection', "There was a problem retrieving a valid link from the external tool"));
|
|
$("#external_tool_create_url").val('');
|
|
$("#external_tool_create_title").val('');
|
|
}
|
|
$("#resource_selection_dialog iframe").attr('src', 'about:blank');
|
|
$dialog.off("dialogbeforeclose", dialogCancelHandler);
|
|
$("#resource_selection_dialog").dialog('close');
|
|
|
|
if (item.placementAdvice.presentationDocumentTarget.toLowerCase() === 'window') {
|
|
document.querySelector('#external_tool_create_new_tab').checked = true
|
|
}
|
|
});
|
|
}
|
|
$dialog.dialog('close')
|
|
.dialog('option', 'width', width || 800)
|
|
.dialog('option', 'height', height || frameHeight || 400)
|
|
.dialog('open');
|
|
$dialog.triggerHandler('dialogresize');
|
|
var url = $.replaceTags($("#select_content_resource_selection_url").attr('href'), 'id', tool.definition_id);
|
|
url = url + '?placement=' + placement_type + '&secure_params=' + $('#secure_params').val();
|
|
$dialog.find("iframe").attr('src', url);
|
|
$(window).on('beforeunload', beforeUnloadHandler);
|
|
} else {
|
|
var placements = $tool.data('tool').placements
|
|
var placement = placements.assignment_selection || placements.link_selection
|
|
$("#external_tool_create_url").val(placement.url || '');
|
|
$("#context_external_tools_select .domain_message").showIf($tool.data('tool').domain)
|
|
.find(".domain").text($tool.data('tool').domain);
|
|
$("#external_tool_create_title").val(placement.title);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
$(document).ready(function() {
|
|
var external_services = null;
|
|
var $dialog = $("#select_context_content_dialog");
|
|
INST.selectContentDialog = function(options) {
|
|
var options = options || {};
|
|
var for_modules = options.for_modules;
|
|
var select_button_text = options.select_button_text || I18n.t('buttons.add_item', "Add Item");
|
|
var holder_name = options.holder_name || "module";
|
|
var dialog_title = options.dialog_title || I18n.t('titles.add_item_to_module', "Add Item to Module");
|
|
var allow_external_urls = for_modules;
|
|
$dialog.data('submitted_function', options.submit);
|
|
$dialog.find(".context_module_content").showIf(for_modules);
|
|
$dialog.find(".holder_name").text(holder_name);
|
|
$dialog.find(".add_item_button").text(select_button_text);
|
|
$dialog.find(".select_item_name").showIf(!options.no_name_input);
|
|
if(allow_external_urls && !external_services) {
|
|
var $services = $("#content_tag_services").empty();
|
|
$.getUserServices('BookmarkService', function(data) {
|
|
for(var idx in data) {
|
|
var service = data[idx].user_service;
|
|
var $service = $("<a href='#' class='bookmark_service no-hover'/>");
|
|
$service.addClass(service.service);
|
|
$service.data('service', service);
|
|
$service.attr('title', I18n.t('titles.find_links_using_service', 'Find links using %{service}', {service: service.service}));
|
|
var $img = $("<img/>");
|
|
$img.attr('src', '/images/' + service.service + '_small_icon.png');
|
|
$service.append($img);
|
|
$service.click(function(event) {
|
|
event.preventDefault();
|
|
$.findLinkForService($(this).data('service').service, function(data) {
|
|
$("#content_tag_create_url").val(data.url);
|
|
$("#content_tag_create_title").val(data.title);
|
|
});
|
|
});
|
|
$services.append($service);
|
|
$services.append(" ");
|
|
}
|
|
});
|
|
}
|
|
$("#select_context_content_dialog #external_urls_select :text").val("");
|
|
$("#select_context_content_dialog #context_module_sub_headers_select :text").val("");
|
|
$('#add_module_item_select').change();
|
|
$("#select_context_content_dialog .module_item_select").change();
|
|
$("#select_context_content_dialog").dialog({
|
|
title: dialog_title,
|
|
width: options.width || 400,
|
|
height: options.height || 400,
|
|
close: function() {
|
|
if (options.close) {
|
|
options.close();
|
|
}
|
|
}
|
|
}).fixDialogButtons();
|
|
|
|
var visibleModuleItemSelect = $('#select_context_content_dialog .module_item_select:visible')[0];
|
|
if (visibleModuleItemSelect) {
|
|
if (visibleModuleItemSelect.selectedIndex != -1) {
|
|
$(".add_item_button").removeClass('disabled').attr('aria-disabled', false);
|
|
} else {
|
|
$(".add_item_button").addClass('disabled').attr('aria-disabled', true);
|
|
}
|
|
}
|
|
$("#select_context_content_dialog").dialog('option', 'title', dialog_title);
|
|
}
|
|
$("#select_context_content_dialog .cancel_button").click(function() {
|
|
$dialog.find('.alert').remove();
|
|
$dialog.dialog('close');
|
|
});
|
|
$("#select_context_content_dialog select, #select_context_content_dialog input[type=text], .module_item_select").keycodes('return', function(event) {
|
|
if(!$('.add_item_button').hasClass('disabled')){ // button is enabled
|
|
$(event.currentTarget).blur();
|
|
$(this).parents(".ui-dialog").find(".add_item_button").last().click();
|
|
}
|
|
});
|
|
$("#select_context_content_dialog .add_item_button").click(function() {
|
|
var submit = function(item_data) {
|
|
var submitted = $dialog.data('submitted_function');
|
|
if(submitted && $.isFunction(submitted)) {
|
|
submitted(item_data);
|
|
}
|
|
setTimeout(function() {
|
|
$dialog.dialog('close');
|
|
$dialog.find('.alert').remove();
|
|
}, 0);
|
|
};
|
|
|
|
var item_type = $("#add_module_item_select").val();
|
|
if(item_type == 'external_url') {
|
|
var item_data = {
|
|
'item[type]': $("#add_module_item_select").val(),
|
|
'item[id]': $("#select_context_content_dialog .module_item_option:visible:first .module_item_select").val(),
|
|
'item[new_tab]': $("#external_url_create_new_tab").attr('checked') ? '1' : '0',
|
|
'item[indent]': $("#content_tag_indent").val()
|
|
}
|
|
item_data['item[url]'] = $("#content_tag_create_url").val();
|
|
item_data['item[title]'] = $("#content_tag_create_title").val();
|
|
|
|
if (item_data['item[url]'] === '') {
|
|
$("#content_tag_create_url").errorBox(I18n.t("URL is required"));
|
|
} else if (item_data['item[title]'] === '') {
|
|
$("#content_tag_create_title").errorBox(I18n.t("Page Name is required"));
|
|
} else {
|
|
submit(item_data);
|
|
}
|
|
} else if(item_type == 'context_external_tool') {
|
|
|
|
var tool = $("#context_external_tools_select .tools .tool.selected").data('tool');
|
|
var tool_type = 'context_external_tool';
|
|
var tool_id = 0;
|
|
if(tool){
|
|
if(tool.definition_type == 'Lti::MessageHandler') { tool_type = 'lti/message_handler'}
|
|
tool_id = tool.definition_id
|
|
}
|
|
var item_data = {
|
|
'item[type]': tool_type,
|
|
'item[id]': tool_id,
|
|
'item[new_tab]': $("#external_tool_create_new_tab").attr('checked') ? '1' : '0',
|
|
'item[indent]': $("#content_tag_indent").val()
|
|
}
|
|
item_data['item[url]'] = $("#external_tool_create_url").val();
|
|
item_data['item[title]'] = $("#external_tool_create_title").val();
|
|
$dialog.find('.alert-error').remove();
|
|
if (item_data['item[url]'] === '') {
|
|
var $errorBox = $('<div />', { 'class': 'alert alert-error', role: 'alert' }).css({marginTop: 8 });
|
|
$errorBox.text(I18n.t('errors.external_tool_url', "An external tool can't be saved without a URL."));
|
|
$dialog.prepend($errorBox);
|
|
} else if (item_data['item[title]'] === '') {
|
|
$("#external_tool_create_title").errorBox(I18n.t("Page Name is required"));
|
|
} else {
|
|
submit(item_data);
|
|
}
|
|
|
|
} else if(item_type == 'context_module_sub_header') {
|
|
|
|
var item_data = {
|
|
'item[type]': $("#add_module_item_select").val(),
|
|
'item[id]': $("#select_context_content_dialog .module_item_option:visible:first .module_item_select").val(),
|
|
'item[indent]': $("#content_tag_indent").val()
|
|
}
|
|
item_data['item[title]'] = $("#sub_header_title").val();
|
|
submit(item_data);
|
|
|
|
} else {
|
|
|
|
var $options = $("#select_context_content_dialog .module_item_option:visible:first .module_item_select option:selected");
|
|
$options.each(function() {
|
|
var $option = $(this);
|
|
var item_data = {
|
|
'item[type]': item_type,
|
|
'item[id]': $option.val(),
|
|
'item[title]': $option.text(),
|
|
'item[indent]': $("#content_tag_indent").val()
|
|
}
|
|
if(item_data['item[id]'] == 'new') {
|
|
$("#select_context_content_dialog").loadingImage();
|
|
var url = $("#select_context_content_dialog .module_item_option:visible:first .new .add_item_url").attr('href');
|
|
var data = $("#select_context_content_dialog .module_item_option:visible:first").getFormData();
|
|
var callback = function(data) {
|
|
var obj;
|
|
|
|
// discussion_topics will come from real api v1 and so wont be nested behind a `discussion_topic` or 'wiki_page' root object
|
|
if (item_data['item[type]'] === 'discussion_topic' || item_data['item[type]'] === 'wiki_page') {
|
|
obj = data;
|
|
} else {
|
|
obj = data[item_data['item[type]']]; // e.g. data['wiki_page'] for wiki pages
|
|
}
|
|
|
|
$("#select_context_content_dialog").loadingImage('remove');
|
|
if (item_data['item[type]'] === 'wiki_page') {
|
|
item_data['item[id]'] = obj.page_id;
|
|
} else {
|
|
item_data['item[id]'] = obj.id;
|
|
}
|
|
if (item_data['item[type]'] === 'attachment') {
|
|
// some browsers return a fake path in the file input value, so use the name returned by the server
|
|
item_data['item[title]'] = obj.display_name;
|
|
} else {
|
|
item_data['item[title]'] = $("#select_context_content_dialog .module_item_option:visible:first .item_title").val();
|
|
item_data['item[title]'] = item_data['item[title]'] || obj.display_name;
|
|
}
|
|
var $option = $(document.createElement('option'));
|
|
$option.val(obj.id).text(item_data['item[title]']);
|
|
$("#" + item_data['item[type]'] + "s_select").find(".module_item_select option:last").after($option);
|
|
submit(item_data);
|
|
};
|
|
|
|
//Force the new assignment to set post_to_sis to false so that possible
|
|
//account validations do not prevent saving
|
|
if(item_data['item[type]'] == 'assignment') {
|
|
data['assignment[post_to_sis]'] = false
|
|
}
|
|
if(item_data['item[type]'] == 'attachment') {
|
|
data['duplicate_handling'] = 'rename';
|
|
$.ajaxJSONFiles(url, 'POST', data, $("#module_attachment_uploaded_data"), function(data) {
|
|
callback(data);
|
|
}, function(data) {
|
|
$("#select_context_content_dialog").loadingImage('remove');
|
|
$("#select_context_content_dialog").errorBox(I18n.t('errors.failed_to_create_item', 'Failed to Create new Item'));
|
|
});
|
|
} else {
|
|
$.ajaxJSON(url, 'POST', data, function(data) {
|
|
callback(data);
|
|
}, function(data) {
|
|
$("#select_context_content_dialog").loadingImage('remove');
|
|
if (data && data.errors && data.errors.title[0] && data.errors.title[0].message && data.errors.title[0].message === "blank") {
|
|
$("#select_context_content_dialog").errorBox(I18n.t('errors.assignment_name_blank', 'Assignment name cannot be blank.'));
|
|
$('.item_title').focus();
|
|
} else {
|
|
$("#select_context_content_dialog").errorBox(I18n.t('errors.failed_to_create_item', 'Failed to Create new Item'));
|
|
}
|
|
|
|
});
|
|
}
|
|
} else {
|
|
submit(item_data);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
var initEvents = SelectContentDialog.Events.init.bind(SelectContentDialog.Events)();
|
|
var $tool_template = $("#context_external_tools_select .tools .tool:first").detach();
|
|
$("#add_module_item_select").change(function() {
|
|
// Don't disable the form button for these options
|
|
var selectedOption = $(this).val();
|
|
var doNotDisable = _.contains(['external_url', 'context_external_tool', 'context_module_sub_header'], selectedOption);
|
|
if (doNotDisable) {
|
|
$(".add_item_button").removeClass('disabled').attr('aria-disabled', false);
|
|
} else {
|
|
$(".add_item_button").addClass('disabled').attr('aria-disabled', true);
|
|
}
|
|
|
|
$("#select_context_content_dialog .module_item_option").hide();
|
|
if ($(this).val() === 'attachment') {
|
|
ReactDOM.render(React.createFactory(FileSelectBox)({contextString: ENV.context_asset_string}), $('#module_item_select_file')[0]);
|
|
}
|
|
$("#" + $(this).val() + "s_select").show().find(".module_item_select").change();
|
|
if($(this).val() == 'context_external_tool') {
|
|
var $select = $("#context_external_tools_select");
|
|
if(!$select.hasClass('loaded')) {
|
|
$select.find(".message").text("Loading...");
|
|
var url = $("#select_context_content_dialog .external_tools_url").attr('href');
|
|
$.ajaxJSON(url, 'GET', {}, function(data) {
|
|
$select.find(".message").remove();
|
|
$select.addClass('loaded');
|
|
$select.find(".tools").empty();
|
|
for(var idx in data) {
|
|
var tool = data[idx];
|
|
var $tool = $tool_template.clone(true);
|
|
var placement = tool.placements.assignment_selection || tool.placements.link_selection;
|
|
$tool.toggleClass('resource_selection', ('resource_selection' in tool.placements || placement.message_type == "ContentItemSelectionRequest"));
|
|
$tool.fillTemplateData({
|
|
data: tool,
|
|
dataValues: ['definition_type', 'definition_id', 'domain', 'name', 'placements', 'description']
|
|
});
|
|
$tool.data('tool', tool);
|
|
$select.find(".tools").append($tool.show());
|
|
}
|
|
}, function(data) {
|
|
$select.find(".message").text(I18n.t('errors.loading_failed', "Loading Failed"));
|
|
});
|
|
}
|
|
}
|
|
})
|
|
$('#select_context_content_dialog').on('change', '.module_item_select', function () {
|
|
var currentSelectItem = $(this)[0];
|
|
if (currentSelectItem && currentSelectItem.selectedIndex > -1) {
|
|
$(".add_item_button").removeClass('disabled').attr('aria-disabled', false);
|
|
}
|
|
|
|
if($(this).val() == "new") {
|
|
$(this).parents(".module_item_option").find(".new").show().focus().select();
|
|
} else {
|
|
$(this).parents(".module_item_option").find(".new").hide();
|
|
}
|
|
});
|
|
});
|
|
|
|
export default SelectContentDialog;
|