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
3a9dc5de
Commit
3a9dc5de
authored
Mar 09, 2017
by
Mushtaq Ali
Committed by
GitHub
Mar 09, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #14625 from edx/mushtaq/bug-bash-fixes
Move Bug fixes
parents
de29ef94
e83bee65
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
241 additions
and
135 deletions
+241
-135
cms/djangoapps/contentstore/views/item.py
+4
-2
cms/djangoapps/contentstore/views/tests/test_item.py
+18
-6
cms/static/js/models/xblock_info.js
+4
-0
cms/static/js/spec/views/move_xblock_spec.js
+79
-41
cms/static/js/spec/views/pages/container_spec.js
+3
-0
cms/static/js/spec/views/pages/container_subviews_spec.js
+3
-0
cms/static/js/views/modals/move_xblock_modal.js
+24
-34
cms/static/js/views/pages/container.js
+15
-5
cms/static/js/views/utils/move_xblock_utils.js
+36
-13
cms/static/js/views/utils/xblock_utils.js
+5
-2
common/test/acceptance/pages/studio/container.py
+12
-0
common/test/acceptance/tests/studio/test_studio_container.py
+38
-32
No files found.
cms/djangoapps/contentstore/views/item.py
View file @
3a9dc5de
...
@@ -739,6 +739,8 @@ def _move_item(source_usage_key, target_parent_usage_key, user, target_index=Non
...
@@ -739,6 +739,8 @@ def _move_item(source_usage_key, target_parent_usage_key, user, target_index=Non
error
=
'You can not move an item into itself.'
error
=
'You can not move an item into itself.'
elif
is_source_item_in_target_parents
(
source_item
,
target_parent
):
elif
is_source_item_in_target_parents
(
source_item
,
target_parent
):
error
=
'You can not move an item into it
\'
s child.'
error
=
'You can not move an item into it
\'
s child.'
elif
target_parent_type
==
'split_test'
:
error
=
'You can not move an item directly into content experiment.'
elif
source_index
is
None
:
elif
source_index
is
None
:
error
=
'{source_usage_key} not found in {parent_usage_key}.'
.
format
(
error
=
'{source_usage_key} not found in {parent_usage_key}.'
.
format
(
source_usage_key
=
unicode
(
source_usage_key
),
source_usage_key
=
unicode
(
source_usage_key
),
...
@@ -1119,7 +1121,8 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
...
@@ -1119,7 +1121,8 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
xblock_info
=
{
xblock_info
=
{
'id'
:
unicode
(
xblock
.
location
),
'id'
:
unicode
(
xblock
.
location
),
'display_name'
:
xblock
.
display_name_with_default
,
'display_name'
:
xblock
.
display_name_with_default
,
'category'
:
xblock
.
category
'category'
:
xblock
.
category
,
'has_children'
:
xblock
.
has_children
}
}
if
is_concise
:
if
is_concise
:
if
child_info
and
len
(
child_info
.
get
(
'children'
,
[]))
>
0
:
if
child_info
and
len
(
child_info
.
get
(
'children'
,
[]))
>
0
:
...
@@ -1127,7 +1130,6 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
...
@@ -1127,7 +1130,6 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
# Groups are labelled with their internal ids, rather than with the group name. Replace id with display name.
# Groups are labelled with their internal ids, rather than with the group name. Replace id with display name.
group_display_name
=
get_group_display_name
(
user_partitions
,
xblock_info
[
'display_name'
])
group_display_name
=
get_group_display_name
(
user_partitions
,
xblock_info
[
'display_name'
])
xblock_info
[
'display_name'
]
=
group_display_name
if
group_display_name
else
xblock_info
[
'display_name'
]
xblock_info
[
'display_name'
]
=
group_display_name
if
group_display_name
else
xblock_info
[
'display_name'
]
xblock_info
[
'has_children'
]
=
xblock
.
has_children
else
:
else
:
xblock_info
.
update
({
xblock_info
.
update
({
'edited_on'
:
get_default_time_display
(
xblock
.
subtree_edited_on
)
if
xblock
.
subtree_edited_on
else
None
,
'edited_on'
:
get_default_time_display
(
xblock
.
subtree_edited_on
)
if
xblock
.
subtree_edited_on
else
None
,
...
...
cms/djangoapps/contentstore/views/tests/test_item.py
View file @
3a9dc5de
...
@@ -948,17 +948,17 @@ class TestMoveItem(ItemTest):
...
@@ -948,17 +948,17 @@ class TestMoveItem(ItemTest):
"""
"""
Test invalid move.
Test invalid move.
"""
"""
parent_loc
=
self
.
store
.
get_parent_location
(
self
.
chapter
_usage_key
)
parent_loc
=
self
.
store
.
get_parent_location
(
self
.
html
_usage_key
)
response
=
self
.
_move_component
(
self
.
chapter_usage_key
,
self
.
usage_key
)
response
=
self
.
_move_component
(
self
.
html_usage_key
,
self
.
seq_
usage_key
)
self
.
assertEqual
(
response
.
status_code
,
400
)
self
.
assertEqual
(
response
.
status_code
,
400
)
response
=
json
.
loads
(
response
.
content
)
response
=
json
.
loads
(
response
.
content
)
expected_error
=
'You can not move {source_type} into {target_type}.'
.
format
(
expected_error
=
'You can not move {source_type} into {target_type}.'
.
format
(
source_type
=
self
.
chapter
_usage_key
.
block_type
,
source_type
=
self
.
html
_usage_key
.
block_type
,
target_type
=
self
.
usage_key
.
block_type
target_type
=
self
.
seq_
usage_key
.
block_type
)
)
self
.
assertEqual
(
expected_error
,
response
[
'error'
])
self
.
assertEqual
(
expected_error
,
response
[
'error'
])
new_parent_loc
=
self
.
store
.
get_parent_location
(
self
.
chapter
_usage_key
)
new_parent_loc
=
self
.
store
.
get_parent_location
(
self
.
html
_usage_key
)
self
.
assertEqual
(
new_parent_loc
,
parent_loc
)
self
.
assertEqual
(
new_parent_loc
,
parent_loc
)
def
test_move_current_parent
(
self
):
def
test_move_current_parent
(
self
):
...
@@ -1039,11 +1039,23 @@ class TestMoveItem(ItemTest):
...
@@ -1039,11 +1039,23 @@ class TestMoveItem(ItemTest):
def
test_move_into_content_experiment_groups
(
self
):
def
test_move_into_content_experiment_groups
(
self
):
"""
"""
Test that a component can be moved to content experiment.
Test that a component can be moved to content experiment
groups
.
"""
"""
split_test
=
self
.
setup_and_verify_content_experiment
(
0
)
split_test
=
self
.
setup_and_verify_content_experiment
(
0
)
self
.
assert_move_item
(
self
.
html_usage_key
,
split_test
.
children
[
0
])
self
.
assert_move_item
(
self
.
html_usage_key
,
split_test
.
children
[
0
])
def
test_can_not_move_into_content_experiment_level
(
self
):
"""
Test that a component can not be moved directly to content experiment level.
"""
self
.
setup_and_verify_content_experiment
(
0
)
response
=
self
.
_move_component
(
self
.
html_usage_key
,
self
.
split_test_usage_key
)
self
.
assertEqual
(
response
.
status_code
,
400
)
response
=
json
.
loads
(
response
.
content
)
self
.
assertEqual
(
response
[
'error'
],
'You can not move an item directly into content experiment.'
)
self
.
assertEqual
(
self
.
store
.
get_parent_location
(
self
.
html_usage_key
),
self
.
vert_usage_key
)
def
test_can_not_move_content_experiment_into_its_children
(
self
):
def
test_can_not_move_content_experiment_into_its_children
(
self
):
"""
"""
Test that a content experiment can not be moved inside any of it's children.
Test that a content experiment can not be moved inside any of it's children.
...
...
cms/static/js/models/xblock_info.js
View file @
3a9dc5de
...
@@ -50,6 +50,10 @@ function(Backbone, _, str, ModuleUtils) {
...
@@ -50,6 +50,10 @@ function(Backbone, _, str, ModuleUtils) {
*/
*/
'published_by'
:
null
,
'published_by'
:
null
,
/**
/**
* True if the xblock is a parentable xblock.
*/
has_children
:
null
,
/**
* True if the xblock has changes.
* True if the xblock has changes.
* Note: this is not always provided as a performance optimization. It is only provided for
* Note: this is not always provided as a performance optimization. It is only provided for
* verticals functioning as units.
* verticals functioning as units.
...
...
cms/static/js/spec/views/move_xblock_spec.js
View file @
3a9dc5de
define
([
'jquery'
,
'underscore'
,
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers'
,
define
([
'jquery'
,
'underscore'
,
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers'
,
'js/spec_helpers/edit_helpers'
,
'common/js/spec_helpers/template_helpers'
,
'common/js/spec_helpers/view_helpers'
,
'common/js/spec_helpers/template_helpers'
,
'common/js/spec_helpers/view_helpers'
,
'js/views/modals/move_xblock_modal'
,
'edx-ui-toolkit/js/utils/html-utils'
,
'js/views/modals/move_xblock_modal'
,
'
js/views/pages/container'
,
'
edx-ui-toolkit/js/utils/html-utils'
,
'edx-ui-toolkit/js/utils/string-utils'
,
'js/models/xblock_info'
],
'edx-ui-toolkit/js/utils/string-utils'
,
'js/models/xblock_info'
],
function
(
$
,
_
,
AjaxHelpers
,
TemplateHelpers
,
ViewHelpers
,
MoveXBlockModal
,
HtmlUtils
,
StringUtils
,
XBlockInfo
)
{
function
(
$
,
_
,
AjaxHelpers
,
EditHelpers
,
TemplateHelpers
,
ViewHelpers
,
MoveXBlockModal
,
ContainerPage
,
HtmlUtils
,
StringUtils
,
XBlockInfo
)
{
'use strict'
;
'use strict'
;
describe
(
'MoveXBlock'
,
function
()
{
describe
(
'MoveXBlock'
,
function
()
{
var
modal
,
showModal
,
renderViews
,
createXBlockInfo
,
createCourseOutline
,
courseOutlineOptions
,
var
modal
,
showModal
,
renderViews
,
createXBlockInfo
,
createCourseOutline
,
courseOutlineOptions
,
parentChildMap
,
categoryMap
,
createChildXBlockInfo
,
xblockAncestorInfo
,
courseOutline
,
parentChildMap
,
categoryMap
,
createChildXBlockInfo
,
xblockAncestorInfo
,
courseOutline
,
verifyBreadcrumbViewInfo
,
verifyListViewInfo
,
getDisplayedInfo
,
clickForwardButton
,
verifyBreadcrumbViewInfo
,
verifyListViewInfo
,
getDisplayedInfo
,
clickForwardButton
,
clickBreadcrumbButton
,
verifyXBlockInfo
,
nextCategory
,
verifyMoveEnabled
,
getSentRequests
,
clickBreadcrumbButton
,
verifyXBlockInfo
,
nextCategory
,
verifyMoveEnabled
,
getSentRequests
,
verifyNotificationStatus
,
sendMoveXBlockRequest
,
moveXBlockWithSuccess
,
verifyNotificationStatus
,
sendMoveXBlockRequest
,
moveXBlockWithSuccess
,
getMovedAlertNotification
,
verifyConfirmationFeedbackTitleHtml
,
verifyConfirmationFeedbackRedirectLinkHtml
,
verifyConfirmationFeedbackTitleText
,
verifyConfirmationFeedbackRedirectLinkText
,
verifyUndoConfirmationFeedbackTitleHtml
,
verifyConfirmationFeedbackUndoMoveActionHtml
,
verifyUndoConfirmationFeedbackTitleText
,
verifyConfirmationFeedbackUndoMoveActionText
,
sourceParentXBlockInfo
,
mockContainerPage
,
createContainerPage
,
containerPage
,
sourceDisplayName
=
'component_display_name_0'
,
sourceDisplayName
=
'component_display_name_0'
,
sourceLocator
=
'component_ID_0'
,
sourceLocator
=
'component_ID_0'
,
sourceParentLocator
=
'unit_ID_0'
;
sourceParentLocator
=
'unit_ID_0'
;
...
@@ -62,13 +64,31 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
...
@@ -62,13 +64,31 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
]
]
};
};
sourceParentXBlockInfo
=
new
XBlockInfo
({
id
:
sourceParentLocator
,
display_name
:
'unit_display_name_0'
,
category
:
'vertical'
});
createContainerPage
=
function
()
{
containerPage
=
new
ContainerPage
({
model
:
sourceParentXBlockInfo
,
templates
:
EditHelpers
.
mockComponentTemplates
,
el
:
$
(
'#content'
),
isUnitPage
:
true
});
};
beforeEach
(
function
()
{
beforeEach
(
function
()
{
setFixtures
(
"<div id='page-alert'></div>"
);
setFixtures
(
"<div id='page-alert'></div>"
);
mockContainerPage
=
readFixtures
(
'mock/mock-container-page.underscore'
);
TemplateHelpers
.
installTemplates
([
TemplateHelpers
.
installTemplates
([
'basic-modal'
,
'basic-modal'
,
'modal-button'
,
'modal-button'
,
'move-xblock-modal'
'move-xblock-modal'
]);
]);
appendSetFixtures
(
mockContainerPage
);
createContainerPage
();
courseOutline
=
createCourseOutline
(
courseOutlineOptions
);
courseOutline
=
createCourseOutline
(
courseOutlineOptions
);
showModal
();
showModal
();
});
});
...
@@ -76,6 +96,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
...
@@ -76,6 +96,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
afterEach
(
function
()
{
afterEach
(
function
()
{
modal
.
hide
();
modal
.
hide
();
courseOutline
=
null
;
courseOutline
=
null
;
containerPage
.
remove
();
});
});
showModal
=
function
()
{
showModal
=
function
()
{
...
@@ -85,11 +106,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
...
@@ -85,11 +106,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
display_name
:
sourceDisplayName
,
display_name
:
sourceDisplayName
,
category
:
'component'
category
:
'component'
}),
}),
sourceParentXBlockInfo
:
new
XBlockInfo
({
sourceParentXBlockInfo
:
sourceParentXBlockInfo
,
id
:
sourceParentLocator
,
display_name
:
'unit_display_name_0'
,
category
:
'vertical'
}),
XBlockUrlRoot
:
'/xblock'
XBlockUrlRoot
:
'/xblock'
});
});
modal
.
show
();
modal
.
show
();
...
@@ -339,6 +356,13 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
...
@@ -339,6 +356,13 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
};
};
/**
/**
* Get move alert confirmation message HTML
*/
getMovedAlertNotification
=
function
()
{
return
$
(
'#page-alert'
);
};
/**
* Send move xblock request.
* Send move xblock request.
*
*
* @param {Object} requests requests object
* @param {Object} requests requests object
...
@@ -384,19 +408,22 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
...
@@ -384,19 +408,22 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
});
});
modal
.
$el
.
find
(
'.modal-actions .action-move'
).
click
();
modal
.
$el
.
find
(
'.modal-actions .action-move'
).
click
();
sendMoveXBlockRequest
(
requests
,
sourceLocator
);
sendMoveXBlockRequest
(
requests
,
sourceLocator
);
expect
(
modal
.
movedAlertView
).
toBeDefined
();
AjaxHelpers
.
expectJsonRequest
(
requests
,
'GET'
,
'/xblock/'
+
sourceParentLocator
);
verifyConfirmationFeedbackTitleHtml
(
sourceDisplayName
);
AjaxHelpers
.
respondWithJson
(
requests
,
sourceParentXBlockInfo
);
verifyConfirmationFeedbackRedirectLinkHtml
();
expect
(
getMovedAlertNotification
().
html
().
length
).
not
.
toEqual
(
0
);
verifyConfirmationFeedbackUndoMoveActionHtml
();
verifyConfirmationFeedbackTitleText
(
sourceDisplayName
);
verifyConfirmationFeedbackRedirectLinkText
();
verifyConfirmationFeedbackUndoMoveActionText
();
};
};
/**
/**
* Verify success banner message html has correct title
html
.
* Verify success banner message html has correct title
text
.
*
*
* @param {String} displayName XBlock display name
* @param {String} displayName XBlock display name
*/
*/
verifyConfirmationFeedbackTitleHtml
=
function
(
displayName
)
{
verifyConfirmationFeedbackTitleText
=
function
(
displayName
)
{
expect
(
modal
.
movedAlertView
.
$el
.
find
(
'.title'
).
html
().
trim
())
expect
(
getMovedAlertNotification
().
find
(
'.title'
).
html
()
.
trim
())
.
toEqual
(
StringUtils
.
interpolate
(
'Success! "{displayName}" has been moved.'
,
.
toEqual
(
StringUtils
.
interpolate
(
'Success! "{displayName}" has been moved.'
,
{
{
displayName
:
displayName
displayName
:
displayName
...
@@ -405,12 +432,12 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
...
@@ -405,12 +432,12 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
};
};
/**
/**
* Verify undo success banner message html has correct title
html
.
* Verify undo success banner message html has correct title
text
.
*
*
* @param {String} displayName XBlock display name
* @param {String} displayName XBlock display name
*/
*/
verifyUndoConfirmationFeedbackTitle
Html
=
function
(
displayName
)
{
verifyUndoConfirmationFeedbackTitle
Text
=
function
(
displayName
)
{
expect
(
modal
.
movedAlertView
.
$el
.
find
(
'.title'
).
html
()).
toEqual
(
expect
(
getMovedAlertNotification
()
.
find
(
'.title'
).
html
()).
toEqual
(
StringUtils
.
interpolate
(
StringUtils
.
interpolate
(
'Move cancelled. "{sourceDisplayName}" has been moved back to its original location.'
,
'Move cancelled. "{sourceDisplayName}" has been moved back to its original location.'
,
{
{
...
@@ -421,25 +448,18 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
...
@@ -421,25 +448,18 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
};
};
/**
/**
* Verify success banner message html has correct redirect link
html
.
* Verify success banner message html has correct redirect link
text
.
*/
*/
verifyConfirmationFeedbackRedirectLinkHtml
=
function
()
{
verifyConfirmationFeedbackRedirectLinkText
=
function
()
{
expect
(
modal
.
movedAlertView
.
$el
.
find
(
'.copy'
).
html
().
indexOf
(
expect
(
getMovedAlertNotification
().
find
(
'.nav-actions .action-secondary'
).
html
())
HtmlUtils
.
HTML
(
.
toEqual
(
'Take me to the new location'
);
'<button class="action-secondary action-cancel">Take me to the new location</button>'
)
!==
-
1
)).
toBeTruthy
();
};
};
/**
/**
* Verify success banner message html has correct undo move
button html
.
* Verify success banner message html has correct undo move
text
.
*/
*/
verifyConfirmationFeedbackUndoMoveActionHtml
=
function
()
{
verifyConfirmationFeedbackUndoMoveActionText
=
function
()
{
expect
(
modal
.
movedAlertView
.
$el
.
find
(
'.copy'
).
html
().
indexOf
(
expect
(
getMovedAlertNotification
().
find
(
'.nav-actions .action-primary'
).
html
()).
toEqual
(
'Undo move'
);
HtmlUtils
.
HTML
(
'<button class="action-primary action-save">Undo Move</button>'
)
!==
-
1
)).
toBeTruthy
();
};
};
/**
/**
...
@@ -633,6 +653,24 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
...
@@ -633,6 +653,24 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
expect
(
modal
.
$el
.
find
(
'.modal-actions .action-move'
).
hasClass
(
'is-disabled'
)).
toBeFalsy
();
expect
(
modal
.
$el
.
find
(
'.modal-actions .action-move'
).
hasClass
(
'is-disabled'
)).
toBeFalsy
();
});
});
it
(
'is enabled when moving a component inside a parentable component'
,
function
()
{
// create a source parent with has_childern set true
modal
.
sourceParentXBlockInfo
=
new
XBlockInfo
({
category
:
'conditional'
,
display_name
:
'Parentable Component'
,
has_children
:
true
,
id
:
'PARENTABLE_ID'
});
// navigate and verify move button is enabled
renderViews
(
courseOutline
);
_
.
each
(
_
.
range
(
3
),
function
()
{
clickForwardButton
(
0
);
});
// move is enabled when moving a component.
expect
(
modal
.
$el
.
find
(
'.modal-actions .action-move'
).
hasClass
(
'is-disabled'
)).
toBeFalsy
();
});
it
(
'is disabled when navigating to any non-parentable component'
,
function
()
{
it
(
'is disabled when navigating to any non-parentable component'
,
function
()
{
var
nonParentableXBlockInfo
=
{
var
nonParentableXBlockInfo
=
{
category
:
'html'
,
category
:
'html'
,
...
@@ -651,7 +689,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
...
@@ -651,7 +689,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
it
(
'can not move in a disabled state'
,
function
()
{
it
(
'can not move in a disabled state'
,
function
()
{
verifyMoveEnabled
(
false
);
verifyMoveEnabled
(
false
);
modal
.
$el
.
find
(
'.modal-actions .action-move'
).
click
();
modal
.
$el
.
find
(
'.modal-actions .action-move'
).
click
();
expect
(
modal
.
movedAlertView
).
toBeNull
(
);
expect
(
getMovedAlertNotification
().
html
().
length
).
toEqual
(
0
);
expect
(
getSentRequests
().
length
).
toEqual
(
0
);
expect
(
getSentRequests
().
length
).
toEqual
(
0
);
});
});
...
@@ -662,7 +700,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
...
@@ -662,7 +700,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
it
(
'do not move an xblock when cancel button is clicked'
,
function
()
{
it
(
'do not move an xblock when cancel button is clicked'
,
function
()
{
modal
.
$el
.
find
(
'.modal-actions .action-cancel'
).
click
();
modal
.
$el
.
find
(
'.modal-actions .action-cancel'
).
click
();
expect
(
modal
.
movedAlertView
).
toBeNull
(
);
expect
(
getMovedAlertNotification
().
html
().
length
).
toEqual
(
0
);
expect
(
getSentRequests
().
length
).
toEqual
(
0
);
expect
(
getSentRequests
().
length
).
toEqual
(
0
);
});
});
...
@@ -670,13 +708,13 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
...
@@ -670,13 +708,13 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
var
sourceIndex
=
0
,
var
sourceIndex
=
0
,
requests
=
AjaxHelpers
.
requests
(
this
);
requests
=
AjaxHelpers
.
requests
(
this
);
moveXBlockWithSuccess
(
requests
);
moveXBlockWithSuccess
(
requests
);
modal
.
movedAlertView
.
$el
.
find
(
'.action-save'
).
click
();
getMovedAlertNotification
()
.
find
(
'.action-save'
).
click
();
AjaxHelpers
.
respondWithJson
(
requests
,
{
AjaxHelpers
.
respondWithJson
(
requests
,
{
move_source_locator
:
sourceLocator
,
move_source_locator
:
sourceLocator
,
parent_locator
:
sourceParentLocator
,
parent_locator
:
sourceParentLocator
,
target_index
:
sourceIndex
target_index
:
sourceIndex
});
});
verifyUndoConfirmationFeedbackTitle
Html
(
sourceDisplayName
);
verifyUndoConfirmationFeedbackTitle
Text
(
sourceDisplayName
);
});
});
});
});
...
@@ -698,7 +736,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
...
@@ -698,7 +736,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
requests
=
AjaxHelpers
.
requests
(
this
);
requests
=
AjaxHelpers
.
requests
(
this
);
moveXBlockWithSuccess
(
requests
);
moveXBlockWithSuccess
(
requests
);
notificationSpy
=
ViewHelpers
.
createNotificationSpy
();
notificationSpy
=
ViewHelpers
.
createNotificationSpy
();
modal
.
movedAlertView
.
$el
.
find
(
'.action-save'
).
click
();
getMovedAlertNotification
()
.
find
(
'.action-save'
).
click
();
verifyNotificationStatus
(
requests
,
notificationSpy
,
'Undo moving'
);
verifyNotificationStatus
(
requests
,
notificationSpy
,
'Undo moving'
);
});
});
...
@@ -719,7 +757,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
...
@@ -719,7 +757,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
var
requests
=
AjaxHelpers
.
requests
(
this
),
var
requests
=
AjaxHelpers
.
requests
(
this
),
notificationSpy
=
ViewHelpers
.
createNotificationSpy
(
'Error'
);
notificationSpy
=
ViewHelpers
.
createNotificationSpy
(
'Error'
);
moveXBlockWithSuccess
(
requests
);
moveXBlockWithSuccess
(
requests
);
modal
.
movedAlertView
.
$el
.
find
(
'.action-save'
).
click
();
getMovedAlertNotification
()
.
find
(
'.action-save'
).
click
();
AjaxHelpers
.
respondWithError
(
requests
);
AjaxHelpers
.
respondWithError
(
requests
);
ViewHelpers
.
verifyNotificationShowing
(
notificationSpy
,
"Studio's having trouble saving your work"
);
ViewHelpers
.
verifyNotificationShowing
(
notificationSpy
,
"Studio's having trouble saving your work"
);
});
});
...
...
cms/static/js/spec/views/pages/container_spec.js
View file @
3a9dc5de
...
@@ -49,6 +49,9 @@ define(['jquery', 'underscore', 'underscore.string', 'edx-ui-toolkit/js/utils/sp
...
@@ -49,6 +49,9 @@ define(['jquery', 'underscore', 'underscore.string', 'edx-ui-toolkit/js/utils/sp
afterEach
(
function
()
{
afterEach
(
function
()
{
EditHelpers
.
uninstallMockXBlock
();
EditHelpers
.
uninstallMockXBlock
();
if
(
containerPage
!==
undefined
)
{
containerPage
.
remove
();
}
});
});
respondWithHtml
=
function
(
html
)
{
respondWithHtml
=
function
(
html
)
{
...
...
cms/static/js/spec/views/pages/container_subviews_spec.js
View file @
3a9dc5de
...
@@ -35,6 +35,9 @@ define(['jquery', 'underscore', 'underscore.string', 'edx-ui-toolkit/js/utils/sp
...
@@ -35,6 +35,9 @@ define(['jquery', 'underscore', 'underscore.string', 'edx-ui-toolkit/js/utils/sp
afterEach
(
function
()
{
afterEach
(
function
()
{
delete
window
.
course
;
delete
window
.
course
;
if
(
containerPage
!==
undefined
)
{
containerPage
.
remove
();
}
});
});
defaultXBlockInfo
=
{
defaultXBlockInfo
=
{
...
...
cms/static/js/views/modals/move_xblock_modal.js
View file @
3a9dc5de
...
@@ -41,7 +41,6 @@ function($, Backbone, _, gettext, BaseView, XBlockViewUtils, MoveXBlockUtils, Ht
...
@@ -41,7 +41,6 @@ function($, Backbone, _, gettext, BaseView, XBlockViewUtils, MoveXBlockUtils, Ht
initialize
:
function
()
{
initialize
:
function
()
{
var
self
=
this
;
var
self
=
this
;
BaseModal
.
prototype
.
initialize
.
call
(
this
);
BaseModal
.
prototype
.
initialize
.
call
(
this
);
this
.
listenTo
(
Backbone
,
'move:breadcrumbRendered'
,
this
.
focusModal
);
this
.
sourceXBlockInfo
=
this
.
options
.
sourceXBlockInfo
;
this
.
sourceXBlockInfo
=
this
.
options
.
sourceXBlockInfo
;
this
.
sourceParentXBlockInfo
=
this
.
options
.
sourceParentXBlockInfo
;
this
.
sourceParentXBlockInfo
=
this
.
options
.
sourceParentXBlockInfo
;
this
.
targetParentXBlockInfo
=
null
;
this
.
targetParentXBlockInfo
=
null
;
...
@@ -57,9 +56,9 @@ function($, Backbone, _, gettext, BaseView, XBlockViewUtils, MoveXBlockUtils, Ht
...
@@ -57,9 +56,9 @@ function($, Backbone, _, gettext, BaseView, XBlockViewUtils, MoveXBlockUtils, Ht
$
(
'.breadcrumb-container'
).
removeClass
(
'is-hidden'
);
$
(
'.breadcrumb-container'
).
removeClass
(
'is-hidden'
);
self
.
renderViews
(
courseOutlineInfo
,
ancestorInfo
);
self
.
renderViews
(
courseOutlineInfo
,
ancestorInfo
);
});
});
this
.
movedAlertView
=
null
;
this
.
listenTo
(
Backbone
,
'move:breadcrumbRendered'
,
this
.
focusModal
);
this
.
isValidMove
=
false
;
this
.
listenTo
(
Backbone
,
'move:enableMoveOperation'
,
this
.
enableMoveOperation
);
this
.
listenTo
(
Backbone
,
'move:enableMoveOperation'
,
this
.
enableMoveOperation
);
this
.
listenTo
(
Backbone
,
'move:hideMoveModal'
,
this
.
hide
);
},
},
getTitle
:
function
()
{
getTitle
:
function
()
{
...
@@ -137,15 +136,22 @@ function($, Backbone, _, gettext, BaseView, XBlockViewUtils, MoveXBlockUtils, Ht
...
@@ -137,15 +136,22 @@ function($, Backbone, _, gettext, BaseView, XBlockViewUtils, MoveXBlockUtils, Ht
}
}
},
},
isValidCategory
:
function
(
sourceParentType
,
targetParentType
,
targetHasChildren
)
{
isValidCategory
:
function
(
targetParentXBlockInfo
)
{
var
basicBlockTypes
=
[
'course'
,
'chapter'
,
'sequential'
,
'vertical'
];
var
basicBlockTypes
=
[
'course'
,
'chapter'
,
'sequential'
,
'vertical'
],
sourceParentType
=
this
.
sourceParentXBlockInfo
.
get
(
'category'
),
targetParentType
=
targetParentXBlockInfo
.
get
(
'category'
),
sourceParentHasChildren
=
this
.
sourceParentXBlockInfo
.
get
(
'has_children'
),
targetParentHasChildren
=
targetParentXBlockInfo
.
get
(
'has_children'
);
// Treat source parent component as vertical to support move child components under content experiment
// Treat source parent component as vertical to support move child components under content experiment
// and other similar xblocks.
// and other similar xblocks.
// eslint-disable-next-line no-param-reassign
if
(
sourceParentHasChildren
&&
!
_
.
contains
(
basicBlockTypes
,
sourceParentType
))
{
sourceParentType
=
sourceParentType
===
'split_test'
?
'vertical'
:
sourceParentType
;
sourceParentType
=
'vertical'
;
// eslint-disable-line no-param-reassign
}
// Treat target parent component as a vertical to support move to parentable target parent components.
// Treat target parent component as a vertical to support move to parentable target parent components.
// Also, moving a component directly to content experiment is not allowed, we need to visit to group level.
// Also, moving a component directly to content experiment is not allowed, we need to visit to group level.
if
(
targetHasChildren
&&
!
_
.
contains
(
basicBlockTypes
,
targetParentType
)
&&
if
(
target
Parent
HasChildren
&&
!
_
.
contains
(
basicBlockTypes
,
targetParentType
)
&&
targetParentType
!==
'split_test'
)
{
targetParentType
!==
'split_test'
)
{
targetParentType
=
'vertical'
;
// eslint-disable-line no-param-reassign
targetParentType
=
'vertical'
;
// eslint-disable-line no-param-reassign
}
}
...
@@ -153,44 +159,28 @@ function($, Backbone, _, gettext, BaseView, XBlockViewUtils, MoveXBlockUtils, Ht
...
@@ -153,44 +159,28 @@ function($, Backbone, _, gettext, BaseView, XBlockViewUtils, MoveXBlockUtils, Ht
},
},
enableMoveOperation
:
function
(
targetParentXBlockInfo
)
{
enableMoveOperation
:
function
(
targetParentXBlockInfo
)
{
var
isValidMove
=
false
,
var
isValidMove
=
false
;
sourceParentType
=
this
.
sourceParentXBlockInfo
.
get
(
'category'
),
targetParentType
=
targetParentXBlockInfo
.
get
(
'category'
),
targetHasChildren
=
targetParentXBlockInfo
.
get
(
'has_children'
);
if
(
this
.
isValidCategory
(
sourceParentType
,
targetParentType
,
targetHasChildren
)
&&
// update target parent on navigation
this
.
targetParentXBlockInfo
=
targetParentXBlockInfo
;
if
(
this
.
isValidCategory
(
targetParentXBlockInfo
)
&&
this
.
sourceParentXBlockInfo
.
id
!==
targetParentXBlockInfo
.
id
&&
// same parent case
this
.
sourceParentXBlockInfo
.
id
!==
targetParentXBlockInfo
.
id
&&
// same parent case
this
.
sourceXBlockInfo
.
id
!==
targetParentXBlockInfo
.
id
)
{
// same source item case
this
.
sourceXBlockInfo
.
id
!==
targetParentXBlockInfo
.
id
)
{
// same source item case
isValidMove
=
true
;
isValidMove
=
true
;
this
.
targetParentXBlockInfo
=
targetParentXBlockInfo
;
}
}
this
.
updateMoveState
(
isValidMove
);
this
.
updateMoveState
(
isValidMove
);
},
},
moveXBlock
:
function
()
{
moveXBlock
:
function
()
{
var
self
=
this
;
MoveXBlockUtils
.
moveXBlock
(
XBlockViewUtils
.
moveXBlock
(
self
.
sourceXBlockInfo
.
id
,
self
.
targetParentXBlockInfo
.
id
)
.
done
(
function
(
response
)
{
// hide modal
self
.
hide
();
// hide xblock element
$
(
"li.studio-xblock-wrapper[data-locator='"
+
self
.
sourceXBlockInfo
.
id
+
"']"
).
hide
();
self
.
movedAlertView
=
MoveXBlockUtils
.
showMovedNotification
(
StringUtils
.
interpolate
(
gettext
(
'Success! "{displayName}" has been moved.'
),
{
{
displayName
:
self
.
sourceXBlockInfo
.
get
(
'display_name'
)
sourceXBlockElement
:
$
(
"li.studio-xblock-wrapper[data-locator='"
+
this
.
sourceXBlockInfo
.
id
+
"']"
),
}
sourceDisplayName
:
this
.
sourceXBlockInfo
.
get
(
'display_name'
),
),
sourceLocator
:
this
.
sourceXBlockInfo
.
id
,
{
sourceParentLocator
:
this
.
sourceParentXBlockInfo
.
id
,
sourceDisplayName
:
self
.
sourceXBlockInfo
.
get
(
'display_name'
),
targetParentLocator
:
this
.
targetParentXBlockInfo
.
id
sourceLocator
:
self
.
sourceXBlockInfo
.
id
,
sourceParentLocator
:
self
.
sourceParentXBlockInfo
.
id
,
targetParentLocator
:
response
.
parent_locator
,
targetIndex
:
response
.
source_index
}
}
);
);
});
}
}
});
});
...
...
cms/static/js/views/pages/container.js
View file @
3a9dc5de
...
@@ -2,11 +2,12 @@
...
@@ -2,11 +2,12 @@
* XBlockContainerPage is used to display Studio's container page for an xblock which has children.
* XBlockContainerPage is used to display Studio's container page for an xblock which has children.
* This page allows the user to understand and manipulate the xblock and its children.
* This page allows the user to understand and manipulate the xblock and its children.
*/
*/
define
([
'jquery'
,
'underscore'
,
'gettext'
,
'js/views/pages/base_page'
,
'common/js/components/utils/view_utils'
,
define
([
'jquery'
,
'underscore'
,
'backbone'
,
'gettext'
,
'js/views/pages/base_page'
,
'js/views/container'
,
'js/views/xblock'
,
'js/views/components/add_xblock'
,
'js/views/modals/edit_xblock'
,
'common/js/components/utils/view_utils'
,
'js/views/container'
,
'js/views/xblock'
,
'js/views/modals/move_xblock_modal'
,
'js/models/xblock_info'
,
'js/views/xblock_string_field_editor'
,
'js/views/components/add_xblock'
,
'js/views/modals/edit_xblock'
,
'js/views/modals/move_xblock_modal'
,
'js/views/pages/container_subviews'
,
'js/views/unit_outline'
,
'js/views/utils/xblock_utils'
],
'js/models/xblock_info'
,
'js/views/xblock_string_field_editor'
,
'js/views/pages/container_subviews'
,
function
(
$
,
_
,
gettext
,
BasePage
,
ViewUtils
,
ContainerView
,
XBlockView
,
AddXBlockComponent
,
'js/views/unit_outline'
,
'js/views/utils/xblock_utils'
],
function
(
$
,
_
,
Backbone
,
gettext
,
BasePage
,
ViewUtils
,
ContainerView
,
XBlockView
,
AddXBlockComponent
,
EditXBlockModal
,
MoveXBlockModal
,
XBlockInfo
,
XBlockStringFieldEditor
,
ContainerSubviews
,
EditXBlockModal
,
MoveXBlockModal
,
XBlockInfo
,
XBlockStringFieldEditor
,
ContainerSubviews
,
UnitOutlineView
,
XBlockUtils
)
{
UnitOutlineView
,
XBlockUtils
)
{
'use strict'
;
'use strict'
;
...
@@ -81,6 +82,8 @@ define(['jquery', 'underscore', 'gettext', 'js/views/pages/base_page', 'common/j
...
@@ -81,6 +82,8 @@ define(['jquery', 'underscore', 'gettext', 'js/views/pages/base_page', 'common/j
});
});
this
.
unitOutlineView
.
render
();
this
.
unitOutlineView
.
render
();
}
}
this
.
listenTo
(
Backbone
,
'move:onXBlockMoved'
,
this
.
onXBlockMoved
);
},
},
getViewParameters
:
function
()
{
getViewParameters
:
function
()
{
...
@@ -283,6 +286,13 @@ define(['jquery', 'underscore', 'gettext', 'js/views/pages/base_page', 'common/j
...
@@ -283,6 +286,13 @@ define(['jquery', 'underscore', 'gettext', 'js/views/pages/base_page', 'common/j
this
.
model
.
fetch
();
this
.
model
.
fetch
();
},
},
/*
After move operation is complete, updates the xblock information from server .
*/
onXBlockMoved
:
function
()
{
this
.
model
.
fetch
();
},
onNewXBlock
:
function
(
xblockElement
,
scrollOffset
,
is_duplicate
,
data
)
{
onNewXBlock
:
function
(
xblockElement
,
scrollOffset
,
is_duplicate
,
data
)
{
ViewUtils
.
setScrollOffset
(
xblockElement
,
scrollOffset
);
ViewUtils
.
setScrollOffset
(
xblockElement
,
scrollOffset
);
xblockElement
.
data
(
'locator'
,
data
.
locator
);
xblockElement
.
data
(
'locator'
,
data
.
locator
);
...
...
cms/static/js/views/utils/move_xblock_utils.js
View file @
3a9dc5de
...
@@ -4,25 +4,53 @@
...
@@ -4,25 +4,53 @@
define
([
define
([
'jquery'
,
'jquery'
,
'underscore'
,
'underscore'
,
'backbone'
,
'common/js/components/views/feedback'
,
'common/js/components/views/feedback'
,
'common/js/components/views/feedback_alert'
,
'common/js/components/views/feedback_alert'
,
'js/views/utils/xblock_utils'
,
'js/views/utils/xblock_utils'
,
'js/views/utils/move_xblock_utils'
,
'js/views/utils/move_xblock_utils'
,
'edx-ui-toolkit/js/utils/string-utils'
'edx-ui-toolkit/js/utils/string-utils'
],
],
function
(
$
,
_
,
Feedback
,
AlertView
,
XBlockViewUtils
,
MoveXBlockUtils
,
StringUtils
)
{
function
(
$
,
_
,
Backbone
,
Feedback
,
AlertView
,
XBlockViewUtils
,
MoveXBlockUtils
,
StringUtils
)
{
'use strict'
;
'use strict'
;
var
redirectLink
,
undoMoveXBlock
,
showMovedNotification
,
hideMovedNotification
;
var
redirectLink
,
moveXBlock
,
undoMoveXBlock
,
showMovedNotification
,
hideMovedNotification
;
redirectLink
=
function
(
link
)
{
redirectLink
=
function
(
link
)
{
window
.
location
.
href
=
link
;
window
.
location
.
href
=
link
;
};
};
moveXBlock
=
function
(
data
)
{
XBlockViewUtils
.
moveXBlock
(
data
.
sourceLocator
,
data
.
targetParentLocator
)
.
done
(
function
(
response
)
{
// hide modal
Backbone
.
trigger
(
'move:hideMoveModal'
);
// hide xblock element
data
.
sourceXBlockElement
.
hide
();
showMovedNotification
(
StringUtils
.
interpolate
(
gettext
(
'Success! "{displayName}" has been moved.'
),
{
displayName
:
data
.
sourceDisplayName
}
),
{
sourceXBlockElement
:
data
.
sourceXBlockElement
,
sourceDisplayName
:
data
.
sourceDisplayName
,
sourceLocator
:
data
.
sourceLocator
,
sourceParentLocator
:
data
.
sourceParentLocator
,
targetParentLocator
:
data
.
targetParentLocator
,
targetIndex
:
response
.
source_index
}
);
Backbone
.
trigger
(
'move:onXBlockMoved'
);
});
};
undoMoveXBlock
=
function
(
data
)
{
undoMoveXBlock
=
function
(
data
)
{
XBlockViewUtils
.
moveXBlock
(
data
.
sourceLocator
,
data
.
sourceParentLocator
,
data
.
targetIndex
)
XBlockViewUtils
.
moveXBlock
(
data
.
sourceLocator
,
data
.
sourceParentLocator
,
data
.
targetIndex
)
.
done
(
function
(
response
)
{
.
done
(
function
()
{
// show XBlock element
// show XBlock element
$
(
'.studio-xblock-wrapper[data-locator="'
+
response
.
move_source_locator
+
'"]'
)
.
show
();
data
.
sourceXBlockElement
.
show
();
showMovedNotification
(
showMovedNotification
(
StringUtils
.
interpolate
(
StringUtils
.
interpolate
(
gettext
(
'Move cancelled. "{sourceDisplayName}" has been moved back to its original location.'
),
gettext
(
'Move cancelled. "{sourceDisplayName}" has been moved back to its original location.'
),
...
@@ -31,6 +59,7 @@ function($, _, Feedback, AlertView, XBlockViewUtils, MoveXBlockUtils, StringUtil
...
@@ -31,6 +59,7 @@ function($, _, Feedback, AlertView, XBlockViewUtils, MoveXBlockUtils, StringUtil
}
}
)
)
);
);
Backbone
.
trigger
(
'move:onXBlockMoved'
);
});
});
};
};
...
@@ -44,15 +73,10 @@ function($, _, Feedback, AlertView, XBlockViewUtils, MoveXBlockUtils, StringUtil
...
@@ -44,15 +73,10 @@ function($, _, Feedback, AlertView, XBlockViewUtils, MoveXBlockUtils, StringUtil
primary
:
{
primary
:
{
text
:
gettext
(
'Undo move'
),
text
:
gettext
(
'Undo move'
),
class
:
'action-save'
,
class
:
'action-save'
,
data
:
JSON
.
stringify
({
sourceDisplayName
:
data
.
sourceDisplayName
,
sourceLocator
:
data
.
sourceLocator
,
sourceParentLocator
:
data
.
sourceParentLocator
,
targetIndex
:
data
.
targetIndex
}),
click
:
function
()
{
click
:
function
()
{
undoMoveXBlock
(
undoMoveXBlock
(
{
{
sourceXBlockElement
:
data
.
sourceXBlockElement
,
sourceDisplayName
:
data
.
sourceDisplayName
,
sourceDisplayName
:
data
.
sourceDisplayName
,
sourceLocator
:
data
.
sourceLocator
,
sourceLocator
:
data
.
sourceLocator
,
sourceParentLocator
:
data
.
sourceParentLocator
,
sourceParentLocator
:
data
.
sourceParentLocator
,
...
@@ -65,9 +89,6 @@ function($, _, Feedback, AlertView, XBlockViewUtils, MoveXBlockUtils, StringUtil
...
@@ -65,9 +89,6 @@ function($, _, Feedback, AlertView, XBlockViewUtils, MoveXBlockUtils, StringUtil
{
{
text
:
gettext
(
'Take me to the new location'
),
text
:
gettext
(
'Take me to the new location'
),
class
:
'action-cancel'
,
class
:
'action-cancel'
,
data
:
JSON
.
stringify
({
targetParentLocator
:
data
.
targetParentLocator
}),
click
:
function
()
{
click
:
function
()
{
redirectLink
(
'/container/'
+
data
.
targetParentLocator
);
redirectLink
(
'/container/'
+
data
.
targetParentLocator
);
}
}
...
@@ -100,6 +121,8 @@ function($, _, Feedback, AlertView, XBlockViewUtils, MoveXBlockUtils, StringUtil
...
@@ -100,6 +121,8 @@ function($, _, Feedback, AlertView, XBlockViewUtils, MoveXBlockUtils, StringUtil
return
{
return
{
redirectLink
:
redirectLink
,
redirectLink
:
redirectLink
,
moveXBlock
:
moveXBlock
,
undoMoveXBlock
:
undoMoveXBlock
,
showMovedNotification
:
showMovedNotification
,
showMovedNotification
:
showMovedNotification
,
hideMovedNotification
:
hideMovedNotification
hideMovedNotification
:
hideMovedNotification
};
};
...
...
cms/static/js/views/utils/xblock_utils.js
View file @
3a9dc5de
...
@@ -272,7 +272,8 @@ define(['jquery', 'underscore', 'gettext', 'common/js/components/utils/view_util
...
@@ -272,7 +272,8 @@ define(['jquery', 'underscore', 'gettext', 'common/js/components/utils/view_util
findXBlockInfo
=
function
(
xblockWrapperElement
,
defaultXBlockInfo
)
{
findXBlockInfo
=
function
(
xblockWrapperElement
,
defaultXBlockInfo
)
{
var
xblockInfo
=
defaultXBlockInfo
,
var
xblockInfo
=
defaultXBlockInfo
,
xblockElement
,
xblockElement
,
displayName
;
displayName
,
hasChildren
;
if
(
xblockWrapperElement
.
length
>
0
)
{
if
(
xblockWrapperElement
.
length
>
0
)
{
xblockElement
=
xblockWrapperElement
.
find
(
'.xblock'
);
xblockElement
=
xblockWrapperElement
.
find
(
'.xblock'
);
displayName
=
xblockWrapperElement
.
find
(
displayName
=
xblockWrapperElement
.
find
(
...
@@ -283,11 +284,13 @@ define(['jquery', 'underscore', 'gettext', 'common/js/components/utils/view_util
...
@@ -283,11 +284,13 @@ define(['jquery', 'underscore', 'gettext', 'common/js/components/utils/view_util
if
(
!
displayName
)
{
if
(
!
displayName
)
{
displayName
=
xblockElement
.
find
(
'.component-header'
).
text
().
trim
();
displayName
=
xblockElement
.
find
(
'.component-header'
).
text
().
trim
();
}
}
hasChildren
=
defaultXBlockInfo
?
defaultXBlockInfo
.
get
(
'has_children'
)
:
false
;
xblockInfo
=
new
XBlockInfo
({
xblockInfo
=
new
XBlockInfo
({
id
:
xblockWrapperElement
.
data
(
'locator'
),
id
:
xblockWrapperElement
.
data
(
'locator'
),
courseKey
:
xblockWrapperElement
.
data
(
'course-key'
),
courseKey
:
xblockWrapperElement
.
data
(
'course-key'
),
category
:
xblockElement
.
data
(
'block-type'
),
category
:
xblockElement
.
data
(
'block-type'
),
display_name
:
displayName
display_name
:
displayName
,
has_children
:
hasChildren
});
});
}
}
return
xblockInfo
;
return
xblockInfo
;
...
...
common/test/acceptance/pages/studio/container.py
View file @
3a9dc5de
...
@@ -229,6 +229,18 @@ class ContainerPage(PageObject, HelpMixin):
...
@@ -229,6 +229,18 @@ class ContainerPage(PageObject, HelpMixin):
self
.
q
(
css
=
'.button-view'
)
.
first
.
click
()
self
.
q
(
css
=
'.button-view'
)
.
first
.
click
()
self
.
_switch_to_lms
()
self
.
_switch_to_lms
()
def
verify_publish_title
(
self
,
expected_title
):
"""
Waits for the publish title to change to the expected value.
"""
def
wait_for_title_change
():
"""
Promise function to check publish title.
"""
return
(
self
.
publish_title
==
expected_title
,
self
.
publish_title
)
Promise
(
wait_for_title_change
,
"Publish title incorrect. Found '"
+
self
.
publish_title
+
"'"
)
.
fulfill
()
def
preview
(
self
):
def
preview
(
self
):
"""
"""
Clicks "Preview", which will open the draft version of the unit page in the LMS.
Clicks "Preview", which will open the draft version of the unit page in the LMS.
...
...
common/test/acceptance/tests/studio/test_studio_container.py
View file @
3a9dc5de
...
@@ -664,7 +664,7 @@ class UnitPublishingTest(ContainerBase):
...
@@ -664,7 +664,7 @@ class UnitPublishingTest(ContainerBase):
And the last saved text contains "Last published"
And the last saved text contains "Last published"
"""
"""
unit
=
self
.
go_to_unit_page
()
unit
=
self
.
go_to_unit_page
()
self
.
_verify_publish_title
(
unit
,
self
.
PUBLISHED_LIVE_STATUS
)
unit
.
verify_publish_title
(
self
.
PUBLISHED_LIVE_STATUS
)
# Start date set in course fixture to 1970.
# Start date set in course fixture to 1970.
self
.
_verify_release_date_info
(
self
.
_verify_release_date_info
(
unit
,
self
.
RELEASE_TITLE_RELEASED
,
'Jan 01, 1970 at 00:00 UTC
\n
with Section "Test Section"'
unit
,
self
.
RELEASE_TITLE_RELEASED
,
'Jan 01, 1970 at 00:00 UTC
\n
with Section "Test Section"'
...
@@ -675,11 +675,11 @@ class UnitPublishingTest(ContainerBase):
...
@@ -675,11 +675,11 @@ class UnitPublishingTest(ContainerBase):
# Add a component to the page so it will have unpublished changes.
# Add a component to the page so it will have unpublished changes.
add_discussion
(
unit
)
add_discussion
(
unit
)
self
.
_verify_publish_title
(
unit
,
self
.
DRAFT_STATUS
)
unit
.
verify_publish_title
(
self
.
DRAFT_STATUS
)
self
.
_verify_last_published_and_saved
(
unit
,
self
.
LAST_PUBLISHED
,
self
.
LAST_SAVED
)
self
.
_verify_last_published_and_saved
(
unit
,
self
.
LAST_PUBLISHED
,
self
.
LAST_SAVED
)
unit
.
publish_action
.
click
()
unit
.
publish_action
.
click
()
unit
.
wait_for_ajax
()
unit
.
wait_for_ajax
()
self
.
_verify_publish_title
(
unit
,
self
.
PUBLISHED_LIVE_STATUS
)
unit
.
verify_publish_title
(
self
.
PUBLISHED_LIVE_STATUS
)
self
.
_verify_last_published_and_saved
(
unit
,
self
.
LAST_PUBLISHED
,
self
.
LAST_PUBLISHED
)
self
.
_verify_last_published_and_saved
(
unit
,
self
.
LAST_PUBLISHED
,
self
.
LAST_PUBLISHED
)
def
test_discard_changes
(
self
):
def
test_discard_changes
(
self
):
...
@@ -696,9 +696,9 @@ class UnitPublishingTest(ContainerBase):
...
@@ -696,9 +696,9 @@ class UnitPublishingTest(ContainerBase):
"""
"""
unit
=
self
.
go_to_unit_page
()
unit
=
self
.
go_to_unit_page
()
add_discussion
(
unit
)
add_discussion
(
unit
)
self
.
_verify_publish_title
(
unit
,
self
.
DRAFT_STATUS
)
unit
.
verify_publish_title
(
self
.
DRAFT_STATUS
)
unit
.
discard_changes
()
unit
.
discard_changes
()
self
.
_verify_publish_title
(
unit
,
self
.
PUBLISHED_LIVE_STATUS
)
unit
.
verify_publish_title
(
self
.
PUBLISHED_LIVE_STATUS
)
def
test_view_live_no_changes
(
self
):
def
test_view_live_no_changes
(
self
):
"""
"""
...
@@ -757,7 +757,7 @@ class UnitPublishingTest(ContainerBase):
...
@@ -757,7 +757,7 @@ class UnitPublishingTest(ContainerBase):
Then I see the content in the unit
Then I see the content in the unit
"""
"""
unit
=
self
.
go_to_unit_page
(
"Unlocked Section"
,
"Unlocked Subsection"
,
"Unlocked Unit"
)
unit
=
self
.
go_to_unit_page
(
"Unlocked Section"
,
"Unlocked Subsection"
,
"Unlocked Unit"
)
self
.
_verify_publish_title
(
unit
,
self
.
PUBLISHED_LIVE_STATUS
)
unit
.
verify_publish_title
(
self
.
PUBLISHED_LIVE_STATUS
)
self
.
assertTrue
(
unit
.
currently_visible_to_students
)
self
.
assertTrue
(
unit
.
currently_visible_to_students
)
self
.
_verify_release_date_info
(
self
.
_verify_release_date_info
(
unit
,
self
.
RELEASE_TITLE_RELEASED
,
self
.
past_start_date_text
+
'
\n
'
+
'with Section "Unlocked Section"'
unit
,
self
.
RELEASE_TITLE_RELEASED
,
self
.
past_start_date_text
+
'
\n
'
+
'with Section "Unlocked Section"'
...
@@ -783,7 +783,7 @@ class UnitPublishingTest(ContainerBase):
...
@@ -783,7 +783,7 @@ class UnitPublishingTest(ContainerBase):
self
.
assertTrue
(
checked
)
self
.
assertTrue
(
checked
)
self
.
assertFalse
(
unit
.
currently_visible_to_students
)
self
.
assertFalse
(
unit
.
currently_visible_to_students
)
self
.
assertFalse
(
unit
.
shows_inherited_staff_lock
())
self
.
assertFalse
(
unit
.
shows_inherited_staff_lock
())
self
.
_verify_publish_title
(
unit
,
self
.
LOCKED_STATUS
)
unit
.
verify_publish_title
(
self
.
LOCKED_STATUS
)
self
.
_view_published_version
(
unit
)
self
.
_view_published_version
(
unit
)
# Will initially be in staff view, locked component should be visible.
# Will initially be in staff view, locked component should be visible.
self
.
_verify_components_visible
([
'problem'
])
self
.
_verify_components_visible
([
'problem'
])
...
@@ -802,7 +802,7 @@ class UnitPublishingTest(ContainerBase):
...
@@ -802,7 +802,7 @@ class UnitPublishingTest(ContainerBase):
Then I do not see any content in the unit
Then I do not see any content in the unit
"""
"""
unit
=
self
.
go_to_unit_page
(
"Section With Locked Unit"
,
"Subsection With Locked Unit"
,
"Locked Unit"
)
unit
=
self
.
go_to_unit_page
(
"Section With Locked Unit"
,
"Subsection With Locked Unit"
,
"Locked Unit"
)
self
.
_verify_publish_title
(
unit
,
self
.
LOCKED_STATUS
)
unit
.
verify_publish_title
(
self
.
LOCKED_STATUS
)
self
.
assertFalse
(
unit
.
currently_visible_to_students
)
self
.
assertFalse
(
unit
.
currently_visible_to_students
)
self
.
_verify_release_date_info
(
self
.
_verify_release_date_info
(
unit
,
self
.
RELEASE_TITLE_RELEASE
,
unit
,
self
.
RELEASE_TITLE_RELEASE
,
...
@@ -826,7 +826,7 @@ class UnitPublishingTest(ContainerBase):
...
@@ -826,7 +826,7 @@ class UnitPublishingTest(ContainerBase):
unit
=
self
.
go_to_unit_page
(
"Section With Locked Unit"
,
"Subsection With Locked Unit"
,
"Locked Unit"
)
unit
=
self
.
go_to_unit_page
(
"Section With Locked Unit"
,
"Subsection With Locked Unit"
,
"Locked Unit"
)
checked
=
unit
.
toggle_staff_lock
()
checked
=
unit
.
toggle_staff_lock
()
self
.
assertFalse
(
checked
)
self
.
assertFalse
(
checked
)
self
.
_verify_publish_title
(
unit
,
self
.
PUBLISHED_LIVE_STATUS
)
unit
.
verify_publish_title
(
self
.
PUBLISHED_LIVE_STATUS
)
self
.
assertTrue
(
unit
.
currently_visible_to_students
)
self
.
assertTrue
(
unit
.
currently_visible_to_students
)
self
.
_view_published_version
(
unit
)
self
.
_view_published_version
(
unit
)
# Will initially be in staff view, components always visible.
# Will initially be in staff view, components always visible.
...
@@ -894,10 +894,10 @@ class UnitPublishingTest(ContainerBase):
...
@@ -894,10 +894,10 @@ class UnitPublishingTest(ContainerBase):
component
.
edit
()
component
.
edit
()
HtmlComponentEditorView
(
self
.
browser
,
component
.
locator
)
.
set_content_and_save
(
modified_content
)
HtmlComponentEditorView
(
self
.
browser
,
component
.
locator
)
.
set_content_and_save
(
modified_content
)
self
.
assertEqual
(
component
.
student_content
,
modified_content
)
self
.
assertEqual
(
component
.
student_content
,
modified_content
)
self
.
_verify_publish_title
(
unit
,
self
.
DRAFT_STATUS
)
unit
.
verify_publish_title
(
self
.
DRAFT_STATUS
)
unit
.
publish_action
.
click
()
unit
.
publish_action
.
click
()
unit
.
wait_for_ajax
()
unit
.
wait_for_ajax
()
self
.
_verify_publish_title
(
unit
,
self
.
PUBLISHED_LIVE_STATUS
)
unit
.
verify_publish_title
(
self
.
PUBLISHED_LIVE_STATUS
)
self
.
_view_published_version
(
unit
)
self
.
_view_published_version
(
unit
)
self
.
assertIn
(
modified_content
,
self
.
courseware
.
xblock_component_html_content
(
0
))
self
.
assertIn
(
modified_content
,
self
.
courseware
.
xblock_component_html_content
(
0
))
...
@@ -917,10 +917,10 @@ class UnitPublishingTest(ContainerBase):
...
@@ -917,10 +917,10 @@ class UnitPublishingTest(ContainerBase):
component
.
edit
()
component
.
edit
()
HtmlComponentEditorView
(
self
.
browser
,
component
.
locator
)
.
set_content_and_cancel
(
"modified content"
)
HtmlComponentEditorView
(
self
.
browser
,
component
.
locator
)
.
set_content_and_cancel
(
"modified content"
)
self
.
assertEqual
(
component
.
student_content
,
"Body of HTML Unit."
)
self
.
assertEqual
(
component
.
student_content
,
"Body of HTML Unit."
)
self
.
_verify_publish_title
(
unit
,
self
.
PUBLISHED_LIVE_STATUS
)
unit
.
verify_publish_title
(
self
.
PUBLISHED_LIVE_STATUS
)
self
.
browser
.
refresh
()
self
.
browser
.
refresh
()
unit
.
wait_for_page
()
unit
.
wait_for_page
()
self
.
_verify_publish_title
(
unit
,
self
.
PUBLISHED_LIVE_STATUS
)
unit
.
verify_publish_title
(
self
.
PUBLISHED_LIVE_STATUS
)
def
test_delete_child_in_published_unit
(
self
):
def
test_delete_child_in_published_unit
(
self
):
"""
"""
...
@@ -936,10 +936,10 @@ class UnitPublishingTest(ContainerBase):
...
@@ -936,10 +936,10 @@ class UnitPublishingTest(ContainerBase):
"""
"""
unit
=
self
.
go_to_unit_page
()
unit
=
self
.
go_to_unit_page
()
unit
.
delete
(
0
)
unit
.
delete
(
0
)
self
.
_verify_publish_title
(
unit
,
self
.
DRAFT_STATUS
)
unit
.
verify_publish_title
(
self
.
DRAFT_STATUS
)
unit
.
publish_action
.
click
()
unit
.
publish_action
.
click
()
unit
.
wait_for_ajax
()
unit
.
wait_for_ajax
()
self
.
_verify_publish_title
(
unit
,
self
.
PUBLISHED_LIVE_STATUS
)
unit
.
verify_publish_title
(
self
.
PUBLISHED_LIVE_STATUS
)
self
.
_view_published_version
(
unit
)
self
.
_view_published_version
(
unit
)
self
.
assertEqual
(
0
,
self
.
courseware
.
num_xblock_components
)
self
.
assertEqual
(
0
,
self
.
courseware
.
num_xblock_components
)
...
@@ -955,12 +955,12 @@ class UnitPublishingTest(ContainerBase):
...
@@ -955,12 +955,12 @@ class UnitPublishingTest(ContainerBase):
Then the title in the Publish information box is "Published (not yet released)"
Then the title in the Publish information box is "Published (not yet released)"
"""
"""
unit
=
self
.
go_to_unit_page
(
'Unreleased Section'
,
'Unreleased Subsection'
,
'Unreleased Unit'
)
unit
=
self
.
go_to_unit_page
(
'Unreleased Section'
,
'Unreleased Subsection'
,
'Unreleased Unit'
)
self
.
_verify_publish_title
(
unit
,
self
.
PUBLISHED_STATUS
)
unit
.
verify_publish_title
(
self
.
PUBLISHED_STATUS
)
add_discussion
(
unit
)
add_discussion
(
unit
)
self
.
_verify_publish_title
(
unit
,
self
.
DRAFT_STATUS
)
unit
.
verify_publish_title
(
self
.
DRAFT_STATUS
)
unit
.
publish_action
.
click
()
unit
.
publish_action
.
click
()
unit
.
wait_for_ajax
()
unit
.
wait_for_ajax
()
self
.
_verify_publish_title
(
unit
,
self
.
PUBLISHED_STATUS
)
unit
.
verify_publish_title
(
self
.
PUBLISHED_STATUS
)
def
_view_published_version
(
self
,
unit
):
def
_view_published_version
(
self
,
unit
):
"""
"""
...
@@ -1007,15 +1007,6 @@ class UnitPublishingTest(ContainerBase):
...
@@ -1007,15 +1007,6 @@ class UnitPublishingTest(ContainerBase):
self
.
assertEqual
(
expected_title
,
unit
.
release_title
)
self
.
assertEqual
(
expected_title
,
unit
.
release_title
)
self
.
assertEqual
(
expected_date
,
unit
.
release_date
)
self
.
assertEqual
(
expected_date
,
unit
.
release_date
)
def
_verify_publish_title
(
self
,
unit
,
expected_title
):
"""
Waits for the publish title to change to the expected value.
"""
def
wait_for_title_change
():
return
(
unit
.
publish_title
==
expected_title
,
unit
.
publish_title
)
Promise
(
wait_for_title_change
,
"Publish title incorrect. Found '"
+
unit
.
publish_title
+
"'"
)
.
fulfill
()
def
_verify_last_published_and_saved
(
self
,
unit
,
expected_published_prefix
,
expected_saved_prefix
):
def
_verify_last_published_and_saved
(
self
,
unit
,
expected_published_prefix
,
expected_saved_prefix
):
"""
"""
Verifies that last published and last saved messages respectively contain the given strings.
Verifies that last published and last saved messages respectively contain the given strings.
...
@@ -1144,6 +1135,9 @@ class MoveComponentTest(ContainerBase):
...
@@ -1144,6 +1135,9 @@ class MoveComponentTest(ContainerBase):
"""
"""
Tests of moving an XBlock to another XBlock.
Tests of moving an XBlock to another XBlock.
"""
"""
PUBLISHED_LIVE_STATUS
=
"Publishing Status
\n
Published and Live"
DRAFT_STATUS
=
"Publishing Status
\n
Draft (Unpublished changes)"
def
setUp
(
self
,
is_staff
=
True
):
def
setUp
(
self
,
is_staff
=
True
):
super
(
MoveComponentTest
,
self
)
.
setUp
(
is_staff
=
is_staff
)
super
(
MoveComponentTest
,
self
)
.
setUp
(
is_staff
=
is_staff
)
self
.
container
=
ContainerPage
(
self
.
browser
,
None
)
self
.
container
=
ContainerPage
(
self
.
browser
,
None
)
...
@@ -1181,26 +1175,36 @@ class MoveComponentTest(ContainerBase):
...
@@ -1181,26 +1175,36 @@ class MoveComponentTest(ContainerBase):
)
)
)
)
def
verify_move_opertions
(
self
,
unit_page
,
source_component
,
operation
,
component_display_names_after_operation
):
def
verify_move_opertions
(
self
,
unit_page
,
source_component
,
operation
,
component_display_names_after_operation
,
should_verify_publish_title
=
True
):
"""
"""
Verify move operations.
Verify move operations.
Arguments:
Arguments:
unit_page (Object) Unit container page.
unit_page (Object) Unit container page.
source_component (Object)
s
ource XBlock object to be moved.
source_component (Object)
S
ource XBlock object to be moved.
operation (str), `move` or `undo move` operation.
operation (str), `move` or `undo move` operation.
component_display_names_after_operation (dict) display names of components after operation in source/dest
component_display_names_after_operation (dict) Display names of components after operation in source/dest
should_verify_publish_title (Boolean) Should verify publish title ot not. Default is True.
"""
"""
source_component
.
open_move_modal
()
source_component
.
open_move_modal
()
self
.
move_modal_view
.
navigate_to_category
(
self
.
source_xblock_category
,
self
.
navigation_options
)
self
.
move_modal_view
.
navigate_to_category
(
self
.
source_xblock_category
,
self
.
navigation_options
)
self
.
assertEqual
(
self
.
move_modal_view
.
is_move_button_enabled
,
True
)
self
.
assertEqual
(
self
.
move_modal_view
.
is_move_button_enabled
,
True
)
# Verify unit is in published state before move operation
if
should_verify_publish_title
:
self
.
container
.
verify_publish_title
(
self
.
PUBLISHED_LIVE_STATUS
)
self
.
move_modal_view
.
click_move_button
()
self
.
move_modal_view
.
click_move_button
()
self
.
container
.
verify_confirmation_message
(
self
.
container
.
verify_confirmation_message
(
self
.
message_move
.
format
(
display_name
=
self
.
source_component_display_name
)
self
.
message_move
.
format
(
display_name
=
self
.
source_component_display_name
)
)
)
self
.
assertEqual
(
len
(
unit_page
.
displayed_children
),
1
)
self
.
assertEqual
(
len
(
unit_page
.
displayed_children
),
1
)
# Verify unit in draft state now
if
should_verify_publish_title
:
self
.
container
.
verify_publish_title
(
self
.
DRAFT_STATUS
)
if
operation
==
'move'
:
if
operation
==
'move'
:
self
.
container
.
click_take_me_there_link
()
self
.
container
.
click_take_me_there_link
()
elif
operation
==
'undo_move'
:
elif
operation
==
'undo_move'
:
...
@@ -1333,7 +1337,8 @@ class MoveComponentTest(ContainerBase):
...
@@ -1333,7 +1337,8 @@ class MoveComponentTest(ContainerBase):
unit_page
=
group_container_page
,
unit_page
=
group_container_page
,
source_component
=
components
[
0
],
source_component
=
components
[
0
],
operation
=
'undo_move'
,
operation
=
'undo_move'
,
component_display_names_after_operation
=
[
'HTML 311'
,
'HTML 312'
]
component_display_names_after_operation
=
[
'HTML 311'
,
'HTML 312'
],
should_verify_publish_title
=
False
)
)
# Verify move operation for content experiment.
# Verify move operation for content experiment.
...
@@ -1341,7 +1346,8 @@ class MoveComponentTest(ContainerBase):
...
@@ -1341,7 +1346,8 @@ class MoveComponentTest(ContainerBase):
unit_page
=
group_container_page
,
unit_page
=
group_container_page
,
source_component
=
components
[
0
],
source_component
=
components
[
0
],
operation
=
'move'
,
operation
=
'move'
,
component_display_names_after_operation
=
[
'HTML 21'
,
'HTML 22'
,
'HTML 311'
]
component_display_names_after_operation
=
[
'HTML 21'
,
'HTML 22'
,
'HTML 311'
],
should_verify_publish_title
=
False
)
)
def
test_a11y
(
self
):
def
test_a11y
(
self
):
...
...
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