Commit 52f4f6af by cahrens

Pull modal cover and date utils into their own files.

Move overview-specific functions into overview.js.
parent a16c567b
......@@ -54,17 +54,14 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model
@courseInfoEdit.$el.find('.save-button').click()
@cancelNewCourseInfo = (useCancelButton) ->
spyOn(@courseInfoEdit.$modalCover, 'show').andCallThrough()
spyOn(@courseInfoEdit.$modalCover, 'hide').andCallThrough()
@courseInfoEdit.onNew(@event)
expect(@courseInfoEdit.$modalCover.show).toHaveBeenCalled()
spyOn(@courseInfoEdit.$modalCover, 'hide').andCallThrough()
spyOn(@courseInfoEdit.$codeMirror, 'getValue').andReturn('unsaved changes')
model = @collection.at(0)
spyOn(model, "save").andCallThrough()
cancelEditingUpdate(useCancelButton)
cancelEditingUpdate(@courseInfoEdit, @courseInfoEdit.$modalCover, useCancelButton)
expect(@courseInfoEdit.$modalCover.hide).toHaveBeenCalled()
expect(model.save).not.toHaveBeenCalled()
......@@ -73,28 +70,25 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model
@cancelExistingCourseInfo = (useCancelButton) ->
@createNewUpdate('existing update')
spyOn(@courseInfoEdit.$modalCover, 'show').andCallThrough()
spyOn(@courseInfoEdit.$modalCover, 'hide').andCallThrough()
@courseInfoEdit.$el.find('.edit-button').click()
expect(@courseInfoEdit.$modalCover.show).toHaveBeenCalled()
spyOn(@courseInfoEdit.$modalCover, 'hide').andCallThrough()
spyOn(@courseInfoEdit.$codeMirror, 'getValue').andReturn('modification')
model = @collection.at(0)
spyOn(model, "save").andCallThrough()
cancelEditingUpdate(useCancelButton)
model.id = "saved_to_server"
cancelEditingUpdate(@courseInfoEdit, @courseInfoEdit.$modalCover, useCancelButton)
expect(@courseInfoEdit.$modalCover.hide).toHaveBeenCalled()
expect(model.save).not.toHaveBeenCalled()
previewContents = @courseInfoEdit.$el.find('.update-contents').html()
expect(previewContents).toEqual('existing update')
cancelEditingUpdate = (update, useCancelButton) ->
cancelEditingUpdate = (update, modalCover, useCancelButton) ->
if useCancelButton
update.$el.find('.cancel-button').click()
else
$('.modal-cover').click()
modalCover.click()
afterEach ->
@xhrRestore()
......
define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base", "date", "jquery.timepicker"],
(OverviewDragger, Notification, sinon) ->
(Overview, Notification, sinon) ->
describe "Course Overview", ->
beforeEach ->
......@@ -62,9 +62,9 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
</ol>
"""
spyOn(window, 'saveSetSectionScheduleDate').andCallThrough()
spyOn(Overview, 'saveSetSectionScheduleDate').andCallThrough()
# Have to do this here, as it normally gets bound in document.ready()
$('a.save-button').click(saveSetSectionScheduleDate)
$('a.save-button').click(Overview.saveSetSectionScheduleDate)
$('a.delete-section-button').click(deleteSection)
$(".edit-subsection-publish-settings .start-date").datepicker()
......@@ -75,7 +75,7 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
requests = @requests = []
@xhr.onCreate = (req) -> requests.push(req)
OverviewDragger.makeDraggable(
Overview.overviewDragger.makeDraggable(
'.unit',
'.unit-drag-handle',
'ol.sortable-unit-list',
......@@ -90,7 +90,7 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
it "should save model when save is clicked", ->
$('a.edit-button').click()
$('a.save-button').click()
expect(saveSetSectionScheduleDate).toHaveBeenCalled()
expect(Overview.saveSetSectionScheduleDate).toHaveBeenCalled()
it "should show a confirmation on save", ->
$('a.edit-button').click()
......@@ -120,7 +120,7 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
$ele.offset(
top: $ele.offset().top + 10, left: $ele.offset().left
)
destination = OverviewDragger.findDestination($ele, 1)
destination = Overview.overviewDragger.findDestination($ele, 1)
expect(destination.ele).toBe($('#unit-2'))
expect(destination.attachMethod).toBe('before')
......@@ -130,7 +130,7 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
top: $('#unit-4').offset().top + 8
left: $ele.offset().left
)
destination = OverviewDragger.findDestination($ele, 1)
destination = Overview.overviewDragger.findDestination($ele, 1)
expect(destination.ele).toBe($('#unit-4'))
# Dragging down into first element, we have a fudge factor makes it easier to drag at beginning.
expect(destination.attachMethod).toBe('before')
......@@ -139,7 +139,7 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
top: $('#unit-4').offset().top + 12
left: $ele.offset().left
)
destination = OverviewDragger.findDestination($ele, 1)
destination = Overview.overviewDragger.findDestination($ele, 1)
expect(destination.ele).toBe($('#unit-4'))
expect(destination.attachMethod).toBe('after')
......@@ -149,7 +149,7 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
top: $('#unit-3').offset().bottom + 4
left: $ele.offset().left
)
destination = OverviewDragger.findDestination($ele, -1)
destination = Overview.overviewDragger.findDestination($ele, -1)
expect(destination.ele).toBe($('#unit-3'))
# Dragging down up into last element, we have a fudge factor makes it easier to drag at beginning.
expect(destination.attachMethod).toBe('after')
......@@ -158,7 +158,7 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
top: $('#unit-3').offset().top + 4
left: $ele.offset().left
)
destination = OverviewDragger.findDestination($ele, -1)
destination = Overview.overviewDragger.findDestination($ele, -1)
expect(destination.ele).toBe($('#unit-3'))
expect(destination.attachMethod).toBe('before')
......@@ -168,7 +168,7 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
top: $('#subsection-3').offset().top + 10
left: $ele.offset().left
)
destination = OverviewDragger.findDestination($ele, 1)
destination = Overview.overviewDragger.findDestination($ele, 1)
expect(destination.ele).toBe($('#subsection-list-3'))
expect(destination.attachMethod).toBe('prepend')
......@@ -177,7 +177,7 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
$ele.offset(
top: $ele.offset().top + 200, left: $ele.offset().left
)
destination = OverviewDragger.findDestination($ele, 1)
destination = Overview.overviewDragger.findDestination($ele, 1)
expect(destination).toEqual(
ele: null
attachMethod: ""
......@@ -190,21 +190,21 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
top: $('#subsection-2').offset().top + 3
left: $ele.offset().left
)
destination = OverviewDragger.findDestination($ele, 1)
destination = Overview.overviewDragger.findDestination($ele, 1)
expect(destination.ele).toBe($('#subsection-list-2'))
expect(destination.parentList).toBe($('#subsection-2'))
expect(destination.attachMethod).toBe('prepend')
describe "onDragStart", ->
it "sets the dragState to its default values", ->
expect(OverviewDragger.dragState).toEqual({})
expect(Overview.overviewDragger.dragState).toEqual({})
# Call with some dummy data
OverviewDragger.onDragStart(
Overview.overviewDragger.onDragStart(
{element: $('#unit-1')},
null,
null
)
expect(OverviewDragger.dragState).toEqual(
expect(Overview.overviewDragger.dragState).toEqual(
dropDestination: null,
attachMethod: '',
parentList: null,
......@@ -214,7 +214,7 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
it "collapses expanded elements", ->
expect($('#subsection-1')).not.toHaveClass('collapsed')
OverviewDragger.onDragStart(
Overview.overviewDragger.onDragStart(
{element: $('#subsection-1')},
null,
null
......@@ -233,7 +233,7 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
$ele.offset(
top: dragY, left: dragX
)
OverviewDragger.onDragMove(
Overview.overviewDragger.onDragMove(
{element: $ele, dragPoint:
{y: dragY}}, '', {clientX: dragX}
)
......@@ -246,7 +246,7 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
$ele.offset(
top: dragY, left: $ele.offset().left
)
OverviewDragger.onDragMove(
Overview.overviewDragger.onDragMove(
{element: $ele, dragPoint:
{y: dragY}}, '', {clientX: $ele.offset().left - 3}
)
......@@ -254,33 +254,33 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
expect($ele).not.toHaveClass('valid-drop')
it "scrolls up if necessary", ->
OverviewDragger.onDragMove(
Overview.overviewDragger.onDragMove(
{element: $('#unit-1')}, '', {clientY: 2}
)
expect(@scrollSpy).toHaveBeenCalledWith(0, -10)
it "scrolls down if necessary", ->
OverviewDragger.onDragMove(
Overview.overviewDragger.onDragMove(
{element: $('#unit-1')}, '', {clientY: (window.innerHeight - 5)}
)
expect(@scrollSpy).toHaveBeenCalledWith(0, 10)
describe "onDragEnd", ->
beforeEach ->
@reorderSpy = spyOn(OverviewDragger, 'handleReorder')
@reorderSpy = spyOn(Overview.overviewDragger, 'handleReorder')
afterEach ->
@reorderSpy.reset()
it "calls handleReorder on a successful drag", ->
OverviewDragger.dragState.dropDestination = $('#unit-2')
OverviewDragger.dragState.attachMethod = "before"
OverviewDragger.dragState.parentList = $('#subsection-1')
Overview.overviewDragger.dragState.dropDestination = $('#unit-2')
Overview.overviewDragger.dragState.attachMethod = "before"
Overview.overviewDragger.dragState.parentList = $('#subsection-1')
$('#unit-1').offset(
top: $('#unit-1').offset().top + 10
left: $('#unit-1').offset().left
)
OverviewDragger.onDragEnd(
Overview.overviewDragger.onDragEnd(
{element: $('#unit-1')},
null,
{clientX: $('#unit-1').offset().left}
......@@ -288,15 +288,15 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
expect(@reorderSpy).toHaveBeenCalled()
it "clears out the drag state", ->
OverviewDragger.onDragEnd(
Overview.overviewDragger.onDragEnd(
{element: $('#unit-1')},
null,
null
)
expect(OverviewDragger.dragState).toEqual({})
expect(Overview.overviewDragger.dragState).toEqual({})
it "sets the element to the correct position", ->
OverviewDragger.onDragEnd(
Overview.overviewDragger.onDragEnd(
{element: $('#unit-1')},
null,
null
......@@ -308,7 +308,7 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
it "expands an element if it was collapsed on drag start", ->
$('#subsection-1').addClass('collapsed')
$('#subsection-1').addClass('expand-on-drop')
OverviewDragger.onDragEnd(
Overview.overviewDragger.onDragEnd(
{element: $('#subsection-1')},
null,
null
......@@ -318,10 +318,10 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
it "expands a collapsed element when something is dropped in it", ->
$('#subsection-2').addClass('collapsed')
OverviewDragger.dragState.dropDestination = $('#list-2')
OverviewDragger.dragState.attachMethod = "prepend"
OverviewDragger.dragState.parentList = $('#subsection-2')
OverviewDragger.onDragEnd(
Overview.overviewDragger.dragState.dropDestination = $('#list-2')
Overview.overviewDragger.dragState.attachMethod = "prepend"
Overview.overviewDragger.dragState.parentList = $('#subsection-2')
Overview.overviewDragger.onDragEnd(
{element: $('#unit-1')},
null,
{clientX: $('#unit-1').offset().left}
......@@ -344,15 +344,15 @@ define ["js/views/overview", "js/views/feedback_notification", "sinon", "js/base
@clock.restore()
it "should send an update on reorder", ->
OverviewDragger.dragState.dropDestination = $('#unit-4')
OverviewDragger.dragState.attachMethod = "after"
OverviewDragger.dragState.parentList = $('#subsection-2')
Overview.overviewDragger.dragState.dropDestination = $('#unit-4')
Overview.overviewDragger.dragState.attachMethod = "after"
Overview.overviewDragger.dragState.parentList = $('#subsection-2')
# Drag Unit 1 from Subsection 1 to the end of Subsection 2.
$('#unit-1').offset(
top: $('#unit-4').offset().top + 10
left: $('#unit-4').offset().left
)
OverviewDragger.onDragEnd(
Overview.overviewDragger.onDragEnd(
{element: $('#unit-1')},
null,
{clientX: $('#unit-1').offset().left}
......
define ["backbone", "jquery", "underscore", "gettext", "xblock/runtime.v1",
"js/views/feedback_notification", "js/views/metadata", "js/collections/metadata"
"jquery.inputnumber", "xmodule"],
(Backbone, $, _, gettext, XBlock, NotificationView, MetadataView, MetadataCollection) ->
"js/utils/modal", "jquery.inputnumber", "xmodule"],
(Backbone, $, _, gettext, XBlock, NotificationView, MetadataView, MetadataCollection, ModalUtils) ->
class ModuleEdit extends Backbone.View
tagName: 'li'
className: 'component'
......@@ -87,7 +87,7 @@ define ["backbone", "jquery", "underscore", "gettext", "xblock/runtime.v1",
id: _this.model.id
data.metadata = _.extend(data.metadata || {}, @changedMetadata())
@hideModal()
ModalUtils.hideModalCover()
saving = new NotificationView.Mini
title: gettext('Saving&hellip;')
saving.show()
......@@ -102,17 +102,12 @@ define ["backbone", "jquery", "underscore", "gettext", "xblock/runtime.v1",
event.preventDefault()
@$el.removeClass('editing')
@$component_editor().slideUp(150)
@hideModal()
hideModal: ->
$modalCover = $(".modal-cover")
$modalCover.hide()
$modalCover.removeClass('is-fixed')
ModalUtils.hideModalCover()
clickEditButton: (event) ->
event.preventDefault()
@$el.addClass('editing')
$(".modal-cover").show().addClass('is-fixed')
ModalUtils.showModalCover(true)
@$component_editor().slideDown(150)
@loadEdit()
......
require(["domReady", "jquery", "underscore", "gettext", "js/views/feedback_notification", "js/views/feedback_prompt",
"js/utils/cancel_on_escape", "jquery.ui", "jquery.timepicker", "jquery.leanModal", "jquery.form", "jquery.smoothScroll"],
function(domReady, $, _, gettext, NotificationView, PromptView, CancelOnEscape) {
"js/utils/get_date", "jquery.ui", "jquery.leanModal", "jquery.form", "jquery.smoothScroll"],
function(domReady, $, _, gettext, NotificationView, PromptView, DateUtils) {
var $body;
var $modal;
var $modalCover;
var $newComponentItem;
var $changedInput;
var $spinner;
......@@ -14,8 +12,6 @@ var $newComponentButton;
domReady(function() {
$body = $('body');
$modal = $('.history-modal');
$modalCover = $('.modal-cover');
$newComponentItem = $('.new-component-item');
$newComponentTypePicker = $('.new-component');
......@@ -23,12 +19,6 @@ domReady(function() {
$newComponentButton = $('.new-component-button');
$spinner = $('<span class="spinner-in-field-icon"></span>');
$('.expand-collapse-icon').bind('click', toggleSubmodules);
$('.visibility-options').bind('change', setVisibility);
$modal.bind('click', hideModal);
$modalCover.bind('click', hideModal);
$body.on('click', '.embeddable-xml-input', function() {
$(this).select();
});
......@@ -70,7 +60,7 @@ domReady(function() {
$('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown');
$title.addClass('is-selected');
$subnav.addClass('is-shown');
// if propogation is not stopped, the event will bubble up to the
// if propagation is not stopped, the event will bubble up to the
// body element, which will close the dropdown.
e.stopPropagation();
}
......@@ -94,14 +84,6 @@ domReady(function() {
// tender feedback window scrolling
$('a.show-tender').bind('click', smoothScrollTop);
// toggling overview section details
$(function() {
if ($('.courseware-section').length > 0) {
$('.toggle-button-sections').addClass('is-shown');
}
});
$('.toggle-button-sections').bind('click', toggleSections);
// autosave when leaving input field
$body.on('change', '.subsection-display-name-input', saveSubsection);
$('.subsection-display-name-input').each(function() {
......@@ -113,12 +95,8 @@ domReady(function() {
// expand/collapse methods for optional date setters
$('.set-date').bind('click', showDateSetter);
$('.remove-date').bind('click', removeDateSetter);
// add new/delete section
$('.new-courseware-section-button').bind('click', addNewSection);
$('.delete-section-button').bind('click', deleteSection);
// add new/delete subsection
$('.new-subsection-item').bind('click', addNewSubsection);
$('.delete-section-button').bind('click', deleteSection);
$('.delete-subsection-button').bind('click', deleteSubsection);
$('.sync-date').bind('click', syncReleaseDate);
......@@ -126,12 +104,7 @@ domReady(function() {
// section date setting
$('.set-publish-date').bind('click', setSectionScheduleDate);
$('.edit-section-start-cancel').bind('click', cancelSetSectionScheduleDate);
$('.edit-section-start-save').bind('click', saveSetSectionScheduleDate);
$body.on('click', '.section-published-date .edit-button', editSectionPublishDate);
$body.on('click', '.section-published-date .schedule-button', editSectionPublishDate);
$body.on('click', '.edit-subsection-publish-settings .save-button', saveSetSectionScheduleDate);
$body.on('click', '.edit-subsection-publish-settings .cancel-button', hideModal);
$body.on('change', '.edit-subsection-publish-settings .start-date', function() {
if ($('.edit-subsection-publish-settings').find('.start-time').val() == '') {
$('.edit-subsection-publish-settings').find('.start-time').val('12:00am');
......@@ -171,44 +144,6 @@ function linkNewWindow(e) {
e.preventDefault();
}
function toggleSections(e) {
e.preventDefault();
$section = $('.courseware-section');
sectionCount = $section.length;
$button = $(this);
$labelCollapsed = $('<i class="icon-arrow-up"></i> <span class="label">' +
gettext('Collapse All Sections') + '</span>');
$labelExpanded = $('<i class="icon-arrow-down"></i> <span class="label">' +
gettext('Expand All Sections') + '</span>');
var buttonLabel = $button.hasClass('is-activated') ? $labelCollapsed : $labelExpanded;
$button.toggleClass('is-activated').html(buttonLabel);
if ($button.hasClass('is-activated')) {
$section.addClass('collapsed');
// first child in order to avoid the icons on the subsection lists which are not in the first child
$section.find('header .expand-collapse-icon').removeClass('collapse').addClass('expand');
} else {
$section.removeClass('collapsed');
// first child in order to avoid the icons on the subsection lists which are not in the first child
$section.find('header .expand-collapse-icon').removeClass('expand').addClass('collapse');
}
}
function editSectionPublishDate(e) {
e.preventDefault();
$modal = $('.edit-subsection-publish-settings').show();
$modal.attr('data-id', $(this).attr('data-id'));
$modal.find('.start-date').val($(this).attr('data-date'));
$modal.find('.start-time').val($(this).attr('data-time'));
if ($modal.find('.start-date').val() == '' && $modal.find('.start-time').val() == '') {
$modal.find('.save-button').hide();
}
$modal.find('.section-name').html('"' + $(this).closest('.courseware-section').find('.section-name-span').text() + '"');
$modalCover.show();
}
function syncReleaseDate(e) {
e.preventDefault();
$(this).closest('.notice').hide();
......@@ -216,21 +151,6 @@ function syncReleaseDate(e) {
$("#start_time").val("");
}
function getDatetime(datepickerInput, timepickerInput) {
// given a pair of inputs (datepicker and timepicker), return a JS Date
// object that corresponds to the datetime that they represent. Assume
// UTC timezone, NOT the timezone of the user's browser.
var date = $(datepickerInput).datepicker("getDate");
var time = $(timepickerInput).timepicker("getTime");
if(date && time) {
return new Date(Date.UTC(
date.getFullYear(), date.getMonth(), date.getDate(),
time.getHours(), time.getMinutes()
));
} else {
return null;
}
}
function autosaveInput(e) {
var self = this;
......@@ -272,7 +192,7 @@ function saveSubsection() {
// get datetimes for start and due, stick into metadata
_(["start", "due"]).each(function(name) {
var datetime = getDatetime(
var datetime = DateUtils(
document.getElementById(name+"_date"),
document.getElementById(name+"_time")
);
......@@ -381,30 +301,6 @@ function _deleteItem($el, type) {
confirm.show();
}
function hideModal(e) {
if (e) {
e.preventDefault();
}
// Unit editors do not want the modal cover to hide when users click outside
// of the editor. Users must press Cancel or Save to exit the editor.
// module_edit adds and removes the "is-fixed" class.
if (!$modalCover.hasClass("is-fixed")) {
$(".modal, .edit-subsection-publish-settings").hide();
$modalCover.hide();
}
}
function toggleSubmodules(e) {
e.preventDefault();
$(this).toggleClass('expand').toggleClass('collapse');
$(this).closest('.branch, .window').toggleClass('collapsed');
}
function setVisibility(e) {
$(this).find('.checked').removeClass('checked');
$(e.target).closest('.option').addClass('checked');
}
function showDateSetter(e) {
e.preventDefault();
var $block = $(this).closest('.due-date-input');
......@@ -422,7 +318,6 @@ function removeDateSetter(e) {
$block.find('.time').val('');
}
function hideNotification(e) {
(e).preventDefault();
$(this).closest('.wrapper-notification').removeClass('is-shown').addClass('is-hiding').attr('aria-hidden', 'true');
......@@ -433,101 +328,6 @@ function hideAlert(e) {
$(this).closest('.wrapper-alert').removeClass('is-shown');
}
function addNewSection(e) {
e.preventDefault();
$(e.target).addClass('disabled');
var $newSection = $($('#new-section-template').html());
var $cancelButton = $newSection.find('.new-section-name-cancel');
$('.courseware-overview').prepend($newSection);
$newSection.find('.new-section-name').focus().select();
$newSection.find('.section-name-form').bind('submit', saveNewSection);
$cancelButton.bind('click', cancelNewSection);
CancelOnEscape($cancelButton);
}
function saveNewSection(e) {
e.preventDefault();
var $saveButton = $(this).find('.new-section-name-save');
var parent = $saveButton.data('parent');
var category = $saveButton.data('category');
var display_name = $(this).find('.new-section-name').val();
analytics.track('Created a Section', {
'course': course_location_analytics,
'display_name': display_name
});
$.post('/create_item', {
'parent_location': parent,
'category': category,
'display_name': display_name
},
function(data) {
if (data.id != undefined) location.reload();
});
}
function cancelNewSection(e) {
e.preventDefault();
$('.new-courseware-section-button').removeClass('disabled');
$(this).parents('section.new-section').remove();
}
function addNewSubsection(e) {
e.preventDefault();
var $section = $(this).closest('.courseware-section');
var $newSubsection = $($('#new-subsection-template').html());
$section.find('.subsection-list > ol').append($newSubsection);
$section.find('.new-subsection-name-input').focus().select();
var $saveButton = $newSubsection.find('.new-subsection-name-save');
var $cancelButton = $newSubsection.find('.new-subsection-name-cancel');
var parent = $(this).parents("section.branch").data("id");
$saveButton.data('parent', parent);
$saveButton.data('category', $(this).data('category'));
$newSubsection.find('.new-subsection-form').bind('submit', saveNewSubsection);
$cancelButton.bind('click', cancelNewSubsection);
CancelOnEscape($cancelButton);
}
function saveNewSubsection(e) {
e.preventDefault();
var parent = $(this).find('.new-subsection-name-save').data('parent');
var category = $(this).find('.new-subsection-name-save').data('category');
var display_name = $(this).find('.new-subsection-name-input').val();
analytics.track('Created a Subsection', {
'course': course_location_analytics,
'display_name': display_name
});
$.post('/create_item', {
'parent_location': parent,
'category': category,
'display_name': display_name
},
function(data) {
if (data.id != undefined) {
location.reload();
}
});
}
function cancelNewSubsection(e) {
e.preventDefault();
$(this).parents('li.branch').remove();
}
function setSectionScheduleDate(e) {
e.preventDefault();
$(this).closest("h4").hide();
......@@ -540,65 +340,6 @@ function cancelSetSectionScheduleDate(e) {
$(this).parent().siblings("h4").show();
}
function saveSetSectionScheduleDate(e) {
e.preventDefault();
var datetime = getDatetime(
$('.edit-subsection-publish-settings .start-date'),
$('.edit-subsection-publish-settings .start-time')
);
var id = $modal.attr('data-id');
analytics.track('Edited Section Release Date', {
'course': course_location_analytics,
'id': id,
'start': datetime
});
var saving = new NotificationView.Mini({
title: gettext("Saving&hellip;")
});
saving.show();
// call into server to commit the new order
$.ajax({
url: "/save_item",
type: "POST",
dataType: "json",
contentType: "application/json",
data: JSON.stringify({
'id': id,
'metadata': {
'start': datetime
}
})
}).success(function() {
var pad2 = function(number) {
// pad a number to two places: useful for formatting months, days, hours, etc
// when displaying a date/time
return (number < 10 ? '0' : '') + number;
};
var $thisSection = $('.courseware-section[data-id="' + id + '"]');
var html = _.template(
'<span class="published-status">' +
'<strong>' + gettext("Will Release:") + '&nbsp;</strong>' +
gettext("{month}/{day}/{year} at {hour}:{minute} UTC") +
'</span>' +
'<a href="#" class="edit-button" data-date="{month}/{day}/{year}" data-time="{hour}:{minute}" data-id="{id}">' +
gettext("Edit") +
'</a>',
{year: datetime.getUTCFullYear(), month: pad2(datetime.getUTCMonth() + 1), day: pad2(datetime.getUTCDate()),
hour: pad2(datetime.getUTCHours()), minute: pad2(datetime.getUTCMinutes()),
id: id},
{interpolate: /\{(.+?)\}/g});
$thisSection.find('.section-published-date').html(html);
hideModal();
saving.hide();
});
}
// Add to window object for unit test (overview_spec).
window.saveSetSectionScheduleDate = saveSetSectionScheduleDate;
window.deleteSection = deleteSection;
}); // end require()
define(["jquery", "jquery.ui", "jquery.timepicker"], function($) {
var getDate = function (datepickerInput, timepickerInput) {
// given a pair of inputs (datepicker and timepicker), return a JS Date
// object that corresponds to the datetime.js that they represent. Assume
// UTC timezone, NOT the timezone of the user's browser.
var date = $(datepickerInput).datepicker("getDate");
var time = $(timepickerInput).timepicker("getTime");
if(date && time) {
return new Date(Date.UTC(
date.getFullYear(), date.getMonth(), date.getDate(),
time.getHours(), time.getMinutes()
));
} else {
return null;
}
};
return getDate;
});
define(["jquery"], function($) {
/**
* Hides the modal and modal cover, using the standard selectors.
* Note though that the class "is-fixed" on the modal cover
* prevents the closing operation.
*/
var hideModal = function(e) {
if (e) {
e.preventDefault();
}
var $modalCover = getModalCover();
// Unit editors (module_edit) do not want the modal cover to hide when users click outside
// of the editor. Users must press Cancel or Save to exit the editor.
if (!$modalCover.hasClass("is-fixed")) {
getModal().hide();
hideModalCover($modalCover);
}
};
/**
* Hides just the modal cover. Caller can pass in a specific
* element as the modal cover, otherwise the standard selector will be used.
*
* This method also unbinds the click handler on the modal cover.
*/
var hideModalCover = function (modalCover) {
if (modalCover == undefined) {
modalCover = getModalCover();
}
modalCover.hide();
modalCover.removeClass("is-fixed");
modalCover.unbind('click');
};
/**
* Shows the modal and modal cover, using the standard selectors.
*/
var showModal = function () {
getModal().show();
showModalCover();
};
/**
* Shows just the modal cover. The caller can optionally choose
* to have the class "is-fixed" added to the cover, and
* the user can also choose to specify a custom click handler
* for the modal cover.
*
* This method returns the modal cover element.
*/
var showModalCover = function(addFixed, clickHandler) {
var $modalCover = getModalCover();
$modalCover.show();
if (addFixed) {
$modalCover.addClass("is-fixed");
}
$modalCover.unbind('click');
if (clickHandler) {
$modalCover.bind('click', clickHandler);
}
else {
$modalCover.bind('click', hideModal);
}
return $modalCover;
};
var getModalCover = function () {
return $('.modal-cover');
};
var getModal = function () {
return $(".modal, .showAsModal");
};
return {
showModal: showModal,
hideModal: hideModal,
showModalCover: showModalCover,
hideModalCover: hideModalCover
};
});
define(["backbone", "underscore", "codemirror", "js/views/feedback_notification", "js/views/course_info_helper"],
function(Backbone, _, CodeMirror, NotificationView, CourseInfoHelper) {
define(["backbone", "underscore", "codemirror", "js/views/feedback_notification", "js/views/course_info_helper", "js/utils/modal"],
function(Backbone, _, CodeMirror, NotificationView, CourseInfoHelper, ModalUtils) {
var $modalCover = $(".modal-cover");
// the handouts view is dumb right now; it needs tied to a model and all that jazz
var CourseInfoHandoutsView = Backbone.View.extend({
// collection is CourseUpdateCollection
......@@ -47,10 +46,7 @@ define(["backbone", "underscore", "codemirror", "js/views/feedback_notification"
this.$codeMirror = CourseInfoHelper.editWithCodeMirror(
self.model, 'data', self.options['base_asset_url'], this.$editor.get(0));
$modalCover.show();
$modalCover.bind('click', function() {
self.closeEditor();
});
ModalUtils.showModalCover(false, function() { self.closeEditor() });
},
onSave: function(event) {
......@@ -81,8 +77,7 @@ define(["backbone", "underscore", "codemirror", "js/views/feedback_notification"
closeEditor: function() {
this.$form.hide();
$modalCover.unbind('click');
$modalCover.hide();
ModalUtils.hideModalCover();
this.$form.find('.CodeMirror').remove();
this.$codeMirror = null;
}
......
define(["backbone", "underscore", "codemirror", "js/models/course_update",
"js/views/feedback_prompt", "js/views/feedback_notification", "js/views/course_info_helper"],
function(Backbone, _, CodeMirror, CourseUpdateModel, PromptView, NotificationView, CourseInfoHelper) {
"js/views/feedback_prompt", "js/views/feedback_notification", "js/views/course_info_helper", "js/utils/modal"],
function(Backbone, _, CodeMirror, CourseUpdateModel, PromptView, NotificationView, CourseInfoHelper, ModalUtils) {
var CourseInfoUpdateView = Backbone.View.extend({
// collection is CourseUpdateCollection
......@@ -17,8 +17,6 @@ define(["backbone", "underscore", "codemirror", "js/models/course_update",
this.render();
// when the client refetches the updates as a whole, re-render them
this.listenTo(this.collection, 'reset', this.render);
this.$modalCover = $(".modal-cover");
},
render: function () {
......@@ -64,9 +62,9 @@ define(["backbone", "underscore", "codemirror", "js/models/course_update",
$newForm.addClass('editing');
this.$currentPost = $newForm.closest('li');
this.$modalCover.show();
this.$modalCover.bind('click', function() {
self.closeEditor(true);
// Variable stored for unit test.
this.$modalCover = ModalUtils.showModalCover(false, function() {
self.closeEditor(true)
});
$('.date').datepicker('destroy');
......@@ -91,7 +89,7 @@ define(["backbone", "underscore", "codemirror", "js/models/course_update",
ele.remove();
}
});
this.closeEditor();
this.closeEditor(false);
analytics.track('Saved Course Update', {
'course': course_location_analytics,
......@@ -121,10 +119,12 @@ define(["backbone", "underscore", "codemirror", "js/models/course_update",
this.$codeMirror = CourseInfoHelper.editWithCodeMirror(
targetModel, 'content', self.options['base_asset_url'], $textArea.get(0));
this.$modalCover.show();
this.$modalCover.bind('click', function() {
self.closeEditor(false);
});
// Variable stored for unit test.
this.$modalCover = ModalUtils.showModalCover(false,
function() {
self.closeEditor(false)
}
);
},
onDelete: function(event) {
......@@ -198,8 +198,7 @@ define(["backbone", "underscore", "codemirror", "js/models/course_update",
this.$currentPost.find('.CodeMirror').remove();
}
this.$modalCover.unbind('click');
this.$modalCover.hide();
ModalUtils.hideModalCover(this.$modalCover);
this.$codeMirror = null;
},
......
define(["domReady", "jquery", "jquery.ui", "gettext", "js/views/feedback_notification", "draggabilly"],
function (domReady, $, ui, gettext, NotificationView, Draggabilly) {
define(["domReady", "jquery", "jquery.ui", "underscore", "gettext", "js/views/feedback_notification", "draggabilly",
"js/utils/modal", "js/utils/cancel_on_escape", "js/utils/get_date"],
function (domReady, $, ui, _, gettext, NotificationView, Draggabilly, ModalUtils, CancelOnEscape, DateUtils) {
var modalSelector = '.edit-subsection-publish-settings';
var toggleSections = function(e) {
e.preventDefault();
var $section = $('.courseware-section');
var $button = $(this);
var $labelCollapsed = $('<i class="icon-arrow-up"></i> <span class="label">' +
gettext('Collapse All Sections') + '</span>');
var $labelExpanded = $('<i class="icon-arrow-down"></i> <span class="label">' +
gettext('Expand All Sections') + '</span>');
var buttonLabel = $button.hasClass('is-activated') ? $labelCollapsed : $labelExpanded;
$button.toggleClass('is-activated').html(buttonLabel);
if ($button.hasClass('is-activated')) {
$section.addClass('collapsed');
// first child in order to avoid the icons on the subsection lists which are not in the first child
$section.find('header .expand-collapse-icon').removeClass('collapse').addClass('expand');
} else {
$section.removeClass('collapsed');
// first child in order to avoid the icons on the subsection lists which are not in the first child
$section.find('header .expand-collapse-icon').removeClass('expand').addClass('collapse');
}
};
var toggleSubmodules = function(e) {
e.preventDefault();
$(this).toggleClass('expand').toggleClass('collapse');
$(this).closest('.branch, .window').toggleClass('collapsed');
};
var editSectionPublishDate = function (e) {
e.preventDefault();
var $modal = $(modalSelector);
$modal.attr('data-id', $(this).attr('data-id'));
$modal.find('.start-date').val($(this).attr('data-date'));
$modal.find('.start-time').val($(this).attr('data-time'));
if ($modal.find('.start-date').val() == '' && $modal.find('.start-time').val() == '') {
$modal.find('.save-button').hide();
}
$modal.find('.section-name').html('"' + $(this).closest('.courseware-section').find('.section-name-span').text() + '"');
ModalUtils.showModal();
};
var saveSetSectionScheduleDate = function (e) {
e.preventDefault();
var datetime = DateUtils(
$('.edit-subsection-publish-settings .start-date'),
$('.edit-subsection-publish-settings .start-time')
);
var id = $(modalSelector).attr('data-id');
analytics.track('Edited Section Release Date', {
'course': course_location_analytics,
'id': id,
'start': datetime
});
var saving = new NotificationView.Mini({
title: gettext("Saving&hellip;")
});
saving.show();
// call into server to commit the new order
$.ajax({
url: "/save_item",
type: "POST",
dataType: "json",
contentType: "application/json",
data: JSON.stringify({
'id': id,
'metadata': {
'start': datetime
}
})
}).success(function() {
var pad2 = function(number) {
// pad a number to two places: useful for formatting months, days, hours, etc
// when displaying a date/time
return (number < 10 ? '0' : '') + number;
};
var $thisSection = $('.courseware-section[data-id="' + id + '"]');
var html = _.template(
'<span class="published-status">' +
'<strong>' + gettext("Will Release:") + '&nbsp;</strong>' +
gettext("{month}/{day}/{year} at {hour}:{minute} UTC") +
'</span>' +
'<a href="#" class="edit-button" data-date="{month}/{day}/{year}" data-time="{hour}:{minute}" data-id="{id}">' +
gettext("Edit") +
'</a>',
{year: datetime.getUTCFullYear(), month: pad2(datetime.getUTCMonth() + 1), day: pad2(datetime.getUTCDate()),
hour: pad2(datetime.getUTCHours()), minute: pad2(datetime.getUTCMinutes()),
id: id},
{interpolate: /\{(.+?)\}/g});
$thisSection.find('.section-published-date').html(html);
ModalUtils.hideModal();
saving.hide();
});
};
var addNewSection = function (e) {
e.preventDefault();
$(e.target).addClass('disabled');
var $newSection = $($('#new-section-template').html());
var $cancelButton = $newSection.find('.new-section-name-cancel');
$('.courseware-overview').prepend($newSection);
$newSection.find('.new-section-name').focus().select();
$newSection.find('.section-name-form').bind('submit', saveNewSection);
$cancelButton.bind('click', cancelNewSection);
CancelOnEscape($cancelButton);
};
var saveNewSection = function (e) {
e.preventDefault();
var $saveButton = $(this).find('.new-section-name-save');
var parent = $saveButton.data('parent');
var category = $saveButton.data('category');
var display_name = $(this).find('.new-section-name').val();
analytics.track('Created a Section', {
'course': course_location_analytics,
'display_name': display_name
});
$.post('/create_item', {
'parent_location': parent,
'category': category,
'display_name': display_name
},
function(data) {
if (data.id != undefined) location.reload();
});
};
var cancelNewSection = function (e) {
e.preventDefault();
$('.new-courseware-section-button').removeClass('disabled');
$(this).parents('section.new-section').remove();
};
var addNewSubsection = function (e) {
e.preventDefault();
var $section = $(this).closest('.courseware-section');
var $newSubsection = $($('#new-subsection-template').html());
$section.find('.subsection-list > ol').append($newSubsection);
$section.find('.new-subsection-name-input').focus().select();
var $saveButton = $newSubsection.find('.new-subsection-name-save');
var $cancelButton = $newSubsection.find('.new-subsection-name-cancel');
var parent = $(this).parents("section.branch").data("id");
$saveButton.data('parent', parent);
$saveButton.data('category', $(this).data('category'));
$newSubsection.find('.new-subsection-form').bind('submit', saveNewSubsection);
$cancelButton.bind('click', cancelNewSubsection);
CancelOnEscape($cancelButton);
};
var saveNewSubsection = function (e) {
e.preventDefault();
var parent = $(this).find('.new-subsection-name-save').data('parent');
var category = $(this).find('.new-subsection-name-save').data('category');
var display_name = $(this).find('.new-subsection-name-input').val();
analytics.track('Created a Subsection', {
'course': course_location_analytics,
'display_name': display_name
});
$.post('/create_item', {
'parent_location': parent,
'category': category,
'display_name': display_name
},
function(data) {
if (data.id != undefined) {
location.reload();
}
});
};
var cancelNewSubsection = function (e) {
e.preventDefault();
$(this).parents('li.branch').remove();
};
var overviewDragger = {
droppableClasses: 'drop-target drop-target-prepend drop-target-before drop-target-after',
......@@ -295,6 +494,24 @@ define(["domReady", "jquery", "jquery.ui", "gettext", "js/views/feedback_notific
};
domReady(function() {
// toggling overview section details
$(function() {
if ($('.courseware-section').length > 0) {
$('.toggle-button-sections').addClass('is-shown');
}
});
$('.toggle-button-sections').bind('click', toggleSections);
$('.expand-collapse-icon').bind('click', toggleSubmodules);
var $body = $('body');
$body.on('click', '.section-published-date .edit-button', editSectionPublishDate);
$body.on('click', '.section-published-date .schedule-button', editSectionPublishDate);
$body.on('click', '.edit-subsection-publish-settings .save-button', saveSetSectionScheduleDate);
$body.on('click', '.edit-subsection-publish-settings .cancel-button', ModalUtils.hideModal);
$('.new-courseware-section-button').bind('click', addNewSection);
$('.new-subsection-item').bind('click', addNewSubsection);
// Section
overviewDragger.makeDraggable(
'.courseware-section',
......@@ -318,5 +535,8 @@ define(["domReady", "jquery", "jquery.ui", "gettext", "js/views/feedback_notific
);
});
return overviewDragger;
return {
overviewDragger: overviewDragger,
saveSetSectionScheduleDate: saveSetSectionScheduleDate
};
});
......@@ -18,29 +18,25 @@
<script type="text/javascript">
require(["domReady", "jquery", "gettext", "js/models/asset", "js/collections/asset",
"js/views/assets", "js/views/feedback_prompt",
"js/views/feedback_notification", "jquery.fileupload"],
function(domReady, $, gettext, AssetModel, AssetCollection, AssetsView, PromptView, NotificationView) {
"js/views/feedback_notification", "js/utils/modal", "jquery.fileupload"],
function(domReady, $, gettext, AssetModel, AssetCollection, AssetsView, PromptView, NotificationView, ModalUtils) {
var assets = new AssetCollection(${asset_list});
assets.url = "${update_asset_callback_url}";
var assetsView = new AssetsView({collection: assets, el: $('#asset_table_body')});
var $modal = $(".upload-modal");
var $modalCover = $(".modal-cover");
var hideModal = function (e) {
if (e) {
e.preventDefault();
}
$('.file-input').unbind('change.startUpload');
$modal.hide();
$modalCover.hide();
}
ModalUtils.hideModal();
};
var showUploadModal = function (e) {
e.preventDefault();
resetUploadModal();
$modal.show();
ModalUtils.showModal();
$('.file-input').bind('change', startUpload);
$('.upload-modal .file-chooser').fileupload({
dataType: 'json',
......@@ -63,8 +59,6 @@ require(["domReady", "jquery", "gettext", "js/models/asset", "js/collections/ass
}
});
$modalCover.show();
};
var showFileSelectionMenu = function(e) {
......
......@@ -225,7 +225,7 @@ require(["domReady!", "jquery", "js/models/location", "js/models/section", "js/v
</div>
<footer></footer>
<div class="edit-subsection-publish-settings">
<div class="edit-subsection-publish-settings showAsModal">
<div class="settings">
<h3>${_("Section Release Date")}</h3>
<div class="picker datepair">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment