My son has been using the Parallels website for a few years now. It’s a mathematics site for secondary school pupils, and it’s designed to provide more challenging material for children who have shown an aptitude for mathematics. It is run by Simon Singh. You may remember him from such books as The Simpsons and Their Mathematical Secrets. It’s a brilliant resource, and I can’t recommend it highly enough.

During the first lockdown, I decided to introduce my daughter to it. She’s only in Year 4, however I was happy to teach her the maths required as she went along. Similarly, my son tried the Year 9 questions once he’d finished all the Year 8 ones.

Anyway, September rolled around again, and whilst all the previous year’s weekly challenges were removed from the site, the previous year’s answers are still in the database. So if you’ve answered the Year 7 Week 1 questions last year, this year it thinks you’ve already submitted it; you have a score, and you cannot submit it again. To be clear, this is not a criticism, as the site is not designed to be able to re-take years.

However, that leaves my children unable to partake in each weekly challenge, at least until they get past the week they reached previously.

Weekly Scores

 

As you can see, we’re in March, and my daughter still hasn’t reached that point.

Being a developer, I obviously began thinking about what I could do to solve this problem, so I decided to see if there was any way I could manipulate the html of the page to reset it, and let my kids answer the new questions.

In this series of posts, I will first detail the problem solving process I went through, which will hopefully provide some useful insight into how to go about investigating a problem. Then I will see how I can use everything that I discover in that process to create a extension for Chromium-based browsers. As this is not something I have done before, it should hopefully be a good introduction as to how to do it, as long as I manage to figure it all out!

Investigating the HTML

Here is what a submitted question looks like:

QuestionWithAnswerAndSolution

It shows the saved answer, whether it is correct, and the solution.

At first glance, this appears to be achieved using HTML and styling. The first port of call in these scenarios is my old friend, the Dev Tools that come with the browser, which lets us see what is going on with the HTML. Either hit F12 and use the picker to select the element you wish to investigate, or else right-click on the element you wish to investigate and select Inspect.

The Question

This is the top-level HTML for the question.

1
<div id="p_1_1" data-marks="1" data-solution="YQ==" class="problem radio"></div> 
          

 

So, what information can we glean from this? Quite a lot, it turns out!

  1. The whole question element has the “problem” class.
  2. There is a class that tells you what type of answers are available: multiple choice (radio) or single value (input).
  3. There are two data- attributes: data-marks tells us how many marks the question is worth, and data-solution contains the answer to the question. If you’re thinking ”How is YQ== the answer?”, it has been Base64 encoded (the value is “a”, I.e. the first answer. “b” would be the second answer, etc…). These are both potentially useful for additional functionality for the extension, so we’ll come back to those later.

All in all, a decent amount of information uncovered from the first element we’ve looked at!

The Answers

Looking at a multiple choice question answer choices:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<ul class="choices">
    <li>
        <div data-value="a" class="choice active correct">Happy</div></li>
    <li>
        <div data-value="b" class="choice">Sad</div>
    </li>
    <li style="display: none;">
        <div class="choice active">(Not answered)</div>
    </li>
</ul>
          

 

This reveals that:

  1. The user’s answer is highlighted using the “active” class
  2. The correct answer is indicated by the “correct” class.
  3. The data-value attribute stores which multiple choice answer this is (a, b, c, etc…). It is this value that is stored as Base 64-encoded text in the data-solution attribute we discovered earlier.
  4. Whilst the choices look like radio buttons in the browser, this is faked using the “choice” class, and a JavaScript function to toggle the states. This will potentially make it more difficult to select an answer once we’ve cleared the form than if they were standard HTML radio buttons, but that’s a problem for Future Me to worry about solving.

So, again we’ve managed to glean a lot of information about how the page works purely from the HTML.

The Solution

Then we have the HTML that shows the solution to the question:

1
<div class="solution"><p>Of course 100 is happy, because 1<sup>2</sup> + 0<sup>2</sup> + 0<sup>2</sup> = 1.</p></div>
          

 

There’s nothing fancy going on here, the div is marked with the “solution” class, so we have an easy way to identify and hide all the solutions on this page.

Additional observations

As well as being navigate the HTML on a page, Dev Tools also has a panel that tells you the styles that apply to the selected element, and where they come from.

DevToolsStyles

Interestingly, for this project, I noticed that there was a style called submitted. Looking back through the HTML, this comes from the div that contains all the questions.

After all that, I think that we’ve identified the classes that style the various elements of the completed answer. But how do we go about messing around with it and changing how the page looks?

Experimenting with the dev console

By using one of the other great features of the Dev Tools, the Console tab, that’s how! This super-useful tool allows you to run JavaScript against a live web page, and we can experiment with using various JavaScript statements to change how an element looks.

So, let’s see what we can do to the answers section. First up, we can get rid of the active class. Going to the dev console, it’s code time!

1
2
3
document.querySelectorAll('.active').forEach(function(element) {
    element.classList.remove('active');
});
          

 

Breaking this down:

  1. document.querySelectorAll(‘.active’) will search the page for all elements that have the active class (the dot means class here).
  2. .forEach will loop over every element that step 1 finds, and runs the function defined next…
  3. Which uses element.classList.remove(‘active’) to remove the active class from the element.

And sure enough, this removes the highlighting from the saved answer:

QuestionWithActiveClassRemoved

Next up, we use the same logic to remove the correct class:

1
2
3
document.querySelectorAll('.correct').forEach(function(element) {
    element.classList.remove('correct');
})
          

 

And the tick disappears:

QuestionWithCorrectClassRemoved

It also makes sense to remove the solution to the question:

1
2
3
document.querySelectorAll('.solution').forEach(function(element) {
    element.style.display = 'none'
;});
          

 

We’ll just hide it, rather than removing it though, as we’d want to show it once the questions have been answered. We do this using element.style.display = ‘none’.

So, what else do we need to clean up? Well, if the answer isn’t multiple choice, then there will be a text box to provide the answer. This is marked up with a submitted class.

InputWithIncorrectAnswer

1
2
3
document.querySelectorAll('.submitted').forEach(function(element) {
    element.classList.remove('submitted');
});
          

 

Again, we use the logic to remove the submitted class from the element, which removes both the X and the “Correct Solution” text.

InputWithSubmittedClassRemoved

And finally, we have the score box at the bottom of the page:

1
2
3
document.querySelectorAll('.score').forEach(function(element) {
    element.style.display = 'none';
});
          

 

This does have the side effect of removing all the scores from the list of Parallels in the side panel, but that’s fine for now.

Conclusion

To conclude, we’ve investigated the HTML of the page, identified the structure of the questions, and the classes that style them up as answered. Then we crafted the JavaScript to remove that styling. I feel that we’ve got a good start to this project, so it’s time to investigate how to create a browser extension, which we’ll do in Part II.


Comment Section