<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: leojpod</title>
    <description>The latest articles on DEV Community by leojpod (@leojpod).</description>
    <link>https://dev.to/leojpod</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F11545%2F27392e79-0727-44dc-a01b-63f457d8243a.png</url>
      <title>DEV Community: leojpod</title>
      <link>https://dev.to/leojpod</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leojpod"/>
    <language>en</language>
    <item>
      <title>Writing custom-elements for elm</title>
      <dc:creator>leojpod</dc:creator>
      <pubDate>Sun, 01 Nov 2020 15:37:29 +0000</pubDate>
      <link>https://dev.to/leojpod/writing-custom-elements-for-elm-3agj</link>
      <guid>https://dev.to/leojpod/writing-custom-elements-for-elm-3agj</guid>
      <description>&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; There are 2 options to integrate JavaScript and Elm, one is the port system which has been around for a while, the other is to use custom-elements.&lt;br&gt;
In this post, we'll see that it is rather simple and show 2 examples of packages that use it.&lt;/p&gt;

&lt;p&gt;The introduction is a tad long but you can always just skip to the main part.&lt;/p&gt;
&lt;h2&gt;
  
  
  What's custom-elements?
&lt;/h2&gt;

&lt;p&gt;Custom elements are part of the Web Components and in short, it allows us to create new HTML tag that has a set of behaviour defined in JavaScript.&lt;br&gt;
Think of it as a "super-tiny-application-wrapped-in-a-tag".&lt;/p&gt;

&lt;p&gt;Have you ever wanted to define a small thing that you could call like &lt;code&gt;&amp;lt;drawing-board tool="pencil" thickness="10pt"&amp;gt;&amp;lt;/drawing-board&amp;gt;&lt;/code&gt; and get the whole set of features that goes with it?&lt;br&gt;
Well, custom-elements allows you to do just that.&lt;/p&gt;

&lt;p&gt;When you think of it, inputs in general and &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; in particular encompass a lot of features and "state" to know what the user input is, where is the cursor, if there is some auto-completion available, ...&lt;/p&gt;

&lt;p&gt;Custom-elements are just a neat way of defining your own version of that.&lt;/p&gt;

&lt;p&gt;For a more complete look at custom-element, you can refer to this post:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/jamesrweb" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2469%2F9ebf0985-a88c-486d-8c6a-d418205d0e5c.jpg" alt="jamesrweb"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/jamesrweb/an-introduction-to-custom-elements-5327" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Custom Elements&lt;/h2&gt;
      &lt;h3&gt;James Robb ・ Sep 26 '18&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#customelements&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#html&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;or refer to the GREAT and all-mighty MDN: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements" rel="noopener noreferrer"&gt;Using custom elements&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How does this help us with Elm?
&lt;/h2&gt;

&lt;p&gt;Quick words of introduction if you don't know &lt;a href="https://elm-lang.org/" rel="noopener noreferrer"&gt;Elm&lt;/a&gt;: Elm is a functional language designed for the front-end.&lt;br&gt;
Think of it as a "light" and more friendly version of Haskell repurposed for a single task.&lt;/p&gt;

&lt;p&gt;Among many advantages, Elm ensures that once compiled your code won't generate any runtime errors.&lt;br&gt;
One of the ways to do this is to force the code your write to handle all the different way things can go wrong using constructs such as &lt;code&gt;Result&lt;/code&gt; or &lt;code&gt;Maybe&lt;/code&gt; which works just perfectly.&lt;/p&gt;

&lt;p&gt;All of this is a long introduction to say that to provide you with this guarantee, Elm restrains the interactions with the unsafe world outside (a.k.a the JavaScript Doomdom...).&lt;br&gt;
Traditionally most interactions are handled in something called &lt;a href="https://guide.elm-lang.org/interop/ports.html" rel="noopener noreferrer"&gt;ports&lt;/a&gt;.&lt;br&gt;
The main interest of exchanging information between the outside world and elm via ports is that you can be sure of preserving the integrity of your elm code.&lt;/p&gt;

&lt;p&gt;Custom elements, however, are an interesting way of integrating some isolated JavaScript in your elm codebase.&lt;br&gt;
This covers for instance: charting libraries, chatbots, ...&lt;/p&gt;

&lt;p&gt;Yes, yes, good, how does that work then? Well, let's get to it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Making it work
&lt;/h2&gt;

&lt;p&gt;The elm documentation provides an &lt;a href="https://guide.elm-lang.org/interop/custom_elements.html" rel="noopener noreferrer"&gt;excellent base&lt;/a&gt; to start interoperating custom elements with elm.&lt;br&gt;
However, nothing is better than a &lt;a href="https://github.com/leojpod/elm-keyboard-shortcut/" rel="noopener noreferrer"&gt;&lt;del&gt;shameless plug&lt;/del&gt;&lt;/a&gt; detailed example.&lt;/p&gt;

