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
e9b8e17f
Commit
e9b8e17f
authored
Jan 24, 2017
by
Mushtaq Ali
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Enable disable move - TNL-6063
parent
e856f07b
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
539 additions
and
457 deletions
+539
-457
cms/djangoapps/contentstore/views/tests/test_item.py
+16
-1
cms/static/cms/js/main.js
+2
-2
cms/static/js/spec/views/modals/move_xblock_modal_spec.js
+9
-220
cms/static/js/spec/views/move_xblock_spec.js
+345
-64
cms/static/js/views/modals/move_xblock_modal.js
+59
-53
cms/static/js/views/move_xblock_list.js
+1
-0
cms/static/js/views/pages/container.js
+1
-1
cms/static/js/views/utils/move_xblock_utils.js
+94
-57
cms/static/js/views/utils/xblock_utils.js
+6
-6
cms/static/sass/elements/_modal-window.scss
+5
-0
common/static/common/js/components/views/feedback.js
+0
-2
common/static/common/js/components/views/feedback_move.js
+0
-49
common/static/common/templates/components/system-feedback.underscore
+1
-2
No files found.
cms/djangoapps/contentstore/views/tests/test_item.py
View file @
e9b8e17f
...
...
@@ -735,6 +735,7 @@ class TestDuplicateItem(ItemTest, DuplicateHelper):
verify_name
(
self
.
seq_usage_key
,
self
.
chapter_usage_key
,
"customized name"
,
display_name
=
"customized name"
)
@ddt.ddt
class
TestMoveItem
(
ItemTest
):
"""
Tests for move item.
...
...
@@ -744,7 +745,16 @@ class TestMoveItem(ItemTest):
Creates the test course structure to build course outline tree.
"""
super
(
TestMoveItem
,
self
)
.
setUp
()
self
.
setup_course
()
def
setup_course
(
self
,
default_store
=
None
):
"""
Helper method to create the course.
"""
if
not
default_store
:
default_store
=
self
.
store
.
default_modulestore
.
get_modulestore_type
()
self
.
course
=
CourseFactory
.
create
(
default_store
=
default_store
)
# Create a parent chapter
chap1
=
self
.
create_xblock
(
parent_usage_key
=
self
.
course
.
location
,
display_name
=
'chapter1'
,
category
=
'chapter'
)
self
.
chapter_usage_key
=
self
.
response_usage_key
(
chap1
)
...
...
@@ -821,10 +831,15 @@ class TestMoveItem(ItemTest):
self
.
assertEqual
(
new_parent_loc
,
target_usage_key
)
self
.
assertNotEqual
(
parent_loc
,
new_parent_loc
)
def
test_move_component
(
self
):
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_move_component
(
self
,
store_type
):
"""
Test move component with different xblock types.
Arguments:
store_type (ModuleStoreEnum.Type): Type of modulestore to create test course in.
"""
self
.
setup_course
(
default_store
=
store_type
)
for
source_usage_key
,
target_usage_key
in
[
(
self
.
html_usage_key
,
self
.
vert2_usage_key
),
(
self
.
vert_usage_key
,
self
.
seq2_usage_key
),
...
...
cms/static/cms/js/main.js
View file @
e9b8e17f
...
...
@@ -59,10 +59,10 @@
success
:
callback
});
};
$
.
postJSON
=
function
(
url
,
data
,
callback
)
{
$
.
postJSON
=
function
(
url
,
data
,
callback
)
{
// eslint-disable-line no-param-reassign
return
sendJSON
(
url
,
data
,
callback
,
'POST'
);
};
$
.
patchJSON
=
function
(
url
,
data
,
callback
)
{
$
.
patchJSON
=
function
(
url
,
data
,
callback
)
{
// eslint-disable-line no-param-reassign
return
sendJSON
(
url
,
data
,
callback
,
'PATCH'
);
};
return
domReady
(
function
()
{
...
...
cms/static/js/spec/views/modals/move_xblock_modal_spec.js
View file @
e9b8e17f
define
([
'jquery'
,
'underscore'
,
'edx-ui-toolkit/js/utils/spec-helpers/ajax-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'
,
'edx-ui-toolkit/js/utils/string-utils'
,
'js/models/xblock_info'
],
function
(
$
,
_
,
AjaxHelpers
,
TemplateHelpers
,
ViewHelpers
,
MoveXBlockModal
,
HtmlUtils
,
StringUtils
,
XBlockInfo
)
{
'js/views/modals/move_xblock_modal'
,
'js/models/xblock_info'
],
function
(
$
,
_
,
AjaxHelpers
,
TemplateHelpers
,
ViewHelpers
,
MoveXBlockModal
,
XBlockInfo
)
{
'use strict'
;
var
modal
,
showModal
,
verifyNotificationStatus
,
selectTargetParent
,
getConfirmationFeedbackTitle
,
getUndoConfirmationFeedbackTitle
,
getConfirmationFeedbackTitleHtml
,
getConfirmationFeedbackMessageHtml
,
sourceDisplayName
=
'HTML 101'
,
outlineUrl
=
'/course/cid?formats=concise'
,
sourceLocator
=
'source-xblock-locator'
,
targetParentLocator
=
'target-parent-xblock-locator'
,
sourceParentLocator
=
'source-parent-xblock-locator'
;
describe
(
'MoveXBlockModal'
,
function
()
{
var
modal
,
showModal
,
...
...
@@ -33,6 +17,11 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
display_name
:
DISPLAY_NAME
,
category
:
'html'
}),
sourceParentXBlockInfo
:
new
XBlockInfo
({
id
:
'PARENT_ID'
,
display_name
:
'VERT 101'
,
category
:
'vertical'
}),
XBlockURLRoot
:
'/xblock'
,
outlineURL
:
OUTLINE_URL
,
XBlockAncestorInfoURL
:
ANCESTORS_URL
...
...
@@ -58,7 +47,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
showModal
();
expect
(
modal
.
$el
.
find
(
'.modal-header .title'
).
contents
().
get
(
0
).
nodeValue
.
trim
()
).
toEqual
(
'Move: '
+
sourceDisplayName
);
).
toEqual
(
'Move: '
+
DISPLAY_NAME
);
expect
(
modal
.
$el
.
find
(
'.modal-sr-title'
).
text
().
trim
()
).
toEqual
(
'Choose a location to move your component to'
);
...
...
@@ -72,7 +61,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
expect
(
modal
.
$el
.
find
(
'.ui-loading.is-hidden'
)).
not
.
toExist
();
renderViewsSpy
=
spyOn
(
modal
,
'renderViews'
);
expect
(
requests
.
length
).
toEqual
(
2
);
AjaxHelpers
.
expectRequest
(
requests
,
'GET'
,
outlineUrl
);
AjaxHelpers
.
expectRequest
(
requests
,
'GET'
,
OUTLINE_URL
);
AjaxHelpers
.
respondWithJson
(
requests
,
{});
AjaxHelpers
.
expectRequest
(
requests
,
'GET'
,
ANCESTORS_URL
);
AjaxHelpers
.
respondWithJson
(
requests
,
{});
...
...
@@ -88,204 +77,4 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
ViewHelpers
.
verifyNotificationShowing
(
notificationSpy
,
"Studio's having trouble saving your work"
);
});
});
showModal
=
function
()
{
modal
=
new
MoveXBlockModal
({
sourceXBlockInfo
:
new
XBlockInfo
({
id
:
sourceLocator
,
display_name
:
sourceDisplayName
,
category
:
'html'
}),
sourceParentXBlockInfo
:
new
XBlockInfo
({
id
:
sourceParentLocator
,
display_name
:
'VERT 101'
,
category
:
'vertical'
}),
XBlockUrlRoot
:
'/xblock'
,
outlineURL
:
outlineUrl
});
modal
.
show
();
};
selectTargetParent
=
function
(
parentLocator
)
{
modal
.
moveXBlockListView
=
{
parent_info
:
{
parent
:
{
id
:
parentLocator
}
},
remove
:
function
()
{}
// attach a fake remove method
};
};
getConfirmationFeedbackTitle
=
function
(
displayName
)
{
return
StringUtils
.
interpolate
(
'Success! "{displayName}" has been moved.'
,
{
displayName
:
displayName
}
);
};
getUndoConfirmationFeedbackTitle
=
function
(
displayName
)
{
return
StringUtils
.
interpolate
(
'Move cancelled. "{sourceDisplayName}" has been moved back to its original location.'
,
{
sourceDisplayName
:
displayName
}
);
};
getConfirmationFeedbackTitleHtml
=
function
(
parentLocator
)
{
return
StringUtils
.
interpolate
(
'{link_start}Take me to the new location{link_end}'
,
{
link_start
:
HtmlUtils
.
HTML
(
'<a href="/container/'
+
parentLocator
+
'">'
),
link_end
:
HtmlUtils
.
HTML
(
'</a>'
)
}
);
};
getConfirmationFeedbackMessageHtml
=
function
(
displayName
,
locator
,
parentLocator
,
sourceIndex
)
{
return
HtmlUtils
.
interpolateHtml
(
HtmlUtils
.
HTML
(
'<a class="action-undo-move" href="#" data-source-display-name="{displayName}" '
+
'data-source-locator="{sourceLocator}" data-source-parent-locator="{parentSourceLocator}" '
+
'data-target-index="{targetIndex}">{undoMove}</a>'
),
{
displayName
:
displayName
,
sourceLocator
:
locator
,
parentSourceLocator
:
parentLocator
,
targetIndex
:
sourceIndex
,
undoMove
:
gettext
(
'Undo move'
)
}
);
};
verifyNotificationStatus
=
function
(
requests
,
notificationSpy
,
notificationText
,
sourceIndex
)
{
var
sourceIndex
=
sourceIndex
||
0
;
// eslint-disable-line no-redeclare
ViewHelpers
.
verifyNotificationShowing
(
notificationSpy
,
notificationText
);
AjaxHelpers
.
respondWithJson
(
requests
,
{
move_source_locator
:
sourceLocator
,
parent_locator
:
sourceParentLocator
,
target_index
:
sourceIndex
});
ViewHelpers
.
verifyNotificationHidden
(
notificationSpy
);
};
describe
(
'Move an xblock'
,
function
()
{
var
sendMoveXBlockRequest
,
moveXBlockWithSuccess
;
beforeEach
(
function
()
{
TemplateHelpers
.
installTemplates
([
'basic-modal'
,
'modal-button'
,
'move-xblock-modal'
]);
showModal
();
});
afterEach
(
function
()
{
modal
.
hide
();
});
sendMoveXBlockRequest
=
function
(
requests
,
xblockLocator
,
parentLocator
,
targetIndex
,
sourceIndex
)
{
var
responseData
,
expectedData
,
sourceIndex
=
sourceIndex
||
0
,
// eslint-disable-line no-redeclare
moveButton
=
modal
.
$el
.
find
(
'.modal-actions .action-move'
)[
sourceIndex
];
// select a target item and click
selectTargetParent
(
parentLocator
);
moveButton
.
click
();
responseData
=
expectedData
=
{
move_source_locator
:
xblockLocator
,
parent_locator
:
parentLocator
};
if
(
targetIndex
!==
undefined
)
{
expectedData
=
_
.
extend
(
expectedData
,
{
targetIndex
:
targetIndex
});
}
// verify content of request
AjaxHelpers
.
expectJsonRequest
(
requests
,
'PATCH'
,
'/xblock/'
,
expectedData
);
// send the response
AjaxHelpers
.
respondWithJson
(
requests
,
_
.
extend
(
responseData
,
{
source_index
:
sourceIndex
}));
};
moveXBlockWithSuccess
=
function
(
requests
)
{
var
sourceIndex
=
0
;
sendMoveXBlockRequest
(
requests
,
sourceLocator
,
targetParentLocator
);
expect
(
modal
.
movedAlertView
).
toBeDefined
();
expect
(
modal
.
movedAlertView
.
options
.
title
).
toEqual
(
getConfirmationFeedbackTitle
(
sourceDisplayName
));
expect
(
modal
.
movedAlertView
.
options
.
titleHtml
).
toEqual
(
getConfirmationFeedbackTitleHtml
(
targetParentLocator
)
);
expect
(
modal
.
movedAlertView
.
options
.
messageHtml
).
toEqual
(
getConfirmationFeedbackMessageHtml
(
sourceDisplayName
,
sourceLocator
,
sourceParentLocator
,
sourceIndex
)
);
};
it
(
'moves an xblock when move button is clicked'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
moveXBlockWithSuccess
(
requests
);
});
it
(
'undo move an xblock when undo move button is clicked'
,
function
()
{
var
sourceIndex
=
0
,
requests
=
AjaxHelpers
.
requests
(
this
);
moveXBlockWithSuccess
(
requests
);
modal
.
movedAlertView
.
undoMoveXBlock
({
target
:
$
(
modal
.
movedAlertView
.
options
.
messageHtml
.
text
)
});
AjaxHelpers
.
respondWithJson
(
requests
,
{
move_source_locator
:
sourceLocator
,
parent_locator
:
sourceParentLocator
,
target_index
:
sourceIndex
});
expect
(
modal
.
movedAlertView
.
movedAlertView
.
options
.
title
).
toEqual
(
getUndoConfirmationFeedbackTitle
(
sourceDisplayName
)
);
});
it
(
'does not move an xblock when cancel button is clicked'
,
function
()
{
var
sourceIndex
=
0
;
// select a target parent and click cancel button
selectTargetParent
(
targetParentLocator
);
modal
.
$el
.
find
(
'.modal-actions .action-cancel'
)[
sourceIndex
].
click
();
expect
(
modal
.
movedAlertView
).
toBeNull
();
});
it
(
'shows a notification when moving'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
),
notificationSpy
=
ViewHelpers
.
createNotificationSpy
();
// select a target item and click on move
selectTargetParent
(
targetParentLocator
);
modal
.
$el
.
find
(
'.modal-actions .action-move'
).
click
();
verifyNotificationStatus
(
requests
,
notificationSpy
,
'Moving'
);
});
it
(
'shows a notification when undo moving'
,
function
()
{
var
notificationSpy
,
requests
=
AjaxHelpers
.
requests
(
this
);
moveXBlockWithSuccess
(
requests
);
notificationSpy
=
ViewHelpers
.
createNotificationSpy
();
modal
.
movedAlertView
.
undoMoveXBlock
({
target
:
$
(
modal
.
movedAlertView
.
options
.
messageHtml
.
text
)
});
verifyNotificationStatus
(
requests
,
notificationSpy
,
'Undo moving'
);
});
});
});
cms/static/js/spec/views/move_xblock_spec.js
View file @
e9b8e17f
define
([
'jquery'
,
'underscore'
,
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers'
,
'common/js/spec_helpers/template_helpers'
,
'
js/views/move_xblock_list
'
,
'js/views/mo
ve_xblock_breadcrumb'
,
'js/models/xblock_info'
]
,
function
(
$
,
_
,
AjaxHelpers
,
TemplateHelpers
,
MoveXBlockListView
,
MoveXBlockBreadcrumbView
,
XBlockInfoModel
)
{
'common/js/spec_helpers/template_helpers'
,
'
common/js/spec_helpers/view_helpers
'
,
'js/views/mo
dals/move_xblock_modal'
,
'edx-ui-toolkit/js/utils/html-utils'
,
'edx-ui-toolkit/js/utils/string-utils'
,
'js/models/xblock_info'
]
,
function
(
$
,
_
,
AjaxHelpers
,
TemplateHelpers
,
ViewHelpers
,
MoveXBlockModal
,
HtmlUtils
,
StringUtils
,
XBlockInfo
)
{
'use strict'
;
describe
(
'MoveXBlock'
,
function
()
{
var
renderViews
,
createXBlockInfo
,
createCourseOutline
,
moveXBlockBreadcrumbView
,
moveXBlockListView
,
parentChildMap
,
categoryMap
,
createChildXBlockInfo
,
var
modal
,
showModal
,
renderViews
,
createXBlockInfo
,
createCourseOutline
,
courseOutlineOptions
,
parentChildMap
,
categoryMap
,
createChildXBlockInfo
,
xblockAncestorInfo
,
courseOutline
,
verifyBreadcrumbViewInfo
,
verifyListViewInfo
,
getDisplayedInfo
,
clickForwardButton
,
clickBreadcrumbButton
,
verifyXBlockInfo
,
nextCategory
;
clickBreadcrumbButton
,
verifyXBlockInfo
,
nextCategory
,
verifyMoveEnabled
,
getSentRequests
,
verifyNotificationStatus
,
sendMoveXBlockRequest
,
moveXBlockWithSuccess
,
verifyConfirmationFeedbackTitleHtml
,
verifyConfirmationFeedbackRedirectLinkHtml
,
verifyUndoConfirmationFeedbackTitleHtml
,
verifyConfirmationFeedbackUndoMoveActionHtml
,
sourceDisplayName
=
'component_display_name_0'
,
sourceLocator
=
'component_ID_0'
,
sourceParentLocator
=
'unit_ID_0'
;
parentChildMap
=
{
course
:
'section'
,
...
...
@@ -24,21 +30,71 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
component
:
'component'
};
courseOutlineOptions
=
{
section
:
2
,
subsection
:
2
,
unit
:
2
,
component
:
2
};
xblockAncestorInfo
=
{
ancestors
:
[
{
category
:
'vertical'
,
display_name
:
'unit_display_name_0'
,
id
:
'unit_ID_0'
},
{
category
:
'sequential'
,
display_name
:
'subsection_display_name_0'
,
id
:
'subsection_ID_0'
},
{
category
:
'chapter'
,
display_name
:
'section_display_name_0'
,
id
:
'section_ID_0'
},
{
category
:
'course'
,
display_name
:
'Demo Course'
,
id
:
'COURSE_ID_101'
}
]
};
beforeEach
(
function
()
{
setFixtures
(
"<div class='breadcrumb-container'></div><div class='xblock-list-container'></div>"
);
setFixtures
(
"<div id='page-alert'></div>"
);
TemplateHelpers
.
installTemplates
([
'move-xblock-list'
,
'move-xblock-breadcrumb'
'basic-modal'
,
'modal-button'
,
'move-xblock-modal'
]);
courseOutline
=
createCourseOutline
(
courseOutlineOptions
);
showModal
();
});
afterEach
(
function
()
{
mo
veXBlockBreadcrumbView
.
remov
e
();
moveXBlockListView
.
remove
()
;
mo
dal
.
hid
e
();
courseOutline
=
null
;
});
showModal
=
function
()
{
modal
=
new
MoveXBlockModal
({
sourceXBlockInfo
:
new
XBlockInfo
({
id
:
sourceLocator
,
display_name
:
sourceDisplayName
,
category
:
'component'
}),
sourceParentXBlockInfo
:
new
XBlockInfo
({
id
:
sourceParentLocator
,
display_name
:
'unit_display_name_0'
,
category
:
'vertical'
}),
XBlockUrlRoot
:
'/xblock'
});
modal
.
show
();
};
/**
* Create child XBlock info.
*
...
...
@@ -51,7 +107,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
var
childInfo
=
{
category
:
categoryMap
[
category
],
display_name
:
category
+
'_display_name_'
+
xblockIndex
,
id
:
category
+
'_ID
'
id
:
category
+
'_ID
_'
+
xblockIndex
};
return
createXBlockInfo
(
parentChildMap
[
category
],
outlineOptions
,
childInfo
);
};
...
...
@@ -93,12 +149,12 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
* @returns {Object}
*/
createCourseOutline
=
function
(
outlineOptions
)
{
var
course
Outline
=
{
var
course
XBlockInfo
=
{
category
:
'course'
,
display_name
:
'Demo Course'
,
id
:
'COURSE_ID_101'
};
return
createXBlockInfo
(
'section'
,
outlineOptions
,
course
Outline
);
return
createXBlockInfo
(
'section'
,
outlineOptions
,
course
XBlockInfo
);
};
/**
...
...
@@ -108,13 +164,8 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
* @param {any} ancestorInfo ancestors info
*/
renderViews
=
function
(
courseOutlineInfo
,
ancestorInfo
)
{
moveXBlockBreadcrumbView
=
new
MoveXBlockBreadcrumbView
({});
moveXBlockListView
=
new
MoveXBlockListView
(
{
model
:
new
XBlockInfoModel
(
courseOutlineInfo
,
{
parse
:
true
}),
ancestorInfo
:
ancestorInfo
||
{
ancestors
:
[]}
}
);
var
ancestorInfo
=
ancestorInfo
||
{
ancestors
:
[]};
// eslint-disable-line no-redeclare
modal
.
renderViews
(
courseOutlineInfo
,
ancestorInfo
);
};
/**
...
...
@@ -123,7 +174,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
* @returns {Object}
*/
getDisplayedInfo
=
function
()
{
var
viewEl
=
moveXBlockListView
.
$el
;
var
viewEl
=
mo
dal
.
mo
veXBlockListView
.
$el
;
return
{
categoryText
:
viewEl
.
find
(
'.category-text'
).
text
().
trim
(),
currentLocationText
:
viewEl
.
find
(
'.current-location'
).
text
().
trim
(),
...
...
@@ -147,7 +198,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
*/
verifyListViewInfo
=
function
(
category
,
expectedXBlocksCount
,
hasCurrentLocation
)
{
var
displayedInfo
=
getDisplayedInfo
();
expect
(
displayedInfo
.
categoryText
).
toEqual
(
moveXBlockListView
.
categoriesText
[
category
]
+
':'
);
expect
(
displayedInfo
.
categoryText
).
toEqual
(
mo
dal
.
mo
veXBlockListView
.
categoriesText
[
category
]
+
':'
);
expect
(
displayedInfo
.
xblockCount
).
toEqual
(
expectedXBlocksCount
);
expect
(
displayedInfo
.
xblockDisplayNames
).
toEqual
(
_
.
map
(
_
.
range
(
expectedXBlocksCount
),
function
(
xblockIndex
)
{
...
...
@@ -174,7 +225,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
* @param {any} xblockIndex XBlock index
*/
verifyBreadcrumbViewInfo
=
function
(
category
,
xblockIndex
)
{
var
displayedBreadcrumbs
=
moveXBlockBreadcrumbView
.
$el
.
find
(
'.breadcrumbs .bc-container'
).
map
(
var
displayedBreadcrumbs
=
mo
dal
.
mo
veXBlockBreadcrumbView
.
$el
.
find
(
'.breadcrumbs .bc-container'
).
map
(
function
()
{
return
$
(
this
).
text
().
trim
();
}
).
get
(),
categories
=
_
.
keys
(
parentChildMap
).
concat
([
'component'
]),
...
...
@@ -195,14 +246,14 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
*/
clickForwardButton
=
function
(
buttonIndex
)
{
buttonIndex
=
buttonIndex
||
0
;
// eslint-disable-line no-param-reassign
moveXBlockListView
.
$el
.
find
(
'[data-item-index="'
+
buttonIndex
+
'"] button'
).
click
();
mo
dal
.
mo
veXBlockListView
.
$el
.
find
(
'[data-item-index="'
+
buttonIndex
+
'"] button'
).
click
();
};
/**
* Click on last clickable breadcrumb button.
*/
clickBreadcrumbButton
=
function
()
{
moveXBlockBreadcrumbView
.
$el
.
find
(
'.bc-container button'
).
last
().
click
();
mo
dal
.
mo
veXBlockBreadcrumbView
.
$el
.
find
(
'.bc-container button'
).
last
().
click
();
};
/**
...
...
@@ -231,6 +282,7 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
verifyListViewInfo
(
category
,
expectedXBlocksCount
,
hasCurrentLocation
);
verifyBreadcrumbViewInfo
(
category
,
buttonIndex
);
verifyMoveEnabled
(
category
,
hasCurrentLocation
);
if
(
direction
===
'forward'
)
{
if
(
category
===
'component'
)
{
...
...
@@ -248,13 +300,162 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
verifyXBlockInfo
(
outlineOptions
,
category
,
buttonIndex
,
direction
,
hasCurrentLocation
);
};
/**
* Verify move button is enabled.
*
* @param {String} category XBlock category
* @param {String} hasCurrentLocation do we need to check current location
*/
verifyMoveEnabled
=
function
(
category
,
hasCurrentLocation
)
{
var
isMoveEnabled
=
!
modal
.
$el
.
find
(
'.modal-actions .action-move'
).
hasClass
(
'is-disabled'
);
if
(
category
===
'component'
&&
!
hasCurrentLocation
)
{
expect
(
isMoveEnabled
).
toBeTruthy
();
}
else
{
expect
(
isMoveEnabled
).
toBeFalsy
();
}
};
/**
* Verify notification status.
*
* @param {Object} requests requests object
* @param {Object} notificationSpy notification spy
* @param {String} notificationText notification text to be verified
* @param {Integer} sourceIndex source index of the xblock
*/
verifyNotificationStatus
=
function
(
requests
,
notificationSpy
,
notificationText
,
sourceIndex
)
{
var
sourceIndex
=
sourceIndex
||
0
;
// eslint-disable-line no-redeclare
ViewHelpers
.
verifyNotificationShowing
(
notificationSpy
,
notificationText
);
AjaxHelpers
.
respondWithJson
(
requests
,
{
move_source_locator
:
sourceLocator
,
parent_locator
:
sourceParentLocator
,
target_index
:
sourceIndex
});
ViewHelpers
.
verifyNotificationHidden
(
notificationSpy
);
};
/**
* Send move xblock request.
*
* @param {Object} requests requests object
* @param {Object} xblockLocator Xblock id location
* @param {Integer} targetIndex target index of the xblock
* @param {Integer} sourceIndex source index of the xblock
*/
sendMoveXBlockRequest
=
function
(
requests
,
xblockLocator
,
targetIndex
,
sourceIndex
)
{
var
responseData
,
expectedData
,
sourceIndex
=
sourceIndex
||
0
;
// eslint-disable-line no-redeclare
responseData
=
expectedData
=
{
move_source_locator
:
xblockLocator
,
parent_locator
:
modal
.
targetParentXBlockInfo
.
id
};
if
(
targetIndex
!==
undefined
)
{
expectedData
=
_
.
extend
(
expectedData
,
{
targetIndex
:
targetIndex
});
}
// verify content of request
AjaxHelpers
.
expectJsonRequest
(
requests
,
'PATCH'
,
'/xblock/'
,
expectedData
);
// send the response
AjaxHelpers
.
respondWithJson
(
requests
,
_
.
extend
(
responseData
,
{
source_index
:
sourceIndex
}));
};
/**
* Move xblock with success.
*
* @param {Object} requests requests object
*/
moveXBlockWithSuccess
=
function
(
requests
)
{
// select a target item and click
renderViews
(
courseOutline
);
_
.
each
(
_
.
range
(
3
),
function
()
{
clickForwardButton
(
1
);
});
modal
.
$el
.
find
(
'.modal-actions .action-move'
).
click
();
sendMoveXBlockRequest
(
requests
,
sourceLocator
);
expect
(
modal
.
movedAlertView
).
toBeDefined
();
verifyConfirmationFeedbackTitleHtml
(
sourceDisplayName
);
verifyConfirmationFeedbackRedirectLinkHtml
();
verifyConfirmationFeedbackUndoMoveActionHtml
();
};
/**
* Verify success banner message html has correct title html.
*
* @param {String} displayName XBlock display name
*/
verifyConfirmationFeedbackTitleHtml
=
function
(
displayName
)
{
expect
(
modal
.
movedAlertView
.
$el
.
find
(
'.title'
).
html
().
trim
())
.
toEqual
(
StringUtils
.
interpolate
(
'Success! "{displayName}" has been moved.'
,
{
displayName
:
displayName
})
);
};
/**
* Verify undo success banner message html has correct title html.
*
* @param {String} displayName XBlock display name
*/
verifyUndoConfirmationFeedbackTitleHtml
=
function
(
displayName
)
{
expect
(
modal
.
movedAlertView
.
$el
.
find
(
'.title'
).
html
()).
toEqual
(
StringUtils
.
interpolate
(
'Move cancelled. "{sourceDisplayName}" has been moved back to its original location.'
,
{
sourceDisplayName
:
displayName
}
)
);
};
/**
* Verify success banner message html has correct redirect link html.
*/
verifyConfirmationFeedbackRedirectLinkHtml
=
function
()
{
expect
(
modal
.
movedAlertView
.
$el
.
find
(
'.copy'
).
html
().
indexOf
(
HtmlUtils
.
HTML
(
'<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.
*/
verifyConfirmationFeedbackUndoMoveActionHtml
=
function
()
{
expect
(
modal
.
movedAlertView
.
$el
.
find
(
'.copy'
).
html
().
indexOf
(
HtmlUtils
.
HTML
(
'<button class="action-primary action-save">Undo Move</button>'
)
!==
-
1
)).
toBeTruthy
();
};
/**
* Get sent requests.
*
* @returns {Object}
*/
getSentRequests
=
function
()
{
return
jasmine
.
Ajax
.
requests
.
filter
(
function
(
request
)
{
return
request
.
readyState
>
0
;
});
};
it
(
'renders views with correct information'
,
function
()
{
var
outlineOptions
=
{
section
:
1
,
subsection
:
1
,
unit
:
1
,
component
:
1
},
outline
=
createCourseOutline
(
outlineOptions
);
renderViews
(
outline
);
verifyXBlockInfo
(
outlineOptions
,
'section'
,
0
,
'forward'
,
fals
e
);
verifyXBlockInfo
(
outlineOptions
,
'component'
,
0
,
'backward'
,
fals
e
);
renderViews
(
outline
,
xblockAncestorInfo
);
verifyXBlockInfo
(
outlineOptions
,
'section'
,
0
,
'forward'
,
tru
e
);
verifyXBlockInfo
(
outlineOptions
,
'component'
,
0
,
'backward'
,
tru
e
);
});
it
(
'shows correct behavior on breadcrumb navigation'
,
function
()
{
...
...
@@ -268,43 +469,18 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
_
.
each
([
'component'
,
'unit'
,
'subsection'
,
'section'
],
function
(
category
)
{
verifyListViewInfo
(
category
,
1
);
if
(
category
!==
'section'
)
{
moveXBlockBreadcrumbView
.
$el
.
find
(
'.bc-container button'
).
last
().
click
();
mo
dal
.
mo
veXBlockBreadcrumbView
.
$el
.
find
(
'.bc-container button'
).
last
().
click
();
}
});
});
it
(
'shows the correct current location'
,
function
()
{
var
outlineOptions
=
{
section
:
2
,
subsection
:
2
,
unit
:
2
,
component
:
2
},
outline
=
createCourseOutline
(
outlineOptions
),
ancestorInfo
=
{
ancestors
:
[
{
category
:
'vertical'
,
display_name
:
'unit_display_name_0'
,
id
:
'unit_ID'
},
{
category
:
'sequential'
,
display_name
:
'subsection_display_name_0'
,
id
:
'subsection_ID'
},
{
category
:
'chapter'
,
display_name
:
'section_display_name_0'
,
id
:
'section_ID'
},
{
category
:
'course'
,
display_name
:
'Demo Course'
,
id
:
'COURSE_ID_101'
}
]
};
renderViews
(
outline
,
ancestorInfo
);
outline
=
createCourseOutline
(
outlineOptions
);
renderViews
(
outline
,
xblockAncestorInfo
);
verifyXBlockInfo
(
outlineOptions
,
'section'
,
0
,
'forward'
,
true
);
// click the outline breadcrumb to render sections
moveXBlockBreadcrumbView
.
$el
.
find
(
'.bc-container button'
).
first
().
click
();
mo
dal
.
mo
veXBlockBreadcrumbView
.
$el
.
find
(
'.bc-container button'
).
first
().
click
();
verifyXBlockInfo
(
outlineOptions
,
'section'
,
1
,
'forward'
,
false
);
});
...
...
@@ -336,9 +512,114 @@ define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpe
_
.
each
(
_
.
range
(
info
.
forwardClicks
),
function
()
{
clickForwardButton
();
});
expect
(
moveXBlockListView
.
$el
.
find
(
'.xblock-no-child-message'
).
text
().
trim
()).
toEqual
(
info
.
message
);
moveXBlockListView
.
undelegateEvents
();
moveXBlockBreadcrumbView
.
undelegateEvents
();
expect
(
modal
.
moveXBlockListView
.
$el
.
find
(
'.xblock-no-child-message'
).
text
().
trim
())
.
toEqual
(
info
.
message
);
modal
.
moveXBlockListView
.
undelegateEvents
();
modal
.
moveXBlockBreadcrumbView
.
undelegateEvents
();
});
});
describe
(
'Move an xblock'
,
function
()
{
it
(
'can not move in a disabled state'
,
function
()
{
verifyMoveEnabled
(
false
);
modal
.
$el
.
find
(
'.modal-actions .action-move'
).
click
();
expect
(
modal
.
movedAlertView
).
toBeNull
();
expect
(
getSentRequests
().
length
).
toEqual
(
0
);
});
it
(
'move button is disabled when navigating to same parent'
,
function
()
{
// select a target parent as the same as source parent and click
renderViews
(
courseOutline
);
_
.
each
(
_
.
range
(
3
),
function
()
{
clickForwardButton
(
0
);
});
verifyMoveEnabled
(
'component'
,
true
);
});
it
(
'move button is enabled when navigating to different parent'
,
function
()
{
// select a target parent as the different as source parent and click
renderViews
(
courseOutline
);
_
.
each
(
_
.
range
(
3
),
function
()
{
clickForwardButton
(
1
);
});
verifyMoveEnabled
(
'component'
,
false
);
});
it
(
'verify move state while navigating'
,
function
()
{
renderViews
(
courseOutline
,
xblockAncestorInfo
);
verifyXBlockInfo
(
courseOutlineOptions
,
'section'
,
0
,
'forward'
,
true
);
// start from course outline again
modal
.
moveXBlockBreadcrumbView
.
$el
.
find
(
'.bc-container button'
).
first
().
click
();
verifyXBlockInfo
(
courseOutlineOptions
,
'section'
,
1
,
'forward'
,
false
);
});
it
(
'move an xblock when move button is clicked'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
moveXBlockWithSuccess
(
requests
);
});
it
(
'do not move an xblock when cancel button is clicked'
,
function
()
{
modal
.
$el
.
find
(
'.modal-actions .action-cancel'
).
click
();
expect
(
modal
.
movedAlertView
).
toBeNull
();
expect
(
getSentRequests
().
length
).
toEqual
(
0
);
});
it
(
'undo move an xblock when undo move link is clicked'
,
function
()
{
var
sourceIndex
=
0
,
requests
=
AjaxHelpers
.
requests
(
this
);
moveXBlockWithSuccess
(
requests
);
modal
.
movedAlertView
.
$el
.
find
(
'.action-save'
).
click
();
AjaxHelpers
.
respondWithJson
(
requests
,
{
move_source_locator
:
sourceLocator
,
parent_locator
:
sourceParentLocator
,
target_index
:
sourceIndex
});
verifyUndoConfirmationFeedbackTitleHtml
(
sourceDisplayName
);
});
});
describe
(
'shows a notification'
,
function
()
{
it
(
'mini operation message when moving an xblock'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
),
notificationSpy
=
ViewHelpers
.
createNotificationSpy
();
// navigate to a target parent and click
renderViews
(
courseOutline
);
_
.
each
(
_
.
range
(
3
),
function
()
{
clickForwardButton
(
1
);
});
modal
.
$el
.
find
(
'.modal-actions .action-move'
).
click
();
verifyNotificationStatus
(
requests
,
notificationSpy
,
'Moving'
);
});
it
(
'mini operation message when undo moving an xblock'
,
function
()
{
var
notificationSpy
,
requests
=
AjaxHelpers
.
requests
(
this
);
moveXBlockWithSuccess
(
requests
);
notificationSpy
=
ViewHelpers
.
createNotificationSpy
();
modal
.
movedAlertView
.
$el
.
find
(
'.action-save'
).
click
();
verifyNotificationStatus
(
requests
,
notificationSpy
,
'Undo moving'
);
});
it
(
'error message when move request fails'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
),
notificationSpy
=
ViewHelpers
.
createNotificationSpy
(
'Error'
);
// select a target item and click
renderViews
(
courseOutline
);
_
.
each
(
_
.
range
(
3
),
function
()
{
clickForwardButton
(
1
);
});
modal
.
$el
.
find
(
'.modal-actions .action-move'
).
click
();
AjaxHelpers
.
respondWithError
(
requests
);
ViewHelpers
.
verifyNotificationShowing
(
notificationSpy
,
"Studio's having trouble saving your work"
);
});
it
(
'error message when undo move request fails'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
),
notificationSpy
=
ViewHelpers
.
createNotificationSpy
(
'Error'
);
moveXBlockWithSuccess
(
requests
);
modal
.
movedAlertView
.
$el
.
find
(
'.action-save'
).
click
();
AjaxHelpers
.
respondWithError
(
requests
);
ViewHelpers
.
verifyNotificationShowing
(
notificationSpy
,
"Studio's having trouble saving your work"
);
});
});
});
...
...
cms/static/js/views/modals/move_xblock_modal.js
View file @
e9b8e17f
...
...
@@ -2,25 +2,29 @@
* The MoveXblockModal to move XBlocks in course.
*/
define
([
'jquery'
,
'backbone'
,
'underscore'
,
'gettext'
,
'js/views/baseview'
,
'js/views/modals/base_modal'
,
'js/models/xblock_info'
,
'js/views/move_xblock_list'
,
'js/views/move_xblock_breadcrumb'
,
'common/js/components/views/feedback'
,
'jquery'
,
'backbone'
,
'underscore'
,
'gettext'
,
'js/views/baseview'
,
'js/views/utils/xblock_utils'
,
'js/views/utils/move_xblock_utils'
,
'edx-ui-toolkit/js/utils/html-utils'
,
'edx-ui-toolkit/js/utils/string-utils'
,
'common/js/components/views/feedback'
,
'js/models/xblock_info'
,
'js/views/modals/base_modal'
,
'js/views/move_xblock_list'
,
'js/views/move_xblock_breadcrumb'
,
'text!templates/move-xblock-modal.underscore'
],
function
(
$
,
Backbone
,
_
,
gettext
,
BaseView
,
BaseModal
,
XBlockInfoModel
,
MoveXBlockListView
,
MoveXBlockBreadcrumbView
,
Feedback
,
XBlockViewUtils
,
MoveXBlockUtils
,
HtmlUtils
,
StringUtils
,
MoveXblockModalTemplate
)
{
function
(
$
,
Backbone
,
_
,
gettext
,
BaseView
,
XBlockViewUtils
,
MoveXBlockUtils
,
HtmlUtils
,
StringUtils
,
Feedback
,
XBlockInfoModel
,
BaseModal
,
MoveXBlockListView
,
MoveXBlockBreadcrumbView
,
MoveXblockModalTemplate
)
{
'use strict'
;
var
MoveXblockModal
=
BaseModal
.
extend
({
modalSRTitle
:
gettext
(
'Choose a location to move your component to'
),
events
:
_
.
extend
({},
BaseModal
.
prototype
.
events
,
{
'click .action-move'
:
'moveXBlock'
'click .action-move
:not(.is-disabled)
'
:
'moveXBlock'
}),
options
:
$
.
extend
({},
BaseModal
.
prototype
.
options
,
{
...
...
@@ -40,6 +44,7 @@ function($, Backbone, _, gettext, BaseView, BaseModal, XBlockInfoModel, MoveXBlo
this
.
listenTo
(
Backbone
,
'move:breadcrumbRendered'
,
this
.
focusModal
);
this
.
sourceXBlockInfo
=
this
.
options
.
sourceXBlockInfo
;
this
.
sourceParentXBlockInfo
=
this
.
options
.
sourceParentXBlockInfo
;
this
.
targetParentXBlockInfo
=
null
;
this
.
XBlockURLRoot
=
this
.
options
.
XBlockURLRoot
;
this
.
XBlockAncestorInfoURL
=
StringUtils
.
interpolate
(
'{urlRoot}/{usageId}?fields=ancestorInfo'
,
...
...
@@ -52,10 +57,9 @@ function($, Backbone, _, gettext, BaseView, BaseModal, XBlockInfoModel, MoveXBlo
$
(
'.breadcrumb-container'
).
removeClass
(
'is-hidden'
);
self
.
renderViews
(
courseOutlineInfo
,
ancestorInfo
);
});
this
.
targetParentXBlockInfo
=
null
;
this
.
movedAlertView
=
null
;
this
.
moveXBlockBreadcrumbView
=
null
;
this
.
moveXBlockListView
=
null
;
this
.
isValidMove
=
false
;
this
.
listenTo
(
Backbone
,
'move:enableMoveOperation'
,
this
.
enableMoveOperation
)
;
},
getTitle
:
function
()
{
...
...
@@ -71,7 +75,8 @@ function($, Backbone, _, gettext, BaseView, BaseModal, XBlockInfoModel, MoveXBlo
show
:
function
()
{
BaseModal
.
prototype
.
show
.
apply
(
this
,
[
false
]);
Feedback
.
prototype
.
inFocus
.
apply
(
this
,
[
this
.
options
.
modalWindowClass
]);
this
.
updateMoveState
(
false
);
MoveXBlockUtils
.
hideMovedNotification
();
},
hide
:
function
()
{
...
...
@@ -122,50 +127,51 @@ function($, Backbone, _, gettext, BaseView, BaseModal, XBlockInfoModel, MoveXBlo
);
},
updateMoveState
:
function
(
isValidMove
)
{
var
$moveButton
=
this
.
$el
.
find
(
'.action-move'
);
if
(
isValidMove
)
{
$moveButton
.
removeClass
(
'is-disabled'
);
}
else
{
$moveButton
.
addClass
(
'is-disabled'
);
}
},
enableMoveOperation
:
function
(
targetParentXBlockInfo
)
{
var
isValidMove
=
false
,
sourceParentType
=
this
.
sourceParentXBlockInfo
.
get
(
'category'
),
targetParentType
=
targetParentXBlockInfo
.
get
(
'category'
);
if
(
targetParentType
===
sourceParentType
&&
this
.
sourceParentXBlockInfo
.
id
!==
targetParentXBlockInfo
.
id
)
{
isValidMove
=
true
;
this
.
targetParentXBlockInfo
=
targetParentXBlockInfo
;
}
this
.
updateMoveState
(
isValidMove
);
},
moveXBlock
:
function
()
{
var
self
=
this
;
XBlockViewUtils
.
moveXBlock
(
self
.
sourceXBlockInfo
.
id
,
self
.
moveXBlockListView
.
parent_info
.
parent
.
id
)
.
done
(
function
(
response
)
{
if
(
response
.
move_source_locator
)
{
// hide modal
self
.
hide
();
// hide xblock element
$
(
"li.studio-xblock-wrapper[data-locator='"
+
self
.
sourceXBlockInfo
.
id
+
"']"
).
hide
();
if
(
self
.
movedAlertView
)
{
self
.
movedAlertView
.
hide
();
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'
)
}
self
.
movedAlertView
=
MoveXBlockUtils
.
showMovedNotification
(
StringUtils
.
interpolate
(
gettext
(
'Success! "{displayName}" has been moved.'
),
{
displayName
:
self
.
sourceXBlockInfo
.
get
(
'display_name'
)
}
),
StringUtils
.
interpolate
(
gettext
(
'{link_start}Take me to the new location{link_end}'
),
{
link_start
:
HtmlUtils
.
HTML
(
'<a href="/container/'
+
response
.
parent_locator
+
'">'
),
link_end
:
HtmlUtils
.
HTML
(
'</a>'
)
}
),
HtmlUtils
.
interpolateHtml
(
HtmlUtils
.
HTML
(
'<a class="action-undo-move" href="#" data-source-display-name="{displayName}" '
+
'data-source-locator="{sourceLocator}" '
+
'data-source-parent-locator="{sourceParentLocator}" '
+
'data-target-index="{targetIndex}">{undoMove}</a>'
),
{
displayName
:
self
.
sourceXBlockInfo
.
get
(
'display_name'
),
sourceLocator
:
self
.
sourceXBlockInfo
.
id
,
sourceParentLocator
:
self
.
sourceParentXBlockInfo
.
id
,
targetIndex
:
response
.
source_index
,
undoMove
:
gettext
(
'Undo move'
)
}
)
);
),
{
sourceDisplayName
:
self
.
sourceXBlockInfo
.
get
(
'display_name'
),
sourceLocator
:
self
.
sourceXBlockInfo
.
id
,
sourceParentLocator
:
self
.
sourceParentXBlockInfo
.
id
,
targetParentLocator
:
response
.
parent_locator
,
targetIndex
:
response
.
source_index
}
});
);
});
}
});
...
...
cms/static/js/views/move_xblock_list.js
View file @
e9b8e17f
...
...
@@ -63,6 +63,7 @@ function($, Backbone, _, gettext, HtmlUtils, StringUtils, XBlockUtils, MoveXBloc
)
);
Backbone
.
trigger
(
'move:childrenRendered'
,
this
.
breadcrumbInfo
());
Backbone
.
trigger
(
'move:enableMoveOperation'
,
this
.
parentInfo
.
parent
);
return
this
;
},
...
...
cms/static/js/views/pages/container.js
View file @
e9b8e17f
...
...
@@ -198,7 +198,7 @@ define(['jquery', 'underscore', 'gettext', 'js/views/pages/base_page', 'common/j
modal
=
new
MoveXBlockModal
({
sourceXBlockInfo
:
XBlockUtils
.
findXBlockInfo
(
xblockElement
,
this
.
model
),
sourceParentXBlockInfo
:
XBlockUtils
.
findXBlockInfo
(
parentXBlockElement
,
this
.
model
),
XBlockU
rl
Root
:
this
.
getURLRoot
(),
XBlockU
RL
Root
:
this
.
getURLRoot
(),
outlineURL
:
this
.
options
.
outlineURL
});
...
...
cms/static/js/views/utils/move_xblock_utils.js
View file @
e9b8e17f
/**
* Provides utilities for move xblock.
*/
define
([
'jquery'
,
'underscore'
,
'common/js/components/views/feedback_alert'
,
'js/views/utils/xblock_utils'
,
'js/views/utils/move_xblock_utils'
,
'edx-ui-toolkit/js/utils/string-utils'
],
function
(
$
,
_
,
AlertView
,
XBlockViewUtils
,
MoveXBlockUtils
,
StringUtils
)
{
'use strict'
;
var
MovedAlertView
,
showMovedNotification
;
define
([
'jquery'
,
'underscore'
,
'common/js/components/views/feedback'
,
'common/js/components/views/feedback_alert'
,
'js/views/utils/xblock_utils'
,
'js/views/utils/move_xblock_utils'
,
'edx-ui-toolkit/js/utils/string-utils'
],
function
(
$
,
_
,
Feedback
,
AlertView
,
XBlockViewUtils
,
MoveXBlockUtils
,
StringUtils
)
{
'use strict'
;
var
redirectLink
,
undoMoveXBlock
,
showMovedNotification
,
hideMovedNotification
;
MovedAlertView
=
AlertView
.
Confirmation
.
extend
({
events
:
_
.
extend
({},
AlertView
.
Confirmation
.
prototype
.
events
,
{
'click .action-undo-move'
:
'undoMoveXBlock'
}),
redirectLink
=
function
(
link
)
{
window
.
location
.
href
=
link
;
};
options
:
$
.
extend
({},
AlertView
.
Confirmation
.
prototype
.
options
),
initialize
:
function
()
{
AlertView
.
prototype
.
initialize
.
apply
(
this
,
arguments
);
this
.
movedAlertView
=
null
;
},
undoMoveXBlock
:
function
(
event
)
{
var
self
=
this
,
$moveButton
=
$
(
event
.
target
),
sourceLocator
=
$moveButton
.
data
(
'source-locator'
),
sourceDisplayName
=
$moveButton
.
data
(
'source-display-name'
),
sourceParentLocator
=
$moveButton
.
data
(
'source-parent-locator'
),
targetIndex
=
$moveButton
.
data
(
'target-index'
);
XBlockViewUtils
.
moveXBlock
(
sourceLocator
,
sourceParentLocator
,
targetIndex
)
.
done
(
function
(
response
)
{
// show XBlock element
$
(
'.studio-xblock-wrapper[data-locator="'
+
response
.
move_source_locator
+
'"]'
).
show
();
if
(
self
.
movedAlertView
)
{
self
.
movedAlertView
.
hide
();
undoMoveXBlock
=
function
(
data
)
{
XBlockViewUtils
.
moveXBlock
(
data
.
sourceLocator
,
data
.
sourceParentLocator
,
data
.
targetIndex
)
.
done
(
function
(
response
)
{
// show XBlock element
$
(
'.studio-xblock-wrapper[data-locator="'
+
response
.
move_source_locator
+
'"]'
).
show
();
showMovedNotification
(
StringUtils
.
interpolate
(
gettext
(
'Move cancelled. "{sourceDisplayName}" has been moved back to its original location.'
),
{
sourceDisplayName
:
data
.
sourceDisplayName
}
self
.
movedAlertView
=
showMovedNotification
(
StringUtils
.
interpolate
(
gettext
(
'Move cancelled. "{sourceDisplayName}" has been moved back to its original '
+
'location.'
),
{
sourceDisplayName
:
sourceDisplayName
}
)
);
});
}
)
);
});
};
showMovedNotification
=
function
(
title
,
titleHtml
,
messageHtml
)
{
var
movedAlertView
=
new
MovedAlertView
({
showMovedNotification
=
function
(
title
,
data
)
{
var
movedAlertView
;
// data is provided when we click undo move button.
if
(
data
)
{
movedAlertView
=
new
AlertView
.
Confirmation
({
title
:
title
,
titleHtml
:
titleHtml
,
messageHtml
:
messageHtml
,
maxShown
:
10000
actions
:
{
primary
:
{
text
:
gettext
(
'Undo move'
),
class
:
'action-save'
,
data
:
JSON
.
stringify
({
sourceDisplayName
:
data
.
sourceDisplayName
,
sourceLocator
:
data
.
sourceLocator
,
sourceParentLocator
:
data
.
sourceParentLocator
,
targetIndex
:
data
.
targetIndex
}),
click
:
function
()
{
undoMoveXBlock
(
{
sourceDisplayName
:
data
.
sourceDisplayName
,
sourceLocator
:
data
.
sourceLocator
,
sourceParentLocator
:
data
.
sourceParentLocator
,
targetIndex
:
data
.
targetIndex
}
);
}
},
secondary
:
[
{
text
:
gettext
(
'Take me to the new location'
),
class
:
'action-cancel'
,
data
:
JSON
.
stringify
({
targetParentLocator
:
data
.
targetParentLocator
}),
click
:
function
()
{
redirectLink
(
'/container/'
+
data
.
targetParentLocator
);
}
}
]
}
});
movedAlertView
.
show
();
// scroll to top
$
.
smoothScroll
({
offset
:
0
,
easing
:
'swing'
,
speed
:
1000
}
else
{
movedAlertView
=
new
AlertView
.
Confirmation
({
title
:
title
});
return
movedAlertView
;
};
}
movedAlertView
.
show
();
// scroll to top
$
.
smoothScroll
({
offset
:
0
,
easing
:
'swing'
,
speed
:
1000
});
movedAlertView
.
$
(
'.wrapper'
).
first
().
focus
();
return
movedAlertView
;
};
hideMovedNotification
=
function
()
{
var
movedAlertView
=
Feedback
.
active_alert
;
if
(
movedAlertView
)
{
AlertView
.
prototype
.
hide
.
apply
(
movedAlertView
);
}
};
return
{
showMovedNotification
:
showMovedNotification
};
});
return
{
redirectLink
:
redirectLink
,
showMovedNotification
:
showMovedNotification
,
hideMovedNotification
:
hideMovedNotification
};
});
cms/static/js/views/utils/xblock_utils.js
View file @
e9b8e17f
...
...
@@ -94,10 +94,10 @@ define(['jquery', 'underscore', 'gettext', 'common/js/components/utils/view_util
/**
* Moves the specified xblock in a new parent xblock.
* @param {String} sourceLocator
The
xblock element to be moved.
* @param {String} targetParentLocator
Target parent xblock locator of the xblock to be moved,
*
new moved xblock would be placed
under this xblock.
* @param {
String
} targetIndex Intended index position of the xblock in parent xblock. If provided,
* @param {String} sourceLocator
Locator of
xblock element to be moved.
* @param {String} targetParentLocator
Locator of the target parent xblock, moved xblock would be placed
* under this xblock.
* @param {
Integer
} targetIndex Intended index position of the xblock in parent xblock. If provided,
* xblock would be placed at the particular index in the parent xblock.
* @returns {jQuery promise} A promise representing the moving of the xblock.
*/
...
...
@@ -110,8 +110,8 @@ define(['jquery', 'underscore', 'gettext', 'common/js/components/utils/view_util
move_source_locator
:
sourceLocator
,
parent_locator
:
targetParentLocator
,
target_index
:
targetIndex
},
function
(
data
)
{
moveOperation
.
resolve
(
data
);
},
function
(
response
)
{
moveOperation
.
resolve
(
response
);
})
.
fail
(
function
()
{
moveOperation
.
reject
();
...
...
cms/static/sass/elements/_modal-window.scss
View file @
e9b8e17f
...
...
@@ -297,6 +297,11 @@
.ui-loading
{
box-shadow
:
none
;
}
.modal-actions
.action-move.is-disabled
{
border
:
1px
solid
$gray-l1
!
important
;
background
:
$gray-l1
!
important
;
}
}
// upload modal
...
...
common/static/common/js/components/views/feedback.js
View file @
e9b8e17f
...
...
@@ -21,8 +21,6 @@
options
:
{
title
:
''
,
message
:
''
,
titleHtml
:
''
,
// an optional html that comes after the title.
messageHtml
:
''
,
// an optional html that comes after the message.
intent
:
null
,
// "warning", "confirmation", "error", "announcement", "step-required", etc
type
:
null
,
// "alert", "notification", or "prompt": set by subclass
shown
:
true
,
// is this view currently being shown?
...
...
common/static/common/js/components/views/feedback_move.js
deleted
100644 → 0
View file @
e856f07b
/**
* The MovedAlertView to show confirmation message when moving XBlocks.
*/
(
function
(
define
)
{
'use strict'
;
define
([
'jquery'
,
'underscore'
,
'common/js/components/views/feedback_alert'
,
'js/views/utils/xblock_utils'
,
'js/views/utils/move_xblock_utils'
,
'edx-ui-toolkit/js/utils/string-utils'
],
function
(
$
,
_
,
AlertView
,
XBlockViewUtils
,
MoveXBlockUtils
,
StringUtils
)
{
var
MovedAlertView
=
AlertView
.
Confirmation
.
extend
({
events
:
_
.
extend
({},
AlertView
.
Confirmation
.
prototype
.
events
,
{
'click .action-undo-move'
:
'undoMoveXBlock'
}),
options
:
$
.
extend
({},
AlertView
.
Confirmation
.
prototype
.
options
),
initialize
:
function
()
{
AlertView
.
prototype
.
initialize
.
apply
(
this
,
arguments
);
this
.
movedAlertView
=
null
;
},
undoMoveXBlock
:
function
(
event
)
{
var
self
=
this
,
$moveButton
=
$
(
event
.
target
),
sourceLocator
=
$moveButton
.
data
(
'source-locator'
),
sourceDisplayName
=
$moveButton
.
data
(
'source-display-name'
),
sourceParentLocator
=
$moveButton
.
data
(
'source-parent-locator'
),
targetIndex
=
$moveButton
.
data
(
'target-index'
);
XBlockViewUtils
.
moveXBlock
(
sourceLocator
,
sourceParentLocator
,
targetIndex
)
.
done
(
function
(
response
)
{
// show XBlock element
$
(
'.studio-xblock-wrapper[data-locator="'
+
response
.
move_source_locator
+
'"]'
).
show
();
if
(
self
.
movedAlertView
)
{
self
.
movedAlertView
.
hide
();
}
self
.
movedAlertView
=
MoveXBlockUtils
.
showMovedNotification
(
StringUtils
.
interpolate
(
gettext
(
'Move cancelled. "{sourceDisplayName}" has been moved back to its original '
+
'location.'
),
{
sourceDisplayName
:
sourceDisplayName
}
)
);
});
}
});
return
MovedAlertView
;
});
}).
call
(
this
,
define
||
RequireJS
.
define
);
common/static/common/templates/components/system-feedback.underscore
View file @
e9b8e17f
...
...
@@ -15,9 +15,8 @@
<% } %>
<div class="copy">
<h2 class="title title-3" id="<%= type %>-<%= intent %>-title"><%- title %><
% if(titleHtml) { %> <%= titleHtml %> <% } %><
/h2>
<h2 class="title title-3" id="<%= type %>-<%= intent %>-title"><%- title %></h2>
<% if(obj.message) { %><p class="message" id="<%= type %>-<%= intent %>-description"><%- message %></p><% } %>
<% if(messageHtml) { %> <%= messageHtml %> <% } %>
</div>
<% if(obj.actions) { %>
...
...
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