Release 0.1a: My First Contribution

Welcome to my first release!

The two first contributions I made to Open Source are to my colleagues' school projects. The project they completed is two online Notepad-like note-taking apps with different customized features.

The release includes two activities: to report a bug and to suggest a new feature. Let's dive into the first one...

Issue #1: Integrated Rich Text Editor (Quill.js) not working

Links: Repository | Issue | Pull Request

The bug I found while going through many of my colleagues' projects is in the repository mentioned above where I already filed an issue. The bug is associated with the use of an integrated Rich Text Editor called Quill.js.

What is Quill.js?

Quill is a JavaScript library allowing the developer to integrate a highly customizable Rich Text Editor to a webpage. All it needs is an HTML <div> element to be initialized when the DOM is loaded.
An interactive editor box with text formatting functionalities created by Quill.js

Bug Details:

In the app, although the text editor box was created successfully by Quill, all of the buttons on the toolbar do not have any effect on the text.

This bug is caused by the conflict between the method the app stores and retrieves the notes' contents and the method Quill.js manages the notes' contents and their styling. Specifically, the two methods used different data shapes to represent the content;

In the app, the author used the innerHTML property to retrieve and set the current content of the note, for example:
function save() {
    var newString = document.getElementById("text").innerHTML;
    fs.writeFile("/note", newString, (err) => {
      // ...
    });
}
The innerHTML property, as its name suggests, uses HTML (represented by a string) as its data format. The browser will normally parse that string as HTML to render the content inside.

However, Quill.js uses a data shape called Delta (also as a string) to represent the content. According to Quill.js' documentation about Delta data shape:
"Deltas are a simple, yet expressive format that can be used to describe Quill’s contents and changes. The format is a strict subset of JSON, is human-readable, and easily parsible by machines. Deltas can describe any Quill document, includes all text and formatting information, without the ambiguity and complexity of HTML."

For example, to represent this string...

Below is the Delta object representing this Quill.js-formatted string!

Quill.js uses this Delta object:

{
  "ops": [
    {
      "insert": "Below is the "
    },
    {
      "attributes": {
        "bold": true
      },
      "insert": "Delta object"
    },
    {
      "insert": " "
    },
    {
      "attributes": {
        "underline": true
      },
      "insert": "representing"
    },
    {
      "insert": " this "
    },
    {
      "attributes": {
        "italic": true,
        "link": "https://quilljs.com/"
      },
      "insert": "Quill.js"
    },
    {
      "attributes": {
        "italic": true
      },
      "insert": "-formatted string"
    },
    {
      "insert": "!\n"
    }
  ]
}

As Quill.js uses Delta to represent the content, the browser is not capable of parsing the it; therefore, innerHTML property cannot be used with element taken over by Quill.js.

So... how do we fix this bug?

Fortunately, Quill.js does not just provide an element with fancy styling and a few buttons, it also facilitates a robust set of API dedicating to programmatically customize the module and manipulate the content.

For our purpose, we will focus on the set of methods that help us set and retrieve the content which is the 3 methods: getContents(), setText(text) and setContents(deltaObj).

The method getContents() will return the current content of the editor as Delta object while setText(text) receives a string and setContents(deltaObj) receives a Delta object as its argument. Thus, the code in the example above should be rewritten as:
function save() {
    var newContent = JSON.stringify(editor.getContents()); // editor is a Quill.js's instance for the div#text element
    fs.writeFile("/note", newContent, (err) => {
      // ...
    });
}
Besides that, when the app's DOM finishes loading, the content should be loaded appropriately, too. Therefore, the below author's initial code...
window.addEventListener('DOMContentLoaded', (event) => {
    fs.readFile('/note', 'utf8', function(err, data) {
        var content = document.getElementById("text");
        if (err)
            content.innerHTML = "...";
        if (data)
            content.innerHTML = data;
    })
});
should be rewritten as...
window.addEventListener('DOMContentLoaded', (event) => {
    fs.readFile('/note', 'utf8', function(err, data) {
        // editor is a Quill.js's instance for the div#text element
        if (err)
            editor.setText("...");
        if (data)
            editor.setContents(JSON.parse(data));
    })
});
Note that the use of JSON.stringify()  and JSON.parse() would help to store the Delta object as a JSON string in the (virtual) file system.

This fix should eliminate the conflict of data shape; allowing the content of the note to be stored and retrieved alongside with its formatting and styling.

I implemented the solution and, as I hoped, the pull request I made to the author's repository was accepted and merged into their master branch to resolve the issue.

My experience

The first, small lesson I learn from fixing this bug is that whenever you encounter a new, cool tool or library, do not just copy code online and paste it in your work just to achieve your goal. Actually studying the library and looking into their documentation may take you a lot of time but it will surely save you a lot more later... especially if you want to leverage the tool for your purpose.

Moreover, this problem helps me develop a better sense of debugging. The process of fixing requires me to analyze many aspects of the code separately and then combine all the cases together each by each to identify the exact "aspect" that causes the problem. This is among the rare cases where I need to build small testing apps with each aspect of the code; trying to reproduce the bug which was finally found in the least expected part, the innerHTML property.

This experience has been fun. I found it challenging enough to trigger me into studying it and the result was satisfying when I eventually solved the problem. I believe this is not only a helpful activity but also beneficial since I get to contribute to the community and enhance my debugging skill at the same time.

Keep watch as I will be posting Release 0.1b - Adding an indicator for the saved status of the note.

Comments

Popular posts from this blog

Release 0.1b: Contributing a new feature... Why not?

Release 0.2b: #js-vs-py - Fianlly learning Python!