Merge pull request #5731 from Stanford-Online/ataki/upstream
Limit Upload File Sizes to GridFS
This commit is contained in:
@@ -15,6 +15,8 @@ requirejs.config({
|
||||
"jquery.cookie": "xmodule_js/common_static/js/vendor/jquery.cookie",
|
||||
"jquery.qtip": "xmodule_js/common_static/js/vendor/jquery.qtip.min",
|
||||
"jquery.fileupload": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload",
|
||||
"jquery.fileupload-process": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-process",
|
||||
"jquery.fileupload-validate": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate",
|
||||
"jquery.iframe-transport": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport",
|
||||
"jquery.inputnumber": "xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill",
|
||||
"jquery.immediateDescendents": "xmodule_js/common_static/coffee/src/jquery.immediateDescendents",
|
||||
@@ -94,9 +96,15 @@ requirejs.config({
|
||||
exports: "jQuery.fn.qtip"
|
||||
},
|
||||
"jquery.fileupload": {
|
||||
deps: ["jquery.iframe-transport"],
|
||||
deps: ["jquery.ui", "jquery.iframe-transport"],
|
||||
exports: "jQuery.fn.fileupload"
|
||||
},
|
||||
"jquery.fileupload-process": {
|
||||
deps: ["jquery.fileupload"]
|
||||
},
|
||||
"jquery.fileupload-validate": {
|
||||
deps: ["jquery.fileupload"]
|
||||
},
|
||||
"jquery.inputnumber": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.inputNumber"
|
||||
|
||||
@@ -14,6 +14,8 @@ requirejs.config({
|
||||
"jquery.cookie": "xmodule_js/common_static/js/vendor/jquery.cookie",
|
||||
"jquery.qtip": "xmodule_js/common_static/js/vendor/jquery.qtip.min",
|
||||
"jquery.fileupload": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload",
|
||||
"jquery.fileupload-process": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-process",
|
||||
"jquery.fileupload-validate": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate",
|
||||
"jquery.iframe-transport": "xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport",
|
||||
"jquery.inputnumber": "xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill",
|
||||
"jquery.immediateDescendents": "xmodule_js/common_static/coffee/src/jquery.immediateDescendents",
|
||||
@@ -84,9 +86,15 @@ requirejs.config({
|
||||
exports: "jQuery.fn.qtip"
|
||||
},
|
||||
"jquery.fileupload": {
|
||||
deps: ["jquery.iframe-transport"],
|
||||
deps: ["jquery.ui", "jquery.iframe-transport"],
|
||||
exports: "jQuery.fn.fileupload"
|
||||
},
|
||||
"jquery.fileupload-process": {
|
||||
deps: ["jquery.fileupload"]
|
||||
},
|
||||
"jquery.fileupload-validate": {
|
||||
deps: ["jquery.fileupload"]
|
||||
},
|
||||
"jquery.inputnumber": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.inputNumber"
|
||||
|
||||
@@ -48,9 +48,12 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
|
||||
@collection = new AssetCollection([@model])
|
||||
@collection.url = "assets-url"
|
||||
@view = new AssetView({model: @model})
|
||||
@createAssetView = (test) =>
|
||||
view = new AssetView({model: @model})
|
||||
requests = if test then AjaxHelpers["requests"](test) else null
|
||||
return {view: view, requests: requests}
|
||||
|
||||
waitsFor (=> @view), "AssetView was not created", 1000
|
||||
waitsFor (=> @createAssetView), "AssetsView Creation function was not initialized", 1000
|
||||
|
||||
afterEach ->
|
||||
@injector.clean()
|
||||
@@ -58,10 +61,12 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
|
||||
describe "Basic", ->
|
||||
it "should render properly", ->
|
||||
{view: @view, requests: requests} = @createAssetView()
|
||||
@view.render()
|
||||
expect(@view.$el).toContainText("test asset")
|
||||
|
||||
it "should pop a delete confirmation when the delete button is clicked", ->
|
||||
{view: @view, requests: requests} = @createAssetView()
|
||||
@view.render().$(".remove-asset-button").click()
|
||||
expect(@promptSpies.constructor).toHaveBeenCalled()
|
||||
ctorOptions = @promptSpies.constructor.mostRecentCall.args[0]
|
||||
@@ -72,7 +77,7 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
|
||||
describe "AJAX", ->
|
||||
it "should destroy itself on confirmation", ->
|
||||
requests = AjaxHelpers["requests"](this)
|
||||
{view: @view, requests: requests} = @createAssetView(this)
|
||||
|
||||
@view.render().$(".remove-asset-button").click()
|
||||
ctorOptions = @promptSpies.constructor.mostRecentCall.args[0]
|
||||
@@ -92,7 +97,7 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
expect(@collection.contains(@model)).toBeFalsy()
|
||||
|
||||
it "should not destroy itself if server errors", ->
|
||||
requests = AjaxHelpers["requests"](this)
|
||||
{view: @view, requests: requests} = @createAssetView(this)
|
||||
|
||||
@view.render().$(".remove-asset-button").click()
|
||||
ctorOptions = @promptSpies.constructor.mostRecentCall.args[0]
|
||||
@@ -106,7 +111,7 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
expect(@collection.contains(@model)).toBeTruthy()
|
||||
|
||||
it "should lock the asset on confirmation", ->
|
||||
requests = AjaxHelpers["requests"](this)
|
||||
{view: @view, requests: requests} = @createAssetView(this)
|
||||
|
||||
@view.render().$(".lock-checkbox").click()
|
||||
# AJAX request has been sent, but not yet returned
|
||||
@@ -123,7 +128,7 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
expect(@model.get("locked")).toBeTruthy()
|
||||
|
||||
it "should not lock the asset if server errors", ->
|
||||
requests = AjaxHelpers["requests"](this)
|
||||
{view: @view, requests: requests} = @createAssetView(this)
|
||||
|
||||
@view.render().$(".lock-checkbox").click()
|
||||
# return an error response
|
||||
@@ -138,6 +143,7 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
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($("<script>", {id: "system-feedback-tpl", type: "text/template"}).text(feedbackTpl))
|
||||
window.analytics = jasmine.createSpyObj('analytics', ['track'])
|
||||
window.course_location_analytics = jasmine.createSpy()
|
||||
appendSetFixtures(sandbox({id: "asset_table_body"}))
|
||||
@@ -182,12 +188,16 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
@AssetModel = AssetModel
|
||||
@collection = new AssetCollection();
|
||||
@collection.url = "assets-url"
|
||||
@view = new AssetsView
|
||||
collection: @collection
|
||||
el: $('#asset_table_body')
|
||||
@view.render()
|
||||
@createAssetsView = (test) =>
|
||||
requests = AjaxHelpers.requests(test)
|
||||
view = new AssetsView
|
||||
collection: @collection
|
||||
el: $('#asset_table_body')
|
||||
view.render()
|
||||
return {view: view, requests: requests}
|
||||
|
||||
waitsFor (=> @view), "AssetsView was not created", 1000
|
||||
|
||||
waitsFor (=> @createAssetsView), "AssetsView Creation function was not initialized", 2000
|
||||
|
||||
$.ajax()
|
||||
|
||||
@@ -230,11 +240,9 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
|
||||
describe "Basic", ->
|
||||
# Separate setup method to work-around mis-parenting of beforeEach methods
|
||||
setup = ->
|
||||
requests = AjaxHelpers.requests(this)
|
||||
setup = (requests) ->
|
||||
@view.setPage(0)
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
return requests
|
||||
|
||||
$.fn.fileupload = ->
|
||||
return ''
|
||||
@@ -243,34 +251,38 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
$(html_selector).click()
|
||||
|
||||
it "should show upload modal on clicking upload asset button", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
spyOn(@view, "showUploadModal")
|
||||
setup.call(this)
|
||||
setup.call(this, requests)
|
||||
expect(@view.showUploadModal).not.toHaveBeenCalled()
|
||||
@view.showUploadModal(clickEvent(".upload-button"))
|
||||
expect(@view.showUploadModal).toHaveBeenCalled()
|
||||
|
||||
it "should show file selection menu on choose file button", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
spyOn(@view, "showFileSelectionMenu")
|
||||
setup.call(this)
|
||||
setup.call(this, requests)
|
||||
expect(@view.showFileSelectionMenu).not.toHaveBeenCalled()
|
||||
@view.showFileSelectionMenu(clickEvent(".choose-file-button"))
|
||||
expect(@view.showFileSelectionMenu).toHaveBeenCalled()
|
||||
|
||||
it "should hide upload modal on clicking close button", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
spyOn(@view, "hideModal")
|
||||
setup.call(this)
|
||||
setup.call(this, requests)
|
||||
expect(@view.hideModal).not.toHaveBeenCalled()
|
||||
@view.hideModal(clickEvent(".close-button"))
|
||||
expect(@view.hideModal).toHaveBeenCalled()
|
||||
|
||||
it "should show a status indicator while loading", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
appendSetFixtures('<div class="ui-loading"/>')
|
||||
expect($('.ui-loading').is(':visible')).toBe(true)
|
||||
setup.call(this)
|
||||
setup.call(this, requests)
|
||||
expect($('.ui-loading').is(':visible')).toBe(false)
|
||||
|
||||
it "should hide the status indicator if an error occurs while loading", ->
|
||||
requests = AjaxHelpers.requests(this)
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
appendSetFixtures('<div class="ui-loading"/>')
|
||||
expect($('.ui-loading').is(':visible')).toBe(true)
|
||||
@view.setPage(0)
|
||||
@@ -278,21 +290,24 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
expect($('.ui-loading').is(':visible')).toBe(false)
|
||||
|
||||
it "should render both assets", ->
|
||||
requests = setup.call(this)
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
expect(@view.$el).toContainText("test asset 1")
|
||||
expect(@view.$el).toContainText("test asset 2")
|
||||
|
||||
it "should remove the deleted asset from the view", ->
|
||||
requests = setup.call(this)
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
# Delete the 2nd asset with success from server.
|
||||
@view.$(".remove-asset-button")[1].click()
|
||||
@promptSpies.constructor.mostRecentCall.args[0].actions.primary.click(@promptSpies)
|
||||
req.respond(200) for req in requests
|
||||
req.respond(200) for req in requests.slice(1)
|
||||
expect(@view.$el).toContainText("test asset 1")
|
||||
expect(@view.$el).not.toContainText("test asset 2")
|
||||
|
||||
it "does not remove asset if deletion failed", ->
|
||||
requests = setup.call(this)
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
# Delete the 2nd asset, but mimic a failure from the server.
|
||||
@view.$(".remove-asset-button")[1].click()
|
||||
@promptSpies.constructor.mostRecentCall.args[0].actions.primary.click(@promptSpies)
|
||||
@@ -301,13 +316,15 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
expect(@view.$el).toContainText("test asset 2")
|
||||
|
||||
it "adds an asset if asset does not already exist", ->
|
||||
requests = setup.call(this)
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
addMockAsset.call(this, requests)
|
||||
expect(@view.$el).toContainText("new asset")
|
||||
expect(@collection.models.length).toBe(3)
|
||||
|
||||
it "does not add an asset if asset already exists", ->
|
||||
setup.call(this)
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
spyOn(@collection, "add").andCallThrough()
|
||||
model = @collection.models[1]
|
||||
@view.addAsset(model)
|
||||
@@ -315,19 +332,19 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
|
||||
describe "Sorting", ->
|
||||
# Separate setup method to work-around mis-parenting of beforeEach methods
|
||||
setup = ->
|
||||
requests = AjaxHelpers.requests(this)
|
||||
setup = (requests) ->
|
||||
@view.setPage(0)
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
return requests
|
||||
|
||||
it "should have the correct default sort order", ->
|
||||
requests = setup.call(this)
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
expect(@view.sortDisplayName()).toBe("Date Added")
|
||||
expect(@view.collection.sortDirection).toBe("desc")
|
||||
|
||||
it "should toggle the sort order when clicking on the currently sorted column", ->
|
||||
requests = setup.call(this)
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
expect(@view.sortDisplayName()).toBe("Date Added")
|
||||
expect(@view.collection.sortDirection).toBe("desc")
|
||||
@view.$("#js-asset-date-col").click()
|
||||
@@ -340,7 +357,8 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
expect(@view.collection.sortDirection).toBe("desc")
|
||||
|
||||
it "should switch the sort order when clicking on a different column", ->
|
||||
requests = setup.call(this)
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
@view.$("#js-asset-name-col").click()
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
expect(@view.sortDisplayName()).toBe("Name")
|
||||
@@ -351,7 +369,8 @@ define ["jquery", "jasmine", "js/common_helpers/ajax_helpers", "squire"],
|
||||
expect(@view.collection.sortDirection).toBe("desc")
|
||||
|
||||
it "should switch sort to most recent date added when a new asset is added", ->
|
||||
requests = setup.call(this)
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
@view.$("#js-asset-name-col").click()
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
addMockAsset.call(this, requests)
|
||||
|
||||
@@ -2,12 +2,18 @@ define([
|
||||
'jquery', 'js/collections/asset', 'js/views/assets', 'jquery.fileupload'
|
||||
], function($, AssetCollection, AssetsView) {
|
||||
'use strict';
|
||||
return function (assetCallbackUrl) {
|
||||
return function (config) {
|
||||
var assets = new AssetCollection(),
|
||||
assetsView;
|
||||
|
||||
assets.url = assetCallbackUrl;
|
||||
assetsView = new AssetsView({collection: assets, el: $('.assets-wrapper')});
|
||||
assets.url = config.assetCallbackUrl;
|
||||
assetsView = new AssetsView({
|
||||
collection: assets,
|
||||
el: $('.assets-wrapper'),
|
||||
uploadChunkSizeInMBs: config.uploadChunkSizeInMBs,
|
||||
maxFileSizeInMBs: config.maxFileSizeInMBs,
|
||||
maxFileSizeRedirectUrl: config.maxFileSizeRedirectUrl
|
||||
});
|
||||
assetsView.render();
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
define([ "jquery", "js/common_helpers/ajax_helpers", "js/views/asset", "js/views/assets",
|
||||
"js/models/asset", "js/collections/asset", "js/spec_helpers/view_helpers" ],
|
||||
"js/models/asset", "js/collections/asset", "js/spec_helpers/view_helpers"],
|
||||
function ($, AjaxHelpers, AssetView, AssetsView, AssetModel, AssetCollection, ViewHelpers) {
|
||||
|
||||
describe("Assets", function() {
|
||||
var assetsView, mockEmptyAssetsResponse, mockAssetUploadResponse,
|
||||
var assetsView, mockEmptyAssetsResponse, mockAssetUploadResponse, mockFileUpload,
|
||||
assetLibraryTpl, assetTpl, pagingFooterTpl, pagingHeaderTpl, uploadModalTpl;
|
||||
|
||||
assetLibraryTpl = readFixtures('asset-library.underscore');
|
||||
@@ -53,6 +53,10 @@ define([ "jquery", "js/common_helpers/ajax_helpers", "js/views/asset", "js/views
|
||||
msg: "Upload completed"
|
||||
};
|
||||
|
||||
mockFileUpload = {
|
||||
files: [{name: 'largefile', size: 0}]
|
||||
};
|
||||
|
||||
$.fn.fileupload = function() {
|
||||
return '';
|
||||
};
|
||||
@@ -95,6 +99,15 @@ define([ "jquery", "js/common_helpers/ajax_helpers", "js/views/asset", "js/views
|
||||
expect($('.upload-modal').is(':visible')).toBe(false);
|
||||
});
|
||||
|
||||
it('has properly initialized constants for handling upload file errors', function() {
|
||||
expect(assetsView).toBeDefined();
|
||||
expect(assetsView.uploadChunkSizeInMBs).toBeDefined();
|
||||
expect(assetsView.maxFileSizeInMBs).toBeDefined();
|
||||
expect(assetsView.uploadChunkSizeInBytes).toBeDefined();
|
||||
expect(assetsView.maxFileSizeInBytes).toBeDefined();
|
||||
expect(assetsView.largeFileErrorMsg).toBeNull();
|
||||
});
|
||||
|
||||
it('uploads file properly', function () {
|
||||
var requests = setup.call(this);
|
||||
expect(assetsView).toBeDefined();
|
||||
@@ -122,6 +135,42 @@ define([ "jquery", "js/common_helpers/ajax_helpers", "js/views/asset", "js/views
|
||||
expect($('#asset_table_body').html()).toContain("dummy.jpg");
|
||||
expect(assetsView.collection.length).toBe(1);
|
||||
});
|
||||
|
||||
it('blocks file uploads larger than the max file size', function() {
|
||||
expect(assetsView).toBeDefined();
|
||||
|
||||
mockFileUpload.files[0].size = assetsView.maxFileSize * 10;
|
||||
|
||||
$('.choose-file-button').click();
|
||||
$(".upload-modal .file-chooser").fileupload('add', mockFileUpload);
|
||||
expect($('.upload-modal h1').text()).not.toContain("Uploading");
|
||||
|
||||
expect(assetsView.largeFileErrorMsg).toBeDefined();
|
||||
expect($('div.progress-bar').text()).not.toContain("Upload completed");
|
||||
expect($('div.progress-fill').width()).toBe(0);
|
||||
});
|
||||
|
||||
it('allows file uploads equal in size to the max file size', function() {
|
||||
expect(assetsView).toBeDefined();
|
||||
|
||||
mockFileUpload.files[0].size = assetsView.maxFileSize;
|
||||
|
||||
$('.choose-file-button').click();
|
||||
$(".upload-modal .file-chooser").fileupload('add', mockFileUpload);
|
||||
|
||||
expect(assetsView.largeFileErrorMsg).toBeNull();
|
||||
});
|
||||
|
||||
it('allows file uploads smaller than the max file size', function() {
|
||||
expect(assetsView).toBeDefined();
|
||||
|
||||
mockFileUpload.files[0].size = assetsView.maxFileSize / 100;
|
||||
|
||||
$('.choose-file-button').click();
|
||||
$(".upload-modal .file-chooser").fileupload('add', mockFileUpload);
|
||||
|
||||
expect(assetsView.largeFileErrorMsg).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
define(["jquery", "underscore", "gettext", "js/models/asset", "js/views/paging", "js/views/asset",
|
||||
"js/views/paging_header", "js/views/paging_footer", "js/utils/modal", "js/views/utils/view_utils"],
|
||||
function($, _, gettext, AssetModel, PagingView, AssetView, PagingHeader, PagingFooter, ModalUtils, ViewUtils) {
|
||||
"js/views/paging_header", "js/views/paging_footer", "js/utils/modal", "js/views/utils/view_utils",
|
||||
"js/views/feedback_notification", "jquery.fileupload-process", "jquery.fileupload-validate"],
|
||||
function($, _, gettext, AssetModel, PagingView, AssetView, PagingHeader, PagingFooter, ModalUtils, ViewUtils, NotificationView) {
|
||||
|
||||
var CONVERSION_FACTOR_MBS_TO_BYTES = 1000 * 1000;
|
||||
|
||||
var AssetsView = PagingView.extend({
|
||||
// takes AssetCollection as model
|
||||
@@ -10,7 +13,9 @@ define(["jquery", "underscore", "gettext", "js/models/asset", "js/views/paging",
|
||||
"click .upload-button": "showUploadModal"
|
||||
},
|
||||
|
||||
initialize : function() {
|
||||
initialize : function(options) {
|
||||
options = options || {};
|
||||
|
||||
PagingView.prototype.initialize.call(this);
|
||||
var collection = this.collection;
|
||||
this.template = this.loadTemplate("asset-library");
|
||||
@@ -20,7 +25,16 @@ define(["jquery", "underscore", "gettext", "js/models/asset", "js/views/paging",
|
||||
this.setInitialSortColumn('js-asset-date-col');
|
||||
ViewUtils.showLoadingIndicator();
|
||||
this.setPage(0);
|
||||
// set default file size for uploads via template var,
|
||||
// and default to static old value if none exists
|
||||
this.uploadChunkSizeInMBs = options.uploadChunkSizeInMBs || 10;
|
||||
this.maxFileSizeInMBs = options.maxFileSizeInMBs || 10;
|
||||
this.uploadChunkSizeInBytes = this.uploadChunkSizeInMBs * CONVERSION_FACTOR_MBS_TO_BYTES;
|
||||
this.maxFileSizeInBytes = this.maxFileSizeInMBs * CONVERSION_FACTOR_MBS_TO_BYTES;
|
||||
this.maxFileSizeRedirectUrl = options.maxFileSizeRedirectUrl || '';
|
||||
assetsView = this;
|
||||
// error message modal for large file uploads
|
||||
this.largeFileErrorMsg = null;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
@@ -111,6 +125,9 @@ define(["jquery", "underscore", "gettext", "js/models/asset", "js/views/paging",
|
||||
}
|
||||
$('.file-input').unbind('change.startUpload');
|
||||
ModalUtils.hideModal();
|
||||
if (assetsView.largeFileErrorMsg) {
|
||||
assetsView.largeFileErrorMsg.hide();
|
||||
}
|
||||
},
|
||||
|
||||
showUploadModal: function (event) {
|
||||
@@ -122,23 +139,44 @@ define(["jquery", "underscore", "gettext", "js/models/asset", "js/views/paging",
|
||||
$('.upload-modal .file-chooser').fileupload({
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
maxChunkSize: 100 * 1000 * 1000, // 100 MB
|
||||
maxChunkSize: self.uploadChunkSizeInBytes,
|
||||
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
|
||||
maxFileSize: self.maxFileSizeInBytes,
|
||||
maxNumberofFiles: 100,
|
||||
add: function(event, data) {
|
||||
data.process().done(function () {
|
||||
data.submit();
|
||||
});
|
||||
},
|
||||
done: function(event, data) {
|
||||
self.displayFinishedUpload(data.result);
|
||||
}
|
||||
},
|
||||
processfail: function(event, data) {
|
||||
var filename = data.files[data.index].name;
|
||||
var error = gettext("File {filename} exceeds maximum size of {maxFileSizeInMBs} MB")
|
||||
.replace("{filename}", filename)
|
||||
.replace("{maxFileSizeInMBs}", self.maxFileSizeInMBs)
|
||||
|
||||
// disable second part of message for any falsy value,
|
||||
// which can be null or an empty string
|
||||
if(self.maxFileSizeRedirectUrl) {
|
||||
var instructions = gettext("Please follow the instructions here to upload a file elsewhere and link to it: {maxFileSizeRedirectUrl}")
|
||||
.replace("{maxFileSizeRedirectUrl}", self.maxFileSizeRedirectUrl);
|
||||
error = error + " " + instructions;
|
||||
}
|
||||
|
||||
assetsView.largeFileErrorMsg = new NotificationView.Error({
|
||||
"title": gettext("Your file could not be uploaded"),
|
||||
"message": error
|
||||
});
|
||||
assetsView.largeFileErrorMsg.show();
|
||||
|
||||
assetsView.displayFailedUpload({
|
||||
"msg": gettext("Max file size exceeded")
|
||||
});
|
||||
},
|
||||
processdone: function(event, data) {
|
||||
assetsView.largeFileErrorMsg = null;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -149,11 +187,12 @@ define(["jquery", "underscore", "gettext", "js/models/asset", "js/views/paging",
|
||||
|
||||
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();
|
||||
if (!assetsView.largeFileErrorMsg) {
|
||||
$('.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 () {
|
||||
@@ -169,6 +208,8 @@ define(["jquery", "underscore", "gettext", "js/models/asset", "js/views/paging",
|
||||
$('.upload-modal .choose-file-button').text(gettext('Choose File'));
|
||||
$('.upload-modal .embeddable-xml-input').val('');
|
||||
$('.upload-modal .embeddable').hide();
|
||||
|
||||
assetsView.largeFileErrorMsg = null;
|
||||
},
|
||||
|
||||
showUploadFeedback: function (event, percentComplete) {
|
||||
@@ -181,7 +222,7 @@ define(["jquery", "underscore", "gettext", "js/models/asset", "js/views/paging",
|
||||
var asset = resp.asset;
|
||||
|
||||
$('.upload-modal h1').text(gettext('Upload New File'));
|
||||
$('.upload-modal .embeddable-xml-input').val(asset.portable_url);
|
||||
$('.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);
|
||||
@@ -189,6 +230,16 @@ define(["jquery", "underscore", "gettext", "js/models/asset", "js/views/paging",
|
||||
$('.upload-modal .progress-fill').width('100%');
|
||||
|
||||
assetsView.addAsset(new AssetModel(asset));
|
||||
},
|
||||
|
||||
displayFailedUpload: function (resp) {
|
||||
$('.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);
|
||||
$('.upload-modal .choose-file-button').text(gettext('Load Another File')).show();
|
||||
$('.upload-modal .progress-fill').width('0%');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -62,6 +62,10 @@ lib_paths:
|
||||
- xmodule_js/common_static/coffee/src/jquery.immediateDescendents.js
|
||||
- xmodule_js/common_static/coffee/src/xblock/
|
||||
- xmodule_js/common_static/js/vendor/URI.min.js
|
||||
- xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport.js
|
||||
- xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload.js
|
||||
- xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-process.js
|
||||
- xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate.js
|
||||
|
||||
# Paths to source JavaScript files
|
||||
src_paths:
|
||||
|
||||
@@ -57,6 +57,10 @@ lib_paths:
|
||||
- xmodule_js/common_static/js/test/i18n.js
|
||||
- xmodule_js/common_static/coffee/src/xblock/
|
||||
- xmodule_js/common_static/js/vendor/URI.min.js
|
||||
- xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.iframe-transport.js
|
||||
- xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload.js
|
||||
- xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-process.js
|
||||
- xmodule_js/common_static/js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate.js
|
||||
|
||||
# Paths to source JavaScript files
|
||||
src_paths:
|
||||
|
||||
@@ -20,6 +20,8 @@ require.config({
|
||||
"jquery.scrollTo": "js/vendor/jquery.scrollTo-1.4.2-min",
|
||||
"jquery.flot": "js/vendor/flot/jquery.flot.min",
|
||||
"jquery.fileupload": "js/vendor/jQuery-File-Upload/js/jquery.fileupload",
|
||||
"jquery.fileupload-process": "js/vendor/jQuery-File-Upload/js/jquery.fileupload-process",
|
||||
"jquery.fileupload-validate": "js/vendor/jQuery-File-Upload/js/jquery.fileupload-validate",
|
||||
"jquery.iframe-transport": "js/vendor/jQuery-File-Upload/js/jquery.iframe-transport",
|
||||
"jquery.inputnumber": "js/vendor/html5-input-polyfills/number-polyfill",
|
||||
"jquery.immediateDescendents": "coffee/src/jquery.immediateDescendents",
|
||||
@@ -128,9 +130,15 @@ require.config({
|
||||
exports: "jQuery.fn.plot"
|
||||
},
|
||||
"jquery.fileupload": {
|
||||
deps: ["jquery.iframe-transport"],
|
||||
deps: ["jquery.ui", "jquery.iframe-transport"],
|
||||
exports: "jQuery.fn.fileupload"
|
||||
},
|
||||
"jquery.fileupload-process": {
|
||||
deps: ["jquery.fileupload"]
|
||||
},
|
||||
"jquery.fileupload-validate": {
|
||||
deps: ["jquery.fileupload"]
|
||||
},
|
||||
"jquery.inputnumber": {
|
||||
deps: ["jquery"],
|
||||
exports: "jQuery.fn.inputNumber"
|
||||
|
||||
Reference in New Issue
Block a user