<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>ghinda.net</title>
  <link href="https://www.ghinda.net"/>
  <link type="application/atom+xml" rel="self" href="https://www.ghinda.net/atom.xml"/>
  <updated>2025-09-18T06:53:32+00:00</updated>
  <id>https://www.ghinda.net</id>
  <author>
    <name>Ionut Colceriu</name>
    <email>contact@ghinda.net</email>
  </author>

  
  <entry>
    <id>https://www.ghinda.net/article/nudgeti-waste-less-time</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/nudgeti-waste-less-time/"/>
    <title>Nudgeti - waste less time on distracting websites</title>
    <updated>2018-03-02T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;Newsfeed algorithms and dark interaction design patterns are designed to trap you. Companies use them to make you spend as much time as possible on their platforms. We need a way around it.&lt;/p&gt;

&lt;p&gt;Here’s what usually happens:&lt;/p&gt;

&lt;p&gt;You want to look up a concert on Facebook, so you go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;facebook.com&lt;/code&gt;. You’re greeted by a photo from one of your friends and some political posts, neatly placed in the newsfeed. Keep scrolling and the next thing you know is that 20 minutes have passed. You forgot what you were looking for in the first place.&lt;/p&gt;

&lt;p&gt;You watch a short lightning talk on YouTube. Next to the video there’s a long list of recommended videos. If you didn’t click on one of them, as soon as your video is over, an “Up Next” video countdown shows up. If you cancel the countdown, a grid of similar videos appears.&lt;/p&gt;

&lt;p&gt;They’re trying to get your attention by any means.&lt;/p&gt;

&lt;p&gt;One solution is to block the websites, but this also blocks their utility aspect. You want to be able to watch some videos, see event details or send messages.&lt;/p&gt;

&lt;h2 id=&quot;nudgeti&quot;&gt;Nudgeti&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.nudgeti.com/&quot;&gt;Nudgeti&lt;/a&gt; is a browser extension that helps you snap out of the &lt;em&gt;newsfeed hypnosis&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;When you spend more than two minutes on social sites like Facebook or Reddit, a notification will pop-up telling you how long you stayed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It uses one of the same attention-grabbing methods, notifications, against them.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;After two more minutes another notification will show up, again telling you the time spent. Afterwards it will leave you alone, you most probably want to be there.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It won’t interrupt you or stop you from going to any website.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;/media/images/nudgeti-firefox-plasma-list.png&quot;&gt;
  &lt;img src=&quot;/media/images/nudgeti-firefox-plasma-list.png&quot; alt=&quot;Nudgeti notifications in KDE Plasma&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;notifications&quot;&gt;Notifications&lt;/h2&gt;

&lt;p&gt;Notifications are native to your operating system, thanks to Web Notifications. You can see them in the notification history.&lt;/p&gt;

&lt;p&gt;They also work in Firefox for Android.&lt;/p&gt;

&lt;h2 id=&quot;privacy&quot;&gt;Privacy&lt;/h2&gt;

&lt;p&gt;The extension does not collect any personal data or statistics.&lt;/p&gt;

&lt;p&gt;Because it’s built as a background script, it can only read tab overview details like titles or urls, but can not read tab contents (eg. your emails, facebook messages, etc.).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.nudgeti.com/&quot;&gt;See the Nudgeti website.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nudgeti is free software under the GPL license. Get the source code from &lt;a href=&quot;https://github.com/ghinda/nudgeti&quot;&gt;github.com/ghinda/nudgeti&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/pouchdb-views</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/pouchdb-views/"/>
    <title>Simple PouchDB view management</title>
    <updated>2017-03-03T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;PouchDB is a JavaScript database that can sync with a remote CouchDB, among other things. Syncing gets all the documents in a database, including views and other design documents.&lt;/p&gt;

&lt;h2 id=&quot;view-code&quot;&gt;View code&lt;/h2&gt;

&lt;p&gt;A common question is how to manage the code for the views.&lt;/p&gt;

&lt;p&gt;A good approach is to keep them with the rest of the source code. You can then add them to the database on create, or on demand.&lt;/p&gt;

&lt;h2 id=&quot;querying-views&quot;&gt;Querying views&lt;/h2&gt;

&lt;p&gt;Another problem you can hit is trying to query a view before syncing is done.&lt;/p&gt;

&lt;p&gt;This can happen when the view is available only in the remote database, and no internet connection is available.&lt;/p&gt;

&lt;p&gt;Since the view is not yet synced with the local database, it will return a 404 error.&lt;/p&gt;

&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;

&lt;p&gt;To resolve these issues I created a function that tries to query a view and, if it doesn’t exist, creates it and retries the query.&lt;/p&gt;

&lt;p&gt;This also solves the view code management issue, by keeping the views in the source code as a map.&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;// declare views&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;views&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;pills&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;blue&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;map&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;doc&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;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_id&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;toString&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;red&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;map&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;doc&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;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_id&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;toString&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;na&quot;&gt;agents&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;agents&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;map&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;doc&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;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_id&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;toString&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;c1&quot;&gt;// query couchdb views&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;db&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;nx&quot;&gt;params&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;namespace&lt;/span&gt; &lt;span class=&quot;o&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;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;db&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;query&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;nx&quot;&gt;params&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;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&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;k&quot;&gt;if&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;nx&quot;&gt;views&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;namespace&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;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`View &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; is not defined.`&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;// if view doesn&apos;t exist, create it, and try again&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;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;404&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;db&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`_design/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;views&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;views&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;namespace&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;then&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;db&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;nx&quot;&gt;params&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;span class=&quot;c1&quot;&gt;// can be used as&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;db&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;PouchDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;agents&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;pills/red&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;pills/blue&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;demo&quot;&gt;Demo&lt;/h2&gt;

&lt;p&gt;Here’s a demo of how it works.&lt;/p&gt;

&lt;div class=&quot;editor-demo&quot; data-html=&quot;/media/demos/pouchdb-views/pouchdb-views.html&quot; data-js=&quot;/media/demos/pouchdb-views/pouchdb-views.js&quot;&gt;&lt;/div&gt;

&lt;h2 id=&quot;couchdb&quot;&gt;CouchDB&lt;/h2&gt;

&lt;p&gt;The method can be adapted to use CouchDB directly, by replacing the PouchDB &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;query&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;put&lt;/code&gt; methods with HTTP calls to the CouchDB API.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/canvas-resize</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/canvas-resize/"/>
    <title>Downscaling large images in Canvas</title>
    <updated>2016-06-21T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;When resizing high resolution images in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canvas&lt;/code&gt; elements, they usually end up &lt;a href=&quot;https://en.wikipedia.org/wiki/Jaggies&quot;&gt;aliased&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To work around this we can use &lt;em&gt;step-down&lt;/em&gt; downscaling. This means reducing the image size in steps, rather than setting the final dimensions directly.&lt;/p&gt;

&lt;p&gt;Here’s a basic function that will half the image resolution until it’s close to the right size.&lt;/p&gt;

&lt;div class=&quot;editor-demo&quot; data-html=&quot;/media/demos/canvas-resize/canvas-resize.html&quot; data-js=&quot;/media/demos/canvas-resize/canvas-resize.js&quot;&gt;&lt;/div&gt;

&lt;p&gt;The main downside of this approach is that the resulting image is sometimes blurry.&lt;/p&gt;

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

&lt;p&gt;If you don’t want to implement the downscaling function yourself, you can use &lt;a href=&quot;https://github.com/nodeca/pica&quot;&gt;pica&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/improved-debounce</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/improved-debounce/"/>
    <title>Improved JavaScript debouncer</title>
    <updated>2016-03-14T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;Debouncer functions are used as rate limiters for functions that trigger many times in rapid succession. This is an attempt to improve the pattern by triggering the function earlier, making it seem more responsive.&lt;/p&gt;

&lt;p&gt;To quote &lt;a href=&quot;https://css-tricks.com/the-difference-between-throttling-and-debouncing/&quot;&gt;css-tricks.com&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Debouncing enforces that a function not be called again until a certain amount of time has passed without it being called. As in “execute this function only if 100 milliseconds have passed without it being called.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;existing-approaches&quot;&gt;Existing approaches&lt;/h2&gt;

&lt;p&gt;Some popular implementations are &lt;a href=&quot;http://benalman.com/projects/jquery-throttle-debounce-plugin/&quot;&gt;Ben Alman&lt;/a&gt;’s or &lt;a href=&quot;https://remysharp.com/2010/07/21/throttling-function-calls&quot;&gt;Remy Sharp&lt;/a&gt;’s.&lt;/p&gt;

&lt;p&gt;The problem with the existing approaches is that they trigger only on the trailing end. Your function will trigger when the event has stopped firing for the configured time.&lt;/p&gt;

&lt;p&gt;For example, using a debouncer on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keyup&lt;/code&gt; event will only trigger the function once you stopped typing. It will not fire when you start typing.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/images/debounce-regular.gif&quot; alt=&quot;Typing in a textfield and showing the keyup debounced callback being called only when we stop typing.&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;improved-debouncer&quot;&gt;Improved debouncer&lt;/h2&gt;

&lt;p&gt;This improved debouncer triggers the first call immediately, and only debounces the next calls. It will trigger again on the trailing end only if it detects more calls.&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;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;debounce&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;delay&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;cooldown&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;multiple&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;k&quot;&gt;return&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arguments&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;cooldown&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;multiple&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;nx&quot;&gt;clearTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cooldown&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;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&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;cooldown&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;setTimeout&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;multiple&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;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&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;cooldown&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;nx&quot;&gt;multiple&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;nx&quot;&gt;delay&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;Here’s a simple demo of the debouncer in action:&lt;/p&gt;

&lt;div class=&quot;editor-demo&quot; data-html=&quot;/media/demos/improved-debouncer/improved-debouncer.html&quot; data-js=&quot;/media/demos/improved-debouncer/improved-debouncer.js&quot;&gt;&lt;/div&gt;

&lt;h2 id=&quot;performance&quot;&gt;Performance&lt;/h2&gt;

&lt;p&gt;For performance, we could refactor the code to set the timeout only once. After testing both approaches with 10.000 debounced function calls, the difference between the version setting the timeout once and the one setting it multiple times is around ~50ms.&lt;/p&gt;

&lt;p&gt;This is calculated using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.time&lt;/code&gt;, starting when we begin calling the functions, and ending when the last debounced function is called.&lt;/p&gt;

&lt;p&gt;Based on these results, I would say optimizing the debouncer to only set the timeout once, thus making it more verbose, is not worth it.&lt;/p&gt;

&lt;p&gt;Here’s the small performance test I used. Make sure you have the console open (for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.time&lt;/code&gt;).&lt;/p&gt;

&lt;div class=&quot;editor-demo&quot; data-js=&quot;/media/demos/improved-debouncer/debouncer-perf.js&quot;&gt;&lt;/div&gt;

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

&lt;p&gt;The debouncer in &lt;a href=&quot;https://lodash.com/docs#debounce&quot;&gt;lodash&lt;/a&gt; has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;leading&lt;/code&gt; option that makes it behave like this improved debouncer, but is much more complex.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/script-tags</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/script-tags/"/>
    <title>Run script tags in innerHTML content</title>
    <updated>2016-02-03T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;When inserting HTML content in the DOM using innerHTML, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;script&lt;/code&gt; tags inside it will not load or run. This applies to both inline scripts and external ones using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src&lt;/code&gt; attribute.&lt;/p&gt;

