<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>blog@clarkwinkelmann</title>
    <description>I'm a Webdesign, Laravel, Linux and Open-source enthusiast</description>
    <link>https://blog.clarkwinkelmann.com/</link>
    <atom:link href="https://blog.clarkwinkelmann.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Mon, 12 Nov 2018 16:46:01 +0000</pubDate>
    <lastBuildDate>Mon, 12 Nov 2018 16:46:01 +0000</lastBuildDate>
    <generator>Jekyll v3.7.4</generator>
    
      <item>
        <title>A look behind my FLL scoreboard</title>
        <description>&lt;p&gt;It’s the fourth year in a row that I develop a &lt;a href=&quot;https://robots-ju.ch/outils&quot;&gt;web scoreboard&lt;/a&gt; for the &lt;a href=&quot;http://www.firstlegoleague.org/&quot;&gt;FLL RobotGame&lt;/a&gt; competition.&lt;/p&gt;

&lt;p class=&quot;wide-picture&quot;&gt;&lt;a href=&quot;https://fll-scoreboard-2017.robots-ju.ch/&quot;&gt;&lt;img src=&quot;/media/2017/08/fll-scoreboard-2017.jpg&quot; alt=&quot;Screenshot of the 2017 scoreboard&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s starting to get routine, but each year has hat its lot of changes. I could have taken the same code base each year and simply update some variable, tweak logos and fix the calculation, but it evolved a bit more than that.&lt;/p&gt;

&lt;p&gt;First, what is it ? The Robot Game is one of four challenges of FIRST LEGO League competition. Two teams compete on a mat with LEGO robots. Robots have 2min30 to score a maximum of points in different missions on the mat, in complete autonomy. Each year a new mat is released with missions around the season theme.&lt;/p&gt;

&lt;p&gt;These missions are described in the challenge rules, and calculating your total of points is sometimes complicated, and often a bit ambiguous.&lt;/p&gt;

&lt;p&gt;It’s never been clear to me if there is or isn’t an official scoreboard. The FLL has a platform to manage the competition that seems to handle score calculation, but it’s not publicly accessible. They also release the paper forms used by judges during the tournaments, but you have to calculate scores by hand !&lt;/p&gt;

&lt;p&gt;That’s why in 2014 I created my &lt;a href=&quot;https://fll-scoreboard-2014.robots-ju.ch/&quot;&gt;first FLL scoreboard&lt;/a&gt;, and did so the following years as well.&lt;/p&gt;

&lt;p&gt;Oh, and I should mention I’m a coach and “IT guy” in the &lt;a href=&quot;https://robots-ju.ch/&quot;&gt;Robots-JU robotics association&lt;/a&gt;, which is why I’m dealing with this competition. We also organized our own competition, as you will see below and probably read in future posts as well.&lt;/p&gt;

&lt;p&gt;Let’s go back in history and explore the different iterations of my scoreboard.&lt;/p&gt;

&lt;h2 id=&quot;2014&quot;&gt;2014&lt;/h2&gt;

&lt;p class=&quot;wide-picture&quot;&gt;&lt;a href=&quot;https://fll-scoreboard-2014.robots-ju.ch/&quot;&gt;&lt;img src=&quot;/media/2017/08/fll-scoreboard-2014.jpg&quot; alt=&quot;Screenshot of the 2014 scoreboard&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If I remember correctly it’s the first year I joined as a coach, and also the time where we officially founded the association. I participated in the FLL the previous two years as a member, but I was now too old to take part. So I joined as a coach and took care to setup our website and such.&lt;/p&gt;

&lt;p&gt;I also decided to create a scoreboard. I knew from experience it would be really useful during the training, even if it was far from perfect. 2014 had a some very complicated rules where you had to calculate fractions of points for some missions to get the final result, making it very hard to do by hand.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://fll-scoreboard-2014.robots-ju.ch/&quot;&gt;2014 scoreboard&lt;/a&gt; was a simple vanilla javascript application, with most of the calculation and texts hard-coded in the page. The page also featured a print stylesheet, which was never really used, and a sharable url, which also wasn’t particularly useful to my knowledge, given it was mostly used internally.&lt;/p&gt;

&lt;p&gt;Right from the start I decided to publish the scoreboards on our website for everyone to use, and also published the &lt;a href=&quot;https://github.com/robots-ju/fll-scoreboard-2014&quot;&gt;source code&lt;/a&gt; under the MIT license on GitHub&lt;/p&gt;

&lt;h2 id=&quot;2015&quot;&gt;2015&lt;/h2&gt;

&lt;p class=&quot;wide-picture&quot;&gt;&lt;a href=&quot;https://fll-scoreboard-2015.robots-ju.ch/&quot;&gt;&lt;img src=&quot;/media/2017/08/fll-scoreboard-2015.jpg&quot; alt=&quot;Screenshot of the 2015 scoreboard&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://fll-scoreboard-2015.robots-ju.ch/&quot;&gt;2015 scoreboard&lt;/a&gt; re-used the 2014 style, but everything else was rewritten.&lt;/p&gt;

&lt;p&gt;I dropped the print stylesheet and also removed the shareable url feature.&lt;/p&gt;

&lt;p&gt;Since 2014 I started using React and thought it was a perfect fit for the job, with plenty of inputs to sync and a single state management logic.&lt;/p&gt;

&lt;p&gt;A regular complaint about the previous scoreboard was that it only contained English mission descriptions (We’re in the French part of Switzerland). So this year I added both French and English variations.&lt;/p&gt;

&lt;p&gt;A big issue with the 2014 scoreboard was its fixed width. It was highly impractical on mobile devices. The 2015 version partly fixes it by aligning missions more regularly on the screen and allowing them to resize as the screen gets smaller.&lt;/p&gt;

&lt;p&gt;Another big issue with the 2014 scoreboard was its unreliability. It contained no unit tests, and each fix was threatening the whole calculator.&lt;/p&gt;

&lt;p&gt;To solve this, I extracted the calculator part of the scoreboard into a &lt;a href=&quot;https://github.com/robots-ju/fll-robotgame-scorer-2015&quot;&gt;separate package&lt;/a&gt;, which would include a complete test suite checking every single mission based on the official rules.&lt;/p&gt;

&lt;p&gt;At the start of 2016 we organized our first robotics competition, the &lt;a href=&quot;https://coupe.robots-ju.ch/&quot;&gt;Coupe Robots-JU&lt;/a&gt;. The competition re-use the Robot Game mat and rules of the FLL so teams who prepared for the FLL can easily take part in our competition as well.&lt;/p&gt;

&lt;p&gt;During a typical FLL tournament, the Robot Game is divided into 3 rounds, in with each team plays once again another team. Matches usually start on alternate table every 5 minutes. The large breaks between rounds usually get overflowed by the matches schedule falling behind, and a lot of time seems to be lost calculating the ranks (thought it improved in the last years, probably because it’s now done on the platform I mentioned above).&lt;/p&gt;

&lt;p&gt;During our Coupe, we pushed the concept further by making each team play multiple times per round, with a match starting every 5 minute and nearly no break. At the same time, the rankings were shown live on screen. This was made possible by judges using the scoreboard to quickly validate and send scores.&lt;/p&gt;

&lt;p&gt;Integrating the web scoreboard into the scoring application wasn’t too difficult, given the ease to re-use React components.&lt;/p&gt;

&lt;p&gt;The biggest issue we noticed was that it was hard to make sure you covered every single mission in the scoreboard before sending it. It’s also an issue we noticed when we wanted to quickly check we entered the correct data in the scoreboard just by looking at the mat.&lt;/p&gt;

&lt;p&gt;It was useless to make changes to the scoreboard at that time, given the FLL season ended and the Coupe was a one-time event. It would be improved the next year.&lt;/p&gt;

&lt;h2 id=&quot;2016&quot;&gt;2016&lt;/h2&gt;

&lt;p class=&quot;wide-picture&quot;&gt;&lt;a href=&quot;https://fll-scoreboard-2016.robots-ju.ch/&quot;&gt;&lt;img src=&quot;/media/2017/08/fll-scoreboard-2016.jpg&quot; alt=&quot;Screenshot of the 2016 scoreboard&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://fll-scoreboard-2016.robots-ju.ch/&quot;&gt;2016 scoreboard&lt;/a&gt; aimed to solve the remaining issues.&lt;/p&gt;

&lt;p&gt;At the association we used the scoreboard on PCs, but it was clear that anybody from outside or simply on the go would prefer to use the app on a mobile device. The 2015 resizable layout was simply making things smaller on small screens. It was time to introduce a mobile-first layout.&lt;/p&gt;