&lt;p&gt;One thing I often found myself doing in elm in the various project I've worked on is a way to trigger some action based on keyboard events (or rather a combination of keys).&lt;br&gt;
In the past, I had mostly used events from the &lt;a href="https://package.elm-lang.org/packages/elm/browser/latest/Browser-Events#onKeyPress" rel="noopener noreferrer"&gt;&lt;code&gt;elm/browser&lt;/code&gt; package&lt;/a&gt; which worked well but there were some drawbacks (for details on that, you can refer to &lt;a href="https://github.com/leojpod/elm-keyboard-shortcut#why" rel="noopener noreferrer"&gt;this link&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Making a custom element to listen to a specific set of shortcut allowed me to keep things simple in my views and treat the shortcut as any other inputs.&lt;br&gt;
Using this small package, I can make a dismissible modal like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;shortcutModal&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt;
&lt;span class="n"&gt;shortcutModal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Shortcut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shortcutElement&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;Shortcut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;esc&lt;/span&gt; &lt;span class="kt"&gt;CloseModal&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fixed top-0 bottom-0 left-0 right-0 flex flex-col items-center justify-center bg-gray-500 bg-opacity-75"&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;singleton&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;div&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w-3/4 max-w-4xl p-12 bg-white border-gray-800 rounded-lg shadow-xl"&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you look a bit closer to that piece of code you'll see the 2 key lines here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;    &lt;span class="kt"&gt;Shortcut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shortcutElement&lt;/span&gt; &lt;span class="c1"&gt;-- simply a wrapper for Html.node "shortcut-element"&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;Shortcut&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;esc&lt;/span&gt; &lt;span class="kt"&gt;CloseModal&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;-- the shortcutElement expect a list of shortcut and Shortcut.esc is just a simple way to say "when the user press ESC send me a CloseModal message"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main interest of this version compared to doing it with subscriptions and &lt;code&gt;Browser.Events&lt;/code&gt; is mainly readability:&lt;br&gt;
Now even small bits of the UI can have shortcut without requiring you to keep track of their visibility/state in your subscriptions and you can also read it directly in the view.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enough! Show me some code!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The entire code is available &lt;a href="https://github.com/leojpod/elm-keyboard-shortcut/" rel="noopener noreferrer"&gt;here&lt;/a&gt; but let's go through the principal components of this solution.&lt;/p&gt;
&lt;h3&gt;
  
  
  Defining shortcuts
&lt;/h3&gt;

&lt;p&gt;Shortcuts are an association of a message to send and a description of a key combination.&lt;br&gt;
A key combination is a base key and some optional modifier.&lt;br&gt;
Elm provides a nice way to do that with is called union types (if you come from TypeScript or the like, think of them as a super-powerful enum type) and record types (again, TypeScript people, think of it as a simple class without method only some properties).&lt;/p&gt;

&lt;p&gt;In the end, the shortcut definition looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;Shortcut&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keyCombination&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;baseKey&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Key&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alt&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctrl&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The type &lt;code&gt;Key&lt;/code&gt; is a union typed defined as (complete code &lt;a href="https://github.com/leojpod/elm-keyboard-shortcut/blob/e0f3a1ecc20e1ff5ca893a9bcebc01a2b3f103ee/src/Shortcut.elm#L70-L88" rel="noopener noreferrer"&gt;here&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Key&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Escape&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;BackSpace&lt;/span&gt;
    &lt;span class="c1"&gt;-- | ... and many other constructors for the special keys&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;Regular&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Defining a custom element
&lt;/h3&gt;

&lt;p&gt;Before actually writing our custom element(s) one thing we should probably do is install a polyfill. &lt;br&gt;
While custom elements are rather well supported (see &lt;a href="https://caniuse.com/custom-elementsv1" rel="noopener noreferrer"&gt;Can I use?&lt;/a&gt;, even the Android browser joined the party!), it's still safer and nice to people who are stuck on IE11 to use a polyfill and make sure they are not left out.&lt;br&gt;
There is one right &lt;a href="https://github.com/webcomponents/polyfills/tree/master/packages/custom-elements" rel="noopener noreferrer"&gt;here&lt;/a&gt; and all you need is just to install it via NPM, ain't that simple?&lt;/p&gt;

&lt;p&gt;Once that's done you can start by making a file for your custom element and put the following scaffolding in it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@webcomponents/custom-elements&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// that's our polyfill&lt;/span&gt;

&lt;span class="c1"&gt;// custom elements are really just a custom HTMLElement&lt;/span&gt;
&lt;span class="c1"&gt;// so it is really no surprise that you just need to extends the HTMLElement class&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShortcutElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nf"&gt;connectedCallback &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// here goes the code you want to run when your custom element is rendered and initialised&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;disconnectedCallback &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// here goes the actions you should do when it's time to destroy/remove your custom element&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// the last important step here: registering our element so people can actually use it in their HTML&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shortcut-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ShortcutElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we look at the code above, the key really is in creating a new class to backup our element that extends &lt;code&gt;HTMLElement&lt;/code&gt; and registering it to a tag name via &lt;code&gt;customElements.define(tagName: string, constructor: HTMLElement)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let's fill that up.&lt;br&gt;
As mentioned in the comments on the snippet above, the first entry and exit points are the 2 callbacks: &lt;code&gt;connectedCallback&lt;/code&gt; and &lt;code&gt;disconnectedCallback&lt;/code&gt;.&lt;br&gt;
The first one is called when your element is added to the page, the second one when it's taken away.&lt;/p&gt;

&lt;p&gt;In our shortcut example, we'll use the &lt;code&gt;connectedCallback&lt;/code&gt; to register an event listener on the &lt;code&gt;body&lt;/code&gt; (since that will capture events regardless of what's on the page) and &lt;code&gt;disconnectedCallback&lt;/code&gt; to unsubscribe our event listener from the &lt;code&gt;body&lt;/code&gt;.&lt;br&gt;
So we'll start with something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShortcutElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;connectedCallback &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt;
      &lt;span class="c1"&gt;// TODO check with the associated shortcuts if we have a match&lt;/span&gt;
      &lt;span class="c1"&gt;// TODO if we have one then send a custom event&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// let's register&lt;/span&gt;
    &lt;span class="c1"&gt;// NOTE: we will register at the capture phase so as to take precedence over the rest (e.g. textarea, input, ...)&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keydown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;capture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;disconnectedCallback &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// let's unregister&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keydown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;capture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we're almost done for the JavaScript part! Yes there are 2 big &lt;code&gt;TODO&lt;/code&gt; in there but we'll get back to them after we take a look at the elm side of things&lt;/p&gt;

&lt;h3&gt;
  
  
  How to use this in Elm?
&lt;/h3&gt;

&lt;p&gt;On the elm side, things are rather simple. We need but 2 things: define a custom &lt;code&gt;Html.Html msg&lt;/code&gt; that uses our element and find a way to communicate with that element.&lt;/p&gt;

&lt;p&gt;The first part is super easy: &lt;code&gt;Html.node "shortcut-element"&lt;/code&gt;.&lt;br&gt;
To make it nice we can wrap that in a function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;shortcutElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attribute&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
&lt;span class="n"&gt;shortcutElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kt"&gt;Html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shortcut-element"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the communication part. Well, this one has 2 subparts actually: information going to the custom element and information coming from the custom element.&lt;br&gt;
For sending information from the JavaScript to Elm we'll use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent" rel="noopener noreferrer"&gt;&lt;code&gt;CustomEvent&lt;/code&gt;&lt;/a&gt; on the JavaScript part which means we can just use our normal &lt;a href="https://package.elm-lang.org/packages/elm/html/latest/Html-Events#on" rel="noopener noreferrer"&gt;&lt;code&gt;Html.Events.on&lt;/code&gt;&lt;/a&gt; function and the familiar &lt;a href="https://package.elm-lang.org/packages/elm/json/latest/Json-Decode" rel="noopener noreferrer"&gt;&lt;code&gt;Json.Decode&lt;/code&gt;&lt;/a&gt; (and &lt;a href="https://package.elm-lang.org/packages/elm-community/json-extra/latest/Json-Decode-Extra" rel="noopener noreferrer"&gt;&lt;code&gt;Json.Decode.Extra&lt;/code&gt;&lt;/a&gt;)&lt;br&gt;
For sending information down to the JavaScript from the Elm world we'll play with attributes and properties.&lt;/p&gt;

&lt;p&gt;So it's gonna look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;encodeShortcut&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Shortcut&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Value&lt;/span&gt;
&lt;span class="n"&gt;encodeShortcut&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;keyCombination&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;shortcut&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="n"&gt;hashShortcut&lt;/span&gt; &lt;span class="n"&gt;shortcut&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;baseKey"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="n"&gt;keyToString&lt;/span&gt; &lt;span class="n"&gt;keyCombination&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;baseKey&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alt"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Extra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maybe&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;keyCombination&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alt&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shift"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Extra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maybe&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;keyCombination&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ctrl"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Extra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maybe&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;keyCombination&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctrl&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meta"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Extra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maybe&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;keyCombination&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="n"&gt;onShortcut&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Shortcut&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attribute&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
&lt;span class="n"&gt;onShortcut&lt;/span&gt; &lt;span class="n"&gt;shortcuts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shortcut"&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;detail"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name"&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;
            &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;andThen&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Extra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hashShortcut&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shortcuts&lt;/span&gt;
                        &lt;span class="c1"&gt;-- NOTE: if a event decoding failed then no message is emitted&lt;/span&gt;
                        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Extra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unwrap&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fail&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;did not match a known shortcut"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;succeed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;shortcutElement&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Shortcut&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attribute&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
&lt;span class="n"&gt;shortcutElement&lt;/span&gt; &lt;span class="n"&gt;shortcuts&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shortcut-element"&lt;/span&gt;
        &lt;span class="c1"&gt;-- Add 2 attributes here: one to send the props we're listening to&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shortcuts"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;encodeShortcut&lt;/span&gt; &lt;span class="n"&gt;shortcuts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;-- one to listen to the stuff&lt;/span&gt;
            &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;onShortcut&lt;/span&gt; &lt;span class="n"&gt;shortcuts&lt;/span&gt;
            &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;attrs&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(For those curious about the note on the &lt;code&gt;onShortcut&lt;/code&gt; function, have a look at this &lt;a href="https://thoughtbot.com/blog/debugging-dom-event-handlers-in-elm" rel="noopener noreferrer"&gt;article&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The main thing here is that we're setting a property called &lt;code&gt;shortcuts&lt;/code&gt; on our custom elements that contains all the shortcuts passed to the &lt;code&gt;shortcutElement&lt;/code&gt; function and that we will listen to the &lt;code&gt;shortcut&lt;/code&gt; event from which we are going to extract the name of our shortcut and find out which message should be sent.&lt;/p&gt;

&lt;p&gt;In the end, the elm-side looks rather simple doesn't it?&lt;/p&gt;

&lt;h3&gt;
  
  
  Huston, JavaScript speaking do you copy?
&lt;/h3&gt;

&lt;p&gt;Getting back to our 2 &lt;code&gt;TODO&lt;/code&gt; in JavaScript:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;find out if we have a match among the shortcut the element should listen for&lt;/li&gt;
&lt;li&gt;send an event if there is one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since the elm part will set the &lt;code&gt;shortcuts&lt;/code&gt; property we can simply access this array via &lt;code&gt;this.shortcuts&lt;/code&gt; from within our &lt;code&gt;ShortcutElement&lt;/code&gt; class. Then one small caveat with shortcuts is the need to detect which key was really pressed since if we ask the user to press ShiftAlto for instance, the value of &lt;code&gt;event.key&lt;/code&gt; might vary a lot based on the user's input method and OS (e.g. &lt;code&gt;o&lt;/code&gt;, &lt;code&gt;Ø&lt;/code&gt;, ...).&lt;br&gt;
As explained on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;, using &lt;code&gt;event.code&lt;/code&gt; would work if we assume our user are all using QWERTY keyboards but that is kind of a rubbish solution.&lt;br&gt;
Instead, I'd recommend using &lt;a href="https://lodash.com/docs/4.17.15#deburr" rel="noopener noreferrer"&gt;&lt;code&gt;deburr&lt;/code&gt; from lodash&lt;/a&gt;, which will remove all the "diacritical marks" (a.k.a. give you back the original letter that was pressed).&lt;/p&gt;

&lt;p&gt;Sending out the event is as simple as using the constructor for a &lt;code&gt;CustomEvent&lt;/code&gt; and setting a property in the &lt;code&gt;detail&lt;/code&gt; part of its second parameter.&lt;br&gt;
Putting it all together we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shortcuts&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;baseKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="nf"&gt;deburr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;baseKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;alt&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;altKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shift&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;shift&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shiftKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;ctrl&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ctrlKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metaKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// now we have all the shortcuts that match the current event&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CustomEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shortcut&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;bubbles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;event&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see it in action you can have a look at the &lt;a href="https://leojpod.github.io/elm-keyboard-shortcut/" rel="noopener noreferrer"&gt;Github page here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Apex Charts in Elm
&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://apexcharts.com/" rel="noopener noreferrer"&gt;Apex charts&lt;/a&gt; is a fancy charting library for JavaScript that provides a lot of interactive chart types and interesting ways to combine them.&lt;br&gt;
As I was looking for such library in Elm but could not quite find the one I was looking for, I thought I would make a custom element to integrate Apex charts and Elm.&lt;/p&gt;

&lt;p&gt;In the end, it allows the dev to write things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="kt"&gt;Apex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chart&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Apex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addLineSeries&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Connections by week"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionsByWeek&lt;/span&gt; &lt;span class="n"&gt;logins&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Apex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addColumnSeries&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Connections within office hour for that week"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dayTimeConnectionByWeek&lt;/span&gt; &lt;span class="n"&gt;logins&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Apex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addColumnSeries&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Connections outside office hour for that week"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outsideOfficeHourConnectionByWeek&lt;/span&gt; &lt;span class="n"&gt;logins&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Apex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withXAxisType&lt;/span&gt; &lt;span class="kt"&gt;Apex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;DateTime&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and get a nice chart with one line and 2 columns. &lt;/p&gt;

&lt;p&gt;Since this post is already quite lengthy, I'll keep the second custom element for another time but you can already have a primeur of it &lt;a href="https://leojpod.github.io/elm-apex-charts-link/" rel="noopener noreferrer"&gt;here&lt;/a&gt; (with the code &lt;a href="https://github.com/leojpod/elm-apex-charts-link/" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;br&gt;
To make it work, we will need to take a closer look at &lt;code&gt;getter&lt;/code&gt; and &lt;code&gt;setter&lt;/code&gt; in JavaScript so as to handle properties that can change over time (i.e. during the life-time of our custom element).&lt;/p&gt;

</description>
      <category>elm</category>
      <category>customelements</category>
      <category>javascript</category>
      <category>ux</category>
    </item>
    <item>
      <title>Anyone attending AWS summit online?</title>
      <dc:creator>leojpod</dc:creator>
      <pubDate>Wed, 17 Jun 2020 07:58:11 +0000</pubDate>
      <link>https://dev.to/leojpod/anyone-attending-aws-summit-online-346i</link>
      <guid>https://dev.to/leojpod/anyone-attending-aws-summit-online-346i</guid>
      <description>&lt;p&gt;I'll be listening all day, any tips on which topics not to miss? &lt;/p&gt;

</description>
      <category>aws</category>
      <category>watercooler</category>
      <category>meetup</category>
    </item>
    <item>
      <title>Testing and documenting your APIs with Vim-Rest-Console</title>
      <dc:creator>leojpod</dc:creator>
      <pubDate>Thu, 27 Feb 2020 16:45:53 +0000</pubDate>
      <link>https://dev.to/leojpod/testing-and-documenting-your-apis-with-vim-rest-console-215d</link>
      <guid>https://dev.to/leojpod/testing-and-documenting-your-apis-with-vim-rest-console-215d</guid>
      <description>&lt;p&gt;I have previously written about a few plugins that I enjoy immensely while working with vim every day.&lt;br&gt;
I had so far forgotten an obvious one until I read a &lt;a href="https://dev.to/monisnap/bye-bye-postman-let-s-share-your-rest-api-calls-in-team-easily-h6l"&gt;post&lt;/a&gt; on Dev.to about yet another VSCode extension copying its behaviour from the already existing and great Vim counterpart!&lt;br&gt;
Not to be a complete troll but it's nice to see that the other editors are finally catching on... 😁&lt;br&gt;
Sadly they are not reusing the existing syntax making sharing those requests among co-workers not using the same IDE not quite possible... &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/monisnap" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F915%2Fbc82ab17-6eba-4fe7-8205-7f1bb80c43ef.png" alt="Monisnap" width="800" height="800"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F162089%2F865c9afd-ad9b-4b99-a68e-e7bf8e1c0252.png" alt="" width="512" height="512"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/monisnap/bye-bye-postman-let-s-share-your-rest-api-calls-in-team-easily-h6l" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Bye bye Postman ! Let's share your REST API calls in team, easily !&lt;/h2&gt;
      &lt;h3&gt;Jonathan BROSSARD for Monisnap ・ Jan 10 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#vscode&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#rest&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#postman&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;It would be interesting to try unifying those various plugins and get one common syntax. That way, the IDE troll-war wouldn't prevent people from having the niceness of versioning their requests!&lt;/p&gt;

&lt;p&gt;Anyway, I thought a quick review of the vim-version could be a nice thing to have on dev.to, so without further ado here we go. &lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;a href="https://github.com/diepm/vim-rest-console" rel="noopener noreferrer"&gt;vim-rest-console&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;In essence, this plugin is quite simple: it defines a &lt;code&gt;.rest&lt;/code&gt; file format and provides one command to run the HTTP call under the cursor of a &lt;code&gt;.rest&lt;/code&gt; file. By default, this command is mapped to &amp;lt;C-j&amp;gt; but I had hard time remembering it so I remapped it to &amp;lt;C-x&amp;gt;  (for eXecute). &lt;/p&gt;

&lt;p&gt;For a complete look at the doc, just follow the usual &lt;code&gt;:help rest-console&lt;/code&gt;😀. But let's have a look at the basic syntax. &lt;/p&gt;

&lt;p&gt;A simple request looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://someurl:port
// here you can put some options: 
// - either cURL options
// - or Http Headers for your request: e.g. content-type, ... 
GET /api/status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can guess, there is a way to avoid repeating the host of your request and the headers that you'd like to have by default. You can do that in the &lt;a href="https://github.com/diepm/vim-rest-console#52-global-definitions" rel="noopener noreferrer"&gt;global section&lt;/a&gt; of your &lt;code&gt;.rest&lt;/code&gt; files. &lt;/p&gt;

&lt;p&gt;Best use an example to see how that would work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Global section
// set the host for the whole file
http://localhost:1337

// set some common header
// those can be overriden for specific calls
Accept: application/json
Content-Type: application/json
// usually most of the api you're gonna call are gonna be secrued behind 
// some authentification scheme. 
// I tend to put mine at the top of the files (of course you need to 
// change those frequently as they have an expiration date)
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.{...}.ka3IfQFX0-Yb5uFp45f97y0zEevNf3en8TLzoPEJDu0



// you can also setup some variables here: 
username = John Doe
password = NOT_a_g00d-password

// the two -- coming next are important: they indicate the end of of the global scope
--


-- // &amp;lt;-- to start a request block, put two dashes
# Get some resource // be nice and put some comments about what your request does
GET /api/resource

-- 
# Create a user
POST /api/users
{ 
  "name": username
  "password": password
}
// note the use of the variables above

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ⚠️ an important thing to keep in mind
&lt;/h2&gt;

&lt;p&gt;Vim-rest-console does NOT encode your URLs and this is particularly something to keep in mind when your API allows some complex filtering on your &lt;code&gt;GET&lt;/code&gt; requests. &lt;/p&gt;

&lt;p&gt;I lost a couple of &lt;del&gt;minutes&lt;/del&gt; &lt;em&gt;almost an hour&lt;/em&gt; on this particular request last week. My API leverage some of &lt;a href="http://sailsjs.com/" rel="noopener noreferrer"&gt;sailsjs&lt;/a&gt;' powerful ORM to allow to write queries like: &lt;code&gt;?filter[name]={\"startsWith\":\"jojo\"}&lt;/code&gt;. While writing it in my Rest-console file I had completely forgotten about this, hence my request wasn't returning me any match. Once corrected back to: &lt;code&gt;?filter[name]=%7B%22startsWith%22:%22jojo%22%7D&lt;/code&gt; all was good again. 🙏&lt;/p&gt;

&lt;h1&gt;
  
  
  In short:
&lt;/h1&gt;

&lt;p&gt;As always, vim shows that it's a full-blown IDE for whoever wants to make it their own and I hope that this quick example will help you on your vim-journey. Don't hesitate to reach out if things are unclear! &lt;/p&gt;

</description>
      <category>vim</category>
      <category>http</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Reviewing PR from Vim: Critiq.vim</title>
      <dc:creator>leojpod</dc:creator>
      <pubDate>Mon, 11 Nov 2019 15:16:59 +0000</pubDate>
      <link>https://dev.to/leojpod/reviewing-pr-from-vim-critiq-vim-2l7p</link>
      <guid>https://dev.to/leojpod/reviewing-pr-from-vim-critiq-vim-2l7p</guid>
      <description>&lt;p&gt;Reviewing PRs is daunting at times, even when dealing with merge requests less massive than the one showed in the cover picture. But regardless of the size of the PR, it has become my latest obsession: why should I quit the comfort of my own settings to review some code? Wouldn't I do the same faster if I was keeping my own cherished environment? &lt;/p&gt;

&lt;p&gt;So, after a quick web search, I found a few candidates and narrowed it to one by applying the "last commit on GitHub/Gitlab shouldn't be 3+ years old if issues are more recent" rule: &lt;a href="https://github.com/AGhost-7/critiq.vim/" rel="noopener noreferrer"&gt;Critiq.vim&lt;/a&gt;. &lt;/p&gt;

&lt;h1&gt;
  
  
  Preliminary work
&lt;/h1&gt;

&lt;p&gt;Before using critiq.vim I had to make a few changes to &lt;a href="https://github.com/leojpod/dotfiles" rel="noopener noreferrer"&gt;my config files&lt;/a&gt;: mainly, I introduced a new file, which will be imported when loading zsh, that will load some secrets into environment variables to let Critiq use my GitHub account (the changes are in &lt;a href="https://github.com/leojpod/dotfiles/commit/e46b7bd35e13e5cb9e711658a611e61df692984d" rel="noopener noreferrer"&gt;this commit&lt;/a&gt; if anyone is mad enough to check it). The nice thing to remember here is that you don't have to put your GitHub password to authenticate with Critiq (thanks for that!). Instead, you can just head to &lt;a href="https://github.com/settings/tokens" rel="noopener noreferrer"&gt;https://github.com/settings/tokens&lt;/a&gt; and generate an access token, give it just the rights you want and use that.&lt;/p&gt;

&lt;h1&gt;
  
  
  Reviewing Critiq.vim
&lt;/h1&gt;

&lt;p&gt;(pun intended)&lt;/p&gt;

&lt;p&gt;The first thing you need to do once you've installed Critiq.vim is to simply call it: &lt;code&gt;:Critiq&lt;/code&gt; which should list the open PRs from Github for your current project in a new tab (this was also a good opportunity for me to (re)learn about tabs in vim since I tend to do most things with only buffers). Pick one and press Enter. This should open 2 panes: the description of the PR in the upper pane and the diff in the lower one.&lt;/p&gt;

&lt;p&gt;From there, just go about your business as you would in GH, with a few twists. &lt;/p&gt;

&lt;h3&gt;
  
  
  I don't get how it runs 🤔
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:CritiqCheckout&lt;/code&gt; while it doesn't do exactly what it should (check out the branch locally), it does check out the code but under a weird name. I assume it does this to prevent conflicts with a potential local branch. Either way, after that you can just move to the previous tab to get your regular vim setting and go check that file or even simpler: &lt;code&gt;CritiqOpenFile&lt;/code&gt; which will open the file in a new vertical pane for you. Isn't that neat? &lt;/p&gt;

&lt;h3&gt;
  
  
  That's code could be better!
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:CritiqCommentLine&lt;/code&gt; while the cursor is on the line you want to comment will open a new small pane at the bottom in which you can type your comment. When you're ready to submit it: &lt;code&gt;:CritiqSubmitComment&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I haven't found yet if there is a possibility to write up a suggestion directly but it's not too complicated to write it yourself since it is after all just a simple code sample typed as &lt;code&gt;suggestion&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Approve/Reject/Comment
&lt;/h3&gt;

&lt;p&gt;The last part of the process is now to submit your final assessment of the review: &lt;code&gt;:CritiqComment&lt;/code&gt;, &lt;code&gt;:CritiqApprove&lt;/code&gt; &amp;amp; &lt;code&gt;:CritiqRequestChanges&lt;/code&gt; are here for that. They will open a new pane to write a comment justifying your assessment. Then use &lt;code&gt;:CritiqSubmitReview&lt;/code&gt; and job done! &lt;/p&gt;

&lt;p&gt;I've created a quick terminal recording (with asciinema) to show how it works (which sadly doesn't keep my beloved colour scheme): &lt;/p&gt;

&lt;p&gt;&lt;a href="https://asciinema.org/a/280566" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4lr4zmbvn8j97g4jqe21.png" alt="asciicast" width="800" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Final thoughts
&lt;/h1&gt;

&lt;p&gt;I'd like to see if it is possible to achieve the same thing for Gitlab as well. I also spend a good time on Gitlab-hosted projects and that would be grand!&lt;/p&gt;

&lt;p&gt;Hope this can be somewhat useful to others and see you next time!&lt;/p&gt;

</description>
      <category>vim</category>
      <category>productivity</category>
      <category>git</category>
      <category>github</category>
    </item>
    <item>
      <title>Hacktober: From Exercism to elm-pages</title>
      <dc:creator>leojpod</dc:creator>
      <pubDate>Tue, 05 Nov 2019 14:15:26 +0000</pubDate>
      <link>https://dev.to/leojpod/hacktober-from-exercism-to-elm-pages-40eg</link>
      <guid>https://dev.to/leojpod/hacktober-from-exercism-to-elm-pages-40eg</guid>
      <description>&lt;p&gt;So, at the beginning of last month, I asked my boss at Zeit.io if it was ok to push some PRs around for Hacktober while waiting for the compiler which he, of course, accepted and encouraged. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgs.xkcd.com%2Fcomics%2Fcompiling.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgs.xkcd.com%2Fcomics%2Fcompiling.png" alt="The all-time excuse for slacking off at work"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No excuses for not doing this year then! &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="//Exercism.io"&gt;Exercism&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="//Exercism.io"&gt;Exercism&lt;/a&gt; is a great platform to learn a programing language and owning your skills. I was feeling kind of bad for not having time to review people's submissions on the elm-track as I used to a while back. So I decided that I could at least use Hacktober to give back to this platform by implementing a few problems for it. &lt;/p&gt;

&lt;p&gt;It was a rather interesting experience as porting a problem includes several steps: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RFTM ... (a step I clearly missed at first which lead to my first PRs failing tests because I hadn't set up properly my exercises). The &lt;a href="https://github.com/exercism/elm/#generating-setup" rel="noopener noreferrer"&gt;Generating setup&lt;/a&gt; part was really helpful to repair my dive-in-first-read-the-readme-after approach.&lt;/li&gt;
&lt;li&gt;The first step I always took after setting up the folder for the new exercise was to grab all the data from the &lt;code&gt;canonical-data.json&lt;/code&gt; file from the exercise specification and turn it into a test suite with &lt;a href="https://package.elm-lang.org/packages/elm-explorations/test/latest" rel="noopener noreferrer"&gt;elm-test&lt;/a&gt; (I was more than glad to use vim and to have become decent at making macros to turn each entry into a test case without having to write too much code myself)&lt;/li&gt;
&lt;li&gt;Once I had the test suite it was time for the really fun part: Make the first solution for the actual problem! For some exercises it was rather straight forward, for other it was actually more complex (looking at you &lt;a href="https://github.com/exercism/elm/pull/276" rel="noopener noreferrer"&gt;bowling exercise&lt;/a&gt;) &lt;/li&gt;
&lt;li&gt;Clean up! An important part of making nice exercises is to make sure that the solutions are clear enough as they might be de-facto examples for a while, one should make sure that the code looks nice enough. &lt;/li&gt;
&lt;li&gt;Push the PR and collect a T-shirt :) &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/exercism/elm/pull/276" rel="noopener noreferrer"&gt;Elm-pages&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I have recently discovered this project on the elm slack (join us here: &lt;a href="http://elmlang.herokuapp.com/" rel="noopener noreferrer"&gt;http://elmlang.herokuapp.com/&lt;/a&gt;). Since I'd read a few days before about the possibility to sync dev.to and something like gatsby I was quite keen on looking up this project. One of the issue I had originally was that it forced me to use the port 3000 to work with locally which was already quite crowded by work stuff. &lt;/p&gt;

&lt;p&gt;So I've made adding an option to specify the port my last Hacktober PR. It allowed me to dive into a really interesting project made by the same guy who is behind elm-pages ((Dillon Kearns)[&lt;a href="https://github.com/dillonkearns%5D):" rel="noopener noreferrer"&gt;https://github.com/dillonkearns]):&lt;/a&gt; (elm-cli-options-parser)[&lt;a href="https://github.com/dillonkearns/elm-cli-options-parser" rel="noopener noreferrer"&gt;https://github.com/dillonkearns/elm-cli-options-parser&lt;/a&gt;]. It's a project that allows you to use elm to define a CLI interface. It's simple yet powerful. If you want to build a CLI tool with elm or node definitely have a look. &lt;/p&gt;

&lt;p&gt;To sum it up, it didn't take very long to participate and hopefully help out and it was rather fun. Also, right after that, we completed our migration from elm 0.18 to 0.19 so no more "it's compiling" excuses from now on!&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>exercism</category>
      <category>elm</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The day I decided to learn DBext.vim</title>
      <dc:creator>leojpod</dc:creator>
      <pubDate>Mon, 23 Sep 2019 09:49:53 +0000</pubDate>
      <link>https://dev.to/leojpod/the-day-i-decided-to-learn-dbext-vim-523c</link>
      <guid>https://dev.to/leojpod/the-day-i-decided-to-learn-dbext-vim-523c</guid>
      <description>&lt;p&gt;Feel free to skip over that part and head straight to the hopefully useful content here.&lt;/p&gt;

&lt;p&gt;Almost a year and a half ago, while I was working at &lt;a href="https://repositive.io" rel="noopener noreferrer"&gt;Repositive&lt;/a&gt; (a cool start-up, you should check what they do), I was convinced by mostly 2 of my colleagues to start using vim. &lt;/p&gt;

&lt;p&gt;Soon after, I started a quest for plugins for everything! A part of that quest can be found by looking at the history of my dotfiles repo, you'll see it's a mess. &lt;/p&gt;

&lt;p&gt;At some point during that quest, I thought of looking for a plugin that would allow me to not use things like workbench, robomongo, pgAdmin or even &lt;code&gt;psql&lt;/code&gt; as I tend to use most after I ditched Atom for nvim. That's when I found this plugin: &lt;a href="https://github.com/vim-scripts/dbext.vim" rel="noopener noreferrer"&gt;DBext.vim&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It promised to do all I needed and then some more! awesome! &lt;/p&gt;

&lt;p&gt;Except, I never took the time to learn it properly hence I never used it and continued to hack my way with &lt;code&gt;psql&lt;/code&gt;. Fast-forward to today, I had to do a bunch of work on our database for my new ticket at &lt;a href="http://zeit.io" rel="noopener noreferrer"&gt;Zeit.io (new website coming soon - in the meantime, if you need something done well give us a call!)&lt;/a&gt; and went on looking for the perfect nvim plugin again and ... &lt;em&gt;wait a minute, I know this plugin!&lt;/em&gt; Yep... I knew it, it was already in my config and had been there for a while... So &lt;strong&gt;this time&lt;/strong&gt; I decided to take learn how to use it properly or well enough at least that I would not need to use &lt;code&gt;psql&lt;/code&gt; anymore and could work from my text editor. &lt;/p&gt;

&lt;h1&gt;
  
  
  Diving in &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;The repo's &lt;code&gt;README.md&lt;/code&gt; sounded a good place as any to start and that 's where I saw that &lt;code&gt;DBext.vim&lt;/code&gt; provided a nice tutorial, it might be a bit lengthy for some but in short: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;start by setting up a connection: in my case, I wanted to connect to PSQL by default so I added this to my &lt;code&gt;.vimrc&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let g:dbext_default_profile_PG = 'type=PGSQL:user=postgres:passwd=:host=localhost:port=5432:dbname=@askb'
let g:dbext_default_profile = 'PG'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the &lt;code&gt;@askb&lt;/code&gt;, it means that DBext will prompt me to know which database to connect once for each buffer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;then learn about a few commands that are quite handy: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;sbp&lt;/code&gt;: if your config isn't right this will allow you to open a quick setup guide. I used it a lot while trying things at first.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;slt&lt;/code&gt;: list the tables in your database.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;st&lt;/code&gt;: show table, probably one of the command I use the most. It allows you to get a really quick overview of a table. Just put your cursor over a table name, type in the mapping and voilà! (If you capitalise the &lt;code&gt;t&lt;/code&gt;, i.e. &lt;code&gt;&amp;lt;leader&amp;gt;sT&lt;/code&gt;, DBext will prompt you to know how many rows you'd like to see)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;stw&lt;/code&gt;: Same as above but will ask you for a &lt;code&gt;WHERE&lt;/code&gt; clause. This is sooo neat!&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;sd&lt;/code&gt;: Describe the table instead of listing its content, this is also pretty handy. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;But most importantly the feature I like the most in all of this is that I don't need to be in a SQL or any other database script: I can run all these from anywhere, from my front-end code, from the doc, from a ticket description, ... This allows me to get a quick glance at what the db holds and to get good insights on what it holds for which tables. &lt;/p&gt;