&lt;h2 id=&quot;documentwrite&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.write&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;One way to load the scripts is to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.write&lt;/code&gt;. The problem with it is that Internet Explorer 9 does not respect execution order. Each script tags will execute when loaded.&lt;/p&gt;

&lt;p&gt;If you’re writing to an iframe, you can set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src&lt;/code&gt; attribute to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;javascript: &apos;&amp;lt;script&amp;gt;...&amp;lt;\/script&amp;gt;&apos;&lt;/code&gt;. This will work even in Internet Explorer 9 with the correct execution order.&lt;/p&gt;

&lt;h2 id=&quot;eval&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Another way is to load the external scripts using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;XMLHttpRequest&lt;/code&gt;, and run both inline and external ones with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt;. One major drawback of this approach is that the same-origin policy restricts requests to other domains. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt; also brings in a series of security issues.&lt;/p&gt;

&lt;h2 id=&quot;createcontextualfragment&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createContextualFragment&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Hat tip to &lt;a href=&quot;https://jakearchibald.com/&quot;&gt;Jake Archibald&lt;/a&gt; for this.&lt;/p&gt;

&lt;p&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createContextualFragment&lt;/code&gt; to insert script tags will execute them. But, same as with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.write&lt;/code&gt;, the scripts will run as they are loaded and not in the specific order.&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;range&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setStart&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;mi&quot;&gt;0&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;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createContextualFragment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;lt;script src=&quot;...&quot;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/script&amp;gt;&amp;lt;script&amp;gt;...&amp;lt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/script&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;documentcreateelement&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.createElement&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;The other solution is to re-create and re-insert each script tag into the DOM using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.createElement&lt;/code&gt;. This doesn’t handle execution order by itself, but we can insert the tags sequentially.&lt;/p&gt;

&lt;h3 id=&quot;type-attribute&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type&lt;/code&gt; attribute&lt;/h3&gt;

&lt;p&gt;Following the &lt;a href=&quot;https://html.spec.whatwg.org/multipage/scripting.html#the-script-element&quot;&gt;HTML spec for script tags&lt;/a&gt;, browsers execute only script tags with no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type&lt;/code&gt; attribute, or with a valid &lt;a href=&quot;https://html.spec.whatwg.org/multipage/scripting.html#javascript-mime-type&quot;&gt;JavaScript MIME type&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some JavaScript libraries use inline script tags with custom types for precompiled code. For example, Babel’s (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5.x&lt;/code&gt;) browser build can compile code from script tags with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;text/babel&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;To match the browser behavior we must run only tags with an omitted or valid &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type&lt;/code&gt; attribute.&lt;/p&gt;

&lt;h3 id=&quot;domcontentloaded&quot;&gt;DOMContentLoaded&lt;/h3&gt;

&lt;p&gt;Browsers fire the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded&quot;&gt;DOMContentLoaded&lt;/a&gt; event when the document is loaded and parsed. This includes having loaded and ran all script tags.&lt;/p&gt;

&lt;p&gt;Because some of the scripts we run could rely on the event, we must trigger the event manually after all tags load.&lt;/p&gt;

&lt;p&gt;For Internet Explorer 9 support we use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/createEvent&quot;&gt;createEvent&lt;/a&gt;, instead of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Event&lt;/code&gt; constructor.&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;// trigger DOMContentLoaded&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;scriptsDone&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;DOMContentLoadedEvent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Event&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;DOMContentLoadedEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;initEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;DOMContentLoaded&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dispatchEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;DOMContentLoadedEvent&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;h3 id=&quot;execution-order&quot;&gt;Execution order&lt;/h3&gt;

&lt;p&gt;To preserve execution order we need to insert each script tag after the previous one has finished loading.&lt;/p&gt;

&lt;p&gt;We also need to trigger &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DOMContentLoaded&lt;/code&gt; after all scripts are loaded.&lt;/p&gt;

&lt;p&gt;For this we use a small helper function.&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;// runs an array of async functions in sequential order&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&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;// first call, without an index&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;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;index&lt;/span&gt; &lt;span class=&quot;o&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;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;index&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;index&lt;/span&gt;&lt;span class=&quot;o&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;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&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;callback&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;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&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;This runs an array of async functions, moving to the next one when the previous reaches the callback.&lt;/p&gt;

&lt;p&gt;When it’s all done it runs the main &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;callback&lt;/code&gt; function.&lt;/p&gt;

&lt;h3 id=&quot;script-running&quot;&gt;Script running&lt;/h3&gt;

&lt;p&gt;Putting it all together, here’s the script running code:&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;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;insertScript&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&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;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;text/javascript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;$script&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;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onerror&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;s&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$script&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;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;textContent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerText&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// re-insert the script tag so it executes.&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// clean-up&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;$script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parentNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// run the callback immediately for inline scripts&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;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$script&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;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;callback&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;c1&quot;&gt;// https://html.spec.whatwg.org/multipage/scripting.html&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;runScriptTypes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/javascript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/ecmascript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/x-ecmascript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/x-javascript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;text/ecmascript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;text/javascript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;text/javascript1.0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;text/javascript1.1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;text/javascript1.2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;text/javascript1.3&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;text/javascript1.4&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;text/javascript1.5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;text/jscript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;text/livescript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;text/x-ecmascript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;text/x-javascript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;nx&quot;&gt;runScripts&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;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// get scripts tags from a node&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$scripts&lt;/span&gt; &lt;span class=&quot;o&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;nx&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;runList&lt;/span&gt; &lt;span class=&quot;o&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;typeAttr&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;[].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$scripts&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;$script&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;typeAttr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// only run script tags without the type attribute&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// or with a javascript mime attribute value&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;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;typeAttr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;runScriptTypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;typeAttr&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;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&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;runList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&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;callback&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;insertScript&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&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;c1&quot;&gt;// insert the script tags sequentially&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// to preserve execution order&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;runList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;scriptsDone&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;It’s possible that some some external scripts will not load, so we also handle the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;onerror&lt;/code&gt; listener.&lt;/p&gt;

&lt;p&gt;Here’s a demo of how it works:&lt;/p&gt;

&lt;div class=&quot;editor-demo&quot; data-html=&quot;/media/demos/script-tags/script-tags.html&quot; data-js=&quot;/media/demos/script-tags/script-tags.js&quot;&gt;&lt;/div&gt;

</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/mimic-native-focus-css</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/mimic-native-focus-css/"/>
    <title>Mimic native browser focus styles</title>
    <updated>2015-12-04T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;When creating custom web components or widgets, elements receiving focus are sometimes hidden. This makes us have to simulate focus on other elements.&lt;/p&gt;

&lt;p&gt;This is one way to mimic the default focus styles, as much as possible, in a cross-browser way.&lt;/p&gt;

&lt;p&gt;Even with custom components, you should try to use native controls (eg. buttons) that provide their own focus styles. Most of the time you &lt;a href=&quot;http://www.outlinenone.com/&quot;&gt;should not mess with the browser’s default focus styles&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;defaults&quot;&gt;Defaults&lt;/h2&gt;

&lt;p&gt;By default, Firefox and Internet Explorer use a dark thin dotted outline on links and other elements.&lt;/p&gt;

&lt;p&gt;Because Firefox tries to integrate with the operating system, native components like buttons provide their own styles, including focus styles, inherited from the OS.&lt;/p&gt;

&lt;p&gt;Browsers with WebKit or Blink usually use a blue or gold glow outline. It’s defined as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;outline: auto&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;outline: -webkit-focus-ring-color auto 5px&lt;/code&gt; in the &lt;a href=&quot;https://trac.webkit.org/browser/trunk/Source/WebCore/css/html.css&quot;&gt;browser styles&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;custom-focus&quot;&gt;Custom focus&lt;/h2&gt;

&lt;p&gt;Our custom styles try to mimic focus on interactive controls like buttons, not on text links, so we use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2px solid&lt;/code&gt; outline for starters.&lt;/p&gt;

&lt;p&gt;On WebKit we can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-webkit-focus-ring-color&lt;/code&gt; keyword for the outline color.&lt;/p&gt;

&lt;p&gt;For other browsers we can use the CSS2 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Highlight&lt;/code&gt; system color. &lt;a href=&quot;http://www.w3.org/TR/CSS2/ui.html&quot;&gt;Highlight&lt;/a&gt; is defined as “Item(s) selected in a control” so it works for what we need. It’s usually a blue-ish color, except for Opera, that uses a light gray.&lt;/p&gt;

&lt;p&gt;WebKit browsers have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;outline-style&lt;/code&gt; set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auto&lt;/code&gt; by default, which looks more like a glow rather than a solid line.&lt;/p&gt;

&lt;p&gt;Firefox and most other browsers translate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auto&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;none&lt;/code&gt;. That’s why we have to use a WebKit-only media query for the outline style. To group WebKit-only properties together, we also set the WebKit specific outline color inside the media query.&lt;/p&gt;

&lt;p&gt;The complete CSS:&lt;/p&gt;

&lt;div class=&quot;language-css 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;nc&quot;&gt;.unreal-focus&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;outline-width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;outline-style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;solid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;outline-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Highlight&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;c&quot;&gt;/* WebKit gets its native focus styles.
 */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;-webkit-min-device-pixel-ratio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&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;nc&quot;&gt;.unreal-focus&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;outline-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;-webkit-focus-ring-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;outline-style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;auto&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;How it looks across various browsers:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/images/mimic-native-focus-screenshots.png&quot; alt=&quot;Native and custom focus in various browsers and os&apos;s&quot; /&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/css-ripple-material-design</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/css-ripple-material-design/"/>
    <title>Material design ripples with CSS</title>
    <updated>2015-11-20T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;I recently created a Material Design theme for the &lt;a href=&quot;/css-toggle-switch&quot;&gt;css-toggle-switch&lt;/a&gt; library, and found a way to implement the “ripple” effect using just CSS.&lt;/p&gt;

&lt;p&gt;Most Material Design implementations use JavaScript for the ripple effect on the input components, to be able to match the &lt;a href=&quot;http://www.google.ro/design/spec/animation/responsive-interaction.html#responsive-interaction-surface-reaction&quot;&gt;“surface reaction”&lt;/a&gt; in the design spec.&lt;/p&gt;

&lt;h2 id=&quot;buttons&quot;&gt;Buttons&lt;/h2&gt;

&lt;p&gt;The technique is a mash of pseudo-classes that trigger an animation on a pseudo-element when matched.&lt;/p&gt;

&lt;div class=&quot;editor-demo&quot; data-html=&quot;/media/demos/css-material-ripples/button.html&quot; data-css=&quot;/media/demos/css-material-ripples/button.css&quot;&gt;&lt;/div&gt;

&lt;p&gt;For the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;button&lt;/code&gt; element, we create the ripple using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;button:after&lt;/code&gt;. Then, to trigger the animation on it, we use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;button:not(:active):after&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-css 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;nt&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:not&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:active&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:after&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ripple&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1s&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’t trigger the animation on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:active&lt;/code&gt; because that would cause the animation to abruptly end when we stop clicking.&lt;/p&gt;