&lt;p&gt;The interface was rewritten to just show small badges on the mat, and let the user browse mission details in a separate, paginated panel. The new layout also made place for longer mission descriptions and mission pictures.&lt;/p&gt;

&lt;p&gt;The new interface also solved the coverage issue encountered the last year. By adding a paginated list of missions, it was now a lot easier to review all missions in order and not miss one. It was still possible to directly click on a mission on the mat to access it, just like before.&lt;/p&gt;

&lt;p&gt;Social buttons to share the score on Twitter and connect with our association were added, but it looks like there were as much used as the print layout of the 2014 version.&lt;/p&gt;

&lt;p class=&quot;wide-picture&quot;&gt;&lt;img src=&quot;/media/2017/08/20170311-coupe.jpg&quot; alt=&quot;Judges at the Coupe Robots-JU 2017&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Once again we organized the &lt;a href=&quot;https://coupe.robots-ju.ch/&quot;&gt;Coupe Robots-JU&lt;/a&gt; and used the scoreboard as part of the technology stack involved. The new layout proved a lot more efficient. Recording the scores and getting the team validation was now one of the shortest part of the organization (we’ve not managed to automate setting the mat back in start position yet !). We even managed to finish matches ahead of schedule at the end of the day !&lt;/p&gt;

&lt;p&gt;A big advantage of using that scoreboard to calculate the scores is that you not only store the final score, but also the details of accomplished missions. This is useful for statistics and providing a complete &lt;a href=&quot;https://coupe.robots-ju.ch/resultats&quot;&gt;detailed list&lt;/a&gt; of the results for each team and match. I suspect the official FLL platform also keeps track of the individual missions, but these are not shown in the interface.&lt;/p&gt;

&lt;h2 id=&quot;2017&quot;&gt;2017&lt;/h2&gt;

&lt;p class=&quot;wide-picture&quot;&gt;&lt;a href=&quot;https://fll-scoreboard-2017.robots-ju.ch/&quot;&gt;&lt;img src=&quot;/media/2017/08/fll-scoreboard-2017.jpg&quot; alt=&quot;Screenshot of the 2017 scoreboard&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here we are. This year challenge rules were released on the 28th of August, and I decided to try to break my personal (and maybe worldwide ?) record of time taken to publish an unofficial scoreboard.&lt;/p&gt;

&lt;p&gt;It usually took me a few months before starting the work on the scoreboard so I don’t have to rewrite everything in case of a rule change. But this year the rules looked pretty straightforward so I started right away. In less than 12 hours the &lt;a href=&quot;https://fll-scoreboard-2017.robots-ju.ch/&quot;&gt;2017 scoreboard&lt;/a&gt; was online.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;fr&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Never finished coding the season scoreboard so quickly. Less than 12 hours since challenge release &lt;a href=&quot;https://twitter.com/hashtag/FLL?src=hash&quot;&gt;#FLL&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/HYDRODYNAMICS?src=hash&quot;&gt;#HYDRODYNAMICS&lt;/a&gt; &lt;a href=&quot;https://t.co/cFffxWQ4tl&quot;&gt;https://t.co/cFffxWQ4tl&lt;/a&gt;&lt;/p&gt;&amp;mdash; Clark Winkelmann (@clarkwinkelmann) &lt;a href=&quot;https://twitter.com/clarkwinkelmann/status/902739466045009920&quot;&gt;30 août 2017&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;I could probably have done it even faster, but I took the opportunity to make a few changes.&lt;/p&gt;

&lt;p&gt;Since 2015 I went from React to Mithril as my main framework, and it already caused a few integration issues during the last Coupe to integrate the React scoreboard into the Mithril app. The React code of 2016 was also a big mess because everything was fit into a single file, meaning it required some major rewrite anyway.&lt;/p&gt;

&lt;p&gt;I decided to re-create the exact same logic from React in Mithril. This went without issues, given the large similarities between the frameworks. The CSS style stayed mostly the same, with updated colors to reflect this year’s theme.&lt;/p&gt;

&lt;p&gt;I also switched from a custom Gulp file to a Laravel Mix setup, which basically did the same things with nearly no code, better performance and better out of the box optimizations for the production files. I also dumped Bower completely and now use Yarn to install all dependencies. This removes a lot of complexity.&lt;/p&gt;

&lt;p&gt;The most time-consuming tasks are copying texts from official websites and PDFs into the test suite and the scoreboard missions list. Since 2016 the layout is built from a JSON file, which allows for easy changes to the list of missions.&lt;/p&gt;

&lt;p&gt;You can use the scoreboard on the Robots-JU website at &lt;a href=&quot;https://fll-scoreboard-2017.robots-ju.ch/&quot;&gt;https://fll-scoreboard-2017.robots-ju.ch/&lt;/a&gt; and also check out the &lt;a href=&quot;https://github.com/robots-ju/fll-scoreboard-2017&quot;&gt;scoreboard source&lt;/a&gt; and the &lt;a href=&quot;https://github.com/robots-ju/fll-robotgame-scorer-2017&quot;&gt;unit-tested score calculator source&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;future&quot;&gt;Future&lt;/h2&gt;

&lt;p&gt;In 2018 we will organize the third Coupe Robots-JU, which will most likely rely on the 2017 scoreboard. With the improvements of the past years, it has now become a robust part of our scoring stack.&lt;/p&gt;

&lt;p&gt;As long as I will be an FLL coach and FIRST does not release an official and better tool I will probably keep coding new scoreboards. And I’m certainly not finished switching javascript frameworks either…&lt;/p&gt;

&lt;p&gt;Given its early release it’s highly probable the 2017 scoreboard still has issues to address. Feel free to drop by the &lt;a href=&quot;https://github.com/robots-ju/fll-scoreboard-2017/issues&quot;&gt;issues section&lt;/a&gt; on GitHub to report problems, make suggestions or directly contribute code.&lt;/p&gt;

&lt;p&gt;If your team uses the scoreboard, we would be happy to hear about it. Please tweet us comments or pictures at &lt;a href=&quot;https://twitter.com/RobotsJU&quot;&gt;@RobotsJU&lt;/a&gt; !&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Written with &lt;a href=&quot;https://stackedit.io/&quot;&gt;StackEdit&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Wed, 30 Aug 2017 23:00:00 +0000</pubDate>
        <link>https://blog.clarkwinkelmann.com/2017/08/behind-my-fll-scoreboard</link>
        <guid isPermaLink="true">https://blog.clarkwinkelmann.com/2017/08/behind-my-fll-scoreboard</guid>
        
        
      </item>
    
      <item>
        <title>Step-by-step creation of my Flarum Emoji extension</title>
        <description>&lt;p&gt;This is a step-by-step guide on how I created my EmojiOne Area Picker extension for Flarum. For more info about my research, trial&amp;amp;error and sources or information, see &lt;a href=&quot;/2017/02/my-first-flarum-extension&quot;&gt;my other article&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;before-we-start&quot;&gt;Before we start&lt;/h2&gt;

&lt;p&gt;This was done with Flarum beta 6 on an Ubuntu 16.04 system. I cannot guarantee it will apply to future versions of Flarum.&lt;/p&gt;

&lt;p&gt;I have a local Flarum install in &lt;code class=&quot;highlighter-rouge&quot;&gt;/var/www/flarum&lt;/code&gt;. This is referred as the &lt;em&gt;Flarum root&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In code snippets, &lt;code class=&quot;highlighter-rouge&quot;&gt;[...]&lt;/code&gt; indicates that nothing changed from the last snippet of the same file.&lt;/p&gt;

&lt;h2 id=&quot;workbench-setup&quot;&gt;Workbench setup&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Based on &lt;a href=&quot;https://discuss.flarum.org/d/1608-extension-development-using-composer-repositories-path&quot;&gt;this discussion&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create a new &lt;code class=&quot;highlighter-rouge&quot;&gt;workbench&lt;/code&gt; folder under the Flarum install and register it as a repository in Flarum’s &lt;code class=&quot;highlighter-rouge&quot;&gt;composer.json&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;repositories&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;workbench&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;workbench/*/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;extension-setup&quot;&gt;Extension setup&lt;/h2&gt;

