Repository: chanind/hanzi-writer
Pull request #187 (2020-09-10 02:53:44)

fix(Quiz) Don't highlight stroke when setting "showHintAfterMisses" to false
The docs mention in multiple places that setting "showHintAfterMisses" to false will disable hint stroke highlighting. This isn't the case and instead highlights after every mistake. This commit fixes the issue.

chanind: Really good catch! Could you add a test for this too?
jamsch: All good, I've added the test

Patch:
diff --git a/src/HanziWriter.js b/src/HanziWriter.js
index af05deba..dfdf3c75 100644
--- a/src/HanziWriter.js
+++ b/src/HanziWriter.js
@@ -227,7 +227,7 @@ HanziWriter.prototype.setCharacter = function(char) {
     this._renderState = new RenderState(this._character, this._options, (nextState) => {
       hanziWriterRenderer.render(nextState);
     });
-    this._hanziWriterRenderer.mount(this.target, this._renderState.state);
+    this._hanziWriterRenderer.mount(this.target);
     this._hanziWriterRenderer.render(this._renderState.state);
   });
   return this._withDataPromise;
@@ -299,12 +299,12 @@ HanziWriter.prototype._withData = function(func) {
 
 HanziWriter.prototype._setupListeners = function() {
   this.target.addPointerStartListener((evt) => {
-    if (this.isLoadingCharData || !this._quiz) return;
+    if (!this._quiz) return;
     evt.preventDefault();
     this._forwardToQuiz('startUserStroke', evt.getPoint());
   });
   this.target.addPointerMoveListener((evt) => {
-    if (this.isLoadingCharData || !this._quiz) return;
+    if (!this._quiz) return;
     evt.preventDefault();
     this._forwardToQuiz('continueUserStroke', evt.getPoint());
   });
diff --git a/src/Quiz.js b/src/Quiz.js
index d4bd10e2..2d359805 100644
--- a/src/Quiz.js
+++ b/src/Quiz.js
@@ -25,7 +25,6 @@ Quiz.prototype.startQuiz = function(options) {
   this._currentStrokeIndex = 0;
   this._numRecentMistakes = 0;
   this._totalMistakes = 0;
-  this._drawnStrokes = [];
   this._renderState.run(quizActions.startQuiz(this._character, options.strokeFadeDuration));
 };
 
@@ -66,10 +65,10 @@ Quiz.prototype.endUserStroke = function() {
   });
 
   if (isMatch) {
-    this._handleSuccess(currentStroke);
+    this._handleSuccess();
   } else {
     this._handleFailure();
-    if (this._numRecentMistakes >= this._options.showHintAfterMisses) {
+    if (this._numRecentMistakes >= this._options.showHintAfterMisses && this._options.showHintAfterMisses !== false) {
       this._renderState.run(
         quizActions.highlightStroke(currentStroke, this._options.highlightColor, this._options.strokeHighlightSpeed),
       );
@@ -85,7 +84,7 @@ Quiz.prototype.cancel = function() {
   }
 };
 
-Quiz.prototype._handleSuccess = function(stroke) {
+Quiz.prototype._handleSuccess = function() {
   callIfExists(this._options.onCorrectStroke, {
     character: this._character.symbol,
     strokeNum: this._currentStrokeIndex,
diff --git a/src/renderers/svg/HanziWriterRenderer.js b/src/renderers/svg/HanziWriterRenderer.js
index 243b2f90..88cc6b13 100644
--- a/src/renderers/svg/HanziWriterRenderer.js
+++ b/src/renderers/svg/HanziWriterRenderer.js
@@ -60,7 +60,7 @@ HanziWriterRenderer.prototype.render = function(props) {
     let strokeRenderer = this._userStrokeRenderers[userStrokeId];
     if (!strokeRenderer) {
       strokeRenderer = new UserStrokeRenderer();
-      strokeRenderer.mount(this._positionedTarget, userStrokeProps);
+      strokeRenderer.mount(this._positionedTarget);
       this._userStrokeRenderers[userStrokeId] = strokeRenderer;
     }
     strokeRenderer.render(userStrokeProps);


Test patch:
diff --git a/src/__tests__/Quiz-test.js b/src/__tests__/Quiz-test.js
index 8cc7f644..37a8db9a 100644
--- a/src/__tests__/Quiz-test.js
+++ b/src/__tests__/Quiz-test.js
@@ -434,6 +434,30 @@ describe('Quiz', () => {
       expect(renderState.state.character.highlight.strokes[0].opacity).toBe(0);
     });
 
+    it('does not highlight strokes if showHintAfterMisses is set to false', async () => {
+      strokeMatches.mockImplementation(() => false);
+
+      const renderState = createRenderState();
+      // should reset this color before highlighting
+      renderState.state.character.highlight.strokeColor = '#00F';
+      const quiz = new Quiz(char, renderState, new Positioner());
+      const onCorrectStroke = jest.fn();
+      const onMistake = jest.fn();
+      const onComplete = jest.fn();
+      quiz.startQuiz(Object.assign({}, opts, { onCorrectStroke, onComplete, onMistake, showHintAfterMisses: false }));
+      clock.tick(1000);
+      await resolvePromises();
+
+      quiz.startUserStroke({x: 10, y: 20});
+      quiz.continueUserStroke({x: 11, y: 21});
+      quiz.endUserStroke();
+      await resolvePromises();
+      clock.tick(1000);
+      await resolvePromises();
+      // Stroke shouldn't be highlighted
+      expect(renderState.state.character.highlight.strokes[0].opacity).toBe(0);
+    });
+
     it('finishes the quiz when all strokes are successful', async () => {
       strokeMatches.mockImplementation(() => true);
 
diff --git a/src/renderers/svg/__tests__/StrokeRenderer-test.js b/src/renderers/svg/__tests__/StrokeRenderer-test.js
index bf015e86..4651b895 100644
--- a/src/renderers/svg/__tests__/StrokeRenderer-test.js
+++ b/src/renderers/svg/__tests__/StrokeRenderer-test.js
@@ -25,7 +25,7 @@ describe('StrokeRenderer', () => {
     };
 
     const renderer = new StrokeRenderer(char.strokes[0]);
-    renderer.mount(target, props);
+    renderer.mount(target);
     renderer.render(props);
 
     expect(target.defs.childNodes.length).toBe(1);