Commit ff1a08cb by E. Kolpakov

Paging for LibraryView added with JS tests.

parent 05817614
...@@ -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)
......
...@@ -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",
......
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();
}); });
}; };
......
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();
}); });
}; };
......
...@@ -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');
......
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();
...@@ -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);
} }
}, },
......
...@@ -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);
} }
......
// 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
...@@ -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 {
......
...@@ -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
......
...@@ -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
......
...@@ -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
......
...@@ -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>
......
...@@ -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>
......
...@@ -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(
'items': contents, self.runtime.render_template("studio_render_paged_children_view.html", {
'xblock_context': context, 'items': contents,
'can_add': True, 'xblock_context': context,
'can_reorder': True, 'can_add': can_add,
})) 'can_reorder': False,
return fragment 'first_displayed': item_start,
'total_children': children_count,
'displayed_children': len(children_to_show)
})
)
@property @property
def display_org_with_default(self): def display_org_with_default(self):
......
...@@ -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
......
<%! 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>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment