Custom selectors

Categories:Blog

I got some time to tinker on the framework today, and I've finally done something I've been wanting to do for ages, which is the ability to programatically create and add your own selectors. But what does that mean?

Overview

Currently, if you want to select items or elements based on properties that aren't covered by the built-in selectors i.e. name, :symbol, [x>50], you would need to over-select items, then use a callback to filter the collection.

The following example selects all symbol elements, then filters them using a callback:

function isBlurred(element)
{
    // code for determining whether element is blurred or not
    return state;
}
var collection = $(':symbol').filter(isBlurred);

While that's a perfectly valid way to select elements, rather than selecting then filtering, it would be inherently more flexible to simply define a new selector which itself could be referenced, combined and reused within CSS expressions, for example, choosing to select all blurred stage elements using an expression such as:

':blurred'

Well, it is now possible to register your own custom :pseudo and [attribute] selectors that determine whether an element should be included in a collection via an external callback which you supply.

:pseudo selectors

In the case of the above example, we would register a custom pseudo selector called :blurred to a function that determines if the element is blurred or not:

function blurred(element)
{
    function callback(filter)
    {
        return filter.name === 'blurFilter' && filter.enabled && filter.strength > 0;
    }
    return element.filters && element.filters.some(callback);
}
Selectors.element.register(':blurred', blurred);

Note the colon (:) starting the first parameter of register(). This indicates that the custom selector is a pseudo-selector. Callbacks for psuedo selectors are expected to return a true/false value, indicating the condition either is, or isn't.

You then simply use the selector as follows:

var collection = $(':blurred').select();

The result is, as below:

[attribute] selectors

Often, rather than a yes/no selection, you want the flexibility to select elements based on values at run time, such as an element's  layer name, or perhaps a Textfield's font (did you know that there is no top-level .font property?)

This is where custom attribute selectors come in, which are specified using square braces ([]) and allow us to supply values directly within the CSS expression itself.

The following example examines the element's first textRuns object, and returns the font name:

function font(element)
{
    return element.textRuns ? element.textRuns[0].textAttrs.face : null;
}
Selectors.element.register('[font]', font);

Note that in this case, because a comparison needs to be made, a value, not a Boolean, is returned so that the Selector engine can compare the value within the supplied expression.

Again, the selector is simply used within an expression:

var collection = $('[font=Arial]').select();

The results of which, are below:

In conclusion

As you can see, custom selectors provide a simple and flexible method to choose which elements to select on stage, and have an advantage over filters that they can be easily combined with other selectors simply by concatenating:

var collection = $('[font=Arial][x>30]:selected').select();

And don't forget, you can also write custom selectors for Library items too!

function isAsset(item)
{
    return item.name.indexOf('asset') != -1;
}
Selectors.item.register(':asset', isAsset);

$$(':asset:exported').select();

All this new functionality is available in the repo now.

Comments are closed.