&lt;p&gt;Create new new folder with the name of the extension inside the &lt;code class=&quot;highlighter-rouge&quot;&gt;workbench&lt;/code&gt; folder, in my case &lt;code class=&quot;highlighter-rouge&quot;&gt;workbench/flarum-ext-emojionearea&lt;/code&gt;. That’s where my extension will be placed and I will refer to it as the &lt;em&gt;Extension folder&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Next create a &lt;code class=&quot;highlighter-rouge&quot;&gt;composer.json&lt;/code&gt; file inside the extension folder with your details:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;clarkwinkelmann/flarum-ext-emojionearea&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Add EmojiOne Area emoji picker to Flarum&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;flarum-extension&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;require&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;flarum/core&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^0.1.0-beta.6&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;extra&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;flarum-extension&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;EmojiOne Area&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then require the extension in Flarum’s &lt;code class=&quot;highlighter-rouge&quot;&gt;composer.json&lt;/code&gt; file with the following line:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;clarkwinkelmann/flarum-ext-emojionearea&quot;: &quot;*@dev&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running &lt;code class=&quot;highlighter-rouge&quot;&gt;composer update&lt;/code&gt; will add a symlink from the &lt;code class=&quot;highlighter-rouge&quot;&gt;vendor&lt;/code&gt; directory to the extension folder, so we don’t need to run a Composer command every time we change our extension in the workbench.&lt;/p&gt;

&lt;h2 id=&quot;javascript-setup&quot;&gt;Javascript setup&lt;/h2&gt;

&lt;p&gt;All following paths are relative to the &lt;em&gt;extension path&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Javscript code will be placed in &lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum&lt;/code&gt; in the extension folder. In this folder we will need two files:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum/package.json&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;private&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;devDependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;gulp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^3.8.11&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;flarum-gulp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^0.2.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum/Gulpfile.js&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;flarum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'flarum-gulp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;flarum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;modules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'clarkwinkelmann/emojionearea'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;'src/**/*.js'&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We also create the javascript bootstrap file that will setup our extension.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum/src/main.js&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;initializers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'clarkwinkelmann-emojionearea'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Nothing yet&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When running &lt;code class=&quot;highlighter-rouge&quot;&gt;gulp&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;gulp watch&lt;/code&gt; this will create an &lt;code class=&quot;highlighter-rouge&quot;&gt;extension.js&lt;/code&gt; file in the &lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum/dist&lt;/code&gt; folder.&lt;/p&gt;

&lt;h2 id=&quot;less-setup&quot;&gt;LESS setup&lt;/h2&gt;

&lt;p&gt;This is easy, create a &lt;code class=&quot;highlighter-rouge&quot;&gt;less/forum/extension.less&lt;/code&gt; file.&lt;/p&gt;

&lt;h2 id=&quot;php-setup&quot;&gt;PHP setup&lt;/h2&gt;

&lt;p&gt;We only need PHP to register our assets, this is done in &lt;code class=&quot;highlighter-rouge&quot;&gt;bootstrap.php&lt;/code&gt; at the root of the extension folder:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Flarum\Event\ConfigureClientView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Illuminate\Contracts\Events\Dispatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Dispatcher&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$events&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ConfigureClientView&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ConfigureClientView&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isForum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addAssets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;__DIR__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/js/forum/dist/extension.js'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;__DIR__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/less/forum/extension.less'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addBootstrapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'clarkwinkelmann/emojionearea/main'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;coding-javascript&quot;&gt;Coding javascript&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Inspired by the &lt;a href=&quot;https://github.com/flagrow/upload&quot;&gt;flagrow/upload&lt;/a&gt; extension.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will use the &lt;a href=&quot;https://github.com/mervick/emojionearea&quot;&gt;mervick/emojionearea&lt;/a&gt; jQuery plugin, so we first need to add it as a dependency:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum/package.json&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;private&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;devDependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;gulp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^3.8.11&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;flarum-gulp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^0.2.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;emojionearea&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^3.1.5&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We need to create our own button. For that, we create a new file for our &lt;code class=&quot;highlighter-rouge&quot;&gt;EmojiAreaButton&lt;/code&gt; that is based on the base &lt;code class=&quot;highlighter-rouge&quot;&gt;flarum/Component&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum/src/components/EmojiAreaButton.js&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;flarum/Component&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;icon&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;flarum/helpers/icon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EmojiAreaButton&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'div'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Button Button-emojionearea hasIcon Button--icon'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'smile-o'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Button-icon'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'span'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Button-label'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Emojis'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'span'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Button-emojioneareaContainer'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;.Button-emojionearea&lt;/code&gt; class allows us to target the button with CSS and the &lt;code class=&quot;highlighter-rouge&quot;&gt;.Button-emojioneareaContainer&lt;/code&gt; element will contain the picker that we will load with jQuery.&lt;/p&gt;

&lt;p&gt;We need to run the &lt;code class=&quot;highlighter-rouge&quot;&gt;$.emojioneArea()&lt;/code&gt; method after this component has been loaded. For that we make use of Mithril’s &lt;code class=&quot;highlighter-rouge&quot;&gt;config&lt;/code&gt; attribute. This allows you to supply a method that will be called each time a DOM item is redrawn. The &lt;code class=&quot;highlighter-rouge&quot;&gt;isInitialized&lt;/code&gt; parameter informs us the method has already been called.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;nx&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'div'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;configArea&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'[...]'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// [...]&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;configArea&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isInitialized&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isInitialized&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$container&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'.Button-emojioneareaContainer'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can then load our javascript plugin in the &lt;code class=&quot;highlighter-rouge&quot;&gt;configArea()&lt;/code&gt; method. We load emojiOneArea on a new jQuery &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;div/&amp;gt;&lt;/code&gt; so it does not try to find a &lt;code class=&quot;highlighter-rouge&quot;&gt;textarea&lt;/code&gt; and we put the picker inside our &lt;code class=&quot;highlighter-rouge&quot;&gt;$container&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;nx&quot;&gt;configArea&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isInitialized&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// [...]&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&amp;lt;div /&amp;gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emojioneArea&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;standalone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;hideSource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;emojibtn_click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;c1&quot;&gt;// emoji clicked&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can then add our button to the post editor.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum/src/main.js&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;flarum/extend&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TextEditor&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;flarum/components/TextEditor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EmojiAreaButton&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'clarkwinkelmann/emojionearea/components/EmojiAreaButton'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;initializers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'clarkwinkelmann-emojionearea'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TextEditor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'controlItems'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;emojiButton&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EmojiAreaButton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'clarkwinkelmann-emojionearea'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;emojiButton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In order for the jQuery plugin to load, we need to add it to our Gulpfile as a &lt;code class=&quot;highlighter-rouge&quot;&gt;file&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum/Gulpfile.js&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;flarum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'flarum-gulp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;flarum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'node_modules/emojionearea/dist/emojionearea.js'&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;modules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'clarkwinkelmann/emojionearea'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;'src/**/*.js'&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After running &lt;code class=&quot;highlighter-rouge&quot;&gt;npm install&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;gulp&lt;/code&gt; (or &lt;code class=&quot;highlighter-rouge&quot;&gt;gulp watch&lt;/code&gt;) in &lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum&lt;/code&gt;, the extension can be enabled in the Flarum install and the Emoji picker is loaded inside the button. Clicking on an emoji does not do anything yet.&lt;/p&gt;

&lt;p&gt;To add text to the post, we need to call the &lt;code class=&quot;highlighter-rouge&quot;&gt;insertAtCursor()&lt;/code&gt; method on the &lt;code class=&quot;highlighter-rouge&quot;&gt;TextEditor&lt;/code&gt; instance. This is not accessible from our button by default, we need to save a pointer when we extend the editor.&lt;/p&gt;

