From fd14695282199130cbac1f33695cc822553af559 Mon Sep 17 00:00:00 2001 From: Jochen Rick Date: Wed, 5 Oct 2016 15:17:22 -0400 Subject: [PATCH 1/2] paired distractor decoration --- runestone/parsons/css/parsons.css | 12 ++- runestone/parsons/js/parsons.js | 169 ++++++++++++++++++++++++++---- 2 files changed, 158 insertions(+), 23 deletions(-) diff --git a/runestone/parsons/css/parsons.css b/runestone/parsons/css/parsons.css index 9cdf28981..2825ee7da 100644 --- a/runestone/parsons/css/parsons.css +++ b/runestone/parsons/css/parsons.css @@ -24,7 +24,7 @@ padding-bottom: 10px; padding-left: 0; margin-left: 0; - border: 1px solid #efefff; + border: 1px solid #b8b8f2; } .parsons .source { background-color: #efefff; @@ -130,6 +130,16 @@ background-color: #ffbaba; border: 1px solid red; } +.parsons .paired { + position: absolute; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + border-radius: 10px; + background-color: transparent; + border: 20px solid #7373e5; + margin-top: 5px; + overflow: hidden; +} .parsons { border-left:0; border-right:0; diff --git a/runestone/parsons/js/parsons.js b/runestone/parsons/js/parsons.js index 9502a8034..9df383294 100644 --- a/runestone/parsons/js/parsons.js +++ b/runestone/parsons/js/parsons.js @@ -13,6 +13,43 @@ ======== Mike Hewner ===================================================================== */ +/* ===================================================================== +==== AdaptiveParsons Object ============================================ +======== Used for adapting problems based on previous performance +==== PROPERTIES ======================================================== +======== problem: the Parsons problem +======== store: the object as it is stored in localStorage +===================================================================== */ + +// Initialize +var AdaptiveParsons = function(problem) { + this.problem = problem; + store = localStorage.getItem("adaptiveParsons"); + if (store == undefined) { + store = {}; + } else { + store = JSON.parse(store); + } + this.store = store; +}; + +// Save the current value to localStorage +AdaptiveParsons.prototype.save = function() { + localStorage.setItem("adaptiveParsons", JSON.stringify(this.store)); +}; + +// When a check is done, note it +AdaptiveParsons.prototype.check = function() { + this.store["latest"] = this.problem.divid; + var count = this.store[this.problem.divid]; + if (count == undefined) { + count = 0; + } + count++; + this.store[this.problem.divid] = count; + this.save(); +}; + /* ===================================================================== ==== LineBasedGrader Object ============================================ ======== Used for grading a Parsons problem. @@ -384,6 +421,7 @@ Parsons.prototype.initializeOptions = function() { var maxdist = $(this.origElem).data('maxdist'); var order = $(this.origElem).data('order'); var noindent = $(this.origElem).data('noindent'); + var adaptive = $(this.origElem).data('adaptive'); if (maxdist !== undefined) { options["maxdist"] = maxdist; } @@ -399,6 +437,10 @@ Parsons.prototype.initializeOptions = function() { noindent = false; } options["noindent"] = noindent; + if (adaptive == undefined) { + adaptive = false; + } + options["adaptive"] = adaptive; // add locale and language var locale = eBookConfig.locale; if (locale == undefined) { @@ -466,7 +508,6 @@ Parsons.prototype.initializeView = function () { $(this.sourceArea).addClass("source"); this.sourceRegionDiv.appendChild(this.sourceArea); - this.answerRegionDiv = document.createElement("div"); this.answerRegionDiv.id = this.counterId + "-answerRegion"; $(this.answerRegionDiv).addClass("sortable-code"); @@ -578,7 +619,7 @@ Parsons.prototype.initializeLines = function(text) { for (i = 0; i < this.lines.length; i++) { line = this.lines[i]; line.indent = indents.indexOf(line.indent); - } + } this.solution = solution; }; @@ -663,6 +704,49 @@ Parsons.prototype.initializeAreas = function(sourceBlocks, answerBlocks) { } else { $(this.answerArea).addClass("answer"); } + + // Initialize paired distractor decoration + var bins = []; + var bin = []; + for (i = 0; i < this.lines.length; i++) { + var line = this.lines[i]; + bin.push(line); + if (!line.groupWithNext) { + bins.push(bin); + bin = []; + } + } + var pairedBins = []; + var lineNumbers = []; + for (i = bins.length - 1; i > -1; i--) { + bin = bins[i]; + if (bin[0].paired) { + // Add all in bin to line numbers + for (j = bin.length - 1; j > -1; j--) { + lineNumbers.unshift(bin[j].index); + } + } else { + if (lineNumbers.length > 0) { + // Add all in bin to line numbers + for (j = bin.length - 1; j > -1; j--) { + lineNumbers.unshift(bin[j].index); + } + pairedBins.unshift(lineNumbers); + lineNumbers = []; + } + } + } + var pairedDivs = []; + for (i = 0; i < pairedBins.length; i++) { + var pairedDiv = document.createElement("div"); + $(pairedDiv).addClass("paired"); + pairedDivs.push(pairedDiv); + this.sourceArea.appendChild(pairedDiv); + } + this.pairedBins = pairedBins; + this.pairedDivs = pairedDivs; + + // Update the view this.state = undefined; // needs to be here for loading from storage this.updateView(); @@ -883,8 +967,16 @@ Parsons.prototype.sourceHash = function() { return this.getHash(this.sourceArea); }; +// Return an array of code blocks adapted to performance on previous problems +Parsons.prototype.adaptiveBlocks = function() { + +}; + // Return an array of code blocks based on what is specified in the problem Parsons.prototype.blocksFromSource = function() { + if (this.options.adaptive) { + return this.adaptiveBlocks(); + } var unorderedBlocks = []; var blocks = []; var lines = []; @@ -1160,18 +1252,20 @@ Parsons.prototype.updateView = function() { // Update the Source Area if (updateSource) { positionTop = 0; + var children = this.sourceArea.childNodes; + var blocks = []; + for (i = 0; i < children.length; i++) { + item = children[i]; + if ($(item).hasClass("block")) { + blocks.push(item); + } + } if (newState == "source") { var hasInserted = false; var x = this.movingX - this.sourceArea.getBoundingClientRect().left - window.pageXOffset - baseWidth / 2 - 11; var y = this.movingY - this.sourceArea.getBoundingClientRect().top - window.pageYOffset; - var children = this.sourceArea.childNodes; - var childrenCopy = []; - for (i = 0; i < children.length; i++) { - childrenCopy.push(children[i]); - } - children = childrenCopy; - for (i = 0; i < children.length; i++) { - item = children[i]; + for (i = 0; i < blocks.length; i++) { + item = blocks[i]; if (!hasInserted) { if (y - positionTop < (movingHeight + $(item).outerHeight(true)) / 2) { hasInserted = true; @@ -1180,7 +1274,7 @@ Parsons.prototype.updateView = function() { 'left' : x, 'top' : y - movingHeight / 2, 'width' : baseWidth, - 'z-index' : 2 + 'z-index' : 3 }); positionTop = positionTop + movingHeight; } @@ -1189,7 +1283,7 @@ Parsons.prototype.updateView = function() { 'left' : 0, 'top' : positionTop, 'width' : baseWidth, - 'z-index' : 1 + 'z-index' : 2 }); positionTop = positionTop + $(item).outerHeight(true); } @@ -1199,22 +1293,53 @@ Parsons.prototype.updateView = function() { 'left' : x, 'top' : y - $(this.moving).outerHeight(true) / 2, 'width' : baseWidth, - 'z-index' : 2 + 'z-index' : 3 }); } } else { - var children = this.sourceArea.childNodes; - for (var i = 0; i < children.length; i++) { - item = children[i]; + for (var i = 0; i < blocks.length; i++) { + item = blocks[i]; $(item).css({ 'left' : 0, 'top' : positionTop, 'width' : baseWidth, - 'z-index' : 1 + 'z-index' : 2 }); positionTop = positionTop + $(item).outerHeight(true); } } + // Update the Paired Distractor Indicators + for (i = 0; i < this.pairedBins.length; i++) { + var bin = this.pairedBins[i]; + var matching = []; + for (j = 0; j < blocks.length; j++) { + block = blocks[j]; + if (bin.includes(this.getBlockById(block.id).lines[0].index)) { + matching.push(block); + } else { + if (matching.length == 1) { + matching = []; + } + } + } + var div = this.pairedDivs[i]; + if (matching.length < 2) { + $(div).hide(); + } else { + $(div).show(); + var height = -5; + height += parseInt($(matching[matching.length - 1]).css("top")); + height -= parseInt($(matching[0]).css("top")); + height += $(matching[matching.length - 1]).outerHeight(true); + $(div).css({ + 'left' : -10, + 'top' : $(matching[0]).css("top"), + 'width' : baseWidth + 42, + 'height' : height, + 'z-index' : 1 + }); + } + } } // Update the Answer Area @@ -1252,7 +1377,7 @@ Parsons.prototype.updateView = function() { 'left' : x, 'top' : y - movingHeight / 2, 'width' : baseWidth, - 'z-index' : 2 + 'z-index' : 3 }); positionTop = positionTop + movingHeight; } @@ -1263,7 +1388,7 @@ Parsons.prototype.updateView = function() { 'left' : indent, 'top' : positionTop, 'width' : width - indent, - 'z-index' : 1 + 'z-index' : 2 }); positionTop = positionTop + $(item).outerHeight(true); } @@ -1273,7 +1398,7 @@ Parsons.prototype.updateView = function() { 'left' : x, 'top' : y - $(this.moving).outerHeight(true) / 2, 'width' : baseWidth, - 'z-index' : 2 + 'z-index' : 3 }); } } else { @@ -1286,7 +1411,7 @@ Parsons.prototype.updateView = function() { 'left' : indent, 'top' : positionTop, 'width' : width - indent, - 'z-index' : 1 + 'z-index' : 2 }); positionTop = positionTop + $(item).outerHeight(true); } @@ -1300,7 +1425,7 @@ Parsons.prototype.updateView = function() { 'left' : this.movingX - this.sourceArea.getBoundingClientRect().left - window.pageXOffset - ($(this.moving).outerWidth(true) / 2), 'top' : this.movingY - this.sourceArea.getBoundingClientRect().top - window.pageYOffset - (movingHeight / 2), 'width' : baseWidth, - 'z-index' : 2 + 'z-index' : 3 }); } From ddb1cf80708ce62649347b1098e5e2d9100c3587 Mon Sep 17 00:00:00 2001 From: Jochen Rick Date: Thu, 13 Oct 2016 11:56:58 -0400 Subject: [PATCH 2/2] Paired Distractor CSS --- runestone/parsons/css/parsons.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runestone/parsons/css/parsons.css b/runestone/parsons/css/parsons.css index 2825ee7da..e327681c0 100644 --- a/runestone/parsons/css/parsons.css +++ b/runestone/parsons/css/parsons.css @@ -136,7 +136,7 @@ -webkit-border-radius: 10px; border-radius: 10px; background-color: transparent; - border: 20px solid #7373e5; + border: 11px solid #b8b8f2; margin-top: 5px; overflow: hidden; }