&lt;p&gt;EDIT: since I started writing this post, I've seen the &lt;a href="https://github.com/tpope/vim-dadbod" rel="noopener noreferrer"&gt;Tim pope version of this: &lt;code&gt;vim-dadbod&lt;/code&gt;&lt;/a&gt;. I haven't tried it yet, that might wait another year :D but if you've feedback about this plugin or some database recipes to share: please let me know! &lt;/p&gt;

</description>
      <category>vim</category>
      <category>productivity</category>
      <category>database</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The interesting case of the `/remind` command in slack</title>
      <dc:creator>leojpod</dc:creator>
      <pubDate>Wed, 31 Jul 2019 15:34:35 +0000</pubDate>
      <link>https://dev.to/leojpod/the-interesting-case-of-the-remind-command-in-slack-ihl</link>
      <guid>https://dev.to/leojpod/the-interesting-case-of-the-remind-command-in-slack-ihl</guid>
      <description>&lt;p&gt;A while back, as I was setting some reminder on slack so I would not forget about that code-review I was supposed to do, I missed type what I wanted to ask slack to remember. It showed me this help message: &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PXINZZWa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ienclwymnnwisyul59yj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PXINZZWa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ienclwymnnwisyul59yj.png" alt="@someone? really?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd seen this message a countless amount of time before but I don't know why I paused. &lt;code&gt;@someone&lt;/code&gt;? Really? Can I make slackbot notify other people whenever I want? Even if I'm not online? let's give it a try, shall we! &lt;/p&gt;