&lt;p&gt;We add the attribute to our button:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum/src/components/EmojiAreaButton.js&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// [...]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EmojiAreaButton&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;textEditor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// [...]&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And fill it at extend time:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum/src/main.js&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// [...]&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;initializers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'clarkwinkelmann-emojionearea'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TextEditor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'controlItems'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;emojiButton&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EmojiAreaButton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;emojiButton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;textEditor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'clarkwinkelmann-emojionearea'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;emojiButton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can access it when an emoji is clicked:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum/src/components/EmojiAreaButton.js&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;nx&quot;&gt;configArea&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isInitialized&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// [...]&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;textEditor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&amp;lt;div /&amp;gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emojioneArea&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// [...]&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;emojibtn_click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;shortcode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'name'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;nx&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;insertAtCursor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;shortcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And it works ! Some optimisations were not shown here, have a look at the &lt;a href=&quot;https://github.com/clarkwinkelmann/flarum-ext-emojionearea&quot;&gt;source code&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;coding-cssless&quot;&gt;Coding CSS/LESS&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;less/forum/extension.less&lt;/code&gt; file contains a few rules to hide the parts of the picker we do not need. Have a look at it &lt;a href=&quot;https://github.com/clarkwinkelmann/flarum-ext-emojionearea/blob/master/less/forum/extension.less&quot;&gt;here&lt;/a&gt; on GitHub for the details.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This CSS part is my own invention &lt;a href=&quot;https://discuss.flarum.org/d/4651-how-to-import-css-from-dependency&quot;&gt;because I did not find any other extension doing it&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To include the CSS of the picker, I use another (normal) Gulp file to copy the CSS needed to a &lt;code class=&quot;highlighter-rouge&quot;&gt;dist&lt;/code&gt; folder, much like the javascript part:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;css/forum/package.json&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;private&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;devDependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;gulp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^3.8.11&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;emojionearea&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^3.1.5&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;css/forum/Gulpfile.js&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'gulp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'default'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'node_modules/emojionearea/dist/emojionearea.css'&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dist'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running &lt;code class=&quot;highlighter-rouge&quot;&gt;npm install&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;gulp&lt;/code&gt; in &lt;code class=&quot;highlighter-rouge&quot;&gt;css/forum&lt;/code&gt; produces a &lt;code class=&quot;highlighter-rouge&quot;&gt;css/forum/dist/emojionearea.css&lt;/code&gt; file that will be included in version control. We also add this file to the &lt;code class=&quot;highlighter-rouge&quot;&gt;bootstrap.php&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Flarum\Event\ConfigureClientView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Illuminate\Contracts\Events\Dispatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Dispatcher&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$events&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ConfigureClientView&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ConfigureClientView&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isForum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addAssets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;__DIR__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/js/forum/dist/extension.js'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;__DIR__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/less/forum/extension.less'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;__DIR__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/css/forum/dist/emojionearea.css'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addBootstrapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'clarkwinkelmann/emojionearea/main'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To finish properly, add a &lt;code class=&quot;highlighter-rouge&quot;&gt;README.md&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;LICENSE.txt&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt; file. Here’s what I used in the &lt;code class=&quot;highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;**/node_modules
/vendor
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In my case I did not even had to run &lt;code class=&quot;highlighter-rouge&quot;&gt;composer install&lt;/code&gt; in the extension folder, but if I had unit tests (for example) I would have to run composer. That’s where the &lt;code class=&quot;highlighter-rouge&quot;&gt;/vendor&lt;/code&gt; rule in the gitignore would be useful.&lt;/p&gt;

&lt;p&gt;Now your extension is ready for &lt;code class=&quot;highlighter-rouge&quot;&gt;git init&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;git commit&lt;/code&gt; !&lt;/p&gt;

&lt;p&gt;Have a look at:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/clarkwinkelmann/flarum-ext-emojionearea&quot;&gt;The GitHub repo&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://discuss.flarum.org/d/4787-emoji-picker&quot;&gt;The discussion on Flarum Discuss&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Written with &lt;a href=&quot;https://stackedit.io/&quot;&gt;StackEdit&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Thu, 02 Feb 2017 01:00:00 +0000</pubDate>
        <link>https://blog.clarkwinkelmann.com/2017/02/step-by-step-flarum-emoji-extension</link>
        <guid isPermaLink="true">https://blog.clarkwinkelmann.com/2017/02/step-by-step-flarum-emoji-extension</guid>
        
        
      </item>
    
      <item>
        <title>My first Flarum extension</title>
        <description>&lt;p&gt;This is a diary on the creation of my first Flarum extension. For the step-by-step tutorial (without all the trial and error rambling) have a look at &lt;a href=&quot;/2017/02/step-by-step-flarum-emoji-extension&quot;&gt;this other article&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;starting-point&quot;&gt;Starting point&lt;/h2&gt;

&lt;p&gt;I just replaced the manually crafted &lt;a href=&quot;https://forum.zetamode.com/&quot;&gt;ZetaMode Forum&lt;/a&gt; with &lt;a href=&quot;http://flarum.org/&quot;&gt;Flarum&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Both &lt;a href=&quot;https://zetamode.com/&quot;&gt;ZetaMode&lt;/a&gt; and Flarum being in beta, this seemed like a good idea. I’m already expecting things to break anyway, so I prefer to help debug and improve Flarum over building custom in-house stuff.&lt;/p&gt;

&lt;p&gt;Of course, new forum means new user suggestions. The first thing reported was it was hard for new users to guess the emoji shortcodes.&lt;/p&gt;

&lt;p&gt;In the previous forum, I added a link to &lt;a href=&quot;http://emoji.codes/&quot;&gt;emoji.codes&lt;/a&gt; at the bottom of the autocomplete popup. But there is no such link in the Flarum emoji popup, nor is an emoji picker included.&lt;/p&gt;

&lt;p&gt;I did a quick search to find if anybody had already made one. I found &lt;a href=&quot;https://discuss.flarum.org/d/3206-emojione&quot;&gt;this thread&lt;/a&gt;. A few people were looking for the same thing as me. Also, there was a link to a jQuery plugin named &lt;a href=&quot;https://github.com/mervick/emojionearea&quot;&gt;emojionearea&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since it looked like nobody had created an extension for that before, I decided to give it a try. I tried to find other existing emoji picker libraries on the web. I found this one by &lt;a href=&quot;https://github.com/tommoor/emojione-picker&quot;&gt;@tommoor&lt;/a&gt; and this one by &lt;a href=&quot;https://github.com/OneSignal/emoji-picker&quot;&gt;@OneSignal&lt;/a&gt;. The first was written for React, which is probably hard to integrate with Mythril, and the second one used a hell lot of files.&lt;/p&gt;

&lt;p&gt;I hesitated. The OneSignal one had more stars on GitHub, but the meverick one had more options. Also, I’ve seen other Flarum extensions use jQuery plugins so I was more confident to success with it.&lt;/p&gt;

&lt;h2 id=&quot;coding-the-extension&quot;&gt;Coding the extension&lt;/h2&gt;

&lt;p&gt;I went back to have a look at the &lt;a href=&quot;http://flarum.org/docs/extend/start/&quot;&gt;official doc&lt;/a&gt;. The start of this page is a bit fishy because I’ve read somewhere there is no more &lt;code class=&quot;highlighter-rouge&quot;&gt;extensions&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;I remembered seeing a composer dev tutorial on the forum, which I quickly &lt;a href=&quot;https://discuss.flarum.org/d/1608-extension-development-using-composer-repositories-path&quot;&gt;found again&lt;/a&gt;. That tutorial is really straightforward and it was easy to setup the project.&lt;/p&gt;

&lt;p&gt;I then proceeded to the javascript part of the extension. There, the official doc is really easy to follow. I created a &lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum&lt;/code&gt; folder inside my extension folder with a &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Gulpfile.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In addition to my own javascript code for UI integration, I needed to import the jQuery plugin. Adding the file path inside the &lt;code class=&quot;highlighter-rouge&quot;&gt;modules&lt;/code&gt; section was not working. I found this &lt;a href=&quot;https://github.com/Avatar4eg/flarum-ext-geotags/blob/master/js/forum/Gulpfile.js&quot;&gt;geotags&lt;/a&gt; plugin that also used a jQuery plugin and found that I could use a &lt;code class=&quot;highlighter-rouge&quot;&gt;files&lt;/code&gt; section to add raw JS imports (the code snippet above is the final version)&lt;/p&gt;

&lt;p&gt;Then, I had to find out which components I had to extend. Again the official doc is great to explain how it works, but I had to look inside other’s extensions source code to find out which was the right component and how it worked.&lt;/p&gt;

&lt;p&gt;I first had a look at the &lt;a href=&quot;https://github.com/flarum/flarum-ext-emoji&quot;&gt;flarum/flarum-ext-emoji&lt;/a&gt;, which does something similar to what I want to do (it implements the emoji autocomplete, but not a real picker). But it turned out it was not necessary to hack into the &lt;code class=&quot;highlighter-rouge&quot;&gt;ComposerBody&lt;/code&gt; component like they had to do with the autocomplete.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/flagrow/upload&quot;&gt;flagrow/upload&lt;/a&gt; extension is actually more similar to what I want to do. It adds a button to the post composer, and this button alters the content of the post.&lt;/p&gt;

&lt;p&gt;First I tried to use the emojionearea plugin the way it was meant to be: by just running &lt;code class=&quot;highlighter-rouge&quot;&gt;$textarea.emojioneArea()&lt;/code&gt;. But I quickly found out it was destroying the whole post composer. Indeed, this plugin creates its own &lt;code class=&quot;highlighter-rouge&quot;&gt;contenteditable&lt;/code&gt; area and hides the original textarea, which breaks the editor. By adjusting the plugin settings, I can change which divs get replaced / used, but there was no way to make it keep the original textarea untouched.&lt;/p&gt;

&lt;p&gt;Hopefully, this plugin also had a “standalone” mode. I was able to embed this box under the post editor. I was then able to use the plugin events to detect an emoji selection and use the Flarum &lt;code class=&quot;highlighter-rouge&quot;&gt;TextEditor&lt;/code&gt; functions to insert the emoji in the post. Great !&lt;/p&gt;