&lt;p&gt;Setting the animation with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:not(:active)&lt;/code&gt; selector helps with triggering it again after the button was clicked, when the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:active&lt;/code&gt; pseudo-class no longer matches. This also makes the animation re-play when clicking the button again.&lt;/p&gt;

&lt;p&gt;Since the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:not(:active)&lt;/code&gt; selector matches from the start, the animation runs once when the page loads, without any user input.&lt;/p&gt;

&lt;p&gt;To fix this, we hide the ripple, and show it only when the button is focused.&lt;/p&gt;

&lt;div class=&quot;language-css 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;nt&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:after&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;visibility&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hidden&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;nt&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:focus:after&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;visibility&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;visible&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;checkboxes-and-radios&quot;&gt;Checkboxes and radios&lt;/h2&gt;

&lt;p&gt;Same as for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;button&lt;/code&gt;, we implement the ripple for checkboxes and radios using pseudo-classes, but instead of using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:active&lt;/code&gt; we use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:checked&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;editor-demo&quot; data-html=&quot;/media/demos/css-material-ripples/toggle.html&quot; data-css=&quot;/media/demos/css-material-ripples/toggle.css&quot;&gt;&lt;/div&gt;

&lt;p&gt;Since radios and checkboxes can use similar markup, we can implement the ripple using a single class on a parent container.&lt;/p&gt;

&lt;div class=&quot;language-html 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;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;toggle&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;checkbox&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;c&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;c1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;c1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Checkbox&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;toggle&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;radio&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;r&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;r1&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;checked&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;r1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Radio&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We create the ripple on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;label:after&lt;/code&gt; pseudo-element.&lt;/p&gt;

&lt;p&gt;To trigger the animation when deselecting the checkbox, we use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.toggle input + label:after&lt;/code&gt; selector.&lt;/p&gt;

&lt;div class=&quot;language-css 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;nc&quot;&gt;.toggle&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:after&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ripple&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;.4s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ease-out&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 re-play the animation when selecting the checkbox, or when selecting a radio button, we need to duplicate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@keyframes&lt;/code&gt;, and change the animation name.&lt;/p&gt;

&lt;div class=&quot;language-css 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;nc&quot;&gt;.toggle&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:checked&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:after&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;animation-name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rippleDuplicate&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 use the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:focus&lt;/code&gt; trick as for the button, to make sure the first animation run is not visible when the page is loaded.&lt;/p&gt;

&lt;h2 id=&quot;drawbacks&quot;&gt;Drawbacks&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;http://www.google.ro/design/spec/animation/responsive-interaction.html#responsive-interaction-material-response&quot;&gt;“Responsive interaction”&lt;/a&gt; section of the Material design spec calls the ripple “instant visual confirmation at the point of contact”.&lt;/p&gt;

&lt;p&gt;With the CSS implementation the ripple will only show up when the input action was finished. That’s because of the pseudo-classes we’re using.&lt;/p&gt;

&lt;p&gt;The other issue is that we can’t position the ripple at the point of click/touch, without using JavaScript.&lt;/p&gt;

&lt;p&gt;Another downside is that the ripple will suddenly disappear if you unfocus the button or input while the animation is running. That’s because of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:focus&lt;/code&gt; trick we use to hide the first run of the animation when the page loads.&lt;/p&gt;

&lt;p&gt;These snippets are highly experimental and will work only on modern browsers. If you need production ready toggle switches, with or without material design, you can use &lt;a href=&quot;/css-toggle-switch&quot;&gt;css-toggle-switch&lt;/a&gt;.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/angular-scope-namespace</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/angular-scope-namespace/"/>
    <title>Simple Angular scope namespacing</title>
    <updated>2015-02-24T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;The best way to work with controller scopes in Angular is to avoid using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$scope&lt;/code&gt; object as much as possible. Instead you should use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;controllerAs&lt;/code&gt; syntax introduced in Angular 1.2.&lt;/p&gt;

&lt;p&gt;If for some reason you can’t use it, here’s a simple pattern that will help you handle and namespace your models.&lt;/p&gt;

&lt;p&gt;At its core, this is how a basic controller using the pattern looks like:&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;controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;MainCtrl&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;$scope&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;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fullName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&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;You’ll notice the most important part at the top:&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;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&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;What this is doing is using a big object that will contain all the models in our controller. This helps with a couple of things.&lt;/p&gt;

&lt;p&gt;First, it helps with the &lt;a href=&quot;http://jimhoskins.com/2012/12/14/nested-scopes-in-angularjs.html&quot;&gt;“there’s gotta be a dot in there somewhere”&lt;/a&gt; guideline for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ng-model&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And second, it gives you some syntactic sugar for referencing the models. After you set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model&lt;/code&gt; variable this way in your controller, you won’t need to reference &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$scope&lt;/code&gt; again, neither in the templates or in the rest of the controller (except for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$watch&lt;/code&gt; or other &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$scope&lt;/code&gt; methods).&lt;/p&gt;

&lt;p&gt;That means you can now use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model.modelName&lt;/code&gt; in the controller and in the templates, for pointing to a model.&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;// in controllers&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;modelName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;abc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;div class=&quot;language-html 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;c&quot;&gt;&amp;lt;!-- in templates --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ng-model=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;model.modelName&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The pattern’s benefits are more obvious when using it with nested controllers.&lt;/p&gt;

&lt;p&gt;Let’s say you want a couple of global models to use throughout the app. You can use the run block for defining the global models.&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;run&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;$rootScope&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;root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$rootScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;userId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;abc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;MainCtrl&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;$scope&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;root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;root&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;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fullName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&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;For namespacing, I used a different variable name(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt;) for the model in the run block.&lt;/p&gt;

&lt;p&gt;You can now reference any model in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; namespace by using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root.modelName&lt;/code&gt; in both the controller and the template.&lt;/p&gt;

&lt;p&gt;Use the same pattern for any number of parent scopes, just make sure to use different namespaces for each parent.&lt;/p&gt;

&lt;p&gt;When you want to share the same model namespace with a parent controller, you can use a slightly modified version of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model&lt;/code&gt; definition.&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;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&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;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;model&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 will either inherit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model&lt;/code&gt; from a top controller scope, if it exists, or define it as an empty object. This means you can use it as a standard route controller, or as a nested controller that shares the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model&lt;/code&gt; namespace with its parent.&lt;/p&gt;

&lt;p&gt;Even if you do use this pattern, keep in mind that the best practice is to to use services for models shared between controllers.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/optware-android-media-center</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/optware-android-media-center/"/>
    <title>Turn your old Android phone into a media center</title>
    <updated>2014-10-16T00:00:00+00:00</updated>
    <content type="html">&lt;blockquote&gt;
  &lt;p&gt;If you have a non-smart TV with USB support and an Android phone, this will show you how to turn them into a poor man’s media center. It will include a torrent server with remote access and automatic torrent downloads, Samba and SSH.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my case, I’m using a Samsung LE32E TV and an Alcatel OT-918 smartphone.&lt;/p&gt;

&lt;p&gt;We’ll work only with the phone, so you won’t have to change anything on the TV.&lt;/p&gt;

&lt;p&gt;First, you need to make sure your device is rooted. See this guide for &lt;a href=&quot;http://forum.xda-developers.com/showthread.php?t=1748927&quot;&gt;rooting the Alcatel OT-918&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next up, if you’re also using an older phone with a smaller internal memory, you need a partitioned SD card, with a larger &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ext2/3/4&lt;/code&gt; partition and the rest as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FAT32&lt;/code&gt;. I’m using a 32GB SD card with a 1GB &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ext2&lt;/code&gt; partition and the rest as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FAT32&lt;/code&gt;. I definitely recommend using a class 10 SD card.&lt;/p&gt;

&lt;p&gt;This means your Android kernel needs to have support for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ext&lt;/code&gt; partitions.
See this &lt;a href=&quot;http://forum.xda-developers.com/showpost.php?p=42693393&amp;amp;postcount=239&quot;&gt;kernel with ext support for Alcatel OT-918&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After you’ve partitioned your SD card, and made sure you have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ext&lt;/code&gt; support in the kernel, use &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.buak.Link2SD&amp;amp;hl=en&quot;&gt;Link2SD&lt;/a&gt; or something similar to mount the ext partition.&lt;/p&gt;

&lt;p&gt;Then connect your phone to your WiFi router and set a static IP for it. If you’re using Android 2.3, go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Settings &amp;gt; WiFi Settings &amp;gt; Advanced&lt;/code&gt; and press &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Use static IP&lt;/code&gt;. Set the IP to something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.1.XX&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;optware-for-android&quot;&gt;Optware for Android&lt;/h2&gt;

&lt;p&gt;We’ll start installing software on the phone. You’ll need to use a Linux system for this. Using a Live CD should also work.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.nslu2-linux.org/wiki/Optware/HomePage&quot;&gt;Optware&lt;/a&gt; is a lightweight package manager for Linux. We’ll install it on the phone and use it to get the rest of the packages we need.&lt;/p&gt;

&lt;p&gt;Make sure you have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;adb&lt;/code&gt; installed. If you’re running Ubuntu you just need to install the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;android-tools-adb&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;Connect the device to your PC and, in a terminal, run:&lt;/p&gt;

&lt;div class=&quot;language-bash 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;nb&quot;&gt;sudo &lt;/span&gt;adb devices
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Your device should show up in a list.&lt;/p&gt;

&lt;p&gt;Download the &lt;a href=&quot;https://github.com/pfalcon/optware-android/blob/master/optware-install-via-adb.sh&quot;&gt;Optware package manager install script&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If your Android device has a small internal memory, edit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;optware-install-via-adb.sh&lt;/code&gt; script, and change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OPTWARE_DIR&lt;/code&gt; variable to point to an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/opt&lt;/code&gt; folder on your mounted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ext&lt;/code&gt; partition.
The variable should look like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OPTWARE_DIR=/data/sdext2/opt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Otherwise, if your device has plenty of internal memory, you can just leave the script as it is.&lt;/p&gt;

&lt;p&gt;Now run the script with:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./optware-install-via-adb.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will install &lt;a href=&quot;https://github.com/pfalcon/optware-android&quot;&gt;Optware for Android&lt;/a&gt; on your device.&lt;/p&gt;

&lt;p&gt;We now have a proper package manager on the device, so we’ll open a shell and start installing packages.&lt;/p&gt;

&lt;p&gt;Connect to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;adb shell&lt;/code&gt; and start the Optware shell with:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;adb shell
./data/sdext2/opt/start.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now install everything related to Transmission (torrent server), FlexGet (automatic downloads), OpenSSH and Samba.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ipkg update
ipkg &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;nano
ipkg &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;transmission

ipkg &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;openssh
ipkg &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;perl
ipkg &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;samba36

ipkg &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;gcc
ipkg &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;python26
ipkg &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;py26-setuptools

easy_install transmissionrpc
easy_install flexget &lt;span class=&quot;c&quot;&gt;# in case of easy_install error, edit opt/lib/python2.6/distutils/distutils.cfg&lt;/span&gt;

easy_install periscope &lt;span class=&quot;c&quot;&gt;# for subtitles&lt;/span&gt;

easy_install pip &lt;span class=&quot;c&quot;&gt;# just to be able to remove packages&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now that we installed the packages, we’ll start configuring them.&lt;/p&gt;

&lt;h2 id=&quot;configure-ssh&quot;&gt;Configure SSH&lt;/h2&gt;

