Commit 9c6d94ad by Brian Jacobel

Require and Webpack can eat the same files

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