&lt;p&gt;Next, I was setting up a couple of reminders for my colleagues so they would not forget to drink coffee and take a walk from time to time to refresh their brain... &lt;/p&gt;

&lt;p&gt;Still when concentration is maybe the most precious asset for a dev, isn't it odd that we can steal away that of our co-workers in one line? &lt;br&gt;
In order to prevent any retaliation, I started using the &lt;code&gt;/dnd&lt;/code&gt; command to turn off any notification for a given amount of time. As an occasional Pomodoro person, I must that using &lt;code&gt;/dnd 25 minutes&lt;/code&gt; is working well. &lt;/p&gt;

&lt;p&gt;Has anyone found a useful use case for putting reminders to other people? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eZCyV7Cm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/h858v38xqmqwbdb81nmy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eZCyV7Cm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/h858v38xqmqwbdb81nmy.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>randomthoughts</category>
      <category>slack</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Has anyone tried pixel art with their GH profile?</title>
      <dc:creator>leojpod</dc:creator>
      <pubDate>Sun, 28 Jul 2019 14:52:01 +0000</pubDate>
      <link>https://dev.to/leojpod/has-anyone-tried-pixel-art-with-their-gh-profile-25p8</link>
      <guid>https://dev.to/leojpod/has-anyone-tried-pixel-art-with-their-gh-profile-25p8</guid>
      <description>&lt;p&gt;If you think of it, the infamous GitHub show-off activity-viewer is just a small canvas of roughly 52*7 pixels... &lt;/p&gt;

