Require and Webpack can eat the same files
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
'underscore.string',
|
||||
'backbone',
|
||||
'gettext',
|
||||
'../../../../common/static/common/js/components/views/feedback_notification',
|
||||
'../../common/js/components/views/feedback_notification',
|
||||
'jquery.cookie'
|
||||
], function(domReady, $, str, Backbone, gettext, NotificationView) {
|
||||
var main, sendJSON;
|
||||
|
||||
@@ -116,7 +116,7 @@ define([
|
||||
Import.reset();
|
||||
onComplete();
|
||||
|
||||
alert(gettext('Your import has failed.') + '\n\n' + errMsg);
|
||||
alert(gettext('Your import has failed.') + '\n\n' + errMsg); // eslint-disable-line max-len, no-alert
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,197 +1,202 @@
|
||||
define(['jquery',
|
||||
(function(define) {
|
||||
'use strict';
|
||||
define([
|
||||
'jquery',
|
||||
'underscore',
|
||||
'underscore.string',
|
||||
'backbone',
|
||||
'text!../../../../common/templates/components/system-feedback.underscore'],
|
||||
function($, _, str, Backbone, systemFeedbackTemplate) {
|
||||
var tabbable_elements = [
|
||||
"a[href]:not([tabindex='-1'])",
|
||||
"area[href]:not([tabindex='-1'])",
|
||||
"input:not([disabled]):not([tabindex='-1'])",
|
||||
"select:not([disabled]):not([tabindex='-1'])",
|
||||
"textarea:not([disabled]):not([tabindex='-1'])",
|
||||
"button:not([disabled]):not([tabindex='-1'])",
|
||||
"iframe:not([tabindex='-1'])",
|
||||
"[tabindex]:not([tabindex='-1'])",
|
||||
"[contentEditable=true]:not([tabindex='-1'])"
|
||||
];
|
||||
var SystemFeedback = Backbone.View.extend({
|
||||
options: {
|
||||
title: '',
|
||||
message: '',
|
||||
intent: null, // "warning", "confirmation", "error", "announcement", "step-required", etc
|
||||
type: null, // "alert", "notification", or "prompt": set by subclass
|
||||
shown: true, // is this view currently being shown?
|
||||
icon: true, // should we render an icon related to the message intent?
|
||||
closeIcon: true, // should we render a close button in the top right corner?
|
||||
minShown: 0, // length of time after this view has been shown before it can be hidden (milliseconds)
|
||||
maxShown: Infinity, // length of time after this view has been shown before it will be automatically hidden (milliseconds)
|
||||
outFocusElement: null // element to send focus to on hide
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'text!../../../../common/templates/components/system-feedback.underscore'
|
||||
],
|
||||
function($, _, str, Backbone, HtmlUtils, systemFeedbackTemplate) {
|
||||
var tabbableElements = [
|
||||
"a[href]:not([tabindex='-1'])",
|
||||
"area[href]:not([tabindex='-1'])",
|
||||
"input:not([disabled]):not([tabindex='-1'])",
|
||||
"select:not([disabled]):not([tabindex='-1'])",
|
||||
"textarea:not([disabled]):not([tabindex='-1'])",
|
||||
"button:not([disabled]):not([tabindex='-1'])",
|
||||
"iframe:not([tabindex='-1'])",
|
||||
"[tabindex]:not([tabindex='-1'])",
|
||||
"[contentEditable=true]:not([tabindex='-1'])"
|
||||
];
|
||||
var SystemFeedback = Backbone.View.extend({
|
||||
options: {
|
||||
title: '',
|
||||
message: '',
|
||||
intent: null, // "warning", "confirmation", "error", "announcement", "step-required", etc
|
||||
type: null, // "alert", "notification", or "prompt": set by subclass
|
||||
shown: true, // is this view currently being shown?
|
||||
icon: true, // should we render an icon related to the message intent?
|
||||
closeIcon: true, // should we render a close button in the top right corner?
|
||||
minShown: 0, // ms after this view has been shown before it can be hidden
|
||||
maxShown: Infinity, // ms after this view has been shown before it will be automatically hidden
|
||||
outFocusElement: null // element to send focus to on hide
|
||||
|
||||
/* Could also have an "actions" hash: here is an example demonstrating
|
||||
the expected structure. For each action, by default the framework
|
||||
will call preventDefault on the click event before the function is
|
||||
run; to make it not do that, just pass `preventDefault: false` in
|
||||
the action object.
|
||||
/* Could also have an "actions" hash: here is an example demonstrating
|
||||
the expected structure. For each action, by default the framework
|
||||
will call preventDefault on the click event before the function is
|
||||
run; to make it not do that, just pass `preventDefault: false` in
|
||||
the action object.
|
||||
|
||||
actions: {
|
||||
primary: {
|
||||
"text": "Save",
|
||||
"class": "action-save",
|
||||
"click": function(view) {
|
||||
// do something when Save is clicked
|
||||
actions: {
|
||||
primary: {
|
||||
"text": "Save",
|
||||
"class": "action-save",
|
||||
"click": function(view) {
|
||||
// do something when Save is clicked
|
||||
}
|
||||
},
|
||||
secondary: [
|
||||
{
|
||||
"text": "Cancel",
|
||||
"class": "action-cancel",
|
||||
"click": function(view) {}
|
||||
}, {
|
||||
"text": "Discard Changes",
|
||||
"class": "action-discard",
|
||||
"click": function(view) {}
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
this.options = _.extend({}, this.options, options);
|
||||
if (!this.options.type) {
|
||||
throw 'SystemFeedback: type required (given ' + // eslint-disable-line no-throw-literal
|
||||
JSON.stringify(this.options) + ')';
|
||||
}
|
||||
if (!this.options.intent) {
|
||||
throw 'SystemFeedback: intent required (given ' + // eslint-disable-line no-throw-literal
|
||||
JSON.stringify(this.options) + ')';
|
||||
}
|
||||
this.setElement($('#page-' + this.options.type));
|
||||
// handle single "secondary" action
|
||||
if (this.options.actions && this.options.actions.secondary &&
|
||||
!_.isArray(this.options.actions.secondary)) {
|
||||
this.options.actions.secondary = [this.options.actions.secondary];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
inFocus: function(wrapperElementSelector) {
|
||||
var wrapper = wrapperElementSelector || '.wrapper',
|
||||
tabbables;
|
||||
this.options.outFocusElement = this.options.outFocusElement || document.activeElement;
|
||||
|
||||
// Set focus to the container.
|
||||
this.$(wrapper).first().focus();
|
||||
|
||||
// Make tabs within the prompt loop rather than setting focus
|
||||
// back to the main content of the page.
|
||||
tabbables = this.$(tabbableElements.join());
|
||||
tabbables.on('keydown', function(event) {
|
||||
// On tab backward from the first tabbable item in the prompt
|
||||
if (event.which === 9 && event.shiftKey && event.target === tabbables.first()[0]) {
|
||||
event.preventDefault();
|
||||
tabbables.last().focus();
|
||||
} else if (event.which === 9 && !event.shiftKey && event.target === tabbables.last()[0]) {
|
||||
// On tab forward from the last tabbable item in the prompt
|
||||
event.preventDefault();
|
||||
tabbables.first().focus();
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
outFocus: function() {
|
||||
this.$(tabbableElements.join()).off('keydown');
|
||||
if (this.options.outFocusElement) {
|
||||
this.options.outFocusElement.focus();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// public API: show() and hide()
|
||||
show: function() {
|
||||
clearTimeout(this.hideTimeout);
|
||||
this.options.shown = true;
|
||||
this.shownAt = new Date();
|
||||
this.render();
|
||||
if ($.isNumeric(this.options.maxShown)) {
|
||||
this.hideTimeout = setTimeout(_.bind(this.hide, this),
|
||||
this.options.maxShown);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
if (this.shownAt && $.isNumeric(this.options.minShown) &&
|
||||
this.options.minShown > new Date() - this.shownAt) {
|
||||
clearTimeout(this.hideTimeout);
|
||||
this.hideTimeout = setTimeout(_.bind(this.hide, this),
|
||||
this.options.minShown - (new Date() - this.shownAt));
|
||||
} else {
|
||||
this.options.shown = false;
|
||||
delete this.shownAt;
|
||||
this.render();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// the rest of the API should be considered semi-private
|
||||
events: {
|
||||
'click .action-close': 'hide',
|
||||
'click .action-primary': 'primaryClick',
|
||||
'click .action-secondary': 'secondaryClick'
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// there can be only one active view of a given type at a time: only
|
||||
// one alert, only one notification, only one prompt. Therefore, we'll
|
||||
// use a singleton approach.
|
||||
var singleton = SystemFeedback['active_' + this.options.type];
|
||||
if (singleton && singleton !== this) {
|
||||
singleton.stopListening();
|
||||
singleton.undelegateEvents();
|
||||
}
|
||||
HtmlUtils.setHtml(this.$el, HtmlUtils.template(systemFeedbackTemplate)(this.options));
|
||||
SystemFeedback['active_' + this.options.type] = this;
|
||||
return this;
|
||||
},
|
||||
|
||||
primaryClick: function(event) {
|
||||
var actions, primary;
|
||||
actions = this.options.actions;
|
||||
if (!actions) { return; }
|
||||
primary = actions.primary;
|
||||
if (!primary) { return; }
|
||||
if (primary.preventDefault !== false) {
|
||||
event.preventDefault();
|
||||
}
|
||||
if (primary.click) {
|
||||
primary.click.call(event.target, this, event);
|
||||
}
|
||||
},
|
||||
secondary: [
|
||||
{
|
||||
"text": "Cancel",
|
||||
"class": "action-cancel",
|
||||
"click": function(view) {}
|
||||
}, {
|
||||
"text": "Discard Changes",
|
||||
"class": "action-discard",
|
||||
"click": function(view) {}
|
||||
|
||||
secondaryClick: function(event) {
|
||||
var actions, secondaryList, secondary, i;
|
||||
actions = this.options.actions;
|
||||
if (!actions) { return; }
|
||||
secondaryList = actions.secondary;
|
||||
if (!secondaryList) { return; }
|
||||
// which secondary action was clicked?
|
||||
i = 0; // default to the first secondary action (easier for testing)
|
||||
if (event && event.target) {
|
||||
i = _.indexOf(this.$('.action-secondary'), event.target);
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
this.options = _.extend({}, this.options, options);
|
||||
if (!this.options.type) {
|
||||
throw 'SystemFeedback: type required (given ' +
|
||||
JSON.stringify(this.options) + ')';
|
||||
}
|
||||
if (!this.options.intent) {
|
||||
throw 'SystemFeedback: intent required (given ' +
|
||||
JSON.stringify(this.options) + ')';
|
||||
}
|
||||
this.setElement($('#page-' + this.options.type));
|
||||
// handle single "secondary" action
|
||||
if (this.options.actions && this.options.actions.secondary &&
|
||||
!_.isArray(this.options.actions.secondary)) {
|
||||
this.options.actions.secondary = [this.options.actions.secondary];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
inFocus: function(wrapperElementSelector) {
|
||||
var wrapper = wrapperElementSelector || '.wrapper',
|
||||
tabbables;
|
||||
this.options.outFocusElement = this.options.outFocusElement || document.activeElement;
|
||||
|
||||
// Set focus to the container.
|
||||
this.$(wrapper).first().focus();
|
||||
|
||||
// Make tabs within the prompt loop rather than setting focus
|
||||
// back to the main content of the page.
|
||||
tabbables = this.$(tabbable_elements.join());
|
||||
tabbables.on('keydown', function(event) {
|
||||
// On tab backward from the first tabbable item in the prompt
|
||||
if (event.which === 9 && event.shiftKey && event.target === tabbables.first()[0]) {
|
||||
secondary = secondaryList[i];
|
||||
if (secondary.preventDefault !== false) {
|
||||
event.preventDefault();
|
||||
tabbables.last().focus();
|
||||
}
|
||||
// On tab forward from the last tabbable item in the prompt
|
||||
else if (event.which === 9 && !event.shiftKey && event.target === tabbables.last()[0]) {
|
||||
event.preventDefault();
|
||||
tabbables.first().focus();
|
||||
if (secondary.click) {
|
||||
secondary.click.call(event.target, this, event);
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
outFocus: function() {
|
||||
var tabbables = this.$(tabbable_elements.join()).off('keydown');
|
||||
if (this.options.outFocusElement) {
|
||||
this.options.outFocusElement.focus();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// public API: show() and hide()
|
||||
show: function() {
|
||||
clearTimeout(this.hideTimeout);
|
||||
this.options.shown = true;
|
||||
this.shownAt = new Date();
|
||||
this.render();
|
||||
if ($.isNumeric(this.options.maxShown)) {
|
||||
this.hideTimeout = setTimeout(_.bind(this.hide, this),
|
||||
this.options.maxShown);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
if (this.shownAt && $.isNumeric(this.options.minShown) &&
|
||||
this.options.minShown > new Date() - this.shownAt) {
|
||||
clearTimeout(this.hideTimeout);
|
||||
this.hideTimeout = setTimeout(_.bind(this.hide, this),
|
||||
this.options.minShown - (new Date() - this.shownAt));
|
||||
} else {
|
||||
this.options.shown = false;
|
||||
delete this.shownAt;
|
||||
this.render();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// the rest of the API should be considered semi-private
|
||||
events: {
|
||||
'click .action-close': 'hide',
|
||||
'click .action-primary': 'primaryClick',
|
||||
'click .action-secondary': 'secondaryClick'
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// there can be only one active view of a given type at a time: only
|
||||
// one alert, only one notification, only one prompt. Therefore, we'll
|
||||
// use a singleton approach.
|
||||
var singleton = SystemFeedback['active_' + this.options.type];
|
||||
if (singleton && singleton !== this) {
|
||||
singleton.stopListening();
|
||||
singleton.undelegateEvents();
|
||||
}
|
||||
this.$el.html(_.template(systemFeedbackTemplate)(this.options));
|
||||
SystemFeedback['active_' + this.options.type] = this;
|
||||
return this;
|
||||
},
|
||||
|
||||
primaryClick: function(event) {
|
||||
var actions, primary;
|
||||
actions = this.options.actions;
|
||||
if (!actions) { return; }
|
||||
primary = actions.primary;
|
||||
if (!primary) { return; }
|
||||
if (primary.preventDefault !== false) {
|
||||
event.preventDefault();
|
||||
}
|
||||
if (primary.click) {
|
||||
primary.click.call(event.target, this, event);
|
||||
}
|
||||
},
|
||||
|
||||
secondaryClick: function(event) {
|
||||
var actions, secondaryList, secondary, i;
|
||||
actions = this.options.actions;
|
||||
if (!actions) { return; }
|
||||
secondaryList = actions.secondary;
|
||||
if (!secondaryList) { return; }
|
||||
// which secondary action was clicked?
|
||||
i = 0; // default to the first secondary action (easier for testing)
|
||||
if (event && event.target) {
|
||||
i = _.indexOf(this.$('.action-secondary'), event.target);
|
||||
}
|
||||
secondary = secondaryList[i];
|
||||
if (secondary.preventDefault !== false) {
|
||||
event.preventDefault();
|
||||
}
|
||||
if (secondary.click) {
|
||||
secondary.click.call(event.target, this, event);
|
||||
}
|
||||
}
|
||||
});
|
||||
return SystemFeedback;
|
||||
});
|
||||
return SystemFeedback;
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
@@ -1,30 +1,34 @@
|
||||
define(['jquery', 'underscore', 'underscore.string', '../../../../common/js/components/views/feedback'],
|
||||
function($, _, str, SystemFeedbackView) {
|
||||
var Notification = SystemFeedbackView.extend({
|
||||
options: $.extend({}, SystemFeedbackView.prototype.options, {
|
||||
type: 'notification',
|
||||
closeIcon: false
|
||||
})
|
||||
});
|
||||
|
||||
// create Notification.Warning, Notification.Confirmation, etc
|
||||
var capitalCamel, intents;
|
||||
capitalCamel = _.compose(str.capitalize, str.camelize);
|
||||
intents = ['warning', 'error', 'confirmation', 'announcement', 'step-required', 'help', 'mini'];
|
||||
_.each(intents, function(intent) {
|
||||
var subclass;
|
||||
subclass = Notification.extend({
|
||||
options: $.extend({}, Notification.prototype.options, {
|
||||
intent: intent
|
||||
(function(define) {
|
||||
'use strict';
|
||||
define(['jquery', 'underscore', 'underscore.string', './feedback'],
|
||||
function($, _, str, SystemFeedbackView) {
|
||||
var Notification = SystemFeedbackView.extend({
|
||||
options: $.extend({}, SystemFeedbackView.prototype.options, {
|
||||
type: 'notification',
|
||||
closeIcon: false
|
||||
})
|
||||
});
|
||||
Notification[capitalCamel(intent)] = subclass;
|
||||
});
|
||||
|
||||
// set more sensible defaults for Notification.Mini views
|
||||
var miniOptions = Notification.Mini.prototype.options;
|
||||
miniOptions.minShown = 1250;
|
||||
miniOptions.closeIcon = false;
|
||||
// create Notification.Warning, Notification.Confirmation, etc
|
||||
var capitalCamel, intents, miniOptions;
|
||||
capitalCamel = _.compose(str.capitalize, str.camelize);
|
||||
intents = ['warning', 'error', 'confirmation', 'announcement', 'step-required', 'help', 'mini'];
|
||||
_.each(intents, function(intent) {
|
||||
var subclass;
|
||||
subclass = Notification.extend({
|
||||
options: $.extend({}, Notification.prototype.options, {
|
||||
intent: intent
|
||||
})
|
||||
});
|
||||
Notification[capitalCamel(intent)] = subclass;
|
||||
});
|
||||
|
||||
return Notification;
|
||||
});
|
||||
// set more sensible defaults for Notification.Mini views
|
||||
miniOptions = Notification.Mini.prototype.options;
|
||||
miniOptions.minShown = 1250;
|
||||
miniOptions.closeIcon = false;
|
||||
|
||||
return Notification;
|
||||
}
|
||||
);
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
@@ -253,17 +253,6 @@ class ImportMixin(ImportExportMixin):
|
||||
"""
|
||||
return self.q(css='.choose-file-button').present
|
||||
|
||||
def is_click_handler_registered(self):
|
||||
"""
|
||||
Check if the click handler for the file selector button has been registered yet
|
||||
"""
|
||||
script = """
|
||||
var $ = require('jquery'),
|
||||
buttonEvents = $._data($('a.choose-file-button')[0], 'events');
|
||||
return buttonEvents && buttonEvents.hasOwnProperty('click');"""
|
||||
stripped_script = ''.join([line.strip() for line in script.split('\n')])
|
||||
return self.browser.execute_script(stripped_script)
|
||||
|
||||
@staticmethod
|
||||
def file_path(filename):
|
||||
"""
|
||||
@@ -325,13 +314,6 @@ class ImportMixin(ImportExportMixin):
|
||||
"""
|
||||
return self.q(css='#fileupload .error-block').visible
|
||||
|
||||
def wait_for_choose_file_click_handler(self):
|
||||
"""
|
||||
Wait for the choose file button click handler to be registered
|
||||
"""
|
||||
EmptyPromise(self.is_click_handler_registered, 'Choose File Button Click Handler Registered',
|
||||
timeout=30).fulfill()
|
||||
|
||||
def wait_for_filename_error(self):
|
||||
"""
|
||||
Wait for the upload field to display an error.
|
||||
|
||||
@@ -168,7 +168,6 @@ class ImportTestMixin(object):
|
||||
I can select the file and upload it
|
||||
And the page will give me confirmation that it uploaded successfully
|
||||
"""
|
||||
self.import_page.wait_for_choose_file_click_handler()
|
||||
self.import_page.upload_tarball(self.tarball_name)
|
||||
self.import_page.wait_for_upload()
|
||||
|
||||
@@ -184,7 +183,6 @@ class ImportTestMixin(object):
|
||||
# import_page timestamp is in (MM/DD/YYYY at HH:mm) so replacing (second, microsecond) to
|
||||
# keep the comparison consistent
|
||||
upload_start_time = datetime.utcnow().replace(microsecond=0, second=0)
|
||||
self.import_page.wait_for_choose_file_click_handler()
|
||||
self.import_page.upload_tarball(self.tarball_name)
|
||||
self.import_page.wait_for_upload()
|
||||
|
||||
@@ -218,7 +216,6 @@ class ImportTestMixin(object):
|
||||
Given that I upload a library or course
|
||||
A button will appear that contains the URL to the library or course's main page
|
||||
"""
|
||||
self.import_page.wait_for_choose_file_click_handler()
|
||||
self.import_page.upload_tarball(self.tarball_name)
|
||||
self.assertEqual(self.import_page.finished_target_url(), self.landing_page.url)
|
||||
|
||||
@@ -228,7 +225,6 @@ class ImportTestMixin(object):
|
||||
Given that I select a file that is an .mp4 for upload
|
||||
An error message will appear
|
||||
"""
|
||||
self.import_page.wait_for_choose_file_click_handler()
|
||||
self.import_page.upload_tarball('funny_cat_video.mp4')
|
||||
self.import_page.wait_for_filename_error()
|
||||
|
||||
@@ -244,7 +240,6 @@ class ImportTestMixin(object):
|
||||
# The task list shouldn't be visible to start.
|
||||
self.assertFalse(self.import_page.is_task_list_showing(), "Task list shown too early.")
|
||||
self.import_page.wait_for_tasks()
|
||||
self.import_page.wait_for_choose_file_click_handler()
|
||||
self.import_page.upload_tarball(self.tarball_name)
|
||||
self.import_page.wait_for_tasks(completed=True)
|
||||
self.assertTrue(self.import_page.is_task_list_showing(), "Task list did not display.")
|
||||
@@ -258,7 +253,6 @@ class ImportTestMixin(object):
|
||||
And the 'Updating' task should be marked failed
|
||||
And the remaining tasks should not be marked as started
|
||||
"""
|
||||
self.import_page.wait_for_choose_file_click_handler()
|
||||
self.import_page.upload_tarball(self.bad_tarball_name)
|
||||
self.import_page.wait_for_tasks(fail_on='Updating')
|
||||
|
||||
@@ -296,7 +290,6 @@ class TestEntranceExamCourseImport(ImportTestMixin, StudioCourseTest):
|
||||
self.assertRaises(IndexError, self.landing_page.section, "Section")
|
||||
self.assertRaises(IndexError, self.landing_page.section, "Entrance Exam")
|
||||
self.import_page.visit()
|
||||
self.import_page.wait_for_choose_file_click_handler()
|
||||
self.import_page.upload_tarball(self.tarball_name)
|
||||
self.import_page.wait_for_upload()
|
||||
self.landing_page.visit()
|
||||
@@ -346,7 +339,6 @@ class TestCourseImport(ImportTestMixin, StudioCourseTest):
|
||||
# Should not exist yet.
|
||||
self.assertRaises(IndexError, self.landing_page.section, "Section")
|
||||
self.import_page.visit()
|
||||
self.import_page.wait_for_choose_file_click_handler()
|
||||
self.import_page.upload_tarball(self.tarball_name)
|
||||
self.import_page.wait_for_upload()
|
||||
self.landing_page.visit()
|
||||
@@ -373,7 +365,6 @@ class TestCourseImport(ImportTestMixin, StudioCourseTest):
|
||||
Then timestamp is not visible
|
||||
"""
|
||||
self.import_page.visit()
|
||||
self.import_page.wait_for_choose_file_click_handler()
|
||||
self.import_page.upload_tarball(self.tarball_name)
|
||||
self.import_page.wait_for_upload()
|
||||
self.assertTrue(self.import_page.is_timestamp_visible())
|
||||
@@ -419,7 +410,6 @@ class TestLibraryImport(ImportTestMixin, StudioLibraryTest):
|
||||
# No items should be in the library to start.
|
||||
self.assertEqual(len(self.landing_page.xblocks), 0)
|
||||
self.import_page.visit()
|
||||
self.import_page.wait_for_choose_file_click_handler()
|
||||
self.import_page.upload_tarball(self.tarball_name)
|
||||
self.import_page.wait_for_upload()
|
||||
self.landing_page.visit()
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"picturefill": "~3.0.2",
|
||||
"raw-loader": "^0.5.1",
|
||||
"requirejs": "~2.3.2",
|
||||
"string-replace-webpack-plugin": "^0.1.3",
|
||||
"uglify-js": "2.7.0",
|
||||
"underscore": "~1.8.3",
|
||||
"underscore.string": "~3.3.4",
|
||||
@@ -32,6 +33,7 @@
|
||||
"edx-custom-a11y-rules": "0.1.3",
|
||||
"eslint-config-edx": "^2.0.1",
|
||||
"eslint-config-edx-es5": "^2.0.0",
|
||||
"eslint-import-resolver-webpack": "^0.8.1",
|
||||
"jasmine-core": "^2.4.1",
|
||||
"jasmine-jquery": "^2.1.1",
|
||||
"karma": "^0.13.22",
|
||||
|
||||
@@ -708,11 +708,11 @@ def execute_webpack(prod, settings=None):
|
||||
sh(
|
||||
cmd(
|
||||
"NODE_ENV={node_env} STATIC_ROOT_LMS={static_root_lms} STATIC_ROOT_CMS={static_root_cms} $(npm bin)/webpack"
|
||||
.format(
|
||||
node_env="production" if prod else "development",
|
||||
static_root_lms=Env.get_django_setting("STATIC_ROOT", "lms", settings=settings),
|
||||
static_root_cms=Env.get_django_setting("STATIC_ROOT", "cms", settings=settings)
|
||||
)
|
||||
.format(
|
||||
node_env="production" if prod else "development",
|
||||
static_root_lms=Env.get_django_setting("STATIC_ROOT", "lms", settings=settings),
|
||||
static_root_cms=Env.get_django_setting("STATIC_ROOT", "cms", settings=settings)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -720,10 +720,10 @@ def execute_webpack(prod, settings=None):
|
||||
def execute_webpack_watch(settings=None):
|
||||
run_background_process(
|
||||
"STATIC_ROOT_LMS={static_root_lms} STATIC_ROOT_CMS={static_root_cms} $(npm bin)/webpack --watch --watch-poll=200"
|
||||
.format(
|
||||
static_root_lms=Env.get_django_setting("STATIC_ROOT", "lms", settings=settings),
|
||||
static_root_cms=Env.get_django_setting("STATIC_ROOT", "cms", settings=settings)
|
||||
)
|
||||
.format(
|
||||
static_root_lms=Env.get_django_setting("STATIC_ROOT", "lms", settings=settings),
|
||||
static_root_cms=Env.get_django_setting("STATIC_ROOT", "cms", settings=settings)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -2378,6 +2378,8 @@ class MakoTemplateLinter(BaseLinter):
|
||||
</script> | # script tag end
|
||||
<%static:require_module(_async)?.*?> | # require js script tag start (optionally the _async version)
|
||||
</%static:require_module(_async)?> | # require js script tag end (optionally the _async version)
|
||||
<%static:webpack.*?> | # webpack script tag start
|
||||
</%static:webpack> | # webpack script tag end
|
||||
<%block[ ]*name=['"]requirejs['"]\w*> | # require js tag start
|
||||
</%block> # require js tag end
|
||||
""",
|
||||
|
||||
@@ -5,9 +5,15 @@
|
||||
var path = require('path');
|
||||
var webpack = require('webpack');
|
||||
var BundleTracker = require('webpack-bundle-tracker');
|
||||
var StringReplace = require('string-replace-webpack-plugin');
|
||||
|
||||
var isProd = process.env.NODE_ENV === 'production';
|
||||
|
||||
var namespacedRequireFiles = [
|
||||
path.resolve(__dirname, 'common/static/common/js/components/views/feedback_notification.js'),
|
||||
path.resolve(__dirname, 'common/static/common/js/components/views/feedback.js')
|
||||
];
|
||||
|
||||
var wpconfig = {
|
||||
context: __dirname,
|
||||
|
||||
@@ -51,9 +57,30 @@ var wpconfig = {
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: namespacedRequireFiles,
|
||||
loader: StringReplace.replace(
|
||||
['babel-loader'],
|
||||
{
|
||||
replacements: [
|
||||
{
|
||||
pattern: /\(function ?\(define\) ?\{/,
|
||||
replacement: function() { return ''; }
|
||||
},
|
||||
{
|
||||
pattern: /\}\)\.call\(this, define \|\| RequireJS\.define\);/,
|
||||
replacement: function() { return ''; }
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
exclude: [
|
||||
/node_modules/,
|
||||
namespacedRequireFiles
|
||||
],
|
||||
use: 'babel-loader'
|
||||
},
|
||||
{
|
||||
@@ -72,7 +99,8 @@ var wpconfig = {
|
||||
use: {
|
||||
loader: 'imports-loader',
|
||||
options: {
|
||||
AjaxPrefix: 'exports-loader?this.AjaxPrefix!../../../../common/static/coffee/src/ajax_prefix.coffee'
|
||||
AjaxPrefix:
|
||||
'exports-loader?this.AjaxPrefix!../../../../common/static/coffee/src/ajax_prefix.coffee'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user