Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
6e784d60
Commit
6e784d60
authored
Aug 07, 2013
by
David Baumgold
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #596 from edx/db/ff-subsection-datetime-bug
Fix Firefox subsection datetime bug
parents
2c78f062
97aaab9c
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
136 additions
and
72 deletions
+136
-72
cms/djangoapps/contentstore/features/section.feature
+1
-1
cms/djangoapps/contentstore/features/section.py
+9
-4
cms/djangoapps/contentstore/features/subsection.feature
+20
-4
cms/djangoapps/contentstore/features/subsection.py
+45
-15
cms/static/coffee/spec/views/overview_spec.coffee
+9
-11
cms/static/js/base.js
+43
-27
cms/static/js/views/overview.js
+1
-1
cms/templates/edit_subsection.html
+4
-5
cms/templates/overview.html
+4
-4
No files found.
cms/djangoapps/contentstore/features/section.feature
View file @
6e784d60
...
@@ -24,7 +24,7 @@ Feature: Create Section
...
@@ -24,7 +24,7 @@ Feature: Create Section
Given
I have opened a new course in Studio
Given
I have opened a new course in Studio
And
I have added a new section
And
I have added a new section
When
I click the Edit link for the release date
When
I click the Edit link for the release date
And
I s
ave a new section release date
And
I s
et the section release date to 12/25/2013
Then
the section release date is updated
Then
the section release date is updated
And
I see a
"saving"
notification
And
I see a
"saving"
notification
...
...
cms/djangoapps/contentstore/features/section.py
View file @
6e784d60
...
@@ -35,10 +35,15 @@ def i_click_the_edit_link_for_the_release_date(_step):
...
@@ -35,10 +35,15 @@ def i_click_the_edit_link_for_the_release_date(_step):
world
.
css_click
(
button_css
)
world
.
css_click
(
button_css
)
@step
(
'I save a new section release date$'
)
@step
(
'I set the section release date to ([0-9/-]+)( [0-9:]+)?'
)
def
i_save_a_new_section_release_date
(
_step
):
def
set_section_release_date
(
_step
,
datestring
,
timestring
):
set_date_and_time
(
'input.start-date.date.hasDatepicker'
,
'12/25/2013'
,
if
hasattr
(
timestring
,
"strip"
):
'input.start-time.time.ui-timepicker-input'
,
'00:00'
)
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'
)
world
.
browser
.
click_link_by_text
(
'Save'
)
...
...
cms/djangoapps/contentstore/features/subsection.feature
View file @
6e784d60
...
@@ -14,7 +14,7 @@ Feature: Create Subsection
...
@@ -14,7 +14,7 @@ Feature: Create Subsection
When
I click the New Subsection link
When
I click the New Subsection link
And
I enter a subsection name with a quote and click save
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
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
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)
Scenario
:
Assign grading type to a subsection and verify it is still shown after refresh (bug
#258)
...
@@ -27,10 +27,13 @@ Feature: Create Subsection
...
@@ -27,10 +27,13 @@ Feature: Create Subsection
Scenario
:
Set a due date in a different year (bug
#256)
Scenario
:
Set a due date in a different year (bug
#256)
Given
I have opened a new subsection in Studio
Given
I have opened a new subsection in Studio
And
I have set a release date and due date in different years
And I set the subsection release date to 12/25/2011 03
:
00
Then
I see the correct dates
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
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
Scenario
:
Delete a subsection
Given
I have opened a new course section in Studio
Given
I have opened a new course section in Studio
...
@@ -40,3 +43,16 @@ Feature: Create Subsection
...
@@ -40,3 +43,16 @@ Feature: Create Subsection
And
I press the
"subsection"
delete icon
And
I press the
"subsection"
delete icon
And
I confirm the prompt
And
I confirm the prompt
Then
the subsection does not exist
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
cms/djangoapps/contentstore/features/subsection.py
View file @
6e784d60
...
@@ -41,8 +41,8 @@ def i_save_subsection_name_with_quote(step):
...
@@ -41,8 +41,8 @@ def i_save_subsection_name_with_quote(step):
save_subsection_name
(
'Subsection With "Quote"'
)
save_subsection_name
(
'Subsection With "Quote"'
)
@step
(
'I click
to edit the subsection name
$'
)
@step
(
'I click
on the subsection
$'
)
def
i_click_to_edit_subsection_name
(
step
):
def
click_on_subsection
(
step
):
world
.
css_click
(
'span.subsection-name-value'
)
world
.
css_click
(
'span.subsection-name-value'
)
...
@@ -53,12 +53,28 @@ def i_see_complete_subsection_name_with_quote_in_editor(step):
...
@@ -53,12 +53,28 @@ def i_see_complete_subsection_name_with_quote_in_editor(step):
assert_equal
(
world
.
css_value
(
css
),
'Subsection With "Quote"'
)
assert_equal
(
world
.
css_value
(
css
),
'Subsection With "Quote"'
)
@step
(
'I have set a release date and due date in different years$'
)
@step
(
'I set the subsection release date to ([0-9/-]+)( [0-9:]+)?'
)
def
test_have_set_dates_in_different_years
(
step
):
def
set_subsection_release_date
(
_step
,
datestring
,
timestring
):
set_date_and_time
(
'input#start_date'
,
'12/25/2011'
,
'input#start_time'
,
'03:00'
)
if
hasattr
(
timestring
,
"strip"
):
world
.
css_click
(
'.set-date'
)
timestring
=
timestring
.
strip
()
# Use a year in the past so that current year will always be different.
if
not
timestring
:
set_date_and_time
(
'input#due_date'
,
'01/02/2012'
,
'input#due_time'
,
'04:00'
)
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$'
)
@step
(
'I mark it as Homework$'
)
...
@@ -72,6 +88,11 @@ def i_see_it_marked__as_homework(step):
...
@@ -72,6 +88,11 @@ def i_see_it_marked__as_homework(step):
assert_equal
(
world
.
css_value
(
".status-label"
),
'Homework'
)
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 ###################
############ ASSERTIONS ###################
...
@@ -91,16 +112,25 @@ def the_subsection_does_not_exist(step):
...
@@ -91,16 +112,25 @@ def the_subsection_does_not_exist(step):
assert
world
.
browser
.
is_element_not_present_by_css
(
css
)
assert
world
.
browser
.
is_element_not_present_by_css
(
css
)
@step
(
'I see the correct dates$'
)
@step
(
'I see the subsection release date is ([0-9/-]+)( [0-9:]+)?'
)
def
i_see_the_correct_dates
(
step
):
def
i_see_subsection_release
(
_step
,
datestring
,
timestring
):
assert_equal
(
'12/25/2011'
,
get_date
(
'input#start_date'
))
if
hasattr
(
timestring
,
"strip"
):
assert_equal
(
'03:00'
,
get_date
(
'input#start_time'
))
timestring
=
timestring
.
strip
()
assert_equal
(
'01/02/2012'
,
get_date
(
'input#due_date'
))
assert_equal
(
datestring
,
get_date
(
'input#start_date'
))
assert_equal
(
'04:00'
,
get_date
(
'input#due_time'
))
if
timestring
:
assert_equal
(
timestring
,
get_date
(
'input#start_time'
))
############ HELPER METHODS ###################
@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
):
def
get_date
(
css
):
return
world
.
css_find
(
css
)
.
first
.
value
.
strip
()
return
world
.
css_find
(
css
)
.
first
.
value
.
strip
()
...
...
cms/static/coffee/spec/views/overview_spec.coffee
View file @
6e784d60
describe
"Course Overview"
,
->
describe
"Course Overview"
,
->
beforeEach
->
beforeEach
->
appendSetFixtures
"""
_
.
each
[
"/static/js/vendor/date.js"
,
"/static/js/vendor/timepicker/jquery.timepicker.js"
,
"/jsi18n/"
],
(
path
)
->
<script src="/static/js/vendor/date.js"></script>
appendSetFixtures
"""
"""
<script type="text/javascript" src="
#{
path
}
"></script>
"""
appendSetFixtures
"""
<script type="text/javascript" src="/jsi18n/"></script>
"""
appendSetFixtures
"""
appendSetFixtures
"""
<div class="section-published-date">
<div class="section-published-date">
<span class="published-status">
<span class="published-status">
<strong>Will Release:</strong> 06/12/2013 at 04:00 UTC
<strong>Will Release:</strong> 06/12/2013 at 04:00 UTC
</span>
</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>
</div>
"""
#"
"""
appendSetFixtures
"""
appendSetFixtures
"""
<div class="edit-subsection-publish-settings">
<div class="edit-subsection-publish-settings">
...
@@ -38,7 +35,7 @@ describe "Course Overview", ->
...
@@ -38,7 +35,7 @@ describe "Course Overview", ->
<a href="#" class="save-button">Save</a><a href="#" class="cancel-button">Cancel</a>
<a href="#" class="save-button">Save</a><a href="#" class="cancel-button">Cancel</a>
</div>
</div>
</div>
</div>
"""
#"
"""
appendSetFixtures
"""
appendSetFixtures
"""
<section class="courseware-section branch" data-id="a-location-goes-here">
<section class="courseware-section branch" data-id="a-location-goes-here">
...
@@ -46,12 +43,13 @@ describe "Course Overview", ->
...
@@ -46,12 +43,13 @@ describe "Course Overview", ->
<a href="#" class="delete-section-button"></a>
<a href="#" class="delete-section-button"></a>
</li>
</li>
</section>
</section>
"""
#"
"""
spyOn
(
window
,
'saveSetSectionScheduleDate'
).
andCallThrough
()
spyOn
(
window
,
'saveSetSectionScheduleDate'
).
andCallThrough
()
# Have to do this here, as it normally gets bound in document.ready()
# Have to do this here, as it normally gets bound in document.ready()
$
(
'a.save-button'
).
click
(
saveSetSectionScheduleDate
)
$
(
'a.save-button'
).
click
(
saveSetSectionScheduleDate
)
$
(
'a.delete-section-button'
).
click
(
deleteSection
)
$
(
'a.delete-section-button'
).
click
(
deleteSection
)
$
(
".edit-subsection-publish-settings .start-date"
).
datepicker
()
@
notificationSpy
=
spyOn
(
CMS
.
Views
.
Notification
.
Mini
.
prototype
,
'show'
).
andCallThrough
()
@
notificationSpy
=
spyOn
(
CMS
.
Views
.
Notification
.
Mini
.
prototype
,
'show'
).
andCallThrough
()
window
.
analytics
=
jasmine
.
createSpyObj
(
'analytics'
,
[
'track'
])
window
.
analytics
=
jasmine
.
createSpyObj
(
'analytics'
,
[
'track'
])
...
...
cms/static/js/base.js
View file @
6e784d60
...
@@ -253,21 +253,20 @@ function syncReleaseDate(e) {
...
@@ -253,21 +253,20 @@ function syncReleaseDate(e) {
$
(
"#start_time"
).
val
(
""
);
$
(
"#start_time"
).
val
(
""
);
}
}
function
getEdxTimeFromDateTimeVals
(
date_val
,
time_val
)
{
function
getDatetime
(
datepickerInput
,
timepickerInput
)
{
if
(
date_val
!=
''
)
{
// given a pair of inputs (datepicker and timepicker), return a JS Date
if
(
time_val
==
''
)
time_val
=
'00:00'
;
// object that corresponds to the datetime that they represent. Assume
// UTC timezone, NOT the timezone of the user's browser.
return
new
Date
(
date_val
+
" "
+
time_val
+
"Z"
);
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
)
{
function
autosaveInput
(
e
)
{
...
@@ -307,9 +306,17 @@ function saveSubsection() {
...
@@ -307,9 +306,17 @@ function saveSubsection() {
metadata
[
$
(
el
).
data
(
"metadata-name"
)]
=
el
.
value
;
metadata
[
$
(
el
).
data
(
"metadata-name"
)]
=
el
.
value
;
}
}
// Piece back together the date/time UI elements into one date/time string
// get datetimes for start and due, stick into metadata
metadata
[
'start'
]
=
getEdxTimeFromDateTimeInputs
(
'start_date'
,
'start_time'
);
_
([
"start"
,
"due"
]).
each
(
function
(
name
)
{
metadata
[
'due'
]
=
getEdxTimeFromDateTimeInputs
(
'due_date'
,
'due_time'
);
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
({
$
.
ajax
({
url
:
"/save_item"
,
url
:
"/save_item"
,
...
@@ -772,21 +779,21 @@ function cancelSetSectionScheduleDate(e) {
...
@@ -772,21 +779,21 @@ function cancelSetSectionScheduleDate(e) {
function
saveSetSectionScheduleDate
(
e
)
{
function
saveSetSectionScheduleDate
(
e
)
{
e
.
preventDefault
();
e
.
preventDefault
();
var
input_date
=
$
(
'.edit-subsection-publish-settings .start-date'
).
val
();
var
datetime
=
getDatetime
(
var
input_time
=
$
(
'.edit-subsection-publish-settings .start-time'
).
val
();
$
(
'.edit-subsection-publish-settings .start-date'
),
$
(
'.edit-subsection-publish-settings .start-time'
)
var
start
=
getEdxTimeFromDateTimeVals
(
input_date
,
input_time
);
);
var
id
=
$modal
.
attr
(
'data-id'
);
var
id
=
$modal
.
attr
(
'data-id'
);
analytics
.
track
(
'Edited Section Release Date'
,
{
analytics
.
track
(
'Edited Section Release Date'
,
{
'course'
:
course_location_analytics
,
'course'
:
course_location_analytics
,
'id'
:
id
,
'id'
:
id
,
'start'
:
start
'start'
:
datetime
});
});
var
saving
=
new
CMS
.
Views
.
Notification
.
Mini
({
var
saving
=
new
CMS
.
Views
.
Notification
.
Mini
({
title
:
gettext
(
"Saving"
)
+
"…"
,
title
:
gettext
(
"Saving"
)
+
"…"
});
});
saving
.
show
();
saving
.
show
();
// call into server to commit the new order
// call into server to commit the new order
...
@@ -798,20 +805,29 @@ function saveSetSectionScheduleDate(e) {
...
@@ -798,20 +805,29 @@ function saveSetSectionScheduleDate(e) {
data
:
JSON
.
stringify
({
data
:
JSON
.
stringify
({
'id'
:
id
,
'id'
:
id
,
'metadata'
:
{
'metadata'
:
{
'start'
:
start
'start'
:
datetime
}
}
})
})
}).
success
(
function
()
{
}).
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
$thisSection
=
$
(
'.courseware-section[data-id="'
+
id
+
'"]'
);
var
html
=
_
.
template
(
var
html
=
_
.
template
(
'<span class="published-status">'
+
'<span class="published-status">'
+
'<strong>'
+
gettext
(
"Will Release:"
)
+
' </strong>'
+
'<strong>'
+
gettext
(
"Will Release:"
)
+
' </strong>'
+
gettext
(
"
<%= date %> at <%= time %>
UTC"
)
+
gettext
(
"
{month}/{day}/{year} at {hour}:{minute}
UTC"
)
+
'</span>'
+
'</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"
)
+
gettext
(
"Edit"
)
+
'</a>'
,
'</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
);
$thisSection
.
find
(
'.section-published-date'
).
html
(
html
);
hideModal
();
hideModal
();
saving
.
hide
();
saving
.
hide
();
...
...
cms/static/js/views/overview.js
View file @
6e784d60
...
@@ -148,7 +148,7 @@ function generateCheckHoverState(selectorsToOpen, selectorsToShove) {
...
@@ -148,7 +148,7 @@ function generateCheckHoverState(selectorsToOpen, selectorsToShove) {
}
}
});
});
}
}
;
}
}
function
removeHesitate
(
event
,
ui
)
{
function
removeHesitate
(
event
,
ui
)
{
...
...
cms/templates/edit_subsection.html
View file @
6e784d60
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
%
>
<
%
inherit
file=
"base.html"
/>
<
%
inherit
file=
"base.html"
/>
<
%!
<
%!
import
logging
import
logging
from
xmodule
.
util
.
date_utils
import
get_default_time_display
,
almost_same_datetime
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=
"title"
>
${_("CMS Subsection")}
</
%
block>
<
%
block
name=
"bodyclass"
>
is-signedin course subsection
</
%
block>
<
%
block
name=
"bodyclass"
>
is-signedin course subsection
</
%
block>
...
...
cms/templates/overview.html
View file @
6e784d60
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
%
>
<
%
inherit
file=
"base.html"
/>
<
%
inherit
file=
"base.html"
/>
<
%!
<
%!
import
logging
import
logging
from
xmodule
.
util
import
date_utils
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=
"title"
>
${_("Course Outline")}
</
%
block>
<
%
block
name=
"bodyclass"
>
is-signedin course outline
</
%
block>
<
%
block
name=
"bodyclass"
>
is-signedin course outline
</
%
block>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment