Make stylus more nodey

Today I wanted to break some stylus files out into their own module, and I wanted to be able to require a stylus module in the same way I would require a node module.

I tryed:

npm i my-styles-module

And then:

@require my my-styles-module

Which of course didn’t work, but there is a way.

As explained here, you can tell stylus other directories to look in for imports and requires, if it can’t find it in its working directory.

I’m using gulp to build my stylus, so all that was required was to add:

...
.pipe(stylus({
include: ['../node_modules']
})
...

And now stylus works just like node.

How to check if something is an array.

Every once in a while, I see someone talking about how to check if a thing is an array. I’ve been through a few stages of how to write an array detection utility myself.

Stage 1; “instanceof is the best!”

I’ll just check if object instanceof Array! Woohoo!

And then I came across this: http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/

Huh, arrays from other frames are not instances of the Array constructor in this frame. I guess that makes sense, since it isn’t an instance of this frames Array.

Stage 2; “instanceof is the worst!”

Righto, guess I’ll use the solution provided.

One problem:

The suggested solution relies on checking a string that gets spit out from Object.prototype.toString.call().

That’s great, except for this:

Object.prototype.toString.call(Array.prototype);
// -> [object Array]

Cool so now your array detection function will detect Array.prototype as an array, which it isn’t.

http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4

Shudup spec, Array.prototype isn’t an array, that would be fucking stupid. Anyway Array.prototype.instanceof Array returns false, as you would expect, because it literally isn’t an instance of Array. If you make your own constructor, you wouldn’t expect it’s prototype to be an instance of it, would you?

Really, if you’re checking that something is a thing based on some random string you pulled from a function on a different constructor… you’ve gotta expect problems.

Stage 3; “Array-detecting libraries are stupid”.

There is a huge amount of noise on the internet around this topic, and it is all noise. You will never make a perfect one-size-fits-all .isArray, Even Array.isArray() won’t work for array-like objects that people intend to be used in place of arrays. In the end, to quote greenday…

It doesn’t even matter.

Think about what you are actually trying to check for. If you have an API that takes an array, just use instanceof Array. Who cares if it doesn’t work across frames? Thats a rare case, and if you need to talk across frames, you will probably know that you’re doing it; Convert the array to a local instance before you give it to your API. Sure it won’t work with that Hipster new library that gives you SuperArrays, but that isn’t important, because the new hotness will come and go. Your library should support JavaScript.

Don’t be afraid to use instanceof, for arrays or any other object. It is an extremely robust way of ensuring an object will look and behave how you expect. It isn’t perfect, but it’s how JavaScript was meant to be used.

The takeaway:

  • instanceof Array is NOT harmful.
  • array detection libraries are stupid, think about what you actually need to check, and check for that.

Samsung Series 9 Touchpad Fixes

Simply put, Samsung software is shit. The touch pad hardware is excellent, and even the drivers for it are great, but the software that ships to configure it is extremely limited.

Have you ever wished you could do crazy things like 3-finger-touch right click? Or maybe use the touch-pad while pressing keys? Probably not right? That all sounds WAYYY too hard and crazy for a user, or at least that’s what Samsung thinks.

Luckily you can change pretty much everything, the Elan driver is really feature-rich and configurable, if you know what to do.

So, to convert your touch-pad from usable to awesome:

1. Open regedit

  • windows+r
  • type ‘regedit’, press enter, 
  • Accept the prompt

2. Go to the honey pot of touchpad settings

  • HKEY_CURRENT_USER
  • Software
  • Elantech
  • Smartpad

3. CHANGE ALL THE THINGS!

Want three finger right-click?

  • change Tap_Three_Finger to 1

Want two finger middle-click?

  • change Tap_Two_Finger to 2

(You can obviously swap 2 finger and 3 finger by swapping their values if you’re weird)

Want to be able to use the touch-pad while typing?

  • Change DisableWhenType_Enable to 0

Just got windows 8.1 and lost the ability to have normal scrolling?

  • Change SC_Reverse_Enable to 0

As you can see there’s a whole ton of settings that can be tweaked. I’m yet to play with everything I’ll want to tweak.

 

Gedi, an absurdly powerful model API

logo

Firstly, what’s gedi?

git: https://github.com/gaffa-tape/gedi
npm: https://npmjs.org/package/gedi

Gedi is model API wrapper. It Allows you to get and set, and remove to/from an object, and bind to changes that occur due to sets/removes.

Simple usage:

    // Set up the models data
    var model = new Gedi({
        thing: 2,
        lifeforms:{
            dogs:[
                {
                    name: "scruffy",
                    age:8
                },
                {
                    name: "spot",
                    age:4
                }
            ],
            users:[
                {
                    name: "bob",
                    age: 20
                },
                {
                    name: "john",
                    age:45
                }
            ]
        }
    });

    // get
    model.get('[thing]'); // --> 2

    // set
    model.set('[thing]', 5);

    // get after set
    model.get('[thing]'); // --> 5

    // bind to [thing]
    model.bind('[thing]', function(event){
        // this callback is called when [thing] changes.
        // event.getValue() returns the value of [thing]
    });
    

You can throw a parent path on the end of get/set/etc.. to make all bindings relative to it.

    model.get('[dogs]'); // --> undefined

    model.get('[lifeforms/dogs]'); // --> Array of dogs.

    // here, [dogs] will be relative to [lifeforms]
    model.get('[dogs]', '[lifeforms]'); // --> Array of dogs.
    

Why square braces?

Because gedi is more powerfull than just an object watcher.

you can pull data out via expressions…

    model.get('(last [lifeforms/dogs]).name'); // --> "spot"
    

And even bind callbacks to expressions…

    model.bind('(last [lifeforms/dogs]).name', function(event){
        // this callback is called when [lifeforms/dogs] changes.
        // event.getValue() returns the value of (last [lifeforms/dogs]).name
    });
    

However there was one thing I’d always thought would be awesome, and i’ve recently made some pretty big changes to how gedi works under the covers to allow.

    // Set the last item in [lifeforms/dogs] to a different dog
    model.set('(last [lifeforms/dogs])', {name: "ellie", age: 2});
    

Gedi can now keep track of paths throughout the execution of an expression, and perform useful opperations using the resulting path.

This is pretty exciting to me, expecially for how it can be used in gaffa.

You can also perform opperations on the result of a filter/map/slice/concat/etc.. eg.

(fyi, the syntax for an anonymous function in gedi is {param1 param2 paramN functionBody})

remove all items in an array that match an expression.

    model.remove('(filter [dogs] {dog (> dog.age 7)})', '[lifeforms]');
    

set properties on all items across multiple arrays that match an expression. (TO RIDICULOUS, AND BEYOND!)

    model.set('(map (filter (concat [dogs] [users]) {item (> item.age 5)}) {item item.label})', 'old!', '[lifeforms]');
    

And of course, any changes made using expressions cause model events to fire at the right paths.

How to do cross-domain async iFrame POST’s the easy/robust way

iFrames, Everyone loves them.

Haha! OK seriously now.

Every seasoned web developer has come up against the need to POST data asynchronously  to a different domain that does not accept cross-domain headers, and the usual solution is an iFrame to post into.

The code is usually something like this:

var myForm = crel('form', {'class':'braintreeForm', method : 'post', target:'myDodgyIframe'});
var myFrame = crel('iframe', {name:'myDodgyIframe'});

And then some code to make this disgusting pile of crap work:

var firstLoad;

myFrame.addEventListener('load', function(event){
    // the load event that gets fired on insertion
    if(!firstLoad){
        firstLoad = true;
        return;
    }

    var result;

    // the actual load event, probably.
    try{
        result = JSON.parse(event.target.contentDocument.documentElement.textContent);
    }catch(jsonError){
        //handle the error somehow
    }

    // use result if it parsed well.
});

An issue that you may encounter is that, if you are inserting the iFrame into the DOM arbitrarily, and not necessarily submitting it, the load event triggers every time it is inserted, not just once.

A solution to this came to me today:

myFrame.addEventListener('load', function(event){
    if(event.target.contentWindow.location.toString() === 'about:blank'){
        // ignorable load, return.
        return;
    }

    // useful load, use.
    var result;

    // the actual load event, probably.
    try{
        result = JSON.parse(event.target.contentDocument.documentElement.textContent);
    }catch(jsonError){
        //handle the error somehow
    }

    // use result if it parsed well.
    
    //cleanup
    event.target.contentWindow.location = 'about:blank';
});

This ignores any useless load events the frame might fire, without dodgy statefull ignore-the-first-load code.

The Blackberry Z10, So much right, so much wrong…

I’ve been using a blackberry Z10 as my main phone for about 2 weeks now, having used the Dev Alpha B for a few months before that, and I’ve pretty much made up my mind about it. My previous phone was a Galaxy Nexus, so that’s what I’ll be comparing it to mostly.

Hardware:

The good:

  • The button-less face is excellent. I’ve already forgotten how to unlock other phones.
  • Nice high res screen.
  • Decent performance (only ever really noticeable when playing 3D games, which run well).
  • Decent battery life, I get a day’s heavy use out of it without issue.
  • The back cover is nice and grippy, you can stick it on a dash and it won’t slide around (if you drive carefully).
  • The camera is excellent.

The bad:

  • The screen is kinda small.. Not iPhone small, that would be ridiculous, but it’s smaller than my GNex, even though the phone its self isn’t any smaller.
  • Looks like an iPhone. While this will help BB steal iPhone users, it makes me slightly embarrassed to be seen with it. I don’t see how they could not get sued by Apple, it actually is very similar, unlike previous phones that were a ‘copy’. It’s quite boring to look at.
  • The volume buttons feel cheap, and I don’t really know what the middle button is for.
  • The plugs are on the side. This is sometimes a good thing, but mostly it looks weird.
  • It has pulg*s*. It doesn’t need a HDMI out, the phone isn’t being pushed as a media device, so why dedicate an ugly port to it?
  • The ports are positioned weirdly, mostly on the body of the phone, but partly into the back cover.

Software:

the good:

  • The browser. It is the best. Ever. Literally nothing else is as good. Chome for desktop? Excellent, still not as good as the BB browser. I’m not kidding, it is better than Chrome, for both viewing and developing web applications.
  • Cascades (or whatever) is awesome. Once you swipe things around on this phone, you can’t help but accidentally swipe other phones, usually resulting in Google now. Something came in to the phone? Slide up, hold, slide to the side if you want a preview of the notification.
  • App-specific notifications. OMG they are awesome. Something happened in an app? Red icon. Something happened in an app in a folder? Red icon. Give the engineer who came up with this a raise, I love it.
  • the Hub is great, no matter what happened, it can always be found in the hub.
  • The app switcher is really fluid for switching between 2 apps.
  • The word flicking keyboard is a good idea.

the bad:

  • The apps. There aren’t enough. This should seem like an obvious, unavoidable issue, as with any new phone, but this phone should be an exception. Blackberry does not leverage their browser enough. Why isn’t there a way to turn any website into a chrome-less app?
  • Maps. They suck. Practically unusable. The app lags all the time. Why the hell would they not just use Google maps?
  • The phone has crashed probably 30 times since I’ve had it. At least once a day, but I have a feeling its probably more often than I realise.
  • Apps cannot run in the background. This is a big issue as it stops apps like llama (for android) working, which is a big issue because the phone is never in the right profile.
  • The phone is never in the right profile (like I just said). It is constantly going off when you don’t want it to, and never ringing when you need it to. This is because I don’t manually change the profile, because I am a human and any ‘smart’ phone should do this for me.
  • The keyboard needs the long-press-for-symbols feature that android has. Things like question marks shouldn’t be difficult to input.
  • It has a shit lock-screen. The only option is a password. Patterns people!

Development:

the good:

  • The browser, as mentioned, is amazing. The development experience is not just bearable, but actually BETTER than Chrome for desktop! The profile tab has better info than Chrome. Apps run fast, every feature you could want is available.
  • Native development: who cares, this is 2013.

the bad:

  • Java. Seriously? you need Java to create a web-app for this phone? Why? BB really needs to improve the tooling around turning web-apps into BB apps.

In summary, I really like some of the ideas that went into this phone, but I don’t think I can live with it. The few apps it does have are either crippled by the lack of OS support, or are just not very good. An example: Google talk lets you have only 1 account, and it notifies you of messages, even when you are using another device to converse with your contact. There is no Google latitude.

I realise that some will say “Well just make the missing apps yourself!” which is true, I could, and probably should do this, but I just don’t have the time.

Should you buy it?

If you are a previous BB user you will probably love it.

If you are a previous iPhone user you will probably hate it for the wrong reasons

If you are a previous Android user you will probably love some of the features, then get annoyed with the lack of applications.

Personally, I’m torn, If i go back to android, I will miss some of the amazingly good features like swipe to  unlock, swipe to notifications, and swipe to do pretty much anything. I will miss the excellent browser. That said the maps, lack of apps, Google talk, and frequent crashes are really getting to me..

Basically…. I lied; I’m not sure yet.

A BB/Android blend would be the perfect phone.

Deploying a Web app in 14 days, No HTML.

Recently, at Sidelab, we developed and deployed signforms.com, an application for signing documents online, in 14 days. The application runs on a node.js back-end, using amazon web services. One interesting thing about the application is that it uses effectively no HTML.

There are a few static html files for the lander site, but once logged in, there is only one .html file. Other than script tags to load the application for the very first time, the file looks like this:

</head>
<body>
</body>
</html>

After that, no HTML is ever sent.

Don’t believe me? Sign up (its free currently), log in, then view source. You will see nothing but JSON.

Signforms uses no html

A typical page in SignForms.com

WAT!?

The front end of SignForms is build using an opensource framework called Gaffa. Once the application has been loaded, all navigation is achieved via requests for JSON resources.

Oh, so it’s client-side templating.

No, there are no templates, ever. When we work on SignForms, we never write HTML, or HAML, or any kind of ML. We write JavaScript ‘pages’ that are made up of ‘view items’ such as containers, textboxes, buttons etc. For cache-ability we serialize these pages to JSON for the application to consume.

In your browser, Gaffa takes the serialized page, inflates it into objects, then generates the DOM required to display the page, and adds all other functionality such as event handlers, page load, and autosave behaviours that are required.

Why?

I’m not a fan of HTML, it’s not something humans should write. One thing that people usually seem to forget is that HTML is a sibling to XML. The majority of people would prefer not to write XML, but have no issues writing HTML. This seems strange to me. The other thing people seem to forget is that HTML is a serialization format for DOM, it is verbose and inflexible.

One commonly seen flow of data for a web application is as follows:

Developer:

  • Write ‘Views’ in HTML
  • Add magic strings to tell the server where to put more strings

Server

  • Scan massive string, stringify data and concatenate the extra strings to the original string
  • Send massive string across the wire
  • Don’t cache it because it will change next time.

Client

  • Parse massive string
  • Correct any invalid HTML, take a best guess as to what it was supposed to be
  • Convert strings into DOM
  • Render the DOM

The way Gaffa handles navigation is different:

Developer:

  • Write code
  • File watcher auto-serializes to JSON

Server:

  • Serve JSON Page, cache for next time.
  • Serve DATA.

Client:

  • Parse JSON into ‘viewItems’.
  • Apply Data to ‘viewItems’.
  • render DOM (Or Canvas, or webGL, or google map markers, or any other logical view).

There are a few big advantages:

  • Only one HTML page is ever sent, once, and it’s tiny (2KB uncompressed)
  • Developers write code, not an XML derivative.
  • Application pages are cached indefinitely, and are tiny (17 KB uncompressed and unminified for a feature rich page)
  • The server only serves data, reducing load.
  • Page-weight is microscopic. (<0.5 MB per page for everything, including all images, css, and data)
  • Pages render stupid-fast (~1s for a complicated, data-bound page).

Gaffa achieves this by creating a declarative programming abstraction for the UI. If you want to display a textbox, and bind it’s value to the model, you would create a textbox viewItem:

var myTextbox = new textbox();

myTextbox.value.binding = '[myValue]';

Other views can bind to the same value in the model:

var myLabel = new label();
myLabel.text.binding = '[myValue]';

And the data can be manipulated before displaying it:

myLabel.text.binding = '(join " " "hello person, your value is" [myValue] "which is" [myValue].length "characters long")';

Then you add the viewItems to gaffa:

gaffa.views.add([myTextbox, myLabel]);

And you’re done.

Because viewItems are rendered as DOM, you can use CSS to style them as you normally would, and end up with a fast, feature rich web application in a very short period of time.

As to be expected from my previous post, this application forgoes the usual “Don’t think, include” librarys such as jQuery, bootstrap, etc, and instead uses small components that do exactly the job required.

A few libraries/technologies used:

JS:

CSS: