upgrade Pagingcollection to edx-ui-toolkit's PagingCollection
This commit is contained in:
@@ -56,7 +56,7 @@
|
||||
"backbone": "common/js/vendor/backbone",
|
||||
"backbone-relational" : "js/vendor/backbone-relational.min",
|
||||
"backbone.associations": "js/vendor/backbone-associations-min",
|
||||
"backbone.paginator": "js/vendor/backbone.paginator.min",
|
||||
"backbone.paginator": "common/js/vendor/backbone.paginator",
|
||||
"tinymce": "js/vendor/tinymce/js/tinymce/tinymce.full.min",
|
||||
"jquery.tinymce": "js/vendor/tinymce/js/tinymce/jquery.tinymce.min",
|
||||
"xmodule": "/xmodule/xmodule",
|
||||
@@ -188,7 +188,7 @@
|
||||
},
|
||||
"backbone.paginator": {
|
||||
deps: ["backbone"],
|
||||
exports: "Backbone.Paginator"
|
||||
exports: "Backbone.PageableCollection"
|
||||
},
|
||||
"youtube": {
|
||||
exports: "YT"
|
||||
|
||||
@@ -32,7 +32,7 @@ requirejs.config({
|
||||
"underscore.string": "common/js/vendor/underscore.string",
|
||||
"backbone": "common/js/vendor/backbone",
|
||||
"backbone.associations": "xmodule_js/common_static/js/vendor/backbone-associations-min",
|
||||
"backbone.paginator": "xmodule_js/common_static/js/vendor/backbone.paginator.min",
|
||||
"backbone.paginator": "common/js/vendor/backbone.paginator",
|
||||
"backbone-relational": "xmodule_js/common_static/js/vendor/backbone-relational.min",
|
||||
"tinymce": "xmodule_js/common_static/js/vendor/tinymce/js/tinymce/tinymce.full.min",
|
||||
"jquery.tinymce": "xmodule_js/common_static/js/vendor/tinymce/js/tinymce/jquery.tinymce",
|
||||
@@ -141,7 +141,7 @@ requirejs.config({
|
||||
},
|
||||
"backbone.paginator": {
|
||||
deps: ["backbone"],
|
||||
exports: "Backbone.Paginator"
|
||||
exports: "Backbone.PageableCollection"
|
||||
},
|
||||
"backbone-relational": {
|
||||
deps: ["backbone"],
|
||||
|
||||
@@ -29,7 +29,7 @@ requirejs.config({
|
||||
"underscore.string": "common/js/vendor/underscore.string",
|
||||
"backbone": "common/js/vendor/backbone",
|
||||
"backbone.associations": "xmodule_js/common_static/js/vendor/backbone-associations-min",
|
||||
"backbone.paginator": "xmodule_js/common_static/js/vendor/backbone.paginator.min",
|
||||
"backbone.paginator": "common/js/vendor/backbone.paginator",
|
||||
"tinymce": "xmodule_js/common_static/js/vendor/tinymce/js/tinymce/tinymce.full.min",
|
||||
"jquery.tinymce": "xmodule_js/common_static/js/vendor/tinymce/js/tinymce/jquery.tinymce",
|
||||
"xmodule": "xmodule_js/src/xmodule",
|
||||
@@ -124,7 +124,7 @@ requirejs.config({
|
||||
},
|
||||
"backbone.paginator": {
|
||||
deps: ["backbone"],
|
||||
exports: "Backbone.Paginator"
|
||||
exports: "Backbone.PageableCollection"
|
||||
},
|
||||
"youtube": {
|
||||
exports: "YT"
|
||||
|
||||
@@ -230,7 +230,7 @@ define ["jquery", "common/js/spec_helpers/ajax_helpers", "squire"],
|
||||
describe "Basic", ->
|
||||
# Separate setup method to work-around mis-parenting of beforeEach methods
|
||||
setup = (requests) ->
|
||||
@view.pagingView.setPage(0)
|
||||
@view.pagingView.setPage(1)
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
|
||||
$.fn.fileupload = ->
|
||||
@@ -274,7 +274,7 @@ define ["jquery", "common/js/spec_helpers/ajax_helpers", "squire"],
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
appendSetFixtures('<div class="ui-loading"/>')
|
||||
expect($('.ui-loading').is(':visible')).toBe(true)
|
||||
@view.pagingView.setPage(0)
|
||||
@view.pagingView.setPage(1)
|
||||
AjaxHelpers.respondWithError(requests)
|
||||
expect($('.ui-loading').is(':visible')).toBe(false)
|
||||
|
||||
@@ -323,7 +323,7 @@ define ["jquery", "common/js/spec_helpers/ajax_helpers", "squire"],
|
||||
describe "Sorting", ->
|
||||
# Separate setup method to work-around mis-parenting of beforeEach methods
|
||||
setup = (requests) ->
|
||||
@view.pagingView.setPage(0)
|
||||
@view.pagingView.setPage(1)
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
|
||||
it "should have the correct default sort order", ->
|
||||
|
||||
@@ -1,77 +1,50 @@
|
||||
define(["backbone.paginator", "js/models/asset"], function(BackbonePaginator, AssetModel) {
|
||||
var AssetCollection = BackbonePaginator.requestPager.extend({
|
||||
define([
|
||||
"underscore",
|
||||
"edx-ui-toolkit/js/pagination/paging-collection",
|
||||
"js/models/asset"
|
||||
], function(_, PagingCollection, AssetModel) {
|
||||
'use strict';
|
||||
|
||||
var AssetCollection = PagingCollection.extend({
|
||||
assetType: '',
|
||||
model : AssetModel,
|
||||
paginator_core: {
|
||||
type: 'GET',
|
||||
accepts: 'application/json',
|
||||
dataType: 'json',
|
||||
url: function() { return this.url; }
|
||||
},
|
||||
paginator_ui: {
|
||||
|
||||
state: {
|
||||
firstPage: 0,
|
||||
currentPage: 0,
|
||||
perPage: 50
|
||||
},
|
||||
server_api: {
|
||||
'page': function() { return this.currentPage; },
|
||||
'page_size': function() { return this.perPage; },
|
||||
'sort': function() { return this.sortField; },
|
||||
'direction': function() { return this.sortDirection; },
|
||||
'asset_type': function() { return this.assetType; },
|
||||
'format': 'json'
|
||||
pageSize: 50,
|
||||
sortKey: 'sort',
|
||||
order: null,
|
||||
currentPage: null,
|
||||
totalRecords: null,
|
||||
totalCount: null
|
||||
},
|
||||
|
||||
parse: function(response) {
|
||||
var totalCount = response.totalCount,
|
||||
start = response.start,
|
||||
currentPage = response.page,
|
||||
pageSize = response.pageSize,
|
||||
totalPages = Math.ceil(totalCount / pageSize);
|
||||
this.totalCount = totalCount;
|
||||
this.totalPages = Math.max(totalPages, 1); // Treat an empty collection as having 1 page...
|
||||
this.currentPage = currentPage;
|
||||
this.start = start;
|
||||
return response.assets;
|
||||
queryParams: {
|
||||
currentPage: 'page',
|
||||
pageSize: 'page_size',
|
||||
sortKey: 'sort',
|
||||
order: 'direction',
|
||||
directions: {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
},
|
||||
asset_type: function() { return this.assetType; }
|
||||
},
|
||||
|
||||
setPage: function (page) {
|
||||
var oldPage = this.currentPage,
|
||||
self = this;
|
||||
this.goTo(page - 1, {
|
||||
reset: true,
|
||||
success: function () {
|
||||
self.trigger('page_changed');
|
||||
},
|
||||
error: function () {
|
||||
self.currentPage = oldPage;
|
||||
}
|
||||
});
|
||||
parse: function(response, options) {
|
||||
response.results = response.assets;
|
||||
delete response.assets;
|
||||
return PagingCollection.prototype.parse.call(this, response, options);
|
||||
},
|
||||
|
||||
nextPage: function () {
|
||||
if (this.currentPage < this.totalPages - 1) {
|
||||
this.setPage(this.getPage() + 1);
|
||||
}
|
||||
},
|
||||
|
||||
previousPage: function () {
|
||||
if (this.currentPage > 0) {
|
||||
this.setPage(this.getPage() - 1);
|
||||
}
|
||||
},
|
||||
|
||||
getPage: function () {
|
||||
return this.currentPage + 1;
|
||||
},
|
||||
|
||||
hasPreviousPage: function () {
|
||||
return this.currentPage > 0;
|
||||
},
|
||||
|
||||
hasNextPage: function () {
|
||||
return this.currentPage < this.totalPages - 1;
|
||||
/* jshint unused:false */
|
||||
parseState: function (response, queryParams, state, options) {
|
||||
return {
|
||||
totalRecords: response[0].totalCount,
|
||||
totalPages: Math.ceil(response[0].totalCount / response[0].pageSize)
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return AssetCollection;
|
||||
});
|
||||
|
||||
@@ -18,7 +18,13 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset
|
||||
|
||||
spyOn($.fn, "fileupload").and.returnValue("");
|
||||
|
||||
var collection = new AssetCollection();
|
||||
var TestAssetsCollection = AssetCollection.extend({
|
||||
state: {
|
||||
firstPage: 0,
|
||||
pageSize: 2
|
||||
}
|
||||
});
|
||||
var collection = new TestAssetsCollection();
|
||||
collection.url = "assets-url";
|
||||
assetsView = new AssetsView({
|
||||
collection: collection,
|
||||
@@ -43,7 +49,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset
|
||||
start: 0,
|
||||
end: 0,
|
||||
page: 0,
|
||||
pageSize: 5,
|
||||
pageSize: 2,
|
||||
totalCount: 0
|
||||
};
|
||||
|
||||
@@ -134,11 +140,10 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset
|
||||
var setup;
|
||||
setup = function(responseData) {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
assetsView.pagingView.setPage(0);
|
||||
assetsView.pagingView.setPage(1);
|
||||
if (!responseData){
|
||||
AjaxHelpers.respondWithJson(requests, mockEmptyAssetsResponse);
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
AjaxHelpers.respondWithJson(requests, responseData);
|
||||
}
|
||||
return requests;
|
||||
@@ -184,7 +189,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset
|
||||
spyOn(assetsView, "addAsset").and.callFake(function () {
|
||||
assetsView.collection.add(mockAssetUploadResponse.asset);
|
||||
assetsView.pagingView.renderPageItems();
|
||||
assetsView.pagingView.setPage(0);
|
||||
assetsView.pagingView.setPage(1);
|
||||
});
|
||||
|
||||
$('a:contains("Upload your first asset")').click();
|
||||
@@ -269,7 +274,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
$.each(assetsView.pagingView.filterableColumns, function(columnID, columnData){
|
||||
var $typeColumn = $('#' + columnID);
|
||||
assetsView.pagingView.setPage(0);
|
||||
assetsView.pagingView.setPage(1);
|
||||
respondWithMockAssets(requests);
|
||||
var assetsNumber = assetsView.collection.length;
|
||||
assetsView._toggleFilterColumn('Images', 'Images');
|
||||
@@ -302,7 +307,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset
|
||||
assetsView.pagingView.registerSortableColumn('name-col', 'Name Column', 'nameField', 'asc');
|
||||
assetsView.pagingView.registerFilterableColumn('js-asset-type-col', gettext('Type'), 'asset_type');
|
||||
assetsView.pagingView.setInitialSortColumn('name-col');
|
||||
assetsView.pagingView.setPage(0);
|
||||
assetsView.pagingView.setPage(1);
|
||||
respondWithMockAssets(requests);
|
||||
var sortInfo = assetsView.pagingView.sortableColumnInfo('name-col');
|
||||
expect(sortInfo.defaultSortDirection).toBe('asc');
|
||||
@@ -318,7 +323,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset
|
||||
expect(assetsView).toBeDefined();
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
$.each(assetsView.pagingView.filterableColumns, function(columnID, columnData) {
|
||||
assetsView.pagingView.setPage(0);
|
||||
assetsView.pagingView.setPage(1);
|
||||
respondWithMockAssets(requests);
|
||||
var $typeColumn = $('#' + columnID);
|
||||
expect($typeColumn).toBeVisible();
|
||||
@@ -410,7 +415,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset
|
||||
|
||||
it('can move forward a page using the next page button', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
assetsView.pagingView.setPage(0);
|
||||
assetsView.pagingView.setPage(1);
|
||||
AjaxHelpers.respondWithJson(requests, firstPageAssets);
|
||||
expect(assetsView.pagingView.pagingFooter).toBeDefined();
|
||||
expect(assetsView.pagingView.pagingFooter.$('button.next-page-link'))
|
||||
@@ -423,7 +428,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset
|
||||
|
||||
it('can move back a page using the previous page button', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
assetsView.pagingView.setPage(1);
|
||||
assetsView.pagingView.setPage(2);
|
||||
AjaxHelpers.respondWithJson(requests, secondPageAssets);
|
||||
expect(assetsView.pagingView.pagingFooter).toBeDefined();
|
||||
expect(assetsView.pagingView.pagingFooter.$('button.previous-page-link'))
|
||||
@@ -436,12 +441,12 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset
|
||||
|
||||
it('can set the current page using the page number input', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
assetsView.pagingView.setPage(0);
|
||||
assetsView.pagingView.setPage(1);
|
||||
AjaxHelpers.respondWithJson(requests, firstPageAssets);
|
||||
assetsView.pagingView.pagingFooter.$('#page-number-input').val('2');
|
||||
assetsView.pagingView.pagingFooter.$('#page-number-input').trigger('change');
|
||||
AjaxHelpers.respondWithJson(requests, secondPageAssets);
|
||||
expect(assetsView.collection.currentPage).toBe(1);
|
||||
expect(assetsView.collection.getPageNumber()).toBe(2);
|
||||
expect(assetsView.pagingView.pagingFooter.$('button.previous-page-link'))
|
||||
.not.toHaveClass('is-disabled');
|
||||
});
|
||||
|
||||
@@ -81,7 +81,7 @@ define(["jquery", "underscore", "common/js/spec_helpers/ajax_helpers", "URI", "j
|
||||
});
|
||||
|
||||
describe("Container", function () {
|
||||
describe("rendering", function(){
|
||||
describe("rendering", function() {
|
||||
|
||||
it('should set show_previews', function() {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
define([
|
||||
"jquery",
|
||||
"common/js/spec_helpers/ajax_helpers",
|
||||
"URI",
|
||||
"common/js/spec_helpers/ajax_helpers",
|
||||
"edx-ui-toolkit/js/pagination/paging-collection",
|
||||
"js/views/paging",
|
||||
"js/views/paging_header",
|
||||
"common/js/components/collections/paging_collection"
|
||||
], function ($, AjaxHelpers, URI, PagingView, PagingHeader, PagingCollection) {
|
||||
"js/views/paging_header"
|
||||
], function ($, URI, AjaxHelpers, PagingCollection, PagingView, PagingHeader) {
|
||||
|
||||
var createPageableItem = function(index) {
|
||||
var id = 'item_' + index;
|
||||
@@ -24,7 +24,6 @@ define([
|
||||
],
|
||||
num_pages: 2,
|
||||
page_size: 3,
|
||||
current_page: 0,
|
||||
count: 4,
|
||||
page: 0,
|
||||
start: 0
|
||||
@@ -35,16 +34,14 @@ define([
|
||||
],
|
||||
num_pages: 2,
|
||||
page_size: 3,
|
||||
current_page: 1,
|
||||
count: 4,
|
||||
page: 1,
|
||||
count: 4,
|
||||
start: 3
|
||||
};
|
||||
var mockEmptyPage = {
|
||||
results: [],
|
||||
num_pages: 1,
|
||||
page_size: 3,
|
||||
current_page: 0,
|
||||
count: 0,
|
||||
page: 0,
|
||||
start: 0
|
||||
@@ -69,11 +66,18 @@ define([
|
||||
});
|
||||
|
||||
describe("Paging", function() {
|
||||
var pagingView;
|
||||
var pagingView,
|
||||
TestPagingCollection = PagingCollection.extend({
|
||||
state: {
|
||||
firstPage: 0,
|
||||
currentPage: null,
|
||||
pageSize: 3
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
var collection = new PagingCollection();
|
||||
collection.isZeroIndexed = true;
|
||||
var collection = new TestPagingCollection();
|
||||
collection.url = '/dummy/';
|
||||
pagingView = new MockPagingView({collection: collection});
|
||||
});
|
||||
|
||||
@@ -83,10 +87,10 @@ define([
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
pagingView.setPage(1);
|
||||
respondWithMockItems(requests);
|
||||
expect(pagingView.collection.currentPage).toBe(0);
|
||||
expect(pagingView.collection.getPageNumber()).toBe(1);
|
||||
pagingView.setPage(2);
|
||||
respondWithMockItems(requests);
|
||||
expect(pagingView.collection.currentPage).toBe(1);
|
||||
expect(pagingView.collection.getPageNumber()).toBe(2);
|
||||
});
|
||||
|
||||
it('should not change page after a server error', function () {
|
||||
@@ -95,7 +99,9 @@ define([
|
||||
respondWithMockItems(requests);
|
||||
pagingView.setPage(2);
|
||||
requests[1].respond(500);
|
||||
expect(pagingView.collection.currentPage).toBe(0);
|
||||
|
||||
/* PagingCollection sets the currentPage to the old page in case of failure */
|
||||
expect(pagingView.collection.getPageNumber()).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -106,7 +112,7 @@ define([
|
||||
respondWithMockItems(requests);
|
||||
pagingView.nextPage();
|
||||
requests[1].respond(500);
|
||||
expect(pagingView.collection.currentPage).toBe(0);
|
||||
expect(pagingView.collection.getPageNumber()).toBe(1);
|
||||
});
|
||||
|
||||
it('can move to the next page', function () {
|
||||
@@ -115,7 +121,9 @@ define([
|
||||
respondWithMockItems(requests);
|
||||
pagingView.nextPage();
|
||||
respondWithMockItems(requests);
|
||||
expect(pagingView.collection.currentPage).toBe(1);
|
||||
|
||||
/* PagingCollection now returns the normalized page number; adds one if zero indexed */
|
||||
expect(pagingView.collection.getPageNumber()).toBe(2);
|
||||
});
|
||||
|
||||
it('can not move forward from the final page', function () {
|
||||
@@ -128,14 +136,13 @@ define([
|
||||
});
|
||||
|
||||
describe("previousPage", function () {
|
||||
|
||||
it('can move back a page', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
pagingView.setPage(2);
|
||||
respondWithMockItems(requests);
|
||||
pagingView.previousPage();
|
||||
respondWithMockItems(requests);
|
||||
expect(pagingView.collection.currentPage).toBe(0);
|
||||
expect(pagingView.collection.getPageNumber()).toBe(1);
|
||||
});
|
||||
|
||||
it('can not move back from the first page', function () {
|
||||
@@ -152,12 +159,11 @@ define([
|
||||
respondWithMockItems(requests);
|
||||
pagingView.previousPage();
|
||||
requests[1].respond(500);
|
||||
expect(pagingView.collection.currentPage).toBe(1);
|
||||
expect(pagingView.collection.getPageNumber()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("toggleSortOrder", function () {
|
||||
|
||||
it('can toggle direction of the current sort', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
expect(pagingView.collection.sortDirection).toBe('desc');
|
||||
@@ -220,7 +226,8 @@ define([
|
||||
respondWithMockItems(requests);
|
||||
pagingHeader.$('.next-page-link').click();
|
||||
requests[1].respond(500);
|
||||
expect(pagingView.collection.currentPage).toBe(0);
|
||||
expect(pagingView.collection.state.currentPage).toBe(0);
|
||||
expect(pagingView.collection.getPageNumber()).toBe(1);
|
||||
});
|
||||
|
||||
it('can move to the next page', function () {
|
||||
@@ -229,7 +236,7 @@ define([
|
||||
respondWithMockItems(requests);
|
||||
pagingHeader.$('.next-page-link').click();
|
||||
respondWithMockItems(requests);
|
||||
expect(pagingView.collection.currentPage).toBe(1);
|
||||
expect(pagingView.collection.getPageNumber()).toBe(2);
|
||||
});
|
||||
|
||||
it('should be enabled when there is at least one more page', function () {
|
||||
@@ -248,7 +255,7 @@ define([
|
||||
|
||||
it('should be disabled on an empty page', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
pagingView.setPage(0);
|
||||
pagingView.setPage(1);
|
||||
AjaxHelpers.respondWithJson(requests, mockEmptyPage);
|
||||
expect(pagingHeader.$('.next-page-link')).toHaveClass('is-disabled');
|
||||
});
|
||||
@@ -267,7 +274,7 @@ define([
|
||||
respondWithMockItems(requests);
|
||||
pagingHeader.$('.previous-page-link').click();
|
||||
requests[1].respond(500);
|
||||
expect(pagingView.collection.currentPage).toBe(1);
|
||||
expect(pagingView.collection.getPageNumber()).toBe(2);
|
||||
});
|
||||
|
||||
it('can go back a page', function () {
|
||||
@@ -276,7 +283,7 @@ define([
|
||||
respondWithMockItems(requests);
|
||||
pagingHeader.$('.previous-page-link').click();
|
||||
respondWithMockItems(requests);
|
||||
expect(pagingView.collection.currentPage).toBe(0);
|
||||
expect(pagingView.collection.getPageNumber()).toBe(1);
|
||||
});
|
||||
|
||||
it('should be disabled on the first page', function () {
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
define(["jquery", "underscore", "gettext", "js/views/baseview", "js/models/asset", "js/views/paging",
|
||||
"js/views/asset", "js/views/paging_header", "common/js/components/views/paging_footer",
|
||||
"js/utils/modal", "common/js/components/utils/view_utils", "common/js/components/views/feedback_notification",
|
||||
define([
|
||||
"jquery",
|
||||
"underscore",
|
||||
"gettext",
|
||||
"edx-ui-toolkit/js/utils/html-utils",
|
||||
"js/views/baseview",
|
||||
"js/models/asset",
|
||||
"js/views/paging",
|
||||
"js/views/asset",
|
||||
"js/views/paging_header",
|
||||
"common/js/components/views/paging_footer",
|
||||
"js/utils/modal",
|
||||
"common/js/components/utils/view_utils",
|
||||
"common/js/components/views/feedback_notification",
|
||||
"text!templates/asset-library.underscore",
|
||||
"jquery.fileupload-process", "jquery.fileupload-validate"],
|
||||
function($, _, gettext, BaseView, AssetModel, PagingView, AssetView, PagingHeader, PagingFooter,
|
||||
"jquery.fileupload-process",
|
||||
"jquery.fileupload-validate"
|
||||
],
|
||||
function($, _, gettext, HtmlUtils, BaseView, AssetModel, PagingView, AssetView, PagingHeader, PagingFooter,
|
||||
ModalUtils, ViewUtils, NotificationView, asset_library_template) {
|
||||
|
||||
var CONVERSION_FACTOR_MBS_TO_BYTES = 1000 * 1000;
|
||||
@@ -67,7 +80,10 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/models/asset
|
||||
ViewUtils.hideLoadingIndicator();
|
||||
|
||||
// Create the table
|
||||
this.$el.html(_.template(asset_library_template)({typeData: this.typeData}));
|
||||
HtmlUtils.setHtml(
|
||||
this.$el,
|
||||
HtmlUtils.template(asset_library_template)({typeData: this.typeData})
|
||||
);
|
||||
tableBody = this.$('#asset-table-body');
|
||||
this.tableBody = tableBody;
|
||||
this.pagingHeader = new PagingHeader({view: this, el: $('#asset-paging-header')});
|
||||
@@ -97,7 +113,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/models/asset
|
||||
pagingView.registerFilterableColumn('js-asset-type-col', gettext('Type'), 'asset_type');
|
||||
pagingView.setInitialSortColumn('js-asset-date-col');
|
||||
pagingView.setInitialFilterColumn('js-asset-type-col');
|
||||
pagingView.setPage(0);
|
||||
pagingView.setPage(1);
|
||||
return pagingView;
|
||||
},
|
||||
|
||||
@@ -106,7 +122,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/models/asset
|
||||
return this;
|
||||
},
|
||||
|
||||
afterRender: function(){
|
||||
afterRender: function() {
|
||||
// Bind events with html elements
|
||||
$('li a.upload-button').on('click', _.bind(this.showUploadModal, this));
|
||||
$('.upload-modal .close-button').on('click', _.bind(this.hideModal, this));
|
||||
@@ -127,7 +143,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/models/asset
|
||||
// so that the new asset is shown at the top of the page.
|
||||
this.pagingView.setInitialSortColumn('js-asset-date-col');
|
||||
this.pagingView.setInitialFilterColumn('js-asset-type-col');
|
||||
this.pagingView.setPage(0);
|
||||
this.pagingView.setPage(1);
|
||||
|
||||
analytics.track('Uploaded a File', {
|
||||
'course': course_location_analytics,
|
||||
@@ -217,9 +233,10 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/models/asset
|
||||
|
||||
startUpload: function (event) {
|
||||
var file = event.target.value;
|
||||
|
||||
if (!this.largeFileErrorMsg) {
|
||||
$('.upload-modal h1').text(gettext('Uploading'));
|
||||
$('.upload-modal .file-name').html(file.substring(file.lastIndexOf("\\") + 1));
|
||||
$('.upload-modal .file-name').text(file.substring(file.lastIndexOf('\\') + 1));
|
||||
$('.upload-modal .choose-file-button').hide();
|
||||
$('.upload-modal .progress-bar').removeClass('loaded').show();
|
||||
}
|
||||
@@ -228,13 +245,16 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/models/asset
|
||||
resetUploadModal: function () {
|
||||
// Reset modal so it no longer displays information about previously
|
||||
// completed uploads.
|
||||
var percentVal = '0%';
|
||||
$('.upload-modal .progress-fill').width(percentVal);
|
||||
$('.upload-modal .progress-fill').html(percentVal);
|
||||
var percentVal = '0%',
|
||||
$progressFill = $('.upload-modal .progress-fill'),
|
||||
$fileName = $('.upload-modal .file-name');
|
||||
|
||||
$progressFill.width(percentVal);
|
||||
$progressFill.text(percentVal);
|
||||
$('.upload-modal .progress-bar').hide();
|
||||
|
||||
$('.upload-modal .file-name').show();
|
||||
$('.upload-modal .file-name').html('');
|
||||
$fileName.show();
|
||||
$fileName.text('');
|
||||
$('.upload-modal .choose-file-button').text(gettext('Choose File'));
|
||||
$('.upload-modal .embeddable-xml-input').val('');
|
||||
$('.upload-modal .embeddable').hide();
|
||||
@@ -243,9 +263,11 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/models/asset
|
||||
},
|
||||
|
||||
showUploadFeedback: function (event, percentComplete) {
|
||||
var percentVal = percentComplete + '%';
|
||||
$('.upload-modal .progress-fill').width(percentVal);
|
||||
$('.upload-modal .progress-fill').html(percentVal);
|
||||
var percentVal = percentComplete + '%',
|
||||
$progressFill = $('.upload-modal .progress-fill');
|
||||
|
||||
$progressFill.width(percentVal);
|
||||
$progressFill.text(percentVal);
|
||||
},
|
||||
|
||||
openFilterColumn: function($this) {
|
||||
@@ -285,12 +307,12 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/models/asset
|
||||
var filterColumn = this.$el.find('.filterable-column');
|
||||
var resetFilter = filterColumn.find('.reset-filter');
|
||||
var title = filterColumn.find('.title');
|
||||
if(assettype === this.allLabel) {
|
||||
|
||||
if (assettype === this.allLabel) {
|
||||
collection.assetType = '';
|
||||
resetFilter.hide();
|
||||
title.removeClass('column-selected-link');
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
collection.assetType = assettype;
|
||||
resetFilter.show();
|
||||
title.addClass('column-selected-link');
|
||||
@@ -302,35 +324,38 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/models/asset
|
||||
'.column-filter-link[data-assetfilter="' + assettype + '"]'));
|
||||
},
|
||||
|
||||
closeFilterPopup: function(element){
|
||||
closeFilterPopup: function(element) {
|
||||
var $menu = element.parents('.nav-dd > .nav-item');
|
||||
this.toggleFilterColumnState($menu, element);
|
||||
},
|
||||
|
||||
displayFinishedUpload: function (resp) {
|
||||
var asset = resp.asset;
|
||||
var asset = resp.asset,
|
||||
$progressFill = $('.upload-modal .progress-fill');
|
||||
|
||||
$('.upload-modal h1').text(gettext('Upload New File'));
|
||||
$('.upload-modal .embeddable-xml-input').val(asset.portable_url).show();
|
||||
$('.upload-modal .embeddable').show();
|
||||
$('.upload-modal .file-name').hide();
|
||||
$('.upload-modal .progress-fill').html(resp.msg);
|
||||
$progressFill.text(resp.msg);
|
||||
$('.upload-modal .choose-file-button').text(gettext('Load Another File')).show();
|
||||
$('.upload-modal .progress-fill').width('100%');
|
||||
$progressFill.width('100%');
|
||||
|
||||
this.addAsset(new AssetModel(asset));
|
||||
},
|
||||
|
||||
displayFailedUpload: function (resp) {
|
||||
var $progressFill = $('.upload-modal .progress-fill');
|
||||
|
||||
$('.upload-modal h1').text(gettext('Upload New File'));
|
||||
$('.upload-modal .embeddable-xml-input').hide();
|
||||
$('.upload-modal .embeddable').hide();
|
||||
$('.upload-modal .file-name').hide();
|
||||
$('.upload-modal .progress-fill').html(resp.msg);
|
||||
$progressFill.text(resp.msg);
|
||||
$('.upload-modal .choose-file-button').text(gettext('Load Another File')).show();
|
||||
$('.upload-modal .progress-fill').width('0%');
|
||||
$progressFill.width('0%');
|
||||
}
|
||||
});
|
||||
|
||||
return AssetsView;
|
||||
}); // end define();
|
||||
});
|
||||
|
||||
@@ -2,7 +2,8 @@ define(["jquery", "underscore", "common/js/components/utils/view_utils", "js/vie
|
||||
"common/js/components/views/feedback_notification", "js/views/paging_header", "common/js/components/views/paging_footer"],
|
||||
function ($, _, ViewUtils, ContainerView, ModuleUtils, gettext, NotificationView, PagingHeader, PagingFooter) {
|
||||
var PagedContainerView = ContainerView.extend({
|
||||
initialize: function(options){
|
||||
|
||||
initialize: function(options) {
|
||||
var self = this;
|
||||
ContainerView.prototype.initialize.call(this);
|
||||
this.page_size = this.options.page_size;
|
||||
@@ -52,6 +53,22 @@ define(["jquery", "underscore", "common/js/components/utils/view_utils", "js/vie
|
||||
|
||||
hasNextPage: function () {
|
||||
return self.collection.currentPage < self.collection.totalPages - 1;
|
||||
},
|
||||
|
||||
getTotalPages: function () {
|
||||
return this.totalPages;
|
||||
},
|
||||
|
||||
getPageNumber: function () {
|
||||
return this.getPage();
|
||||
},
|
||||
|
||||
getTotalRecords: function () {
|
||||
return this.totalCount;
|
||||
},
|
||||
|
||||
getPageSize: function () {
|
||||
return self.page_size;
|
||||
}
|
||||
};
|
||||
},
|
||||
@@ -66,11 +83,12 @@ define(["jquery", "underscore", "common/js/components/utils/view_utils", "js/vie
|
||||
return this.renderPage(options);
|
||||
},
|
||||
|
||||
renderPage: function(options){
|
||||
renderPage: function(options) {
|
||||
var self = this,
|
||||
view = this.view,
|
||||
xblockInfo = this.model,
|
||||
xblockUrl = xblockInfo.url();
|
||||
|
||||
return $.ajax({
|
||||
url: decodeURIComponent(xblockUrl) + "/" + view,
|
||||
type: 'GET',
|
||||
@@ -101,8 +119,10 @@ define(["jquery", "underscore", "common/js/components/utils/view_utils", "js/vie
|
||||
};
|
||||
},
|
||||
|
||||
getPageCount: function(total_count){
|
||||
if (total_count===0) return 1;
|
||||
getPageCount: function(total_count) {
|
||||
if (total_count === 0) {
|
||||
return 1;
|
||||
}
|
||||
return Math.ceil(total_count / this.page_size);
|
||||
},
|
||||
|
||||
|
||||
@@ -116,12 +116,15 @@
|
||||
sortInfo = this.sortableColumnInfo(sortColumn),
|
||||
sortField = sortInfo.fieldName,
|
||||
defaultSortDirection = sortInfo.defaultSortDirection;
|
||||
|
||||
if (collection.sortField === sortField) {
|
||||
collection.sortDirection = collection.sortDirection === 'asc' ? 'desc' : 'asc';
|
||||
} else {
|
||||
collection.sortField = sortField;
|
||||
collection.sortDirection = defaultSortDirection;
|
||||
}
|
||||
|
||||
collection.setSorting(sortField, collection.sortDirection);
|
||||
this.sortColumn = sortColumn;
|
||||
this.collection.setPage(1);
|
||||
},
|
||||
@@ -129,8 +132,8 @@
|
||||
selectFilter: function(filterColumn) {
|
||||
var collection = this.collection,
|
||||
filterInfo = this.filterableColumnInfo(filterColumn),
|
||||
filterField = filterInfo.fieldName,
|
||||
defaultFilterKey = false;
|
||||
filterField = filterInfo.fieldName;
|
||||
|
||||
if (collection.filterField !== filterField) {
|
||||
collection.filterField = filterField;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
define(["underscore", "backbone", "gettext", "text!templates/paging-header.underscore"],
|
||||
function(_, Backbone, gettext, paging_header_template) {
|
||||
|
||||
define([
|
||||
'underscore',
|
||||
'backbone',
|
||||
'gettext',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'edx-ui-toolkit/js/utils/string-utils',
|
||||
'text!templates/paging-header.underscore'
|
||||
], function(_, Backbone, gettext, HtmlUtils, StringUtils, pagingHeaderTemplate) {
|
||||
'use strict';
|
||||
/* jshint maxlen:false */
|
||||
var PagingHeader = Backbone.View.extend({
|
||||
events : {
|
||||
"click .next-page-link": "nextPage",
|
||||
"click .previous-page-link": "previousPage"
|
||||
'click .next-page-link': 'nextPage',
|
||||
'click .previous-page-link': 'previousPage'
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
@@ -19,83 +26,99 @@ define(["underscore", "backbone", "gettext", "text!templates/paging-header.under
|
||||
render: function() {
|
||||
var view = this.view,
|
||||
collection = view.collection,
|
||||
currentPage = collection.currentPage,
|
||||
lastPage = collection.totalPages - 1,
|
||||
messageHtml = this.messageHtml();
|
||||
this.$el.html(_.template(paging_header_template)({ messageHtml: messageHtml}));
|
||||
this.$(".previous-page-link").toggleClass("is-disabled", currentPage === 0).attr('aria-disabled', currentPage === 0);
|
||||
this.$(".next-page-link").toggleClass("is-disabled", currentPage === lastPage).attr('aria-disabled', currentPage === lastPage);
|
||||
currentPage = collection.getPageNumber(),
|
||||
lastPage = collection.getTotalPages(),
|
||||
messageHtml = this.messageHtml(),
|
||||
isNextDisabled = lastPage === 0 || currentPage === lastPage;
|
||||
|
||||
HtmlUtils.setHtml(this.$el, HtmlUtils.template(pagingHeaderTemplate)({messageHtml: messageHtml}));
|
||||
this.$('.previous-page-link')
|
||||
.toggleClass('is-disabled', currentPage === 1)
|
||||
.attr('aria-disabled', currentPage === 1);
|
||||
this.$('.next-page-link')
|
||||
.toggleClass('is-disabled', isNextDisabled)
|
||||
.attr('aria-disabled', isNextDisabled);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
messageHtml: function() {
|
||||
var message = '';
|
||||
var asset_type = false;
|
||||
var message = '',
|
||||
assetType = false;
|
||||
|
||||
if (this.view.collection.assetType) {
|
||||
if (this.view.collection.sortDirection === 'asc') {
|
||||
// Translators: sample result:
|
||||
// "Showing 0-9 out of 25 total, filtered by Images, sorted by Date Added ascending"
|
||||
message = gettext('Showing %(current_item_range)s out of %(total_items_count)s, filtered by %(asset_type)s, sorted by %(sort_name)s ascending');
|
||||
message = gettext('Showing {currentItemRange} out of {totalItemsCount}, filtered by {assetType}, sorted by {sortName} ascending');
|
||||
} else {
|
||||
// Translators: sample result:
|
||||
// "Showing 0-9 out of 25 total, filtered by Images, sorted by Date Added descending"
|
||||
message = gettext('Showing %(current_item_range)s out of %(total_items_count)s, filtered by %(asset_type)s, sorted by %(sort_name)s descending');
|
||||
message = gettext('Showing {currentItemRange} out of {totalItemsCount}, filtered by {assetType}, sorted by {sortName} descending');
|
||||
}
|
||||
asset_type = this.filterNameLabel();
|
||||
}
|
||||
else {
|
||||
assetType = this.filterNameLabel();
|
||||
} else {
|
||||
if (this.view.collection.sortDirection === 'asc') {
|
||||
// Translators: sample result:
|
||||
// "Showing 0-9 out of 25 total, sorted by Date Added ascending"
|
||||
message = gettext('Showing %(current_item_range)s out of %(total_items_count)s, sorted by %(sort_name)s ascending');
|
||||
message = gettext('Showing {currentItemRange} out of {totalItemsCount}, sorted by {sortName} ascending');
|
||||
} else {
|
||||
// Translators: sample result:
|
||||
// "Showing 0-9 out of 25 total, sorted by Date Added descending"
|
||||
message = gettext('Showing %(current_item_range)s out of %(total_items_count)s, sorted by %(sort_name)s descending');
|
||||
message = gettext('Showing {currentItemRange} out of {totalItemsCount}, sorted by {sortName} descending');
|
||||
}
|
||||
}
|
||||
|
||||
return '<p>' + interpolate(message, {
|
||||
current_item_range: this.currentItemRangeLabel(),
|
||||
total_items_count: this.totalItemsCountLabel(),
|
||||
asset_type: asset_type,
|
||||
sort_name: this.sortNameLabel()
|
||||
}, true) + "</p>";
|
||||
return HtmlUtils.interpolateHtml(message, {
|
||||
currentItemRange: this.currentItemRangeLabel(),
|
||||
totalItemsCount: this.totalItemsCountLabel(),
|
||||
assetType: assetType,
|
||||
sortName: this.sortNameLabel()
|
||||
});
|
||||
},
|
||||
|
||||
currentItemRangeLabel: function() {
|
||||
var view = this.view,
|
||||
collection = view.collection,
|
||||
start = collection.start,
|
||||
start = (collection.getPageNumber() - 1) * collection.getPageSize(),
|
||||
count = collection.size(),
|
||||
end = start + count;
|
||||
return interpolate('<span class="count-current-shown">%(start)s-%(end)s</span>', {
|
||||
end = start + count,
|
||||
htmlMessage = HtmlUtils.HTML('<span class="count-current-shown">{start}-{end}</span>');
|
||||
|
||||
return HtmlUtils.interpolateHtml(htmlMessage, {
|
||||
start: Math.min(start + 1, end),
|
||||
end: end
|
||||
}, true);
|
||||
});
|
||||
},
|
||||
|
||||
totalItemsCountLabel: function() {
|
||||
var totalItemsLabel;
|
||||
var totalItemsLabel,
|
||||
htmlMessage = HtmlUtils.HTML('<span class="count-total">{totalItemsLabel}</span>');
|
||||
|
||||
// Translators: turns into "25 total" to be used in other sentences, e.g. "Showing 0-9 out of 25 total".
|
||||
totalItemsLabel = interpolate(gettext('%(total_items)s total'), {
|
||||
total_items: this.view.collection.totalCount
|
||||
}, true);
|
||||
return interpolate('<span class="count-total">%(total_items_label)s</span>', {
|
||||
total_items_label: totalItemsLabel
|
||||
}, true);
|
||||
totalItemsLabel = StringUtils.interpolate(gettext('{totalItems} total'), {
|
||||
totalItems: this.view.collection.getTotalRecords()
|
||||
});
|
||||
|
||||
return HtmlUtils.interpolateHtml(htmlMessage, {
|
||||
totalItemsLabel: totalItemsLabel
|
||||
});
|
||||
},
|
||||
|
||||
sortNameLabel: function() {
|
||||
return interpolate('<span class="sort-order">%(sort_name)s</span>', {
|
||||
sort_name: this.view.sortDisplayName()
|
||||
}, true);
|
||||
var htmlMessage = HtmlUtils.HTML('<span class="sort-order">{sortName}</span>');
|
||||
|
||||
return HtmlUtils.interpolateHtml(htmlMessage, {
|
||||
sortName: this.view.sortDisplayName()
|
||||
});
|
||||
},
|
||||
|
||||
filterNameLabel: function() {
|
||||
return interpolate('<span class="filter-column">%(filter_name)s</span>', {
|
||||
filter_name: this.view.filterDisplayName()
|
||||
}, true);
|
||||
var htmlMessage = HtmlUtils.HTML('<span class="filter-column">{filterName}</span>');
|
||||
|
||||
return HtmlUtils.interpolateHtml(htmlMessage, {
|
||||
filterName: this.view.filterDisplayName()
|
||||
});
|
||||
},
|
||||
|
||||
nextPage: function() {
|
||||
@@ -108,4 +131,4 @@ define(["underscore", "backbone", "gettext", "text!templates/paging-header.under
|
||||
});
|
||||
|
||||
return PagingHeader;
|
||||
}); // end define();
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="meta-wrap">
|
||||
<div class="meta">
|
||||
<%= messageHtml %>
|
||||
<p><%= HtmlUtils.ensureHtml(messageHtml) %></p>
|
||||
</div>
|
||||
<nav class="pagination pagination-compact top" aria-label="Compact Pagination">
|
||||
<ol>
|
||||
|
||||
@@ -1,273 +0,0 @@
|
||||
/**
|
||||
* A generic paging collection for use with a ListView and PagingFooter.
|
||||
*
|
||||
* By default this collection is designed to work with Django Rest Framework APIs, but can be configured to work with
|
||||
* others. There is support for ascending or descending sort on a particular field, as well as filtering on a field.
|
||||
* While the backend API may use either zero or one indexed page numbers, this collection uniformly exposes a one
|
||||
* indexed interface to make consumption easier for views.
|
||||
*
|
||||
* Subclasses may want to override the following properties:
|
||||
* - url (string): The base url for the API endpoint.
|
||||
* - isZeroIndexed (boolean): If true, API calls will use page numbers starting at zero. Defaults to false.
|
||||
* - perPage (number): Count of elements to fetch for each page.
|
||||
* - server_api (object): Query parameters for the API call. Subclasses may add entries as necessary. By default,
|
||||
* a 'sort_order' field is included to specify the field to sort on. This field may be removed for subclasses
|
||||
* that do not support sort ordering, or support it in a non-standard way. By default filterField and
|
||||
* sortDirection do not affect the API calls. It is up to subclasses to add this information to the appropriate
|
||||
* query string parameters in server_api.
|
||||
*/
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(['backbone.paginator'], function (BackbonePaginator) {
|
||||
var PagingCollection = BackbonePaginator.requestPager.extend({
|
||||
initialize: function (models, options) {
|
||||
options = options || {};
|
||||
if (options.url) {
|
||||
this.url = options.url;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
// These must be initialized in the constructor because otherwise all PagingCollections would point
|
||||
// to the same object references for sortableFields and filterableFields.
|
||||
this.sortableFields = {};
|
||||
this.filterableFields = {};
|
||||
|
||||
this.paginator_core = {
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
url: function () { return this.url; }
|
||||
};
|
||||
this.paginator_ui = {
|
||||
firstPage: function () { return self.isZeroIndexed ? 0 : 1; },
|
||||
// Specifies the initial page during collection initialization
|
||||
currentPage: self.isZeroIndexed ? 0 : 1,
|
||||
perPage: function () { return self.perPage; }
|
||||
};
|
||||
|
||||
this.currentPage = this.paginator_ui.currentPage;
|
||||
|
||||
this.server_api = {
|
||||
page: function () { return self.currentPage; },
|
||||
page_size: function () { return self.perPage; },
|
||||
text_search: function () { return self.searchString ? self.searchString : ''; },
|
||||
sort_order: function () { return self.sortField; }
|
||||
};
|
||||
},
|
||||
|
||||
isZeroIndexed: false,
|
||||
perPage: 10,
|
||||
|
||||
isStale: false,
|
||||
|
||||
sortField: '',
|
||||
sortDirection: 'descending',
|
||||
sortableFields: {},
|
||||
|
||||
filterField: '',
|
||||
filterableFields: {},
|
||||
|
||||
searchString: null,
|
||||
|
||||
parse: function (response) {
|
||||
this.totalCount = response.count;
|
||||
this.currentPage = response.current_page;
|
||||
this.totalPages = response.num_pages;
|
||||
this.start = response.start;
|
||||
|
||||
// Note: sort_order is not returned when performing a search
|
||||
if (response.sort_order) {
|
||||
this.sortField = response.sort_order;
|
||||
}
|
||||
return response.results;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the current page number as if numbering starts on page one, regardless of the indexing of the
|
||||
* underlying server API.
|
||||
*/
|
||||
getPage: function () {
|
||||
// TODO: this.currentPage is currently returning a function sometimes when it is called.
|
||||
// It is possible it always did this, but we either need to investigate more, or just wait until
|
||||
// we replace this code with the pattern library.
|
||||
return this.currentPage + (this.isZeroIndexed ? 1 : 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the current page of the collection. Page is assumed to be one indexed, regardless of the indexing
|
||||
* of the underlying server API. If there is an error fetching the page, the Backbone 'error' event is
|
||||
* triggered and the page does not change. A 'page_changed' event is triggered on a successful page change.
|
||||
* @param page one-indexed page to change to
|
||||
*/
|
||||
setPage: function (page) {
|
||||
var oldPage = this.currentPage,
|
||||
self = this,
|
||||
deferred = $.Deferred();
|
||||
this.goTo(page - (this.isZeroIndexed ? 1 : 0), {reset: true}).then(
|
||||
function () {
|
||||
self.isStale = false;
|
||||
self.trigger('page_changed');
|
||||
deferred.resolve();
|
||||
},
|
||||
function () {
|
||||
self.currentPage = oldPage;
|
||||
deferred.fail();
|
||||
}
|
||||
);
|
||||
return deferred.promise();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Refreshes the collection if it has been marked as stale.
|
||||
* @returns {promise} Returns a promise representing the refresh.
|
||||
*/
|
||||
refresh: function() {
|
||||
var deferred = $.Deferred();
|
||||
if (this.isStale) {
|
||||
this.setPage(1)
|
||||
.done(function() {
|
||||
deferred.resolve();
|
||||
});
|
||||
} else {
|
||||
deferred.resolve();
|
||||
}
|
||||
return deferred.promise();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if the collection has a next page, false otherwise.
|
||||
*/
|
||||
hasNextPage: function () {
|
||||
return this.getPage() < this.totalPages;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if the collection has a previous page, false otherwise.
|
||||
*/
|
||||
hasPreviousPage: function () {
|
||||
return this.getPage() > 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Moves the collection to the next page if it exists.
|
||||
*/
|
||||
nextPage: function () {
|
||||
if (this.hasNextPage()) {
|
||||
this.setPage(this.getPage() + 1);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Moves the collection to the previous page if it exists.
|
||||
*/
|
||||
previousPage: function () {
|
||||
if (this.hasPreviousPage()) {
|
||||
this.setPage(this.getPage() - 1);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds the given field to the list of fields that can be sorted on.
|
||||
* @param fieldName name of the field for the server API
|
||||
* @param displayName name of the field to display to the user
|
||||
*/
|
||||
registerSortableField: function (fieldName, displayName) {
|
||||
this.addField(this.sortableFields, fieldName, displayName);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds the given field to the list of fields that can be filtered on.
|
||||
* @param fieldName name of the field for the server API
|
||||
* @param displayName name of the field to display to the user
|
||||
*/
|
||||
registerFilterableField: function (fieldName, displayName) {
|
||||
this.addField(this.filterableFields, fieldName, displayName);
|
||||
},
|
||||
|
||||
/**
|
||||
* For internal use only. Adds the given field to the given collection of fields.
|
||||
* @param fields object of existing fields
|
||||
* @param fieldName name of the field for the server API
|
||||
* @param displayName name of the field to display to the user
|
||||
*/
|
||||
addField: function (fields, fieldName, displayName) {
|
||||
fields[fieldName] = {
|
||||
displayName: displayName
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the display name of the field that the collection is currently sorted on.
|
||||
*/
|
||||
sortDisplayName: function () {
|
||||
return this.sortableFields[this.sortField].displayName;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the display name of the field that the collection is currently filtered on.
|
||||
*/
|
||||
filterDisplayName: function () {
|
||||
return this.filterableFields[this.filterField].displayName;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the field to sort on. Sends a request to the server to fetch the first page of the collection with
|
||||
* the new sort order. If successful, the collection resets to page one with the new data.
|
||||
* @param fieldName name of the field to sort on
|
||||
* @param toggleDirection if true, the sort direction is toggled if the given field was already set
|
||||
*/
|
||||
setSortField: function (fieldName, toggleDirection) {
|
||||
if (toggleDirection) {
|
||||
if (this.sortField === fieldName) {
|
||||
this.sortDirection = PagingCollection.SortDirection.flip(this.sortDirection);
|
||||
} else {
|
||||
this.sortDirection = PagingCollection.SortDirection.DESCENDING;
|
||||
}
|
||||
}
|
||||
this.sortField = fieldName;
|
||||
this.isStale = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the direction of the sort. Sends a request to the server to fetch the first page of the collection
|
||||
* with the new sort order. If successful, the collection resets to page one with the new data.
|
||||
* @param direction either ASCENDING or DESCENDING from PagingCollection.SortDirection.
|
||||
*/
|
||||
setSortDirection: function (direction) {
|
||||
this.sortDirection = direction;
|
||||
this.isStale = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the field to filter on. Sends a request to the server to fetch the first page of the collection
|
||||
* with the new filter options. If successful, the collection resets to page one with the new data.
|
||||
* @param fieldName name of the field to filter on
|
||||
*/
|
||||
setFilterField: function (fieldName) {
|
||||
this.filterField = fieldName;
|
||||
this.isStale = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the string to use for a text search. If no string is specified then
|
||||
* the search is cleared.
|
||||
* @param searchString A string to search on, or null if no search is to be applied.
|
||||
*/
|
||||
setSearchString: function(searchString) {
|
||||
if (searchString !== this.searchString) {
|
||||
this.searchString = searchString;
|
||||
this.isStale = true;
|
||||
}
|
||||
}
|
||||
}, {
|
||||
SortDirection: {
|
||||
ASCENDING: 'ascending',
|
||||
DESCENDING: 'descending',
|
||||
flip: function (direction) {
|
||||
return direction === this.ASCENDING ? this.DESCENDING : this.ASCENDING;
|
||||
}
|
||||
}
|
||||
});
|
||||
return PagingCollection;
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
@@ -19,11 +19,12 @@
|
||||
define([
|
||||
'backbone',
|
||||
'underscore',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'common/js/components/views/paging_header',
|
||||
'common/js/components/views/paging_footer',
|
||||
'common/js/components/views/list',
|
||||
'text!common/templates/components/paginated-view.underscore'
|
||||
], function (Backbone, _, PagingHeader, PagingFooter, ListView, paginatedViewTemplate) {
|
||||
], function (Backbone, _, HtmlUtils, PagingHeader, PagingFooter, ListView, paginatedViewTemplate) {
|
||||
var PaginatedView = Backbone.View.extend({
|
||||
initialize: function () {
|
||||
var ItemListView = this.listViewClass.extend({
|
||||
@@ -51,13 +52,14 @@
|
||||
|
||||
createFooterView: function() {
|
||||
return new PagingFooter({
|
||||
collection: this.collection, hideWhenOnePage: true,
|
||||
collection: this.collection,
|
||||
hideWhenOnePage: true,
|
||||
paginationLabel: this.paginationLabel
|
||||
});
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.html(_.template(this.viewTemplate)({type: this.type}));
|
||||
HtmlUtils.setHtml(this.$el, HtmlUtils.template(this.viewTemplate)({type: this.type}));
|
||||
this.assign(this.listView, '.' + this.type + '-list');
|
||||
if (this.headerView) {
|
||||
this.assign(this.headerView, '.' + this.type + '-paging-header');
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(["underscore", "gettext", "backbone", "text!common/templates/components/paging-footer.underscore"],
|
||||
function(_, gettext, Backbone, paging_footer_template) {
|
||||
define([
|
||||
"underscore",
|
||||
"gettext",
|
||||
"backbone",
|
||||
"edx-ui-toolkit/js/utils/html-utils",
|
||||
"text!common/templates/components/paging-footer.underscore"
|
||||
],
|
||||
function(_, gettext, Backbone, HtmlUtils, pagingFooterTemplate) {
|
||||
|
||||
var PagingFooter = Backbone.View.extend({
|
||||
events : {
|
||||
@@ -17,25 +23,27 @@
|
||||
this.collection.bind('add', _.bind(this.render, this));
|
||||
this.collection.bind('remove', _.bind(this.render, this));
|
||||
this.collection.bind('reset', _.bind(this.render, this));
|
||||
this.render();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var onFirstPage = !this.collection.hasPreviousPage(),
|
||||
onLastPage = !this.collection.hasNextPage();
|
||||
if (this.hideWhenOnePage) {
|
||||
if (_.isUndefined(this.collection.totalPages)
|
||||
|| this.collection.totalPages <= 1) {
|
||||
if (this.collection.getTotalPages() <= 1) {
|
||||
this.$el.addClass('hidden');
|
||||
} else if (this.$el.hasClass('hidden')) {
|
||||
this.$el.removeClass('hidden');
|
||||
}
|
||||
}
|
||||
this.$el.html(_.template(paging_footer_template)({
|
||||
current_page: this.collection.getPage(),
|
||||
total_pages: this.collection.totalPages,
|
||||
paginationLabel: this.paginationLabel
|
||||
}));
|
||||
|
||||
HtmlUtils.setHtml(
|
||||
this.$el,
|
||||
HtmlUtils.template(pagingFooterTemplate)({
|
||||
current_page: this.collection.getPageNumber(),
|
||||
total_pages: this.collection.getTotalPages(),
|
||||
paginationLabel: this.paginationLabel
|
||||
})
|
||||
);
|
||||
this.$(".previous-page-link").toggleClass("is-disabled", onFirstPage).attr('aria-disabled', onFirstPage);
|
||||
this.$(".next-page-link").toggleClass("is-disabled", onLastPage).attr('aria-disabled', onLastPage);
|
||||
return this;
|
||||
@@ -43,11 +51,11 @@
|
||||
|
||||
changePage: function() {
|
||||
var collection = this.collection,
|
||||
currentPage = collection.getPage(),
|
||||
currentPage = collection.getPageNumber(),
|
||||
pageInput = this.$("#page-number-input"),
|
||||
pageNumber = parseInt(pageInput.val(), 10),
|
||||
validInput = true;
|
||||
if (!pageNumber || pageNumber > collection.totalPages || pageNumber < 1) {
|
||||
if (!pageNumber || pageNumber > collection.getTotalPages() || pageNumber < 1) {
|
||||
validInput = false;
|
||||
}
|
||||
// If we still have a page number by this point,
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
'backbone',
|
||||
'underscore',
|
||||
'gettext',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'edx-ui-toolkit/js/utils/string-utils',
|
||||
'text!common/templates/components/paging-header.underscore'
|
||||
], function (Backbone, _, gettext, headerTemplate) {
|
||||
], function (Backbone, _, gettext, HtmlUtils, StringUtils, headerTemplate) {
|
||||
var PagingHeader = Backbone.View.extend({
|
||||
initialize: function (options) {
|
||||
this.srInfo = options.srInfo;
|
||||
@@ -21,25 +23,37 @@
|
||||
|
||||
render: function () {
|
||||
var message,
|
||||
start = _.isUndefined(this.collection.start) ? 0 : this.collection.start,
|
||||
end = start + this.collection.length,
|
||||
num_items = _.isUndefined(this.collection.totalCount) ? 0 : this.collection.totalCount,
|
||||
context = {first_index: Math.min(start + 1, end), last_index: end, num_items: num_items};
|
||||
start = (this.collection.getPageNumber() - 1) * this.collection.getPageSize(),
|
||||
end = start + this.collection.size(),
|
||||
numItems = this.collection.getTotalRecords(),
|
||||
context = {
|
||||
firstIndex: Math.min(start + 1, end),
|
||||
lastIndex: end,
|
||||
numItems: numItems
|
||||
};
|
||||
|
||||
if (end <= 1) {
|
||||
message = interpolate(gettext('Showing %(first_index)s out of %(num_items)s total'), context, true);
|
||||
message = StringUtils.interpolate(
|
||||
gettext('Showing {firstIndex} out of {numItems} total'),
|
||||
context
|
||||
);
|
||||
} else {
|
||||
message = interpolate(
|
||||
gettext('Showing %(first_index)s-%(last_index)s out of %(num_items)s total'),
|
||||
context, true
|
||||
message = StringUtils.interpolate(
|
||||
gettext('Showing {firstIndex}-{lastIndex} out of {numItems} total'),
|
||||
context
|
||||
);
|
||||
}
|
||||
this.$el.html(_.template(headerTemplate)({
|
||||
message: message,
|
||||
srInfo: this.srInfo,
|
||||
sortableFields: this.collection.sortableFields,
|
||||
sortOrder: this.sortOrder,
|
||||
showSortControls: this.showSortControls
|
||||
}));
|
||||
|
||||
HtmlUtils.setHtml(
|
||||
this.$el,
|
||||
HtmlUtils.template(headerTemplate)({
|
||||
message: message,
|
||||
srInfo: this.srInfo,
|
||||
sortableFields: this.collection.sortableFields,
|
||||
sortOrder: this.sortOrder,
|
||||
showSortControls: this.showSortControls
|
||||
})
|
||||
);
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
@@ -6,8 +6,14 @@
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
|
||||
define(['backbone', 'jquery', 'underscore', 'text!common/templates/components/search-field.underscore'],
|
||||
function (Backbone, $, _, searchFieldTemplate) {
|
||||
define([
|
||||
'backbone',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'text!common/templates/components/search-field.underscore'
|
||||
],
|
||||
function (Backbone, $, _, HtmlUtils, searchFieldTemplate) {
|
||||
return Backbone.View.extend({
|
||||
|
||||
events: {
|
||||
@@ -16,7 +22,7 @@
|
||||
'keyup .search-field': 'refreshState',
|
||||
'click .action-clear': 'clearSearch',
|
||||
'mouseover .action-clear': 'setMouseOverState',
|
||||
'mouseout .action-clear': 'setMouseOutState',
|
||||
'mouseout .action-clear': 'setMouseOutState'
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
@@ -29,6 +35,7 @@
|
||||
var searchField = this.$('.search-field'),
|
||||
clearButton = this.$('.action-clear'),
|
||||
searchString = $.trim(searchField.val());
|
||||
|
||||
if (searchString) {
|
||||
clearButton.removeClass('is-hidden');
|
||||
} else {
|
||||
@@ -37,11 +44,14 @@
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.$el.html(_.template(searchFieldTemplate)({
|
||||
type: this.type,
|
||||
searchString: this.collection.searchString,
|
||||
searchLabel: this.label
|
||||
}));
|
||||
HtmlUtils.setHtml(
|
||||
this.$el,
|
||||
HtmlUtils.template(searchFieldTemplate)({
|
||||
type: this.type,
|
||||
searchString: this.collection.searchString,
|
||||
searchLabel: this.label
|
||||
})
|
||||
);
|
||||
this.refreshState();
|
||||
return this;
|
||||
},
|
||||
|
||||
@@ -2,10 +2,10 @@ define([
|
||||
'jquery',
|
||||
'backbone',
|
||||
'underscore',
|
||||
'edx-ui-toolkit/js/pagination/paging-collection',
|
||||
'common/js/spec_helpers/ajax_helpers',
|
||||
'common/js/components/views/paginated_view',
|
||||
'common/js/components/collections/paging_collection'
|
||||
], function ($, Backbone, _, AjaxHelpers, PaginatedView, PagingCollection) {
|
||||
'common/js/components/views/paginated_view'
|
||||
], function ($, Backbone, _, PagingCollection, AjaxHelpers, PaginatedView) {
|
||||
'use strict';
|
||||
describe('PaginatedView', function () {
|
||||
var TestItemView = Backbone.View.extend({
|
||||
@@ -36,11 +36,18 @@ define([
|
||||
beforeEach(function () {
|
||||
setFixtures('<div class="test-container"></div>');
|
||||
initialItems = generateItems(5);
|
||||
testCollection = new PagingCollection({
|
||||
var TestPagingCollection = PagingCollection.extend({
|
||||
state: {
|
||||
pageSize: 5
|
||||
}
|
||||
});
|
||||
|
||||
testCollection = new TestPagingCollection();
|
||||
testCollection.url = '/dummy/url';
|
||||
testCollection.set({
|
||||
count: 6,
|
||||
num_pages: 2,
|
||||
current_page: 1,
|
||||
start: 0,
|
||||
page: 1,
|
||||
results: initialItems
|
||||
}, {parse: true});
|
||||
testView = new TestPaginatedView({el: '.test-container', collection: testCollection}).render();
|
||||
@@ -76,7 +83,7 @@ define([
|
||||
function expectFooter(options) {
|
||||
var footerEl = testView.$('.test-paging-footer');
|
||||
expect(footerEl.text())
|
||||
.toMatch(new RegExp(options.currentPage + '\\s+out of\\s+\/\\s+' + testCollection.totalPages));
|
||||
.toMatch(new RegExp(options.currentPage + '\\s+out of\\s+\/\\s+' + options.totalPages));
|
||||
expect(footerEl.hasClass('hidden')).toBe(options.isHidden);
|
||||
}
|
||||
|
||||
@@ -90,11 +97,11 @@ define([
|
||||
initialItems = generateItems(1);
|
||||
testCollection.set(
|
||||
{
|
||||
"count": 1,
|
||||
"num_pages": 1,
|
||||
"current_page": 1,
|
||||
"start": 0,
|
||||
"results": initialItems
|
||||
count: 1,
|
||||
num_pages: 1,
|
||||
page: 1,
|
||||
start: 0,
|
||||
results: initialItems
|
||||
},
|
||||
{parse: true}
|
||||
);
|
||||
@@ -112,11 +119,10 @@ define([
|
||||
AjaxHelpers.expectNoRequests(requests);
|
||||
testView.$(nextPageButtonCss).click();
|
||||
AjaxHelpers.respondWithJson(requests, {
|
||||
"count": 6,
|
||||
"num_pages": 2,
|
||||
"current_page": 2,
|
||||
"start": 5,
|
||||
"results": newItems
|
||||
count: 6,
|
||||
num_pages: 2,
|
||||
page: 2,
|
||||
results: newItems
|
||||
});
|
||||
expectHeader('Showing 6-6 out of 6 total');
|
||||
expectItems(newItems);
|
||||
@@ -129,11 +135,10 @@ define([
|
||||
initialItems = generateItems(1);
|
||||
testCollection.set(
|
||||
{
|
||||
"count": 6,
|
||||
"num_pages": 2,
|
||||
"current_page": 2,
|
||||
"start": 5,
|
||||
"results": initialItems
|
||||
count: 6,
|
||||
num_pages: 2,
|
||||
page: 2,
|
||||
results: initialItems
|
||||
},
|
||||
{parse: true}
|
||||
);
|
||||
@@ -143,11 +148,10 @@ define([
|
||||
testView.$(previousPageButtonCss).click();
|
||||
previousPageItems = generateItems(5);
|
||||
AjaxHelpers.respondWithJson(requests, {
|
||||
"count": 6,
|
||||
"num_pages": 2,
|
||||
"current_page": 1,
|
||||
"start": 0,
|
||||
"results": previousPageItems
|
||||
count: 6,
|
||||
num_pages: 2,
|
||||
page: 1,
|
||||
results: previousPageItems
|
||||
});
|
||||
expectHeader('Showing 1-5 out of 6 total');
|
||||
expectItems(previousPageItems);
|
||||
@@ -159,11 +163,10 @@ define([
|
||||
spyOn($.fn, 'focus');
|
||||
testView.$(nextPageButtonCss).click();
|
||||
AjaxHelpers.respondWithJson(requests, {
|
||||
"count": 6,
|
||||
"num_pages": 2,
|
||||
"current_page": 2,
|
||||
"start": 5,
|
||||
"results": generateItems(1)
|
||||
count: 6,
|
||||
num_pages: 2,
|
||||
page: 2,
|
||||
results: generateItems(1)
|
||||
});
|
||||
expect(testView.$('.sr-is-focusable').focus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -1,256 +0,0 @@
|
||||
define(['jquery',
|
||||
'backbone',
|
||||
'underscore',
|
||||
'URI',
|
||||
'common/js/components/collections/paging_collection',
|
||||
'common/js/spec_helpers/ajax_helpers',
|
||||
'common/js/spec_helpers/spec_helpers'
|
||||
],
|
||||
function ($, Backbone, _, URI, PagingCollection, AjaxHelpers, SpecHelpers) {
|
||||
'use strict';
|
||||
|
||||
describe('PagingCollection', function () {
|
||||
var collection;
|
||||
var server = {
|
||||
isZeroIndexed: false,
|
||||
count: 43,
|
||||
respond: function (requests) {
|
||||
var request = AjaxHelpers.currentRequest(requests),
|
||||
params = (new URI(request.url)).query(true),
|
||||
page = parseInt(params['page'], 10),
|
||||
page_size = parseInt(params['page_size'], 10),
|
||||
page_count = Math.ceil(this.count / page_size);
|
||||
|
||||
// Make zeroPage consistently start at zero for ease of calculation
|
||||
var zeroPage = page - (this.isZeroIndexed ? 0 : 1);
|
||||
if (zeroPage < 0 || zeroPage > page_count) {
|
||||
AjaxHelpers.respondWithError(requests, 404);
|
||||
} else {
|
||||
AjaxHelpers.respondWithJson(requests, {
|
||||
'count': this.count,
|
||||
'current_page': page,
|
||||
'num_pages': page_count,
|
||||
'start': zeroPage * page_size,
|
||||
'results': []
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
var assertQueryParams = function (requests, params) {
|
||||
var request = AjaxHelpers.currentRequest(requests),
|
||||
urlParams = (new URI(request.url)).query(true);
|
||||
_.each(params, function (value, key) {
|
||||
expect(urlParams[key]).toBe(value);
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
collection = new PagingCollection();
|
||||
collection.perPage = 10;
|
||||
server.isZeroIndexed = false;
|
||||
server.count = 43;
|
||||
});
|
||||
|
||||
it('can register sortable fields', function () {
|
||||
collection.registerSortableField('test_field', 'Test Field');
|
||||
expect('test_field' in collection.sortableFields).toBe(true);
|
||||
expect(collection.sortableFields['test_field'].displayName).toBe('Test Field');
|
||||
});
|
||||
|
||||
it('can register filterable fields', function () {
|
||||
collection.registerFilterableField('test_field', 'Test Field');
|
||||
expect('test_field' in collection.filterableFields).toBe(true);
|
||||
expect(collection.filterableFields['test_field'].displayName).toBe('Test Field');
|
||||
});
|
||||
|
||||
it('sets the sort field based on the server response', function () {
|
||||
var sort_order = 'my_sort_order';
|
||||
collection = new PagingCollection({sort_order: sort_order}, {parse: true});
|
||||
expect(collection.sortField).toBe(sort_order);
|
||||
});
|
||||
|
||||
it('can set the sort field', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
collection.registerSortableField('test_field', 'Test Field');
|
||||
collection.setSortField('test_field', false);
|
||||
collection.refresh();
|
||||
assertQueryParams(requests, {'sort_order': 'test_field'});
|
||||
expect(collection.sortField).toBe('test_field');
|
||||
expect(collection.sortDisplayName()).toBe('Test Field');
|
||||
});
|
||||
|
||||
it('can set the filter field', function () {
|
||||
collection.registerFilterableField('test_field', 'Test Field');
|
||||
collection.setFilterField('test_field');
|
||||
collection.refresh();
|
||||
// The default implementation does not send any query params for filtering
|
||||
expect(collection.filterField).toBe('test_field');
|
||||
expect(collection.filterDisplayName()).toBe('Test Field');
|
||||
});
|
||||
|
||||
it('can set the sort direction', function () {
|
||||
collection.setSortDirection(PagingCollection.SortDirection.ASCENDING);
|
||||
// The default implementation does not send any query params for sort direction
|
||||
expect(collection.sortDirection).toBe(PagingCollection.SortDirection.ASCENDING);
|
||||
collection.setSortDirection(PagingCollection.SortDirection.DESCENDING);
|
||||
expect(collection.sortDirection).toBe(PagingCollection.SortDirection.DESCENDING);
|
||||
});
|
||||
|
||||
it('can toggle the sort direction when setting the sort field', function () {
|
||||
collection.registerSortableField('test_field', 'Test Field');
|
||||
collection.registerSortableField('test_field_2', 'Test Field 2');
|
||||
collection.setSortField('test_field', true);
|
||||
expect(collection.sortDirection).toBe(PagingCollection.SortDirection.DESCENDING);
|
||||
collection.setSortField('test_field', true);
|
||||
expect(collection.sortDirection).toBe(PagingCollection.SortDirection.ASCENDING);
|
||||
collection.setSortField('test_field', true);
|
||||
expect(collection.sortDirection).toBe(PagingCollection.SortDirection.DESCENDING);
|
||||
collection.setSortField('test_field_2', true);
|
||||
expect(collection.sortDirection).toBe(PagingCollection.SortDirection.DESCENDING);
|
||||
});
|
||||
|
||||
SpecHelpers.withData({
|
||||
'queries with page, page_size, and sort_order parameters when zero indexed': [true, 2],
|
||||
'queries with page, page_size, and sort_order parameters when one indexed': [false, 3],
|
||||
}, function (isZeroIndexed, page) {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
collection.isZeroIndexed = isZeroIndexed;
|
||||
collection.perPage = 5;
|
||||
collection.sortField = 'test_field';
|
||||
collection.setPage(3);
|
||||
assertQueryParams(requests, {'page': page.toString(), 'page_size': '5', 'sort_order': 'test_field'});
|
||||
});
|
||||
|
||||
SpecHelpers.withConfiguration({
|
||||
'using a zero indexed collection': [true],
|
||||
'using a one indexed collection': [false]
|
||||
}, function (isZeroIndexed) {
|
||||
collection.isZeroIndexed = isZeroIndexed;
|
||||
server.isZeroIndexed = isZeroIndexed;
|
||||
}, function () {
|
||||
describe('setPage', function() {
|
||||
it('triggers a reset event when the page changes successfully', function () {
|
||||
var requests = AjaxHelpers.requests(this),
|
||||
resetTriggered = false;
|
||||
collection.on('reset', function () { resetTriggered = true; });
|
||||
collection.setPage(3);
|
||||
server.respond(requests);
|
||||
expect(resetTriggered).toBe(true);
|
||||
});
|
||||
|
||||
it('triggers an error event when the requested page is out of range', function () {
|
||||
var requests = AjaxHelpers.requests(this),
|
||||
errorTriggered = false;
|
||||
collection.on('error', function () { errorTriggered = true; });
|
||||
collection.setPage(17);
|
||||
server.respond(requests);
|
||||
expect(errorTriggered).toBe(true);
|
||||
});
|
||||
|
||||
it('triggers an error event if the server responds with a 500', function () {
|
||||
var requests = AjaxHelpers.requests(this),
|
||||
errorTriggered = false;
|
||||
collection.on('error', function () { errorTriggered = true; });
|
||||
collection.setPage(2);
|
||||
expect(collection.getPage()).toBe(2);
|
||||
server.respond(requests);
|
||||
collection.setPage(3);
|
||||
AjaxHelpers.respondWithError(requests, 500);
|
||||
expect(errorTriggered).toBe(true);
|
||||
expect(collection.getPage()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPage', function () {
|
||||
it('returns the correct page', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
collection.setPage(1);
|
||||
server.respond(requests);
|
||||
expect(collection.getPage()).toBe(1);
|
||||
collection.setPage(3);
|
||||
server.respond(requests);
|
||||
expect(collection.getPage()).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasNextPage', function () {
|
||||
SpecHelpers.withData(
|
||||
{
|
||||
'returns false for a single page': [1, 3, false],
|
||||
'returns true on the first page': [1, 43, true],
|
||||
'returns true on the penultimate page': [4, 43, true],
|
||||
'returns false on the last page': [5, 43, false]
|
||||
},
|
||||
function (page, count, result) {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
server.count = count;
|
||||
collection.setPage(page);
|
||||
server.respond(requests);
|
||||
expect(collection.hasNextPage()).toBe(result);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('hasPreviousPage', function () {
|
||||
SpecHelpers.withData(
|
||||
{
|
||||
'returns false for a single page': [1, 3, false],
|
||||
'returns true on the last page': [5, 43, true],
|
||||
'returns true on the second page': [2, 43, true],
|
||||
'returns false on the first page': [1, 43, false]
|
||||
},
|
||||
function (page, count, result) {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
server.count = count;
|
||||
collection.setPage(page);
|
||||
server.respond(requests);
|
||||
expect(collection.hasPreviousPage()).toBe(result);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('nextPage', function () {
|
||||
SpecHelpers.withData(
|
||||
{
|
||||
'advances to the next page': [2, 43, 3],
|
||||
'silently fails on the last page': [5, 43, 5]
|
||||
},
|
||||
function (page, count, newPage) {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
server.count = count;
|
||||
collection.setPage(page);
|
||||
server.respond(requests);
|
||||
expect(collection.getPage()).toBe(page);
|
||||
collection.nextPage();
|
||||
if (requests.length > 1) {
|
||||
server.respond(requests);
|
||||
}
|
||||
expect(collection.getPage()).toBe(newPage);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('previousPage', function () {
|
||||
SpecHelpers.withData(
|
||||
{
|
||||
'moves to the previous page': [2, 43, 1],
|
||||
'silently fails on the first page': [1, 43, 1]
|
||||
},
|
||||
function (page, count, newPage) {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
server.count = count;
|
||||
collection.setPage(page);
|
||||
server.respond(requests);
|
||||
expect(collection.getPage()).toBe(page);
|
||||
collection.previousPage();
|
||||
if (requests.length > 1) {
|
||||
server.respond(requests);
|
||||
}
|
||||
expect(collection.getPage()).toBe(newPage);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -2,10 +2,10 @@ define([
|
||||
'jquery',
|
||||
'URI',
|
||||
'underscore',
|
||||
'edx-ui-toolkit/js/pagination/paging-collection',
|
||||
'common/js/spec_helpers/ajax_helpers',
|
||||
'common/js/components/views/paging_footer',
|
||||
'common/js/components/collections/paging_collection'
|
||||
], function ($, URI, _, AjaxHelpers, PagingFooter, PagingCollection) {
|
||||
'common/js/components/views/paging_footer'
|
||||
], function ($, URI, _, PagingCollection, AjaxHelpers, PagingFooter) {
|
||||
'use strict';
|
||||
describe("PagingFooter", function () {
|
||||
var pagingFooter,
|
||||
@@ -15,10 +15,10 @@ define([
|
||||
}
|
||||
return {
|
||||
count: null,
|
||||
current_page: currentPage,
|
||||
page: currentPage,
|
||||
num_pages: numPages,
|
||||
start: null,
|
||||
results: _.map(_.range(collectionLength), function() { return {}; }) // need to have non-empty collection to render
|
||||
// need to have non-empty collection to render
|
||||
results: _.map(_.range(collectionLength), function() { return {}; })
|
||||
};
|
||||
},
|
||||
nextPageCss = '.next-page-link',
|
||||
@@ -29,9 +29,12 @@ define([
|
||||
|
||||
beforeEach(function () {
|
||||
setFixtures('<div class="paging-footer"></div>');
|
||||
var collection = new PagingCollection(mockPage(1, 2), {parse: true});
|
||||
collection.url = '/test/url/';
|
||||
|
||||
pagingFooter = new PagingFooter({
|
||||
el: $('.paging-footer'),
|
||||
collection: new PagingCollection(mockPage(1, 2), {parse: true})
|
||||
collection: collection
|
||||
}).render();
|
||||
});
|
||||
|
||||
@@ -75,7 +78,7 @@ define([
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
pagingFooter.$(nextPageCss).click();
|
||||
AjaxHelpers.respondWithJson(requests, mockPage(2, 2));
|
||||
expect(pagingFooter.collection.currentPage).toBe(2);
|
||||
expect(pagingFooter.collection.getPageNumber()).toBe(2);
|
||||
});
|
||||
|
||||
it('should be enabled when there is at least one more page', function () {
|
||||
@@ -91,7 +94,7 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
describe("Previous page button", function () {
|
||||
describe('Previous page button', function () {
|
||||
it('does not move back if a server error occurs', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
pagingFooter.collection.reset(mockPage(2, 2), {parse: true});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
define([
|
||||
'underscore',
|
||||
'common/js/components/views/paging_header',
|
||||
'common/js/components/collections/paging_collection'
|
||||
], function (_, PagingHeader, PagingCollection) {
|
||||
'edx-ui-toolkit/js/pagination/paging-collection',
|
||||
'common/js/components/views/paging_header'
|
||||
], function (_, PagingCollection, PagingHeader) {
|
||||
'use strict';
|
||||
describe('PagingHeader', function () {
|
||||
var pagingHeader,
|
||||
|
||||
@@ -1,30 +1,31 @@
|
||||
define([
|
||||
'underscore',
|
||||
'URI',
|
||||
'edx-ui-toolkit/js/pagination/paging-collection',
|
||||
'common/js/components/views/search_field',
|
||||
'common/js/components/collections/paging_collection',
|
||||
'common/js/spec_helpers/ajax_helpers'
|
||||
], function (_, SearchFieldView, PagingCollection, AjaxHelpers) {
|
||||
], function (_, URI, PagingCollection, SearchFieldView, AjaxHelpers) {
|
||||
'use strict';
|
||||
describe('SearchFieldView', function () {
|
||||
var searchFieldView,
|
||||
mockUrl = '/api/mock_collection';
|
||||
|
||||
var newCollection = function (size, perPage) {
|
||||
var pageSize = 5,
|
||||
results = _.map(_.range(size), function (i) { return {foo: i}; });
|
||||
var collection = new PagingCollection(
|
||||
[],
|
||||
{
|
||||
url: mockUrl,
|
||||
count: results.length,
|
||||
num_pages: results.length / pageSize,
|
||||
current_page: 1,
|
||||
start: 0,
|
||||
results: _.first(results, perPage)
|
||||
var results = _.map(_.range(size), function (i) { return {foo: i}; });
|
||||
var TestPagingCollection = PagingCollection.extend({
|
||||
state: {
|
||||
pageSize: 5
|
||||
}
|
||||
);
|
||||
collection.start = 0;
|
||||
collection.totalCount = results.length;
|
||||
});
|
||||
|
||||
var collection = new TestPagingCollection({
|
||||
count: results.length,
|
||||
num_pages: Math.ceil(results.length / perPage),
|
||||
page: 1,
|
||||
results: _.first(results, perPage)
|
||||
}, {parse: true});
|
||||
|
||||
collection.url = mockUrl;
|
||||
return collection;
|
||||
};
|
||||
|
||||
@@ -40,6 +41,18 @@ define([
|
||||
return new SearchFieldView(options);
|
||||
};
|
||||
|
||||
var assertQueryParams = function (request, expectedParameters) {
|
||||
var urlParams = new URI(request.url).query(true);
|
||||
_.each(expectedParameters, function (value, key) {
|
||||
expect(urlParams[key]).toBe(value);
|
||||
});
|
||||
};
|
||||
|
||||
var assertNotInQueryParams = function (request, param) {
|
||||
var urlParams = new URI(request.url).query(true);
|
||||
return !urlParams.hasOwnProperty(param);
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
setFixtures('<section class="test-search"></section>');
|
||||
});
|
||||
@@ -62,17 +75,16 @@ define([
|
||||
searchFieldView = createSearchFieldView().render();
|
||||
searchFieldView.$('.search-field').val('foo');
|
||||
searchFieldView.$('.action-search').click();
|
||||
AjaxHelpers.expectRequestURL(requests, mockUrl, {
|
||||
assertQueryParams(requests[0], {
|
||||
page: '1',
|
||||
page_size: '10',
|
||||
sort_order: '',
|
||||
page_size: '5',
|
||||
text_search: 'foo'
|
||||
});
|
||||
|
||||
AjaxHelpers.respondWithJson(requests, {
|
||||
count: 10,
|
||||
current_page: 1,
|
||||
page: 1,
|
||||
num_pages: 1,
|
||||
start: 0,
|
||||
results: []
|
||||
});
|
||||
expect(searchFieldView.$('.search-field').val(), 'foo');
|
||||
@@ -84,17 +96,12 @@ define([
|
||||
searchString: 'foo'
|
||||
}).render();
|
||||
searchFieldView.$('.action-clear').click();
|
||||
AjaxHelpers.expectRequestURL(requests, mockUrl, {
|
||||
page: '1',
|
||||
page_size: '10',
|
||||
sort_order: '',
|
||||
text_search: ''
|
||||
});
|
||||
assertNotInQueryParams('text_search');
|
||||
|
||||
AjaxHelpers.respondWithJson(requests, {
|
||||
count: 10,
|
||||
current_page: 1,
|
||||
page: 1,
|
||||
num_pages: 1,
|
||||
start: 0,
|
||||
results: []
|
||||
});
|
||||
expect(searchFieldView.$('.search-field').val(), '');
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
'underscore.string': 'common/js/vendor/underscore.string',
|
||||
'backbone': 'common/js/vendor/backbone',
|
||||
'backbone.associations': 'js/vendor/backbone-associations-min',
|
||||
'backbone.paginator': 'js/vendor/backbone.paginator.min',
|
||||
'backbone.paginator': 'common/js/vendor/backbone.paginator',
|
||||
'backbone-super': 'js/vendor/backbone-super',
|
||||
'jasmine-imagediff': 'js/vendor/jasmine-imagediff',
|
||||
'URI': 'js/vendor/URI.min',
|
||||
@@ -131,7 +131,7 @@
|
||||
},
|
||||
'backbone.paginator': {
|
||||
deps: ['backbone'],
|
||||
exports: 'Backbone.Paginator'
|
||||
exports: 'Backbone.PageableCollection'
|
||||
},
|
||||
"backbone-super": {
|
||||
deps: ["backbone"]
|
||||
@@ -166,7 +166,6 @@
|
||||
'common/js/spec/components/feedback_spec.js',
|
||||
'common/js/spec/components/list_spec.js',
|
||||
'common/js/spec/components/paginated_view_spec.js',
|
||||
'common/js/spec/components/paging_collection_spec.js',
|
||||
'common/js/spec/components/paging_header_spec.js',
|
||||
'common/js/spec/components/paging_footer_spec.js',
|
||||
'common/js/spec/components/search_field_spec.js',
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<% if (!_.isUndefined(srInfo)) { %>
|
||||
<h2 class="sr" id="<%= srInfo.id %>"><%- srInfo.text %></h2>
|
||||
<h2 class="sr" id="<%- srInfo.id %>"><%- srInfo.text %></h2>
|
||||
<% } %>
|
||||
<div class="search-tools listing-tools">
|
||||
<span class="search-count listing-count">
|
||||
<%= message %>
|
||||
<%- message %>
|
||||
</span>
|
||||
<% if (showSortControls) { %>
|
||||
|
|
||||
@@ -11,7 +11,7 @@
|
||||
<label class="field-label" for="paging-header-select"><%- gettext("Sorted by") %></label>
|
||||
<select id="paging-header-select" name="paging-header-select" class="field-input input-select listing-sort-select">
|
||||
<% _.each(sortableFields, function (option, key) { %>
|
||||
<option value="<%= key %>" <% if (key === sortOrder) { %> selected="true" <% } %>>
|
||||
<option value="<%- key %>" <% if (key === sortOrder) { %> selected="true" <% } %>>
|
||||
<%- option.displayName %>
|
||||
</option>
|
||||
<% }) %>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<div class="page-header-search wrapper-search-<%= type %>">
|
||||
<div class="page-header-search wrapper-search-<%- type %>">
|
||||
<form class="search-form">
|
||||
<div class="wrapper-search-input">
|
||||
<label for="search-<%= type %>" class="search-label"><%- searchLabel %></label>
|
||||
<input id="search-<%= type %>" class="search-field" type="text" value="<%- searchString %>" placeholder="<%- searchLabel %>" />
|
||||
<button type="button" class="action action-clear <%= searchLabel ? '' : 'is-hidden' %>" aria-label="<%- gettext('Clear search') %>">
|
||||
<label for="search-<%- type %>" class="search-label"><%- searchLabel %></label>
|
||||
<input id="search-<%- type %>" class="search-field" type="text" value="<%- searchString %>" placeholder="<%- searchLabel %>" />
|
||||
<button type="button" class="action action-clear <%- searchLabel ? '' : 'is-hidden' %>" aria-label="<%- gettext('Clear search') %>">
|
||||
<i class="icon fa fa-times-circle" aria-hidden="true"></i><span class="sr"><%- gettext('Search') %></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,23 +1,48 @@
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(['common/js/components/collections/paging_collection'],
|
||||
define(['edx-ui-toolkit/js/pagination/paging-collection'],
|
||||
function(PagingCollection) {
|
||||
var BaseCollection = PagingCollection.extend({
|
||||
initialize: function(options) {
|
||||
constructor: function (models, options) {
|
||||
this.options = options;
|
||||
this.url = options.url;
|
||||
|
||||
PagingCollection.prototype.initialize.call(this);
|
||||
this.state.perPage = options.per_page;
|
||||
|
||||
this.course_id = options.course_id;
|
||||
this.perPage = options.per_page;
|
||||
|
||||
this.teamEvents = options.teamEvents;
|
||||
this.teamEvents.bind('teams:update', this.onUpdate, this);
|
||||
|
||||
this.queryParams = _.extend({}, BaseCollection.prototype.queryParams, this.queryParams);
|
||||
PagingCollection.prototype.constructor.call(this, models, options);
|
||||
},
|
||||
|
||||
parse: function (response, options) {
|
||||
if (!response) {
|
||||
response = {};
|
||||
}
|
||||
|
||||
if (!response.results) {
|
||||
response.results = [];
|
||||
}
|
||||
|
||||
return PagingCollection.prototype.parse.call(this, response, options);
|
||||
},
|
||||
|
||||
onUpdate: function(event) {
|
||||
// Mark the collection as stale so that it knows to refresh when needed.
|
||||
this.isStale = true;
|
||||
},
|
||||
|
||||
sync: function (method, model, options) {
|
||||
// do not send total pages and total records in request
|
||||
if (method === 'read') {
|
||||
var params = _.values(_.pick(this.queryParams, ['totalPages', 'totalRecords']));
|
||||
_.each(params, function (param) {
|
||||
delete options.data[param];
|
||||
});
|
||||
}
|
||||
|
||||
return PagingCollection.prototype.sync(method, model, options);
|
||||
}
|
||||
});
|
||||
return BaseCollection;
|
||||
|
||||
@@ -2,13 +2,20 @@
|
||||
'use strict';
|
||||
define(['teams/js/collections/team'], function (TeamCollection) {
|
||||
var MyTeamsCollection = TeamCollection.extend({
|
||||
initialize: function (teams, options) {
|
||||
this.url = options.url;
|
||||
TeamCollection.prototype.initialize.call(this, teams, options);
|
||||
delete this.server_api.topic_id;
|
||||
this.server_api = _.extend(this.server_api, {
|
||||
username: options.username
|
||||
});
|
||||
queryParams: {
|
||||
username: function () {
|
||||
return this.options.username;
|
||||
},
|
||||
text_search: function () {
|
||||
return this.searchString || '';
|
||||
},
|
||||
totalPages: null,
|
||||
totalRecords: null
|
||||
},
|
||||
|
||||
constructor: function (teams, options) {
|
||||
TeamCollection.prototype.constructor.call(this, teams, options);
|
||||
delete this.queryParams.topic_id;
|
||||
}
|
||||
});
|
||||
return MyTeamsCollection;
|
||||
|
||||
@@ -3,29 +3,46 @@
|
||||
define(['teams/js/collections/base', 'teams/js/models/team', 'gettext'],
|
||||
function(BaseCollection, TeamModel, gettext) {
|
||||
var TeamCollection = BaseCollection.extend({
|
||||
sortField: 'last_activity_at',
|
||||
model: TeamModel,
|
||||
|
||||
state: {
|
||||
sortKey: 'last_activity_at',
|
||||
order: null
|
||||
},
|
||||
|
||||
initialize: function(teams, options) {
|
||||
this.url = options.url;
|
||||
var self = this;
|
||||
BaseCollection.prototype.initialize.call(this, options);
|
||||
queryParams: {
|
||||
topic_id: function () {
|
||||
return this.options.topic_id;
|
||||
},
|
||||
expand: 'user',
|
||||
course_id: function () {
|
||||
return this.options.course_id;
|
||||
},
|
||||
order_by: function () {
|
||||
return this.getSearchString() ? '' : this.state.sortKey;
|
||||
},
|
||||
text_search: function () {
|
||||
return this.getSearchString() || '';
|
||||
}
|
||||
},
|
||||
|
||||
this.server_api = _.extend(
|
||||
this.server_api,
|
||||
{
|
||||
topic_id: this.topic_id = options.topic_id,
|
||||
expand: 'user',
|
||||
course_id: function () { return encodeURIComponent(self.course_id); },
|
||||
order_by: function () { return self.searchString ? '' : this.sortField; }
|
||||
}
|
||||
);
|
||||
delete this.server_api.sort_order; // Sort order is not specified for the Team API
|
||||
constructor: function(teams, options) {
|
||||
this.state = _.extend({}, TeamCollection.prototype.state, this.state);
|
||||
this.queryParams = _.extend({}, TeamCollection.prototype.queryParams, this.queryParams);
|
||||
this.topic_id = options.topic_id;
|
||||
BaseCollection.prototype.constructor.call(this, teams, options);
|
||||
|
||||
this.registerSortableField('last_activity_at', gettext('last activity'));
|
||||
this.registerSortableField('open_slots', gettext('open slots'));
|
||||
},
|
||||
|
||||
model: TeamModel
|
||||
setFilterField: function (fieldName, value) {
|
||||
BaseCollection.prototype.setFilterField.call(this, fieldName, value);
|
||||
|
||||
this.queryParams[fieldName] = function () {
|
||||
return value;
|
||||
};
|
||||
}
|
||||
});
|
||||
return TeamCollection;
|
||||
});
|
||||
|
||||
@@ -3,23 +3,25 @@
|
||||
define(['underscore', 'gettext', 'teams/js/collections/base', 'teams/js/models/topic'],
|
||||
function(_, gettext, BaseCollection, TopicModel) {
|
||||
var TopicCollection = BaseCollection.extend({
|
||||
initialize: function(topics, options) {
|
||||
model: TopicModel,
|
||||
|
||||
var self = this;
|
||||
state: {
|
||||
perPage: null,
|
||||
sortKey: 'name'
|
||||
},
|
||||
|
||||
BaseCollection.prototype.initialize.call(this, options);
|
||||
queryParams: {
|
||||
course_id: function () { return this.course_id; },
|
||||
text_search: function () { return this.searchString || ''; }
|
||||
},
|
||||
|
||||
this.perPage = topics.results.length;
|
||||
|
||||
this.server_api = _.extend(
|
||||
this.server_api,
|
||||
{
|
||||
course_id: function () { return encodeURIComponent(self.course_id); },
|
||||
order_by: function () { return this.sortField; }
|
||||
}
|
||||
);
|
||||
delete this.server_api['sort_order']; // Sort order is not specified for the Team API
|
||||
constructor: function(topics, options) {
|
||||
BaseCollection.prototype.constructor.call(this, topics, options);
|
||||
|
||||
this.state.pageSize = topics.results.length;
|
||||
if (topics.sort_order) {
|
||||
this.state.sortKey = topics.sort_order;
|
||||
}
|
||||
this.registerSortableField('name', gettext('name'));
|
||||
// Translators: This refers to the number of teams (a count of how many teams there are)
|
||||
this.registerSortableField('team_count', gettext('team count'));
|
||||
@@ -29,9 +31,7 @@
|
||||
if (_.contains(['create', 'delete'], event.action)) {
|
||||
this.isStale = true;
|
||||
}
|
||||
},
|
||||
|
||||
model: TopicModel
|
||||
}
|
||||
});
|
||||
return TopicCollection;
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ define(['backbone', 'URI', 'underscore', 'common/js/spec_helpers/ajax_helpers',
|
||||
};
|
||||
|
||||
it('sets its perPage based on initial page size', function () {
|
||||
expect(topicCollection.perPage).toBe(5);
|
||||
expect(topicCollection.getPageSize()).toBe(5);
|
||||
});
|
||||
|
||||
it('sorts by name', function () {
|
||||
|
||||
@@ -43,7 +43,6 @@ define([
|
||||
teams = TeamSpecHelpers.createMockTeams({
|
||||
results: []
|
||||
}, {
|
||||
per_page: 2,
|
||||
url: TeamSpecHelpers.testContext.myTeamsUrl,
|
||||
username: TeamSpecHelpers.testContext.userInfo.username
|
||||
}, MyTeamsCollection),
|
||||
@@ -60,7 +59,7 @@ define([
|
||||
username : TeamSpecHelpers.testContext.userInfo.username,
|
||||
course_id : TeamSpecHelpers.testContext.courseID,
|
||||
page : '1',
|
||||
page_size : '2',
|
||||
page_size : '5',
|
||||
text_search: '',
|
||||
order_by: 'last_activity_at'
|
||||
}
|
||||
|
||||
@@ -263,9 +263,9 @@ define([
|
||||
// Clear the search and submit it again
|
||||
teamsTabView.$('.search-field').val('');
|
||||
teamsTabView.$('.action-search').click();
|
||||
|
||||
verifyTeamsRequest({
|
||||
order_by: 'last_activity_at',
|
||||
text_search: ''
|
||||
order_by: 'last_activity_at'
|
||||
});
|
||||
AjaxHelpers.respondWithJson(requests, {});
|
||||
expect(teamsTabView.$('.page-title').text()).toBe('Test Topic 1');
|
||||
|
||||
@@ -63,9 +63,11 @@ define([
|
||||
return new collectionType(
|
||||
createMockTeamsResponse(responseOptions),
|
||||
_.extend({
|
||||
state: {
|
||||
pageSize: 5
|
||||
},
|
||||
teamEvents: teamEvents,
|
||||
course_id: testCourseID,
|
||||
per_page: 2,
|
||||
parse: true
|
||||
}, options)
|
||||
);
|
||||
@@ -287,6 +289,9 @@ define([
|
||||
sort_order: 'name'
|
||||
},
|
||||
{
|
||||
state: {
|
||||
pageSize: 5
|
||||
},
|
||||
teamEvents: teamEvents,
|
||||
course_id: testCourseID,
|
||||
parse: true,
|
||||
|
||||
@@ -3,12 +3,19 @@
|
||||
*/
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(['backbone', 'underscore', 'gettext', 'teams/js/views/team_discussion',
|
||||
define([
|
||||
'backbone',
|
||||
'underscore',
|
||||
'gettext',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'teams/js/views/team_discussion',
|
||||
'common/js/components/utils/view_utils',
|
||||
'teams/js/views/team_utils',
|
||||
'text!teams/templates/team-profile.underscore',
|
||||
'text!teams/templates/team-member.underscore'],
|
||||
function (Backbone, _, gettext, TeamDiscussionView, ViewUtils, TeamUtils, teamTemplate, teamMemberTemplate) {
|
||||
'text!teams/templates/team-member.underscore'
|
||||
],
|
||||
function (Backbone, _, gettext, HtmlUtils, TeamDiscussionView, ViewUtils, TeamUtils,
|
||||
teamTemplate, teamMemberTemplate) {
|
||||
var TeamProfileView = Backbone.View.extend({
|
||||
|
||||
errorMessage: gettext("An error occurred. Try again."),
|
||||
@@ -16,6 +23,7 @@
|
||||
events: {
|
||||
'click .leave-team-link': 'leaveTeam'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this.teamEvents = options.teamEvents;
|
||||
this.context = options.context;
|
||||
@@ -31,17 +39,21 @@
|
||||
var memberships = this.model.get('membership'),
|
||||
discussionTopicID = this.model.get('discussion_topic_id'),
|
||||
isMember = TeamUtils.isUserMemberOfTeam(memberships, this.context.userInfo.username);
|
||||
this.$el.html(_.template(teamTemplate)({
|
||||
courseID: this.context.courseID,
|
||||
discussionTopicID: discussionTopicID,
|
||||
readOnly: !(this.context.userInfo.privileged || isMember),
|
||||
country: this.countries[this.model.get('country')],
|
||||
language: this.languages[this.model.get('language')],
|
||||
membershipText: TeamUtils.teamCapacityText(memberships.length, this.context.maxTeamSize),
|
||||
isMember: isMember,
|
||||
hasCapacity: memberships.length < this.context.maxTeamSize,
|
||||
hasMembers: memberships.length >= 1
|
||||
}));
|
||||
|
||||
HtmlUtils.setHtml(
|
||||
this.$el,
|
||||
HtmlUtils.template(teamTemplate)({
|
||||
courseID: this.context.courseID,
|
||||
discussionTopicID: discussionTopicID,
|
||||
readOnly: !(this.context.userInfo.privileged || isMember),
|
||||
country: this.countries[this.model.get('country')],
|
||||
language: this.languages[this.model.get('language')],
|
||||
membershipText: TeamUtils.teamCapacityText(memberships.length, this.context.maxTeamSize),
|
||||
isMember: isMember,
|
||||
hasCapacity: memberships.length < this.context.maxTeamSize,
|
||||
hasMembers: memberships.length >= 1
|
||||
})
|
||||
);
|
||||
this.discussionView = new TeamDiscussionView({
|
||||
el: this.$('.discussion-module')
|
||||
});
|
||||
@@ -56,11 +68,14 @@
|
||||
renderTeamMembers: function() {
|
||||
var view = this;
|
||||
_.each(this.model.get('membership'), function(membership) {
|
||||
view.$('.members-info').append(_.template(teamMemberTemplate)({
|
||||
imageUrl: membership.user.profile_image.image_url_medium,
|
||||
username: membership.user.username,
|
||||
memberProfileUrl: '/u/' + membership.user.username
|
||||
}));
|
||||
HtmlUtils.append(
|
||||
view.$('.members-info'),
|
||||
HtmlUtils.template(teamMemberTemplate)({
|
||||
imageUrl: membership.user.profile_image.image_url_medium,
|
||||
username: membership.user.username,
|
||||
memberProfileUrl: '/u/' + membership.user.username
|
||||
})
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
type: 'teams',
|
||||
|
||||
srInfo: {
|
||||
id: "heading-browse-teams",
|
||||
id: 'heading-browse-teams',
|
||||
text: gettext('All teams')
|
||||
},
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
'jquery',
|
||||
'underscore',
|
||||
'gettext',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'edx-ui-toolkit/js/utils/string-utils',
|
||||
'common/js/components/views/search_field',
|
||||
'js/components/header/views/header',
|
||||
'js/components/header/models/header',
|
||||
@@ -25,7 +27,7 @@
|
||||
'teams/js/views/team_utils',
|
||||
'teams/js/views/instructor_tools',
|
||||
'text!teams/templates/teams_tab.underscore'],
|
||||
function (Backbone, $, _, gettext, SearchFieldView, HeaderView, HeaderModel,
|
||||
function (Backbone, $, _, gettext, HtmlUtils, StringUtils, SearchFieldView, HeaderView, HeaderModel,
|
||||
TopicModel, TopicCollection, TeamModel, TeamCollection, MyTeamsCollection, TeamAnalytics,
|
||||
TeamsTabbedView, TopicsView, TeamProfileView, MyTeamsView, TopicTeamsView, TeamEditView,
|
||||
TeamMembersEditView, TeamProfileHeaderActionsView, TeamUtils, InstructorToolsView, teamsTemplate) {
|
||||
@@ -44,7 +46,7 @@
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.html(_.template(teamsTemplate));
|
||||
HtmlUtils.setHtml(this.$el, HtmlUtils.template(teamsTemplate)({}));
|
||||
this.$('p.error').hide();
|
||||
this.header.setElement(this.$('.teams-header')).render();
|
||||
if (this.instructorTools) {
|
||||
@@ -121,7 +123,7 @@
|
||||
course_id: this.context.courseID,
|
||||
parse: true
|
||||
}
|
||||
).bootstrap();
|
||||
);
|
||||
|
||||
this.topicsView = new TopicsView({
|
||||
router: this.router,
|
||||
@@ -138,12 +140,15 @@
|
||||
url: 'my-teams',
|
||||
view: this.myTeamsView
|
||||
}, {
|
||||
title: interpolate(
|
||||
title: HtmlUtils.interpolateHtml(
|
||||
// Translators: sr_start and sr_end surround text meant only for screen readers.
|
||||
// The whole string will be shown to users as "Browse teams" if they are using a
|
||||
// screenreader, and "Browse" otherwise.
|
||||
gettext("Browse %(sr_start)s teams %(sr_end)s"),
|
||||
{"sr_start": '<span class="sr">', "sr_end": '</span>'}, true
|
||||
gettext('Browse {sr_start} teams {sr_end}'),
|
||||
{
|
||||
sr_start: HtmlUtils.HTML('<span class="sr">'),
|
||||
sr_end: HtmlUtils.HTML('</span>')
|
||||
}
|
||||
),
|
||||
url: 'browse',
|
||||
view: this.topicsView
|
||||
@@ -219,10 +224,9 @@
|
||||
collection: view.teamsCollection,
|
||||
breadcrumbs: view.createBreadcrumbs(topic),
|
||||
title: gettext('Team Search'),
|
||||
description: interpolate(
|
||||
gettext('Showing results for "%(searchString)s"'),
|
||||
{ searchString: view.teamsCollection.searchString },
|
||||
true
|
||||
description: StringUtils.interpolate(
|
||||
gettext('Showing results for "{searchString}"'),
|
||||
{searchString: view.teamsCollection.getSearchString()}
|
||||
),
|
||||
showSortControls: false
|
||||
});
|
||||
@@ -336,16 +340,15 @@
|
||||
per_page: 10
|
||||
});
|
||||
view.teamsCollection = collection;
|
||||
collection.goTo(1)
|
||||
.done(function() {
|
||||
var teamsView = view.createTeamsListView({
|
||||
topic: topic,
|
||||
collection: collection,
|
||||
breadcrumbs: view.createBreadcrumbs(),
|
||||
showSortControls: true
|
||||
collection.getPage(1).then(function () {
|
||||
var teamsView = view.createTeamsListView({
|
||||
topic: topic,
|
||||
collection: collection,
|
||||
breadcrumbs: view.createBreadcrumbs(),
|
||||
showSortControls: true
|
||||
});
|
||||
deferred.resolve(teamsView);
|
||||
});
|
||||
deferred.resolve(teamsView);
|
||||
});
|
||||
});
|
||||
}
|
||||
return deferred.promise();
|
||||
@@ -354,7 +357,6 @@
|
||||
createTeamsListView: function(options) {
|
||||
var topic = options.topic,
|
||||
collection = options.collection,
|
||||
self = this,
|
||||
teamsView = new TopicTeamsView({
|
||||
router: this.router,
|
||||
context: this.context,
|
||||
@@ -389,7 +391,7 @@
|
||||
// that the collection doesn't unnecessarily get refreshed again.
|
||||
collection.isStale = false;
|
||||
|
||||
if (collection.searchString) {
|
||||
if (collection.getSearchString()) {
|
||||
Backbone.history.navigate(searchUrl, {trigger: true});
|
||||
} else if (Backbone.history.getFragment() === searchUrl) {
|
||||
Backbone.history.navigate('topics/' + topic.get('id'), {trigger: true});
|
||||
@@ -591,30 +593,27 @@
|
||||
|
||||
routeNotFound: function (route) {
|
||||
this.notFoundError(
|
||||
interpolate(
|
||||
gettext('The page "%(route)s" could not be found.'),
|
||||
{route: route},
|
||||
true
|
||||
StringUtils.interpolate(
|
||||
gettext('The page "{route}" could not be found.'),
|
||||
{route: route}
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
topicNotFound: function (topicID) {
|
||||
this.notFoundError(
|
||||
interpolate(
|
||||
gettext('The topic "%(topic)s" could not be found.'),
|
||||
{topic: topicID},
|
||||
true
|
||||
StringUtils.interpolate(
|
||||
gettext('The topic "{topic}" could not be found.'),
|
||||
{topic: topicID}
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
teamNotFound: function (teamID) {
|
||||
this.notFoundError(
|
||||
interpolate(
|
||||
gettext('The team "%(team)s" could not be found.'),
|
||||
{team: teamID},
|
||||
true
|
||||
StringUtils.interpolate(
|
||||
gettext('The team "{team}" could not be found.'),
|
||||
{team: teamID}
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
type: 'topics',
|
||||
|
||||
srInfo: {
|
||||
id: "heading-browse-topics",
|
||||
text: gettext("All topics")
|
||||
id: 'heading-browse-topics',
|
||||
text: gettext('All topics')
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<div class="team-profile">
|
||||
<div class="page-content-main">
|
||||
<div class="discussion-module" data-course-id="<%= courseID %>" data-discussion-id="<%= discussionTopicID %>"
|
||||
data-read-only="<%= readOnly %>"
|
||||
data-user-create-comment="<%= !readOnly %>"
|
||||
data-user-create-subcomment="<%= !readOnly %>">
|
||||
<% if ( !readOnly) { %>
|
||||
<div class="discussion-module" data-course-id="<%- courseID %>" data-discussion-id="<%- discussionTopicID %>"
|
||||
data-read-only="<%- readOnly %>"
|
||||
data-user-create-comment="<%- !readOnly %>"
|
||||
data-user-create-subcomment="<%- !readOnly %>">
|
||||
<% if (!readOnly) { %>
|
||||
<button type="button" class="btn new-post-btn"><i class="icon fa fa-edit new-post-icon" aria-hidden="true"></i><%- gettext("New Post") %></button>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(['backbone', 'common/js/components/collections/paging_collection', 'js/bookmarks/models/bookmark'],
|
||||
function (Backbone, PagingCollection, BookmarkModel) {
|
||||
|
||||
define([
|
||||
'backbone',
|
||||
'edx-ui-toolkit/js/pagination/paging-collection',
|
||||
'js/bookmarks/models/bookmark'
|
||||
], function (Backbone, PagingCollection, BookmarkModel) {
|
||||
return PagingCollection.extend({
|
||||
initialize: function(options) {
|
||||
PagingCollection.prototype.initialize.call(this);
|
||||
|
||||
this.url = options.url;
|
||||
this.server_api = _.extend(
|
||||
{
|
||||
course_id: function () { return encodeURIComponent(options.course_id); },
|
||||
fields : function () { return encodeURIComponent('display_name,path'); }
|
||||
},
|
||||
this.server_api
|
||||
);
|
||||
delete this.server_api.sort_order; // Sort order is not specified for the Bookmark API
|
||||
},
|
||||
|
||||
model: BookmarkModel,
|
||||
|
||||
queryParams: {
|
||||
course_id: function () { return this.options.course_id; },
|
||||
fields : function () { return 'display_name,path'; }
|
||||
},
|
||||
|
||||
url: function() {
|
||||
return this.url;
|
||||
},
|
||||
|
||||
constructor: function (models, options) {
|
||||
this.options = options;
|
||||
this.url = options.url;
|
||||
PagingCollection.prototype.constructor.call(this, models, options);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
;(function (define, undefined) {
|
||||
'use strict';
|
||||
define(['gettext', 'jquery', 'underscore', 'backbone', 'logger', 'moment',
|
||||
define(['gettext', 'jquery', 'underscore', 'backbone', 'logger', 'moment', 'edx-ui-toolkit/js/utils/html-utils',
|
||||
'common/js/components/views/paging_header', 'common/js/components/views/paging_footer',
|
||||
'text!templates/bookmarks/bookmarks-list.underscore'
|
||||
],
|
||||
function (gettext, $, _, Backbone, Logger, _moment,
|
||||
function (gettext, $, _, Backbone, Logger, _moment, HtmlUtils,
|
||||
PagingHeaderView, PagingFooterView, BookmarksListTemplate) {
|
||||
|
||||
var moment = _moment || window.moment;
|
||||
@@ -28,7 +28,7 @@
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this.template = _.template(BookmarksListTemplate);
|
||||
this.template = HtmlUtils.template(BookmarksListTemplate);
|
||||
this.loadingMessageView = options.loadingMessageView;
|
||||
this.errorMessageView = options.errorMessageView;
|
||||
this.langCode = $(this.el).data('langCode');
|
||||
@@ -43,7 +43,8 @@
|
||||
bookmarksCollection: this.collection,
|
||||
humanFriendlyDate: this.humanFriendlyDate
|
||||
};
|
||||
this.$el.html(this.template(data));
|
||||
|
||||
HtmlUtils.setHtml(this.$el, this.template(data));
|
||||
this.pagingHeaderView.setElement(this.$('.paging-header')).render();
|
||||
this.pagingFooterView.setElement(this.$('.paging-footer')).render();
|
||||
this.delegateEvents();
|
||||
@@ -56,7 +57,7 @@
|
||||
this.hideErrorMessage();
|
||||
this.showBookmarksContainer();
|
||||
|
||||
this.collection.goTo(this.defaultPage).done(function () {
|
||||
this.collection.getPage(this.defaultPage).done(function () {
|
||||
view.render();
|
||||
view.focusBookmarksElement();
|
||||
}).fail(function () {
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
},
|
||||
|
||||
initialize: function () {
|
||||
var bookmarksCollection = new BookmarksCollection(
|
||||
var bookmarksCollection = new BookmarksCollection([],
|
||||
{
|
||||
course_id: $('.courseware-results').data('courseId'),
|
||||
url: $(".courseware-bookmarks-button").data('bookmarksApiUrl')
|
||||
url: $('.courseware-bookmarks-button').data('bookmarksApiUrl')
|
||||
}
|
||||
);
|
||||
bookmarksCollection.bootstrap();
|
||||
this.bookmarksListView = new BookmarksListView(
|
||||
{
|
||||
collection: bookmarksCollection,
|
||||
|
||||
@@ -1,20 +1,26 @@
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define([
|
||||
'underscore', 'common/js/components/collections/paging_collection', 'js/edxnotes/models/note'
|
||||
'underscore', 'edx-ui-toolkit/js/pagination/paging-collection', 'js/edxnotes/models/note'
|
||||
], function (_, PagingCollection, NoteModel) {
|
||||
return PagingCollection.extend({
|
||||
model: NoteModel,
|
||||
|
||||
initialize: function(models, options) {
|
||||
PagingCollection.prototype.initialize.call(this);
|
||||
state: {
|
||||
pageSize: 10
|
||||
},
|
||||
|
||||
queryParams: {},
|
||||
|
||||
constructor: function (models, options) {
|
||||
this.url = options.url;
|
||||
this.perPage = options.perPage;
|
||||
this.server_api = _.pick(this.server_api, "page", "page_size");
|
||||
this.state.pageSize = options.perPage;
|
||||
|
||||
if (options.text) {
|
||||
this.server_api.text = options.text;
|
||||
this.queryParams.text = options.text;
|
||||
}
|
||||
|
||||
PagingCollection.prototype.constructor.call(this, models, options);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
;(function (define, undefined) {
|
||||
'use strict';
|
||||
define([
|
||||
'jquery', 'underscore', 'backbone', 'gettext', 'js/edxnotes/utils/logger',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'backbone',
|
||||
'gettext',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'js/edxnotes/utils/logger',
|
||||
'js/edxnotes/collections/notes'
|
||||
], function ($, _, Backbone, gettext, NotesLogger, NotesCollection) {
|
||||
], function ($, _, Backbone, gettext, HtmlUtils, NotesLogger, NotesCollection) {
|
||||
var SearchBoxView = Backbone.View.extend({
|
||||
events: {
|
||||
'submit': 'submitHandler'
|
||||
},
|
||||
|
||||
errorMessage: gettext('An error has occurred. Make sure that you are connected to the Internet, and then try refreshing the page.'),
|
||||
emptyFieldMessage: (function () {
|
||||
var message = gettext('Please enter a term in the %(anchor_start)s search field%(anchor_end)s.');
|
||||
return interpolate(message, {
|
||||
'anchor_start': '<a href="#search-notes-input">',
|
||||
'anchor_end': '</a>'
|
||||
}, true);
|
||||
} ()),
|
||||
|
||||
emptyFieldMessageHtml: (function () {
|
||||
var message = gettext('Please enter a term in the {anchorStart} search field{anchorEnd}.');
|
||||
return HtmlUtils.interpolateHtml(message, {
|
||||
anchorStart: HtmlUtils.HTML('<a href="#search-notes-input">'),
|
||||
anchorEnd: HtmlUtils.HTML('</a>')
|
||||
});
|
||||
}()),
|
||||
|
||||
initialize: function (options) {
|
||||
_.bindAll(this, 'onSuccess', 'onError', 'onComplete');
|
||||
@@ -91,7 +97,7 @@ define([
|
||||
|
||||
validateField: function (searchQuery) {
|
||||
if (!($.trim(searchQuery))) {
|
||||
this.options.error(this.emptyFieldMessage, searchQuery);
|
||||
this.options.error(this.emptyFieldMessageHtml, searchQuery);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -102,7 +108,7 @@ define([
|
||||
if (args) {
|
||||
this.options.search.apply(this, args);
|
||||
this.logger.emit('edx.course.student_notes.searched', {
|
||||
'number_of_results': args[0].totalCount,
|
||||
'number_of_results': args[0].getTotalRecords(),
|
||||
'search_string': args[1]
|
||||
});
|
||||
} else {
|
||||
@@ -147,15 +153,13 @@ define([
|
||||
* @return {jQuery.Deferred}
|
||||
*/
|
||||
sendRequest: function (text) {
|
||||
this.collection = new NotesCollection(
|
||||
[],
|
||||
{
|
||||
text: text,
|
||||
perPage: this.options.perPage,
|
||||
url: this.el.action
|
||||
}
|
||||
);
|
||||
return this.collection.goTo(1);
|
||||
this.collection = new NotesCollection([], {
|
||||
text: text,
|
||||
perPage: this.options.perPage,
|
||||
url: this.el.action
|
||||
});
|
||||
|
||||
return this.collection.getPage(1);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
;(function (define, undefined) {
|
||||
'use strict';
|
||||
define([
|
||||
'jquery', 'underscore', 'backbone', 'js/edxnotes/models/tab'
|
||||
], function ($, _, Backbone, TabModel) {
|
||||
'jquery',
|
||||
'underscore',
|
||||
'backbone',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'js/edxnotes/models/tab'
|
||||
], function ($, _, Backbone, HtmlUtils, TabModel) {
|
||||
var TabView = Backbone.View.extend({
|
||||
PanelConstructor: null,
|
||||
|
||||
@@ -121,11 +125,11 @@ define([
|
||||
/**
|
||||
* Shows error message.
|
||||
*/
|
||||
showErrorMessage: function (message) {
|
||||
this.$('.wrapper-msg')
|
||||
.removeClass('is-hidden')
|
||||
.find('.msg-content .copy').html(message);
|
||||
showErrorMessageHtml: function (htmlMessage) {
|
||||
var $wrapper = this.$('.wrapper-msg');
|
||||
$wrapper.removeClass('is-hidden');
|
||||
|
||||
HtmlUtils.setHtml($wrapper.find('.msg-content .copy'), htmlMessage);
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ define([
|
||||
},
|
||||
|
||||
onSearchError: function (errorMessage) {
|
||||
this.showErrorMessage(errorMessage);
|
||||
this.showErrorMessageHtml(errorMessage);
|
||||
if (this.searchDeferred) {
|
||||
this.searchDeferred.reject();
|
||||
}
|
||||
|
||||
@@ -186,7 +186,12 @@ define(['backbone',
|
||||
|
||||
it("calls bookmarks list render on page_changed event", function () {
|
||||
var renderSpy = spyOn(BookmarksListView.prototype, 'render');
|
||||
var listView = new BookmarksListView({collection: new BookmarksCollection({course_id: 'abc'})});
|
||||
var listView = new BookmarksListView({
|
||||
collection: new BookmarksCollection([], {
|
||||
course_id: 'abc',
|
||||
url: '/test-bookmarks/url/'
|
||||
})
|
||||
});
|
||||
listView.collection.trigger('page_changed');
|
||||
expect(renderSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
define([
|
||||
'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'js/edxnotes/views/search_box',
|
||||
'js/edxnotes/collections/notes', 'js/spec/edxnotes/helpers'
|
||||
], function($, _, AjaxHelpers, SearchBoxView, NotesCollection, Helpers) {
|
||||
'jquery',
|
||||
'underscore',
|
||||
'common/js/spec_helpers/ajax_helpers',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'js/edxnotes/views/search_box',
|
||||
'js/edxnotes/collections/notes',
|
||||
'js/spec/edxnotes/helpers'
|
||||
], function($, _, AjaxHelpers, HtmlUtils, SearchBoxView, NotesCollection, Helpers) {
|
||||
'use strict';
|
||||
describe('EdxNotes SearchBoxView', function() {
|
||||
var getSearchBox, submitForm, assertBoxIsEnabled, assertBoxIsDisabled, searchResponse;
|
||||
@@ -159,7 +164,7 @@ define([
|
||||
expect(requests).toHaveLength(0);
|
||||
assertBoxIsEnabled(this.searchBox);
|
||||
expect(this.searchBox.options.error).toHaveBeenCalledWith(
|
||||
'Please enter a term in the <a href="#search-notes-input"> search field</a>.',
|
||||
HtmlUtils.HTML('Please enter a term in the <a href="#search-notes-input"> search field</a>.'),
|
||||
' '
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
define([
|
||||
'jquery', 'backbone', 'common/js/spec_helpers/template_helpers', 'js/edxnotes/collections/tabs',
|
||||
'js/edxnotes/views/tabs_list', 'js/edxnotes/views/tab_view'
|
||||
], function(
|
||||
$, Backbone, TemplateHelpers, TabsCollection, TabsListView, TabView
|
||||
) {
|
||||
'jquery',
|
||||
'backbone',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'common/js/spec_helpers/template_helpers',
|
||||
'js/edxnotes/collections/tabs',
|
||||
'js/edxnotes/views/tabs_list',
|
||||
'js/edxnotes/views/tab_view'
|
||||
], function ($, Backbone, HtmlUtils, TemplateHelpers, TabsCollection, TabsListView, TabView) {
|
||||
'use strict';
|
||||
describe('EdxNotes TabView', function() {
|
||||
var TestSubView = Backbone.View.extend({
|
||||
@@ -94,7 +97,8 @@ define([
|
||||
it('can show/hide error messages', function () {
|
||||
var view = getView(this.tabsCollection),
|
||||
errorHolder = view.$('.wrapper-msg');
|
||||
view.showErrorMessage('<p>error message is here</p>');
|
||||
|
||||
view.showErrorMessageHtml(HtmlUtils.HTML('<p>error message is here</p>'));
|
||||
expect(errorHolder).not.toHaveClass('is-hidden');
|
||||
expect(errorHolder.find('.copy')).toContainHtml('<p>error message is here</p>');
|
||||
|
||||
@@ -106,7 +110,7 @@ define([
|
||||
it('should hide error messages before rendering', function () {
|
||||
var view = getView(this.tabsCollection),
|
||||
errorHolder = view.$('.wrapper-msg');
|
||||
view.showErrorMessage('<p>error message is here</p>');
|
||||
view.showErrorMessageHtml('<p>error message is here</p>');
|
||||
view.render();
|
||||
expect(errorHolder).toHaveClass('is-hidden');
|
||||
expect(errorHolder.find('.copy')).toBeEmpty();
|
||||
|
||||
@@ -70,6 +70,7 @@ define([
|
||||
]);
|
||||
|
||||
this.collection = new NotesCollection(notes, {perPage: 10, parse: true});
|
||||
this.collection.url = '/test/notes/';
|
||||
this.tabsCollection = new TabsCollection();
|
||||
});
|
||||
|
||||
@@ -79,7 +80,7 @@ define([
|
||||
Helpers.verifyPageData(view, this.tabsCollection, tabInfo, recentActivityTabId, notes);
|
||||
});
|
||||
|
||||
it("will not render header and footer if there are no notes", function () {
|
||||
it('will not render header and footer if there are no notes', function () {
|
||||
var notes = {
|
||||
'count': 0,
|
||||
'current_page': 1,
|
||||
@@ -95,7 +96,7 @@ define([
|
||||
expect(view.$('.pagination.pagination-full.bottom')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("can go to a page number", function () {
|
||||
it('can go to a page number', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
var notes = Helpers.createNotesData(
|
||||
{
|
||||
@@ -108,6 +109,7 @@ define([
|
||||
);
|
||||
|
||||
var collection = new NotesCollection(notes, {perPage: 10, parse: true});
|
||||
collection.url = '/test/notes/';
|
||||
var view = getView(collection, this.tabsCollection);
|
||||
|
||||
Helpers.verifyPaginationInfo(view, "Showing 1-10 out of 12 total", false, 1, 2);
|
||||
@@ -134,7 +136,7 @@ define([
|
||||
Helpers.verifyPageData(view, this.tabsCollection, tabInfo, recentActivityTabId, notes);
|
||||
});
|
||||
|
||||
it("can navigate forward and backward", function () {
|
||||
it('can navigate forward and backward', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
var page1Notes = Helpers.createNotesData(
|
||||
{
|
||||
@@ -146,6 +148,7 @@ define([
|
||||
}
|
||||
);
|
||||
var collection = new NotesCollection(page1Notes, {perPage: 10, parse: true});
|
||||
collection.url = '/test/notes/';
|
||||
var view = getView(collection, this.tabsCollection);
|
||||
|
||||
Helpers.verifyPaginationInfo(view, "Showing 1-10 out of 15 total", false, 1, 2);
|
||||
@@ -180,7 +183,7 @@ define([
|
||||
Helpers.verifyPageData(view, this.tabsCollection, tabInfo, recentActivityTabId, page1Notes);
|
||||
});
|
||||
|
||||
it("sends correct page size value", function () {
|
||||
it('sends correct page size value', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
var notes = Helpers.createNotesData(
|
||||
{
|
||||
@@ -192,6 +195,7 @@ define([
|
||||
}
|
||||
);
|
||||
var collection = new NotesCollection(notes, {perPage: 5, parse: true});
|
||||
collection.url = '/test/notes/';
|
||||
var view = getView(collection, this.tabsCollection);
|
||||
|
||||
view.$('.pagination .next-page-link').click();
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
'underscore.string': 'common/js/vendor/underscore.string',
|
||||
'backbone': 'common/js/vendor/backbone',
|
||||
'backbone.associations': 'xmodule_js/common_static/js/vendor/backbone-associations-min',
|
||||
'backbone.paginator': 'xmodule_js/common_static/js/vendor/backbone.paginator.min',
|
||||
'backbone.paginator': 'common/js/vendor/backbone.paginator',
|
||||
'backbone-super': 'js/vendor/backbone-super',
|
||||
'URI': 'xmodule_js/common_static/js/vendor/URI.min',
|
||||
'tinymce': 'xmodule_js/common_static/js/vendor/tinymce/js/tinymce/tinymce.full.min',
|
||||
@@ -202,11 +202,14 @@
|
||||
},
|
||||
'backbone.paginator': {
|
||||
deps: ['backbone'],
|
||||
exports: 'Backbone.Paginator'
|
||||
exports: 'Backbone.PageableCollection'
|
||||
},
|
||||
"backbone-super": {
|
||||
deps: ["backbone"]
|
||||
},
|
||||
'paging-collection': {
|
||||
deps: ['jquery', 'underscore', 'backbone.paginator']
|
||||
},
|
||||
'youtube': {
|
||||
exports: 'YT'
|
||||
},
|
||||
|
||||
@@ -1,33 +1,43 @@
|
||||
define(['backbone', 'jquery', 'underscore', 'URI', 'common/js/spec_helpers/ajax_helpers',
|
||||
define([
|
||||
'backbone',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'URI',
|
||||
'edx-ui-toolkit/js/pagination/paging-collection',
|
||||
'common/js/spec_helpers/ajax_helpers',
|
||||
'js/spec/student_profile/helpers',
|
||||
'js/student_profile/views/badge_list_container',
|
||||
'common/js/components/collections/paging_collection'
|
||||
'js/student_profile/views/badge_list_container'
|
||||
],
|
||||
function (Backbone, $, _, URI, AjaxHelpers, LearnerProfileHelpers, BadgeListContainer, PagingCollection) {
|
||||
function (Backbone, $, _, URI, PagingCollection, AjaxHelpers, LearnerProfileHelpers, BadgeListContainer) {
|
||||
'use strict';
|
||||
describe('edx.user.BadgeListContainer', function () {
|
||||
|
||||
var view, requests;
|
||||
|
||||
var createView = function (requests, badge_list_object) {
|
||||
var badgeCollection = new PagingCollection();
|
||||
var createView = function (requests, pageNum, badge_list_object) {
|
||||
var BadgeCollection = PagingCollection.extend({
|
||||
queryParams: {
|
||||
currentPage: 'current_page'
|
||||
}
|
||||
});
|
||||
var badgeCollection = new BadgeCollection();
|
||||
badgeCollection.url = '/api/badges/v1/assertions/user/staff/';
|
||||
var models = [];
|
||||
_.each(_.range(badge_list_object.count), function (idx) {
|
||||
models.push(LearnerProfileHelpers.makeBadge(idx));
|
||||
});
|
||||
badge_list_object.results = models;
|
||||
badgeCollection.fetch();
|
||||
badgeCollection.setPage(pageNum);
|
||||
var request = AjaxHelpers.currentRequest(requests);
|
||||
var path = new URI(request.url).path();
|
||||
expect(path).toBe('/api/badges/v1/assertions/user/staff/');
|
||||
AjaxHelpers.respondWithJson(requests, badge_list_object);
|
||||
var badge_list_container = new BadgeListContainer({
|
||||
var badgeListContainer = new BadgeListContainer({
|
||||
'collection': badgeCollection
|
||||
|
||||
});
|
||||
badge_list_container.render();
|
||||
return badge_list_container;
|
||||
badgeListContainer.render();
|
||||
return badgeListContainer;
|
||||
};
|
||||
|
||||
afterEach(function () {
|
||||
@@ -36,7 +46,7 @@ define(['backbone', 'jquery', 'underscore', 'URI', 'common/js/spec_helpers/ajax_
|
||||
|
||||
it('displays all badges', function () {
|
||||
requests = AjaxHelpers.requests(this);
|
||||
view = createView(requests, {
|
||||
view = createView(requests, 1, {
|
||||
count: 30,
|
||||
previous: '/arbitrary/url',
|
||||
num_pages: 3,
|
||||
@@ -51,7 +61,7 @@ define(['backbone', 'jquery', 'underscore', 'URI', 'common/js/spec_helpers/ajax_
|
||||
|
||||
it('displays placeholder on last page', function () {
|
||||
requests = AjaxHelpers.requests(this);
|
||||
view = createView(requests, {
|
||||
view = createView(requests, 3, {
|
||||
count: 30,
|
||||
previous: '/arbitrary/url',
|
||||
num_pages: 3,
|
||||
@@ -66,7 +76,7 @@ define(['backbone', 'jquery', 'underscore', 'URI', 'common/js/spec_helpers/ajax_
|
||||
|
||||
it('does not display placeholder on first page', function () {
|
||||
requests = AjaxHelpers.requests(this);
|
||||
view = createView(requests, {
|
||||
view = createView(requests, 1, {
|
||||
count: 30,
|
||||
previous: '/arbitrary/url',
|
||||
num_pages: 3,
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
define(['backbone', 'jquery', 'underscore',
|
||||
define([
|
||||
'backbone',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'edx-ui-toolkit/js/pagination/paging-collection',
|
||||
'js/spec/student_profile/helpers',
|
||||
'js/student_profile/views/badge_list_view',
|
||||
'common/js/components/collections/paging_collection'
|
||||
'js/student_profile/views/badge_list_view'
|
||||
],
|
||||
function (Backbone, $, _, LearnerProfileHelpers, BadgeListView, PagingCollection) {
|
||||
function (Backbone, $, _, PagingCollection, LearnerProfileHelpers, BadgeListView) {
|
||||
"use strict";
|
||||
describe("edx.user.BadgeListView", function () {
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
|
||||
};
|
||||
|
||||
it("renders the full profile for a user", function() {
|
||||
|
||||
requests = AjaxHelpers.requests(this);
|
||||
|
||||
var context = createProfilePage(true),
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'common/js/spec_helpers/template_helpers',
|
||||
define(['backbone',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'edx-ui-toolkit/js/pagination/paging-collection',
|
||||
'common/js/spec_helpers/ajax_helpers',
|
||||
'common/js/spec_helpers/template_helpers',
|
||||
'js/spec/student_account/helpers',
|
||||
'js/spec/student_profile/helpers',
|
||||
'js/views/fields',
|
||||
@@ -8,12 +13,11 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
|
||||
'js/student_profile/views/learner_profile_view',
|
||||
'js/student_profile/views/badge_list_container',
|
||||
'js/student_account/views/account_settings_fields',
|
||||
'common/js/components/collections/paging_collection',
|
||||
'js/views/message_banner'
|
||||
],
|
||||
function (Backbone, $, _, AjaxHelpers, TemplateHelpers, Helpers, LearnerProfileHelpers, FieldViews,
|
||||
UserAccountModel, AccountPreferencesModel, LearnerProfileFields, LearnerProfileView,
|
||||
BadgeListContainer, AccountSettingsFieldViews, PagingCollection, MessageBannerView) {
|
||||
],
|
||||
function (Backbone, $, _, PagingCollection, AjaxHelpers, TemplateHelpers, Helpers, LearnerProfileHelpers,
|
||||
FieldViews, UserAccountModel, AccountPreferencesModel, LearnerProfileFields, LearnerProfileView,
|
||||
BadgeListContainer, AccountSettingsFieldViews, MessageBannerView) {
|
||||
'use strict';
|
||||
|
||||
describe("edx.user.LearnerProfileView", function () {
|
||||
|
||||
@@ -6,18 +6,24 @@
|
||||
'text!templates/student_profile/badge_list.underscore'],
|
||||
function (gettext, $, _, PaginatedView, BadgeView, BadgeListView, BadgeListTemplate) {
|
||||
var BadgeListContainer = PaginatedView.extend({
|
||||
type: 'badge',
|
||||
|
||||
itemViewClass: BadgeView,
|
||||
|
||||
listViewClass: BadgeListView,
|
||||
|
||||
viewTemplate: BadgeListTemplate,
|
||||
|
||||
isZeroIndexed: true,
|
||||
|
||||
paginationLabel: gettext('Accomplishments Pagination'),
|
||||
|
||||
initialize: function (options) {
|
||||
BadgeListContainer.__super__.initialize.call(this, options);
|
||||
this.listView.find_courses_url = options.find_courses_url;
|
||||
this.listView.badgeMeta = options.badgeMeta;
|
||||
this.listView.ownProfile = options.ownProfile;
|
||||
},
|
||||
type: 'badge',
|
||||
itemViewClass: BadgeView,
|
||||
listViewClass: BadgeListView,
|
||||
viewTemplate: BadgeListTemplate,
|
||||
isZeroIndexed: true,
|
||||
paginationLabel: gettext("Accomplishments Pagination")
|
||||
}
|
||||
});
|
||||
|
||||
return BadgeListContainer;
|
||||
|
||||
@@ -1,39 +1,58 @@
|
||||
;(function (define, undefined) {
|
||||
'use strict';
|
||||
define([
|
||||
'gettext', 'jquery', 'underscore', 'common/js/components/views/list', 'js/student_profile/views/badge_view',
|
||||
'text!templates/student_profile/badge_placeholder.underscore'],
|
||||
function (gettext, $, _, ListView, BadgeView, badgePlaceholder) {
|
||||
'gettext',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'common/js/components/views/list',
|
||||
'js/student_profile/views/badge_view',
|
||||
'text!templates/student_profile/badge_placeholder.underscore'
|
||||
],
|
||||
function (gettext, $, _, HtmlUtils, ListView, BadgeView, badgePlaceholder) {
|
||||
var BadgeListView = ListView.extend({
|
||||
tagName: 'div',
|
||||
template: _.template(badgePlaceholder),
|
||||
|
||||
template: HtmlUtils.template(badgePlaceholder),
|
||||
|
||||
renderCollection: function () {
|
||||
var self = this,
|
||||
$row;
|
||||
|
||||
this.$el.empty();
|
||||
var self = this;
|
||||
var row;
|
||||
|
||||
// Split into two columns.
|
||||
this.collection.each(function (badge, index) {
|
||||
if (index % 2 === 0) {
|
||||
row = $('<div class="row">');
|
||||
this.$el.append(row);
|
||||
$row = $('<div class="row">');
|
||||
this.$el.append($row);
|
||||
}
|
||||
var item = new BadgeView({
|
||||
var $item = new BadgeView({
|
||||
model: badge,
|
||||
badgeMeta: this.badgeMeta,
|
||||
ownProfile: this.ownProfile
|
||||
}).render().el;
|
||||
row.append(item);
|
||||
this.itemViews.push(item);
|
||||
|
||||
if ($row) {
|
||||
$row.append($item);
|
||||
}
|
||||
|
||||
this.itemViews.push($item);
|
||||
}, this);
|
||||
// Placeholder must always be at the end, and may need a new row.
|
||||
if (!this.collection.hasNextPage()) {
|
||||
// find_courses_url set by BadgeListContainer during initialization.
|
||||
var placeholder = this.template({find_courses_url: self.find_courses_url});
|
||||
if (this.collection.length % 2 === 0) {
|
||||
row = $('<div class="row">');
|
||||
this.$el.append(row);
|
||||
$row = $('<div class="row">');
|
||||
this.$el.append($row);
|
||||
}
|
||||
|
||||
if ($row) {
|
||||
HtmlUtils.append(
|
||||
$row,
|
||||
this.template({find_courses_url: self.find_courses_url})
|
||||
);
|
||||
}
|
||||
row.append(placeholder);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
;(function (define, undefined) {
|
||||
'use strict';
|
||||
define([
|
||||
'gettext', 'jquery', 'underscore', 'backbone', 'logger',
|
||||
'gettext',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'backbone',
|
||||
'logger',
|
||||
'edx-ui-toolkit/js/pagination/paging-collection',
|
||||
'js/student_account/models/user_account_model',
|
||||
'js/student_account/models/user_preferences_model',
|
||||
'js/views/fields',
|
||||
'js/student_profile/views/learner_profile_fields',
|
||||
'js/student_profile/views/learner_profile_view',
|
||||
'js/student_profile/models/badges_model',
|
||||
'common/js/components/collections/paging_collection',
|
||||
'js/student_profile/views/badge_list_container',
|
||||
'js/student_account/views/account_settings_fields',
|
||||
'js/views/message_banner',
|
||||
'string_utils'
|
||||
], function (gettext, $, _, Backbone, Logger, AccountSettingsModel, AccountPreferencesModel, FieldsView,
|
||||
LearnerProfileFieldsView, LearnerProfileView, BadgeModel, PagingCollection, BadgeListContainer,
|
||||
], function (gettext, $, _, Backbone, Logger, PagingCollection, AccountSettingsModel, AccountPreferencesModel,
|
||||
FieldsView, LearnerProfileFieldsView, LearnerProfileView, BadgeModel, BadgeListContainer,
|
||||
AccountSettingsFieldViews, MessageBannerView) {
|
||||
|
||||
return function (options) {
|
||||
@@ -64,7 +68,7 @@
|
||||
|
||||
var profileImageFieldView = new LearnerProfileFieldsView.ProfileImageFieldView({
|
||||
model: accountSettingsModel,
|
||||
valueAttribute: "profile_image",
|
||||
valueAttribute: 'profile_image',
|
||||
editable: editable === 'toggle',
|
||||
messageView: messageView,
|
||||
imageMaxBytes: options['profile_image_max_bytes'],
|
||||
@@ -125,7 +129,12 @@
|
||||
})
|
||||
];
|
||||
|
||||
var badgeCollection = new PagingCollection();
|
||||
var BadgeCollection = PagingCollection.extend({
|
||||
queryParams: {
|
||||
currentPage: 'current_page'
|
||||
}
|
||||
});
|
||||
var badgeCollection = new BadgeCollection();
|
||||
badgeCollection.url = options.badges_api_url;
|
||||
|
||||
var badgeListContainer = new BadgeListContainer({
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
"logger": "js/src/logger",
|
||||
"backbone": "common/js/vendor/backbone",
|
||||
"backbone-super": "js/vendor/backbone-super",
|
||||
"backbone.paginator": "js/vendor/backbone.paginator.min",
|
||||
"backbone.paginator": "common/js/vendor/backbone.paginator",
|
||||
"underscore": "common/js/vendor/underscore",
|
||||
"underscore.string": "common/js/vendor/underscore.string",
|
||||
// The jquery-migrate library was added in upgrading from
|
||||
@@ -144,7 +144,7 @@
|
||||
},
|
||||
"backbone.paginator": {
|
||||
deps: ["backbone"],
|
||||
exports: "Backbone.Paginator"
|
||||
exports: "Backbone.PageableCollection"
|
||||
},
|
||||
"backbone-super": {
|
||||
deps: ["backbone"]
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"backbone": "~1.3.2",
|
||||
"coffee-script": "1.6.1",
|
||||
"edx-pattern-library": "~0.12.4",
|
||||
"edx-ui-toolkit": "~0.9.1",
|
||||
"edx-ui-toolkit": "~1.1.0",
|
||||
"jquery": "~2.2.0",
|
||||
"jquery-migrate": "^1.4.1",
|
||||
"jquery.scrollto": "~2.1.2",
|
||||
|
||||
@@ -52,6 +52,7 @@ NPM_INSTALLED_LIBRARIES = [
|
||||
'underscore.string/dist/underscore.string.js',
|
||||
'picturefill/dist/picturefill.js',
|
||||
'backbone/backbone.js',
|
||||
'edx-ui-toolkit/node_modules/backbone.paginator/lib/backbone.paginator.js',
|
||||
]
|
||||
|
||||
# Directory to install static vendor files
|
||||
|
||||
Reference in New Issue
Block a user