move upload code for assets to AssetsView
STUD-1523
This commit is contained in:
@@ -6,9 +6,12 @@ Feature: CMS.Upload Files
|
||||
@skip_safari
|
||||
Scenario: Users can upload files
|
||||
Given I am at the files and upload page of a Studio course
|
||||
When I upload the file "test"
|
||||
When I upload the file "test" by clicking "Upload your first asset"
|
||||
Then I should see the file "test" was uploaded
|
||||
And The url for the file "test" is valid
|
||||
When I upload the file "test2"
|
||||
Then I should see the file "test2" was uploaded
|
||||
And The url for the file "test2" is valid
|
||||
|
||||
# Uploading isn't working on safari with sauce labs
|
||||
@skip_safari
|
||||
|
||||
@@ -25,8 +25,11 @@ def go_to_uploads(_step):
|
||||
|
||||
|
||||
@step(u'I upload the( test)? file "([^"]*)"$')
|
||||
def upload_file(_step, is_test_file, file_name):
|
||||
world.click_link('Upload New File')
|
||||
def upload_file(_step, is_test_file, file_name, button_text=None):
|
||||
if button_text:
|
||||
world.click_link(button_text)
|
||||
else:
|
||||
world.click_link('Upload New File')
|
||||
|
||||
if not is_test_file:
|
||||
_write_test_file(file_name, "test file")
|
||||
@@ -39,6 +42,11 @@ def upload_file(_step, is_test_file, file_name):
|
||||
world.css_click(close_css)
|
||||
|
||||
|
||||
@step(u'I upload the file "([^"]*)" by clicking "([^"]*)"')
|
||||
def upload_file_on_button_press(_step, file_name, button_text=None):
|
||||
upload_file(_step, '', file_name, button_text)
|
||||
|
||||
|
||||
@step(u'I upload the files "([^"]*)"$')
|
||||
def upload_files(_step, files_string):
|
||||
# files_string should be comma separated with no spaces.
|
||||
|
||||
@@ -220,6 +220,7 @@ define([
|
||||
|
||||
"js/spec/views/baseview_spec",
|
||||
"js/spec/views/paging_spec",
|
||||
"js/spec/views/assets_spec",
|
||||
|
||||
"js/spec/views/container_spec",
|
||||
"js/spec/views/unit_spec",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
define ["jasmine", "js/spec_helpers/create_sinon", "squire"],
|
||||
(jasmine, create_sinon, Squire) ->
|
||||
define ["jquery", "jasmine", "js/spec_helpers/create_sinon", "squire"],
|
||||
($, jasmine, create_sinon, Squire) ->
|
||||
|
||||
feedbackTpl = readFixtures('system-feedback.underscore')
|
||||
assetLibraryTpl = readFixtures('asset-library.underscore')
|
||||
@@ -236,6 +236,33 @@ define ["jasmine", "js/spec_helpers/create_sinon", "squire"],
|
||||
create_sinon.respondWithJson(requests, @mockAssetsResponse)
|
||||
return requests
|
||||
|
||||
$.fn.fileupload = ->
|
||||
return ''
|
||||
|
||||
clickEvent = (html_selector) ->
|
||||
$(html_selector).click()
|
||||
|
||||
it "should show upload modal on clicking upload asset button", ->
|
||||
spyOn(@view, "showUploadModal")
|
||||
setup.call(this)
|
||||
expect(@view.showUploadModal).not.toHaveBeenCalled()
|
||||
@view.showUploadModal(clickEvent(".upload-button"))
|
||||
expect(@view.showUploadModal).toHaveBeenCalled()
|
||||
|
||||
it "should show file selection menu on choose file button", ->
|
||||
spyOn(@view, "showFileSelectionMenu")
|
||||
setup.call(this)
|
||||
expect(@view.showFileSelectionMenu).not.toHaveBeenCalled()
|
||||
@view.showFileSelectionMenu(clickEvent(".choose-file-button"))
|
||||
expect(@view.showFileSelectionMenu).toHaveBeenCalled()
|
||||
|
||||
it "should hide upload modal on clicking close button", ->
|
||||
spyOn(@view, "hideModal")
|
||||
setup.call(this)
|
||||
expect(@view.hideModal).not.toHaveBeenCalled()
|
||||
@view.hideModal(clickEvent(".close-button"))
|
||||
expect(@view.hideModal).toHaveBeenCalled()
|
||||
|
||||
it "should show a status indicator while loading", ->
|
||||
appendSetFixtures('<div class="ui-loading"/>')
|
||||
expect($('.ui-loading').is(':visible')).toBe(true)
|
||||
|
||||
129
cms/static/js/spec/views/assets_spec.js
Normal file
129
cms/static/js/spec/views/assets_spec.js
Normal file
@@ -0,0 +1,129 @@
|
||||
define([ "jquery", "js/spec_helpers/create_sinon", "js/views/asset", "js/views/assets",
|
||||
"js/models/asset", "js/collections/asset" ],
|
||||
function ($, create_sinon, AssetView, AssetsView, AssetModel, AssetCollection) {
|
||||
|
||||
describe("Assets", function() {
|
||||
var assetsView, mockEmptyAssetsResponse, mockAssetUploadResponse,
|
||||
assetLibraryTpl, assetTpl, pagingFooterTpl, pagingHeaderTpl, uploadModalTpl;
|
||||
|
||||
assetLibraryTpl = readFixtures('asset-library.underscore');
|
||||
assetTpl = readFixtures('asset.underscore');
|
||||
pagingHeaderTpl = readFixtures('paging-header.underscore');
|
||||
pagingFooterTpl = readFixtures('paging-footer.underscore');
|
||||
uploadModalTpl = readFixtures('asset-upload-modal.underscore');
|
||||
|
||||
beforeEach(function () {
|
||||
setFixtures($("<script>", { id: "asset-library-tpl", type: "text/template" }).text(assetLibraryTpl));
|
||||
appendSetFixtures($("<script>", { id: "asset-tpl", type: "text/template" }).text(assetTpl));
|
||||
appendSetFixtures($("<script>", { id: "paging-header-tpl", type: "text/template" }).text(pagingHeaderTpl));
|
||||
appendSetFixtures($("<script>", { id: "paging-footer-tpl", type: "text/template" }).text(pagingFooterTpl));
|
||||
appendSetFixtures(uploadModalTpl);
|
||||
appendSetFixtures(sandbox({ id: "asset_table_body" }));
|
||||
|
||||
var collection = new AssetCollection();
|
||||
collection.url = "assets-url";
|
||||
assetsView = new AssetsView({
|
||||
collection: collection,
|
||||
el: $('#asset_table_body')
|
||||
});
|
||||
assetsView.render();
|
||||
});
|
||||
|
||||
var mockAsset = {
|
||||
display_name: "dummy.jpg",
|
||||
url: 'actual_asset_url',
|
||||
portable_url: 'portable_url',
|
||||
date_added: 'date',
|
||||
thumbnail: null,
|
||||
locked: false,
|
||||
id: 'id_1'
|
||||
};
|
||||
|
||||
mockEmptyAssetsResponse = {
|
||||
assets: [],
|
||||
start: 0,
|
||||
end: 0,
|
||||
page: 0,
|
||||
pageSize: 5,
|
||||
totalCount: 0
|
||||
};
|
||||
|
||||
mockAssetUploadResponse = {
|
||||
asset: mockAsset,
|
||||
msg: "Upload completed"
|
||||
};
|
||||
|
||||
$.fn.fileupload = function() {
|
||||
return '';
|
||||
};
|
||||
|
||||
var event = {}
|
||||
event.target = {"value": "dummy.jpg"};
|
||||
|
||||
describe("AssetsView", function () {
|
||||
var setup;
|
||||
setup = function() {
|
||||
var requests;
|
||||
requests = create_sinon.requests(this);
|
||||
assetsView.setPage(0);
|
||||
create_sinon.respondWithJson(requests, mockEmptyAssetsResponse);
|
||||
return requests;
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
window.analytics = jasmine.createSpyObj('analytics', ['track']);
|
||||
window.course_location_analytics = jasmine.createSpy();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
delete window.analytics;
|
||||
delete window.course_location_analytics;
|
||||
});
|
||||
|
||||
it('shows the upload modal when clicked on "Upload your first asset" button', function () {
|
||||
expect(assetsView).toBeDefined();
|
||||
appendSetFixtures('<div class="ui-loading"/>');
|
||||
expect($('.ui-loading').is(':visible')).toBe(true);
|
||||
expect($('.upload-button').is(':visible')).toBe(false);
|
||||
setup.call(this);
|
||||
expect($('.ui-loading').is(':visible')).toBe(false);
|
||||
expect($('.upload-button').is(':visible')).toBe(true);
|
||||
|
||||
expect($('.upload-modal').is(':visible')).toBe(false);
|
||||
$('a:contains("Upload your first asset")').click();
|
||||
expect($('.upload-modal').is(':visible')).toBe(true);
|
||||
|
||||
$('.close-button').click();
|
||||
expect($('.upload-modal').is(':visible')).toBe(false);
|
||||
});
|
||||
|
||||
it('uploads file properly', function () {
|
||||
var requests = setup.call(this);
|
||||
expect(assetsView).toBeDefined();
|
||||
spyOn(assetsView, "addAsset").andCallFake(function () {
|
||||
assetsView.collection.add(mockAssetUploadResponse.asset);
|
||||
assetsView.renderPageItems();
|
||||
assetsView.setPage(0);
|
||||
});
|
||||
|
||||
$('a:contains("Upload your first asset")').click();
|
||||
expect($('.upload-modal').is(':visible')).toBe(true);
|
||||
|
||||
$('.choose-file-button').click();
|
||||
$("input[type=file]").change();
|
||||
expect($('.upload-modal h1').text()).toContain("Uploading");
|
||||
|
||||
assetsView.showUploadFeedback(event, 100);
|
||||
expect($('div.progress-bar').text()).toContain("100%");
|
||||
|
||||
assetsView.displayFinishedUpload(mockAssetUploadResponse);
|
||||
expect($('div.progress-bar').text()).toContain("Upload completed");
|
||||
$('.close-button').click();
|
||||
expect($('.upload-modal').is(':visible')).toBe(false);
|
||||
|
||||
expect($('#asset_table_body').html()).toContain("dummy.jpg");
|
||||
expect(assetsView.collection.length).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,11 +1,13 @@
|
||||
define(["jquery", "underscore", "gettext", "js/views/paging", "js/views/asset", "js/views/paging_header", "js/views/paging_footer"],
|
||||
function($, _, gettext, PagingView, AssetView, PagingHeader, PagingFooter) {
|
||||
define(["jquery", "underscore", "gettext", "js/models/asset", "js/views/paging", "js/views/asset",
|
||||
"js/views/paging_header", "js/views/paging_footer", "js/utils/modal"],
|
||||
function($, _, gettext, AssetModel, PagingView, AssetView, PagingHeader, PagingFooter, ModalUtils) {
|
||||
|
||||
var AssetsView = PagingView.extend({
|
||||
// takes AssetCollection as model
|
||||
|
||||
events : {
|
||||
"click .column-sort-link": "onToggleColumn"
|
||||
"click .column-sort-link": "onToggleColumn",
|
||||
"click .upload-button": "showUploadModal"
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
@@ -17,6 +19,8 @@ define(["jquery", "underscore", "gettext", "js/views/paging", "js/views/asset",
|
||||
this.registerSortableColumn('js-asset-date-col', gettext('Date Added'), 'date_added', 'desc');
|
||||
this.setInitialSortColumn('js-asset-date-col');
|
||||
this.showLoadingIndicator();
|
||||
this.setPage(0);
|
||||
assetsView = this;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
@@ -24,6 +28,14 @@ define(["jquery", "underscore", "gettext", "js/views/paging", "js/views/asset",
|
||||
return this;
|
||||
},
|
||||
|
||||
afterRender: function(){
|
||||
// Bind events with html elements
|
||||
$('li a.upload-button').on('click', this.showUploadModal);
|
||||
$('.upload-modal .close-button').on('click', this.hideModal);
|
||||
$('.upload-modal .choose-file-button').on('click', this.showFileSelectionMenu);
|
||||
return this;
|
||||
},
|
||||
|
||||
getTableBody: function() {
|
||||
var tableBody = this.tableBody;
|
||||
if (!tableBody) {
|
||||
@@ -47,9 +59,9 @@ define(["jquery", "underscore", "gettext", "js/views/paging", "js/views/asset",
|
||||
|
||||
renderPageItems: function() {
|
||||
var self = this,
|
||||
assets = this.collection,
|
||||
hasAssets = assets.length > 0,
|
||||
tableBody = this.getTableBody();
|
||||
assets = this.collection,
|
||||
hasAssets = assets.length > 0,
|
||||
tableBody = this.getTableBody();
|
||||
tableBody.empty();
|
||||
if (hasAssets) {
|
||||
assets.each(
|
||||
@@ -91,6 +103,92 @@ define(["jquery", "underscore", "gettext", "js/views/paging", "js/views/asset",
|
||||
onToggleColumn: function(event) {
|
||||
var columnName = event.target.id;
|
||||
this.toggleSortOrder(columnName);
|
||||
},
|
||||
|
||||
hideModal: function (event) {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
$('.file-input').unbind('change.startUpload');
|
||||
ModalUtils.hideModal();
|
||||
},
|
||||
|
||||
showUploadModal: function (event) {
|
||||
var self = assetsView;
|
||||
event.preventDefault();
|
||||
self.resetUploadModal();
|
||||
ModalUtils.showModal();
|
||||
$('.file-input').bind('change', self.startUpload);
|
||||
$('.upload-modal .file-chooser').fileupload({
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
maxChunkSize: 100 * 1000 * 1000, // 100 MB
|
||||
autoUpload: true,
|
||||
progressall: function(event, data) {
|
||||
var percentComplete = parseInt((100 * data.loaded) / data.total, 10);
|
||||
self.showUploadFeedback(event, percentComplete);
|
||||
},
|
||||
maxFileSize: 100 * 1000 * 1000, // 100 MB
|
||||
maxNumberofFiles: 100,
|
||||
add: function(event, data) {
|
||||
data.process().done(function () {
|
||||
data.submit();
|
||||
});
|
||||
},
|
||||
done: function(event, data) {
|
||||
self.displayFinishedUpload(data.result);
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
showFileSelectionMenu: function(event) {
|
||||
event.preventDefault();
|
||||
$('.file-input').click();
|
||||
},
|
||||
|
||||
startUpload: function (event) {
|
||||
var file = event.target.value;
|
||||
|
||||
$('.upload-modal h1').text(gettext('Uploading…'));
|
||||
$('.upload-modal .file-name').html(file.substring(file.lastIndexOf("\\") + 1));
|
||||
$('.upload-modal .choose-file-button').hide();
|
||||
$('.upload-modal .progress-bar').removeClass('loaded').show();
|
||||
},
|
||||
|
||||
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);
|
||||
$('.upload-modal .progress-bar').hide();
|
||||
|
||||
$('.upload-modal .file-name').show();
|
||||
$('.upload-modal .file-name').html('');
|
||||
$('.upload-modal .choose-file-button').text(gettext('Choose File'));
|
||||
$('.upload-modal .embeddable-xml-input').val('');
|
||||
$('.upload-modal .embeddable').hide();
|
||||
},
|
||||
|
||||
showUploadFeedback: function (event, percentComplete) {
|
||||
var percentVal = percentComplete + '%';
|
||||
$('.upload-modal .progress-fill').width(percentVal);
|
||||
$('.upload-modal .progress-fill').html(percentVal);
|
||||
},
|
||||
|
||||
displayFinishedUpload: function (resp) {
|
||||
var asset = resp.asset;
|
||||
|
||||
$('.upload-modal h1').text(gettext('Upload New File'));
|
||||
$('.upload-modal .embeddable-xml-input').val(asset.portable_url);
|
||||
$('.upload-modal .embeddable').show();
|
||||
$('.upload-modal .file-name').hide();
|
||||
$('.upload-modal .progress-fill').html(resp.msg);
|
||||
$('.upload-modal .choose-file-button').text(gettext('Load Another File')).show();
|
||||
$('.upload-modal .progress-fill').width('100%');
|
||||
|
||||
assetsView.addAsset(new AssetModel(asset));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -19,112 +19,16 @@
|
||||
|
||||
<%block name="jsextra">
|
||||
<script type="text/javascript">
|
||||
require(["domReady", "jquery", "js/models/asset", "js/collections/asset",
|
||||
"js/views/assets", "js/views/feedback_prompt",
|
||||
"js/views/feedback_notification", "js/views/paging_header", "js/views/paging_footer",
|
||||
"js/utils/modal", "jquery.fileupload"],
|
||||
function(domReady, $, AssetModel, AssetCollection, AssetsView, PromptView, NotificationView,
|
||||
PagingHeader, PagingFooter, ModalUtils) {
|
||||
var assets = new AssetCollection();
|
||||
require(["jquery", "js/collections/asset", "js/views/assets", "jquery.fileupload"],
|
||||
function($, AssetCollection, AssetsView) {
|
||||
|
||||
assets.url = "${asset_callback_url}";
|
||||
var assetsView = new AssetsView({collection: assets, el: $('.assets-wrapper')});
|
||||
assetsView.render();
|
||||
assetsView.setPage(0);
|
||||
var assets = new AssetCollection();
|
||||
assets.url = "${asset_callback_url}";
|
||||
var assetsView = new AssetsView({collection: assets, el: $('.assets-wrapper')});
|
||||
assetsView.render();
|
||||
|
||||
var hideModal = function (e) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
$('.file-input').unbind('change.startUpload');
|
||||
ModalUtils.hideModal();
|
||||
};
|
||||
|
||||
var showUploadModal = function (e) {
|
||||
e.preventDefault();
|
||||
resetUploadModal();
|
||||
ModalUtils.showModal();
|
||||
$('.file-input').bind('change', startUpload);
|
||||
$('.upload-modal .file-chooser').fileupload({
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
maxChunkSize: 100 * 1000 * 1000, // 100 MB
|
||||
autoUpload: true,
|
||||
progressall: function(e, data) {
|
||||
var percentComplete = parseInt((100 * data.loaded) / data.total, 10);
|
||||
showUploadFeedback(e, percentComplete);
|
||||
},
|
||||
maxFileSize: 100 * 1000 * 1000, // 100 MB
|
||||
maxNumberofFiles: 100,
|
||||
add: function(e, data) {
|
||||
data.process().done(function () {
|
||||
data.submit();
|
||||
});
|
||||
},
|
||||
done: function(e, data) {
|
||||
displayFinishedUpload(data.result);
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
var showFileSelectionMenu = function(e) {
|
||||
e.preventDefault();
|
||||
$('.file-input').click();
|
||||
};
|
||||
|
||||
var startUpload = function (e) {
|
||||
var file = e.target.value;
|
||||
|
||||
$('.upload-modal h1').text("${_(u'Uploading…')}");
|
||||
$('.upload-modal .file-name').html(file.substring(file.lastIndexOf("\\") + 1));
|
||||
$('.upload-modal .choose-file-button').hide();
|
||||
$('.upload-modal .progress-bar').removeClass('loaded').show();
|
||||
};
|
||||
|
||||
var 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);
|
||||
$('.upload-modal .progress-bar').hide();
|
||||
|
||||
$('.upload-modal .file-name').show();
|
||||
$('.upload-modal .file-name').html('');
|
||||
$('.upload-modal .choose-file-button').text("${_('Choose File')}");
|
||||
$('.upload-modal .embeddable-xml-input').val('');
|
||||
$('.upload-modal .embeddable').hide();
|
||||
};
|
||||
|
||||
var showUploadFeedback = function (event, percentComplete) {
|
||||
var percentVal = percentComplete + '%';
|
||||
$('.upload-modal .progress-fill').width(percentVal);
|
||||
$('.upload-modal .progress-fill').html(percentVal);
|
||||
};
|
||||
|
||||
var displayFinishedUpload = function (resp) {
|
||||
var asset = resp.asset;
|
||||
|
||||
$('.upload-modal h1').text("${_('Upload New File')}");
|
||||
$('.upload-modal .embeddable-xml-input').val(asset.portable_url);
|
||||
$('.upload-modal .embeddable').show();
|
||||
$('.upload-modal .file-name').hide();
|
||||
$('.upload-modal .progress-fill').html(resp.msg);
|
||||
$('.upload-modal .choose-file-button').text("${_('Load Another File')}").show();
|
||||
$('.upload-modal .progress-fill').width('100%');
|
||||
|
||||
assetsView.addAsset(new AssetModel(asset));
|
||||
};
|
||||
|
||||
domReady(function() {
|
||||
$('.uploads .upload-button').bind('click', showUploadModal);
|
||||
$('.upload-modal .close-button').bind('click', hideModal);
|
||||
$('.upload-modal .choose-file-button').bind('click', showFileSelectionMenu);
|
||||
});
|
||||
|
||||
}); // end of require()
|
||||
</script>
|
||||
}); // end of require()
|
||||
</script>
|
||||
</%block>
|
||||
|
||||
<%block name="content">
|
||||
|
||||
19
cms/templates/js/asset-upload-modal.underscore
Normal file
19
cms/templates/js/asset-upload-modal.underscore
Normal file
@@ -0,0 +1,19 @@
|
||||
<div class="upload-modal modal" style="display: none;">
|
||||
<a href="#" class="close-button"><i class="icon-remove-sign"></i> <span class="sr"><%= gettext('close') %></span></a>
|
||||
<div class="modal-body">
|
||||
<h1 class="title"><%= gettext("Upload New File") %></h1>
|
||||
<p class="file-name">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill"></div>
|
||||
</div>
|
||||
<div class="embeddable">
|
||||
<label>URL:</label>
|
||||
<input type="text" class="embeddable-xml-input" value='' readonly>
|
||||
</div>
|
||||
<form class="file-chooser" action="asset-url"
|
||||
method="post" enctype="multipart/form-data">
|
||||
<a href="#" class="choose-file-button"><%= gettext("Choose File") %></a>
|
||||
<input type="file" class="file-input" name="file">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user