&lt;p&gt;Last part, I needed to put this selector inside a Flarum button and hide its own button style (the standalone version displays the current selected emoji and a button with an icon - but it does not fit nicely with Flarum). Some custom CSS in &lt;code class=&quot;highlighter-rouge&quot;&gt;less/forum/extension.less&lt;/code&gt; did the trick, hiding what’s not required. &lt;code class=&quot;highlighter-rouge&quot;&gt;opacity: 0&lt;/code&gt; on the original button allows the user to click on the original button through the Flarum button.&lt;/p&gt;

&lt;p&gt;The tricky part was to include the original CSS file of EmojiOne Area into the extension as well.&lt;/p&gt;

&lt;p&gt;Even after &lt;a href=&quot;https://discuss.flarum.org/d/4651-how-to-import-css-from-dependency&quot;&gt;desperately asking for help&lt;/a&gt; on the forum, I still have not found any example of extension doing that. Let’s consider I am the first ever person to do it and have to decide myself how to do it.&lt;/p&gt;

&lt;p&gt;The easy option would have been to use the Gulpfile inside the &lt;code class=&quot;highlighter-rouge&quot;&gt;js/forum&lt;/code&gt; folder to copy the CSS to a dist folder. Unfortunately, the Flarum gulp helper does not seem to have an option to copy files. Plus, doing this in the &lt;code class=&quot;highlighter-rouge&quot;&gt;js&lt;/code&gt; folder didn’t seem right.&lt;/p&gt;

&lt;p&gt;So I created a new &lt;code class=&quot;highlighter-rouge&quot;&gt;css/forum&lt;/code&gt; folder in my project folder, with another &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Gulpfile.js&lt;/code&gt;. There I load the same emojionearea library, as well as a standard Gulp. With a simple gulp task, I copy the CSS file I need to a &lt;code class=&quot;highlighter-rouge&quot;&gt;dist&lt;/code&gt; folder that is included in my version control.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'gulp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'default'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'node_modules/emojionearea/dist/emojionearea.css'&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dist'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There is no real back-end code for this extension, the only thing to do is to register the assets. I decided to put everything in &lt;code class=&quot;highlighter-rouge&quot;&gt;bootstrap.php&lt;/code&gt;, but if I had more files I should probably store events listener in an &lt;code class=&quot;highlighter-rouge&quot;&gt;src&lt;/code&gt; folder and only list these in the bootstrapping file like most extensions do.&lt;/p&gt;

&lt;p&gt;I then commited the extension folder to my GitHub account, created a new release tagged &lt;code class=&quot;highlighter-rouge&quot;&gt;v0.1.0&lt;/code&gt; and registered it on &lt;a href=&quot;https://packagist.org/&quot;&gt;Packagist&lt;/a&gt;. That was my first time adding a package to &lt;a href=&quot;https://getcomposer.org/&quot;&gt;Composer&lt;/a&gt;. That was really easy and straightforward.&lt;/p&gt;

&lt;p&gt;In conclusion, creating front-end extensions is not as scary as it looked like for me. I will now try to create more complex ones. Please tell me if you want other articles from me on the subject !&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/clarkwinkelmann/flarum-ext-emojionearea&quot;&gt;The code on GitHub&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://discuss.flarum.org/d/4787-emoji-picker&quot;&gt;The discussion on Flarum Discuss&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Written with &lt;a href=&quot;https://stackedit.io/&quot;&gt;StackEdit&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Thu, 02 Feb 2017 01:00:00 +0000</pubDate>
        <link>https://blog.clarkwinkelmann.com/2017/02/my-first-flarum-extension</link>
        <guid isPermaLink="true">https://blog.clarkwinkelmann.com/2017/02/my-first-flarum-extension</guid>
        
        
      </item>
    
      <item>
        <title>Bypassing broken Joomla! permissions</title>
        <description>&lt;p&gt;I just retired an (already) old Joomla! website to replace it with a &lt;a href=&quot;https://www.agrijura.ch/&quot;&gt;new Concrete5 one&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I backed up the whole Joomla! database and files.
I still needed to access some archive items so I set up the Joomla website on my local machine.&lt;/p&gt;

&lt;p&gt;I am not familiar with Joomla! at all, but it’s certainly not the first time that I try to launch an “old” website on localhost.&lt;/p&gt;

&lt;p&gt;I was afraid that the PHP version would mess everything.
I run 7.0 on my dev machine and the old server hosting the website was still on 5.2.&lt;/p&gt;

&lt;p&gt;I imported the database on my local MySQL instance, edited the config file and fired the PHP dev server in the root directory.
Incredibly, it worked !&lt;/p&gt;

&lt;p&gt;For reference, here was the Joomla version (does not seem too old - again, I don’t know anything about Joomla!):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;table&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;Joomla! Version&lt;/td&gt;
        &lt;td&gt;Joomla! 2.5.24 Stable [ Ember ] 25-July-2014 13:00 GMT&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Joomla! Platform Version&lt;/td&gt;
        &lt;td&gt;Joomla Platform 11.4.0 Stable [ Brian Kernighan ] 03-Jan-2012 00:00 GMT&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;
&lt;/blockquote&gt;

&lt;p&gt;I had access to the administration panel, but what I wanted was to see the old website as it was previously online
(I need to access specific known URLs and it’s just a mess in the admin panel).
Here, things were not OK: the home page was displayed, but there was no menu.
Every other page returned an error:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You are not authorised to view this resource.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A few minutes on &lt;a href=&quot;https://duckduckgo.com/?q=joomla+You+are+not+authorised+to+view+this+resource&quot;&gt;DuckDuckGo&lt;/a&gt;,
or &lt;a href=&quot;https://encrypted.google.com/search?q=joomla%20You%20are%20not%20authorised%20to%20view%20this%20resource&quot;&gt;Google&lt;/a&gt;,
or whatever reveals there could be &lt;strong&gt;A TON&lt;/strong&gt; of reasons behind this message.
And even the StackOverflow answers are not very helpful, because each case is very specific.&lt;/p&gt;

&lt;p&gt;I tried a few of the suggested actions.
Cleared cache, but it seems it was disabled;
check permissions, everything is public;
empty trash - wait, I still have no idea where is this damn Joomla! trash.
Nothing helped. Still same error.&lt;/p&gt;

&lt;p&gt;I didn’t want to lose time into debugging this, &lt;strong&gt;I just wanted to see the website&lt;/strong&gt;.
Looking for ways to disable the permissions all together didn’t yield interesting results either.&lt;/p&gt;

&lt;p&gt;So before spending a day on the internet to troubleshoot this I decided to just go into the PHP files and edit whatever needed to be able to see the website.&lt;/p&gt;

&lt;p&gt;Fortunately, enabling debug mode is as simple as:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;configuration.php&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JConfig&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// [...]
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$debug&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// [...]
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This enables a nice little console at the bottom of each page.&lt;/p&gt;

&lt;p&gt;On a problematic page I can see in &lt;strong&gt;Joomla! Debug Console &amp;gt; Errors&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;You are not authorised to view this resource.&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Call stack&lt;/strong&gt;&lt;/p&gt;

  &lt;table&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;#&lt;/td&gt;
        &lt;td&gt;Function&lt;/td&gt;
        &lt;td&gt;Location&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;1&lt;/td&gt;
        &lt;td&gt;JSite-&amp;gt;dispatch()&lt;/td&gt;
        &lt;td&gt;JROOT/index.php:42&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2&lt;/td&gt;
        &lt;td&gt;JComponentHelper::renderComponent()&lt;/td&gt;
        &lt;td&gt;JROOT/includes/application.php:194&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;3&lt;/td&gt;
        &lt;td&gt;JComponentHelper::executeComponent()&lt;/td&gt;
        &lt;td&gt;JROOT/libraries/joomla/application/component/helper.php:348&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;4&lt;/td&gt;
        &lt;td&gt;require_once()&lt;/td&gt;
        &lt;td&gt;JROOT/libraries/joomla/application/component/helper.php:380&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;5&lt;/td&gt;
        &lt;td&gt;JController-&amp;gt;execute()&lt;/td&gt;
        &lt;td&gt;JROOT/components/com_content/content.php:16&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;6&lt;/td&gt;
        &lt;td&gt;ContentController-&amp;gt;display()&lt;/td&gt;
        &lt;td&gt;JROOT/libraries/joomla/application/component/controller.php:761&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;7&lt;/td&gt;
        &lt;td&gt;JController-&amp;gt;display()&lt;/td&gt;
        &lt;td&gt;JROOT/components/com_content/controller.php:74&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;8&lt;/td&gt;
        &lt;td&gt;ContentViewArticle-&amp;gt;display()&lt;/td&gt;
        &lt;td&gt;JROOT/libraries/joomla/application/component/controller.php:722&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;9&lt;/td&gt;
        &lt;td&gt;JError::raiseWarning()&lt;/td&gt;
        &lt;td&gt;JROOT/components/com_content/views/article/view.html.php:104&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;10&lt;/td&gt;
        &lt;td&gt;JError::raise()&lt;/td&gt;
        &lt;td&gt;JROOT/libraries/joomla/error/error.php:276&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;