&lt;p&gt;We’ll enable connecting by SSH using your public key. I’m assuming you already have your SSH keys set up on your system.&lt;/p&gt;

&lt;p&gt;Edit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/opt/etc/openssh/sshd_config&lt;/code&gt; file, and set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RSAAuthentication&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PubkeyAuthentication&lt;/code&gt; to:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;RSAAuthentication &lt;span class=&quot;nb&quot;&gt;yes
&lt;/span&gt;PubkeyAuthentication &lt;span class=&quot;nb&quot;&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can edit the file with Nano, since we installed it before:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nano /opt/etc/openssh/sshd_config
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Edit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/opt/home/root/.ssh/authorized_keys&lt;/code&gt; file, and paste the contents of your local public key file (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./pub&lt;/code&gt;) in it.&lt;/p&gt;

&lt;p&gt;Same as before, you can use Nano for this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nano /opt/home/root/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now restart OpenSSH with:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/opt/etc/init.d/S40sshd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sometimes when restarting OpenSSH, it will complain about the host key. If it does, create it with:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ssh-keygen &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; ecdsa &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /opt/etc/openssh/ssh_host_ecdsa_key &lt;span class=&quot;nt&quot;&gt;-N&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Exit the ADB shell, and you should now be able to get on the device using SSH:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ssh root@192.168.1.X
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now that we have SSH, you can also log-in onto your device using something like &lt;a href=&quot;https://filezilla-project.org/&quot;&gt;FileZilla&lt;/a&gt; for easier file access.&lt;/p&gt;

&lt;h2 id=&quot;configure-samba&quot;&gt;Configure Samba&lt;/h2&gt;

&lt;p&gt;I won’t go into much detail about the Samba config. Download my &lt;a href=&quot;https://github.com/ghinda/optware-mediacenter/blob/master/opt/etc/samba/smb.conf&quot;&gt;smb.conf&lt;/a&gt; file, and copy it into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/opt/etc/samba&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now restart Samba with&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/opt/etc/init.d/S08samba
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and it should be working.&lt;/p&gt;

&lt;p&gt;
&lt;del&gt;
There is an issue with Samba that is preventing you from deleting any files on the device. I haven’t managed to figure out what the cause is yet. It’s possible that the old version of Samba packaged for Optware has this bug.
&lt;/del&gt;
&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;On Ubuntu, mounting the Samba share with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cifs&lt;/code&gt; fixes the issues with deleting files.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Add this to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/fstab&lt;/code&gt; to mount the share with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cifs&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;//192.168.1.X/sdcard /media/MOUNT_POINT cifs &lt;span class=&quot;nb&quot;&gt;users&lt;/span&gt;,username&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;root,password&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,rw,nounix,iocharset&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;utf8,file_mode&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0777,dir_mode&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0777 0 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;configure-transmission&quot;&gt;Configure Transmission&lt;/h2&gt;

&lt;p&gt;Run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transmission-daemon&lt;/code&gt; first, then stop it, so it will create its config file.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;transmission-daemon
killall transmission-daemon
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can edit the config file at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;opt/home/root/.config/transmission-daemon/settings.json&lt;/code&gt;, or just use my &lt;a href=&quot;https://github.com/ghinda/optware-mediacenter/blob/master/opt/home/root/.config/transmission-daemon/settings.json&quot;&gt;settings.json&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A good idea is to change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;download-dir&lt;/code&gt; to point to the location you want it to download the torrents on the FAT32 SD card partition. Set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rpc-enabled&lt;/code&gt; property to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;, to enable RPC and be able to connect to the web interface at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://192.168.1.XX:9091/&lt;/code&gt; or use the &lt;a href=&quot;https://code.google.com/p/transmisson-remote-gui/&quot;&gt;Transmission Remote GUI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These are both already done in my &lt;a href=&quot;https://github.com/ghinda/optware-mediacenter/blob/master/opt/home/root/.config/transmission-daemon/settings.json&quot;&gt;settings.json&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;Once you have the config set-up, start transmission with:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;transmission-daemon
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;configure-flexget&quot;&gt;Configure FlexGet&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://flexget.com/&quot;&gt;FlexGet&lt;/a&gt; is a multipurpose download automation tool. We’ll use it to automate downloads.&lt;/p&gt;

&lt;p&gt;To configure Flexget, edit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/opt/home/root/.flexget/config.yml&lt;/code&gt; file. You can check out the &lt;a href=&quot;http://flexget.com/wiki/Cookbook&quot;&gt;FlexGet Cookbook&lt;/a&gt; for config file examples.&lt;/p&gt;

&lt;p&gt;See &lt;a href=&quot;http://flexget.com/wiki/Cookbook/Series/AdvancedTransmissionAndDownloadManagement&quot;&gt;the Transmission config example&lt;/a&gt;, to connect FlexGet to it, and have it add torrents automatically.&lt;/p&gt;

&lt;p&gt;If you need automatic subtitle downloads, we installed Periscope before, so just follow the &lt;a href=&quot;http://flexget.com/wiki/Plugins/periscope&quot;&gt;FlexGet Periscope config&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now copy the &lt;a href=&quot;https://github.com/ghinda/optware-mediacenter/blob/master/opt/flexget.sh&quot;&gt;flexget.sh&lt;/a&gt; file to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/opt/flexget.sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We’ll use this file to run the Flexget tasks. Flexget does have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;daemon&lt;/code&gt; mode with a scheduler, but I noticed it’s a real memory hog, so I can’t use it.&lt;/p&gt;

&lt;h2 id=&quot;configure-autorun-and-scheduling&quot;&gt;Configure autorun and scheduling&lt;/h2&gt;

&lt;p&gt;Copy &lt;a href=&quot;https://github.com/ghinda/optware-mediacenter/blob/master/opt/start.sh&quot;&gt;start.sh&lt;/a&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/opt/start.sh&lt;/code&gt;. This script will run everything related to SSH, Samba and Transmission.&lt;/p&gt;

&lt;p&gt;We need something that will run the script on startup and periodically run FlexGet. I’m using &lt;a href=&quot;https://play.google.com/store/apps/details?id=os.tools.scriptmanager&amp;amp;hl=en&quot;&gt;Script Manager&lt;/a&gt;, since it can do both.&lt;/p&gt;

&lt;p&gt;You need to set up the two scripts in Script Manager. Set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/opt/start.sh&lt;/code&gt; to run on Boot and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/opt/flexget.sh&lt;/code&gt; to run as often as you need it to check for new content (every 1 day/1 hour/etc.).&lt;/p&gt;

&lt;h2 id=&quot;dual-mount&quot;&gt;Dual Mount&lt;/h2&gt;

&lt;p&gt;By default, when you connect the Phone to the TV with USB, all apps on the phone, including Transmission and FlexGet will not be able to access the SD card. To get around this, we have to use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dual mount&lt;/code&gt; app.&lt;/p&gt;

&lt;p&gt;The app will mount the SD card on phone and the TV at the same time. This is usually not a good idea, since it will corrupt your SD card when doing simultaneous writes, but in this case the TV has read-only access, so it won’t happen.&lt;/p&gt;

&lt;p&gt;I recommend using &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.protocol.x.USB&quot;&gt;Dual Mount SD Widget&lt;/a&gt; since it’s the one that worked best for me.&lt;/p&gt;

&lt;p&gt;You can also use something like &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.rafoid.multimountsdcard.widget.free&quot;&gt;Multi Mount SD-Card Lite&lt;/a&gt; or similar.&lt;/p&gt;

&lt;p&gt;##Extra tips&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;My TV does not auto-refresh the contents on the SD card, so I have to turn it on and off to be able to see the newly added files in the USB interface.&lt;/li&gt;
  &lt;li&gt;If you’re using an older phone, it’s best to free up as much memory as possible. So remove any apps you don’t need and use something like &lt;a href=&quot;https://play.google.com/store/apps/details?id=cn.wq.disableservice&quot;&gt;Disable Service&lt;/a&gt; to kill any extra services.&lt;/li&gt;
  &lt;li&gt;After downloading lots of torrents on the SD card, even if it is a class 10, corruption will happen on the FAT32 partition. When it does, mount the SD card on your PC and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo dosfsck -w -r -l -a -v -t /dev/sdc1&lt;/code&gt; (replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sdc1&lt;/code&gt; with your SD card FAT32 partition) to try and fix the issues.&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/thanks-webmonkey</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/thanks-webmonkey/"/>
    <title>Thanks Webmonkey</title>
    <updated>2014-08-01T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;Around 2000, there weren’t that many “tutorial websites” out there for web development. The tutorials available were hard to follow or not that well-written. All but the ones on Webmonkey.&lt;/p&gt;

&lt;p&gt;I had to search for hours for a good tutorial on anything related to web development, before great learning resource sites like Codecademy, Smashing Magazine or MDN were available.&lt;/p&gt;

&lt;p&gt;Considering I didn’t have an internet connection at home, and internet cafés were pretty expensive at the time, this was less than ideal. When I did get a dial-up connection at home, the prices were still terrible.&lt;/p&gt;

&lt;p&gt;But looking around, one of the websites especially stood out. That was Webmonkey.&lt;/p&gt;

&lt;p&gt;I found it through Tripod.com, a free ad-supported web hosting service by Lycos that was popular then. Tripod.com gave you a whole 20 MBs of storage space, and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*.tripod.com&lt;/code&gt; subdomain, for free!&lt;/p&gt;

&lt;p&gt;Lycos also owned Webmonkey, so naturally they were pointing future “webmasters” to it.&lt;/p&gt;

&lt;p&gt;It was one of the few who had well-structured tutorials, with learning plans, containing everything from graphic design to JavaScript or SEO. It even had an “E-Business” category with stuff related to marketing or analytics.&lt;/p&gt;

&lt;p&gt;Dave Thau, or just Thau! as he was known on Webmonkey, wrote some of the best articles. His &lt;a href=&quot;https://web.archive.org/web/20010602040619/http://hotwired.lycos.com/webmonkey/programming/javascript/tutorials/tutorial2.html&quot;&gt;Advanced JavaScript Tutorial&lt;/a&gt; became pretty popular, and had stuff like cookies, timers or image preloading. It was awesome.&lt;/p&gt;

&lt;p&gt;His tutorials are the ones that initially got me into JavaScript, and helped me understand how it worked with the DOM and everything else.&lt;/p&gt;

&lt;p&gt;The articles were so great I was downloading them onto floppy disks at cafés, to take home and read again. I had created my own personal “MDN”, that I could reference anytime I couldn’t remember a tag or a JavaScript method.&lt;/p&gt;

&lt;p&gt;There were also lots of articles on other things like browser sniffing, frames, or XSS, which influenced how we did web development for years.&lt;/p&gt;

&lt;p&gt;Lycos &lt;a href=&quot;http://archive.wired.com/techbiz/it/news/2004/02/62300&quot;&gt;shut down Webmonkey formally in 2004&lt;/a&gt;, but it’s still online today in a basic news format.&lt;/p&gt;

&lt;p&gt;For all the nights I stayed up reading your tutorials, wanting to learn more because it was so much fun, I just wanted to say thank you!&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/community-driven-development</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/community-driven-development/"/>
    <title>Community driven development</title>
    <updated>2013-07-23T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;Just following trends is a bad idea at any time. But this is not about following trends. This is about switching open-source development tools because of the communities around them.&lt;/p&gt;

