Clean up eslint failures
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
'js/factories/settings',
|
||||
'js/factories/settings_advanced',
|
||||
'js/factories/settings_graders',
|
||||
'js/factories/videos_index',
|
||||
'js/factories/videos_index'
|
||||
]),
|
||||
/**
|
||||
* By default all the configuration for optimization happens from the command
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
define([
|
||||
'domReady',
|
||||
'jquery',
|
||||
'underscore',
|
||||
'underscore.string',
|
||||
'backbone',
|
||||
'gettext',
|
||||
'../../common/js/components/views/feedback_notification',
|
||||
'jquery.cookie'
|
||||
], function(domReady, $, str, Backbone, gettext, NotificationView) {
|
||||
], function(domReady, $, _, str, Backbone, gettext, NotificationView) {
|
||||
'use strict';
|
||||
|
||||
var main, sendJSON;
|
||||
@@ -78,6 +79,7 @@ define([
|
||||
if (window.onTouchBasedDevice()) {
|
||||
return $('body').addClass('touch-based-device');
|
||||
}
|
||||
return null;
|
||||
});
|
||||
};
|
||||
main();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
(function(requirejs, requireSerial) {
|
||||
'use strict';
|
||||
|
||||
var i, specHelpers, testFiles;
|
||||
if (window) {
|
||||
define('add-a11y-deps',
|
||||
[
|
||||
@@ -20,8 +21,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
var i, specHelpers, testFiles;
|
||||
|
||||
requirejs.config({
|
||||
baseUrl: '/base/',
|
||||
paths: {
|
||||
|
||||
@@ -26,8 +26,35 @@ define([
|
||||
IframeUtils,
|
||||
DropdownMenuView
|
||||
) {
|
||||
'use strict';
|
||||
var $body;
|
||||
|
||||
function smoothScrollLink(e) {
|
||||
(e).preventDefault();
|
||||
|
||||
$.smoothScroll({
|
||||
offset: -200,
|
||||
easing: 'swing',
|
||||
speed: 1000,
|
||||
scrollElement: null,
|
||||
scrollTarget: $(this).attr('href')
|
||||
});
|
||||
}
|
||||
|
||||
function hideNotification(e) {
|
||||
(e).preventDefault();
|
||||
$(this)
|
||||
.closest('.wrapper-notification')
|
||||
.removeClass('is-shown')
|
||||
.addClass('is-hiding')
|
||||
.attr('aria-hidden', 'true');
|
||||
}
|
||||
|
||||
function hideAlert(e) {
|
||||
(e).preventDefault();
|
||||
$(this).closest('.wrapper-alert').removeClass('is-shown');
|
||||
}
|
||||
|
||||
domReady(function() {
|
||||
var dropdownMenuView;
|
||||
|
||||
@@ -44,14 +71,14 @@ define([
|
||||
$('.action-notification-close').bind('click', hideNotification);
|
||||
|
||||
// nav - dropdown related
|
||||
$body.click(function(e) {
|
||||
$body.click(function() {
|
||||
$('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown');
|
||||
$('.nav-dd .nav-item .title').removeClass('is-selected');
|
||||
});
|
||||
|
||||
$('.nav-dd .nav-item, .filterable-column .nav-item').click(function(e) {
|
||||
$subnav = $(this).find('.wrapper-nav-sub');
|
||||
$title = $(this).find('.title');
|
||||
var $subnav = $(this).find('.wrapper-nav-sub'),
|
||||
$title = $(this).find('.title');
|
||||
|
||||
if ($subnav.hasClass('is-shown')) {
|
||||
$subnav.removeClass('is-shown');
|
||||
@@ -68,7 +95,8 @@ define([
|
||||
});
|
||||
|
||||
// general link management - new window/tab
|
||||
$('a[rel="external"]:not([title])').attr('title', gettext('This link will open in a new browser window/tab'));
|
||||
$('a[rel="external"]:not([title])')
|
||||
.attr('title', gettext('This link will open in a new browser window/tab'));
|
||||
$('a[rel="external"]').attr('target', '_blank');
|
||||
|
||||
// general link management - lean modal window
|
||||
@@ -100,38 +128,4 @@ define([
|
||||
|
||||
window.studioNavMenuActive = true;
|
||||
});
|
||||
|
||||
function smoothScrollLink(e) {
|
||||
(e).preventDefault();
|
||||
|
||||
$.smoothScroll({
|
||||
offset: -200,
|
||||
easing: 'swing',
|
||||
speed: 1000,
|
||||
scrollElement: null,
|
||||
scrollTarget: $(this).attr('href')
|
||||
});
|
||||
}
|
||||
|
||||
function smoothScrollTop(e) {
|
||||
(e).preventDefault();
|
||||
|
||||
$.smoothScroll({
|
||||
offset: -200,
|
||||
easing: 'swing',
|
||||
speed: 1000,
|
||||
scrollElement: null,
|
||||
scrollTarget: $('#view-top')
|
||||
});
|
||||
}
|
||||
|
||||
function hideNotification(e) {
|
||||
(e).preventDefault();
|
||||
$(this).closest('.wrapper-notification').removeClass('is-shown').addClass('is-hiding').attr('aria-hidden', 'true');
|
||||
}
|
||||
|
||||
function hideAlert(e) {
|
||||
(e).preventDefault();
|
||||
$(this).closest('.wrapper-alert').removeClass('is-shown');
|
||||
}
|
||||
}); // end require()
|
||||
|
||||
@@ -1,9 +1,80 @@
|
||||
define(['jquery', 'date', 'js/utils/change_on_enter', 'jquery.ui', 'jquery.timepicker'],
|
||||
function($, date, TriggerChangeEventOnEnter) {
|
||||
'use strict';
|
||||
var setupDatePicker = function(fieldName, view, index) {
|
||||
|
||||
function getDate(datepickerInput, timepickerInput) {
|
||||
// given a pair of inputs (datepicker and timepicker), return a JS Date
|
||||
// object that corresponds to the datetime.js that they represent. Assume
|
||||
// UTC timezone, NOT the timezone of the user's browser.
|
||||
var selectedDate = null,
|
||||
selectedTime = null;
|
||||
if (datepickerInput.length > 0) {
|
||||
selectedDate = $(datepickerInput).datepicker('getDate');
|
||||
}
|
||||
if (timepickerInput.length > 0) {
|
||||
selectedTime = $(timepickerInput).timepicker('getTime');
|
||||
}
|
||||
if (selectedDate && selectedTime) {
|
||||
return new Date(Date.UTC(
|
||||
selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate(),
|
||||
selectedTime.getHours(), selectedTime.getMinutes()
|
||||
));
|
||||
} else if (selectedDate) {
|
||||
return new Date(Date.UTC(
|
||||
selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate()));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function setDate(datepickerInput, timepickerInput, datetime) {
|
||||
// given a pair of inputs (datepicker and timepicker) and the date as an
|
||||
// ISO-formatted date string.
|
||||
var parsedDatetime = Date.parse(datetime);
|
||||
if (parsedDatetime) {
|
||||
$(datepickerInput).datepicker('setDate', parsedDatetime);
|
||||
if (timepickerInput.length > 0) {
|
||||
$(timepickerInput).timepicker('setTime', parsedDatetime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderDate(dateArg) {
|
||||
// Render a localized date from an argument that can be passed to
|
||||
// the Date constructor (e.g. another Date or an ISO 8601 string)
|
||||
var dateObj = new Date(dateArg);
|
||||
return dateObj.toLocaleString(
|
||||
[],
|
||||
{timeZone: 'UTC', timeZoneName: 'short'}
|
||||
);
|
||||
}
|
||||
|
||||
function parseDateFromString(stringDate) {
|
||||
if (stringDate && typeof stringDate === 'string') {
|
||||
return new Date(stringDate);
|
||||
} else {
|
||||
return stringDate;
|
||||
}
|
||||
}
|
||||
|
||||
function convertDateStringsToObjects(obj, dateFields) {
|
||||
var i;
|
||||
for (i = 0; i < dateFields.length; i++) {
|
||||
if (obj[dateFields[i]]) {
|
||||
obj[dateFields[i]] = parseDateFromString(obj[dateFields[i]]);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
function setupDatePicker(fieldName, view, index) {
|
||||
var cacheModel;
|
||||
var div;
|
||||
var datefield;
|
||||
var timefield;
|
||||
var cacheview;
|
||||
var setfield;
|
||||
var currentDate;
|
||||
if (typeof index !== 'undefined' && view.hasOwnProperty('collection')) {
|
||||
cacheModel = view.collection.models[index];
|
||||
div = view.$el.find('#' + view.collectionSelector(cacheModel.cid));
|
||||
@@ -11,10 +82,10 @@ function($, date, TriggerChangeEventOnEnter) {
|
||||
cacheModel = view.model;
|
||||
div = view.$el.find('#' + view.fieldToSelectorMap[fieldName]);
|
||||
}
|
||||
var datefield = $(div).find('input.date');
|
||||
var timefield = $(div).find('input.time');
|
||||
var cacheview = view;
|
||||
var setfield = function(event) {
|
||||
datefield = $(div).find('input.date');
|
||||
timefield = $(div).find('input.time');
|
||||
cacheview = view;
|
||||
setfield = function(event) {
|
||||
var newVal = getDate(datefield, timefield);
|
||||
|
||||
// Setting to null clears the time as well, as date and time are linked.
|
||||
@@ -34,83 +105,19 @@ function($, date, TriggerChangeEventOnEnter) {
|
||||
timefield.on('changeTime', setfield);
|
||||
timefield.on('input', setfield);
|
||||
|
||||
var current_date = null;
|
||||
currentDate = null;
|
||||
if (cacheModel) {
|
||||
current_date = cacheModel.get(fieldName);
|
||||
currentDate = cacheModel.get(fieldName);
|
||||
}
|
||||
// timepicker doesn't let us set null, so check that we have a time
|
||||
if (current_date) {
|
||||
setDate(datefield, timefield, current_date);
|
||||
} // but reset fields either way
|
||||
else {
|
||||
if (currentDate) {
|
||||
setDate(datefield, timefield, currentDate);
|
||||
} else {
|
||||
// but reset fields either way
|
||||
timefield.val('');
|
||||
datefield.val('');
|
||||
}
|
||||
};
|
||||
|
||||
var getDate = function(datepickerInput, timepickerInput) {
|
||||
// given a pair of inputs (datepicker and timepicker), return a JS Date
|
||||
// object that corresponds to the datetime.js that they represent. Assume
|
||||
// UTC timezone, NOT the timezone of the user's browser.
|
||||
var date = null,
|
||||
time = null;
|
||||
if (datepickerInput.length > 0) {
|
||||
date = $(datepickerInput).datepicker('getDate');
|
||||
}
|
||||
if (timepickerInput.length > 0) {
|
||||
time = $(timepickerInput).timepicker('getTime');
|
||||
}
|
||||
if (date && time) {
|
||||
return new Date(Date.UTC(
|
||||
date.getFullYear(), date.getMonth(), date.getDate(),
|
||||
time.getHours(), time.getMinutes()
|
||||
));
|
||||
} else if (date) {
|
||||
return new Date(Date.UTC(
|
||||
date.getFullYear(), date.getMonth(), date.getDate()));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
var setDate = function(datepickerInput, timepickerInput, datetime) {
|
||||
// given a pair of inputs (datepicker and timepicker) and the date as an
|
||||
// ISO-formatted date string.
|
||||
datetime = Date.parse(datetime);
|
||||
if (datetime) {
|
||||
$(datepickerInput).datepicker('setDate', datetime);
|
||||
if (timepickerInput.length > 0) {
|
||||
$(timepickerInput).timepicker('setTime', datetime);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var renderDate = function(dateArg) {
|
||||
// Render a localized date from an argument that can be passed to
|
||||
// the Date constructor (e.g. another Date or an ISO 8601 string)
|
||||
var date = new Date(dateArg);
|
||||
return date.toLocaleString(
|
||||
[],
|
||||
{timeZone: 'UTC', timeZoneName: 'short'}
|
||||
);
|
||||
};
|
||||
|
||||
var parseDateFromString = function(stringDate) {
|
||||
if (stringDate && typeof stringDate === 'string') {
|
||||
return new Date(stringDate);
|
||||
} else {
|
||||
return stringDate;
|
||||
}
|
||||
};
|
||||
|
||||
var convertDateStringsToObjects = function(obj, dateFields) {
|
||||
for (var i = 0; i < dateFields.length; i++) {
|
||||
if (obj[dateFields[i]]) {
|
||||
obj[dateFields[i]] = parseDateFromString(obj[dateFields[i]]);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
getDate: getDate,
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
define(['jquery', 'underscore', 'js/views/xblock', 'js/utils/module', 'gettext', 'common/js/components/views/feedback_notification',
|
||||
'jquery.ui'], // The container view uses sortable, which is provided by jquery.ui.
|
||||
define([
|
||||
'jquery', 'underscore', 'js/views/xblock', 'js/utils/module',
|
||||
'gettext', 'common/js/components/views/feedback_notification',
|
||||
'jquery.ui'
|
||||
], // The container view uses sortable, which is provided by jquery.ui.
|
||||
function($, _, XBlockView, ModuleUtils, gettext, NotificationView) {
|
||||
'use strict';
|
||||
|
||||
var studioXBlockWrapperClass = '.studio-xblock-wrapper';
|
||||
|
||||
var ContainerView = XBlockView.extend({
|
||||
@@ -12,10 +17,10 @@ define(['jquery', 'underscore', 'js/views/xblock', 'js/utils/module', 'gettext',
|
||||
new_child_view: 'reorderable_container_child_preview',
|
||||
|
||||
xblockReady: function() {
|
||||
XBlockView.prototype.xblockReady.call(this);
|
||||
var reorderableClass, reorderableContainer,
|
||||
newParent, oldParent,
|
||||
self = this;
|
||||
XBlockView.prototype.xblockReady.call(this);
|
||||
|
||||
this.requestToken = this.$('div.xblock').first().data('request-token');
|
||||
reorderableClass = this.makeRequestSpecificSelector('.reorderable-container');
|
||||
@@ -24,13 +29,13 @@ define(['jquery', 'underscore', 'js/views/xblock', 'js/utils/module', 'gettext',
|
||||
reorderableContainer.sortable({
|
||||
handle: '.drag-handle',
|
||||
|
||||
start: function(event, ui) {
|
||||
start: function() {
|
||||
// Necessary because of an open bug in JQuery sortable.
|
||||
// http://bugs.jqueryui.com/ticket/4990
|
||||
reorderableContainer.sortable('refreshPositions');
|
||||
},
|
||||
|
||||
stop: function(event, ui) {
|
||||
stop: function() {
|
||||
var saving, hideSaving, removeFromParent;
|
||||
|
||||
if (_.isUndefined(oldParent)) {
|
||||
|
||||
@@ -44,7 +44,8 @@ define(['jquery', 'underscore', 'common/js/components/utils/view_utils', 'js/vie
|
||||
successCallback = options ? options.success || options.done : null,
|
||||
errorCallback = options ? options.error || options.done : null,
|
||||
xblock,
|
||||
fragmentsRendered;
|
||||
fragmentsRendered,
|
||||
aside;
|
||||
|
||||
fragmentsRendered = this.renderXBlockFragment(fragment, wrapper);
|
||||
fragmentsRendered.always(function() {
|
||||
@@ -55,7 +56,7 @@ define(['jquery', 'underscore', 'common/js/components/utils/view_utils', 'js/vie
|
||||
self.xblockReady(self.xblock);
|
||||
self.$('.xblock_asides-v1').each(function() {
|
||||
if (!$(this).hasClass('xblock-initialized')) {
|
||||
var aside = XBlock.initializeBlock($(this));
|
||||
aside = XBlock.initializeBlock($(this));
|
||||
self.initRuntimeData(aside, options);
|
||||
}
|
||||
});
|
||||
@@ -86,13 +87,15 @@ define(['jquery', 'underscore', 'common/js/components/utils/view_utils', 'js/vie
|
||||
* @param data The data to be passed to any listener's of the event.
|
||||
*/
|
||||
notifyRuntime: function(eventName, data) {
|
||||
var runtime = this.xblock && this.xblock.runtime;
|
||||
var runtime = this.xblock && this.xblock.runtime,
|
||||
xblockChildren;
|
||||
|
||||
if (runtime) {
|
||||
runtime.notify(eventName, data);
|
||||
} else if (this.xblock) {
|
||||
var xblock_children = this.xblock.element && $(this.xblock.element).prop('xblock_children');
|
||||
if (xblock_children) {
|
||||
$(xblock_children).each(function() {
|
||||
xblockChildren = this.xblock.element && $(this.xblock.element).prop('xblock_children');
|
||||
if (xblockChildren) {
|
||||
$(xblockChildren).each(function() {
|
||||
if (this.runtime) {
|
||||
this.runtime.notify(eventName, data);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ var options = {
|
||||
|
||||
fixtureFiles: [
|
||||
{pattern: '../templates/js/**/*.underscore'},
|
||||
{pattern: 'templates/**/*.underscore'},
|
||||
{pattern: 'templates/**/*.underscore'}
|
||||
],
|
||||
|
||||
runFiles: [
|
||||
|
||||
10
common/lib/xmodule/xmodule/assets/word_cloud/.eslintrc.js
Normal file
10
common/lib/xmodule/xmodule/assets/word_cloud/.eslintrc.js
Normal file
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
extends: 'eslint-config-edx',
|
||||
root: true,
|
||||
settings: {
|
||||
'import/resolver': 'webpack',
|
||||
},
|
||||
overrides: {
|
||||
excludedFiles: 'public/js/*',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
import WordCloudMain from './word_cloud_main';
|
||||
|
||||
function WordCloud(el) {
|
||||
return new WordCloudMain(el);
|
||||
}
|
||||
|
||||
window.WordCloud = WordCloud;
|
||||
@@ -0,0 +1,316 @@
|
||||
/**
|
||||
* @file The main module definition for Word Cloud XModule.
|
||||
*
|
||||
* Defines a constructor function which operates on a DOM element. Either
|
||||
* show the user text inputs so he can enter words, or render his selected
|
||||
* words along with the word cloud representing the top words.
|
||||
*
|
||||
* @module WordCloudMain
|
||||
*
|
||||
* @exports WordCloudMain
|
||||
*
|
||||
* @external $
|
||||
*/
|
||||
|
||||
import * as HtmlUtils from 'edx-ui-toolkit/js/utils/html-utils';
|
||||
import d3 from 'd3.min';
|
||||
import { cloud as d3Cloud } from 'd3.layout.cloud';
|
||||
import gettext from 'gettext';
|
||||
|
||||
function generateUniqueId(wordCloudId, counter) {
|
||||
return `_wc_${wordCloudId}_${counter}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function WordCloudMain
|
||||
*
|
||||
* This function will process all the attributes from the DOM element passed, taking all of
|
||||
* the configuration attributes. It will either then attach a callback handler for the click
|
||||
* event on the button in the case when the user needs to enter words, or it will call the
|
||||
* appropriate mehtod to generate and render a word cloud from user's enetered words along with
|
||||
* all of the other words.
|
||||
*
|
||||
* @constructor
|
||||
*
|
||||
* @param {jQuery} el DOM element where the word cloud will be processed and created.
|
||||
*/
|
||||
export default function WordCloudMain(el) {
|
||||
const cloud = this;
|
||||
|
||||
this.wordCloudEl = $(el).find('.word_cloud');
|
||||
|
||||
// Get the URL to which we will post the users words.
|
||||
this.ajax_url = this.wordCloudEl.data('ajax-url');
|
||||
|
||||
// Dimensions of the box where the word cloud will be drawn.
|
||||
this.width = 635;
|
||||
this.height = 635;
|
||||
|
||||
// Hide WordCloud container before Ajax request done
|
||||
this.wordCloudEl.hide();
|
||||
|
||||
// Retriveing response from the server as an AJAX request. Attach a callback that will
|
||||
// be fired on server's response.
|
||||
$.postWithPrefix(
|
||||
`${cloud.ajax_url}/get_state`, null,
|
||||
(response) => {
|
||||
if (response.status !== 'success') {
|
||||
return;
|
||||
}
|
||||
|
||||
cloud.configJson = response;
|
||||
},
|
||||
)
|
||||
.done(() => {
|
||||
// Show WordCloud container after Ajax request done
|
||||
cloud.wordCloudEl.show();
|
||||
|
||||
if (cloud.configJson && cloud.configJson.submitted) {
|
||||
cloud.showWordCloud(cloud.configJson);
|
||||
}
|
||||
});
|
||||
|
||||
$(el).find('.save').on('click', () => {
|
||||
cloud.submitAnswer();
|
||||
});
|
||||
} // End-of: var WordCloudMain = function(el) {
|
||||
|
||||
/**
|
||||
* @function submitAnswer
|
||||
*
|
||||
* Callback to be executed when the user eneter his words. It will send user entries to the
|
||||
* server, and upon receiving correct response, will call the function to generate the
|
||||
* word cloud.
|
||||
*/
|
||||
WordCloudMain.prototype.submitAnswer = () => {
|
||||
const cloud = this;
|
||||
const data = { student_words: [] };
|
||||
|
||||
// Populate the data to be sent to the server with user's words.
|
||||
this.wordCloudEl.find('input.input-cloud').each((index, value) => {
|
||||
data.student_words.push($(value).val());
|
||||
});
|
||||
|
||||
// Send the data to the server as an AJAX request. Attach a callback that will
|
||||
// be fired on server's response.
|
||||
$.postWithPrefix(
|
||||
`${cloud.ajax_url}/submit`, $.param(data),
|
||||
(response) => {
|
||||
if (response.status !== 'success') {
|
||||
return;
|
||||
}
|
||||
|
||||
cloud.showWordCloud(response);
|
||||
},
|
||||
);
|
||||
}; // End-of: WordCloudMain.prototype.submitAnswer = () => {
|
||||
|
||||
/**
|
||||
* @function showWordCloud
|
||||
*
|
||||
* @param {object} response The response from the server that contains the user's entered words
|
||||
* along with all of the top words.
|
||||
*
|
||||
* This function will set up everything for d3 and launch the draw method. Among other things,
|
||||
* iw will determine maximum word size.
|
||||
*/
|
||||
WordCloudMain.prototype.showWordCloud = (response) => {
|
||||
const words = response.top_words;
|
||||
const cloud = this;
|
||||
let maxSize = 0;
|
||||
let minSize = 10000;
|
||||
let scaleFactor = 1;
|
||||
let maxFontSize = 200;
|
||||
const minFontSize = 16;
|
||||
|
||||
this.wordCloudEl.find('.input_cloud_section').hide();
|
||||
|
||||
// Find the word with the maximum percentage. I.e. the most popular word.
|
||||
$.each(words, (index, word) => {
|
||||
if (word.size > maxSize) {
|
||||
maxSize = word.size;
|
||||
}
|
||||
if (word.size < minSize) {
|
||||
minSize = word.size;
|
||||
}
|
||||
});
|
||||
|
||||
// Find the longest word, and calculate the scale appropriately. This is
|
||||
// required so that even long words fit into the drawing area.
|
||||
//
|
||||
// This is a fix for: if the word is very long and/or big, it is discarded by
|
||||
// for unknown reason.
|
||||
$.each(words, (index, word) => {
|
||||
let tempScaleFactor = 1.0;
|
||||
const size = ((word.size / maxSize) * maxFontSize);
|
||||
|
||||
if (size * 0.7 * word.text.length > cloud.width) {
|
||||
tempScaleFactor = ((cloud.width / word.text.length) / 0.7) / size;
|
||||
}
|
||||
|
||||
if (scaleFactor > tempScaleFactor) {
|
||||
scaleFactor = tempScaleFactor;
|
||||
}
|
||||
});
|
||||
|
||||
// Update the maximum font size based on the longest word.
|
||||
maxFontSize *= scaleFactor;
|
||||
|
||||
// Generate the word cloud.
|
||||
d3Cloud().size([this.width, this.height])
|
||||
.words(words)
|
||||
.rotate(() => Math.floor((Math.random() * 2)) * 90)
|
||||
.font('Impact')
|
||||
.fontSize((d) => {
|
||||
let size = (d.size / maxSize) * maxFontSize;
|
||||
|
||||
size = size >= minFontSize ? size : minFontSize;
|
||||
|
||||
return size;
|
||||
})
|
||||
// Draw the word cloud.
|
||||
.on('end', (wds, bounds) => cloud.drawWordCloud(response, wds, bounds))
|
||||
.start();
|
||||
}; // End-of: WordCloudMain.prototype.showWordCloud = function(response) {
|
||||
|
||||
/**
|
||||
* @function drawWordCloud
|
||||
*
|
||||
* This function will be called when d3 has finished initing the state for our word cloud,
|
||||
* and it is ready to hand off the process to the drawing routine. Basically set up everything
|
||||
* necessary for the actual drwing of the words.
|
||||
*
|
||||
* @param {object} response The response from the server that contains the user's entered words
|
||||
* along with all of the top words.
|
||||
*
|
||||
* @param {array} words An array of objects. Each object must have two properties. One property
|
||||
* is 'text' (the actual word), and the other property is 'size' which represents the number that the
|
||||
* word was enetered by the students.
|
||||
*
|
||||
* @param {array} bounds An array of two objects. First object is the top-left coordinates of the bounding
|
||||
* box where all of the words fir, second object is the bottom-right coordinates of the bounding box. Each
|
||||
* coordinate object contains two properties: 'x', and 'y'.
|
||||
*/
|
||||
WordCloudMain.prototype.drawWordCloud = (response, words, bounds) => {
|
||||
// Color words in different colors.
|
||||
const fill = d3.scale.category20();
|
||||
|
||||
// Will be populated by words the user enetered.
|
||||
const studentWordsKeys = [];
|
||||
|
||||
// By default we do not scale.
|
||||
let scale = 1;
|
||||
|
||||
// Caсhing of DOM element
|
||||
const cloudSectionEl = this.wordCloudEl.find('.result_cloud_section');
|
||||
|
||||
// Iterator for word cloud count for uniqueness
|
||||
let wcCount = 0;
|
||||
|
||||
// If bounding rectangle is given, scale based on the bounding box of all the words.
|
||||
if (bounds) {
|
||||
scale = 0.5 * Math.min(
|
||||
this.width / Math.abs(bounds[1].x - (this.width / 2)),
|
||||
this.width / Math.abs(bounds[0].x - (this.width / 2)),
|
||||
this.height / Math.abs(bounds[1].y - (this.height / 2)),
|
||||
this.height / Math.abs(bounds[0].y - (this.height / 2)),
|
||||
);
|
||||
}
|
||||
|
||||
$.each(response.student_words, (word, stat) => {
|
||||
const percent = (response.display_student_percents) ? ` ${Math.round(100 * (stat / response.total_count))}%` : '';
|
||||
|
||||
studentWordsKeys.push(HtmlUtils.interpolateHtml(
|
||||
'{listStart}{startTag}{word}{endTag}{percent}{listEnd}',
|
||||
{
|
||||
listStart: HtmlUtils.HTML('<li>'),
|
||||
startTag: HtmlUtils.HTML('<strong>'),
|
||||
word,
|
||||
endTag: HtmlUtils.HTML('</strong>'),
|
||||
percent,
|
||||
listEnd: HtmlUtils.HTML('</li>'),
|
||||
},
|
||||
).toString());
|
||||
});
|
||||
|
||||
// Comma separated string of user enetered words.
|
||||
const studentWordsStr = studentWordsKeys.join('');
|
||||
|
||||
cloudSectionEl
|
||||
.addClass('active');
|
||||
|
||||
HtmlUtils.setHtml(
|
||||
cloudSectionEl.find('.your_words'),
|
||||
HtmlUtils.HTML(studentWordsStr),
|
||||
);
|
||||
|
||||
HtmlUtils.setHtml(
|
||||
cloudSectionEl.find('.your_words').end().find('.total_num_words'),
|
||||
HtmlUtils.interpolateHtml(
|
||||
gettext('{start_strong}{total}{end_strong} words submitted in total.'),
|
||||
{
|
||||
start_strong: HtmlUtils.HTML('<strong>'),
|
||||
end_strong: HtmlUtils.HTML('</strong>'),
|
||||
total: response.total_count,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
$(`${cloudSectionEl.attr('id')} .word_cloud`).empty();
|
||||
|
||||
// Actual drawing of word cloud.
|
||||
const groupEl = d3.select(`#${cloudSectionEl.attr('id')} .word_cloud`).append('svg')
|
||||
.attr('width', this.width)
|
||||
.attr('height', this.height)
|
||||
.append('g')
|
||||
.attr('transform', `translate(${0.5 * this.width},${0.5 * this.height})`)
|
||||
.selectAll('text')
|
||||
.data(words)
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('data-id', () => {
|
||||
wcCount += 1;
|
||||
return wcCount;
|
||||
})
|
||||
.attr('aria-describedby', () => HtmlUtils.interpolateHtml(
|
||||
gettext('text_word_{uniqueId} title_word_{uniqueId}'),
|
||||
{
|
||||
uniqueId: generateUniqueId(cloudSectionEl.attr('id'), $(this).data('id')),
|
||||
},
|
||||
));
|
||||
|
||||
groupEl
|
||||
.append('title')
|
||||
.attr('id', () => HtmlUtils.interpolateHtml(
|
||||
gettext('title_word_{uniqueId}'),
|
||||
{
|
||||
uniqueId: generateUniqueId(cloudSectionEl.attr('id'), $(this).parent().data('id')),
|
||||
},
|
||||
))
|
||||
.text((d) => {
|
||||
let res = '';
|
||||
|
||||
$.each(response.top_words, (index, value) => {
|
||||
if (value.text === d.text) {
|
||||
res = `${value.percent}%`;
|
||||
}
|
||||
});
|
||||
|
||||
return res;
|
||||
});
|
||||
|
||||
groupEl
|
||||
.append('text')
|
||||
.attr('id', () => HtmlUtils.interpolateHtml(
|
||||
gettext('text_word_{uniqueId}'),
|
||||
{
|
||||
uniqueId: generateUniqueId(cloudSectionEl.attr('id'), $(this).parent().data('id')),
|
||||
},
|
||||
))
|
||||
.style('font-size', d => `${d.size}px`)
|
||||
.style('font-family', 'Impact')
|
||||
.style('fill', (d, i) => fill(i))
|
||||
.attr('text-anchor', 'middle')
|
||||
.attr('transform', d => `translate(${d.x}, ${d.y})rotate(${d.rotate$})scale(${scale})`)
|
||||
.text(d => d.text);
|
||||
}; // End-of: WordCloudMain.prototype.drawWordCloud = function(words, bounds) {
|
||||
@@ -0,0 +1,56 @@
|
||||
/* eslint-env node */
|
||||
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
word_cloud: 'word_cloud',
|
||||
},
|
||||
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'public/js'),
|
||||
filename: '[name].js',
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
use: 'babel-loader',
|
||||
},
|
||||
{
|
||||
test: /d3.min/,
|
||||
use: [
|
||||
'babel-loader',
|
||||
{
|
||||
loader: 'exports-loader',
|
||||
options: {
|
||||
d3: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
resolve: {
|
||||
modules: [
|
||||
path.resolve(__dirname, 'src/js'),
|
||||
path.resolve(__dirname, '../../../../../../node_modules'),
|
||||
],
|
||||
alias: {
|
||||
'edx-ui-toolkit': 'edx-ui-toolkit/src/', // @TODO: some paths in toolkit are not valid relative paths
|
||||
},
|
||||
extensions: ['.js', '.jsx', '.json'],
|
||||
},
|
||||
|
||||
externals: {
|
||||
gettext: 'gettext',
|
||||
canvas: 'canvas',
|
||||
jquery: 'jQuery',
|
||||
$: 'jQuery',
|
||||
underscore: '_',
|
||||
},
|
||||
};
|
||||
@@ -23,7 +23,7 @@
|
||||
window.Video(el);
|
||||
});
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
// If normal call to `window.Video` constructor, store the element for later initializing.
|
||||
@@ -128,14 +128,15 @@
|
||||
initialize(innerState, element);
|
||||
};
|
||||
};
|
||||
var onSequenceChange;
|
||||
|
||||
new VideoAccessibleMenu(el, {
|
||||
VideoAccessibleMenu(el, {
|
||||
storage: storage,
|
||||
saveStateUrl: state.metadata.saveStateUrl
|
||||
});
|
||||
|
||||
if (bumperMetadata) {
|
||||
new VideoPoster(el, {
|
||||
VideoPoster(el, {
|
||||
poster: el.data('poster'),
|
||||
onClick: _.once(function() {
|
||||
var mainVideoPlayer = player(state);
|
||||
@@ -162,7 +163,7 @@
|
||||
}
|
||||
|
||||
el.data('video-player-state', state);
|
||||
var onSequenceChange = function onSequenceChange() {
|
||||
onSequenceChange = function() {
|
||||
if (state && state.videoPlayer) {
|
||||
state.videoPlayer.destroy();
|
||||
}
|
||||
|
||||
@@ -29,11 +29,9 @@
|
||||
*/
|
||||
toggleExpandCollapse = function(target, collapsedClass) {
|
||||
// Support the old 'collapsed' option until fully switched over to is-collapsed
|
||||
if (!collapsedClass) {
|
||||
collapsedClass = 'collapsed';
|
||||
}
|
||||
var collapsed = collapsedClass || 'collapsed';
|
||||
target.closest('.expand-collapse').toggleClass('expand collapse');
|
||||
target.closest('.is-collapsible, .window').toggleClass(collapsedClass);
|
||||
target.closest('.is-collapsible, .window').toggleClass(collapsed);
|
||||
target.closest('.is-collapsible').children('article').slideToggle();
|
||||
};
|
||||
|
||||
@@ -239,20 +237,20 @@
|
||||
};
|
||||
|
||||
// Ensure that sum length of key field values <= ${MAX_SUM_KEY_LENGTH} chars.
|
||||
validateTotalKeyLength = function(key_field_selectors) {
|
||||
validateTotalKeyLength = function(keyFieldSelectors) {
|
||||
var totalLength = _.reduce(
|
||||
key_field_selectors,
|
||||
keyFieldSelectors,
|
||||
function(sum, ele) { return sum + $(ele).val().length; },
|
||||
0
|
||||
);
|
||||
return totalLength <= MAX_SUM_KEY_LENGTH;
|
||||
};
|
||||
|
||||
checkTotalKeyLengthViolations = function(selectors, classes, key_field_selectors, message_tpl) {
|
||||
if (!validateTotalKeyLength(key_field_selectors)) {
|
||||
checkTotalKeyLengthViolations = function(selectors, classes, keyFieldSelectors, messageTpl) {
|
||||
if (!validateTotalKeyLength(keyFieldSelectors)) {
|
||||
$(selectors.errorWrapper).addClass(classes.shown).removeClass(classes.hiding);
|
||||
$(selectors.errorMessage).html(
|
||||
'<p>' + _.template(message_tpl)({limit: MAX_SUM_KEY_LENGTH}) + '</p>'
|
||||
'<p>' + _.template(messageTpl)({limit: MAX_SUM_KEY_LENGTH}) + '</p>'
|
||||
);
|
||||
$(selectors.save).addClass(classes.disabled);
|
||||
} else {
|
||||
|
||||
@@ -45,8 +45,6 @@ var webdriver = require('selenium-webdriver');
|
||||
var firefox = require('selenium-webdriver/firefox');
|
||||
var webpackConfig = require(path.join(appRoot, 'webpack.dev.config.js'));
|
||||
|
||||
delete webpackConfig.entry;
|
||||
|
||||
// The following crazy bit is to work around the webpack.optimize.CommonsChunkPlugin
|
||||
// plugin. The problem is that it it factors out the code that defines webpackJsonp
|
||||
// and puts in in the commons JS, which Karma doesn't know to load first. This is a
|
||||
@@ -56,33 +54,36 @@ delete webpackConfig.entry;
|
||||
// https://github.com/webpack-contrib/karma-webpack/issues/24#issuecomment-257613167
|
||||
//
|
||||
// This should be fixed in v3 of karma-webpack
|
||||
const commonsChunkPluginIndex = webpackConfig.plugins.findIndex(plugin => plugin.chunkNames);
|
||||
webpackConfig.plugins.splice(commonsChunkPluginIndex, 1);
|
||||
var commonsChunkPluginIndex = webpackConfig.plugins.findIndex(function(plugin) { return plugin.chunkNames; });
|
||||
|
||||
// Files which are needed by all lms/cms suites.
|
||||
var commonFiles = {
|
||||
libraryFiles: [
|
||||
{ pattern: 'common/js/vendor/**/*.js' },
|
||||
{ pattern: 'edx-pattern-library/js/**/*.js' },
|
||||
{ pattern: 'edx-ui-toolkit/js/**/*.js' },
|
||||
{ pattern: 'xmodule_js/common_static/common/js/**/!(*spec).js' },
|
||||
{ pattern: 'xmodule_js/common_static/js/**/!(*spec).js' },
|
||||
{ pattern: 'xmodule_js/src/**/*.js' }
|
||||
{pattern: 'common/js/vendor/**/*.js'},
|
||||
{pattern: 'edx-pattern-library/js/**/*.js'},
|
||||
{pattern: 'edx-ui-toolkit/js/**/*.js'},
|
||||
{pattern: 'xmodule_js/common_static/common/js/**/!(*spec).js'},
|
||||
{pattern: 'xmodule_js/common_static/js/**/!(*spec).js'},
|
||||
{pattern: 'xmodule_js/src/**/*.js'}
|
||||
],
|
||||
|
||||
sourceFiles: [
|
||||
{ pattern: 'common/js/!(spec_helpers)/**/!(*spec).js' }
|
||||
{pattern: 'common/js/!(spec_helpers)/**/!(*spec).js'}
|
||||
],
|
||||
|
||||
specFiles: [
|
||||
{ pattern: 'common/js/spec_helpers/**/*.js' }
|
||||
{pattern: 'common/js/spec_helpers/**/*.js'}
|
||||
],
|
||||
|
||||
fixtureFiles: [
|
||||
{ pattern: 'common/templates/**/*.underscore' }
|
||||
{pattern: 'common/templates/**/*.underscore'}
|
||||
]
|
||||
};
|
||||
|
||||
webpackConfig.plugins.splice(commonsChunkPluginIndex, 1);
|
||||
|
||||
delete webpackConfig.entry;
|
||||
|
||||
/**
|
||||
* Customize the name attribute in xml testcase element
|
||||
* @param {Object} browser
|
||||
@@ -124,6 +125,8 @@ function reporters(config) {
|
||||
* @return {Object}
|
||||
*/
|
||||
function getBasepathAndFilename(filepath) {
|
||||
var file, dir;
|
||||
|
||||
if (!filepath) {
|
||||
// these will configure the reporters to create report files relative to this karma config file
|
||||
return {
|
||||
@@ -131,9 +134,8 @@ function getBasepathAndFilename(filepath) {
|
||||
file: undefined
|
||||
};
|
||||
}
|
||||
|
||||
var file = filepath.replace(/^.*[\\\/]/, ''),
|
||||
dir = filepath.replace(file, '');
|
||||
file = filepath.replace(/^.*[\\/]/, '');
|
||||
dir = filepath.replace(file, '');
|
||||
|
||||
return {
|
||||
dir: dir,
|
||||
@@ -148,14 +150,14 @@ function getBasepathAndFilename(filepath) {
|
||||
* @return {Object}
|
||||
*/
|
||||
function coverageSettings(config) {
|
||||
var path = getBasepathAndFilename(config.coveragereportpath);
|
||||
var pth = getBasepathAndFilename(config.coveragereportpath);
|
||||
return {
|
||||
dir: path.dir,
|
||||
dir: pth.dir,
|
||||
subdir: '.',
|
||||
includeAllSources: true,
|
||||
reporters: [
|
||||
{ type: 'cobertura', file: path.file },
|
||||
{ type: 'text-summary' }
|
||||
{type: 'cobertura', file: pth.file},
|
||||
{type: 'text-summary'}
|
||||
]
|
||||
};
|
||||
}
|
||||
@@ -167,10 +169,10 @@ function coverageSettings(config) {
|
||||
* @return {Object}
|
||||
*/
|
||||
function junitSettings(config) {
|
||||
var path = getBasepathAndFilename(config.junitreportpath);
|
||||
var pth = getBasepathAndFilename(config.junitreportpath);
|
||||
return {
|
||||
outputDir: path.dir,
|
||||
outputFile: path.file,
|
||||
outputDir: pth.dir,
|
||||
outputFile: pth.file,
|
||||
suite: 'javascript',
|
||||
useBrowserName: false,
|
||||
nameFormatter: junitNameFormatter,
|
||||
@@ -185,14 +187,15 @@ function junitSettings(config) {
|
||||
* @return {String}
|
||||
*/
|
||||
// I'd like to fix the no-shadow violation on the next line, but it would break this shared conf's API.
|
||||
function defaultNormalizeFunc(appRoot, pattern) { // eslint-disable-line no-shadow
|
||||
if (pattern.match(/^common\/js/)) {
|
||||
pattern = path.join(appRoot, '/common/static/' + pattern);
|
||||
} else if (pattern.match(/^xmodule_js\/common_static/)) {
|
||||
pattern = path.join(appRoot, '/common/static/' +
|
||||
pattern.replace(/^xmodule_js\/common_static\//, ''));
|
||||
function defaultNormalizeFunc(appRoot, pattern) { // eslint-disable-line no-shadow
|
||||
var pat = pattern;
|
||||
if (pat.match(/^common\/js/)) {
|
||||
pat = path.join(appRoot, '/common/static/' + pat);
|
||||
} else if (pat.match(/^xmodule_js\/common_static/)) {
|
||||
pat = path.join(appRoot, '/common/static/' +
|
||||
pat.replace(/^xmodule_js\/common_static\//, ''));
|
||||
}
|
||||
return pattern;
|
||||
return pat;
|
||||
}
|
||||
|
||||
function normalizePathsForCoverage(files, normalizeFunc, preprocessors) {
|
||||
@@ -200,7 +203,7 @@ function normalizePathsForCoverage(files, normalizeFunc, preprocessors) {
|
||||
normalizedFile,
|
||||
filesForCoverage = {};
|
||||
|
||||
files.forEach(function (file) {
|
||||
files.forEach(function(file) {
|
||||
if (!file.ignoreCoverage) {
|
||||
normalizedFile = normalizeFn(appRoot, file.pattern);
|
||||
if (preprocessors && preprocessors.hasOwnProperty(normalizedFile)) {
|
||||
@@ -222,17 +225,17 @@ function normalizePathsForCoverage(files, normalizeFunc, preprocessors) {
|
||||
* @return {Object}
|
||||
*/
|
||||
function setDefaults(files) {
|
||||
return files.map(function (f) {
|
||||
var file = _.isObject(f) ? f : { pattern: f };
|
||||
return files.map(function(f) {
|
||||
var file = _.isObject(f) ? f : {pattern: f};
|
||||
if (!file.included && !file.webpack) {
|
||||
f.included = false;
|
||||
file.included = false;
|
||||
}
|
||||
return file;
|
||||
});
|
||||
}
|
||||
|
||||
function getBaseConfig(config, useRequireJs) {
|
||||
var getFrameworkFiles = function () {
|
||||
var getFrameworkFiles = function() {
|
||||
var files = [
|
||||
'common/static/common/js/vendor/jquery.js',
|
||||
'node_modules/jasmine-core/lib/jasmine-core/jasmine.js',
|
||||
@@ -244,7 +247,7 @@ function getBaseConfig(config, useRequireJs) {
|
||||
'node_modules/bootstrap/dist/js/bootstrap.js',
|
||||
'node_modules/underscore/underscore.js',
|
||||
'node_modules/backbone/backbone.js',
|
||||
'common/static/js/test/i18n.js',
|
||||
'common/static/js/test/i18n.js'
|
||||
];
|
||||
|
||||
if (useRequireJs) {
|
||||
@@ -263,8 +266,8 @@ function getBaseConfig(config, useRequireJs) {
|
||||
// which isn't a karma plugin. Though a karma framework for jasmine-jquery is available
|
||||
// but it's not actively maintained. In future we also wanna add jQuery at the top when
|
||||
// we upgrade to jQuery 2
|
||||
var initFrameworks = function (files) {
|
||||
getFrameworkFiles().reverse().forEach(function (f) {
|
||||
var initFrameworks = function(files) {
|
||||
getFrameworkFiles().reverse().forEach(function(f) {
|
||||
files.unshift({
|
||||
pattern: path.join(appRoot, f),
|
||||
included: true,
|
||||
@@ -276,22 +279,21 @@ function getBaseConfig(config, useRequireJs) {
|
||||
|
||||
var hostname = 'localhost';
|
||||
var port = 9876;
|
||||
var customPlugin = {
|
||||
'framework:custom': ['factory', initFrameworks]
|
||||
};
|
||||
|
||||
if (process.env.hasOwnProperty('BOK_CHOY_HOSTNAME')) {
|
||||
hostname = process.env.BOK_CHOY_HOSTNAME;
|
||||
if (hostname === 'edx.devstack.lms') {
|
||||
port = 19876;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
port = 19877;
|
||||
}
|
||||
}
|
||||
|
||||
initFrameworks.$inject = ['config.files'];
|
||||
|
||||
var customPlugin = {
|
||||
'framework:custom': ['factory', initFrameworks]
|
||||
};
|
||||
|
||||
return {
|
||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
basePath: '',
|
||||
@@ -370,7 +372,7 @@ function getBaseConfig(config, useRequireJs) {
|
||||
ChromeDocker: {
|
||||
base: 'SeleniumWebdriver',
|
||||
browserName: 'chrome',
|
||||
getDriver: function () {
|
||||
getDriver: function() {
|
||||
return new webdriver.Builder()
|
||||
.forBrowser('chrome')
|
||||
.usingServer('http://edx.devstack.chrome:4444/wd/hub')
|
||||
@@ -380,7 +382,7 @@ function getBaseConfig(config, useRequireJs) {
|
||||
FirefoxDocker: {
|
||||
base: 'SeleniumWebdriver',
|
||||
browserName: 'firefox',
|
||||
getDriver: function () {
|
||||
getDriver: function() {
|
||||
var options = new firefox.Options(),
|
||||
profile = new firefox.Profile();
|
||||
profile.setPreference('focusmanager.testmode', true);
|
||||
@@ -419,44 +421,45 @@ function getBaseConfig(config, useRequireJs) {
|
||||
}
|
||||
|
||||
function configure(config, options) {
|
||||
var useRequireJs = options.useRequireJs === undefined ? true : useRequireJs,
|
||||
baseConfig = getBaseConfig(config, useRequireJs);
|
||||
var useRequireJs = options.useRequireJs === undefined ? true : options.useRequireJs,
|
||||
baseConfig = getBaseConfig(config, useRequireJs),
|
||||
files, filesForCoverage, preprocessors;
|
||||
|
||||
if (options.includeCommonFiles) {
|
||||
_.forEach(['libraryFiles', 'sourceFiles', 'specFiles', 'fixtureFiles'], function (collectionName) {
|
||||
_.forEach(['libraryFiles', 'sourceFiles', 'specFiles', 'fixtureFiles'], function(collectionName) {
|
||||
options[collectionName] = _.flatten([commonFiles[collectionName], options[collectionName]]);
|
||||
});
|
||||
}
|
||||
|
||||
var files = _.flatten(
|
||||
files = _.flatten(
|
||||
_.map(
|
||||
['libraryFilesToInclude', 'libraryFiles', 'sourceFiles', 'specFiles', 'fixtureFiles', 'runFiles'],
|
||||
function (collectionName) { return options[collectionName] || []; }
|
||||
function(collectionName) { return options[collectionName] || []; }
|
||||
)
|
||||
);
|
||||
|
||||
files.unshift(
|
||||
{ pattern: path.join(appRoot, 'common/static/common/js/jasmine.common.conf.js'), included: true }
|
||||
{pattern: path.join(appRoot, 'common/static/common/js/jasmine.common.conf.js'), included: true}
|
||||
);
|
||||
|
||||
if (useRequireJs) {
|
||||
files.unshift({ pattern: 'common/js/utils/require-serial.js', included: true });
|
||||
files.unshift({pattern: 'common/js/utils/require-serial.js', included: true});
|
||||
}
|
||||
|
||||
// Karma sets included=true by default.
|
||||
// We set it to false by default because RequireJS should be used instead.
|
||||
files = setDefaults(files);
|
||||
|
||||
var filesForCoverage = _.flatten(
|
||||
filesForCoverage = _.flatten(
|
||||
_.map(
|
||||
['sourceFiles', 'specFiles'],
|
||||
function (collectionName) { return options[collectionName]; }
|
||||
function(collectionName) { return options[collectionName]; }
|
||||
)
|
||||
);
|
||||
|
||||
// If we give symlink paths to Istanbul, coverage for each path gets tracked
|
||||
// separately. So we pass absolute paths to the karma-coverage preprocessor.
|
||||
var preprocessors = _.extend(
|
||||
preprocessors = _.extend(
|
||||
{},
|
||||
options.preprocessors,
|
||||
normalizePathsForCoverage(filesForCoverage, options.normalizePathsForCoverageFunc, options.preprocessors)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* Provides helper methods for invoking Studio modal windows in Jasmine tests.
|
||||
*/
|
||||
define(['jquery', 'common/js/components/views/feedback_notification', 'common/js/components/views/feedback_prompt',
|
||||
define(['underscore', 'jquery', 'common/js/components/views/feedback_notification', 'common/js/components/views/feedback_prompt',
|
||||
'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers'],
|
||||
function($, NotificationView, Prompt, AjaxHelpers) {
|
||||
function(_, $, NotificationView, Prompt, AjaxHelpers) {
|
||||
'use strict';
|
||||
var installViewTemplates, createFeedbackSpy, verifyFeedbackShowing,
|
||||
verifyFeedbackHidden, createNotificationSpy, verifyNotificationShowing,
|
||||
@@ -41,11 +41,11 @@ define(['jquery', 'common/js/components/views/feedback_notification', 'common/js
|
||||
return createFeedbackSpy(NotificationView, type || 'Mini');
|
||||
};
|
||||
|
||||
verifyNotificationShowing = function(notificationSpy, text) {
|
||||
verifyNotificationShowing = function() {
|
||||
verifyFeedbackShowing.apply(this, arguments);
|
||||
};
|
||||
|
||||
verifyNotificationHidden = function(notificationSpy) {
|
||||
verifyNotificationHidden = function() {
|
||||
verifyFeedbackHidden.apply(this, arguments);
|
||||
};
|
||||
|
||||
@@ -62,11 +62,11 @@ define(['jquery', 'common/js/components/views/feedback_notification', 'common/js
|
||||
}
|
||||
};
|
||||
|
||||
verifyPromptShowing = function(promptSpy, text) {
|
||||
verifyPromptShowing = function() {
|
||||
verifyFeedbackShowing.apply(this, arguments);
|
||||
};
|
||||
|
||||
verifyPromptHidden = function(promptSpy) {
|
||||
verifyPromptHidden = function() {
|
||||
verifyFeedbackHidden.apply(this, arguments);
|
||||
};
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
|
||||
this.XBlock.Runtime.v1 = (function() {
|
||||
function v1() {
|
||||
var _this = this;
|
||||
var block = this;
|
||||
this.childMap = function() {
|
||||
return v1.prototype.childMap.apply(_this, arguments);
|
||||
return v1.prototype.childMap.apply(block, arguments);
|
||||
};
|
||||
this.children = function() {
|
||||
return v1.prototype.children.apply(_this, arguments);
|
||||
return v1.prototype.children.apply(block, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,14 +17,15 @@
|
||||
};
|
||||
|
||||
v1.prototype.childMap = function(block, childName) {
|
||||
var child, _i, _len, _ref;
|
||||
_ref = this.children(block);
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
child = _ref[_i];
|
||||
var child, idx, len, ref;
|
||||
ref = this.children(block);
|
||||
for (idx = 0, len = ref.length; idx < len; idx++) {
|
||||
child = ref[idx];
|
||||
if (child.name === childName) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -323,7 +323,7 @@ def run_eslint(options):
|
||||
violations_limit = int(getattr(options, 'limit', -1))
|
||||
|
||||
sh(
|
||||
"eslint --ext .js --ext .jsx --format=compact . | tee {eslint_report}".format(
|
||||
"nodejs --max_old_space_size=4096 node_modules/.bin/eslint --ext .js --ext .jsx --format=compact . | tee {eslint_report}".format(
|
||||
eslint_report=eslint_report
|
||||
),
|
||||
ignore_error=True
|
||||
|
||||
@@ -14,14 +14,16 @@ var filesWithRequireJSBlocks = [
|
||||
path.resolve(__dirname, 'common/static/common/js/components/utils/view_utils.js'),
|
||||
/descriptors\/js/,
|
||||
/modules\/js/,
|
||||
/common\/lib\/xmodule\/xmodule\/js\/src\//,
|
||||
/common\/lib\/xmodule\/xmodule\/js\/src\//
|
||||
];
|
||||
|
||||
var defineHeader = /\(function ?\(((define|require|requirejs|\$)(, )?)+\) ?\{/;
|
||||
var defineCallFooter = /\}\)\.call\(this, ((define|require)( \|\| RequireJS\.(define|require))?(, )?)+?\);/;
|
||||
var defineDirectFooter = /\}\(((window\.)?(RequireJS\.)?(requirejs|define|require|jQuery)(, )?)+\)\);/;
|
||||
var defineFancyFooter = /\}\).call\(\s*this(\s|.)*define(\s|.)*\);/;
|
||||
var defineFooter = new RegExp('(' + defineCallFooter.source + ')|(' + defineDirectFooter.source + ')|(' + defineFancyFooter.source + ')', 'm');
|
||||
var defineFooter = new RegExp('(' + defineCallFooter.source + ')|('
|
||||
+ defineDirectFooter.source + ')|('
|
||||
+ defineFancyFooter.source + ')', 'm');
|
||||
|
||||
module.exports = {
|
||||
context: __dirname,
|
||||
@@ -335,7 +337,7 @@ module.exports = {
|
||||
'common/static/js/vendor/jQuery-File-Upload/js/',
|
||||
'common/static/js/vendor/tinymce/js/tinymce',
|
||||
'node_modules',
|
||||
'common/static/xmodule',
|
||||
'common/static/xmodule'
|
||||
]
|
||||
},
|
||||
|
||||
@@ -354,7 +356,7 @@ module.exports = {
|
||||
underscore: '_',
|
||||
URI: 'URI',
|
||||
XModule: 'XModule',
|
||||
XBlockToXModuleShim: 'XBlockToXModuleShim',
|
||||
XBlockToXModuleShim: 'XBlockToXModuleShim'
|
||||
},
|
||||
|
||||
watchOptions: {
|
||||
|
||||
Reference in New Issue
Block a user