Eli Grey

Fonts in Processing.js

I recently implemented fully-featured cross-(HTML5-supporting)-browser loadFont() and text() functions in Processing.js. This implementation does not suffer from the limitation of the old implementation that only supported SVG fonts and writing text from already-installed fonts only worked recent Mozilla-based browsers. I also revamped the entire library, fixing a few hundred errors, changing and optimizing many Processing method implementations, and getting rid of all of the implied global variable leaks. Included is an image gallery of the same Processing program being run using Processing and Processing.js. The one showing only the outputted image was saved directly from a canvas element. You can also try out fonts in Processing.js at this demo page. The demo page does not use the same font as in the screenshot but it is similar. If your browser does not support @font-face CSS rules but does support the canvas text API, your system default monospace font will be used instead.

processing-js-loadFont-test-150x150 processing-loadFont-test-150x150

Another E4X DOM library

I just made another E4X DOM library, but this one is intended to implement the optional features in the ECMA-357 standard that are not implemented by Mozilla in JavaScript. The library is named e4x.js due to, for the most part, it only implementing stuff already specified in E4X. The only difference between the standard and my implementation is that the XML.xpath(xpathExpression) method also supports numeric, string, and boolean result types.

E4X DOM toolkit

I have created a small JavaScript toolkit named e4x-dom.js for making it easy to manipulate the DOM with E4X.

The following methods are implemented on XML objects by e4x-dom.js:

node()
Returns the HTML node representation of the XML.
over(element or selector)
Either overwrites element or every element matched by the CSS selector with node().
overId(id)
Same as over(document.getElementById(id)) but also preserves the the id of the element being overwritten in the element replacing it.
fill(element or selector)
Removes every child node of element or every element matched by the CSS selector. Then node() is appended to all of the emptied elements.
fillId(id)
Same as fill(document.getElementById(id))
appendTo(element or selector)
Appends node() to element or every element matched by the CSS selector.
appendToId(id)
Same as appendTo(document.getElementById(id)).
insertBefore(element or selector)
Inserts node() before element or every element matched by the CSS selector.
insertBeforeId(id)
Same as insertBefore(document.getElementById(id)).
insertAfter(element or selector)
Inserts node() after element or every element matched by the CSS selector.
insertAfterId(id)
Same as insertAfter(document.getElementById(id)).

The following are examples of using the toolkit:

var img = <img
 src={prompt("Enter an image URI")}
 alt={prompt("Describe the image")}
 id="foobar"
/>;
img.appendTo(document.body);
 
<h1>The image was <em>removed</em>.</em>.overId("foobar");
<![CDATA[And then this text node filled the header]]>.fill("#foobar");
 
// the CDATA isn't itself put into the document but the data inside it is escaped so it
// works in HTML and XHTML
<h1><![CDATA[<html> in here is <escaped>]]></h1>.insertBefore(document.body.firstChild);
 
// if you just want to create an element quickly, do xml.node()
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"/>.node(); // SVG node
<div/>.node(); // div node
 
// DOM methods are forwarded to .node()[method]()
<canvas/>.getContext("2d");
<foo bar="baz"/>.getAttribute("bar") === "baz"; // same as getting .@bar
 
// mass-modifications with CSS selectors
<strong>Absolute links are <em>not</em> allowed</strong>
 .over('a[href^="http://"], a[href^="https://"], a[href^="//"]');
 
if (user.hasEditPrivileges) {
 // wikipedia-style "put an edit link at the start of each section"
 <a href={"/edit?page=" + page.id}>[edit]</a>.insertAfter('h2');
}
 
// <![CDATA[]]> nodes directly accessed are converted to text nodes:
 
<![CDATA[
 This is a text node.
 <html> is escaped inside it.
]]>.appendTo("#some-element");

JSandbox 0.2

I have recently released JSandbox version 0.2. JSandbox is a JavaScript sandboxing library. Version 0.2 is, for the most part, a complete re-write. It introduces many new features, such as load (for loading external scripts) and exec (faster than eval but no return value). There is now an additional fixed-position arguments API along with the version 0.1 API.

mumbl

mumbl is a JavaScript library that makes it easy to play music and create playlists on web pages.

Demo

A demo is included with mumbl but if you dont want to download it, there is also an online demo.

Please note that mumbl is not the player in the demo. mumbl is the back-end and the demo is just an example of using mumbl.

Supported Platforms

Supported Platforms

  • HTML5
    • Firefox 3.5+
    • Google Chrome 4+
  • SoundManager 2 (version 2.95b.20100323+)
    • Firefox 1.5+
    • Opera 10+
    • Google Chrome 1+
  • Songbird 1.4+

API

API documentation can be found in the readme.

Roadmap

  • 0.1.1
    • Better error handling.
    • loaderror event.
  • A while after version 0.1 is released
    • Create a simple library that makes all MP3, OGG, WAV, etc. links be able to be played using mumbl.
    • Make the demo mumbl-powered music player (it will be renamed “mumblr”) portable and reusable.
    • Remove jQuery dependency from mumblr.
    • Make the track title display scroll (maybe using a <marquee>) when it overflows.
  • Version 0.2
    • Full compatability with every major browser.
  • The distant future (maybe version 1.0)
    • Create a simplified flash audio back-end for mumbl that integrates much more nicely and has a smaller file size than SoundManager2.

