Merge pull request #5731 from Stanford-Online/ataki/upstream

Limit Upload File Sizes to GridFS
This commit is contained in:
Sarina Canelake
2014-12-11 16:36:30 -05:00
14 changed files with 295 additions and 61 deletions

View File

@@ -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"

View File

@@ -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"

View File

@@ -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)

View File

@@ -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();
};
});

View File

@@ -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();
});
});
});
});

View File

@@ -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%');
}
});

View File

@@ -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:

View File

@@ -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:

View File

@@ -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"