diff --git a/common/lib/xmodule/xmodule/assets/word_cloud/.gitignore b/common/lib/xmodule/xmodule/assets/word_cloud/.gitignore new file mode 100644 index 0000000000..a48cf0de7a --- /dev/null +++ b/common/lib/xmodule/xmodule/assets/word_cloud/.gitignore @@ -0,0 +1 @@ +public diff --git a/common/lib/xmodule/xmodule/assets/word_cloud/public/js/word_cloud.js b/common/lib/xmodule/xmodule/assets/word_cloud/public/js/word_cloud.js deleted file mode 100644 index 130e88edcc..0000000000 --- a/common/lib/xmodule/xmodule/assets/word_cloud/public/js/word_cloud.js +++ /dev/null @@ -1,5 +0,0 @@ -window.WordCloud = function(el) { - RequireJS.require(['WordCloudMain'], function(WordCloudMain) { - new WordCloudMain(el); - }); -}; diff --git a/common/lib/xmodule/xmodule/assets/word_cloud/public/js/word_cloud_main.js b/common/lib/xmodule/xmodule/assets/word_cloud/public/js/word_cloud_main.js deleted file mode 100644 index 2a251eb30c..0000000000 --- a/common/lib/xmodule/xmodule/assets/word_cloud/public/js/word_cloud_main.js +++ /dev/null @@ -1,349 +0,0 @@ -/** - * @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 d3, $, RequireJS - */ - -(function(requirejs, require, define) { - 'use strict'; - define('WordCloudMain', [ - 'gettext', - 'edx-ui-toolkit/js/utils/html-utils' - ], function(gettext, HtmlUtils) { - 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. - */ - var WordCloudMain = function(el) { - var _this = 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( - _this.ajax_url + '/get_state', null, - function(response) { - if (response.status !== 'success') { - return; - } - - _this.configJson = response; - } - ) - .done(function() { - // Show WordCloud container after Ajax request done - _this.wordCloudEl.show(); - - if (_this.configJson && _this.configJson.submitted) { - _this.showWordCloud(_this.configJson); - - return; - } - }); - - $(el).find('.save').on('click', function() { - _this.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 = function() { - var _this = this, - data = {student_words: []}; - - // Populate the data to be sent to the server with user's words. - this.wordCloudEl.find('input.input-cloud').each(function(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( - _this.ajax_url + '/submit', $.param(data), - function(response) { - if (response.status !== 'success') { - return; - } - - _this.showWordCloud(response); - } - ); - }; // End-of: WordCloudMain.prototype.submitAnswer = function() { - - /** - * @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 = function(response) { - var words, - _this = this, - maxSize, minSize, scaleFactor, maxFontSize, minFontSize; - - this.wordCloudEl.find('.input_cloud_section').hide(); - - words = response.top_words; - maxSize = 0; - minSize = 10000; - scaleFactor = 1; - maxFontSize = 200; - minFontSize = 16; - - // Find the word with the maximum percentage. I.e. the most popular word. - $.each(words, function(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, function(index, word) { - var tempScaleFactor = 1.0, - size = ((word.size / maxSize) * maxFontSize); - - if (size * 0.7 * word.text.length > _this.width) { - tempScaleFactor = ((_this.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. - d3.layout.cloud().size([this.width, this.height]) - .words(words) - .rotate(function() { - return Math.floor((Math.random() * 2)) * 90; - }) - .font('Impact') - .fontSize(function(d) { - var size = (d.size / maxSize) * maxFontSize; - - size = size >= minFontSize ? size : minFontSize; - - return size; - }) - .on('end', function(words, bounds) { // eslint-disable-line no-shadow - // Draw the word cloud. - _this.drawWordCloud(response, words, 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 = function(response, words, bounds) { - // Color words in different colors. - var fill = d3.scale.category20(), - - // Will be populated by words the user enetered. - studentWordsKeys = [], - - // Comma separated string of user enetered words. - studentWordsStr, - - // By default we do not scale. - scale = 1, - - // Caсhing of DOM element - cloudSectionEl = this.wordCloudEl.find('.result_cloud_section'), - - // Needed for caсhing of d3 group elements - groupEl, - - // Iterator for word cloud count for uniqueness - 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, function(word, stat) { - var 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('
  • '), - startTag: HtmlUtils.HTML(''), - word: word, - endTag: HtmlUtils.HTML(''), - percent: percent, - listEnd: HtmlUtils.HTML('
  • ') - } - ).toString()); - }); - - 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(''), - end_strong: HtmlUtils.HTML(''), - total: response.total_count - } - ) - ); - - $(cloudSectionEl.attr('id') + ' .word_cloud').empty(); - - // Actual drawing of word cloud. - 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', function() { - wcCount = wcCount + 1; - return wcCount; - }) - .attr('aria-describedby', function() { - return HtmlUtils.interpolateHtml( - gettext('text_word_{uniqueId} title_word_{uniqueId}'), - { - uniqueId: generateUniqueId(cloudSectionEl.attr('id'), $(this).data('id')) - } - ); - }); - - groupEl - .append('title') - .attr('id', function() { - return HtmlUtils.interpolateHtml( - gettext('title_word_{uniqueId}'), - { - uniqueId: generateUniqueId(cloudSectionEl.attr('id'), $(this).parent().data('id')) - } - ); - }) - .text(function(d) { - var res = ''; - - $.each(response.top_words, function(index, value) { - if (value.text === d.text) { - res = value.percent + '%'; - - return; - } - }); - - return res; - }); - - groupEl - .append('text') - .attr('id', function() { - return HtmlUtils.interpolateHtml( - gettext('text_word_{uniqueId}'), - { - uniqueId: generateUniqueId(cloudSectionEl.attr('id'), $(this).parent().data('id')) - } - ); - }) - .style('font-size', function(d) { - return d.size + 'px'; - }) - .style('font-family', 'Impact') - .style('fill', function(d, i) { - return fill(i); - }) - .attr('text-anchor', 'middle') - .attr('transform', function(d) { - return 'translate(' + [d.x, d.y] + ')rotate(' + d.rotate + ')scale(' + scale + ')'; - }) - .text(function(d) { - return d.text; - }); - }; // End-of: WordCloudMain.prototype.drawWordCloud = function(words, bounds) { - return WordCloudMain; - }); // End-of: define('WordCloudMain', [], function() { -}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function(requirejs, require, define) { diff --git a/common/lib/xmodule/xmodule/assets/word_cloud/public/js/d3.layout.cloud.js b/common/lib/xmodule/xmodule/assets/word_cloud/src/js/d3.layout.cloud.js similarity index 100% rename from common/lib/xmodule/xmodule/assets/word_cloud/public/js/d3.layout.cloud.js rename to common/lib/xmodule/xmodule/assets/word_cloud/src/js/d3.layout.cloud.js diff --git a/common/lib/xmodule/xmodule/assets/word_cloud/public/js/d3.min.js b/common/lib/xmodule/xmodule/assets/word_cloud/src/js/d3.min.js similarity index 100% rename from common/lib/xmodule/xmodule/assets/word_cloud/public/js/d3.min.js rename to common/lib/xmodule/xmodule/assets/word_cloud/src/js/d3.min.js