<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[syntaxiom]]></title><description><![CDATA[syntaxiom]]></description><link>https://skeate.github.io</link><image><url>http://i.imgur.com/cJWZ7vI.jpg</url><title>syntaxiom</title><link>https://skeate.github.io</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 13 Feb 2017 02:17:54 GMT</lastBuildDate><atom:link href="https://skeate.github.io/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Seque: What It Is & How It Works]]></title><description><![CDATA[<div class="sect2">
<h3 id="_what_even_is_this">What even is this?</h3>
<div class="paragraph">
<p><a href="https://github.com/skeate/seque">Seque</a> is a library of chainable control flow functions&#8201;&#8212;&#8201;in other words, it allows you to write code like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">[1, 2, 3]
  .if(useEvens)
  .filter(x =&gt; x % 2 === 0)
  .else()
  .filter(x =&gt; x % 2 === 1)
  .endif()
  .forEach(doSomething)
  // ...</code></pre>
</div>
</div>
<div class="paragraph">
<p>So far there are three control flow functions:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>if(&lt;boolean&gt;)</code> &#8230;&#8203; [<code>else()</code> &#8230;&#8203;] <code>endif()</code></p>
</li>
<li>
<p><code>while(&lt;Function&gt;)</code> &#8230;&#8203; <code>endwhile()</code> (continuously applies functions as long as the function returns true)</p>
</li>
<li>
<p><code>loop(&lt;number&gt;)</code> &#8230;&#8203; <code>endloop()</code> (applies functions &lt;number&gt; times)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>How does it work? First, a quick recap of what&#8217;s really going on in a chain:</p>
</div>
<div class="paragraph">
<p>
<p data-height="147" data-theme-id="16793" data-slug-hash="yNEKwg" data-default-tab="result" data-user="skeate" class='codepen'>See the Pen <a href='http://codepen.io/skeate/pen/yNEKwg/'>Basic Chain</a> by Jonathan Skeate (<a href='http://codepen.io/skeate'>@skeate</a>) on <a href='http://codepen.io'>CodePen</a>.</p>
</p>
</div>
<div class="paragraph">
<p>Each step returns a value, which the next function in the chain is then invoked upon. Chained functions have no knowledge of each other.</p>
</div>
</div>
<div class="sect2">
<h3 id="_wrappers_galore">Wrappers Galore</h3>
<div class="paragraph">
<p>To get around this, Seque uses a <code>wrap</code> function. Essentially, it returns an object which will intercept any function you try to call on it. It stashes these away until some endpoint (e.g. <code>endif()</code>), and then executes a callback with the entire list of functions that had been "called", along with their arguments. The callback can then decide to apply them or not apply them as it sees fit.</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Technically, it will only intercept <em>any</em> function if the platform has ES6 <code>Proxy</code> support. More on that in a bit.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>All of Seque&#8217;s control flow methods use this <code>wrap</code> method, with differing callbacks. <code>if</code> 's callback, for example, splits the chain where the <code>else</code> call is (if it exists), and then applies the stack before or after the else based on the value it was passed.</p>
</div>
<div class="paragraph">
<p>An attempt at illustrating this point (press arrow buttons at the top to change slides):</p>
</div>
<div class="paragraph">
<p>
<p data-height="268" data-theme-id="16793" data-slug-hash="VLdXJq" data-default-tab="result" data-user="skeate" class='codepen'>See the Pen <a href='http://codepen.io/skeate/pen/VLdXJq/'>Seque chain</a> by Jonathan Skeate (<a href='http://codepen.io/skeate'>@skeate</a>) on <a href='http://codepen.io'>CodePen</a>.</p>
<script async src="//assets.codepen.io/assets/embed/ei.js"></script>
</p>
</div>
</div>
<div class="sect2">
<h3 id="_caveat">Caveat</h3>
<div class="paragraph">
<p>Without ES6&#8217;s new <code>Proxy</code> feature, doing this in a completely seamless way is (as far as I can tell) impossible. Without it, the <code>wrap</code> function can only track those functions it has some way of knowing about. By default, it will track any functions available on the original object it was called upon&#8201;&#8212;&#8201;if an array, it&#8217;ll watch for calls to <code>map</code> or <code>forEach</code>, for example. But if some link in the chain returns a different type, then you could have problems if you try to call a function that didn&#8217;t exist (at least by name) on the original object.</p>
</div>
<div class="paragraph">
<p>For example, something like this will work:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">['a', 'b', 'c', ...]
  .if(someCondition)
  .join('')
  .slice(1)
  .endif()</code></pre>