&lt;p&gt;It should be possible to make a mono-chrome of something with it. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ftv58kjzb8f5ms0olhylw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ftv58kjzb8f5ms0olhylw.png" alt="chrome's dev tool is practical"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>watercooler</category>
      <category>randomthoughts</category>
    </item>
    <item>
      <title>My 5 late ideas for the 'Blog More' challenge on CNC2018</title>
      <dc:creator>leojpod</dc:creator>
      <pubDate>Mon, 29 Jan 2018 15:52:11 +0000</pubDate>
      <link>https://dev.to/leojpod/my-5-late-ideas-for-the-blog-more-challenge-on-cnc2018-19b9</link>
      <guid>https://dev.to/leojpod/my-5-late-ideas-for-the-blog-more-challenge-on-cnc2018-19b9</guid>
      <description>&lt;p&gt;So here is a mix of 5 ideas which is a mix of some old and new ones for posting (those in &lt;strong&gt;&lt;em&gt;bold&lt;/em&gt;&lt;/strong&gt; are locked for the next phase):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;1/ Making a PWA in Elm: I made a small tabata/interval trainer app in Elm that runs with Webpack and cordova. How to make and deploy an app with that stack, how to make a PWA with lightbox, some personal experience and why I would skip cordova if I was to start again&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;2/ Playing with SVG and animation in Elm: still about this tabata app, I've made a few unsuccessful attempts to get a nice animation while working out and resting. Comparing generating an animation tag in SVG vs regenerating the SVG itself from Elm (latter is the best solution IMO but... I'd started with the other one first)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;3/ The carbon cost of emails. I recently switched from gmail to lilo.org's mail solution, it's a carbon-compensated solution and that got me to think of a few costs of emailing, problem is there isn't enough good numbers on it.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;4/ Some kind of shortish "biography" on how I went from an engineering school in France to freelancing from the North of Sweden and focus on a few pointers to start as a freelancer and of what I would do different.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;5/ Another Elm article about some of the tools in the ecosystems that I recently discovered hoping other Elm enthusiast will get to know them if they haven't already (mainly elm-lens &amp;amp; elm-analyse to provide the next level of code quality for your elm projects). &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I've got the 3 posts I needed! Thanks to all of you for helping! &lt;/p&gt;

