My first Open Source contribution
Tags: javascript, html, css, vue
Published: 2019-09-23 19:05:31

If you've met me in a tech event, you might already know that I'm an active user of [Habitica](https://habitica.com/), a habit tracker that applies gamification into your life. It's been helping me to keep myself organized while providing the sensation of playing an MMORPG which is something that I'm very passionate.

My [profile](https://habitica.com/profile/40387571-91ee-489e-960f-278bf8fd503a) was created in 2014, but only in 2016 I've given a try. I've engaged some other friends and it worked pretty well for some time. I even had contributed to [Habitica's Portuguese Wiki](https://habitica.fandom.com/pt-br/wiki/Usu%C3%A1rio:Kopmark) with translations.
A few months ago I came back to Habitica and today I'm a Front-End Developer, so it shouldn't be hard to contribute with some code.

{% github HabitRPG/habitica no-readme %}

I've taken [this good first issue](https://github.com/HabitRPG/habitica/issues/11042) and shared my progress in this post. Before started I was concerned about the main difficulties being setting up the development environment and working with VueJS (which was very curious since I've learned React)

{% github https://github.com/HabitRPG/habitica/issues/11042 %}

## First Steps

In this first part, I simply followed this guide:
[Habitica Wiki - Setting Up Habitica Locally on Linux](https://habitica.fandom.com/wiki/Setting_up_Habitica_Locally_on_Linux)

Since I already had Git, build-essentials, Node, npm and MongoDB installed, these were the commands I've run:
```shell
sudo npm install -g mocha 
git clone https://github.com/Markkop/habitica.git
cd habitica
git remote add upstream https://github.com/HabitRPG/habitica.git
cp config.json.example config.json
npm install
sudo service mongod start
npm start
npm run client:dev
```

http://localhost:8080/static/home
Hurray, Habitica is running on my own machine!
The login page was a little bugged without texts, but as instructed [clearing](http://localhost:8080/static/clear-browser-data) the cache fixed it.
Then I created a User and logged in.

## Starting to change stuff

By following this guide we create a new git branch
[Habitica Wiki - Using Your Local Install to Modify Habitica's Website and API](https://habitica.fandom.com/wiki/Using_Your_Local_Install_to_Modify_Habitica%27s_Website_and_API)

```
git fetch upstream
git checkout -b firefox-extension-link
```

The main goal is to add a link in the Settings page, and we can find it at `website/client/components/settings/api.vue`.

![Before any changes](https://i.imgur.com/yZU6wrL.png)

This is what we want to change:
```javascript
li
  a(target='_blank' href='https://chrome.google.com/webstore/detail/habitrpg-chat-client/hidkdfgonpoaiannijofifhjidbnilbb') {{ $t('chromeChatExtension') }}
  br
  | {{ $t('chromeChatExtensionDesc') }}
```

But what kind of HTML is that? As hinted by `<template lang="pug">`, this is the [Pug](https://pugjs.org/api/getting-started.html) [Pre-Processor](https://vue-loader.vuejs.org/guide/pre-processors.html#typescript) that takes this code and outputs HTML. The same with [SASS](https://sass-lang.com/) and CSS.

Cool, so we only have to change this text and add other link. 
But the thing is: all texts are actually variables because [internationalization](
https://www.freecodecamp.org/news/how-to-add-internationalization-to-a-vue-application-d9cfdcabb03b/
). How to access `$t('chromeChatExtension')` or even how to have a single text variable with two links?

A good way out is asking for help in the Blacksmiths Guild, but looking somewhere for a similar situation also works.

By checking this api's webpage we can notice that right above there is this API Token Warning message.

![api token warning message](http://i.imgur.com/ojcKAd6.png)

that corresponds to this line in the code
```javascript
p(v-html='$t("APITokenWarning", { hrefTechAssistanceEmail })')`
```

And by searching for `APITokenWarning` inside the project, we can find how `settings.json` declare this kind of variable

```json
"APITokenWarning": "If you need a new API Token (e.g., if you accidentally shared it), email <%= hrefTechAssistanceEmail %> with your User ID and current Token. Once it is reset you will need to re-authorise everything by logging out of the website and mobile app and by providing the new Token to any other Habitica tools that you use.",
```

Therefore, with `<%= hrefTechAssistanceEmail %>`

Also, the **hrefTechAssistanceEmail**'s value can be found in the following section


```javascript
/// api.vue
...
const TECH_ASSISTANCE_EMAIL = "admin@habitica.com";

export default {
  data() {
    return {
      newWebhook: {
        url: ""
      },
      hrefTechAssistanceEmail: `<a href="mailto:${TECH_ASSISTANCE_EMAIL}">${TECH_ASSISTANCE_EMAIL}</a>`,
      showApiToken: false
    };
  }
}, ...
```

And after some trying out, we find out the correct way to use directly:

```javascript
{{ $t("APITokenWarning", { hrefTechAssistanceEmail: "myemail@lol.com" }) }}
```

### Actually...

Ok, cool. We could just create some constants with each link and use them as the example above. However, what if someday someone had to change these links? Perhaps changing the text string directly in the `settings.json` file would be easier.
 
Since this approach results in less code, we're going to use it instead.

We then change **chromeChatExtension** and **chromeChatExtensionDesc** to the following:

```json
"chatExtension": "<a target='blank' href='https://chrome.google.com/webstore/detail/habitrpg-chat-client/hidkdfgonpoaiannijofifhjidbnilbb'>Chrome Chat Extension</a> and <a target='blank' href='https://addons.mozilla.org/en-US/firefox/addon/habitica-chat-client-v2/'>Firefox Chat Extension</a>",
"chatExtensionDesc": "The Chat Extension for Habitica adds an intuitive chat box to all of habitica.com. It allows users to chat in the Tavern, their party, and any guilds they are in.",
```

And our extensions list ends up being
```javascript
ul
  li
    a(target='_blank' href='https://www.beeminder.com/habitica') {{ $t('beeminder') }}
    br
    | {{ $t('beeminderDesc') }}
  li(v-html="$t('chatExtension')")
    br
    | {{ $t('chatExtensionDesc') }}
  li
    a(target='_blank' :href='`https://oldgods.net/habitica/habitrpg_user_data_display.html?uuid=` + user._id') {{ $t('dataTool') }}
    br
    | {{ $t('dataToolDesc') }}
  li(v-html="$t('otherExtensions')")
    | {{ $t('otherDesc') }}
```

### The problem

![After changes](http://i.imgur.com/G1ujmDd.png)

By checking manually, we notice that **chatExtensionsDesc** isn't being displayed. In fact, **otherDesc** text isn't appearing, even on live!

After some experimenting, it seems that when **tags** are being created **with attributes** such as `li(v-html="$t('otherExtensions')")`, their children tags aren't displayed. The solution is changing the child indentation so it appears just below. 

*(bug with Pug+Vue?)*

The final code is 
```javascript
      ul
        li
          a(target='_blank' href='https://www.beeminder.com/habitica') {{ $t('beeminder') }}
          br
          | {{ $t('beeminderDesc') }}
        li(v-html="$t('chatExtension')")
        | {{ $t('chatExtensionDesc') }}
        li
          a(target='_blank' :href='`https://oldgods.net/habitica/habitrpg_user_data_display.html?uuid=` + user._id') {{ $t('dataTool') }}
          br
          | {{ $t('dataToolDesc') }}
        li(v-html="$t('otherExtensions')")
        | {{ $t('otherDesc') }}
```

![End result](https://i.imgur.com/IpNohdw.png)

# Conclusion

Before starting the project I thought the **main difficult** would be setting the project's **environment**, but instructions were **crystal clear** and I hadn't any problem. 
The interesting part is that I thought it would be very **simple to add another link** in a single line of text, but faced **several possible solutions** because of Vue-i18n Plugin's internationalization.
At first the initial approach made more sense, because `api.vue` would be the **main file** where someone would check for if they'd need to change a link.
However, by putting it in the `settings.json` links could be changed to **different languages** as well. And changing the code would be much **simpler**.
The learnings in this opportunity were having my **first hands-on contact** with Vue, discovering the existence of **HTML's pre-processors** such as Pug and creating a **Pull Request** to a big project already in production. 

{% github https://github.com/HabitRPG/habitica/pull/11375 %}