&lt;p&gt;What I’ve learned is that with free software projects, large communities are a definite sign of health and bring a lot of benefits in terms of code, documentation, testing or bug reports.&lt;/p&gt;

&lt;h2 id=&quot;from-brunch-to-yeoman&quot;&gt;From Brunch to Yeoman&lt;/h2&gt;

&lt;p&gt;The first decent build tool I used for my JavaScript projects was &lt;a href=&quot;http://brunch.io/&quot;&gt;Brunch&lt;/a&gt;. It has a simple config file, clear directory structure, and it’s flexible enough. It’s great. But I’m switching to Yeoman now. And here’s why.&lt;/p&gt;

&lt;p&gt;Brunch itself is written in CoffeeScript, but other than that, it’s language agnostic, so it doesn’t force it on you unless you want to contribute to the project directly. Still, because of this the community around it is also CoffeeScript-based, so most plugins, skeletons, and tutorials are CoffeeScript, so you can’t contribute to those either, unless you write CoffeeScript.&lt;/p&gt;

&lt;p&gt;Even after Grunt and Yeoman were released, I stuck with Brunch. But in the meantime the community around Yeoman and Grunt has gotten much bigger, and that means more plugins, generators and help available online right now.&lt;/p&gt;

&lt;p&gt;I’m not switching from one to the other because of a lack of features, but because I would have to invest more time in the development process if I didn’t. If I would stick with the project with the smaller community I’d have to be write plugins, skeletons and find documentation.&lt;/p&gt;

&lt;h2 id=&quot;same-thing-different-tools&quot;&gt;Same thing, different tools&lt;/h2&gt;

&lt;p&gt;Around late 2009, after using Subversion for a pretty long time, I decided to move on to distributed version control.&lt;/p&gt;

&lt;p&gt;On most projects I worked on with Svn, we used a single branch, continuously merged our code, and used tags for stable releases. It was less than optimal, and that’s why I was really looking forward to the proper branching features in DVCS’.&lt;/p&gt;

&lt;p&gt;The most popular options were, and still are, Mercurial and Git, so I had to choose between the two.&lt;/p&gt;

&lt;p&gt;Most of the people I work with use Windows, so good support for it was a must. This was definitely a plus for Mercurial, since Git was pretty shaky on Windows at the time.&lt;/p&gt;

&lt;p&gt;I also liked the more clean and monolithic architecture of Mercurial, instead of the more MacGyver-ish Git, which had many different ways of doing more or less the same thing.&lt;/p&gt;

&lt;p&gt;Since I chose Hg and wanted to have my repositories available online, I started using Bitbucket.&lt;/p&gt;

&lt;p&gt;Bitbucket was great, but it didn’t have a community as large as GitHub’s. This meant more people with GitHub accounts, and possibly more contributions, bug reports, and overall better visibility for a public project there, rather than on Bitbucket.&lt;/p&gt;

&lt;p&gt;That’s why, when I released &lt;a href=&quot;https://github.com/ghinda/acornmediaplayer&quot;&gt;Acorn Media Player&lt;/a&gt;, I hosted it on GitHub. There haven’t been that many contributions over time, but I’m sure there were more then there would have been if the repository would be on Bitbucket.&lt;/p&gt;

&lt;p&gt;At work I was still using Svn, but planned on moving to Hg, as I decided initially. I looked around for a web interface for Hg initially, like Bitbucket and Github, but open-source and self-hosted.&lt;/p&gt;

&lt;p&gt;Browsing around, I found RhodeCode and Gitlab. After I tested them both, it was clear that Gitlab was better for us, and just as with Github/Bitbucket, it had a larger community than RhodeCode and a faster development pace.&lt;/p&gt;

&lt;p&gt;This, along with GitHub’s popularity and the larger community around Git, which also meant more help available online, made me switch completely to Git for all my projects.&lt;/p&gt;

&lt;h2 id=&quot;competition-vs-collaboration&quot;&gt;Competition vs. Collaboration?&lt;/h2&gt;

&lt;p&gt;Ever since I took this decisions I wonder: is this popularity contest ok? Should we try to take a different approach?&lt;/p&gt;

&lt;p&gt;Maybe trying to improve the tool we’re currently using? But, again, wouldn’t this just be wasted time, if everybody else still switches to the other, more popular project, eventually?&lt;/p&gt;

&lt;p&gt;Having a common system of plugins, packages or modules, used by multiple projects would definitely solve a part of the issue, but i’’s probably not going to happen too soon.&lt;/p&gt;

&lt;p&gt;In an &lt;a href=&quot;https://github.com/brunch/brunch/issues/408&quot;&gt;issue on GitHub discussing the differences between Yeoman and Brunch&lt;/a&gt; Paul Miller, the creator of Brunch, says:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I believe existence of Yeoman is a potentially good thing, because it brings competition to the board. Yeoman will become better, brunch will become better.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Free software should be about collaboration, but collaboration rarely happens between projects with the same scope, so we just end up creating the same functionality in different ways.&lt;/p&gt;

&lt;p&gt;This is the same type of competition that goes on between closed-source projects. Is this better than collaboration?&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/tasks-sidebar-gmail</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/tasks-sidebar-gmail/"/>
    <title>Google Tasks sidebar in Gmail</title>
    <updated>2013-06-29T00:00:00+00:00</updated>
    <content type="html">&lt;blockquote&gt;
  &lt;p&gt;RightTasks is now also available for &lt;a href=&quot;https://addons.opera.com/en/extensions/details/righttasks-for-gmailtm/&quot;&gt;Opera&lt;/a&gt; and &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/righttasks-for-gmail/&quot;&gt;Firefox&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A couple of months ago I released the &lt;a href=&quot;https://chrome.google.com/webstore/detail/righttasks-for-gmail/hgniockidojcaaolfcbbkaaakbjdebpe&quot;&gt;RightTasks for Gmail&lt;/a&gt; extension for Chrome, which adds your Google Tasks to a sidebar in Gmail.&lt;/p&gt;

&lt;p&gt;Google Calendar has this feature by default, and allows you to have your Google Tasks visible in a sidebar, on the right side of the calendar. Since it’s so handy, people have been asking for the same feature in Gmail for, at least, as long as it’s been available in Calendar.&lt;/p&gt;

&lt;p&gt;The default Tasks widget available in Gmail, when activated, is placed above everything else, so you have to keep opening and closing it, to not get in the way of your work.&lt;/p&gt;

&lt;p&gt;I’ve seen people use Remember The Milk just for the tasks sidebar feature, since they provide the &lt;a href=&quot;https://www.rememberthemilk.com/services/gmail/addon/&quot;&gt;Remember The Milk for Gmail Add-on&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is a different way of getting something similar, by using the Gadgets feature from Labs, but it’s not nearly as functional as the default Tasks widget.&lt;/p&gt;

&lt;p&gt;There are also other extensions for Tasks, but having to manually open a popup, or tab, just to see them is not as useful as having them placed next to your emails, especially if you’re using Gmail like a traditional desktop email client, keeping it open all the time.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/righttasks-for-gmail/hgniockidojcaaolfcbbkaaakbjdebpe&quot;&gt;RightTasks&lt;/a&gt; uses the default Tasks widget, so you have all the official features available, like adding an email as a task, with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SHIFT + T&lt;/code&gt; keyboard shortcut, or focusing on the Tasks widget with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;G then K&lt;/code&gt; keyboard shortcut.&lt;/p&gt;

&lt;p&gt;You can contribute to the extension, or report any issues, on GitHub: &lt;a href=&quot;https://github.com/ghinda/righttasks&quot;&gt;https://github.com/ghinda/righttasks&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/jpeg-blob-ajax-android</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/jpeg-blob-ajax-android/"/>
    <title>Send a JPEG Blob with AJAX on Android</title>
    <updated>2012-11-25T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;Having to upload a JPEG image as a raw Blob on Android 4.0+ revealed a couple of bugs.&lt;/p&gt;

&lt;p&gt;If you have direct access to the specific JPEG image, when the image is on the same domain as the rest of your app, or you are in an environment without cross-origin restrictions, such as a PhoneGap webview, you can use the XHR2 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;responseType&lt;/code&gt; property to specify the format of the returned data.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://caniuse.com/#feat=xhr2&quot;&gt;XMLHttpRequest 2 support&lt;/a&gt; was introduced in Android 3.0.&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;imageXhr&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;XMLHttpRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;imageXhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;path/to/image.jpg&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;nx&quot;&gt;imageXhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;responseType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;blob&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;get-image-from-canvas&quot;&gt;Get image from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canvas&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;If you have to get the image data from a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canvas&lt;/code&gt;, you should be able to get the dataURL, write it to an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ArrayBuffer&lt;/code&gt; and then write it to a Blob. In the near future we’ll be able to use the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/DOM/HTMLCanvasElement#Methods&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toBlob()&lt;/code&gt; method&lt;/a&gt;, which will return the image data as a Blob. Right now, to be “future friendly”, we can detect support for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toBlob()&lt;/code&gt; and use Sebastian Tschan’s &lt;a href=&quot;https://github.com/blueimp/JavaScript-Canvas-to-Blob&quot;&gt;canvas.toBlob() polyfill&lt;/a&gt; if there’s no native support for it.&lt;/p&gt;

&lt;p&gt;Unfortunately, if you need the image data as a JPEG you’ll hit an Android bug.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toDataURL&lt;/code&gt; method allows you to specify the type of the returned &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data:&lt;/code&gt;, so you should be able to specify the ‘image/jpeg’ type, and get a JPEG image. While this works on most desktop browsers, Android always returns the image as a PNG.&lt;/p&gt;

&lt;p&gt;Here’s a simple &lt;a href=&quot;http://jsfiddle.net/ghinda/na86m/&quot;&gt;test for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canvas.toDataURL(&apos;image/jpeg&apos;)&lt;/code&gt; method&lt;/a&gt;, demonstrating the bug. While this will work on desktop browsers, testing it on Android 3+ will always return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;image/png&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The only work-around is to use a &lt;a href=&quot;http://web.archive.org/web/20120830003356/http://www.bytestrom.eu/blog/2009/1120a_jpeg_encoder_for_javascript&quot;&gt;JavaScript JPEG Encoder&lt;/a&gt;, and encode the raw image data yourself.&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;encoder&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;JPEGEncoder&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;imageData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;encoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;2d&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getImageData&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;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;canvasWidth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;canvasHeight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&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;You can now convert the image data to a Blob.&lt;/p&gt;

&lt;h2 id=&quot;blobs&quot;&gt;Blobs&lt;/h2&gt;

&lt;p&gt;Android introduced &lt;a href=&quot;http://caniuse.com/#feat=blobbuilder&quot;&gt;support for Blobs&lt;/a&gt; in 3.0, using the now deprecated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BlobBuilder&lt;/code&gt; interface, and has kept it the same up to the latest version (4.2 as of November 2012).&lt;/p&gt;

&lt;p&gt;According to &lt;a href=&quot;https://sites.google.com/a/chromium.org/dev/developers/web-platform-status&quot;&gt;chromestatus.com&lt;/a&gt;, Chrome for Android also has support only for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BlobBuilder&lt;/code&gt; interface right now.&lt;/p&gt;