&lt;/blockquote&gt;

&lt;p&gt;The error (&lt;code class=&quot;highlighter-rouge&quot;&gt;raiseWarning()&lt;/code&gt; does not seem a really good name here) comes from the &lt;code class=&quot;highlighter-rouge&quot;&gt;view.html.php&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;You can disable it by removing the whole &lt;code class=&quot;highlighter-rouge&quot;&gt;if&lt;/code&gt; block checking if user has access.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;components/com_content/views/article/view.html.php:101&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// remove:
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$item&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'access-view'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$item&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'show_noauth'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'guest'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;JError&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;raiseWarning&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;403&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JText&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'JERROR_ALERTNOAUTHOR'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This removes the error but the page is still blank.
On pages with “paged” navigation, the navigation now appears, but not the content.
A quick look in the subdirectories of this &lt;code class=&quot;highlighter-rouge&quot;&gt;article/view&lt;/code&gt; module reveals a template file &lt;code class=&quot;highlighter-rouge&quot;&gt;tmpl/default.php&lt;/code&gt; where additional checks occur.
By hard-coding &lt;code class=&quot;highlighter-rouge&quot;&gt;true&lt;/code&gt; into the normal display case the content shows up.&lt;/p&gt;

&lt;p&gt;In &lt;code class=&quot;highlighter-rouge&quot;&gt;components/com_content/views/article/tmpl/default.php:161&lt;/code&gt; change:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'access-view'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And voilà.&lt;/p&gt;

&lt;p&gt;This does not solve the problem of the menu, but it was not important for me.
It may be a little harder to fix because there are no errors indicating where to look, but I expect a similar menu controller and template somewhere.&lt;/p&gt;

&lt;p&gt;I hope this article will be useful to somebody else facing the same issue.
I also put some bold text saying again that &lt;strong&gt;this is a hack to access every page on a local Joomla! instance, do not try this in production !&lt;/strong&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 18 Oct 2016 19:00:00 +0000</pubDate>
        <link>https://blog.clarkwinkelmann.com/2016/10/bypassing-broken-joomla-permissions</link>
        <guid isPermaLink="true">https://blog.clarkwinkelmann.com/2016/10/bypassing-broken-joomla-permissions</guid>
        
        
      </item>
    
      <item>
        <title>Javascript redirect and Piwik tracking</title>
        <description>&lt;p&gt;Today I set up a custom shortlink: &lt;a href=&quot;https://zetamode.com/questionnaire&quot;&gt;https://zetamode.com/questionnaire&lt;/a&gt; pointing to a Google Form
(Click it if you speak french and are interested in online fashiown game, we’re doing a survey !)&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/zetamode/zetamode.com&quot;&gt;zetamode.com&lt;/a&gt; website is hosted with GitHub Pages, so I cannot go with an HTTP redirect.
And I want to track the origin of the shortlink users through my Piwik instance.&lt;/p&gt;

&lt;p&gt;[Of course] I did not find anybody who had the same use-case on Google.
But I found two interesting articles: &lt;a href=&quot;http://stackoverflow.com/a/36846720/3133038&quot;&gt;Here&lt;/a&gt; someone explains how to replicate
the behavior of the &lt;a href=&quot;https://github.com/jekyll/jekyll-redirect-from&quot;&gt;jekyll-redirect-from&lt;/a&gt; plugin (without tracking) and
&lt;a href=&quot;http://stackoverflow.com/questions/8692503/javascript-redirect-with-google-analytics&quot;&gt;here&lt;/a&gt; there are a few interesting ways
to do a javascript redirect while tracking it with Google Analytics.
I find &lt;a href=&quot;http://stackoverflow.com/a/8692588/3133038&quot;&gt;this one&lt;/a&gt; particularly interesting.
It involves turning the async tracking code into a sync one, and put the redirect after the tracking code.
This prevents the redirect from happening before the tracking, and we don’t need hard-coded waiting times.&lt;/p&gt;

&lt;p&gt;You can have a look at the actual file &lt;a href=&quot;https://github.com/zetamode/zetamode.com/blob/gh-pages/_layouts/redirect.html&quot;&gt;here&lt;/a&gt;, but below is a more generic version you are welcome to edit to fit your needs:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/clarkwinkelmann/fa56404d69b36ed5f67a561fbd41d5ce.js?file=redirect.html&quot;&gt; &lt;/script&gt;

&lt;p&gt;And to use it:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/clarkwinkelmann/fa56404d69b36ed5f67a561fbd41d5ce.js?file=shorturl.html&quot;&gt; &lt;/script&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;a href=&quot;http://stackoverflow.com/a/36846720/3133038&quot;&gt;SO answer I based my code on&lt;/a&gt; states that
you should not use &lt;code class=&quot;highlighter-rouge&quot;&gt;page.redirect_to&lt;/code&gt; as the parameter name, as it will conflict with the &lt;code class=&quot;highlighter-rouge&quot;&gt;jekyll-redirect-to&lt;/code&gt; plugin,
which I believe is enabled on GitHub Pages (didn’t test myself).&lt;/p&gt;

&lt;p&gt;So far it seems this method works !&lt;/p&gt;

&lt;p&gt;Sources:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://stackoverflow.com/a/36846720/3133038&quot;&gt;http://stackoverflow.com/a/36846720/3133038&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://stackoverflow.com/a/8692588/3133038&quot;&gt;http://stackoverflow.com/a/8692588/3133038&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 02 Sep 2016 23:20:00 +0000</pubDate>
        <link>https://blog.clarkwinkelmann.com/2016/09/javascript-redirect-and-piwik-tracking</link>
        <guid isPermaLink="true">https://blog.clarkwinkelmann.com/2016/09/javascript-redirect-and-piwik-tracking</guid>
        
        
      </item>
    
      <item>
        <title>Flarum templating</title>
        <description>&lt;blockquote&gt;
  &lt;p&gt;Note by Clark from the future (November 2018): this was written a long time ago and while still accurate, the &lt;a href=&quot;https://github.com/flarum/docs&quot;&gt;new Flarum docs&lt;/a&gt; now cover this a lot better than I did here :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An interesting discussion was taking place on the &lt;a href=&quot;https://gitter.im/flarum/flarum&quot;&gt;Flarum Gitter&lt;/a&gt; today.
I figured I should better write an article instead of writing thousands of words in a small text input.&lt;/p&gt;

&lt;p&gt;I’m new to &lt;a href=&quot;http://flarum.org/&quot;&gt;Flarum&lt;/a&gt;, I didn’t even have time to write my first extension.
But I read all the docs, looked at the source code of most core extensions,
and I must say this is some very impressive technology.&lt;/p&gt;

&lt;p&gt;So impressive, that some devs get confused very quickly.&lt;/p&gt;

&lt;p&gt;Why use composer, why do I have to write JavaScript to edit the templates, why can’t I just paste my HTML there ?&lt;/p&gt;

&lt;p&gt;I will try to explain this the best as I can.
Hopefully, I will be able to re-use this post everytime someone gets confused.&lt;/p&gt;

&lt;h2 id=&quot;the-old-way-of-doing-things&quot;&gt;The old way of doing things&lt;/h2&gt;

&lt;p&gt;In very old web application, you just didn’t have &lt;em&gt;Views&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For example, in &lt;a href=&quot;https://www.oscommerce.com/&quot;&gt;osCommerce&lt;/a&gt; (until v2 at least, I don’t know if v3 will ever be released)
you had to edit the core files to change how things look.
Want to add a link to the user settings ?
Better edit that &lt;code class=&quot;highlighter-rouge&quot;&gt;account.php&lt;/code&gt; file in the root folder.&lt;/p&gt;

&lt;p&gt;Of course, everything breaks when:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;There is an update to the software (which requires to overwrite the files you edited)&lt;/li&gt;
  &lt;li&gt;You want to share your amazing feature with somebody else which has a base installation&lt;/li&gt;
  &lt;li&gt;or worse, someone who &lt;strong&gt;already has another extension&lt;/strong&gt; installed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’d like to say nobody does it anymore but guess that ?
I’m actually maintaining a 2005 shop which cannot easily be migrated.&lt;/p&gt;