</description>
      <category>discuss</category>
      <category>cnc2018</category>
      <category>misseddeadline</category>
    </item>
    <item>
      <title>A few more steps with Elm: Mdl, architecture and "local" update</title>
      <dc:creator>leojpod</dc:creator>
      <pubDate>Mon, 22 May 2017 15:20:24 +0000</pubDate>
      <link>https://dev.to/leojpod/a-few-more-steps-with-elm-mdl-architecture-and-local-update</link>
      <guid>https://dev.to/leojpod/a-few-more-steps-with-elm-mdl-architecture-and-local-update</guid>
      <description>&lt;h4&gt;
  
  
  Picking up where I left off last time, I'll share my experience on moving from an ugly web-page to an elm-mdl based one and how to split the code and the update method (which doesn't seem that popular though)
&lt;/h4&gt;

&lt;h3&gt;
  
  
  Starting to play with elm-mdl
&lt;/h3&gt;

&lt;p&gt;Although the module elm-mdl proved itself rather nice to use, setting it up wasn't as easy. I followed &lt;a href="https://medium.com/@dailydrip/introduction-to-using-material-design-in-elm-dc2320087410" rel="noopener noreferrer"&gt;this post&lt;/a&gt; to set up my app. The first step was to create a "property" on my main model to plug-in the mdl model. This is where elm-mdl is gonna work its magic and keep up with the state of things across the app. elm-mdl also provide us with an "initial" state for its module.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Next thing that we need to do to get ready to play with elm-mdl is to "tag" elm-mdl's messages so that anything coming up for an elm-mdl function in your code will be redirected to elm-mdl for handling, be transformed into whatever you asked for and be returned to you in a better message. We will do that by adding this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You'll probably have to follow the same principle for the subscription if you start playing with Layout and things like that but elm-mdl explain it rather well and the previously mention post as well.&lt;/p&gt;