&lt;p&gt;This isn’t really a problem, since we can check support for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BlobBuilder&lt;/code&gt;, and create the Blob using the supported interface.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;canvas.toBlob&lt;/code&gt; polyfill adds an additional function called &lt;a href=&quot;https://github.com/blueimp/JavaScript-Canvas-to-Blob#api&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dataURLtoBlob&lt;/code&gt;&lt;/a&gt;, which can convert a data url to a Blob. We can use this method on the manually-encoded JPEG image data.&lt;/p&gt;

&lt;h2 id=&quot;sending-the-blob-with-ajax&quot;&gt;Sending the Blob with AJAX&lt;/h2&gt;

&lt;p&gt;XHR2 allows us to send additional formats with AJAX beside FormData, like Blob or ArrayBuffer. We can simply use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;send&lt;/code&gt; method with our Blob as the parameter.&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;xhr&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;XMLHttpRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;upload/binary/jpeg&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setRequestHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;image/jpeg&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;blob&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;While the request works as expected on supporting desktop browsers, there seems to be a bug in Android that sends the request completely empty. Here’s a &lt;a href=&quot;http://jsfiddle.net/ghinda/fRgbf/&quot;&gt;test for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xhr.send(blob)&lt;/code&gt; using GitHub’s API&lt;/a&gt;, which sends both a Blob and an ArrayBuffer.&lt;/p&gt;

&lt;p&gt;On supporting desktop browsers, you’ll get the proper response from the API, while on Android you’ll get an error for the Blob-based request, because the API request doesn’t send the required parameters, sending the request without any payload.&lt;/p&gt;

&lt;p&gt;Weirdly, the work-around is to send an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ArrayBuffer&lt;/code&gt;, instead of a Blob, which will have the exact same effect. You can convert a Blob to an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ArrayBuffer&lt;/code&gt; using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileReader&lt;/code&gt; object. Check the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str2ab_blobreader&lt;/code&gt; function in the example above to see how you use it exactly.&lt;/p&gt;

&lt;h2 id=&quot;bug-reports&quot;&gt;Bug reports&lt;/h2&gt;

&lt;p&gt;I’ve opened bug reports for these bugs on the Android bug tracker:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://code.google.com/p/android/issues/detail?id=39885&quot;&gt;Browser: canvas.toDataURL(‘image/jpeg’) returns image/png&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://code.google.com/p/android/issues/detail?id=39882&quot;&gt;Browser: Trying to send a Blob with XHR2 sends the request with an empty body&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And also on the &lt;a href=&quot;https://github.com/scottjehl/Device-Bugs&quot;&gt;Device-Bugs issue collection&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/scottjehl/Device-Bugs/issues/33&quot;&gt;canvas.toDataURL(‘image/jpeg’) returns image/png on Android&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/scottjehl/Device-Bugs/issues/34&quot;&gt;Trying to send a Blob with XHR2 sends the request with an empty body on Android 4+&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please help me get the attention of the Android developers, so that they can get these bugs fixed for newer releases.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/awd-poster-design-process</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/awd-poster-design-process/"/>
    <title>I love Adaptive Web Design poster design process</title>
    <updated>2012-08-03T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;In February, &lt;a href=&quot;http://veerle.duoh.com&quot;&gt;Veerle Pieters&lt;/a&gt; partnered with &lt;a href=&quot;http://easy-readers.net&quot;&gt;Easy Readers&lt;/a&gt; and launched the &lt;a href=&quot;http://veerle.duoh.com/design/article/i_love_adaptive_web_design_poster_contest&quot;&gt;I Love Adaptive Web Design Poster Contest&lt;/a&gt;. Since I was lucky enough to be among the winners, I thought it would be a great idea to give some insight on how the poster came together, and what’s the idea behind it.&lt;/p&gt;

&lt;p&gt;There is just not enough information online about the complete design process. Sure, there are a lot of tutorials, articles and notes about specific tools or techniques, but design is much more than that, crossing tools and mediums.&lt;/p&gt;

&lt;h2 id=&quot;concept&quot;&gt;Concept&lt;/h2&gt;

&lt;p&gt;The basic requirement for the contest was to &lt;em&gt;design a poster celebrating your passion for adaptive web design&lt;/em&gt;, as stated in the original briefing, so there was plenty of creative freedom.&lt;/p&gt;

&lt;p&gt;Veerle Pieters provided the sources for the cover she had designed for Aaron Gustafson’s book, along with the &lt;a href=&quot;http://veerle.duoh.com/design/article/adaptive_web_design_book_cover&quot;&gt;design process for the cover&lt;/a&gt; available on her blog, which provided a great starting point for me.&lt;/p&gt;

&lt;p&gt;Since &lt;em&gt;adaptive web design&lt;/em&gt; is such a broad term, I tried not to use actual devices, screen sizes, or the such, even if those were my initial thoughts. But, even if I didn’t want exact metrics, I still wanted to present the concept in clear way that was easy to understand.&lt;/p&gt;

&lt;p&gt;After getting the first chapter of the book, that was available for download, and reading Aaron Gustafson’s clear description of the levels of user experience, the idea of infographics quickly came to mind.&lt;/p&gt;

&lt;h2 id=&quot;inspiration&quot;&gt;Inspiration&lt;/h2&gt;

&lt;p&gt;It’s always important to know your history, so, as a designer, it’s mandatory to know where’re we’re coming from. If you’re unfamiliar with design history, I encourage you look into the great work of the past, such as the &lt;a href=&quot;http://www.smashingmagazine.com/2009/08/02/bauhaus-ninety-years-of-inspiration/&quot;&gt;Bauhaus&lt;/a&gt; or the &lt;a href=&quot;http://www.smashingmagazine.com/2009/07/17/lessons-from-swiss-style-graphic-design/&quot;&gt;Swiss design style&lt;/a&gt;. There are of course many more parts of history to look into, but for a condensed overview with a focus on graphic design I suggest you take a look at &lt;a href=&quot;http://www.designishistory.com/&quot;&gt;DesignIsHistory&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After some browsing around I came up with the following mood board.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/images/awd-poster-moodboard.png&quot; alt=&quot;I Love Adaptive Web Design Poster Mood board&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-tower&quot;&gt;The Tower&lt;/h2&gt;

&lt;p&gt;Afterwards, I started sketching to see if there was anything good I could come up with, starting from the moodboard, the levels of user experience and the general idea of infographics.&lt;/p&gt;

&lt;p&gt;I imagined the levels of experience as skin layers on an onion, but also as building blocks providing a different experience at each height. I prefer a more geometric style, so I decided to work on the “building blocks” idea some more.&lt;/p&gt;

&lt;p&gt;After some initial sketching, this is how the first version looked like.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/images/ghinda-iloveawdposter1-web.jpg&quot; alt=&quot;First version of the I Love Adaptive Web Design Poster&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;final-version&quot;&gt;Final version&lt;/h2&gt;

&lt;p&gt;While I was pretty happy with the first version of the poster, it still wasn’t as clear as would’ve liked it to be. The basic idea was to be able to show the poster to somebody who was unfamiliar with the concept, and they could easily understand it.&lt;/p&gt;

&lt;p&gt;With this idea in mind, I started sketching and experimenting with including more text, without complicating the overall look of the poster.&lt;/p&gt;

&lt;p&gt;Ultimately, the idea came from one of &lt;a href=&quot;http://www.aiga.org/medalist-ladislavsutnar/&quot;&gt;Ladislav Sutnar&lt;/a&gt; catalog layouts.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/images/ghinda-iloveawdposter2-web.jpg&quot; alt=&quot;Second, final version of the I Love Adaptive Web Design Poster&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can find some great articles about design processes on &lt;a href=&quot;http://www.davidairey.com/portfolio/&quot;&gt;David Airey’s website&lt;/a&gt; or on &lt;a href=&quot;http://veerle.duoh.com&quot;&gt;Veerle Pieters’ Blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The full list of winners is available on &lt;a href=&quot;http://veerle.duoh.com/design/article/i_love_adaptive_web_design_poster_contest_winners&quot;&gt;Veerle Pieters’ blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Congrats to the winners, the entries were great!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/css-toggle-switches-mobile</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/css-toggle-switches-mobile/"/>
    <title>Mobile support for the CSS toggle switches</title>
    <updated>2012-03-10T00:00:00+00:00</updated>
    <content type="html">&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Update December 2012&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;The latest version of the toggle switch has full mobile support and easy integration with &lt;a href=&quot;/css-toggle-switch/bootstrap.html&quot;&gt;Twitter Bootstrap&lt;/a&gt; or &lt;a href=&quot;/css-toggle-switch/foundation.html&quot;&gt;ZURB Foundation&lt;/a&gt;.&lt;/p&gt;

  &lt;p&gt;See the latest demos: &lt;a href=&quot;/css-toggle-switch/&quot;&gt;CSS Toggle Switch&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Update October 2012&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;After some testing it turns out that the Android 2.3 browser, and possibly other older Webkit browsers, are affected by this older &lt;a href=&quot;http://css-tricks.com/webkit-sibling-bug/&quot;&gt;WebKit Adjacent/General Sibling and Pseudo Class Bug&lt;/a&gt;, which was causing issues with the toggle switches.&lt;/p&gt;

  &lt;p&gt;The fix I added is based on the one described in the article above, but applied only to the containers, not the whole &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;body&lt;/code&gt;, for performance reasons.&lt;/p&gt;

  &lt;p&gt;Another issue was that, &lt;a href=&quot;http://stackoverflow.com/questions/7358781/tapping-on-label-in-mobile-safari&quot;&gt;on older iOS versions the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;input&lt;/code&gt; was not selected, when tapping the label&lt;/a&gt;. The work-around for this was to add an empty &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;onclick&lt;/code&gt; handler. This handler also makes Opera Mini re-render the page, with the right input selected.&lt;/p&gt;

  &lt;p&gt;These changes completely remove the need for the JavaScript functionality that was previously adding mobile support.&lt;/p&gt;

  &lt;p&gt;Latest demos: &lt;a href=&quot;/css-toggle-switch/&quot;&gt;CSS Toggle Switch&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While testing the &lt;a href=&quot;/article/css-toggle-switches&quot;&gt;CSS toggle switches&lt;/a&gt; from my last article, I noticed they had issues, or didn’t work at all, in various mobile browsers. The only mobile browsers which seemed to properly support the switches were Firefox Mobile and Opera Mobile.&lt;/p&gt;

&lt;p&gt;For both the radio and checkbox-based versions, the switches looked alright but the behavior wasn’t working; the toggle buttons didn’t move when selected.&lt;/p&gt;

&lt;p&gt;The only version that worked properly was the one where the checkbox input was placed inside the label.&lt;/p&gt;

&lt;p&gt;After some digging, I ended up on &lt;a href=&quot;http://www.thecssninja.com/css/custom-inputs-using-css&quot;&gt;The CSS Ninja&lt;/a&gt;, who also had similar problems with custom radio and checkbox inputs. His latest solution to the iOS issue was to make sure the input is topmost, and set it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;opacity&lt;/code&gt; to zero.&lt;/p&gt;

&lt;p&gt;When applying this technique on the basic checkbox-based example, after taping the switch, the background, border, and text colors where changing, but the position of the button wasn’t.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.toggle input:checked + label:after&lt;/code&gt; rule was working, while the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.toggle input:checked ~ span&lt;/code&gt; rule, supposed to change the position of the toggle button, wasn’t.&lt;/p&gt;