RetargetMouseScroll

Yesterday I made a simple JavaScript micro-library named RetargetMouseScroll that provides a simple API to retarget/redirect mouse scroll events. I named it this because RedirectMouseScroll sounded weird. At first glance it seems pretty useless but there are some cool things you can do with the library which are listed in the examples section of this post.

Demo

The test suite functions as a great demo.

Usage

RetargetMouseScroll(
    element         :Node,    // default: document
    targetWindow    :Window,  // default: window
    preventDefault  :Boolean, // default: true
    scrollMultiplier:Number   // default: 1.0
)

RetargetMouseScroll returns an object containing a restore method. Calling the method restores the default scrolling.

Examples

  • RetargetMouseScroll(myElement, myFrame) – Per-element mouse scroll retargetting to a frame
  • RetargetMouseScroll(document, window, true, 0.5) – Slow down scrolling
  • RetargetMouseScroll(document, window, true, -1) – Invert scrolling
  • RetargetMouseScroll(document, window, true, 2) – Speed up scrolling

More advanced example using a popup:

var win = window.open("/", "example", "w=" + (screen.availWidth / 3.5)
                                      + ",h=" + (screen.availHeight / 3.5)
                                      + ",scrollbars=yes,resize=yes");
win.addEventListener("DOMContentLoaded", function() {
    var retargetting = RetargetMouseScroll(document, win);
    win.onunload = function () {
        retargetting.restore();
    };
}, false);

In the previous example, all mouse scrolling on the main document is retargetted to the popup until it is closed.

GTranslatifier

I have created a very simple Jetpack feature called GTranslatifier that adds a Google Translate icon to Firefox’s status bar for easy access to Google Translate services. Upon clicking the icon, one of the following things happen. If no text is selected in the tab currently being viewed, the page in the browser tab currently being viewed is translated into your native language. If the icon was left-clicked, the translated page will be loaded in the same tab. If the icon was middle-clicked or right-clicked the translated page is loaded in a new tab. If there is text selected in the current tab being viewed, a new tab is opened which has a translation of the selected text. If you are on a page translated using Google Translate, clicking the button will return you to the original page.

Array methods for XML lists

I have created an open source library that implements every array method for E4X XML lists in JavaScript named e4x-array-methods.js. The methods output XML as opposed to arrays to make the output directly usable with other XML. To get the array representation of an XML list, use slice. This returns XML when used to slice out ranges from XML but if no arguments are passed or a third argument is specified which is equivalent to true, it will convert an XML list to an array instead. For example, xmllist.slice(3, 5) returns an XML list and xmllist.slice(3, 5, true) returns an array.

Download

You can download e4x-array-methods.js at it’s github repository. If you wish to minify the library yourself, make sure that your minification tool supports the E4X used in this library. Rhino-based minifiers fail, throwing syntax errors, and /packer/ errantly minifies all of the public methods names preceded by .function::.

Example

The following example demonstrate the usefulness of having array methods for XML lists. If you want to try out the example in a JavaScript shell, make sure XML.prettyPrinting is set to false, which removes any unnecessary whitespace from xml.toString() and xml.toXMLString().

XML.prettyPrinting = false; // for simplifying the comparisons below
 
var foo = <></>; // XMLList literal
foo.push(<n>0</n>, 1, 5, 3, 2, 6, 4);
foo.toXMLString() === "<n>0</n><n>1</n><n>5</n><n>3</n><n>2</n><n>6</n><n>4</n>";
foo.sort(function(a, b) {
    return a - b;
}).toXMLString() === "<n>0</n><n>1</n><n>2</n><n>3</n><n>4</n><n>5</n><n>6</n>";
foo.filter(function(x) { // filter out integers less then 3
    if (!(x < 3))
        return true;
}).toXMLString() === "<n>3</n><n>4</n><n>5</n><n>6</n>";
foo.slice(2, 5).toXMLString() === "<n>2</n><n>3</n><n>4</n>";
foo.splice(2, 1, <n>9</n>, <n>8</n>).toXMLString() === "<n>2</n>";
foo.slice(2, 5).toXMLString() === "<n>3</n><n>9</n><n>8</n>";
foo.pop().toXMLString() === "<n>6</n>";
foo.shift().toXMLString() === "<n>0</n>";
foo.shift().toXMLString() === "<n>1</n>";
foo.unshift(<bar/>);
foo.toXMLString() === "<bar/><n>3</n><n>9</n><n>8</n><n>4</n><n>5</n>";
foo.map(parseFloat).forEach(function(n){ print(n) }) // prints NaN, 3, 9, 8, 4, 5
foo.some(function(x) { // some are greater than 5
    if (x > 5) return true;
}) === true;
foo.every(function(x) { // all are numbers
    if (typeof x == "number") return true
}) === false;