&lt;p&gt;Then of course you need to remember to put these lines in your html file (and no I definitely did NOT scratched my head for a moment before I remember about it…)&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Talking about the index.html file. I couldn't find a nice way to use a custom html file with elm-reactor, so instead I turned to elm-live for that. Bottom line: install it with npm or yarn and then use this line to start your app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;elm-live "your-file" --output=elm.js --open
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and that's it! Elm-live will open your browser and reload as you make your changes! Ain't it cool?&lt;/p&gt;
&lt;h3&gt;
  
  
  Splitting the app into "modules"
&lt;/h3&gt;

&lt;p&gt;One thing bothered me with the code as it was: having all the code in a bunch of big files, no matter how clear they were, was still not "clean code" for me. So I went out and tried to find guidelines on how to split the code and found out &lt;a href="https://leojpod.github.io/elm-game-of-life/" rel="noopener noreferrer"&gt;this link&lt;/a&gt;. Well I had to pause a bit after reading it actually. Splitting the original code into different files to separate the responsibilities was rather easy. I got 4 files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Types.elm: host the types used in our application (mainly Model and Msg)&lt;/li&gt;
&lt;li&gt;State.elm: host the state of our application. i.e. how to initialize the application, how to update it&lt;/li&gt;
&lt;li&gt;View.elm: host the HTML of our application&lt;/li&gt;
&lt;li&gt;App.elm: ties it all together!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, that was enough for my small game but still it would have been cleaner to extract each part of the application in a separate module. So for the sack of the exercise (and for the peace of my mind…) I split up the application on 2 parts: the setup and the actual game. I will not go into the detail of the implementation of each module: it is more or less copied and paste from the previous implementation however linking the pieces together was rather interesting and we'll check that out here.&lt;/p&gt;

&lt;p&gt;First let's look at the "main" type file:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;What we see in here is more or less a natural definition of our model: a record that host the model definition of each of its submodule. Each module in turn is responsible for hosting whichever properties they need in their model. But the most interesting part (IMO at least) lies in the State.elm file where we will define the app's initial state and update function.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can see on the init, this code is rather simple yet verbose. For each direct child-module, our current modul need to pull the init state and add it to it's own init. This could be automatically written though, I hope to have some time to dig in &lt;a href="https://medium.com/u/b7650e3a2d8c" rel="noopener noreferrer"&gt;Atomist&lt;/a&gt; to try making that happen. Then the update method is just a dispatcher that forward each message to its rightful submodule. It makes it rather easy to communicate between each submodule as they just need to trigger the right message to send something to another module: in this app for instance, the setup send message to let the board module now when it should be ticking or not. The counter point to that is that it requires our view to send Msg (i.e. the main message type).&lt;/p&gt;

&lt;p&gt;The same observation can be seen on the Cmd part of our update method in the submodule. One could be tempted to "tag" the command like we do for the elm-mdl messages but then it would prevent or at least complicate the process of sending command to other modules.&lt;/p&gt;

&lt;p&gt;Anyhow, enough of that. Have a look at the code if you've questions, suggestions I'll be happy to talk :)&lt;/p&gt;

&lt;h3&gt;
  
  
  A quick stop via SVG!
&lt;/h3&gt;

&lt;p&gt;Before closing this post, let's have a look at how manipulating SVG is seamless in Elm. For those who checked the code of my &lt;a href="https://dev.to/leojpod/getting-started-with-elm-temp-slug-9740695"&gt;first post&lt;/a&gt; about elm you've seen something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F264%2F1%2AwCs3p4YIv804MvT5CRnBAA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F264%2F1%2AwCs3p4YIv804MvT5CRnBAA.png"&gt;&lt;/a&gt;the ugly state in which I left things lastÂ time.&lt;/p&gt;

&lt;p&gt;The view code that was responsible for that horror looking table was this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Switching to SVG was seamless: in Elm SVG nodes are manipulated exactly like HTML ones! (provided you remember to elm package elm-lang/svg).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And we're done!&lt;/p&gt;

