Merge pull request #596 from edx/db/ff-subsection-datetime-bug
Fix Firefox subsection datetime bug
This commit is contained in:
@@ -24,7 +24,7 @@ Feature: Create Section
|
||||
Given I have opened a new course in Studio
|
||||
And I have added a new section
|
||||
When I click the Edit link for the release date
|
||||
And I save a new section release date
|
||||
And I set the section release date to 12/25/2013
|
||||
Then the section release date is updated
|
||||
And I see a "saving" notification
|
||||
|
||||
|
||||
@@ -35,10 +35,15 @@ def i_click_the_edit_link_for_the_release_date(_step):
|
||||
world.css_click(button_css)
|
||||
|
||||
|
||||
@step('I save a new section release date$')
|
||||
def i_save_a_new_section_release_date(_step):
|
||||
set_date_and_time('input.start-date.date.hasDatepicker', '12/25/2013',
|
||||
'input.start-time.time.ui-timepicker-input', '00:00')
|
||||
@step('I set the section release date to ([0-9/-]+)( [0-9:]+)?')
|
||||
def set_section_release_date(_step, datestring, timestring):
|
||||
if hasattr(timestring, "strip"):
|
||||
timestring = timestring.strip()
|
||||
if not timestring:
|
||||
timestring = "00:00"
|
||||
set_date_and_time(
|
||||
'input.start-date.date.hasDatepicker', datestring,
|
||||
'input.start-time.time.ui-timepicker-input', timestring)
|
||||
world.browser.click_link_by_text('Save')
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ Feature: Create Subsection
|
||||
When I click the New Subsection link
|
||||
And I enter a subsection name with a quote and click save
|
||||
Then I see my subsection name with a quote on the Courseware page
|
||||
And I click to edit the subsection name
|
||||
And I click on the subsection
|
||||
Then I see the complete subsection name with a quote in the editor
|
||||
|
||||
Scenario: Assign grading type to a subsection and verify it is still shown after refresh (bug #258)
|
||||
@@ -27,10 +27,13 @@ Feature: Create Subsection
|
||||
|
||||
Scenario: Set a due date in a different year (bug #256)
|
||||
Given I have opened a new subsection in Studio
|
||||
And I have set a release date and due date in different years
|
||||
Then I see the correct dates
|
||||
And I set the subsection release date to 12/25/2011 03:00
|
||||
And I set the subsection due date to 01/02/2012 04:00
|
||||
Then I see the subsection release date is 12/25/2011 03:00
|
||||
And I see the subsection due date is 01/02/2012 04:00
|
||||
And I reload the page
|
||||
Then I see the correct dates
|
||||
Then I see the subsection release date is 12/25/2011 03:00
|
||||
And I see the subsection due date is 01/02/2012 04:00
|
||||
|
||||
Scenario: Delete a subsection
|
||||
Given I have opened a new course section in Studio
|
||||
@@ -40,3 +43,16 @@ Feature: Create Subsection
|
||||
And I press the "subsection" delete icon
|
||||
And I confirm the prompt
|
||||
Then the subsection does not exist
|
||||
|
||||
Scenario: Sync to Section
|
||||
Given I have opened a new course section in Studio
|
||||
And I click the Edit link for the release date
|
||||
And I set the section release date to 01/02/2103
|
||||
And I have added a new subsection
|
||||
And I click on the subsection
|
||||
And I set the subsection release date to 01/20/2103
|
||||
And I reload the page
|
||||
And I click the link to sync release date to section
|
||||
And I wait for "1" second
|
||||
And I reload the page
|
||||
Then I see the subsection release date is 01/02/2103
|
||||
|
||||
@@ -41,8 +41,8 @@ def i_save_subsection_name_with_quote(step):
|
||||
save_subsection_name('Subsection With "Quote"')
|
||||
|
||||
|
||||
@step('I click to edit the subsection name$')
|
||||
def i_click_to_edit_subsection_name(step):
|
||||
@step('I click on the subsection$')
|
||||
def click_on_subsection(step):
|
||||
world.css_click('span.subsection-name-value')
|
||||
|
||||
|
||||
@@ -53,12 +53,28 @@ def i_see_complete_subsection_name_with_quote_in_editor(step):
|
||||
assert_equal(world.css_value(css), 'Subsection With "Quote"')
|
||||
|
||||
|
||||
@step('I have set a release date and due date in different years$')
|
||||
def test_have_set_dates_in_different_years(step):
|
||||
set_date_and_time('input#start_date', '12/25/2011', 'input#start_time', '03:00')
|
||||
world.css_click('.set-date')
|
||||
# Use a year in the past so that current year will always be different.
|
||||
set_date_and_time('input#due_date', '01/02/2012', 'input#due_time', '04:00')
|
||||
@step('I set the subsection release date to ([0-9/-]+)( [0-9:]+)?')
|
||||
def set_subsection_release_date(_step, datestring, timestring):
|
||||
if hasattr(timestring, "strip"):
|
||||
timestring = timestring.strip()
|
||||
if not timestring:
|
||||
timestring = "00:00"
|
||||
set_date_and_time(
|
||||
'input#start_date', datestring,
|
||||
'input#start_time', timestring)
|
||||
|
||||
|
||||
@step('I set the subsection due date to ([0-9/-]+)( [0-9:]+)?')
|
||||
def set_subsection_due_date(_step, datestring, timestring):
|
||||
if hasattr(timestring, "strip"):
|
||||
timestring = timestring.strip()
|
||||
if not timestring:
|
||||
timestring = "00:00"
|
||||
if not world.css_visible('input#due_date'):
|
||||
world.css_click('.due-date-input .set-date')
|
||||
set_date_and_time(
|
||||
'input#due_date', datestring,
|
||||
'input#due_time', timestring)
|
||||
|
||||
|
||||
@step('I mark it as Homework$')
|
||||
@@ -72,6 +88,11 @@ def i_see_it_marked__as_homework(step):
|
||||
assert_equal(world.css_value(".status-label"), 'Homework')
|
||||
|
||||
|
||||
@step('I click the link to sync release date to section')
|
||||
def click_sync_release_date(step):
|
||||
world.css_click('.sync-date')
|
||||
|
||||
|
||||
############ ASSERTIONS ###################
|
||||
|
||||
|
||||
@@ -91,16 +112,25 @@ def the_subsection_does_not_exist(step):
|
||||
assert world.browser.is_element_not_present_by_css(css)
|
||||
|
||||
|
||||
@step('I see the correct dates$')
|
||||
def i_see_the_correct_dates(step):
|
||||
assert_equal('12/25/2011', get_date('input#start_date'))
|
||||
assert_equal('03:00', get_date('input#start_time'))
|
||||
assert_equal('01/02/2012', get_date('input#due_date'))
|
||||
assert_equal('04:00', get_date('input#due_time'))
|
||||
@step('I see the subsection release date is ([0-9/-]+)( [0-9:]+)?')
|
||||
def i_see_subsection_release(_step, datestring, timestring):
|
||||
if hasattr(timestring, "strip"):
|
||||
timestring = timestring.strip()
|
||||
assert_equal(datestring, get_date('input#start_date'))
|
||||
if timestring:
|
||||
assert_equal(timestring, get_date('input#start_time'))
|
||||
|
||||
|
||||
@step('I see the subsection due date is ([0-9/-]+)( [0-9:]+)?')
|
||||
def i_see_subsection_due(_step, datestring, timestring):
|
||||
if hasattr(timestring, "strip"):
|
||||
timestring = timestring.strip()
|
||||
assert_equal(datestring, get_date('input#due_date'))
|
||||
if timestring:
|
||||
assert_equal(timestring, get_date('input#due_time'))
|
||||
|
||||
|
||||
############ HELPER METHODS ###################
|
||||
|
||||
def get_date(css):
|
||||
return world.css_find(css).first.value.strip()
|
||||
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
describe "Course Overview", ->
|
||||
|
||||
beforeEach ->
|
||||
appendSetFixtures """
|
||||
<script src="/static/js/vendor/date.js"></script>
|
||||
"""
|
||||
|
||||
appendSetFixtures """
|
||||
<script type="text/javascript" src="/jsi18n/"></script>
|
||||
"""
|
||||
_.each ["/static/js/vendor/date.js", "/static/js/vendor/timepicker/jquery.timepicker.js", "/jsi18n/"], (path) ->
|
||||
appendSetFixtures """
|
||||
<script type="text/javascript" src="#{path}"></script>
|
||||
"""
|
||||
|
||||
appendSetFixtures """
|
||||
<div class="section-published-date">
|
||||
<span class="published-status">
|
||||
<strong>Will Release:</strong> 06/12/2013 at 04:00 UTC
|
||||
</span>
|
||||
<a href="#" class="edit-button" "="" data-date="06/12/2013" data-time="04:00" data-id="i4x://pfogg/42/chapter/d6b47f7b084f49debcaf67fe5436c8e2">Edit</a>
|
||||
<a href="#" class="edit-button" data-date="06/12/2013" data-time="04:00" data-id="i4x://pfogg/42/chapter/d6b47f7b084f49debcaf67fe5436c8e2">Edit</a>
|
||||
</div>
|
||||
"""#"
|
||||
"""
|
||||
|
||||
appendSetFixtures """
|
||||
<div class="edit-subsection-publish-settings">
|
||||
@@ -38,7 +35,7 @@ describe "Course Overview", ->
|
||||
<a href="#" class="save-button">Save</a><a href="#" class="cancel-button">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
"""#"
|
||||
"""
|
||||
|
||||
appendSetFixtures """
|
||||
<section class="courseware-section branch" data-id="a-location-goes-here">
|
||||
@@ -46,12 +43,13 @@ describe "Course Overview", ->
|
||||
<a href="#" class="delete-section-button"></a>
|
||||
</li>
|
||||
</section>
|
||||
"""#"
|
||||
"""
|
||||
|
||||
spyOn(window, 'saveSetSectionScheduleDate').andCallThrough()
|
||||
# Have to do this here, as it normally gets bound in document.ready()
|
||||
$('a.save-button').click(saveSetSectionScheduleDate)
|
||||
$('a.delete-section-button').click(deleteSection)
|
||||
$(".edit-subsection-publish-settings .start-date").datepicker()
|
||||
|
||||
@notificationSpy = spyOn(CMS.Views.Notification.Mini.prototype, 'show').andCallThrough()
|
||||
window.analytics = jasmine.createSpyObj('analytics', ['track'])
|
||||
|
||||
@@ -253,21 +253,20 @@ function syncReleaseDate(e) {
|
||||
$("#start_time").val("");
|
||||
}
|
||||
|
||||
function getEdxTimeFromDateTimeVals(date_val, time_val) {
|
||||
if (date_val != '') {
|
||||
if (time_val == '') time_val = '00:00';
|
||||
|
||||
return new Date(date_val + " " + time_val + "Z");
|
||||
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;
|
||||
}
|
||||
|
||||
else return null;
|
||||
}
|
||||
|
||||
function getEdxTimeFromDateTimeInputs(date_id, time_id) {
|
||||
var input_date = $('#' + date_id).val();
|
||||
var input_time = $('#' + time_id).val();
|
||||
|
||||
return getEdxTimeFromDateTimeVals(input_date, input_time);
|
||||
}
|
||||
|
||||
function autosaveInput(e) {
|
||||
@@ -307,9 +306,17 @@ function saveSubsection() {
|
||||
metadata[$(el).data("metadata-name")] = el.value;
|
||||
}
|
||||
|
||||
// Piece back together the date/time UI elements into one date/time string
|
||||
metadata['start'] = getEdxTimeFromDateTimeInputs('start_date', 'start_time');
|
||||
metadata['due'] = getEdxTimeFromDateTimeInputs('due_date', 'due_time');
|
||||
// get datetimes for start and due, stick into metadata
|
||||
_(["start", "due"]).each(function(name) {
|
||||
|
||||
var datetime = getDatetime(
|
||||
document.getElementById(name+"_date"),
|
||||
document.getElementById(name+"_time")
|
||||
);
|
||||
// if datetime is null, we want to set that in metadata anyway;
|
||||
// its an indication to the server to clear the datetime in the DB
|
||||
metadata[name] = datetime;
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: "/save_item",
|
||||
@@ -772,21 +779,21 @@ function cancelSetSectionScheduleDate(e) {
|
||||
function saveSetSectionScheduleDate(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var input_date = $('.edit-subsection-publish-settings .start-date').val();
|
||||
var input_time = $('.edit-subsection-publish-settings .start-time').val();
|
||||
|
||||
var start = getEdxTimeFromDateTimeVals(input_date, input_time);
|
||||
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': start
|
||||
'start': datetime
|
||||
});
|
||||
|
||||
var saving = new CMS.Views.Notification.Mini({
|
||||
title: gettext("Saving") + "…",
|
||||
title: gettext("Saving") + "…"
|
||||
});
|
||||
saving.show();
|
||||
// call into server to commit the new order
|
||||
@@ -798,20 +805,29 @@ function saveSetSectionScheduleDate(e) {
|
||||
data: JSON.stringify({
|
||||
'id': id,
|
||||
'metadata': {
|
||||
'start': start
|
||||
'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:") + ' </strong>' +
|
||||
gettext("<%= date %> at <%= time %> UTC") +
|
||||
gettext("{month}/{day}/{year} at {hour}:{minute} UTC") +
|
||||
'</span>' +
|
||||
'<a href="#" class="edit-button" data-date="<%= date %>" data-time="<%= time %>" data-id="<%= id %>">' +
|
||||
'<a href="#" class="edit-button" data-date="{month}/{day}/{year}" data-time="{hour}:{minute}" data-id="{id}">' +
|
||||
gettext("Edit") +
|
||||
'</a>',
|
||||
{date: input_date, time: input_time, id: id});
|
||||
{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();
|
||||
|
||||
@@ -148,7 +148,7 @@ function generateCheckHoverState(selectorsToOpen, selectorsToShove) {
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function removeHesitate(event, ui) {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%inherit file="base.html" />
|
||||
<%!
|
||||
import logging
|
||||
from xmodule.util.date_utils import get_default_time_display, almost_same_datetime
|
||||
import logging
|
||||
from xmodule.util.date_utils import get_default_time_display, almost_same_datetime
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
%>
|
||||
|
||||
<%! from django.core.urlresolvers import reverse %>
|
||||
<%block name="title">${_("CMS Subsection")}</%block>
|
||||
<%block name="bodyclass">is-signedin course subsection</%block>
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%inherit file="base.html" />
|
||||
<%!
|
||||
import logging
|
||||
from xmodule.util import date_utils
|
||||
import logging
|
||||
from xmodule.util import date_utils
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
%>
|
||||
<%! from django.core.urlresolvers import reverse %>
|
||||
<%block name="title">${_("Course Outline")}</%block>
|
||||
<%block name="bodyclass">is-signedin course outline</%block>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user