</div>
</div>
<div class="paragraph">
<p>Because <code>slice</code> is available on both arrays and strings. However, this will fail:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">['a', 'b', 'c', ...]
  .if(someCondition)
  .join('')
  .toUpperCase()
  .endif()</code></pre>
</div>
</div>
<div class="paragraph">
<p>Because <code>toUpperCase()</code> does <strong>not</strong> exist on arrays. The Seque-wrapped version of the original array will not know that it should be looking for some function named <code>toUpperCase</code>, and thus when it encounters that in the chain, it will say <code>undefined is not a function</code> (or something along those lines).</p>
</div>
<div class="paragraph">
<p>There is a way around this issue: pass an array of the extra function names as a second argument to the control flow function. Thus, the above failing example would become</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">['a', 'b', 'c', ...]
  .if(someCondition, ['toUpperCase'])
  .join('')
  .toUpperCase()
  .endif()</code></pre>
</div>
</div>
<div class="paragraph">
<p>Admittedly, this is a bit gross, but I can think of no other way around a lack of proper <code>Proxy</code> support, at least in the code itself. One <em>possible</em> way would be to make a Seque preprocessor, so the array of function names would be generated for you. Of course, if what you&#8217;re chaining always returns the same type (e.g. arrays or promises), then this is unnecessary. Speaking of promises&#8230;&#8203;</p>
</div>
</div>
<div class="sect2">
<h3 id="_chaining_asynchrony_with_promises">Chaining Asynchrony with Promises</h3>
<div class="paragraph">
<p>One thing you might have noticed is that these all resolve immediately. That <em>can</em> be useful with a chain of promises (e.g. if you want to do this one asynchronous step conditionally, but you know the condition ahead of time). But what if you want to branch or loop based on the resolved value of a promise? Seque includes some <code>Async</code> versions of its functions for this purpose.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">$.get('/api/posts')
  .ifAsync(posts =&gt; posts.length === 1)
  .then(handleSinglePost)
  .else()
  .then(handlePostList)
  .endif()</code></pre>
</div>
</div>
<div class="paragraph">
<p>It takes a function which will get passed the resolved value of the promise immediately preceding the <code>ifAsync</code>.</p>
</div>
<div class="paragraph">
<p>There is also a similar <code>whileAsync</code>, but its function will get the last resolved value in the enclosed chain on each iteration. For example, imagine you are dealing with some awful API that has a "nextPage" endpoint which returns page info (including a <code>pageNumber</code> property), and no way to get many pages at once. You want to load up and process 50 pages. You could do something like</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">$.get('/api/page')
  .whileAsync(page =&gt; {
    processPage(page);
    return page.pageNumber !== 50;
  })
  .then(() =&gt; $.get('/api/nextPage'))
  .endWhile();</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_next">Next</h3>
<div class="paragraph">
<p>Have ideas for other functions? Find bugs with the current ones? Please <a href="https://github.com/skeate/seque/issues">post an issue to Github</a>, and I&#8217;ll see what I can do!</p>
</div>
</div>]]></description><link>https://skeate.github.io/2015/07/17/Seque-What-It-Is-and-How-It-Works.html</link><guid isPermaLink="true">https://skeate.github.io/2015/07/17/Seque-What-It-Is-and-How-It-Works.html</guid><category><![CDATA[seque]]></category><category><![CDATA[ javascript]]></category><dc:creator><![CDATA[Jonathan Skeate]]></dc:creator><pubDate>Fri, 17 Jul 2015 00:00:00 GMT</pubDate></item><item><title><![CDATA[Wrapping Text to Fit Shaped Containers with CSS]]></title><description><![CDATA[<div class="paragraph lead">
<p>With CSS, <a href="http://nicolasgallagher.com/pure-css-gui-icons/demo/#non">you
can make all kinds of shapes</a>, but if you try to put any text inside
even a simple non-rectangular shape, you can run into problems. The text
will not wrap to fit inside the container.</p>
</div>
<div class="paragraph">
<p>
<p data-height="268" data-theme-id="16793" data-slug-hash="raOVjY" data-default-tab="result" data-user="skeate" class='codepen'>See the Pen <a href='http://codepen.io/skeate/pen/raOVjY/'>raOVjY</a> by Jonathan Skeate (<a href='http://codepen.io/skeate'>@skeate</a>) on <a href='http://codepen.io'>CodePen</a>.</p>
</p>
</div>
<div class="paragraph">
<p>However, recently I discovered the
<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/shape-outside">CSS
property <code>shape-outside</code></a>. Browser support isn’t great (currently only
Webkit-based browsers), but there is a
<a href="https://github.com/adobe-webplatform/css-shapes-polyfill">polyfill</a>. It
allows you to wrap text around a floated element, as if it had a shape
you specify. Perhaps the most common example is a circle:</p>
</div>
<div class="paragraph">
<p>
<p data-height="268" data-theme-id="16793" data-slug-hash="qEOdrM" data-default-tab="result" data-user="skeate" class='codepen'>See the Pen <a href='http://codepen.io/skeate/pen/qEOdrM/'>qEOdrM</a> by Jonathan Skeate (<a href='http://codepen.io/skeate'>@skeate</a>) on <a href='http://codepen.io'>CodePen</a>.</p>
</p>
</div>
<div class="paragraph">
<p>Gorgeous. But how does this help with the original problem? This handles
wrapping outside a shape. There’s no <code>shape-inside</code>
(<a href="http://dev.w3.org/csswg/css-shapes-2/#shape-inside-property">yet</a>).</p>
</div>
<div class="paragraph">
<p>Until that arrives, we can still manage this. The trick lies in
inverting the <code>shape-outside</code>. In other words, make the shape a polygon,
with two points at (0,0) and (0, 100%), and the rest following the
contour of the desired shape. It’s not perfect (for circles at least)
but it’s good enough, since text would never be perfect anyway.</p>
</div>
<div class="paragraph">
<p>One caveat: this only works with floated elements. We can float the
<code>::before</code> pseudoelement just fine, but if we try to float the
<code>::after</code>, it doesn’t look right. See the example below — you can hover
over the circle to color the pseudoelements, to make it more obvious
what’s happening.</p>
</div>
<div class="paragraph">
<p>
<p data-height="268" data-theme-id="16793" data-slug-hash="gbarrN" data-default-tab="result" data-user="skeate" class='codepen'>See the Pen <a href='http://codepen.io/skeate/pen/gbarrN/'>gbarrN</a> by Jonathan Skeate (<a href='http://codepen.io/skeate'>@skeate</a>) on <a href='http://codepen.io'>CodePen</a>.</p>
</p>
</div>
<div class="paragraph">
<p>Unfortunately the only way I’ve found around it so far is
double-wrapping the circle element, so you can use both <code>::before</code> elements.
Forgiveable, I suppose, but I would like a single-element solution.</p>
</div>
<div class="paragraph">
<p>
<p data-height="268" data-theme-id="16793" data-slug-hash="YPyqWd" data-default-tab="result" data-user="skeate" class='codepen'>See the Pen <a href='http://codepen.io/skeate/pen/YPyqWd/'>YPyqWd</a> by Jonathan Skeate (<a href='http://codepen.io/skeate'>@skeate</a>) on <a href='http://codepen.io'>CodePen</a>.</p>
</p>
</div>
<div class="paragraph">
<p>Here’s an SCSS mixin to handle it all:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scss" data-lang="scss">@mixin circle($radius){
  width: $radius*2;
  height: $radius*2;
  border-radius: $radius;
  &amp;::before{
    content: '';
    height: 100%;
    width: 50%;
    float: left;
    shape-outside: polygon(
      0 0, 100% 0, 60% 4%, 40% 10%, 20% 20%, 10% 28.2%, 5% 34.4%, 0 50%,
      5% 65.6%, 10% 71.8%, 20% 80%, 40% 90%, 60% 96%, 100% 100%, 0 100%
    );
  }
  &gt; span::before{
    content: '';
    height: 100%;
    width: 50%;
    float: right;
    shape-outside: polygon(
      100% 0, 0 0, 40% 4%, 60% 10%, 80% 20%, 90% 28.2%, 95% 34.4%, 100% 50%,
      95% 65.6%, 90% 71.8%, 80% 80%, 60% 90%, 40% 96%, 0 100%, 100% 100%
    );
  }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>
<script async src="//assets.codepen.io/assets/embed/ei.js"></script>
</p>
</div>]]></description><link>https://skeate.github.io/2015/07/13/Wrapping-Text-to-Fit-Shaped-Containers-with-CSS.html</link><guid isPermaLink="true">https://skeate.github.io/2015/07/13/Wrapping-Text-to-Fit-Shaped-Containers-with-CSS.html</guid><category><![CDATA[css]]></category><category><![CDATA[ css3]]></category><category><![CDATA[ demo]]></category><dc:creator><![CDATA[Jonathan Skeate]]></dc:creator><pubDate>Mon, 13 Jul 2015 00:00:00 GMT</pubDate></item></channel></rss>