&lt;p&gt;Also, it wasn’t working at all for the radio input-based switch.&lt;/p&gt;

&lt;h2 id=&quot;mobile-webkit&quot;&gt;Mobile Webkit&lt;/h2&gt;

&lt;p&gt;After some more digging, it turns out that most mobile Webkits try to prevent reflows, and don’t trigger them when checking/selecting radios or checkboxes. I’m guessing this is mostly for performance reasons.&lt;/p&gt;

&lt;p&gt;That’s why, to get mobile support, you have to force a reflow when toggling the switch. The only way to do this is to use JavaScript.&lt;/p&gt;

&lt;h2 id=&quot;opera-mini&quot;&gt;Opera Mini&lt;/h2&gt;

&lt;p&gt;Since Opera Mini is one of the most used mobile browsers, supporting it is big plus. And, even though it’s a proxy browser, it does have some support for JavaScript. Still, using the same technique to trigger a reflow as on the other mobile browsers, isn’t working.&lt;/p&gt;

&lt;p&gt;But, it turns out that setting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checked&lt;/code&gt; property on the input with JavaScript, does trigger a sort-of-reflow. It will reload the page, with the new option selected. It’s probably the best solution we can get for Opera Mini, since it doen’t have any “real” interactions on the page.&lt;/p&gt;

&lt;h2 id=&quot;the-script&quot;&gt;The Script&lt;/h2&gt;

&lt;p&gt;The script I put together is pretty straight forward, except for a couple of things.&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;cm&quot;&gt;/* Minimal Touch support test.
* You should probably use Modernizr.
*/&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;touchSupport&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ontouchstart&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;mobile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Utility function, needed to get the input elements next to labels&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;Object&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;nx&quot;&gt;previousObject&lt;/span&gt; &lt;span class=&quot;o&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;p&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;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;previousSibling&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nodeType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&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;p&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;cm&quot;&gt;/* Manualy check the input, for Opera Mini/proxy browsers
*/&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;checkRadio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&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;input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;previousObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;inputType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;inputType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;checkbox&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;checked&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;checked&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;checked&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&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;inputType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;radio&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;checked&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/* Force reflow
*/&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;forceReflow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&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;cm&quot;&gt;/* There&apos;s a delay between taping a label, and checking the input.
  * That&apos;s why we have to
  */&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;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;previousObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;checked&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;// force reflow&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;className&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;className&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;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// if the input is not checked yet, try again&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;setTimeout&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;forceReflow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&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;mi&quot;&gt;100&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;cm&quot;&gt;/* Get all labels on the page.
* You should use a more specific selector on your page.
*/&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;labels&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;touchSupport&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;// Mobile Webkit(Android, iOS, BB, WebOS, etc.), and others with Touch support&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;o&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;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&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;labels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ontouchstart&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;forceReflow&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;k&quot;&gt;else&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;mobile&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;// Non-touch browsers, Opera Mini and other proxy-browsers&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&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;i&lt;/span&gt; &lt;span class=&quot;o&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;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&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;labels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onclick&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;checkRadio&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;I’m using the timeout because there seems to be a delay between taping the label, and the input actually getting checked. If we trigger the reflow too early, before the input is checked, it still won’t change it’s position. So we have to wait until the input is checked, before the reflow.&lt;/p&gt;

&lt;p&gt;The reflow is triggered using:&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;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;className&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;className&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These solutions should also work on other “checkbox-hack” experiments.&lt;/p&gt;

&lt;p&gt;The demos are on Github: &lt;a href=&quot;https://github.com/ghinda/css-toggle-switch&quot;&gt;css-toggle-switch&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/css-toggle-switches</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/css-toggle-switches/"/>
    <title>CSS toggle switches</title>
    <updated>2011-10-21T00:00:00+00:00</updated>
    <content type="html">&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Update December 2012&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;The latest version of the toggle switch has full mobile support and easy integration with &lt;a href=&quot;/css-toggle-switch/bootstrap.html&quot;&gt;Twitter Bootstrap&lt;/a&gt; or &lt;a href=&quot;/css-toggle-switch/foundation.html&quot;&gt;ZURB Foundation&lt;/a&gt;.&lt;/p&gt;

  &lt;p&gt;See the latest demos: &lt;a href=&quot;/css-toggle-switch/&quot;&gt;CSS Toggle Switch&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Back in August I saw &lt;a href=&quot;http://www.premiumpixels.com&quot;&gt;Orman Clark&lt;/a&gt;’s latest work at the time, a &lt;a href=&quot;http://www.premiumpixels.com/freebies/sort-switches-toggles-psd/&quot;&gt;set of beautiful toggle switches&lt;/a&gt;, and decided I’d have a go at creating a functional version of them.&lt;/p&gt;

&lt;p&gt;We must start with some meaningful markup, this will ensure our switches are accessible and work everywhere.&lt;/p&gt;

&lt;h2 id=&quot;radio&quot;&gt;Radio&lt;/h2&gt;

&lt;p&gt;The best way to mark up the multi-state switch is to use radio buttons. The first obvious advantage is that it supports an unlimited number of options, and is easily usable by keyboard alone.&lt;/p&gt;

&lt;div class=&quot;language-html 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;nt&quot;&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;legend&amp;gt;&lt;/span&gt;View: &lt;span class=&quot;nt&quot;&gt;&amp;lt;/legend&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;week&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;view&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;radio&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;checked&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;week&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Week&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;month&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;view&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;radio&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;month&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Month&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fieldset&lt;/code&gt; to wrap the switch, along with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;legend&lt;/code&gt; for the switch label, and the radio buttons with a label for each.&lt;/p&gt;

&lt;h3 id=&quot;accessibility&quot;&gt;Accessibility&lt;/h3&gt;

&lt;p&gt;We don’t have to use any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aria-roles&lt;/code&gt; for the switch, because we’re using proper markup, and screen-readers (or other assistive technology) will recognize it as a form control.&lt;/p&gt;

&lt;p&gt;We need to hide the inputs, but we can’t use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;display: none&lt;/code&gt;, because this will also hide them from screen readers, and make them unreachable by keyboard.&lt;/p&gt;

&lt;p&gt;To overcome these issues we hide them by moving them off screen.&lt;/p&gt;

&lt;div class=&quot;language-css 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;nt&quot;&gt;fieldset&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;absolute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;-9999px&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;NVDA will reach the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fieldset&lt;/code&gt;, read the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;legend&lt;/code&gt;, and stop on the first input. Then we can use the up-down/left-right keys to switch between the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;input&lt;/code&gt;s.&lt;/p&gt;

&lt;h3 id=&quot;switch-button&quot;&gt;Switch button&lt;/h3&gt;
&lt;p&gt;“So what that’s empty &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;span&lt;/code&gt;?”, you might ask.
While I’m not really a fan of empty elements used only for styling purposes, we’re forced to use an actual element, rather than a pseudo-element, if we want to be able to use transitions on the switch.&lt;/p&gt;

&lt;p&gt;There is a bug in most web browsers right now, except Firefox 4+, that prevents CSS3 animation and transitions on pseudo-elements. More about &lt;a href=&quot;http://css-tricks.com/13555-transitions-and-animations-on-css-generated-content/&quot;&gt;Transitions and Animations on CSS Generated Content&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;look&quot;&gt;Look&lt;/h3&gt;

&lt;p&gt;We create the background slide rail with an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:after&lt;/code&gt; pseudo-element on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;legend&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-css 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;nt&quot;&gt;legend&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:after&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nl&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;absolute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;50%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;z-index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;50%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#2d3035&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nl&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;box-shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;inset&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;6px&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0px&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.2&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;Then we position the labels next to each other, and create the look of the switch button. I won’t go into to many details regarding the look of the switch, since you’re all pretty familiar with CSS rounded corners, gradients and box-shadows.&lt;/p&gt;

&lt;h3 id=&quot;behavior&quot;&gt;Behavior&lt;/h3&gt;

&lt;p&gt;This is where all the magic happens. We implement the full functionality of the switch only with CSS, by targeting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;span&lt;/code&gt;, from the last &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:checked&lt;/code&gt; input, using the general sibling selector.&lt;/p&gt;

&lt;div class=&quot;language-css 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;nt&quot;&gt;fieldset&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:last-of-type:checked&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;75%&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 switch is now fully functional, but we’re lacking one important feature: a way to style the focused label, this is especially useful for users that are unable to use a mouse.&lt;/p&gt;

&lt;h3 id=&quot;active-label&quot;&gt;Active label&lt;/h3&gt;

&lt;p&gt;To style the active label differently, we target the label following the checked input, using the adjacent sibling selector.&lt;/p&gt;

&lt;div class=&quot;language-css 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;nt&quot;&gt;fieldset&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:checked&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#2d592a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;text-shadow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.5&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 need to provide a way to highlight the focused label, even if the associated input is not checked. We’ll use the same technique we used for the checked item, but instead of using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:checked&lt;/code&gt; pseudo-class, we’ll use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:focus&lt;/code&gt;, and provide an outline for it.&lt;/p&gt;

&lt;div class=&quot;language-css 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;nt&quot;&gt;fieldset&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:focus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;outline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;dotted&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#fff&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 benefits mostly Opera, since it’s the only browser that allows you to reach each option using Tab, and select it by pressing the Enter or Space keys. Other browsers jump to the next fieldset when pressing Tab.&lt;/p&gt;

&lt;p&gt;Every browser, except Chrome, will also focus the label when clicking it. Chrome will only focus it when reached by keyboard.&lt;/p&gt;

&lt;h2 id=&quot;checkbox&quot;&gt;Checkbox&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Update: This approach has been removed from the latest version of the toggle switches, because of accessibility issues.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My next approach was using a checkbox, instead of radio input. This means we can simplify the markup a bit, since we don’t have multiple input elements, like in the radio version.&lt;/p&gt;

&lt;div class=&quot;language-html 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;nt&quot;&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
  View:
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;checkbox&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notice I’m not using the fieldset element any more, but just wrapping the input in a label, and again, than empty span.&lt;/p&gt;

&lt;h3 id=&quot;onoff-labels&quot;&gt;On/Off Labels&lt;/h3&gt;

&lt;p&gt;We can only use the main text in the label, so we have to use generated content to create the “Week” and “Month” labels.&lt;/p&gt;

&lt;div class=&quot;language-html 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;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-on=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Week&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-off=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Month&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To be able to easily reuse the toggle switch, you can see I’m using custom HTML5 attributes for these labels.&lt;/p&gt;

&lt;div class=&quot;language-css 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;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:after&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;relative&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;50%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nl&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data-on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&quot;\a&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data-off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;white-space&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;center&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nl&quot;&gt;column-count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&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 the content property, I use the attr() notation to get the value of the custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data-&lt;/code&gt; attributes, and separate them using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\a&lt;/code&gt; newline character.&lt;/p&gt;

&lt;p&gt;I’m doing that to be able to properly position them. The problem is that, because of the look of the switch, I need to use the :before pseudo-element to create the background of the switch. This leaves me with only one element for both the text labels.&lt;/p&gt;

&lt;p&gt;So, in order to properly position them I use the CSS3 column-count property to split the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:after&lt;/code&gt; element into two columns, and center each label in each of these columns.&lt;/p&gt;

