From 4dc7aa13867527b124dc9f8fc5aa2e775cb1d896 Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Fri, 18 Dec 2015 18:12:17 +0700 Subject: [PATCH 1/6] Added spinner to initial load notification --- drag_and_drop_v2/templates/html/drag_and_drop.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drag_and_drop_v2/templates/html/drag_and_drop.html b/drag_and_drop_v2/templates/html/drag_and_drop.html index c82680559..7fd93ec81 100644 --- a/drag_and_drop_v2/templates/html/drag_and_drop.html +++ b/drag_and_drop_v2/templates/html/drag_and_drop.html @@ -1,4 +1,4 @@ {% load i18n %}
- {% trans "Loading drag and drop exercise." %} + {% trans "Loading drag and drop exercise." %}
From a62272d94c5bbb6f2c4d6d38f2cec6fa7b49dcee Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Fri, 18 Dec 2015 19:12:58 +0700 Subject: [PATCH 2/6] Spinners for droppable elements --- drag_and_drop_v2/public/css/drag_and_drop.css | 10 ++++++ drag_and_drop_v2/public/js/drag_and_drop.js | 34 +++++++++++-------- drag_and_drop_v2/public/js/view.js | 12 ++++++- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/drag_and_drop_v2/public/css/drag_and_drop.css b/drag_and_drop_v2/public/css/drag_and_drop.css index 57ce76b6a..a196e4a4d 100644 --- a/drag_and_drop_v2/public/css/drag_and_drop.css +++ b/drag_and_drop_v2/public/css/drag_and_drop.css @@ -76,6 +76,16 @@ z-index: 10 !important; } +.xblock--drag-and-drop .drag-container .option .spinner-wrapper { + margin-right: 3px; + float: left; + display: none; +} + +.xblock--drag-and-drop .drag-container .option .item-content { + display: inline-block; +} + /* Placed option */ .xblock--drag-and-drop .drag-container .target .option { position: absolute; diff --git a/drag_and_drop_v2/public/js/drag_and_drop.js b/drag_and_drop_v2/public/js/drag_and_drop.js index c1a2e1aa2..4a0483dd7 100644 --- a/drag_and_drop_v2/public/js/drag_and_drop.js +++ b/drag_and_drop_v2/public/js/drag_and_drop.js @@ -202,20 +202,26 @@ function DragAndDropBlock(runtime, element, configuration) { x_percent: x_percent, y_percent: y_percent, }; - $.post(url, JSON.stringify(data), 'json').done(function(data){ - if (data.correct_location) { - state.items[item_id].correct_input = Boolean(data.correct); - state.items[item_id].submitting_location = false; - } else { - delete state.items[item_id]; - } - state.feedback = data.feedback; - if (data.finished) { - state.finished = true; - state.overall_feedback = data.overall_feedback; - } - applyState(); - }); + var $item = $root.find(".option[data-value='"+item_id+"']"); + $item.find('.spinner-wrapper').show(); + + $.post(url, JSON.stringify(data), 'json') + .done(function(data){ + if (data.correct_location) { + state.items[item_id].correct_input = Boolean(data.correct); + state.items[item_id].submitting_location = false; + } else { + delete state.items[item_id]; + } + state.feedback = data.feedback; + if (data.finished) { + state.finished = true; + state.overall_feedback = data.overall_feedback; + } + $item.find('.spinner-wrapper').hide(); + applyState(); + }) + .fail(function (data) { $item.find('.spinner-wrapper').hide(); }); }; var submitInput = function(evt) { diff --git a/drag_and_drop_v2/public/js/view.js b/drag_and_drop_v2/public/js/view.js index 466d0f58a..d790d152f 100644 --- a/drag_and_drop_v2/public/js/view.js +++ b/drag_and_drop_v2/public/js/view.js @@ -18,6 +18,15 @@ }, 0); }; + var itemSpinnerTemplate = function() { + return (h( + "div.spinner-wrapper", + [ + h("i.fa.fa-spin.fa-spinner") + ] + )); + }; + var renderCollection = function(template, collection, ctx) { return collection.map(function(item) { return template(item, ctx); @@ -59,7 +68,8 @@ attributes: {'data-value': item.value, 'data-drag-disabled': item.drag_disabled}, style: style }, [ - h('div', {innerHTML: item.content_html}), + itemSpinnerTemplate(), + h('div', {innerHTML: item.content_html, className: "item-content"}), itemInputTemplate(item.input) ] ) From cc7bc7ea1416d18e3571872ccba4c175da596792 Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Mon, 21 Dec 2015 17:32:34 +0700 Subject: [PATCH 3/6] Spinners for inputs --- drag_and_drop_v2/public/css/drag_and_drop.css | 13 +++++++ drag_and_drop_v2/public/js/drag_and_drop.js | 38 ++++++++++++------- drag_and_drop_v2/public/js/view.js | 1 + 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/drag_and_drop_v2/public/css/drag_and_drop.css b/drag_and_drop_v2/public/css/drag_and_drop.css index a196e4a4d..d520de0d4 100644 --- a/drag_and_drop_v2/public/css/drag_and_drop.css +++ b/drag_and_drop_v2/public/css/drag_and_drop.css @@ -112,6 +112,19 @@ top: calc(50% - 16px); } +.xblock--drag-and-drop .drag-container .option .numerical-input .spinner-wrapper { + position: absolute; + right: 0; + top: 0; + margin-right: 5px; + padding-top: 6px; + display: none; +} + +.xblock--drag-and-drop .drag-container .option .numerical-input .spinner-wrapper { + color: #333; +} + .xblock--drag-and-drop .drag-container .option .numerical-input .input { display: inline-block; width: 144px; diff --git a/drag_and_drop_v2/public/js/drag_and_drop.js b/drag_and_drop_v2/public/js/drag_and_drop.js index 4a0483dd7..41a9c5019 100644 --- a/drag_and_drop_v2/public/js/drag_and_drop.js +++ b/drag_and_drop_v2/public/js/drag_and_drop.js @@ -191,6 +191,14 @@ function DragAndDropBlock(runtime, element, configuration) { }); }; + var showSpinner = function($item) { + $item.find('.spinner-wrapper').show(); + }; + + var hideSpinner = function($item) { + $item.find('.spinner-wrapper').hide(); + }; + var submitLocation = function(item_id, zone, x_percent, y_percent) { if (!zone) { return; @@ -203,7 +211,7 @@ function DragAndDropBlock(runtime, element, configuration) { y_percent: y_percent, }; var $item = $root.find(".option[data-value='"+item_id+"']"); - $item.find('.spinner-wrapper').show(); + showSpinner($item); $.post(url, JSON.stringify(data), 'json') .done(function(data){ @@ -218,10 +226,10 @@ function DragAndDropBlock(runtime, element, configuration) { state.finished = true; state.overall_feedback = data.overall_feedback; } - $item.find('.spinner-wrapper').hide(); + hideSpinner($item); applyState(); }) - .fail(function (data) { $item.find('.spinner-wrapper').hide(); }); + .fail(function (data) { hideSpinner($item); }); }; var submitInput = function(evt) { @@ -236,22 +244,26 @@ function DragAndDropBlock(runtime, element, configuration) { return; } + showSpinner(input_div); state.items[item_id].input = input_value; state.items[item_id].submitting_input = true; applyState(); var url = runtime.handlerUrl(element, 'do_attempt'); var data = {val: item_id, input: input_value}; - $.post(url, JSON.stringify(data), 'json').done(function(data) { - state.items[item_id].submitting_input = false; - state.items[item_id].correct_input = data.correct; - state.feedback = data.feedback; - if (data.finished) { - state.finished = true; - state.overall_feedback = data.overall_feedback; - } - applyState(); - }); + $.post(url, JSON.stringify(data), 'json') + .done(function(data) { + state.items[item_id].submitting_input = false; + state.items[item_id].correct_input = data.correct; + state.feedback = data.feedback; + if (data.finished) { + state.finished = true; + state.overall_feedback = data.overall_feedback; + } + hideSpinner(input_div); + applyState(); + }) + .fail(function(data) { hideSpinner(input_div); }); }; var closePopup = function(evt) { diff --git a/drag_and_drop_v2/public/js/view.js b/drag_and_drop_v2/public/js/view.js index d790d152f..a9c91e982 100644 --- a/drag_and_drop_v2/public/js/view.js +++ b/drag_and_drop_v2/public/js/view.js @@ -43,6 +43,7 @@ style: {display: input.is_visible ? 'block' : 'none'}}, [ h('input.input', {type: 'text', value: input.value, disabled: input.has_value, focusHook: focus_hook}), + itemSpinnerTemplate(), h('button.submit-input', {disabled: input.has_value}, gettext('ok')) ]) ); From 834fb7fcf049f80cb6b72c523d8f3ef2ce608e01 Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Tue, 22 Dec 2015 13:59:02 +0700 Subject: [PATCH 4/6] Initial load spinner margin --- drag_and_drop_v2/public/css/drag_and_drop.css | 7 ++++--- drag_and_drop_v2/templates/html/drag_and_drop.html | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drag_and_drop_v2/public/css/drag_and_drop.css b/drag_and_drop_v2/public/css/drag_and_drop.css index d520de0d4..a3003e2b5 100644 --- a/drag_and_drop_v2/public/css/drag_and_drop.css +++ b/drag_and_drop_v2/public/css/drag_and_drop.css @@ -5,6 +5,10 @@ padding: 0; } +.xblock--drag-and-drop .initial-load-spinner { + margin-right: 3px; +} + /* Header, instruction text, etc. */ .xblock--drag-and-drop .problem-header { @@ -119,9 +123,6 @@ margin-right: 5px; padding-top: 6px; display: none; -} - -.xblock--drag-and-drop .drag-container .option .numerical-input .spinner-wrapper { color: #333; } diff --git a/drag_and_drop_v2/templates/html/drag_and_drop.html b/drag_and_drop_v2/templates/html/drag_and_drop.html index 7fd93ec81..90f5ed683 100644 --- a/drag_and_drop_v2/templates/html/drag_and_drop.html +++ b/drag_and_drop_v2/templates/html/drag_and_drop.html @@ -1,4 +1,4 @@ {% load i18n %}
- {% trans "Loading drag and drop exercise." %} + {% trans "Loading drag and drop exercise." %}
From 7fb5cfc9d6eb15cad9210557a81e6d3fdabeac1c Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Tue, 22 Dec 2015 14:11:51 +0700 Subject: [PATCH 5/6] Virtual DOM instead of explicit hide/show --- drag_and_drop_v2/public/css/drag_and_drop.css | 2 -- drag_and_drop_v2/public/js/drag_and_drop.js | 25 ++++++++----------- drag_and_drop_v2/public/js/view.js | 9 ++++--- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/drag_and_drop_v2/public/css/drag_and_drop.css b/drag_and_drop_v2/public/css/drag_and_drop.css index a3003e2b5..ad4962f46 100644 --- a/drag_and_drop_v2/public/css/drag_and_drop.css +++ b/drag_and_drop_v2/public/css/drag_and_drop.css @@ -83,7 +83,6 @@ .xblock--drag-and-drop .drag-container .option .spinner-wrapper { margin-right: 3px; float: left; - display: none; } .xblock--drag-and-drop .drag-container .option .item-content { @@ -122,7 +121,6 @@ top: 0; margin-right: 5px; padding-top: 6px; - display: none; color: #333; } diff --git a/drag_and_drop_v2/public/js/drag_and_drop.js b/drag_and_drop_v2/public/js/drag_and_drop.js index 41a9c5019..2b5fa3a43 100644 --- a/drag_and_drop_v2/public/js/drag_and_drop.js +++ b/drag_and_drop_v2/public/js/drag_and_drop.js @@ -191,14 +191,6 @@ function DragAndDropBlock(runtime, element, configuration) { }); }; - var showSpinner = function($item) { - $item.find('.spinner-wrapper').show(); - }; - - var hideSpinner = function($item) { - $item.find('.spinner-wrapper').hide(); - }; - var submitLocation = function(item_id, zone, x_percent, y_percent) { if (!zone) { return; @@ -210,8 +202,6 @@ function DragAndDropBlock(runtime, element, configuration) { x_percent: x_percent, y_percent: y_percent, }; - var $item = $root.find(".option[data-value='"+item_id+"']"); - showSpinner($item); $.post(url, JSON.stringify(data), 'json') .done(function(data){ @@ -226,10 +216,12 @@ function DragAndDropBlock(runtime, element, configuration) { state.finished = true; state.overall_feedback = data.overall_feedback; } - hideSpinner($item); applyState(); }) - .fail(function (data) { hideSpinner($item); }); + .fail(function (data) { + delete state.items[item_id]; + applyState(); + }); }; var submitInput = function(evt) { @@ -244,7 +236,6 @@ function DragAndDropBlock(runtime, element, configuration) { return; } - showSpinner(input_div); state.items[item_id].input = input_value; state.items[item_id].submitting_input = true; applyState(); @@ -260,10 +251,12 @@ function DragAndDropBlock(runtime, element, configuration) { state.finished = true; state.overall_feedback = data.overall_feedback; } - hideSpinner(input_div); applyState(); }) - .fail(function(data) { hideSpinner(input_div); }); + .fail(function(data) { + state.items[item_id].submitting_input = false; + applyState(); + }); }; var closePopup = function(evt) { @@ -311,6 +304,7 @@ function DragAndDropBlock(runtime, element, configuration) { has_value: Boolean(item_user_state && 'input' in item_user_state), value : (item_user_state && item_user_state.input) || '', class_name: undefined, + xhr_active: (item_user_state && item_user_state.submitting_input) }; if (input.has_value && !item_user_state.submitting_input) { input.class_name = item_user_state.correct_input ? 'correct' : 'incorrect'; @@ -320,6 +314,7 @@ function DragAndDropBlock(runtime, element, configuration) { value: item.id, drag_disabled: Boolean(item_user_state || state.finished), class_name: item_user_state && ('input' in item_user_state || item_user_state.correct_input) ? 'fade': undefined, + xhr_active: (item_user_state && item_user_state.submitting_location), input: input, content_html: item.backgroundImage ? '' : item.displayName }; diff --git a/drag_and_drop_v2/public/js/view.js b/drag_and_drop_v2/public/js/view.js index a9c91e982..783d14513 100644 --- a/drag_and_drop_v2/public/js/view.js +++ b/drag_and_drop_v2/public/js/view.js @@ -18,7 +18,10 @@ }, 0); }; - var itemSpinnerTemplate = function() { + var itemSpinnerTemplate = function(xhr_active) { + if (!xhr_active) { + return null; + } return (h( "div.spinner-wrapper", [ @@ -43,7 +46,7 @@ style: {display: input.is_visible ? 'block' : 'none'}}, [ h('input.input', {type: 'text', value: input.value, disabled: input.has_value, focusHook: focus_hook}), - itemSpinnerTemplate(), + itemSpinnerTemplate(input.xhr_active), h('button.submit-input', {disabled: input.has_value}, gettext('ok')) ]) ); @@ -69,7 +72,7 @@ attributes: {'data-value': item.value, 'data-drag-disabled': item.drag_disabled}, style: style }, [ - itemSpinnerTemplate(), + itemSpinnerTemplate(item.xhr_active), h('div', {innerHTML: item.content_html, className: "item-content"}), itemInputTemplate(item.input) ] From 0e723306bc6f830e6dfe4f44b0f8a775567d8561 Mon Sep 17 00:00:00 2001 From: "E. Kolpakov" Date: Tue, 22 Dec 2015 14:36:33 +0700 Subject: [PATCH 6/6] Overlay-style spinner for items with images --- drag_and_drop_v2/public/css/drag_and_drop.css | 16 ++++++++++++++++ drag_and_drop_v2/public/js/drag_and_drop.js | 3 ++- drag_and_drop_v2/public/js/view.js | 6 +++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drag_and_drop_v2/public/css/drag_and_drop.css b/drag_and_drop_v2/public/css/drag_and_drop.css index ad4962f46..ac54f0859 100644 --- a/drag_and_drop_v2/public/css/drag_and_drop.css +++ b/drag_and_drop_v2/public/css/drag_and_drop.css @@ -85,6 +85,22 @@ float: left; } +.xblock--drag-and-drop .drag-container .option.option-with-image .spinner-wrapper { + position: absolute; + float: none; + left: 0; + right: 0; + top: 0; + bottom: 0; + background-color: #000; + opacity: 0.6; + color: #fff; + margin: 0; + display: flex; + justify-content: center; /* align horizontal */ + align-items: center; /* align vertical */ +} + .xblock--drag-and-drop .drag-container .option .item-content { display: inline-block; } diff --git a/drag_and_drop_v2/public/js/drag_and_drop.js b/drag_and_drop_v2/public/js/drag_and_drop.js index 2b5fa3a43..c56b64341 100644 --- a/drag_and_drop_v2/public/js/drag_and_drop.js +++ b/drag_and_drop_v2/public/js/drag_and_drop.js @@ -316,7 +316,8 @@ function DragAndDropBlock(runtime, element, configuration) { class_name: item_user_state && ('input' in item_user_state || item_user_state.correct_input) ? 'fade': undefined, xhr_active: (item_user_state && item_user_state.submitting_location), input: input, - content_html: item.backgroundImage ? '' : item.displayName + content_html: item.backgroundImage ? '' : item.displayName, + has_image: !!item.backgroundImage }; if (item_user_state) { itemProperties.is_placed = true; diff --git a/drag_and_drop_v2/public/js/view.js b/drag_and_drop_v2/public/js/view.js index 783d14513..22f8ab4a3 100644 --- a/drag_and_drop_v2/public/js/view.js +++ b/drag_and_drop_v2/public/js/view.js @@ -54,6 +54,7 @@ var itemTemplate = function(item) { var style = {}; + var className = (item.class_name) ? item.class_name : ""; if (item.background_color) { style['background-color'] = item.background_color; } @@ -64,11 +65,14 @@ style.left = item.x_percent + "%"; style.top = item.y_percent + "%"; } + if (item.has_image) { + className += " " + "option-with-image"; + } return ( h('div.option', { key: item.value, - className: item.class_name, + className: className, attributes: {'data-value': item.value, 'data-drag-disabled': item.drag_disabled}, style: style }, [