&lt;p&gt;Anyway, most websites now use another technique:&lt;/p&gt;

&lt;h2 id=&quot;the-current-way-of-doing-things&quot;&gt;The current way of doing things&lt;/h2&gt;

&lt;p&gt;If you come from a &lt;a href=&quot;https://wordpress.org/&quot;&gt;WordPress&lt;/a&gt; background for example, this is the way things work:&lt;/p&gt;

&lt;p&gt;You get your own special directory somewhere like &lt;code class=&quot;highlighter-rouge&quot;&gt;wp-content/themes/myamazingtheme&lt;/code&gt;.
There, you create &lt;code class=&quot;highlighter-rouge&quot;&gt;php&lt;/code&gt; template files, which get used for a given request.
If you don’t create a file, a default one kicks in and everything works.&lt;/p&gt;

&lt;p&gt;In this file, you get access to a few variables, so you know what to display.
You can include other files to prevent duplication.&lt;/p&gt;

&lt;p&gt;Important note: Views can not only return HTML.
You may also format your data as XML or JSON for example.&lt;/p&gt;

&lt;p&gt;Congratulations, you are using &lt;em&gt;Views&lt;/em&gt; !
&lt;a href=&quot;https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller&quot;&gt;MVC frameworks&lt;/a&gt; takes this to a higher level,
by using them to separate the visual interface from the data.
I won’t go into that, there are loads of good MVC tutorials out there.&lt;/p&gt;

&lt;p&gt;In modern frameworks like &lt;a href=&quot;https://laravel.com/&quot;&gt;Laravel&lt;/a&gt;, there are other components which glue everything together.
The only one that you should know to understand my article is the Router, which maps URLs to Controllers.
A Controller then returns a View.&lt;/p&gt;

&lt;p&gt;A typical request to a web application could be drawn like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;User &amp;gt; Request (GET) &amp;gt; Router &amp;gt; Controller &amp;gt; Fetch data &amp;gt; View (HTML) &amp;gt; Page
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-modern-way-of-doing-things&quot;&gt;The modern way of doing things&lt;/h2&gt;

&lt;p&gt;The new trend is JavaScript applications.&lt;/p&gt;

&lt;p&gt;How it works: The first time you load the page, the application loads, without worrying of what the current page is.
When it is ready or when you change page, an AJAX request is issued to get the new content, and the interface is updated through JavaScript.&lt;/p&gt;

&lt;p&gt;It now works like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;User &amp;gt; Request (GET) &amp;gt; Controller &amp;gt; View (HTML) &amp;gt; Empty page (JavaScript App)
JS App &amp;gt; Request (AJAX) &amp;gt; Controller &amp;gt; Fetch data &amp;gt; View (JSON) &amp;gt; Page update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This changes everything.&lt;/p&gt;

&lt;p&gt;We still have a Controller which returns HTML, but there is no data here, just the application bootstrap code.&lt;/p&gt;

&lt;p&gt;When the JavaScript application is started, it fetches the data based on the current URL.
No fancy HTML there, the data is returned in JSON format, and the JavaScript takes care of placing this data at the correct place.&lt;/p&gt;

&lt;p&gt;Now you think you’ve seen everything ? Nope.&lt;/p&gt;

&lt;h2 id=&quot;mvc-on-client-side&quot;&gt;MVC on client side&lt;/h2&gt;

&lt;p&gt;Flarum &lt;a href=&quot;http://flarum.org/docs/extend/start/#changing-the-ui&quot;&gt;uses&lt;/a&gt; &lt;a href=&quot;http://mithril.js.org/&quot;&gt;Mithril&lt;/a&gt;,
which is itself an &lt;strong&gt;MVC Framework&lt;/strong&gt;, but &lt;strong&gt;on the client side&lt;/strong&gt; !&lt;/p&gt;

&lt;p&gt;This means there is also a Router, some Controllers and of course Views written in JavaScript !&lt;/p&gt;

&lt;p&gt;Let’s draw a new schema taking that into account.
Here’s what happens on a typical page load:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(Server) User &amp;gt; Request (GET) &amp;gt; Router &amp;gt; Controller &amp;gt; View (HTML) &amp;gt; Page (Mithril App)
(Client) Mithril App &amp;gt; Router &amp;gt; Controller &amp;gt; Data request [...]
(Server) Mithril &amp;gt; Request (AJAX) &amp;gt; Router &amp;gt; Controller &amp;gt; Fetch data &amp;gt; View (JSON) &amp;gt; Response
(Client) [...] &amp;gt; Parse response &amp;gt; Controller &amp;gt; View (Virtual DOM) &amp;gt; HTML update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, how do Mithril Views work ?
Pretty much the same as the PHP ones.
The view consists of an HTML structure, which is written inside the page and takes the whole place.&lt;/p&gt;

&lt;p&gt;To make things easier and prevent code duplication, Mithril uses Components, which can be “included” from a parent Component.
You can find some example Components in the &lt;a href=&quot;http://flarum.org/docs/extend/start/#components&quot;&gt;Flarum documentation&lt;/a&gt;, like &lt;em&gt;DiscussionPage&lt;/em&gt;, &lt;em&gt;PostStream&lt;/em&gt;, &lt;em&gt;Post&lt;/em&gt;, etc…&lt;/p&gt;

&lt;p&gt;How to extend the interface ?
You just need to change the HTML output of the JavaScript Component of the item you want to change on the page.
You can add new Components inside existing ones, too !
From now on the official Flarum doc will tell you where to change things: &lt;a href=&quot;http://flarum.org/docs/extend/start/&quot;&gt;http://flarum.org/docs/extend/start/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One last thing: &lt;a href=&quot;http://mithril.js.org/&quot;&gt;Mithril&lt;/a&gt;, like &lt;a href=&quot;https://facebook.github.io/react/&quot;&gt;React&lt;/a&gt;, uses Virtual DOM.
This is a way to make things faster by computing the “HTML” in memory, and updating only the bits of the page that changed across requests.&lt;/p&gt;

&lt;p&gt;The difference for you is that you don’t return a “string of HTML” but a “representation of the HTML”, which is made of JavaScript objects.
The good news is that you can write HTML almost normally and it will be turned into cryptic objects at compilation time.
Have a look at how it looks on &lt;a href=&quot;http://mithril.js.org/&quot;&gt;Mithril’s home page&lt;/a&gt; or the &lt;a href=&quot;http://flarum.org/docs/extend/start/&quot;&gt;Flarum Extensions documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;recap&quot;&gt;Recap&lt;/h2&gt;

&lt;p&gt;So what did we learn here (I hope you learned something lol).&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The visual interface of Flarum is a JavaScript MVC application powered by &lt;a href=&quot;http://mithril.js.org/&quot;&gt;Mithril&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;It talks to a PHP application which just sends data as JSON, not as HTML&lt;/li&gt;
  &lt;li&gt;The PHP application does uses Views, but only to render the JavaScript application&lt;/li&gt;
  &lt;li&gt;The JavaScript Views are organised as Components, which are placed in a hierarchical way on the page&lt;/li&gt;
  &lt;li&gt;To change how something looks like, you have to edit the Component responsible for it&lt;/li&gt;
  &lt;li&gt;You can add new Components as child of existing ones&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I won’t go into further details on the development of Extensions for now.
I think the &lt;a href=&quot;http://flarum.org/docs/extend/start/&quot;&gt;official&lt;/a&gt; one is pretty good once you know how the technologies used work together.&lt;/p&gt;

&lt;p&gt;This is my first tutorial, please give me feedback &lt;a href=&quot;https://twitter.com/clarkwinkelmann&quot;&gt;on Twitter&lt;/a&gt; or anywhere else that you can find me =)&lt;/p&gt;

&lt;h2 id=&quot;additional-notes&quot;&gt;Additional notes&lt;/h2&gt;