&lt;p&gt;That’s where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\a&lt;/code&gt; character comes in. Using it, I’m pushing the “Off” label to next line, and since it’s a single line, the next column.&lt;/p&gt;

&lt;h3 id=&quot;accessibility-1&quot;&gt;Accessibility&lt;/h3&gt;

&lt;p&gt;NVDA will read the label as “View, checkbox, not checked, Week Month”. But this is only because the latest version of NVDA(2011.2 right now) also reads generated content.
Other screen readers, and especially older versions, don’t read generated content &lt;em&gt;at all&lt;/em&gt;. So the “Week” and “Month” labels won’t be available to screen reader users.&lt;/p&gt;

&lt;p&gt;This is one of the main downsides of this approach.&lt;/p&gt;

&lt;p&gt;The other downside is from a semantic point of view. Checkboxes are just not suitable for for these type of selections, but rather for on/off states.&lt;/p&gt;

&lt;p&gt;Add these to the bigger issue, that, even if using a modern screen reader that can read generated content, the read label just doesn’t make proper sense. Which one is selected? Which one is checked or unchecked?&lt;/p&gt;

&lt;p&gt;Needless to say, these would be impossible to use using a screen-reader. Which brings me to my next approach.&lt;/p&gt;

&lt;h2 id=&quot;checkbox-used-properly&quot;&gt;Checkbox, used properly&lt;/h2&gt;

&lt;p&gt;Since checkboxes should be used for on/off states, I’m using another one of Orman’s great designs as a starting point, this &lt;a href=&quot;http://www.premiumpixels.com/freebies/onoff-switches-and-toggles-psd/&quot;&gt;set of on/off switches&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;markup&quot;&gt;Markup&lt;/h3&gt;

&lt;p&gt;You’ll notice I’m using a structure similar to the one used in the radio version, that allows for more flexibility in CSS.&lt;/p&gt;

&lt;div class=&quot;language-html 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;nt&quot;&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;wireless&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;checkbox&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;wireless&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Wireless:&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;behaviour&quot;&gt;Behaviour&lt;/h3&gt;

&lt;p&gt;When activated, the switch needs to move the toggle button and change the style of the rail. For this, I use the sibling selectors.&lt;/p&gt;

&lt;div class=&quot;language-css 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;c&quot;&gt;/* Move the toggle button */&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:focus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;45px&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;c&quot;&gt;/* Change the style of the rail */&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:checked&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:after&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#a0c66b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;border-color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#87aa5b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nl&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#60783f&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;I’ve used the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;label:after&lt;/code&gt; pseudo-element to generate the rail, like in the radio version, and also included the On/Off text labels in it, since they’re on the same depth.&lt;/p&gt;

&lt;h3 id=&quot;accessibility-2&quot;&gt;Accessibility&lt;/h3&gt;

&lt;p&gt;NVDA will read the switch as “Checkbox, not checked. Wireless. Off, On”. Once reached, it can be controlled (checked/unchecked) using the Space or Enter key.&lt;/p&gt;

&lt;p&gt;Even if you’re using a screen-reader that doesn’t read generated content, the switch still makes sense, because it will read the checkbox as “checked” or “unchecked”.&lt;/p&gt;

&lt;p&gt;It’s usable, but it would be ideal if we could place the label before the input, so that the screen-reader will read it before reaching the checkbox.
But we can’t change the order of the elements, since we need to reach the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;label&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;span&lt;/code&gt; elements using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; and ‘~’ sibling selectors.&lt;/p&gt;

&lt;p&gt;Still, it’s not an absolute must, since many form layouts place the checkbox before the label, and people are probably used to it.&lt;/p&gt;

&lt;h2 id=&quot;internet-explorer&quot;&gt;Internet Explorer&lt;/h2&gt;

&lt;p&gt;The switches work right, without transitions, in IE9. But, as usual, IE8 and bellow will need special treatment. There’s two ways you can deal with this.&lt;/p&gt;

&lt;p&gt;Either use conditional comments, or classes created with conditional comments, to make the input visible again, and provide standard form controls.&lt;/p&gt;

&lt;p&gt;Or, since we don’t really have nothing specific to feature-detect, wrap the switch-specific code in a plain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@media all&lt;/code&gt; media query.
This will make sure &lt;a href=&quot;http://caniuse.com/#feat=css-mediaqueries&quot;&gt;browsers that support media queries&lt;/a&gt; get the proper switch, while browser that don’t, such as IE8 and bellow or older mobile browsers, get the perfectly usable, standard form controls.&lt;/p&gt;

&lt;h2 id=&quot;mobile-support&quot;&gt;Mobile support&lt;/h2&gt;

&lt;p&gt;After some quick testing on mobile browsers (Mobile Safari, Android, S60, Opera Mobile and Mini), the only one that seem to properly support the switches is Opera Mobile.&lt;/p&gt;

&lt;p&gt;The switches look right in all the browsers, but the toggle buttons don’t move when selected, in either the radio or checkbox versions.&lt;/p&gt;

&lt;p&gt;
&lt;del&gt;I&apos;m working on a solution for this, and will follow-up with a new post addressing mobile support for the switches. &lt;/del&gt;
&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’ve added mobile support for the toggle switches, describing the development process in a new article: &lt;a href=&quot;/article/css-toggle-switches-mobile&quot;&gt;Mobile support for the CSS toggle switches&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Any ideas?&lt;/em&gt; You can contribute to the &lt;a href=&quot;https://github.com/ghinda/css-toggle-switch&quot;&gt;css-toggle-switch GitHub repository&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/accessible-html5-media-player</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/accessible-html5-media-player/"/>
    <title>Make your HTML5 media player accessible</title>
    <updated>2010-12-10T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;In my last article regarding HTML5 media, I implemented a customizable, cross-browser video player for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element. This is a good solution for many reasons, including accessibility - HTML5 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;video&amp;gt;&lt;/code&gt; &lt;em&gt;can be&lt;/em&gt; a lot more accessible than plugin-based alternatives, for example in terms of keyboard accessibility out of the box, and easier to customize without the need for a costly IDE.&lt;/p&gt;

&lt;p&gt;But our work does not stop there. The solution I have built so far, like other JavaScript-based widgets, still has a number of accessibility concerns in terms of semantics and discoverability, which could be addressed using the W3C Web Accessibility Initiative’s WAI-ARIA specification.&lt;/p&gt;

&lt;p&gt;In my latest article on Dev.Opera, I’m trying to address such problems with WAI-ARIA, and add some further accessibility enhancements to the player, such as closed-captions and transcript.&lt;/p&gt;

&lt;p&gt;I’m trying to get the best accessible keyboard navigation model possible, that’s why I’m not implementing any custom keyboard shortcuts, combinations, access-keys, or the like. Instead I’m relying on well known, easy to use, tab-based navigation for the player controls. This should make it much easier, especially for people using screen-readers, to find and use the controls.&lt;/p&gt;

&lt;p&gt;For the sliders, I’m using the ARIA slider &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;role&lt;/code&gt;, and some further attributes to better describe the current position.&lt;/p&gt;

&lt;p&gt;To finish up, I’m wrapping the media in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;figure&amp;gt;&lt;/code&gt; element, and pointing to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;figcaption&amp;gt;&lt;/code&gt; element inside it using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aria-describedby&lt;/code&gt; to provide a better description of the media element. I’m not totally sold on this markup approach, but when browsers will expose the new HTML5 elements to screen-readers better, we probably won’t need the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aria-describedby&lt;/code&gt; attribute any longer.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read the complete article on &lt;a href=&quot;http://dev.opera.com/&quot;&gt;Dev.Opera&lt;/a&gt;: &lt;a href=&quot;https://web.archive.org/web/20200712114530/https://dev.opera.com/articles/more-accessible-html5-video-player/&quot;&gt;A more accessible HTML5 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;video&amp;gt;&lt;/code&gt; player&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;source&quot;&gt;Source&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/ghinda/acornmediaplayer/&quot;&gt;acornmediaplayer GitHub repository&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/acornmediaplayer/&quot;&gt;Acorn Media Player project page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <id>https://www.ghinda.net/article/customizable-html5-media-player</id>
    <link type="text/html" rel="alternate" href="https://www.ghinda.net/article/customizable-html5-media-player/"/>
    <title>Build your own customizable HTML5 media player</title>
    <updated>2010-09-10T00:00:00+00:00</updated>
    <content type="html">&lt;p&gt;If you’ve been following the latest in web browser tech, you’ve surely noticed the widespread support for HTML5 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;video&amp;gt;&lt;/code&gt; by now. Even IE9 is supporting it!&lt;/p&gt;

&lt;p&gt;There are many advantages of having video embedded natively in the browser (covered in the article &lt;a href=&quot;https://web.archive.org/web/20200303130354/https://dev.opera.com/articles/introduction-html5-video/&quot;&gt;Introduction to HTML5 video&lt;/a&gt; by Bruce Lawson), so many developers are trying to use it as soon as possible. There are a couple of barriers to this that remain, most notably the problem of which codecs are supported in each browser, with a disagreement between Opera/Firefox and IE/Safari. That might not be a problem for much longer though, with Google recently releasing the VP8 codec, and the WebM project coming into existence. Opera, Firefox, Chrome and IE9 all have support in final builds, developer builds, or at least support announced for this format, and Flash will be able to play VP8. This means that we will soon be able to create a single version of the video that will play in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element in most browsers, and the Flash Player in those that don’t support WebM natively.&lt;/p&gt;

&lt;p&gt;The other major barrier to consider is building up a custom HTML5 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;video&amp;gt;&lt;/code&gt; player — this is where a Flash-only solution currently has an advantage, with the powerful Flash IDE providing an easy interface with which to create a customized video player component. If we want to write a customized player for the HTML5 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element we need to code all the HTML5, CSS3, JavaScript, and any other open standards we want to use to build a player!&lt;/p&gt;

&lt;h2 id=&quot;tutorial&quot;&gt;Tutorial&lt;/h2&gt;
&lt;p&gt;I’ve recently wrote an article for &lt;a href=&quot;http://dev.opera.com/&quot;&gt;Dev.Opera&lt;/a&gt; addressing the custom media controls issue, and explaining step-by-step how you could create your own HTML5 media player “shell”, using jQuery, the slider component from jQuery UI and some CSS3 wizardry.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read the article on Dev.Opera, here: &lt;a href=&quot;https://web.archive.org/web/20200107003522/https://dev.opera.com/articles/custom-html5-video-player-with-css3-and-jquery/&quot;&gt;Building a custom HTML5 video player with CSS3 and jQuery&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;open-source&quot;&gt;Open Source&lt;/h2&gt;
&lt;p&gt;What started out more as a proof-of-concept video player ended up being a usable jQuery plugin.&lt;/p&gt;

&lt;p&gt;Therefore, I’m constantly trying to improve it, and looking for suggestions. So feel free contribute code or report issues on the &lt;a href=&quot;https://github.com/ghinda/acornmediaplayer/&quot;&gt;acornmediaplayer GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also check out the &lt;a href=&quot;/acornmediaplayer/&quot;&gt;Acorn Media Player&lt;/a&gt; project page for some demos and documentation on how to use the plugin.&lt;/p&gt;
</content>
  </entry>
  

</feed>
