thingsinjars

  • 17 Dec 2011

    Latest 140byt.es offerings

    Long-term readers (a.k.a. my Mum) might remember my JS1K efforts last year and the subsequent discussion of Extreme JS Minification. The same kind of mindset that inspired qfox to create that competition also inspired Jed to create 140 Bytes. As with JS1K, the clue is in the name, you have the length of a tweet – 140 characters – to create something cool or clever in JS.

    I won't go into any more detail here, if you're interested, you've either already heard about it or would do better clicking around the 140bytes site or reading the comments on the master gist.

    My entries

    Following last week's draggable file script, I started messing about with making it small enough to qualify and, predictably, got hooked. Here are four I made last weekend.

    The scripts below are directly embedded from GitHub and are the minified, highly compressed versions. I recommend clicking through to the original gist for each of them where you'l find a file called annotated.js which talks through the code.

    Create a draggable file on-the-fly

    The code from last week shrunk down.

    Detect Doctype

    There's no simple way to access the current document's doctype as a string. There is already a document.doctype object so you might expect (or, at least I'd expect) you could do a .toString() or .asDoctypeString or something like that. Nope. Nothing. You have to manually recreate it as a concatenation of properties. A quick discussion with kirbysayshi and mmarcon came up with a few alternative methods (Max's is quite devious, actually) before eventually culminating in this.

    Chainify and Propertize

    This began as a very minimal implementation of Lea Verou's Chainvas. The idea is to enhance various constructors (Element, Node, etc.) so that each method returns the original object. This means that you can then chain (jQuery-style) any built-in function. Each constructor is also enhanced with a .prop function which allows property setting in a similarly chainable manner. For a better description, read through the Chainvas site.

    Javascript, Geek

  • 9 Dec 2011

    jQuery Detach Scrollbars Plugin

    tl;dr: I made a plugin: jQueryDetach Scrollbars Plugin download [Zip – 1.4KB]

    A design I recently worked on called for a scrollbar which only took up half the height of the area it was scrolling. Now, I'm not going to get into a discussion about scroll behaviour, accepted standards or user expectations - fascinating though that would be - instead, Here's a jquery plugin.

    The existing jQuery plugins I found that dealt with scrollbars created their own custom, themable bars. jScrollpane, for instance, gives you complete control over pretty much every aspect of the look and feel of the scrollbar. I figured this was too much for my needs, all I wanted was to be able to anchor the scrollbar to a given corner and change its height. The resulting plugin does just that. It even handles OS X Lion's disappearing scrollbars natively, too.

    Usage

    Note: This currently only works on vertical scrolling and doesn't have a good jQuery setup and teardown. If I needed it more than once on a page, I'd have written it a bit more robustly so it could be used more than once. Maybe I'll leave that task as an exercise for the enthusiastic reader.

    If you call the plugin on an element with a scrollbar (i.e. the element has height and contains content that overflows), it will duplicate the scrollbar using the standard browser scrollbar and get rid of the original one. In fact, in its default configuration, there's pretty much no difference between using the plugin and not using it.

    $(element).detachScrollbar();

    It becomes more useful, however, when you pass in a couple of options. This example will move the scrollbar to the left of the content area:

    $(element).detachScrollbar({anchor : 'topleft'});

    You could leave the scrollbar on the right but shrink it downwards:

    $(element).detachScrollbar({anchor : 'bottomright', height : '50%'});

    The only behaviour of a standard scrollable area that isn't replicated by default is being able to use the mouse wheel to scroll while over the content area. If you want this behaviour (and you probably do), all you need to do is include the jQuery Mousewheel plugin in your page. This script will recognise if it's available and enable the functionality.

    How it works

    The script creates a container div around the original scrollable content and sets that to overflow:hidden while setting the original area to height:auto. This means that the original scrollbar disappears. It then creates another invisible div the same height as the original content and wraps that in a div with overflow-y:scroll, this creates a scrollbar that looks exactly like the original one. Add in some clever event trickery to tie the scroll position of one to the scroll position of the other and we're done. We've replicated the original functionality but can now control the styles applied to the scrollbar completely separately from the original content. This means we can position it to the left or above, maybe add a 90° CSS transform and have it look like a horizontal scrollbar, anything you like.

    The plugin also incorporates “Cowboy” Ben Alman's scrollbar width plugin to make sure we're matching dimensions on whatever platform this is used on.

    The options that can be passed in are:

    internal: true / false (default: true)
    autoposition: true / false (default: true)
    anchor: 'topleft' / 'topright' / 'bottomleft' / 'bottomright' (default: 'topright')
    height: Any CSS length (default '100%')

    Advanced usage

    The autoposition option allows you to decide whether to let the plugin handle the layout (which you probably do for most cases) or whether you want to specify everything yourself using the provided classes as styling hooks.

    The other option, internal, determines the DOM structure. Specifically, it says whether everything is contained within the one element or whether the scrollbar is separate. Specifying internal: false would allow you to put the scrollbar anywhere on your page. You could have all scrollbars set as position: fixed along the top of the page if you wanted. Not sure why you would but you could.

    Example and Download

    jQueryDetach Scrollbars Plugin

    jquery.detach-scrollbars.js

    Geek, Javascript

  • 8 Dec 2011

    Create a draggable file on-the-fly with JS

    Here's a useful little code snippet if you're building a web application. It's a simple way of making the boundary between web-browser and platform a bit smaller. It allows you to create a file (text, html, whatever) in in your page which the user can drag onto their desktop (if their browser supports the dragstart event and dataTransfer methods).

    document.getElementById('downloadElement').addEventListener("dragstart", function (e) {
      e.dataTransfer.setData("DownloadURL", "text/html:filename.html:data:image/png;base64," + btoa(fileContent));
    });
    

    A description of the code:

    • attach an event listener to the draggable element you specify (downloadElement)
    • when you start to drag it (dragstart),
    • it creates a dataTransfer object (with the type DownloadURL)
    • and sets the content of that to be whatever you pass it (fileContent)
    • It uses btoa() to encode the string data as a base64-encoded string.
    • When you combine this with the MIME-type (text/html),
    • you can create a file with the specified name (filename.html) when the user releases the drag in their local file system.
    • The fake MIME-type (image/png) is there as part of the object data to convince the browser this is a binary file (which it is, even though it's not an image).

    Note: The element this is attached to (downloadElement above) should either be draggable by default (image, link or text selection) or have the draggable attribute set otherwise this'll do nothing.

    Credit goes to Paul Kinlan for using this in Appmator which is where I first saw this done this way. He actually uses it alongside some extremely clever JS zip-file creation stuff, too, it's definitely worth digging through the source there.

    You can find out more about the drag events on the MDN.

    Guides, Javascript, Development, Geek

  • 3 Dec 2011

    Simple and clever beats clever

    When messing about with another little game idea, I found myself retyping (for the umpteenth time) the same little bit of value bounding code I use a lot:

    var x = Math.max(0, Math.min(y, 1))
    Which basically translates to:
    "Set x to be the value of y as long as it's between 0 and 1. 
    If not, set it to 
      0 if it's smaller or 
      1 if it's larger."

    Of course, 0 and 1 don't need to be the boundaries, I'm just using them for convenience.

    Instead of continuing with the game, I decided to take a little tangent and see if there was any way I could rewrite this so that the syntax was a bit more obvious. I'd like to be able to use syntax like:

    x = [0 < y < 1]

    to mean the same. Written exactly as above, JS will try and evaluate left-to-right, changing the comparisons to booleans. The statement would become

    y = 0.5
    
    x = [0 < y < 1]
    x = [0 < 0.5 < 1]
    x = [true < 1]
    x = [false]

    Similarly:

    y = -0.5
    
    x = [0 < y < 1]
    x = [0 < -0.5 < 1]
    x = [false < 1]
    x = [true]

    My first thought was to be clever about it, I wanted to try and figure out how to partially evaluate the expression and take the different outcomes to figure out the logic required. If '0 < y' was false, then y is less than zero therefore outside our bounds, the return value should then be 0. If the first part is true and the second is false then we know the value is higher than our bounds....etc and so on.

    This proved to be a logical dead-end as there was no good way to partially evaluate the statements. Not without preparsing the JS, anyway. Which leads me onto the second attempt...

    Preparsing the JS

    The next attack on the problem was the idea of reading the JS as a string, shuffling it around quickly and silently (not like a ninja, more like a speedy librarian in slippers) and put it back where it was.

    So I began to look at ways to recreate that. I remembered from many, many years ago (two, actually) Alex Sexton creating the genius abomination that is goto.js and how that used some kind of preparsing. A quick skim through the code later and I ended up on James Padolsey's site looking at parseScripts.js.

    In the end, all I needed to do was include parseScripts (which is a generalised form of the code I ended up using for the whitehat SEO question from last month) and provide a new parser function and script type.

    parseScripts(/:bound/, function(unparsed) {
     return unparsed.replace(/\[(\d)\s*<\s*(\w)\s*<\s*(\d)\]/g, "Math.max($1, Math.min($2, $3))");
    })

    I'm not saying parseScript isn't clever because it most definitely is but I am saying it's simple. There's not always a need to branch off into deep technical investigations of partial evaluation when a simple search-and-replace does the job better and faster.

    For someone always going on about bringing simplicity and pragmatism into development, you'd think I'd have gotten there faster...

    Bounded Range

    The final bounded range syntax code is available here (hint: view the console). It's silly but it was a fun half-hour.

    Improvements?

    Do you know of any better way to do this? Is there a clever parsing trick we can use instead? Is there, indeed, any language which has this syntax?

    Guides, Geek, Javascript

  • newer posts
  • older posts

Categories

Toys, Guides, Opinion, Geek, Non-geek, Development, Design, CSS, JS, Open-source Ideas, Cartoons, Photos

Shop

Colourful clothes for colourful kids

I'm currently reading

Projects

  • Awsm Street – Kid's clothing
  • Stickture
  • Explanating
  • Open Source Snacks
  • My life in sans-serif
  • My life in monospace
Simon Madine (thingsinjars)

@thingsinjars.com

Hi, I’m Simon Madine and I make music, write books and code.

I’m the Engineering Lead for komment.

© 2025 Simon Madine