&lt;p&gt;If you want to have a look at the app's current state: &lt;a href="http://leojpod.github.io/elm-game-of-life/" rel="noopener noreferrer"&gt;check this out&lt;/a&gt;&lt;/p&gt;

</description>
      <category>games</category>
      <category>helloworld</category>
      <category>elm</category>
    </item>
    <item>
      <title>Why is there no need for Multicase matching in Elm</title>
      <dc:creator>leojpod</dc:creator>
      <pubDate>Thu, 30 Mar 2017 15:23:58 +0000</pubDate>
      <link>https://dev.to/leojpod/why-is-there-no-need-for-multicase-matching-in-elm</link>
      <guid>https://dev.to/leojpod/why-is-there-no-need-for-multicase-matching-in-elm</guid>
      <description>&lt;p&gt;As a beginner developer with Elm, I quickly ended up both loving the union types and the _ operator but founded a tad bit irritating the absence of Multicase matching until … Until I saw the &lt;a href="http://stackoverflow.com/questions/41118171/handling-multiple-match-cases-with-single-statement-in-elm"&gt;light&lt;/a&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  TL;DR?
&lt;/h3&gt;

&lt;p&gt;Use the following pattern whenever you have some behaviour shared by several constructor of your union types and stay away from the _ operator!&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  The problem with single case matching
&lt;/h3&gt;

&lt;p&gt;Let's say I want to create a task tracking software. I might end up with this Item type to describe my model:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can guess, a lot of operations are gonna require the same treatment for most kind of Item : assigning the item to somebody, changing the start or end date, adding/editing a description, … while there will be some that will differ. So how can we deal with that?&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the underscore matching
&lt;/h3&gt;

&lt;p&gt;When I encountered this problem my first idea was to use the _ to match all the kind of Item that didn't require a specific treatment for any given case ... of . There are two main problems with that approach: we can't get the properties and it introduce potential &lt;strong&gt;BUGS!&lt;/strong&gt; And by that I mean problems and unexpected behaviour that won't be caught up by the compiler. But first let's see how it looks:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let's take back the Item example and let's pretend that we want to create a new kind of Item : milestone. Say milestones do not have start date but are just used as deadlines. Say my app is pretty developed and I am doing a lot of things on my Item and use the underscore matching a lot. By adding a new kind of Item in my union type I'd expect the compiler to throw a bunch of errors at my face directly which will not happen in that case: my new kind Milestone would already be matched by the _ so there will not be anything wrong that will be caught by the compiler. Yet I probably don' t want my Milestone items to be dealt with like any other items… So I would have to resolve to looking up for any _ and make sure that I adapt the code manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  The replacement
&lt;/h3&gt;

&lt;p&gt;Use let … in! (or make another helper function)… It really is as simple as that… instead of making multicase matching, put the common treatment in a function within the let ... in or put it outside if the treatment is consequent and use it afterwards:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And voilÃ ! It sounds pretty stupid but I hope it helps!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitlab.com/leojpod/elm-task-stuff"&gt;Here&lt;/a&gt; is a small "project" showing this… nothing fancy, only one message and one button.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>elm</category>
    </item>
    <item>
      <title>To all JS dev, please use Standard!</title>
      <dc:creator>leojpod</dc:creator>
      <pubDate>Wed, 29 Mar 2017 14:52:52 +0000</pubDate>
      <link>https://dev.to/leojpod/to-all-js-dev-please-use-standard</link>
      <guid>https://dev.to/leojpod/to-all-js-dev-please-use-standard</guid>
      <description>&lt;h1&gt;
  
  
  Once upon a time
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;you can jump over that section it's merely an introduction of what has led me to adopt standardjs&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As a dev coming from the world of Java to JavaScript some 6-7 years ago I was kind of lost by the "liberty" of coding that JS offered. Then again with that was a good deal of good and bad things and I quickly ended up using JSLint to help me navigate through this world and to teach me what was right and what was wrong. &lt;/p&gt;

&lt;p&gt;It wasn't enough though. I quickly moved on to JSHint, later to JSCS and to ESLint with each time a new set of recommendations and some change to my coding style and habits. It is worse noting that most of these tools were actually a great help to polish my skills little by little each of them providing finner and finner warnings. &lt;/p&gt;

&lt;p&gt;What's the link with Standard.js? &lt;/p&gt;

&lt;p&gt;That I've seen a lot of different style of JavaScript and I am use to the discomfort of changing your coding habits from one style to the other depending on which project one works on. &lt;/p&gt;

&lt;p&gt;Recently, I've been working on 3 different freelance projects all using different configuration of ESLint... Why are we doing that to ourselves when there is a single style without config (a.k.a divergences) readily usable! &lt;/p&gt;

&lt;p&gt;By using one single config for all the JS code out there no more time spent configuring an IDE, no more time "configuring" our brain to read and write the code according to this or that style. &lt;/p&gt;

&lt;h1&gt;
  
  
  The ultimate rules!
&lt;/h1&gt;

&lt;p&gt;As said previously, standardjs makes opinionated yet fully justified choice regarding the coding style. You may not agree with all of them but it doesn't matter! (I disagree with many exceptions of the French language but I still accept them :x). &lt;/p&gt;

&lt;p&gt;Here are the "main" ones: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no unused variable: it always drive me nuts when I review some code to see them... I become a game of guessing, what that supposed to be used somewhere? Should I delete the whole stuff? &lt;/li&gt;
&lt;li&gt;plenty of aesthetic decisions that helps make the code clearer&lt;/li&gt;
&lt;li&gt;plenty of totally sound decisions about more or less obscure things that are allowed by JavaScript but that should never have been! (like reassigning const, calling constructor without parenthesis when there is no parameters, ...)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Globally there is nothing out of the ordinary in there. Most of these rules are already applied by most of the good coding styles out there. The most important change however is yet to be introduced. &lt;/p&gt;

&lt;h1&gt;
  
  
  Getting ride of the semicolon
&lt;/h1&gt;

&lt;p&gt;Perhaps the most important change when switching to standardjs is to stop putting &lt;code&gt;;&lt;/code&gt; all around the place. We don't need it! If you doubt it, go read &lt;a href="http://blog.izs.me/post/2353458699/an-open-letter-to-javascript-leaders-regarding"&gt;this&lt;/a&gt; and &lt;a href="http://inimino.org/~inimino/blog/javascript_semicolons"&gt;that&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;When I read it for the first time I paused for a second and asked myself why I had always put some? 'cause I was coming from Java and Java forced me to... Right but other than that? No idea. &lt;/p&gt;

&lt;p&gt;Moreover, how many lines of code do we type everyday? sparing that one key press if helping greatly to reduce the stress and repetitive strain injury risks to our right ring finger. Ain't it great? &lt;/p&gt;

&lt;h1&gt;
  
  
  Just a few more words
&lt;/h1&gt;

&lt;p&gt;A few notes to conclude this totally biased post: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;standard is totally compatible with ES6! &lt;/li&gt;
&lt;li&gt;there is an effort toward &lt;a href="https://github.com/blakeembrey/tslint-config-standard"&gt;porting standard to the TypeScript world&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;you don't need to agree with me but please give standard a try :D&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>lint</category>
      <category>standardjs</category>
      <category>codestyle</category>
    </item>
  </channel>
</rss>
