Commit f92c3372 by Andy Armstrong

Add a loading indicator to the Files & Uploads page.

parent ca685028
......@@ -236,6 +236,20 @@ define ["jasmine", "js/spec/create_sinon", "squire"],
create_sinon.respondWithJson(requests, @mockAssetsResponse)
return requests
it "should show a status indicator while loading", ->
appendSetFixtures('<div class="ui-loading"/>')
expect($('.ui-loading').is(':visible')).toBe(true)
setup.call(this)
expect($('.ui-loading').is(':visible')).toBe(false)
it "should hide the status indicator if an error occurs while loading", ->
requests = create_sinon.requests(this)
appendSetFixtures('<div class="ui-loading"/>')
expect($('.ui-loading').is(':visible')).toBe(true)
@view.setPage(0)
create_sinon.respondWithError(requests)
expect($('.ui-loading').is(':visible')).toBe(false)
it "should render both assets", ->
requests = setup.call(this)
expect(@view.$el).toContainText("test asset 1")
......
define(["sinon"], function(sinon) {
var fakeServer, fakeRequests, respondWithJson, respondWithError;
/* These utility methods are used by Jasmine tests to create a mock server or
* get reference to mock requests. In either case, the cleanup (restore) is done with
* an after function.
......@@ -15,7 +17,7 @@ define(["sinon"], function(sinon) {
* Get a reference to the mocked server, and respond
* to all requests with the specified statusCode.
*/
var fakeServer = function (statusCode, that) {
fakeServer = function (statusCode, that) {
var server = sinon.fakeServer.create();
that.after(function() {
server.restore();
......@@ -29,9 +31,9 @@ define(["sinon"], function(sinon) {
* return a reference to the Array. This allows tests
* to respond for individual requests.
*/
var fakeRequests = function (that) {
var requests = [];
var xhr = sinon.useFakeXMLHttpRequest();
fakeRequests = function (that) {
var requests = [],
xhr = sinon.useFakeXMLHttpRequest();
xhr.onCreate = function(request) {
requests.push(request);
};
......@@ -43,16 +45,24 @@ define(["sinon"], function(sinon) {
return requests;
};
var respondWithJson = function(requests, jsonResponse, requestIndex) {
respondWithJson = function(requests, jsonResponse, requestIndex) {
requestIndex = requestIndex || requests.length - 1;
requests[requestIndex].respond(200,
{ "Content-Type": "application/json" },
JSON.stringify(jsonResponse));
};
respondWithError = function(requests, requestIndex) {
requestIndex = requestIndex || requests.length - 1;
requests[requestIndex].respond(500,
{ "Content-Type": "application/json" },
JSON.stringify({ }));
};
return {
"server": fakeServer,
"requests": fakeRequests,
"respondWithJson": respondWithJson
"respondWithJson": respondWithJson,
"respondWithError": respondWithError
};
});
define(["js/views/paging", "js/views/asset", "js/views/paging_header", "js/views/paging_footer"],
function(PagingView, AssetView, PagingHeader, PagingFooter) {
define(["jquery", "underscore", "gettext", "js/views/paging", "js/views/asset", "js/views/paging_header", "js/views/paging_footer"],
function($, _, gettext, PagingView, AssetView, PagingHeader, PagingFooter) {
var AssetsView = PagingView.extend({
var AssetsView = PagingView.extend({
// takes AssetCollection as model
events : {
......@@ -16,11 +16,23 @@ var AssetsView = PagingView.extend({
this.registerSortableColumn('js-asset-name-col', gettext('Name'), 'display_name', 'asc');
this.registerSortableColumn('js-asset-date-col', gettext('Date Added'), 'date_added', 'desc');
this.setInitialSortColumn('js-asset-date-col');
this.showLoadingIndicator();
},
render: function() {
// Wait until the content is loaded the first time to render
return this;
},
getTableBody: function() {
var tableBody = this.tableBody;
if (!tableBody) {
this.hideLoadingIndicator();
// Create the table
this.$el.html(this.template());
this.tableBody = this.$('#asset-table-body');
tableBody = this.$('#asset-table-body');
this.tableBody = tableBody;
this.pagingHeader = new PagingHeader({view: this, el: $('#asset-paging-header')});
this.pagingFooter = new PagingFooter({view: this, el: $('#asset-paging-footer')});
this.pagingHeader.render();
......@@ -29,28 +41,34 @@ var AssetsView = PagingView.extend({
// Hide the contents until the collection has loaded the first time
this.$('.asset-library').hide();
this.$('.no-asset-content').hide();
return this;
}
return tableBody;
},
renderPageItems: function() {
var self = this,
assets = this.collection,
hasAssets = assets.length > 0;
self.tableBody.empty();
hasAssets = assets.length > 0,
tableBody = this.getTableBody();
tableBody.empty();
if (hasAssets) {
assets.each(
function(asset) {
var view = new AssetView({model: asset});
self.tableBody.append(view.render().el);
});
tableBody.append(view.render().el);
}
);
}
self.$('.asset-library').toggle(hasAssets);
self.$('.no-asset-content').toggle(!hasAssets);
return this;
},
handleDestroy: function(model, collection, options) {
onError: function() {
this.hideLoadingIndicator();
},
handleDestroy: function(model) {
this.collection.fetch({reset: true}); // reload the collection to get a fresh page full of items
analytics.track('Deleted Asset', {
'course': course_location_analytics,
......@@ -74,7 +92,7 @@ var AssetsView = PagingView.extend({
var columnName = event.target.id;
this.toggleSortOrder(columnName);
}
});
});
return AssetsView;
}); // end define();
return AssetsView;
}); // end define();
......@@ -46,6 +46,14 @@ define(["jquery", "underscore", "backbone", "js/utils/handle_iframe_binding"],
event.preventDefault();
target.closest('.expand-collapse').toggleClass('expand').toggleClass('collapse');
target.closest('.is-collapsible, .window').toggleClass('collapsed');
},
showLoadingIndicator: function() {
$('.ui-loading').show();
},
hideLoadingIndicator: function() {
$('.ui-loading').hide();
}
});
......
define(["backbone", "js/views/feedback_alert", "gettext"], function(Backbone, AlertView, gettext) {
define(["underscore", "js/views/baseview", "js/views/feedback_alert", "gettext"],
function(_, BaseView, AlertView, gettext) {
var PagingView = Backbone.View.extend({
var PagingView = BaseView.extend({
// takes a Backbone Paginator as a model
sortableColumns: {},
initialize: function() {
Backbone.View.prototype.initialize.call(this);
BaseView.prototype.initialize.call(this);
var collection = this.collection;
collection.bind('add', _.bind(this.onPageRefresh, this));
collection.bind('remove', _.bind(this.onPageRefresh, this));
......@@ -29,12 +30,17 @@ define(["backbone", "js/views/feedback_alert", "gettext"], function(Backbone, Al
success: function() {
window.scrollTo(0, 0);
},
error: function(collection, response, options) {
error: function(collection) {
collection.currentPage = oldPage;
self.onError();
}
});
},
onError: function() {
// Do nothing by default
},
nextPage: function() {
var collection = this.collection,
currentPage = collection.currentPage,
......@@ -82,12 +88,9 @@ define(["backbone", "js/views/feedback_alert", "gettext"], function(Backbone, Al
},
sortDirectionName: function() {
var collection = this.collection;
if (collection.sortDirection === 'asc') {
return gettext("ascending");
} else {
return gettext("descending");
}
var collection = this.collection,
ascending = collection.sortDirection === 'asc';
return ascending ? gettext("ascending") : gettext("descending");
},
setInitialSortColumn: function(sortColumn) {
......@@ -115,4 +118,4 @@ define(["backbone", "js/views/feedback_alert", "gettext"], function(Backbone, Al
});
return PagingView;
}); // end define();
}); // end define();
......@@ -27,7 +27,7 @@ require(["domReady", "jquery", "js/models/asset", "js/collections/asset",
var assets = new AssetCollection();
assets.url = "${asset_callback_url}";
var assetsView = new AssetsView({collection: assets, el: $('#asset-library')});
var assetsView = new AssetsView({collection: assets, el: $('.assets-wrapper')});
assetsView.render();
assetsView.setPage(0);
......@@ -148,7 +148,12 @@ require(["domReady", "jquery", "js/models/asset", "js/collections/asset",
<div class="wrapper-content wrapper">
<section class="content">
<article id="asset-library" class="content-primary" role="main"></article>
<article class="content-primary" role="main">
<div class="assets-wrapper"/>
<div class="ui-loading">
<p><span class="spin"><i class="icon-refresh"></i></span> <span class="copy">${_("Loading&hellip;")}</span></p>
</div>
</article>
<aside class="content-supplementary" role="complimentary">
<div class="bit">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment