01. October 2015

Tonic

During my browse session at work this morning I came across this post. If I understand correctly the easiest way to describe Tonic is as a plugin that let’s you run Node.js in a browser.

The reason why I write about this today is because of the newley released feature of embedding it on your page. This feature can be accessed in two ways. Via HTML markup or by initializing it programatically. Lets take a look at some examples.

When you have access to the document markup we would make it work like this:

<script src="https://embed.tonicdev.com" data-element-id="daily-element"></script>

<!-- anywhere else on your page -->
<div id="daily-element">
var request = require('request');
request('http://www.google.com', function (error, response, body) {
    console.log(body) // Show the HTML for the Google homepage.
});
</div>

If this code runs Tonic it will dropdown an element showing the log output.

If you do not have access to the document markup you can trigger it from Javascript like this:


var scriptTag = document.createElement("script"),
    head = document.querySelector("head"),
    dailyElement = document.createElement('div');
scriptTag.src = "https://embed.tonicdev.com";
dailyElement.id = "daily-element";
head.appendChild( scriptTag );

document.body.appendChild( dailyElement );

var notebook = Tonic.createNotebook({
    // the parent element for the new notebook
    element: document.querySelector("#daily-element"),

    // specify the source of the notebook
    source: "\"hello world\"",

    // optionally, set the notebook to be read-only
    readOnly: false,

    // optionally, provide a callback to be called when the notebook has finished loading
    onLoad: function(){}
});

On of the things I’m still missing is the ability to run ES2015. I hope that the support for that will come very soon. This weekend I will be trying to include this within this website so you will be able to run the examples that I post right there in the browser.

28. September 2015

Clipboard.js

After writing this blog for a few days now I noticed that the bar of two libraries a day is hard to do when you have a day job next to it. Because I want to give each library a fair shot, I will be reducing it to one library a day on workdays so I can work on updates for the website as well.

Clipboard.js (GitHub: zenorocha/clipboard.js, License: MIT, npm: clipboard, bower: clipboard )

During my daily browse I came across Clipboard.js which is a library to put given content to the users clipboard from Javascript. Normally we are used to implementing this behavior using Flash or some bloated framework. Luckley now there is Clipboard.js which is an 2kb implementation of “Copy to clipboard”.

To use it we need to require it first. If you are using Browersify or Webpack then use:

import * as Clipboard from 'clipboard';

// Or the old way
var Clipboard = require('clipboard');

When including it in your html do it like this:

<script src="dist/clipboard.min.js"></script>

Now we can instantiate it using a DOM selector. For instance

new Clipboard('.btn');

Internally, it needs to fetch all elements that match the selector and attach event listeners for each one. But what if you have hundreds of matches? Then this operation can consume a lot of memory. Because of this it uses event delegation which replaces multiple event listeners with just a single listener.

The most common usage of this library would be to copy the text value of an input field or textarea. This is how:

<!-- Target -->
<input id="foo" value="https://github.com/zenorocha/clipboard.js.git">

<!-- Trigger -->
<button class="btn" data-clipboard-target="#foo">
    <img src="assets/clippy.svg" alt="Copy to clipboard">
</button>

It also has the ability to cut to clipboard. You would do this by attaching the data-clipboard-action attribute to the trigger element like this:

<!-- Target -->
<textarea id="bar">Mussum ipsum cacilds...</textarea>

<!-- Trigger -->
<button class="btn" data-clipboard-action="cut" data-clipboard-target="#bar">
    Cut to clipboard
</button>

When you find yourself in a situation where you would like to show some feedback to the user or capture what has been selected after a copy/cut operation, you can make use of the success and error events that are being sent. You would use that like this:

var clipboard = new Clipboard('.btn');

clipboard.on('success', function(e) {
    console.info('Action:', e.action);
    console.info('Text:', e.text);
    console.info('Trigger:', e.trigger);

    e.clearSelection();
});

clipboard.on('error', function(e) {
    console.error('Action:', e.action);
    console.error('Trigger:', e.trigger);
});

The browser support on this project superised me, it relies on both Selection and execCommand APIs. The second one is supported in the following browsers.

Chrome logo Firefox logo Internet Explorer logo Opera logo Safari logo
42+ ✔ 41+ ✔ 9+ ✔ 29+ ✔ Nope ✘

Although copy/cut operations with execCommand aren’t supported in Safari yet (including mobile), it gracefully degrades, because Selection is supported.

This means you could show a tooltip saying Copied! when success event is called and Press Ctrl+C to copy when error event is called because the text is already selected.

28. September 2015

Rune.js and queryl

Rune.js (GitHub: runemadsen/rune.js, License: MIT )

Rune.js is a library for programming graphic design systems with SVG. It has a fluent drawing API, an unobtrusive scene graph, and a bunch of features designed specifically for graphic designers, such as: native support for color conversion, grid systems, typography, pixel iteration and an expanding set of computational geometry helpers. What peaked my interest is that it uses a virtual-dom under the hood.

If you’re not familiar with the virtual-dom I suggest you take a break to take a look at that first.

Unfortunately I could not find any npm or bower install instructions, so I am hoping that the developer will add that soon.

Rune.js has all basic shapes in the API.

r.line(0, 0, 100, 100);

r.rect(0, 0, 100, 50);

r.ellipse(0, 0, 100, 50);

r.circle(0, 0, 100);

r.triangle(0, 0, 100, 0, 100, 100);

And for more complex shapes it fluent API makes drawing with SVG very readable and familiar.

r.polygon(0, 0).lineTo(100, 0).lineTo(100, 100).lineTo(0, 100);

r.path(0, 0).lineTo(100, 0).curveTo(100, 100, 0, 100, 0, 0);

Since this library is packed with features and concepts, I will only give you the tip of the iceberg right now. If you want to know more, consult the amazing documentation.

queryl

queryl (GitHub: issuetrackapp/queryl, License: MIT, npm: queryl)

queryl is a query language to preform complex object searches. The purpose of this “language” is to allow the developer to build very complex queries to e.g. search a collection of objects, to validate objects before you dump it in a db or even to make assertions in tests.

queryl comes with a very simple API. queryl.match is the main entry at this point this will always return a boolean and expects an object to match. For example:

queryl.match({
  $contain: {
    foo: 1
  }
}, {
  foo: [ 1, 2, 3 ]
});
> true

This is just a very basic example of what it can do. The full API docs shows the entire power of this “language”.

I can see this working very well for matching and parsing certain objects like the ones you would receive from, for instance, the Google spreadsheet API.

28. September 2015

Levi

Levi (GitHub: cshum/levi, License: MIT, npm: levi)

Levi is a streaming full-text search for Node.js and browsers which used LevelDB for storage. The search implementation is done by using TF-IDF and cosine similarity, and it’s provided with configurable text processing pipelines: Tokenizer, Porter Stemmer and Stopwords filter.

Levi is built on LevelUP which is a fast, asynchronous, transactional storage interface. By default it uses LevelDB on Node.js, when in running in the browser it uses IndexedDB. Levi supports with a variety of LevelDOWN compatible backends.

In addition, Levi provides relevancy scoring for live changing data using TF-ICF - a TF-IDF approximation based on existing corpus. Such scoring matches are comparably close to TF-IDF when existing corpus is sufficiently large, with significantly better performance O(N) instead of O(N^2).

Let’s take a look at the API. To get started, we need to create a new Levi instance. We do that like this:

import levi from 'levi';

const lv = levi('db')
.use(levi.tokenizer())
.use(levi.stemmer())
.use(levi.stopword());

The text processing pipeline levi.tokenizer(), levi.stemmer(), levi.stopword() are required for indexing. These are exposed as ginga plugins so that they can be swapped for different language configurations.

Now that we have an instance we can use it to talk to the API like this:

lv.put('a', 'Lorem Ipsum is simply dummy text.', err => {
    // ...
 });

// object fields as value
lv.put('b', {
  id: 'b',
  title: 'Lorem Ipsum',
  body: 'Dummy text of the printing and typesetting industry.'
}, (err) => {
    //...
});

Or retrieve it like:

lv.get('b', res => {
    // res here;
});

To actually search we need to use Levi’s main interface which would be searchStream. We use that like this.

lv.searchStream('lorem ipsum').toArray(function (results) { ... }) // highland method

lv.searchStream('lorem ipsum', {
  fields: { title: 10, '*': 1 } // title field boost. '*' means any field
}).pipe(...)

lv.searchStream('lorem ipusm', {
  fields: { title: 1 }, // title only
}).pipe(...)

// ltgt
lv.searchStream('lorem ipusm', {
  gt: '!posts!',
  lt: '!posts!~'
}).pipe(...)

// document as query
lv.searchStream({
  title: 'Lorem Ipsum',
  body: 'Dummy text of the printing and typesetting industry.'
}).pipe(...)

Because I do not fully understand everything that is going on here, I need to refer you to the extensive documentation on the GitHub page. The reason I still mention this library is that I understand from the explanation a colleague gave me that this library will have a significant impact on the speed of your text search.

27. September 2015

XRegExp and Gun

XRegExp (GitHub: slevithan/xregexp, License: MIT, npm: xregexp)

XRegExp is a regex utility belt that provides augmented and extensible JavaScript regular expressions. It comes with a new modern syntax and flags beyond what browsers support natively. Furthermore it comes with tools to make client-side grepping and string parsing easier. This will free you from worrying about cross-browser inconsistencies and problems like manually manipulating lastIndex or slicing strings when tokenizing.

Because XRegExp compiles to native RegExp objects it’s just as fast native regular expressions. The only penalty would be the compiling the pattern the first time.

Here are two example that the developer posted on Github.

 // Using named capture and flag x (free-spacing and line comments)
const date = XRegExp('(?<year>  [0-9]{4} ) -?  # year  \n\
                    (?<month> [0-9]{2} ) -?  # month \n\
                    (?<day>   [0-9]{2} )     # day   ', 'x');

// XRegExp.exec gives you named backreferences on the match result
let match = XRegExp.exec('2015-02-22', date);
match.year; // -> '2015'

// You can also pass forward and return specific backreferences
const html = '<a href="http://daily-javascript.com/">Daily Javascript</a>' +
           '<a href="http://www.google.com/">Google</a>';
XRegExp.matchChain(html, [
    {regex: /<a href="([^"]+)">/i, backref: 1},
    {regex: XRegExp('(?i)^https?://(?<domain>[^/?#]+)'), backref: 'domain'}
]); // -> ['daily-javascript.com', 'www.google.com']

// Merge strings and regexes into a single pattern, safely rewriting backreferences
XRegExp.union(['a+b*c', /(dog)\1/, /(cat)\1/], 'i');
// -> /a\+b\*c|(dog)\1|(cat)\2/i

You can also enabled some add-ons such as unicode support and then you can do this:

// Test the Unicode category L (Letter)
const unicodeWord = XRegExp('^\\pL+$');
unicodeWord.test('Русский'); // -> true
unicodeWord.test('日本語'); // -> true
unicodeWord.test('العربية'); // -> true

// Test some Unicode scripts
XRegExp('^\\p{Hiragana}+$').test('ひらがな'); // -> true
XRegExp('^[\\p{Latin}\\p{Common}]+$').test('Über Café.'); // -> true

When installed via npm all add-ons are always available to use this in the browser. You must include to addons like this:

<script src="src/xregexp.js"></script>
<script src="src/addons/unicode-base.js"></script> <!-- This must be include before the other addons -->
<script src="src/addons/unicode-categories.js"></script>
<script src="src/addons/unicode-scripts.js"></script>

GUN

GUN (GitHub: amark/gun, License: Apache 2.0, npm: gun)

Mark Nadal sent in GUN which is an open source alternative to Firebase. Mark tells me that he got tired of dealing with DevOps/SysAdmin work to keep MongoDB running in production. It was making him very unhappy. So he took it upon him self to start a DBaaS like Firebase, but one that he could run on his own servers.

It looks very promising and very easy to setup. Right now it doesn’t have an efficient storage engine yet so it stores all the data in JSON. Let’s look at some examples.

To make a connection we must require it and make a reference to it.

var Gun = require('gun');
var ref = Gun('http://gunjs.herokuapp.com/gun').get('daily/javascript');

Now we are able to put and get data this way.


// Putting data
gun.put({
  username: "RamonGebben",
  name: "Ramon Gebben",
  email: "daily-javascript@ra-ge.net"
}).key('usernames/RamonGebben');

// Getting data
gun.get('usernames/RamonGebben').val((user) => console.log(user.name));

You can also extend GUN by reacting on events like this:

Gun.on('opt').event((gun, opt) => {
    /* Your module here! */
});

If you take a look at what the developers have planned to introduce, you will notice this is something to keep your eye on.

I would not recommend using this in production just yet, because it feels very young, but for small prototype for which you don’t want to bother setting up an entire infrastructure to load and save this could be a good choice.