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
ff1a08cb
Commit
ff1a08cb
authored
Nov 03, 2014
by
E. Kolpakov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Paging for LibraryView added with JS tests.
parent
05817614
Show whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
1584 additions
and
226 deletions
+1584
-226
cms/djangoapps/contentstore/views/item.py
+17
-1
cms/static/coffee/spec/main.coffee
+1
-0
cms/static/js/factories/container.js
+10
-12
cms/static/js/factories/library.js
+10
-12
cms/static/js/spec/views/library_container_spec.js
+489
-0
cms/static/js/spec/views/pages/container_spec.js
+80
-57
cms/static/js/views/container.js
+4
-0
cms/static/js/views/library_container.js
+164
-0
cms/static/js/views/pages/container.js
+38
-14
cms/static/js/views/paging_footer.js
+6
-0
cms/static/sass/elements/_pagination.scss
+120
-0
cms/static/sass/elements/_uploaded-assets.scss
+1
-114
cms/static/sass/elements/_xblocks.scss
+31
-0
cms/static/sass/style-app-extend1-rtl.scss
+1
-0
cms/static/sass/style-app-extend1.scss
+1
-0
cms/templates/container.html
+4
-1
cms/templates/js/mock/mock-container-paged-after-add-xblock.underscore
+283
-0
cms/templates/js/mock/mock-container-paged-xblock.underscore
+257
-0
cms/templates/library.html
+6
-2
common/lib/xmodule/xmodule/library_root_xblock.py
+38
-12
common/lib/xmodule/xmodule/video_module/video_handlers.py
+0
-1
lms/templates/studio_render_paged_children_view.html
+23
-0
No files found.
cms/djangoapps/contentstore/views/item.py
View file @
ff1a08cb
...
@@ -237,12 +237,28 @@ def xblock_view_handler(request, usage_key_string, view_name):
...
@@ -237,12 +237,28 @@ def xblock_view_handler(request, usage_key_string, view_name):
if
view_name
==
'reorderable_container_child_preview'
:
if
view_name
==
'reorderable_container_child_preview'
:
reorderable_items
.
add
(
xblock
.
location
)
reorderable_items
.
add
(
xblock
.
location
)
paging
=
None
try
:
if
request
.
REQUEST
.
get
(
'enable_paging'
,
'false'
)
==
'true'
:
paging
=
{
'page_number'
:
int
(
request
.
REQUEST
.
get
(
'page_number'
,
0
)),
'page_size'
:
int
(
request
.
REQUEST
.
get
(
'page_size'
,
0
)),
}
except
ValueError
:
log
.
exception
(
"Couldn't parse paging parameters: enable_paging:
%
s, page_number:
%
s, page_size:
%
s"
,
request
.
REQUEST
.
get
(
'enable_paging'
,
'false'
),
request
.
REQUEST
.
get
(
'page_number'
,
0
),
request
.
REQUEST
.
get
(
'page_size'
,
0
)
)
# Set up the context to be passed to each XBlock's render method.
# Set up the context to be passed to each XBlock's render method.
context
=
{
context
=
{
'is_pages_view'
:
is_pages_view
,
# This setting disables the recursive wrapping of xblocks
'is_pages_view'
:
is_pages_view
,
# This setting disables the recursive wrapping of xblocks
'is_unit_page'
:
is_unit
(
xblock
),
'is_unit_page'
:
is_unit
(
xblock
),
'root_xblock'
:
xblock
if
(
view_name
==
'container_preview'
)
else
None
,
'root_xblock'
:
xblock
if
(
view_name
==
'container_preview'
)
else
None
,
'reorderable_items'
:
reorderable_items
'reorderable_items'
:
reorderable_items
,
'paging'
:
paging
}
}
fragment
=
get_preview_fragment
(
request
,
xblock
,
context
)
fragment
=
get_preview_fragment
(
request
,
xblock
,
context
)
...
...
cms/static/coffee/spec/main.coffee
View file @
ff1a08cb
...
@@ -239,6 +239,7 @@ define([
...
@@ -239,6 +239,7 @@ define([
"js/spec/views/assets_spec"
,
"js/spec/views/assets_spec"
,
"js/spec/views/baseview_spec"
,
"js/spec/views/baseview_spec"
,
"js/spec/views/container_spec"
,
"js/spec/views/container_spec"
,
"js/spec/views/library_container_spec"
,
"js/spec/views/group_configuration_spec"
,
"js/spec/views/group_configuration_spec"
,
"js/spec/views/paging_spec"
,
"js/spec/views/paging_spec"
,
"js/spec/views/unit_outline_spec"
,
"js/spec/views/unit_outline_spec"
,
...
...
cms/static/js/factories/container.js
View file @
ff1a08cb
define
([
define
([
'jquery'
,
'js/models/xblock_info'
,
'js/views/pages/container'
,
'jquery'
,
'
underscore'
,
'
js/models/xblock_info'
,
'js/views/pages/container'
,
'js/collections/component_template'
,
'xmodule'
,
'coffee/src/main'
,
'js/collections/component_template'
,
'xmodule'
,
'coffee/src/main'
,
'xblock/cms.runtime.v1'
'xblock/cms.runtime.v1'
],
],
function
(
$
,
XBlockInfo
,
ContainerPage
,
ComponentTemplates
,
xmoduleLoader
)
{
function
(
$
,
_
,
XBlockInfo
,
ContainerPage
,
ComponentTemplates
,
xmoduleLoader
)
{
'use strict'
;
'use strict'
;
return
function
(
componentTemplates
,
XBlockInfoJson
,
action
,
isUnitPage
)
{
return
function
(
componentTemplates
,
XBlockInfoJson
,
action
,
options
)
{
var
templates
=
new
ComponentTemplates
(
componentTemplates
,
{
parse
:
true
}),
var
main_options
=
{
mainXBlockInfo
=
new
XBlockInfo
(
XBlockInfoJson
,
{
parse
:
true
});
xmoduleLoader
.
done
(
function
()
{
var
view
=
new
ContainerPage
({
el
:
$
(
'#content'
),
el
:
$
(
'#content'
),
model
:
mainXBlockInfo
,
model
:
new
XBlockInfo
(
XBlockInfoJson
,
{
parse
:
true
})
,
action
:
action
,
action
:
action
,
templates
:
templates
,
templates
:
new
ComponentTemplates
(
componentTemplates
,
{
parse
:
true
})
isUnitPage
:
isUnitPage
};
});
xmoduleLoader
.
done
(
function
()
{
var
view
=
new
ContainerPage
(
_
.
extend
(
main_options
,
options
));
view
.
render
();
view
.
render
();
});
});
};
};
...
...
cms/static/js/factories/library.js
View file @
ff1a08cb
define
([
define
([
'jquery'
,
'js/models/xblock_info'
,
'js/views/pages/container'
,
'jquery'
,
'
underscore'
,
'
js/models/xblock_info'
,
'js/views/pages/container'
,
'js/collections/component_template'
,
'xmodule'
,
'coffee/src/main'
,
'js/collections/component_template'
,
'xmodule'
,
'coffee/src/main'
,
'xblock/cms.runtime.v1'
'xblock/cms.runtime.v1'
],
],
function
(
$
,
XBlockInfo
,
ContainerPage
,
ComponentTemplates
,
xmoduleLoader
)
{
function
(
$
,
_
,
XBlockInfo
,
ContainerPage
,
ComponentTemplates
,
xmoduleLoader
)
{
'use strict'
;
'use strict'
;
return
function
(
componentTemplates
,
XBlockInfoJson
)
{
return
function
(
componentTemplates
,
XBlockInfoJson
,
options
)
{
var
templates
=
new
ComponentTemplates
(
componentTemplates
,
{
parse
:
true
}),
var
main_options
=
{
mainXBlockInfo
=
new
XBlockInfo
(
XBlockInfoJson
,
{
parse
:
true
});
el
:
$
(
'#content'
),
model
:
new
XBlockInfo
(
XBlockInfoJson
,
{
parse
:
true
}),
templates
:
new
ComponentTemplates
(
componentTemplates
,
{
parse
:
true
}),
action
:
'view'
};
xmoduleLoader
.
done
(
function
()
{
xmoduleLoader
.
done
(
function
()
{
var
view
=
new
ContainerPage
({
var
view
=
new
ContainerPage
(
_
.
extend
(
main_options
,
options
));
el
:
$
(
'#content'
),
model
:
mainXBlockInfo
,
action
:
"view"
,
templates
:
templates
,
isUnitPage
:
false
});
view
.
render
();
view
.
render
();
});
});
};
};
...
...
cms/static/js/spec/views/library_container_spec.js
0 → 100644
View file @
ff1a08cb
define
([
"jquery"
,
"underscore"
,
"js/common_helpers/ajax_helpers"
,
"URI"
,
"js/models/xblock_info"
,
"js/views/library_container"
,
"js/views/paging_header"
,
"js/views/paging_footer"
],
function
(
$
,
_
,
AjaxHelpers
,
URI
,
XBlockInfo
,
PagedContainer
,
PagingContainer
,
PagingFooter
)
{
var
htmlResponseTpl
=
_
.
template
(
''
+
'<div class="xblock-container-paging-parameters" data-start="<%= start %>" data-displayed="<%= displayed %>" data-total="<%= total %>"/>'
);
function
getResponseHtml
(
options
){
return
'<div class="xblock" data-request-token="request_token">'
+
'<div class="container-paging-header"></div>'
+
htmlResponseTpl
(
options
)
+
'<div class="container-paging-footer"></div>'
+
'</div>'
}
var
PAGE_SIZE
=
3
;
var
mockFirstPage
=
{
resources
:
[],
html
:
getResponseHtml
({
start
:
0
,
displayed
:
PAGE_SIZE
,
total
:
PAGE_SIZE
+
1
})
};
var
mockSecondPage
=
{
resources
:
[],
html
:
getResponseHtml
({
start
:
PAGE_SIZE
,
displayed
:
1
,
total
:
PAGE_SIZE
+
1
})
};
var
mockEmptyPage
=
{
resources
:
[],
html
:
getResponseHtml
({
start
:
0
,
displayed
:
0
,
total
:
0
})
};
var
respondWithMockPage
=
function
(
requests
)
{
var
requestIndex
=
requests
.
length
-
1
;
var
request
=
requests
[
requestIndex
];
var
url
=
new
URI
(
request
.
url
);
var
queryParameters
=
url
.
query
(
true
);
// Returns an object with each query parameter stored as a value
var
page
=
queryParameters
.
page_number
;
var
response
=
page
===
"0"
?
mockFirstPage
:
mockSecondPage
;
AjaxHelpers
.
respondWithJson
(
requests
,
response
,
requestIndex
);
};
var
MockPagingView
=
PagedContainer
.
extend
({
view
:
'container_preview'
,
el
:
$
(
"<div><div class='xblock' data-request-token='test_request_token'/></div>"
),
model
:
new
XBlockInfo
({},
{
parse
:
true
})
});
describe
(
"Paging Container"
,
function
()
{
var
pagingContainer
;
beforeEach
(
function
()
{
var
feedbackTpl
=
readFixtures
(
'system-feedback.underscore'
);
setFixtures
(
$
(
"<script>"
,
{
id
:
"system-feedback-tpl"
,
type
:
"text/template"
}).
text
(
feedbackTpl
));
pagingContainer
=
new
MockPagingView
({
page_size
:
PAGE_SIZE
});
});
describe
(
"Container"
,
function
()
{
describe
(
"setPage"
,
function
()
{
it
(
'can set the current page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
0
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
1
);
});
it
(
'should not change page after a server error'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
pagingContainer
.
setPage
(
1
);
requests
[
1
].
respond
(
500
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
0
);
});
});
describe
(
"nextPage"
,
function
()
{
it
(
'does not move forward after a server error'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
pagingContainer
.
nextPage
();
requests
[
1
].
respond
(
500
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
0
);
});
it
(
'can move to the next page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
pagingContainer
.
nextPage
();
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
1
);
});
it
(
'can not move forward from the final page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
pagingContainer
.
nextPage
();
expect
(
requests
.
length
).
toBe
(
1
);
});
});
describe
(
"previousPage"
,
function
()
{
it
(
'can move back a page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
pagingContainer
.
previousPage
();
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
0
);
});
it
(
'can not move back from the first page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
pagingContainer
.
previousPage
();
expect
(
requests
.
length
).
toBe
(
1
);
});
it
(
'does not move back after a server error'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
pagingContainer
.
previousPage
();
requests
[
1
].
respond
(
500
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
1
);
});
});
});
describe
(
"PagingHeader"
,
function
()
{
beforeEach
(
function
()
{
var
pagingFooterTpl
=
readFixtures
(
'paging-header.underscore'
);
appendSetFixtures
(
$
(
"<script>"
,
{
id
:
"paging-header-tpl"
,
type
:
"text/template"
}).
text
(
pagingFooterTpl
));
});
describe
(
"Next page button"
,
function
()
{
beforeEach
(
function
()
{
pagingContainer
.
render
();
});
it
(
'does not move forward if a server error occurs'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
pagingContainer
.
pagingHeader
.
$
(
'.next-page-link'
).
click
();
requests
[
1
].
respond
(
500
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
0
);
});
it
(
'can move to the next page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
pagingContainer
.
pagingHeader
.
$
(
'.next-page-link'
).
click
();
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
1
);
});
it
(
'should be enabled when there is at least one more page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingHeader
.
$
(
'.next-page-link'
)).
not
.
toHaveClass
(
'is-disabled'
);
});
it
(
'should be disabled on the final page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingHeader
.
$
(
'.next-page-link'
)).
toHaveClass
(
'is-disabled'
);
});
it
(
'should be disabled on an empty page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
AjaxHelpers
.
respondWithJson
(
requests
,
mockEmptyPage
);
expect
(
pagingContainer
.
pagingHeader
.
$
(
'.next-page-link'
)).
toHaveClass
(
'is-disabled'
);
});
});
describe
(
"Previous page button"
,
function
()
{
beforeEach
(
function
()
{
pagingContainer
.
render
();
});
it
(
'does not move back if a server error occurs'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
pagingContainer
.
pagingHeader
.
$
(
'.previous-page-link'
).
click
();
requests
[
1
].
respond
(
500
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
1
);
});
it
(
'can go back a page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
pagingContainer
.
pagingHeader
.
$
(
'.previous-page-link'
).
click
();
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
0
);
});
it
(
'should be disabled on the first page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingHeader
.
$
(
'.previous-page-link'
)).
toHaveClass
(
'is-disabled'
);
});
it
(
'should be enabled on the second page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingHeader
.
$
(
'.previous-page-link'
)).
not
.
toHaveClass
(
'is-disabled'
);
});
it
(
'should be disabled for an empty page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
AjaxHelpers
.
respondWithJson
(
requests
,
mockEmptyPage
);
expect
(
pagingContainer
.
pagingHeader
.
$
(
'.previous-page-link'
)).
toHaveClass
(
'is-disabled'
);
});
});
describe
(
"Page metadata section"
,
function
()
{
it
(
'shows the correct metadata for the current page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
),
message
;
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
message
=
pagingContainer
.
pagingHeader
.
$
(
'.meta'
).
html
().
trim
();
expect
(
message
).
toBe
(
'<p>Showing <span class="count-current-shown">1-3</span>'
+
' out of <span class="count-total">4 total</span>, '
+
'sorted by <span class="sort-order">Date added</span> descending</p>'
);
});
});
describe
(
"Children count label"
,
function
()
{
it
(
'should show correct count on first page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingHeader
.
$
(
'.count-current-shown'
)).
toHaveHtml
(
'1-3'
);
});
it
(
'should show correct count on second page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingHeader
.
$
(
'.count-current-shown'
)).
toHaveHtml
(
'4-4'
);
});
it
(
'should show correct count for an empty collection'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
AjaxHelpers
.
respondWithJson
(
requests
,
mockEmptyPage
);
expect
(
pagingContainer
.
pagingHeader
.
$
(
'.count-current-shown'
)).
toHaveHtml
(
'0-0'
);
});
});
describe
(
"Children total label"
,
function
()
{
it
(
'should show correct total on the first page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingHeader
.
$
(
'.count-total'
)).
toHaveText
(
'4 total'
);
});
it
(
'should show correct total on the second page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingHeader
.
$
(
'.count-total'
)).
toHaveText
(
'4 total'
);
});
it
(
'should show zero total for an empty collection'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
AjaxHelpers
.
respondWithJson
(
requests
,
mockEmptyPage
);
expect
(
pagingContainer
.
pagingHeader
.
$
(
'.count-total'
)).
toHaveText
(
'0 total'
);
});
});
});
describe
(
"PagingFooter"
,
function
()
{
var
pagingFooter
;
beforeEach
(
function
()
{
var
pagingFooterTpl
=
readFixtures
(
'paging-footer.underscore'
);
appendSetFixtures
(
$
(
"<script>"
,
{
id
:
"paging-footer-tpl"
,
type
:
"text/template"
}).
text
(
pagingFooterTpl
));
});
describe
(
"Next page button"
,
function
()
{
beforeEach
(
function
()
{
// Render the page and header so that they can react to events
pagingContainer
.
render
();
});
it
(
'does not move forward if a server error occurs'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
pagingContainer
.
pagingFooter
.
$
(
'.next-page-link'
).
click
();
requests
[
1
].
respond
(
500
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
0
);
});
it
(
'can move to the next page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
pagingContainer
.
pagingFooter
.
$
(
'.next-page-link'
).
click
();
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
1
);
});
it
(
'should be enabled when there is at least one more page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.next-page-link'
)).
not
.
toHaveClass
(
'is-disabled'
);
});
it
(
'should be disabled on the final page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.next-page-link'
)).
toHaveClass
(
'is-disabled'
);
});
it
(
'should be disabled on an empty page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
AjaxHelpers
.
respondWithJson
(
requests
,
mockEmptyPage
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.next-page-link'
)).
toHaveClass
(
'is-disabled'
);
});
});
describe
(
"Previous page button"
,
function
()
{
beforeEach
(
function
()
{
// Render the page and header so that they can react to events
pagingContainer
.
render
();
});
it
(
'does not move back if a server error occurs'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
pagingContainer
.
pagingFooter
.
$
(
'.previous-page-link'
).
click
();
requests
[
1
].
respond
(
500
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
1
);
});
it
(
'can go back a page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
pagingContainer
.
pagingFooter
.
$
(
'.previous-page-link'
).
click
();
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
0
);
});
it
(
'should be disabled on the first page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.previous-page-link'
)).
toHaveClass
(
'is-disabled'
);
});
it
(
'should be enabled on the second page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.previous-page-link'
)).
not
.
toHaveClass
(
'is-disabled'
);
});
it
(
'should be disabled for an empty page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
AjaxHelpers
.
respondWithJson
(
requests
,
mockEmptyPage
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.previous-page-link'
)).
toHaveClass
(
'is-disabled'
);
});
});
describe
(
"Current page label"
,
function
()
{
it
(
'should show 1 on the first page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.current-page'
)).
toHaveText
(
'1'
);
});
it
(
'should show 2 on the second page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
1
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.current-page'
)).
toHaveText
(
'2'
);
});
it
(
'should show 1 for an empty collection'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
AjaxHelpers
.
respondWithJson
(
requests
,
mockEmptyPage
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.current-page'
)).
toHaveText
(
'1'
);
});
});
describe
(
"Page total label"
,
function
()
{
it
(
'should show the correct value with more than one page'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.total-pages'
)).
toHaveText
(
'2'
);
});
it
(
'should show page 1 when there are no assets'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
AjaxHelpers
.
respondWithJson
(
requests
,
mockEmptyPage
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.total-pages'
)).
toHaveText
(
'1'
);
});
});
describe
(
"Page input field"
,
function
()
{
var
input
;
it
(
'should initially have a blank page input'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.page-number-input'
)).
toHaveValue
(
''
);
});
it
(
'should handle invalid page requests'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
pagingContainer
.
pagingFooter
.
$
(
'.page-number-input'
).
val
(
'abc'
);
pagingContainer
.
pagingFooter
.
$
(
'.page-number-input'
).
trigger
(
'change'
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
0
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.page-number-input'
)).
toHaveValue
(
''
);
});
it
(
'should switch pages via the input field'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
pagingContainer
.
pagingFooter
.
$
(
'.page-number-input'
).
val
(
'2'
);
pagingContainer
.
pagingFooter
.
$
(
'.page-number-input'
).
trigger
(
'change'
);
AjaxHelpers
.
respondWithJson
(
requests
,
mockSecondPage
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
1
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.page-number-input'
)).
toHaveValue
(
''
);
});
it
(
'should handle AJAX failures when switching pages via the input field'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
pagingContainer
.
setPage
(
0
);
respondWithMockPage
(
requests
);
pagingContainer
.
pagingFooter
.
$
(
'.page-number-input'
).
val
(
'2'
);
pagingContainer
.
pagingFooter
.
$
(
'.page-number-input'
).
trigger
(
'change'
);
requests
[
1
].
respond
(
500
);
expect
(
pagingContainer
.
collection
.
currentPage
).
toBe
(
0
);
expect
(
pagingContainer
.
pagingFooter
.
$
(
'.page-number-input'
)).
toHaveValue
(
''
);
});
});
});
});
});
cms/static/js/spec/views/pages/container_spec.js
View file @
ff1a08cb
...
@@ -3,11 +3,13 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -3,11 +3,13 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
"js/views/pages/container"
,
"js/models/xblock_info"
,
"jquery.simulate"
],
"js/views/pages/container"
,
"js/models/xblock_info"
,
"jquery.simulate"
],
function
(
$
,
_
,
str
,
AjaxHelpers
,
TemplateHelpers
,
EditHelpers
,
ContainerPage
,
XBlockInfo
)
{
function
(
$
,
_
,
str
,
AjaxHelpers
,
TemplateHelpers
,
EditHelpers
,
ContainerPage
,
XBlockInfo
)
{
describe
(
"ContainerPage"
,
function
()
{
function
parameterized_suite
(
label
,
global_page_options
,
fixtures
)
{
var
lastRequest
,
renderContainerPage
,
expectComponents
,
respondWithHtml
,
describe
(
label
+
" ContainerPage"
,
function
()
{
var
lastRequest
,
getContainerPage
,
renderContainerPage
,
expectComponents
,
respondWithHtml
,
model
,
containerPage
,
requests
,
initialDisplayName
,
model
,
containerPage
,
requests
,
initialDisplayName
,
mockContainerPage
=
readFixtures
(
'mock/mock-container-page.underscore'
),
mockContainerPage
=
readFixtures
(
'mock/mock-container-page.underscore'
),
mockContainerXBlockHtml
=
readFixtures
(
'mock/mock-container-xblock.underscore'
),
mockContainerXBlockHtml
=
readFixtures
(
fixtures
.
initial
),
mockXBlockHtml
=
readFixtures
(
fixtures
.
add_response
),
mockBadContainerXBlockHtml
=
readFixtures
(
'mock/mock-bad-javascript-container-xblock.underscore'
),
mockBadContainerXBlockHtml
=
readFixtures
(
'mock/mock-bad-javascript-container-xblock.underscore'
),
mockBadXBlockContainerXBlockHtml
=
readFixtures
(
'mock/mock-bad-xblock-container-xblock.underscore'
),
mockBadXBlockContainerXBlockHtml
=
readFixtures
(
'mock/mock-bad-xblock-container-xblock.underscore'
),
mockUpdatedContainerXBlockHtml
=
readFixtures
(
'mock/mock-updated-container-xblock.underscore'
),
mockUpdatedContainerXBlockHtml
=
readFixtures
(
'mock/mock-updated-container-xblock.underscore'
),
...
@@ -37,13 +39,15 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -37,13 +39,15 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
});
});
});
});
afterEach
(
function
()
{
afterEach
(
function
()
{
EditHelpers
.
uninstallMockXBlock
();
EditHelpers
.
uninstallMockXBlock
();
});
});
lastRequest
=
function
()
{
return
requests
[
requests
.
length
-
1
];
};
lastRequest
=
function
()
{
return
requests
[
requests
.
length
-
1
];
};
respondWithHtml
=
function
(
html
)
{
respondWithHtml
=
function
(
html
)
{
var
requestIndex
=
requests
.
length
-
1
;
var
requestIndex
=
requests
.
length
-
1
;
AjaxHelpers
.
respondWithJson
(
AjaxHelpers
.
respondWithJson
(
requests
,
requests
,
...
@@ -52,13 +56,18 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -52,13 +56,18 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
);
);
};
};
renderContainerPage
=
function
(
test
,
html
,
options
)
{
getContainerPage
=
function
(
options
)
{
requests
=
AjaxHelpers
.
requests
(
test
);
var
default_options
=
{
containerPage
=
new
ContainerPage
(
_
.
extend
(
options
||
{},
{
model
:
model
,
model
:
model
,
templates
:
EditHelpers
.
mockComponentTemplates
,
templates
:
EditHelpers
.
mockComponentTemplates
,
el
:
$
(
'#content'
)
el
:
$
(
'#content'
)
}));
};
return
new
ContainerPage
(
_
.
extend
(
options
||
{},
global_page_options
,
default_options
));
};
renderContainerPage
=
function
(
test
,
html
,
options
)
{
requests
=
AjaxHelpers
.
requests
(
test
);
containerPage
=
getContainerPage
(
options
);
containerPage
.
render
();
containerPage
.
render
();
respondWithHtml
(
html
);
respondWithHtml
(
html
);
};
};
...
@@ -67,39 +76,40 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -67,39 +76,40 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
// verify expected components (in expected order) by their locators
// verify expected components (in expected order) by their locators
var
components
=
$
(
container
).
find
(
'.studio-xblock-wrapper'
);
var
components
=
$
(
container
).
find
(
'.studio-xblock-wrapper'
);
expect
(
components
.
length
).
toBe
(
locators
.
length
);
expect
(
components
.
length
).
toBe
(
locators
.
length
);
_
.
each
(
locators
,
function
(
locator
,
locator_index
)
{
_
.
each
(
locators
,
function
(
locator
,
locator_index
)
{
expect
(
$
(
components
[
locator_index
]).
data
(
'locator'
)).
toBe
(
locator
);
expect
(
$
(
components
[
locator_index
]).
data
(
'locator'
)).
toBe
(
locator
);
});
});
};
};
describe
(
"Initial display"
,
function
()
{
describe
(
"Initial display"
,
function
()
{
it
(
'can render itself'
,
function
()
{
it
(
'can render itself'
,
function
()
{
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
expect
(
containerPage
.
$
(
'.xblock-header'
).
length
).
toBe
(
9
);
expect
(
containerPage
.
$
(
'.xblock-header'
).
length
).
toBe
(
9
);
expect
(
containerPage
.
$
(
'.wrapper-xblock .level-nesting'
)).
not
.
toHaveClass
(
'is-hidden'
);
expect
(
containerPage
.
$
(
'.wrapper-xblock .level-nesting'
)).
not
.
toHaveClass
(
'is-hidden'
);
});
});
it
(
'shows a loading indicator'
,
function
()
{
it
(
'shows a loading indicator'
,
function
()
{
requests
=
AjaxHelpers
.
requests
(
this
);
requests
=
AjaxHelpers
.
requests
(
this
);
containerPage
=
getContainerPage
();
containerPage
.
render
();
containerPage
.
render
();
expect
(
containerPage
.
$
(
'.ui-loading'
)).
not
.
toHaveClass
(
'is-hidden'
);
expect
(
containerPage
.
$
(
'.ui-loading'
)).
not
.
toHaveClass
(
'is-hidden'
);
respondWithHtml
(
mockContainerXBlockHtml
);
respondWithHtml
(
mockContainerXBlockHtml
);
expect
(
containerPage
.
$
(
'.ui-loading'
)).
toHaveClass
(
'is-hidden'
);
expect
(
containerPage
.
$
(
'.ui-loading'
)).
toHaveClass
(
'is-hidden'
);
});
});
it
(
'can show an xblock with broken JavaScript'
,
function
()
{
it
(
'can show an xblock with broken JavaScript'
,
function
()
{
renderContainerPage
(
this
,
mockBadContainerXBlockHtml
);
renderContainerPage
(
this
,
mockBadContainerXBlockHtml
);
expect
(
containerPage
.
$
(
'.wrapper-xblock .level-nesting'
)).
not
.
toHaveClass
(
'is-hidden'
);
expect
(
containerPage
.
$
(
'.wrapper-xblock .level-nesting'
)).
not
.
toHaveClass
(
'is-hidden'
);
expect
(
containerPage
.
$
(
'.ui-loading'
)).
toHaveClass
(
'is-hidden'
);
expect
(
containerPage
.
$
(
'.ui-loading'
)).
toHaveClass
(
'is-hidden'
);
});
});
it
(
'can show an xblock with an invalid XBlock'
,
function
()
{
it
(
'can show an xblock with an invalid XBlock'
,
function
()
{
renderContainerPage
(
this
,
mockBadXBlockContainerXBlockHtml
);
renderContainerPage
(
this
,
mockBadXBlockContainerXBlockHtml
);
expect
(
containerPage
.
$
(
'.wrapper-xblock .level-nesting'
)).
not
.
toHaveClass
(
'is-hidden'
);
expect
(
containerPage
.
$
(
'.wrapper-xblock .level-nesting'
)).
not
.
toHaveClass
(
'is-hidden'
);
expect
(
containerPage
.
$
(
'.ui-loading'
)).
toHaveClass
(
'is-hidden'
);
expect
(
containerPage
.
$
(
'.ui-loading'
)).
toHaveClass
(
'is-hidden'
);
});
});
it
(
'inline edits the display name when performing a new action'
,
function
()
{
it
(
'inline edits the display name when performing a new action'
,
function
()
{
renderContainerPage
(
this
,
mockContainerXBlockHtml
,
{
renderContainerPage
(
this
,
mockContainerXBlockHtml
,
{
action
:
'new'
action
:
'new'
});
});
...
@@ -109,19 +119,19 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -109,19 +119,19 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
});
});
});
});
describe
(
"Editing the container"
,
function
()
{
describe
(
"Editing the container"
,
function
()
{
var
updatedDisplayName
=
'Updated Test Container'
,
var
updatedDisplayName
=
'Updated Test Container'
,
getDisplayNameWrapper
;
getDisplayNameWrapper
;
afterEach
(
function
()
{
afterEach
(
function
()
{
EditHelpers
.
cancelModalIfShowing
();
EditHelpers
.
cancelModalIfShowing
();
});
});
getDisplayNameWrapper
=
function
()
{
getDisplayNameWrapper
=
function
()
{
return
containerPage
.
$
(
'.wrapper-xblock-field'
);
return
containerPage
.
$
(
'.wrapper-xblock-field'
);
};
};
it
(
'can edit itself'
,
function
()
{
it
(
'can edit itself'
,
function
()
{
var
editButtons
,
displayNameElement
;
var
editButtons
,
displayNameElement
;
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
displayNameElement
=
containerPage
.
$
(
'.page-header-title'
);
displayNameElement
=
containerPage
.
$
(
'.page-header-title'
);
...
@@ -161,7 +171,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -161,7 +171,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
expect
(
displayNameElement
.
text
().
trim
()).
toBe
(
updatedDisplayName
);
expect
(
displayNameElement
.
text
().
trim
()).
toBe
(
updatedDisplayName
);
});
});
it
(
'can inline edit the display name'
,
function
()
{
it
(
'can inline edit the display name'
,
function
()
{
var
displayNameInput
,
displayNameWrapper
;
var
displayNameInput
,
displayNameWrapper
;
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
displayNameWrapper
=
getDisplayNameWrapper
();
displayNameWrapper
=
getDisplayNameWrapper
();
...
@@ -176,12 +186,12 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -176,12 +186,12 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
});
});
});
});
describe
(
"Editing an xblock"
,
function
()
{
describe
(
"Editing an xblock"
,
function
()
{
afterEach
(
function
()
{
afterEach
(
function
()
{
EditHelpers
.
cancelModalIfShowing
();
EditHelpers
.
cancelModalIfShowing
();
});
});
it
(
'can show an edit modal for a child xblock'
,
function
()
{
it
(
'can show an edit modal for a child xblock'
,
function
()
{
var
editButtons
;
var
editButtons
;
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
editButtons
=
containerPage
.
$
(
'.wrapper-xblock .edit-button'
);
editButtons
=
containerPage
.
$
(
'.wrapper-xblock .edit-button'
);
...
@@ -197,7 +207,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -197,7 +207,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
expect
(
EditHelpers
.
isShowingModal
()).
toBeTruthy
();
expect
(
EditHelpers
.
isShowingModal
()).
toBeTruthy
();
});
});
it
(
'can show an edit modal for a child xblock with broken JavaScript'
,
function
()
{
it
(
'can show an edit modal for a child xblock with broken JavaScript'
,
function
()
{
var
editButtons
;
var
editButtons
;
renderContainerPage
(
this
,
mockBadContainerXBlockHtml
);
renderContainerPage
(
this
,
mockBadContainerXBlockHtml
);
editButtons
=
containerPage
.
$
(
'.wrapper-xblock .edit-button'
);
editButtons
=
containerPage
.
$
(
'.wrapper-xblock .edit-button'
);
...
@@ -210,7 +220,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -210,7 +220,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
});
});
});
});
describe
(
"Editing an xmodule"
,
function
()
{
describe
(
"Editing an xmodule"
,
function
()
{
var
mockXModuleEditor
=
readFixtures
(
'mock/mock-xmodule-editor.underscore'
),
var
mockXModuleEditor
=
readFixtures
(
'mock/mock-xmodule-editor.underscore'
),
newDisplayName
=
'New Display Name'
;
newDisplayName
=
'New Display Name'
;
...
@@ -223,12 +233,12 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -223,12 +233,12 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
});
});
});
});
afterEach
(
function
()
{
afterEach
(
function
()
{
EditHelpers
.
uninstallMockXModule
();
EditHelpers
.
uninstallMockXModule
();
EditHelpers
.
cancelModalIfShowing
();
EditHelpers
.
cancelModalIfShowing
();
});
});
it
(
'can save changes to settings'
,
function
()
{
it
(
'can save changes to settings'
,
function
()
{
var
editButtons
,
modal
,
mockUpdatedXBlockHtml
;
var
editButtons
,
modal
,
mockUpdatedXBlockHtml
;
mockUpdatedXBlockHtml
=
readFixtures
(
'mock/mock-updated-xblock.underscore'
);
mockUpdatedXBlockHtml
=
readFixtures
(
'mock/mock-updated-xblock.underscore'
);
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
...
@@ -262,27 +272,29 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -262,27 +272,29 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
});
});
});
});
describe
(
"xblock operations"
,
function
()
{
describe
(
"xblock operations"
,
function
()
{
var
getGroupElement
,
var
getGroupElement
,
NUM_COMPONENTS_PER_GROUP
=
3
,
GROUP_TO_TEST
=
"A"
,
NUM_COMPONENTS_PER_GROUP
=
3
,
GROUP_TO_TEST
=
"A"
,
allComponentsInGroup
=
_
.
map
(
allComponentsInGroup
=
_
.
map
(
_
.
range
(
NUM_COMPONENTS_PER_GROUP
),
_
.
range
(
NUM_COMPONENTS_PER_GROUP
),
function
(
index
)
{
return
'locator-component-'
+
GROUP_TO_TEST
+
(
index
+
1
);
}
function
(
index
)
{
return
'locator-component-'
+
GROUP_TO_TEST
+
(
index
+
1
);
}
);
);
getGroupElement
=
function
()
{
getGroupElement
=
function
()
{
return
containerPage
.
$
(
"[data-locator='locator-group-"
+
GROUP_TO_TEST
+
"']"
);
return
containerPage
.
$
(
"[data-locator='locator-group-"
+
GROUP_TO_TEST
+
"']"
);
};
};
describe
(
"Deleting an xblock"
,
function
()
{
describe
(
"Deleting an xblock"
,
function
()
{
var
clickDelete
,
deleteComponent
,
deleteComponentWithSuccess
,
var
clickDelete
,
deleteComponent
,
deleteComponentWithSuccess
,
promptSpy
;
promptSpy
;
beforeEach
(
function
()
{
beforeEach
(
function
()
{
promptSpy
=
EditHelpers
.
createPromptSpy
();
promptSpy
=
EditHelpers
.
createPromptSpy
();
});
});
clickDelete
=
function
(
componentIndex
,
clickNo
)
{
clickDelete
=
function
(
componentIndex
,
clickNo
)
{
// find all delete buttons for the given group
// find all delete buttons for the given group
var
deleteButtons
=
getGroupElement
().
find
(
".delete-button"
);
var
deleteButtons
=
getGroupElement
().
find
(
".delete-button"
);
...
@@ -295,7 +307,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -295,7 +307,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
EditHelpers
.
confirmPrompt
(
promptSpy
,
clickNo
);
EditHelpers
.
confirmPrompt
(
promptSpy
,
clickNo
);
};
};
deleteComponent
=
function
(
componentIndex
)
{
deleteComponent
=
function
(
componentIndex
)
{
clickDelete
(
componentIndex
);
clickDelete
(
componentIndex
);
AjaxHelpers
.
respondWithJson
(
requests
,
{});
AjaxHelpers
.
respondWithJson
(
requests
,
{});
...
@@ -308,7 +320,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -308,7 +320,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
AjaxHelpers
.
expectJsonRequest
(
requests
,
'GET'
,
'/xblock/locator-container'
);
AjaxHelpers
.
expectJsonRequest
(
requests
,
'GET'
,
'/xblock/locator-container'
);
};
};
deleteComponentWithSuccess
=
function
(
componentIndex
)
{
deleteComponentWithSuccess
=
function
(
componentIndex
)
{
deleteComponent
(
componentIndex
);
deleteComponent
(
componentIndex
);
// verify the new list of components within the group
// verify the new list of components within the group
...
@@ -318,22 +330,22 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -318,22 +330,22 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
);
);
};
};
it
(
"can delete the first xblock"
,
function
()
{
it
(
"can delete the first xblock"
,
function
()
{
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
deleteComponentWithSuccess
(
0
);
deleteComponentWithSuccess
(
0
);
});
});
it
(
"can delete a middle xblock"
,
function
()
{
it
(
"can delete a middle xblock"
,
function
()
{
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
deleteComponentWithSuccess
(
1
);
deleteComponentWithSuccess
(
1
);
});
});
it
(
"can delete the last xblock"
,
function
()
{
it
(
"can delete the last xblock"
,
function
()
{
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
deleteComponentWithSuccess
(
NUM_COMPONENTS_PER_GROUP
-
1
);
deleteComponentWithSuccess
(
NUM_COMPONENTS_PER_GROUP
-
1
);
});
});
it
(
"can delete an xblock with broken JavaScript"
,
function
()
{
it
(
"can delete an xblock with broken JavaScript"
,
function
()
{
renderContainerPage
(
this
,
mockBadContainerXBlockHtml
);
renderContainerPage
(
this
,
mockBadContainerXBlockHtml
);
containerPage
.
$
(
'.delete-button'
).
first
().
click
();
containerPage
.
$
(
'.delete-button'
).
first
().
click
();
EditHelpers
.
confirmPrompt
(
promptSpy
);
EditHelpers
.
confirmPrompt
(
promptSpy
);
...
@@ -361,7 +373,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -361,7 +373,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
expect
(
requests
.
length
).
toBe
(
numRequests
);
expect
(
requests
.
length
).
toBe
(
numRequests
);
});
});
it
(
'shows a notification during the delete operation'
,
function
()
{
it
(
'shows a notification during the delete operation'
,
function
()
{
var
notificationSpy
=
EditHelpers
.
createNotificationSpy
();
var
notificationSpy
=
EditHelpers
.
createNotificationSpy
();
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
clickDelete
(
0
);
clickDelete
(
0
);
...
@@ -381,11 +393,11 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -381,11 +393,11 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
});
});
});
});
describe
(
"Duplicating an xblock"
,
function
()
{
describe
(
"Duplicating an xblock"
,
function
()
{
var
clickDuplicate
,
duplicateComponentWithSuccess
,
var
clickDuplicate
,
duplicateComponentWithSuccess
,
refreshXBlockSpies
;
refreshXBlockSpies
;
clickDuplicate
=
function
(
componentIndex
)
{
clickDuplicate
=
function
(
componentIndex
)
{
// find all duplicate buttons for the given group
// find all duplicate buttons for the given group
var
duplicateButtons
=
getGroupElement
().
find
(
".duplicate-button"
);
var
duplicateButtons
=
getGroupElement
().
find
(
".duplicate-button"
);
...
@@ -395,7 +407,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -395,7 +407,7 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
duplicateButtons
[
componentIndex
].
click
();
duplicateButtons
[
componentIndex
].
click
();
};
};
duplicateComponentWithSuccess
=
function
(
componentIndex
)
{
duplicateComponentWithSuccess
=
function
(
componentIndex
)
{
refreshXBlockSpies
=
spyOn
(
containerPage
,
"refreshXBlock"
);
refreshXBlockSpies
=
spyOn
(
containerPage
,
"refreshXBlock"
);
clickDuplicate
(
componentIndex
);
clickDuplicate
(
componentIndex
);
...
@@ -415,22 +427,22 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -415,22 +427,22 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
expect
(
refreshXBlockSpies
).
toHaveBeenCalled
();
expect
(
refreshXBlockSpies
).
toHaveBeenCalled
();
};
};
it
(
"can duplicate the first xblock"
,
function
()
{
it
(
"can duplicate the first xblock"
,
function
()
{
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
duplicateComponentWithSuccess
(
0
);
duplicateComponentWithSuccess
(
0
);
});
});
it
(
"can duplicate a middle xblock"
,
function
()
{
it
(
"can duplicate a middle xblock"
,
function
()
{
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
duplicateComponentWithSuccess
(
1
);
duplicateComponentWithSuccess
(
1
);
});
});
it
(
"can duplicate the last xblock"
,
function
()
{
it
(
"can duplicate the last xblock"
,
function
()
{
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
renderContainerPage
(
this
,
mockContainerXBlockHtml
);
duplicateComponentWithSuccess
(
NUM_COMPONENTS_PER_GROUP
-
1
);
duplicateComponentWithSuccess
(
NUM_COMPONENTS_PER_GROUP
-
1
);
});
});
it
(
"can duplicate an xblock with broken JavaScript"
,
function
()
{
it
(
"can duplicate an xblock with broken JavaScript"
,
function
()
{
renderContainerPage
(
this
,
mockBadContainerXBlockHtml
);
renderContainerPage
(
this
,
mockBadContainerXBlockHtml
);
containerPage
.
$
(
'.duplicate-button'
).
first
().
click
();
containerPage
.
$
(
'.duplicate-button'
).
first
().
click
();
AjaxHelpers
.
expectJsonRequest
(
requests
,
'POST'
,
'/xblock/'
,
{
AjaxHelpers
.
expectJsonRequest
(
requests
,
'POST'
,
'/xblock/'
,
{
...
@@ -498,15 +510,14 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -498,15 +510,14 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
expectComponents
(
getGroupElement
(),
allComponentsInGroup
);
expectComponents
(
getGroupElement
(),
allComponentsInGroup
);
});
});
describe
(
'Template Picker'
,
function
()
{
describe
(
'Template Picker'
,
function
()
{
var
showTemplatePicker
,
verifyCreateHtmlComponent
,
var
showTemplatePicker
,
verifyCreateHtmlComponent
;
mockXBlockHtml
=
readFixtures
(
'mock/mock-xblock.underscore'
);
showTemplatePicker
=
function
()
{
showTemplatePicker
=
function
()
{
containerPage
.
$
(
'.new-component .new-component-type a.multiple-templates'
)[
0
].
click
();
containerPage
.
$
(
'.new-component .new-component-type a.multiple-templates'
)[
0
].
click
();
};
};
verifyCreateHtmlComponent
=
function
(
test
,
templateIndex
,
expectedRequest
)
{
verifyCreateHtmlComponent
=
function
(
test
,
templateIndex
,
expectedRequest
)
{
var
xblockCount
;
var
xblockCount
;
renderContainerPage
(
test
,
mockContainerXBlockHtml
);
renderContainerPage
(
test
,
mockContainerXBlockHtml
);
showTemplatePicker
();
showTemplatePicker
();
...
@@ -518,17 +529,17 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -518,17 +529,17 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
expect
(
containerPage
.
$
(
'.studio-xblock-wrapper'
).
length
).
toBe
(
xblockCount
+
1
);
expect
(
containerPage
.
$
(
'.studio-xblock-wrapper'
).
length
).
toBe
(
xblockCount
+
1
);
};
};
it
(
'can add an HTML component without a template'
,
function
()
{
it
(
'can add an HTML component without a template'
,
function
()
{
verifyCreateHtmlComponent
(
this
,
0
,
{
verifyCreateHtmlComponent
(
this
,
0
,
{
"category"
:
"html"
,
"category"
:
"html"
,
"parent_locator"
:
"locator-group-A"
"parent_locator"
:
"locator-group-A"
});
});
});
});
it
(
'can add an HTML component with a template'
,
function
()
{
it
(
'can add an HTML component with a template'
,
function
()
{
verifyCreateHtmlComponent
(
this
,
1
,
{
verifyCreateHtmlComponent
(
this
,
1
,
{
"category"
:
"html"
,
"category"
:
"html"
,
"boilerplate"
:
"announcement.yaml"
,
"boilerplate"
:
"announcement.yaml"
,
"parent_locator"
:
"locator-group-A"
"parent_locator"
:
"locator-group-A"
});
});
});
});
...
@@ -536,4 +547,16 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
...
@@ -536,4 +547,16 @@ define(["jquery", "underscore", "underscore.string", "js/common_helpers/ajax_hel
});
});
});
});
});
});
}
parameterized_suite
(
"Non paged"
,
{
enable_paging
:
false
},
{
initial
:
'mock/mock-container-xblock.underscore'
,
add_response
:
'mock/mock-xblock.underscore'
}
);
parameterized_suite
(
"Paged"
,
{
enable_paging
:
true
,
page_size
:
42
},
{
initial
:
'mock/mock-container-paged-xblock.underscore'
,
add_response
:
'mock/mock-container-paged-after-add-xblock.underscore'
});
});
});
cms/static/js/views/container.js
View file @
ff1a08cb
...
@@ -123,6 +123,10 @@ define(["jquery", "underscore", "js/views/xblock", "js/utils/module", "gettext",
...
@@ -123,6 +123,10 @@ define(["jquery", "underscore", "js/views/xblock", "js/utils/module", "gettext",
});
});
},
},
acknowledgeXBlockDeletion
:
function
(
locator
){
this
.
notifyRuntime
(
'deleted-child'
,
locator
);
},
refresh
:
function
()
{
refresh
:
function
()
{
var
sortableInitializedClass
=
this
.
makeRequestSpecificSelector
(
'.reorderable-container.ui-sortable'
);
var
sortableInitializedClass
=
this
.
makeRequestSpecificSelector
(
'.reorderable-container.ui-sortable'
);
this
.
$
(
sortableInitializedClass
).
sortable
(
'refresh'
);
this
.
$
(
sortableInitializedClass
).
sortable
(
'refresh'
);
...
...
cms/static/js/views/library_container.js
0 → 100644
View file @
ff1a08cb
define
([
"jquery"
,
"underscore"
,
"js/views/xblock"
,
"js/utils/module"
,
"gettext"
,
"js/views/feedback_notification"
,
"js/views/paging_header"
,
"js/views/paging_footer"
],
function
(
$
,
_
,
XBlockView
,
ModuleUtils
,
gettext
,
NotificationView
,
PagingHeader
,
PagingFooter
)
{
var
LibraryContainerView
=
XBlockView
.
extend
({
// Store the request token of the first xblock on the page (which we know was rendered by Studio when
// the page was generated). Use that request token to filter out user-defined HTML in any
// child xblocks within the page.
requestToken
:
""
,
initialize
:
function
(
options
){
var
self
=
this
;
XBlockView
.
prototype
.
initialize
.
call
(
this
);
this
.
page_size
=
this
.
options
.
page_size
||
10
;
if
(
options
)
{
this
.
page_reload_callback
=
options
.
page_reload_callback
;
}
// emulating Backbone.paginator interface
this
.
collection
=
{
currentPage
:
0
,
totalPages
:
0
,
totalCount
:
0
,
sortDirection
:
"desc"
,
start
:
0
,
_size
:
0
,
bind
:
function
()
{},
// no-op
size
:
function
()
{
return
self
.
collection
.
_size
;
}
};
},
render
:
function
(
options
)
{
var
eff_options
=
options
||
{};
if
(
eff_options
.
block_added
)
{
this
.
collection
.
currentPage
=
this
.
getPageCount
(
this
.
collection
.
totalCount
+
1
)
-
1
;
}
eff_options
.
page_number
=
typeof
eff_options
.
page_number
!==
"undefined"
?
eff_options
.
page_number
:
this
.
collection
.
currentPage
;
return
this
.
renderPage
(
eff_options
);
},
renderPage
:
function
(
options
){
var
self
=
this
,
view
=
this
.
view
,
xblockInfo
=
this
.
model
,
xblockUrl
=
xblockInfo
.
url
();
return
$
.
ajax
({
url
:
decodeURIComponent
(
xblockUrl
)
+
"/"
+
view
,
type
:
'GET'
,
cache
:
false
,
data
:
this
.
getRenderParameters
(
options
.
page_number
),
headers
:
{
Accept
:
'application/json'
},
success
:
function
(
fragment
)
{
self
.
handleXBlockFragment
(
fragment
,
options
);
self
.
processPaging
({
requested_page
:
options
.
page_number
});
if
(
options
.
paging
&&
self
.
page_reload_callback
){
self
.
page_reload_callback
(
self
.
$el
);
}
}
});
},
getRenderParameters
:
function
(
page_number
)
{
return
{
enable_paging
:
true
,
page_size
:
this
.
page_size
,
page_number
:
page_number
};
},
getPageCount
:
function
(
total_count
){
if
(
total_count
==
0
)
return
1
;
return
Math
.
ceil
(
total_count
/
this
.
page_size
);
},
setPage
:
function
(
page_number
)
{
this
.
render
({
page_number
:
page_number
,
paging
:
true
});
},
nextPage
:
function
()
{
var
collection
=
this
.
collection
,
currentPage
=
collection
.
currentPage
,
lastPage
=
collection
.
totalPages
-
1
;
if
(
currentPage
<
lastPage
)
{
this
.
setPage
(
currentPage
+
1
);
}
},
previousPage
:
function
()
{
var
collection
=
this
.
collection
,
currentPage
=
collection
.
currentPage
;
if
(
currentPage
>
0
)
{
this
.
setPage
(
currentPage
-
1
);
}
},
processPaging
:
function
(
options
){
var
$element
=
this
.
$el
.
find
(
'.xblock-container-paging-parameters'
),
total
=
$element
.
data
(
'total'
),
displayed
=
$element
.
data
(
'displayed'
),
start
=
$element
.
data
(
'start'
);
this
.
collection
.
currentPage
=
options
.
requested_page
;
this
.
collection
.
totalCount
=
total
;
this
.
collection
.
totalPages
=
this
.
getPageCount
(
total
);
this
.
collection
.
start
=
start
;
this
.
collection
.
_size
=
displayed
;
this
.
processPagingHeaderAndFooter
();
},
processPagingHeaderAndFooter
:
function
(){
if
(
this
.
pagingHeader
)
this
.
pagingHeader
.
undelegateEvents
();
if
(
this
.
pagingFooter
)
this
.
pagingFooter
.
undelegateEvents
();
this
.
pagingHeader
=
new
PagingHeader
({
view
:
this
,
el
:
this
.
$el
.
find
(
'.container-paging-header'
)
});
this
.
pagingFooter
=
new
PagingFooter
({
view
:
this
,
el
:
this
.
$el
.
find
(
'.container-paging-footer'
)
});
this
.
pagingHeader
.
render
();
this
.
pagingFooter
.
render
();
},
xblockReady
:
function
()
{
XBlockView
.
prototype
.
xblockReady
.
call
(
this
);
this
.
requestToken
=
this
.
$
(
'div.xblock'
).
first
().
data
(
'request-token'
);
},
refresh
:
function
()
{
},
acknowledgeXBlockDeletion
:
function
(
locator
){
this
.
notifyRuntime
(
'deleted-child'
,
locator
);
this
.
collection
.
_size
-=
1
;
this
.
collection
.
totalCount
-=
1
;
// pages are counted from 0 - thus currentPage == 1 if we're on second page
if
(
this
.
collection
.
_size
==
0
&&
this
.
collection
.
currentPage
>=
1
)
{
this
.
setPage
(
this
.
collection
.
currentPage
-
1
);
this
.
collection
.
totalPages
-=
1
;
}
else
{
this
.
pagingHeader
.
render
();
this
.
pagingFooter
.
render
();
}
},
makeRequestSpecificSelector
:
function
(
selector
)
{
return
'div.xblock[data-request-token="'
+
this
.
requestToken
+
'"] > '
+
selector
;
},
sortDisplayName
:
function
()
{
return
"Date added"
;
// TODO add support for sorting
}
});
return
LibraryContainerView
;
});
// end define();
cms/static/js/views/pages/container.js
View file @
ff1a08cb
...
@@ -3,10 +3,10 @@
...
@@ -3,10 +3,10 @@
* 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"
,
"js/views/utils/view_utils"
,
define
([
"jquery"
,
"underscore"
,
"gettext"
,
"js/views/pages/base_page"
,
"js/views/utils/view_utils"
,
"js/views/container"
,
"js/views/xblock"
,
"js/views/components/add_xblock"
,
"js/views/modals/edit_xblock"
,
"js/views/container"
,
"js/views/
library_container"
,
"js/views/
xblock"
,
"js/views/components/add_xblock"
,
"js/views/modals/edit_xblock"
,
"js/models/xblock_info"
,
"js/views/xblock_string_field_editor"
,
"js/views/pages/container_subviews"
,
"js/models/xblock_info"
,
"js/views/xblock_string_field_editor"
,
"js/views/pages/container_subviews"
,
"js/views/unit_outline"
,
"js/views/utils/xblock_utils"
],
"js/views/unit_outline"
,
"js/views/utils/xblock_utils"
],
function
(
$
,
_
,
gettext
,
BasePage
,
ViewUtils
,
ContainerView
,
XBlockView
,
AddXBlockComponent
,
function
(
$
,
_
,
gettext
,
BasePage
,
ViewUtils
,
ContainerView
,
PagedContainerView
,
XBlockView
,
AddXBlockComponent
,
EditXBlockModal
,
XBlockInfo
,
XBlockStringFieldEditor
,
ContainerSubviews
,
UnitOutlineView
,
EditXBlockModal
,
XBlockInfo
,
XBlockStringFieldEditor
,
ContainerSubviews
,
UnitOutlineView
,
XBlockUtils
)
{
XBlockUtils
)
{
'use strict'
;
'use strict'
;
...
@@ -27,6 +27,10 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
...
@@ -27,6 +27,10 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
initialize
:
function
(
options
)
{
initialize
:
function
(
options
)
{
BasePage
.
prototype
.
initialize
.
call
(
this
,
options
);
BasePage
.
prototype
.
initialize
.
call
(
this
,
options
);
this
.
enable_paging
=
options
.
enable_paging
||
false
;
if
(
this
.
enable_paging
)
{
this
.
page_size
=
options
.
page_size
||
10
;
}
this
.
nameEditor
=
new
XBlockStringFieldEditor
({
this
.
nameEditor
=
new
XBlockStringFieldEditor
({
el
:
this
.
$
(
'.wrapper-xblock-field'
),
el
:
this
.
$
(
'.wrapper-xblock-field'
),
model
:
this
.
model
model
:
this
.
model
...
@@ -35,11 +39,7 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
...
@@ -35,11 +39,7 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
if
(
this
.
options
.
action
===
'new'
)
{
if
(
this
.
options
.
action
===
'new'
)
{
this
.
nameEditor
.
$
(
'.xblock-field-value-edit'
).
click
();
this
.
nameEditor
.
$
(
'.xblock-field-value-edit'
).
click
();
}
}
this
.
xblockView
=
new
ContainerView
({
this
.
xblockView
=
this
.
getXBlockView
();
el
:
this
.
$
(
'.wrapper-xblock'
),
model
:
this
.
model
,
view
:
this
.
view
});
this
.
messageView
=
new
ContainerSubviews
.
MessageView
({
this
.
messageView
=
new
ContainerSubviews
.
MessageView
({
el
:
this
.
$
(
'.container-message'
),
el
:
this
.
$
(
'.container-message'
),
model
:
this
.
model
model
:
this
.
model
...
@@ -75,6 +75,28 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
...
@@ -75,6 +75,28 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
}
}
},
},
getXBlockView
:
function
(){
var
self
=
this
,
parameters
=
{
el
:
this
.
$
(
'.wrapper-xblock'
),
model
:
this
.
model
,
view
:
this
.
view
};
if
(
this
.
enable_paging
)
{
parameters
=
_
.
extend
(
parameters
,
{
page_size
:
this
.
page_size
,
page_reload_callback
:
function
(
$element
)
{
self
.
renderAddXBlockComponents
();
}
});
return
new
PagedContainerView
(
parameters
);
}
else
{
return
new
ContainerView
(
parameters
);
}
},
render
:
function
(
options
)
{
render
:
function
(
options
)
{
var
self
=
this
,
var
self
=
this
,
xblockView
=
this
.
xblockView
,
xblockView
=
this
.
xblockView
,
...
@@ -106,7 +128,8 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
...
@@ -106,7 +128,8 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
// Re-enable Backbone events for any updated DOM elements
// Re-enable Backbone events for any updated DOM elements
self
.
delegateEvents
();
self
.
delegateEvents
();
}
},
block_added
:
options
&&
options
.
block_added
});
});
},
},
...
@@ -144,7 +167,7 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
...
@@ -144,7 +167,7 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
modal
.
edit
(
xblockElement
,
this
.
model
,
{
modal
.
edit
(
xblockElement
,
this
.
model
,
{
refresh
:
function
()
{
refresh
:
function
()
{
self
.
refreshXBlock
(
xblockElement
);
self
.
refreshXBlock
(
xblockElement
,
false
);
}
}
});
});
},
},
...
@@ -226,7 +249,7 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
...
@@ -226,7 +249,7 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
// Inform the runtime that the child has been deleted in case
// Inform the runtime that the child has been deleted in case
// other views are listening to deletion events.
// other views are listening to deletion events.
xblockView
.
notifyRuntime
(
'deleted-child'
,
parent
.
data
(
'locator'
));
xblockView
.
acknowledgeXBlockDeletion
(
parent
.
data
(
'locator'
));
// Update publish and last modified information from the server.
// Update publish and last modified information from the server.
this
.
model
.
fetch
();
this
.
model
.
fetch
();
...
@@ -235,7 +258,7 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
...
@@ -235,7 +258,7 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
onNewXBlock
:
function
(
xblockElement
,
scrollOffset
,
data
)
{
onNewXBlock
:
function
(
xblockElement
,
scrollOffset
,
data
)
{
ViewUtils
.
setScrollOffset
(
xblockElement
,
scrollOffset
);
ViewUtils
.
setScrollOffset
(
xblockElement
,
scrollOffset
);
xblockElement
.
data
(
'locator'
,
data
.
locator
);
xblockElement
.
data
(
'locator'
,
data
.
locator
);
return
this
.
refreshXBlock
(
xblockElement
);
return
this
.
refreshXBlock
(
xblockElement
,
true
);
},
},
/**
/**
...
@@ -243,17 +266,18 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
...
@@ -243,17 +266,18 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
* reorderable container then the element will be refreshed inline. If not, then the
* reorderable container then the element will be refreshed inline. If not, then the
* parent container will be refreshed instead.
* parent container will be refreshed instead.
* @param element An element representing the xblock to be refreshed.
* @param element An element representing the xblock to be refreshed.
* @param block_added Flag to indicate that new block has been just added.
*/
*/
refreshXBlock
:
function
(
element
)
{
refreshXBlock
:
function
(
element
,
block_added
)
{
var
xblockElement
=
this
.
findXBlockElement
(
element
),
var
xblockElement
=
this
.
findXBlockElement
(
element
),
parentElement
=
xblockElement
.
parent
(),
parentElement
=
xblockElement
.
parent
(),
rootLocator
=
this
.
xblockView
.
model
.
id
;
rootLocator
=
this
.
xblockView
.
model
.
id
;
if
(
xblockElement
.
length
===
0
||
xblockElement
.
data
(
'locator'
)
===
rootLocator
)
{
if
(
xblockElement
.
length
===
0
||
xblockElement
.
data
(
'locator'
)
===
rootLocator
)
{
this
.
render
({
refresh
:
true
});
this
.
render
({
refresh
:
true
,
block_added
:
block_added
});
}
else
if
(
parentElement
.
hasClass
(
'reorderable-container'
))
{
}
else
if
(
parentElement
.
hasClass
(
'reorderable-container'
))
{
this
.
refreshChildXBlock
(
xblockElement
);
this
.
refreshChildXBlock
(
xblockElement
);
}
else
{
}
else
{
this
.
refreshXBlock
(
this
.
findXBlockElement
(
parentElement
));
this
.
refreshXBlock
(
this
.
findXBlockElement
(
parentElement
)
,
block_added
);
}
}
},
},
...
...
cms/static/js/views/paging_footer.js
View file @
ff1a08cb
...
@@ -38,6 +38,12 @@ define(["underscore", "js/views/baseview"], function(_, BaseView) {
...
@@ -38,6 +38,12 @@ define(["underscore", "js/views/baseview"], function(_, BaseView) {
currentPage
=
collection
.
currentPage
+
1
,
currentPage
=
collection
.
currentPage
+
1
,
pageInput
=
this
.
$
(
"#page-number-input"
),
pageInput
=
this
.
$
(
"#page-number-input"
),
pageNumber
=
parseInt
(
pageInput
.
val
(),
10
);
pageNumber
=
parseInt
(
pageInput
.
val
(),
10
);
if
(
pageNumber
>
collection
.
totalPages
)
{
pageNumber
=
false
;
}
if
(
pageNumber
<=
0
)
{
pageNumber
=
false
;
}
if
(
pageNumber
&&
pageNumber
!==
currentPage
)
{
if
(
pageNumber
&&
pageNumber
!==
currentPage
)
{
view
.
setPage
(
pageNumber
-
1
);
view
.
setPage
(
pageNumber
-
1
);
}
}
...
...
cms/static/sass/elements/_pagination.scss
0 → 100644
View file @
ff1a08cb
// studio - elements - pagination
// ==========================
%pagination
{
@include
clearfix
;
display
:
inline-block
;
width
:
flex-grid
(
3
,
12
);
&
.pagination-compact
{
@include
text-align
(
right
);
}
&
.pagination-full
{
display
:
block
;
width
:
flex-grid
(
4
,
12
);
margin
:
$baseline
auto
;
}
.nav-item
{
position
:
relative
;
display
:
inline-block
;
}
.nav-link
{
@include
transition
(
all
$tmg-f2
ease-in-out
0s
);
display
:
block
;
padding
:
(
$baseline
/
4
)
(
$baseline
*
0
.75
);
&
.previous
{
margin-right
:
(
$baseline
/
2
);
}
&
.next
{
margin-left
:
(
$baseline
/
2
);
}
&
:hover
{
background-color
:
$blue
;
border-radius
:
3px
;
color
:
$white
;
}
&
.is-disabled
{
background-color
:
transparent
;
color
:
$gray-l2
;
pointer-events
:
none
;
}
}
.nav-label
{
@extend
.sr
;
}
.pagination-form
,
.current-page
,
.page-divider
,
.total-pages
{
display
:
inline-block
;
}
.current-page
,
.page-number-input
,
.total-pages
{
@extend
%t-copy-base
;
@extend
%t-strong
;
width
:
(
$baseline
*
2
.5
);
margin
:
0
(
$baseline
*
0
.75
);
padding
:
(
$baseline
/
4
);
text-align
:
center
;
color
:
$gray
;
}
.current-page
{
@extend
%ui-depth1
;
position
:
absolute
;
@include
left
(
-
(
$baseline
/
4
));
}
.page-divider
{
@extend
%t-title4
;
@extend
%t-regular
;
vertical-align
:
middle
;
color
:
$gray-l2
;
}
.pagination-form
{
@extend
%ui-depth2
;
position
:
relative
;
.page-number-label
,
.submit-pagination-form
{
@extend
.sr
;
}
.page-number-input
{
@include
transition
(
all
$tmg-f2
ease-in-out
0s
);
border
:
1px
solid
transparent
;
border-bottom
:
1px
dotted
$gray-l2
;
border-radius
:
0
;
box-shadow
:
none
;
background
:
none
;
&
:hover
{
background-color
:
$white
;
opacity
:
0
.6
;
}
&
:focus
{
// borrowing the base input focus styles to match overall app
@include
linear-gradient
(
$paleYellow
,
tint
(
$paleYellow
,
90%
));
opacity
:
1
.0
;
box-shadow
:
0
0
3px
$shadow-d1
inset
;
background-color
:
$white
;
border
:
1px
solid
transparent
;
border-radius
:
3px
;
}
}
}
}
\ No newline at end of file
cms/static/sass/elements/_uploaded-assets.scss
View file @
ff1a08cb
...
@@ -28,120 +28,7 @@
...
@@ -28,120 +28,7 @@
}
}
.pagination
{
.pagination
{
@include
clearfix
;
@extend
%pagination
;
display
:
inline-block
;
width
:
flex-grid
(
3
,
12
);
&
.pagination-compact
{
@include
text-align
(
right
);
}
&
.pagination-full
{
display
:
block
;
width
:
flex-grid
(
4
,
12
);
margin
:
$baseline
auto
;
}
.nav-item
{
position
:
relative
;
display
:
inline-block
;
}
.nav-link
{
@include
transition
(
all
$tmg-f2
ease-in-out
0s
);
display
:
block
;
padding
:
(
$baseline
/
4
)
(
$baseline
*
0
.75
);
&
.previous
{
margin-right
:
(
$baseline
/
2
);
}
&
.next
{
margin-left
:
(
$baseline
/
2
);
}
&
:hover
{
background-color
:
$blue
;
border-radius
:
3px
;
color
:
$white
;
}
&
.is-disabled
{
background-color
:
transparent
;
color
:
$gray-l2
;
pointer-events
:
none
;
}
}
.nav-label
{
@extend
.sr
;
}
.pagination-form
,
.current-page
,
.page-divider
,
.total-pages
{
display
:
inline-block
;
}
.current-page
,
.page-number-input
,
.total-pages
{
@extend
%t-copy-base
;
@extend
%t-strong
;
width
:
(
$baseline
*
2
.5
);
margin
:
0
(
$baseline
*
0
.75
);
padding
:
(
$baseline
/
4
);
text-align
:
center
;
color
:
$gray
;
}
.current-page
{
@extend
%ui-depth1
;
position
:
absolute
;
@include
left
(
-
(
$baseline
/
4
));
}
.page-divider
{
@extend
%t-title4
;
@extend
%t-regular
;
vertical-align
:
middle
;
color
:
$gray-l2
;
}
.pagination-form
{
@extend
%ui-depth2
;
position
:
relative
;
.page-number-label
,
.submit-pagination-form
{
@extend
.sr
;
}
.page-number-input
{
@include
transition
(
all
$tmg-f2
ease-in-out
0s
);
border
:
1px
solid
transparent
;
border-bottom
:
1px
dotted
$gray-l2
;
border-radius
:
0
;
box-shadow
:
none
;
background
:
none
;
&
:hover
{
background-color
:
$white
;
opacity
:
0
.6
;
}
&
:focus
{
// borrowing the base input focus styles to match overall app
@include
linear-gradient
(
$paleYellow
,
tint
(
$paleYellow
,
90%
));
opacity
:
1
.0
;
box-shadow
:
0
0
3px
$shadow-d1
inset
;
background-color
:
$white
;
border
:
1px
solid
transparent
;
border-radius
:
3px
;
}
}
}
}
}
.assets-table
{
.assets-table
{
...
...
cms/static/sass/elements/_xblocks.scss
View file @
ff1a08cb
...
@@ -103,6 +103,37 @@
...
@@ -103,6 +103,37 @@
}
}
}
}
.container-paging-header
{
.meta-wrap
{
margin
:
$baseline
$baseline
/
2
;
}
.meta
{
@extend
%t-copy-sub2
;
display
:
inline-block
;
vertical-align
:
top
;
width
:
flex-grid
(
9
,
12
);
color
:
$gray-l1
;
.count-current-shown
,
.count-total
,
.sort-order
{
@extend
%t-strong
;
}
}
.pagination
{
@extend
%pagination
;
}
}
.container-paging-footer
{
.pagination
{
@extend
%pagination
;
}
}
// ====================
// ====================
//UI: default internal xblock content styles
//UI: default internal xblock content styles
...
...
cms/static/sass/style-app-extend1-rtl.scss
View file @
ff1a08cb
...
@@ -40,6 +40,7 @@
...
@@ -40,6 +40,7 @@
// +Base - Elements
// +Base - Elements
// ====================
// ====================
@import
'elements/typography'
;
@import
'elements/typography'
;
@import
'elements/pagination'
;
// pagination
@import
'elements/icons'
;
// references to icons used
@import
'elements/icons'
;
// references to icons used
@import
'elements/controls'
;
// buttons, link styles, sliders, etc.
@import
'elements/controls'
;
// buttons, link styles, sliders, etc.
@import
'elements/xblocks'
;
// studio rendering chrome for xblocks
@import
'elements/xblocks'
;
// studio rendering chrome for xblocks
...
...
cms/static/sass/style-app-extend1.scss
View file @
ff1a08cb
...
@@ -40,6 +40,7 @@
...
@@ -40,6 +40,7 @@
// +Base - Elements
// +Base - Elements
// ====================
// ====================
@import
'elements/typography'
;
@import
'elements/typography'
;
@import
'elements/pagination'
;
// pagination
@import
'elements/icons'
;
// references to icons used
@import
'elements/icons'
;
// references to icons used
@import
'elements/controls'
;
// buttons, link styles, sliders, etc.
@import
'elements/controls'
;
// buttons, link styles, sliders, etc.
@import
'elements/xblocks'
;
// studio rendering chrome for xblocks
@import
'elements/xblocks'
;
// studio rendering chrome for xblocks
...
...
cms/templates/container.html
View file @
ff1a08cb
...
@@ -31,7 +31,10 @@ from django.utils.translation import ugettext as _
...
@@ -31,7 +31,10 @@ from django.utils.translation import ugettext as _
require(["js/factories/container"], function(ContainerFactory) {
require(["js/factories/container"], function(ContainerFactory) {
ContainerFactory(
ContainerFactory(
${component_templates | n}, ${json.dumps(xblock_info) | n},
${component_templates | n}, ${json.dumps(xblock_info) | n},
"${action}", ${json.dumps(is_unit_page)}
"${action}",
{
isUnitPage: ${json.dumps(is_unit_page)}
}
);
);
});
});
</
%
block>
</
%
block>
...
...
cms/templates/js/mock/mock-container-paged-after-add-xblock.underscore
0 → 100644
View file @
ff1a08cb
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-details">
<span class="xblock-display-name">Test Container</span>
</div>
<div class="header-actions">
<ul class="actions-list">
</ul>
</div>
</div>
</header>
<article class="xblock-render">
<div class="xblock" data-locator="locator-container" data-request-token="page-render-token"
data-init="MockXBlock" data-runtime-class="StudioRuntime" data-runtime-version="1">
<script type="text/template" id="paging-header-tpl">
<div class="meta-wrap">
<div class="meta">
<%= messageHtml %>
</div>
<nav class="pagination pagination-compact top">
<ol>
<li class="nav-item previous"><a class="nav-link previous-page-link" href="#"><i class="icon-angle-left"></i> <span class="nav-label"><%= gettext("Previous") %></span></a></li>
<li class="nav-item next"><a class="nav-link next-page-link" href="#"><span class="nav-label"><%= gettext("Next") %></span> <i class="icon-angle-right"></i></a></li>
</ol>
</nav>
</div>
</script>
<script type="text/template" id="paging-footer-tpl">
<nav class="pagination pagination-full bottom">
<ol>
<li class="nav-item previous"><a class="nav-link previous-page-link" href="#"><i class="icon-angle-left"></i> <span class="nav-label"><%= gettext("Previous") %></span></a></li>
<li class="nav-item page">
<div class="pagination-form">
<label class="page-number-label" for="page-number"><%= gettext("Page number") %></label>
<input id="page-number-input" class="page-number-input" name="page-number" type="text" size="4" />
</div>
<span class="current-page"><%= current_page + 1 %></span>
<span class="page-divider">/</span>
<span class="total-pages"><%= total_pages %></span>
</li>
<li class="nav-item next"><a class="nav-link next-page-link" href="#"><span class="nav-label"><%= gettext("Next") %></span> <i class="icon-angle-right"></i></a></li>
</ol>
</nav>
</script>
<div class="container-paging-header"></div>
<div class="studio-xblock-wrapper" data-locator="locator-group-A">
<section class="wrapper-xblock level-nesting">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-details">
<a href="#" data-tooltip="Expand or Collapse" class="action expand-collapse expand">
<i class="icon-caret-down ui-toggle-expansion"></i>
<span class="sr">Expand or Collapse</span>
</a>
<span class="xblock-display-name">Group A</span>
</div>
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render">
<div class="xblock" data-request-token="page-render-token">
<div class="studio-xblock-wrapper" data-locator="locator-component-A1">
<section class="wrapper-xblock level-element">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
<li class="action-item action-delete">
<a href="#" class="delete-button action-button"></a>
</li>
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render"></article>
</section>
</div>
<div class="studio-xblock-wrapper" data-locator="locator-component-A2">
<section class="wrapper-xblock level-element">
<header class="xblock-header">
<div class="header-actions">
<div class="xblock-header-primary">
<ul class="actions-list">
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
<li class="action-item action-delete">
<a href="#" class="delete-button action-button"></a>
</li>
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render"></article>
</section>
</div>
<div class="studio-xblock-wrapper" data-locator="locator-component-A3">
<section class="wrapper-xblock level-element">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
<li class="action-item action-delete">
<a href="#" class="delete-button action-button"></a>
</li>
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render"></article>
</section>
</div>
<div class="studio-xblock-wrapper" data-locator="locator-component-A4">
<section class="wrapper-xblock level-element">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
<li class="action-item action-delete">
<a href="#" class="delete-button action-button"></a>
</li>
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render"></article>
</section>
</div>
<div class="add-xblock-component new-component-item adding"></div>
</div>
</article>
</section>
</div>
<div class="studio-xblock-wrapper" data-locator="locator-group-B">
<section class="wrapper-xblock level-nesting">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-details">
<a href="#" data-tooltip="Expand or Collapse" class="action expand-collapse expand">
<i class="icon-caret-down ui-toggle-expansion"></i>
<span class="sr">Expand or Collapse</span>
</a>
<span class="xblock-display-name">Group B</span>
</div>
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render">
<div class="xblock" data-request-token="page-render-token">
<div class="studio-xblock-wrapper" data-locator="locator-component-B1">
<section class="wrapper-xblock level-element">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
<li class="action-item action-delete">
<a href="#" class="delete-button action-button"></a>
</li>
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render"></article>
</section>
</div>
<div class="studio-xblock-wrapper" data-locator="locator-component-B2">
<section class="wrapper-xblock level-element">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
<li class="action-item action-delete">
<a href="#" class="delete-button action-button"></a>
</li>
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render"></article>
</section>
</div>
<div class="studio-xblock-wrapper" data-locator="locator-component-B3">
<section class="wrapper-xblock level-element">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
<li class="action-item action-delete">
<a href="#" class="delete-button action-button"></a>
</li>
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render"></article>
</section>
</div>
<div class="add-xblock-component new-component-item adding"></div>
</div>
</article>
</section>
<div class="container-paging-footer"></div>
</div>
</article>
cms/templates/js/mock/mock-container-paged-xblock.underscore
0 → 100644
View file @
ff1a08cb
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-details">
<span class="xblock-display-name">Test Container</span>
</div>
<div class="header-actions">
<ul class="actions-list">
</ul>
</div>
</div>
</header>
<article class="xblock-render">
<div class="xblock" data-locator="locator-container" data-request-token="page-render-token"
data-init="MockXBlock" data-runtime-class="StudioRuntime" data-runtime-version="1">
<script type="text/template" id="paging-header-tpl">
<div class="meta-wrap">
<div class="meta">
<%= messageHtml %>
</div>
<nav class="pagination pagination-compact top">
<ol>
<li class="nav-item previous"><a class="nav-link previous-page-link" href="#"><i class="icon-angle-left"></i> <span class="nav-label"><%= gettext("Previous") %></span></a></li>
<li class="nav-item next"><a class="nav-link next-page-link" href="#"><span class="nav-label"><%= gettext("Next") %></span> <i class="icon-angle-right"></i></a></li>
</ol>
</nav>
</div>
</script>
<script type="text/template" id="paging-footer-tpl">
<nav class="pagination pagination-full bottom">
<ol>
<li class="nav-item previous"><a class="nav-link previous-page-link" href="#"><i class="icon-angle-left"></i> <span class="nav-label"><%= gettext("Previous") %></span></a></li>
<li class="nav-item page">
<div class="pagination-form">
<label class="page-number-label" for="page-number"><%= gettext("Page number") %></label>
<input id="page-number-input" class="page-number-input" name="page-number" type="text" size="4" />
</div>
<span class="current-page"><%= current_page + 1 %></span>
<span class="page-divider">/</span>
<span class="total-pages"><%= total_pages %></span>
</li>
<li class="nav-item next"><a class="nav-link next-page-link" href="#"><span class="nav-label"><%= gettext("Next") %></span> <i class="icon-angle-right"></i></a></li>
</ol>
</nav>
</script>
<div class="container-paging-header"></div>
<div class="studio-xblock-wrapper" data-locator="locator-group-A">
<section class="wrapper-xblock level-nesting">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-details">
<a href="#" data-tooltip="Expand or Collapse" class="action expand-collapse expand">
<i class="icon-caret-down ui-toggle-expansion"></i>
<span class="sr">Expand or Collapse</span>
</a>
<span class="xblock-display-name">Group A</span>
</div>
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render">
<div class="xblock" data-request-token="page-render-token">
<div class="studio-xblock-wrapper" data-locator="locator-component-A1">
<section class="wrapper-xblock level-element">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
<li class="action-item action-delete">
<a href="#" class="delete-button action-button"></a>
</li>
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render"></article>
</section>
</div>
<div class="studio-xblock-wrapper" data-locator="locator-component-A2">
<section class="wrapper-xblock level-element">
<header class="xblock-header">
<div class="header-actions">
<div class="xblock-header-primary">
<ul class="actions-list">
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
<li class="action-item action-delete">
<a href="#" class="delete-button action-button"></a>
</li>
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render"></article>
</section>
</div>
<div class="studio-xblock-wrapper" data-locator="locator-component-A3">
<section class="wrapper-xblock level-element">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
<li class="action-item action-delete">
<a href="#" class="delete-button action-button"></a>
</li>
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render"></article>
</section>
</div>
<div class="add-xblock-component new-component-item adding"></div>
</div>
</article>
</section>
</div>
<div class="studio-xblock-wrapper" data-locator="locator-group-B">
<section class="wrapper-xblock level-nesting">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-details">
<a href="#" data-tooltip="Expand or Collapse" class="action expand-collapse expand">
<i class="icon-caret-down ui-toggle-expansion"></i>
<span class="sr">Expand or Collapse</span>
</a>
<span class="xblock-display-name">Group B</span>
</div>
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render">
<div class="xblock" data-request-token="page-render-token">
<div class="studio-xblock-wrapper" data-locator="locator-component-B1">
<section class="wrapper-xblock level-element">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
<li class="action-item action-delete">
<a href="#" class="delete-button action-button"></a>
</li>
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render"></article>
</section>
</div>
<div class="studio-xblock-wrapper" data-locator="locator-component-B2">
<section class="wrapper-xblock level-element">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
<li class="action-item action-delete">
<a href="#" class="delete-button action-button"></a>
</li>
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render"></article>
</section>
</div>
<div class="studio-xblock-wrapper" data-locator="locator-component-B3">
<section class="wrapper-xblock level-element">
<header class="xblock-header">
<div class="xblock-header-primary">
<div class="header-actions">
<ul class="actions-list">
<li class="action-item action-edit">
<a href="#" class="edit-button action-button"></a>
</li>
<li class="action-item action-duplicate">
<a href="#" class="duplicate-button action-button"></a>
</li>
<li class="action-item action-delete">
<a href="#" class="delete-button action-button"></a>
</li>
<li class="action-item action-drag">
<span data-tooltip="Drag to reorder" class="drag-handle action"></span>
</li>
</ul>
</div>
</div>
</header>
<article class="xblock-render"></article>
</section>
</div>
<div class="add-xblock-component new-component-item adding"></div>
</div>
</article>
</section>
<div class="container-paging-footer"></div>
</div>
</article>
cms/templates/library.html
View file @
ff1a08cb
...
@@ -22,8 +22,12 @@ from django.utils.translation import ugettext as _
...
@@ -22,8 +22,12 @@ from django.utils.translation import ugettext as _
<
%
block
name=
"requirejs"
>
<
%
block
name=
"requirejs"
>
require(["js/factories/library"], function(LibraryFactory) {
require(["js/factories/library"], function(LibraryFactory) {
LibraryFactory(
LibraryFactory(
${component_templates | n},
${component_templates | n}, ${json.dumps(xblock_info) | n},
${json.dumps(xblock_info) | n}
{
isUnitPage: false,
enable_paging: true,
page_size: 10
}
);
);
});
});
</
%
block>
</
%
block>
...
...
common/lib/xmodule/xmodule/library_root_xblock.py
View file @
ff1a08cb
...
@@ -3,10 +3,10 @@
...
@@ -3,10 +3,10 @@
"""
"""
import
logging
import
logging
from
.studio_editable
import
StudioEditableModule
from
xblock.core
import
XBlock
from
xblock.core
import
XBlock
from
xblock.fields
import
Scope
,
String
,
List
from
xblock.fields
import
Scope
,
String
,
List
from
xblock.fragment
import
Fragment
from
xblock.fragment
import
Fragment
from
xmodule.studio_editable
import
StudioEditableModule
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
...
@@ -42,29 +42,55 @@ class LibraryRoot(XBlock):
...
@@ -42,29 +42,55 @@ class LibraryRoot(XBlock):
def
author_view
(
self
,
context
):
def
author_view
(
self
,
context
):
"""
"""
Renders the Studio preview view
, which supports drag and drop
.
Renders the Studio preview view.
"""
"""
fragment
=
Fragment
()
fragment
=
Fragment
()
self
.
render_children
(
context
,
fragment
,
can_reorder
=
False
,
can_add
=
True
)
return
fragment
def
render_children
(
self
,
context
,
fragment
,
can_reorder
=
False
,
can_add
=
False
):
# pylint: disable=unused-argument
"""
Renders the children of the module with HTML appropriate for Studio. If can_reorder is True,
then the children will be rendered to support drag and drop.
"""
contents
=
[]
contents
=
[]
for
child_key
in
self
.
children
:
# pylint: disable=E1101
paging
=
context
.
get
(
'paging'
,
None
)
context
[
'reorderable_items'
]
.
add
(
child_key
)
children_count
=
len
(
self
.
children
)
# pylint: disable=no-member
item_start
,
item_end
=
0
,
children_count
# TODO sort children
if
paging
:
page_number
=
paging
.
get
(
'page_number'
,
0
)
raw_page_size
=
paging
.
get
(
'page_size'
,
None
)
page_size
=
raw_page_size
if
raw_page_size
is
not
None
else
children_count
item_start
,
item_end
=
page_size
*
page_number
,
page_size
*
(
page_number
+
1
)
children_to_show
=
self
.
children
[
item_start
:
item_end
]
# pylint: disable=no-member
for
child_key
in
children_to_show
:
# pylint: disable=E1101
child
=
self
.
runtime
.
get_block
(
child_key
)
child
=
self
.
runtime
.
get_block
(
child_key
)
rendered_child
=
self
.
runtime
.
render_child
(
child
,
StudioEditableModule
.
get_preview_view_name
(
child
),
context
)
child_view_name
=
StudioEditableModule
.
get_preview_view_name
(
child
)
rendered_child
=
self
.
runtime
.
render_child
(
child
,
child_view_name
,
context
)
fragment
.
add_frag_resources
(
rendered_child
)
fragment
.
add_frag_resources
(
rendered_child
)
contents
.
append
({
contents
.
append
({
'id'
:
unicode
(
child_key
),
'id'
:
child
.
location
.
to_deprecated_string
(
),
'content'
:
rendered_child
.
content
,
'content'
:
rendered_child
.
content
})
})
fragment
.
add_content
(
self
.
runtime
.
render_template
(
"studio_render_children_view.html"
,
{
fragment
.
add_content
(
self
.
runtime
.
render_template
(
"studio_render_paged_children_view.html"
,
{
'items'
:
contents
,
'items'
:
contents
,
'xblock_context'
:
context
,
'xblock_context'
:
context
,
'can_add'
:
True
,
'can_add'
:
can_add
,
'can_reorder'
:
True
,
'can_reorder'
:
False
,
}))
'first_displayed'
:
item_start
,
return
fragment
'total_children'
:
children_count
,
'displayed_children'
:
len
(
children_to_show
)
})
)
@property
@property
def
display_org_with_default
(
self
):
def
display_org_with_default
(
self
):
...
...
common/lib/xmodule/xmodule/video_module/video_handlers.py
View file @
ff1a08cb
...
@@ -155,7 +155,6 @@ class VideoStudentViewHandlers(object):
...
@@ -155,7 +155,6 @@ class VideoStudentViewHandlers(object):
if
transcript_name
:
if
transcript_name
:
# Get the asset path for course
# Get the asset path for course
asset_path
=
None
course
=
self
.
descriptor
.
runtime
.
modulestore
.
get_course
(
self
.
course_id
)
course
=
self
.
descriptor
.
runtime
.
modulestore
.
get_course
(
self
.
course_id
)
if
course
.
static_asset_path
:
if
course
.
static_asset_path
:
asset_path
=
course
.
static_asset_path
asset_path
=
course
.
static_asset_path
...
...
lms/templates/studio_render_paged_children_view.html
0 → 100644
View file @
ff1a08cb
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
%
>
<
%
namespace
name=
'static'
file=
'static_content.html'
/>
% for template_name in ["paging-header", "paging-footer"]:
<script
type=
"text/template"
id=
"${template_name}-tpl"
>
<%
static
:
include
path
=
"js/${template_name}.underscore"
/>
</script>
% endfor
<div
class=
"xblock-container-paging-parameters"
data-start=
"${first_displayed}"
data-displayed=
"${displayed_children}"
data-total=
"${total_children}"
></div>
<div
class=
"container-paging-header"
></div>
% for item in items:
${item['content']}
% endfor
% if can_add:
<div
class=
"add-xblock-component new-component-item adding"
></div>
% endif
<div
class=
"container-paging-footer"
></div>
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