&lt;p&gt;There are in fact a few HTML templates in the &lt;a href=&quot;https://github.com/flarum/core/tree/master/views&quot;&gt;views folder of Flarum&lt;/a&gt;.
They are used to display a simple alternative interface to users with JavaScript disabled.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://discuss.flarum.org/d/2739-davis-custom-header&quot;&gt;Davis Custom Header extension&lt;/a&gt; does
&lt;a href=&quot;https://github.com/dav-is/flarum-ext-customheader/blob/master/js/forum/src/main.js&quot;&gt;manipulate the DOM directly&lt;/a&gt; with a jQuery selector.
That’s a special case. Why ?
If you look at &lt;a href=&quot;https://github.com/flarum/core/blob/master/views/forum.blade.php&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;views/forum.blade.php&lt;/code&gt;&lt;/a&gt; you can see several things:
&lt;code class=&quot;highlighter-rouge&quot;&gt;#content&lt;/code&gt; will hold the main application Component. &lt;code class=&quot;highlighter-rouge&quot;&gt;#header-primary&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;#header-secondary&lt;/code&gt; will hold the navigation Components.
The tags that are accessed directly (&lt;code class=&quot;highlighter-rouge&quot;&gt;#header&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;head&lt;/code&gt;) are outside the JS application.
They are not Components and therefore must be accessed in the “old” way.
You can’t do that with Components, because the DOM is managed by Mithril.
Maybe in the future the &lt;code class=&quot;highlighter-rouge&quot;&gt;#header&lt;/code&gt; tag will be merged into the main application, which would allow to change all its content via Components.&lt;/p&gt;

&lt;p&gt;I only cover the problems that newcomers may face when editing Flarum &lt;em&gt;interface&lt;/em&gt;.
Adding &lt;em&gt;functionality&lt;/em&gt; is another topic that includes things like &lt;em&gt;Providers&lt;/em&gt; and &lt;em&gt;Events&lt;/em&gt; (as opposed with WP &lt;em&gt;Hooks&lt;/em&gt;).
I’ll write another article if there is interest in the matter !&lt;/p&gt;
</description>
        <pubDate>Mon, 22 Aug 2016 16:20:00 +0000</pubDate>
        <link>https://blog.clarkwinkelmann.com/2016/08/flarum-templating</link>
        <guid isPermaLink="true">https://blog.clarkwinkelmann.com/2016/08/flarum-templating</guid>
        
        
      </item>
    
      <item>
        <title>The blog deadline</title>
        <description>&lt;p&gt;I’m lazy.&lt;/p&gt;

&lt;p&gt;So lazy that launching a blog was on my TODO list for a long time now.
There was only one way to finally do it.
I set a deadline.
The deadline is today.
So here is the blog.&lt;/p&gt;

&lt;p&gt;In fact making a blog is easy.
Making it open-source is just as well.&lt;/p&gt;

&lt;p&gt;What’s taking a lot of time is writing (wow it’s already been an hour to write the first 2 posts, hope I get better at it).
But the simple fact of having a blog will force me to write more content.&lt;/p&gt;

&lt;h2 id=&quot;here-are-the-easy-to-use-tools-i-used&quot;&gt;Here are the easy-to-use tools I used&lt;/h2&gt;

&lt;p&gt;I use &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt; because I already use it for my other websites.
It’s actually the first time I will be using it for a blog.&lt;/p&gt;

&lt;p&gt;I write text in &lt;a href=&quot;https://daringfireball.net/projects/markdown/&quot;&gt;Markdown&lt;/a&gt; because that’s just so easy.
And I don’t need any special editor.
&lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code&lt;/a&gt; is actually pretty good at it.
Sucks for PHP, though.&lt;/p&gt;

&lt;p&gt;I host the code on &lt;a href=&quot;https://github.com/clarkwinkelmann/blog.clarkwinkelmann.com&quot;&gt;GitHub&lt;/a&gt;,
because I thing it is logical to share the source and allow contributions.&lt;/p&gt;

&lt;p&gt;I use &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt; to host the website because, well, it’s free,
and you can’t choose anything easier when your code is already on GitHub.
They even launched &lt;a href=&quot;https://github.com/blog/2228-simpler-github-pages-publishing&quot;&gt;an update&lt;/a&gt; yesterday that makes things easier.
Hello &lt;code class=&quot;highlighter-rouge&quot;&gt;master&lt;/code&gt; branch.&lt;/p&gt;

&lt;p&gt;I put &lt;a href=&quot;https://www.cloudflare.com/&quot;&gt;CloudFlare&lt;/a&gt; in front of it just.
GitHub Pages already uses a CDN but I would not look serious if my blog wasn’t HTTPS secured.&lt;/p&gt;

&lt;p&gt;By the way, maybe you noticed I use the default Jekyll Theme.
If I had decided to create a theme before launching the blog, it would have taken ages !
So I stay with default for the moment. But guess what, &lt;em&gt;it even looks good&lt;/em&gt;.&lt;/p&gt;
</description>
        <pubDate>Thu, 18 Aug 2016 10:40:00 +0000</pubDate>
        <link>https://blog.clarkwinkelmann.com/2016/08/the-blog-deadline</link>
        <guid isPermaLink="true">https://blog.clarkwinkelmann.com/2016/08/the-blog-deadline</guid>
        
        
      </item>
    
      <item>
        <title>And I started a blog</title>
        <description>&lt;p&gt;Hi there ! My name is Clark Winkelmann and I’m a webdesigner freelancer.&lt;/p&gt;

&lt;p&gt;I will keep this short. I will use this blog to share my experiences with open-source software as well
as share insights about projects I’m working on.&lt;/p&gt;

&lt;p&gt;Why ? I’ve been contributing to the &lt;a href=&quot;https://github.com/clarkwinkelmann&quot;&gt;open-source community&lt;/a&gt; for some time already,
but generally don’t share all the knowledge I gained while working on a project.
I merely share the code (and &lt;em&gt;sometimes&lt;/em&gt; the doc) without going further.&lt;/p&gt;

&lt;p&gt;This was a way to get things done quicker so I could work on something else.
Now that I do more serious stuff and that I’m more confident in doing things &lt;em&gt;sort of&lt;/em&gt; right, it’s time to share more !&lt;/p&gt;

&lt;p&gt;Let’s keep this simple, with a list. Things-I-often-face-and-others-will-too:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Trouble setting up dev environment&lt;/li&gt;
  &lt;li&gt;Getting the minimum required knowledge of a software to fix things like URLs or typos&lt;/li&gt;
  &lt;li&gt;Old and great software whose installation documentation is just totally outdated &lt;em&gt;Anybody still on Ubuntu 8.04 ?&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the end, I find a way to work around and make things work.
But this knowledge is lost.
It would be much more useful if I put it online so others can find it.&lt;/p&gt;

&lt;h2 id=&quot;what-to-expect-on-this-blog&quot;&gt;What to expect on this blog&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Open-source related things&lt;/li&gt;
  &lt;li&gt;Web development stuff&lt;/li&gt;
  &lt;li&gt;Linux &amp;amp; Ubuntu stuff&lt;/li&gt;
  &lt;li&gt;Command line stuff&lt;/li&gt;
  &lt;li&gt;Installation of web applications in the cloud&lt;/li&gt;
  &lt;li&gt;How-to’s about old projects that are still great&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve seen that all devs have a “goto” language to try out logic and quickly connect things between them.
Mine is &lt;code class=&quot;highlighter-rouge&quot;&gt;PHP&lt;/code&gt;. Expect to see a lot of PHP here =)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Immediate projects:&lt;/strong&gt; I will start by retroactively talking about important projects I’ve developed.
My biggest projects can be found at &lt;a href=&quot;https://clarkwinkelmann.com/&quot;&gt;https://clarkwinkelmann.com/&lt;/a&gt; (French) and &lt;a href=&quot;https://github.com/clarkwinkelmann&quot;&gt;https://github.com/clarkwinkelmann&lt;/a&gt;,
but they lack a proper description from a programmer point of view.&lt;/p&gt;

&lt;h2 id=&quot;a-last-few-things-about-me&quot;&gt;A last few things about me&lt;/h2&gt;

&lt;p&gt;I live in Switzerland and my native language is French.
Most articles here will be written in English.
If I write something in French I’ll try to provide the English translation as well.&lt;/p&gt;

&lt;p&gt;Note that I may share progress about projects that use the French language.
When I work with other people in my area I may comment the code in French.
Otherwise, all my code is named and commented in English.&lt;/p&gt;

&lt;p&gt;I’m open to all suggestions about this blog.
Feel free to contact me on Twitter &lt;a href=&quot;https://twitter.com/clarkwinkelmann&quot;&gt;@clarkwinkelmann&lt;/a&gt; or by email at &lt;a href=&quot;mailto:clark.winkelmann@gmail.com&quot;&gt;clark.winkelmann@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If like me you want things fixed quickly (horrible typos or non-https-but-compatible links for example)
you are welcome to send me PRs on the &lt;a href=&quot;https://github.com/clarkwinkelmann/blog.clarkwinkelmann.com&quot;&gt;GitHub repo&lt;/a&gt; of the blog.&lt;/p&gt;
</description>
        <pubDate>Thu, 18 Aug 2016 10:00:00 +0000</pubDate>
        <link>https://blog.clarkwinkelmann.com/2016/08/and-i-started-a-blog</link>
        <guid isPermaLink="true">https://blog.clarkwinkelmann.com/2016/08/and-i-started-a-blog</guid>
        
        
      </item>
    
  </channel>
</rss>
