diff --git a/xblocks_contrib/word_cloud/static/js/src/word_cloud.js b/xblocks_contrib/word_cloud/static/js/src/word_cloud.js
index 728e652..475f1fd 100644
--- a/xblocks_contrib/word_cloud/static/js/src/word_cloud.js
+++ b/xblocks_contrib/word_cloud/static/js/src/word_cloud.js
@@ -27,44 +27,20 @@ function generateUniqueId(wordCloudId, counter) {
}
function WordCloudBlock(runtime, element) {
-
- // eslint-disable-next-line no-undef
- const wordCloudEl = $(element).find(blockIdentifier);
-
- // Get the URL to which we will post the users words.
- const ajax_url = wordCloudEl.data('ajax-url');
-
- // Hide WordCloud container until Ajax request is complete.
- wordCloudEl.hide();
-
- // Fetch initial state via AJAX request. Attach a callback that will
- // be fired on server's response.
- // eslint-disable-next-line no-undef
- $.postWithPrefix(
- `${ajax_url}/get_state`,
- null,
- (response) => {
- if (response.status !== 'success') {
- console.error('Failed to fetch state');
- return;
+ $.ajax({
+ type: "POST",
+ url: runtime.handlerUrl(element, 'handle_get_state'),
+ data: JSON.stringify(null),
+ success: function (response) {
+ if (response && response.submitted) {
+ showWordCloud(response, element);
}
-
- configJson = response;
- if (configJson && configJson.submitted) {
- showWordCloud(configJson, wordCloudEl);
- }
-
- },
- )
- .done(() => {
- // Show WordCloud container after Ajax request done
- wordCloudEl.show();
- });
-
- // eslint-disable-next-line no-undef
- $(element).find('.save').on('click', () => {
- submitAnswer(ajax_url, wordCloudEl);
+ }
});
+
+ $('.save', element).on('click', () =>
+ submitAnswer(runtime, element)
+ );
}
/**
@@ -74,32 +50,23 @@ function WordCloudBlock(runtime, element) {
* server, and upon receiving correct response, will call the function to generate the
* word cloud.
*/
-function submitAnswer(ajax_url, wordCloudEl)
-{
+function submitAnswer(runtime, element) {
+ const wordCloudEl = $(element).find(blockIdentifier);
const data = {student_words: []};
- // Populate the data to be sent to the server with user's words.
wordCloudEl.find('input.input-cloud').each((index, value) => {
// eslint-disable-next-line no-undef
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.
- // eslint-disable-next-line no-undef
- $.postWithPrefix(
- `${ajax_url}/submit`,
- // eslint-disable-next-line no-undef
- $.param(data),
- (response) => {
- if (response.status !== 'success') {
- console.error('Submission failed');
- return;
- }
-
- showWordCloud(response, wordCloudEl);
- },
- );
+ $.ajax({
+ type: "POST",
+ url: runtime.handlerUrl(element, 'handle_submit_state'),
+ data: JSON.stringify(data),
+ success: function (response) {
+ showWordCloud(response, element);
+ }
+ });
}
/**
@@ -111,7 +78,7 @@ function submitAnswer(ajax_url, wordCloudEl)
* This function will set up everything for d3 and launch the draw method. Among other things,
* iw will determine maximum word size.
*/
-function showWordCloud(response, wordCloudEl)
+function showWordCloud(response, element)
{
const words = response.top_words;
let maxSize = 0;
@@ -120,6 +87,7 @@ function showWordCloud(response, wordCloudEl)
let maxFontSize = 200;
const minFontSize = 16;
+ const wordCloudEl = $(element).find(blockIdentifier);
wordCloudEl.find('.input_cloud_section').hide();
// Find the word with the maximum percentage. I.e. the most popular word.
diff --git a/xblocks_contrib/word_cloud/templates/word_cloud.html b/xblocks_contrib/word_cloud/templates/word_cloud.html
index 7c57b37..ec009a5 100644
--- a/xblocks_contrib/word_cloud/templates/word_cloud.html
+++ b/xblocks_contrib/word_cloud/templates/word_cloud.html
@@ -2,8 +2,7 @@
+ class="word_cloud_block">
{% if display_name %}
{{ display_name }}
{% endif %}
diff --git a/xblocks_contrib/word_cloud/word_cloud.py b/xblocks_contrib/word_cloud/word_cloud.py
index d40ebde..387625f 100644
--- a/xblocks_contrib/word_cloud/word_cloud.py
+++ b/xblocks_contrib/word_cloud/word_cloud.py
@@ -13,8 +13,6 @@
from xblock.utils.resources import ResourceLoader
from xblock.utils.studio_editable import StudioEditableXBlockMixin
-from xblocks_contrib.utils.mixins.x_module import XModuleToXBlockMixin
-
resource_loader = ResourceLoader(__name__)
@@ -37,11 +35,7 @@ def pretty_bool(value):
return value in bool_dict
-class WordCloudBlock(
- StudioEditableXBlockMixin,
- XBlock,
- XModuleToXBlockMixin,
-):
+class WordCloudBlock(StudioEditableXBlockMixin, XBlock):
"""
Word Cloud XBlock.
"""
@@ -135,7 +129,6 @@ def student_view(self, context=None): # pylint: disable=W0613
frag = Fragment()
frag.add_content(resource_loader.render_django_template(
"templates/word_cloud.html", {
- 'ajax_url': self.ajax_url,
'display_name': self.display_name,
'instructions': self.instructions,
'element_id': self.scope_ids.usage_id.html_id(),
@@ -176,6 +169,92 @@ def top_dict(self, dict_obj, amount):
)[:amount]
)
+ def get_state(self):
+ """Return success json answer for client."""
+ if self.submitted:
+ total_count = sum(self.all_words.values())
+ return {
+ 'status': 'success',
+ 'submitted': True,
+ 'display_student_percents': pretty_bool(
+ self.display_student_percents
+ ),
+ 'student_words': {
+ word: self.all_words[word] for word in self.student_words
+ },
+ 'total_count': total_count,
+ 'top_words': self.prepare_words(self.top_words, total_count),
+ }
+ else:
+ return {
+ 'status': 'success',
+ 'submitted': False,
+ 'display_student_percents': False,
+ 'student_words': {},
+ 'total_count': 0,
+ 'top_words': {}
+ }
+
+ @XBlock.json_handler
+ def handle_get_state(self, data, suffix=''): # pylint: disable=unused-argument
+ """
+ AJAX handler to get the current state of the XBlock
+
+ Args:
+ data: dict having request get parameters
+
+ Returns:
+ json string
+ """
+ return self.get_state()
+
+ @XBlock.json_handler
+ def handle_submit_state(self, data, suffix=''): # pylint: disable=unused-argument
+ """
+ AJAX handler to submit the current state of the XBlock
+
+ Args:
+ data: dict having request get parameters
+
+ Returns:
+ json string
+ """
+
+ if self.submitted:
+ return {
+ 'status': 'fail',
+ 'error': 'You have already posted your data.'
+ }
+
+ # Student words from client.
+ # FIXME: we must use raw JSON, not a post data (multipart/form-data)
+ raw_student_words = data.get('student_words')
+ student_words = [word for word in map(self.good_word, raw_student_words) if word]
+
+ self.student_words = student_words
+
+ # FIXME: fix this, when xblock will support mutable types.
+ # Now we use this hack.
+ # speed issues
+ temp_all_words = self.all_words
+
+ self.submitted = True
+
+ # Save in all_words.
+ for word in self.student_words:
+ temp_all_words[word] = temp_all_words.get(word, 0) + 1
+
+ # Update top_words.
+ self.top_words = self.top_dict(
+ temp_all_words,
+ self.num_top_words
+ )
+
+ # Save all_words in database.
+ self.all_words = temp_all_words
+
+ return self.get_state()
+
def prepare_words(self, top_words, total_count):
"""Convert words dictionary for client API.
@@ -286,29 +365,3 @@ def handle_ajax(self, dispatch, data):
'status': 'fail',
'error': 'Unknown Command!'
})
-
- def get_state(self):
- """Return success json answer for client."""
- if self.submitted:
- total_count = sum(self.all_words.values())
- return json.dumps({
- 'status': 'success',
- 'submitted': True,
- 'display_student_percents': pretty_bool(
- self.display_student_percents
- ),
- 'student_words': {
- word: self.all_words[word] for word in self.student_words
- },
- 'total_count': total_count,
- 'top_words': self.prepare_words(self.top_words, total_count)
- })
- else:
- return json.dumps({
- 'status': 'success',
- 'submitted': False,
- 'display_student_percents': False,
- 'student_words': {},
- 'total_count': 0,
- 'top_words': {}
- })