Selectors

Categories:Elements

Overview

Summary

CSS-style expressions used with xJSFL Selector functions to filter or match a subset of elements within a larger set (such as stage elements or library items).

Contents

Concept

Identifying elements on stage, or items from within the library using code alone can be a fairly involved task, requiring the developer to loop over elements, compare properties, etc., etc. Before you know it, you've lots of code to do something which feels like it should be quite simple, in this case, grab all unsmoothed bitmaps in the "assets/game/" folder:

var arrOut = [];
var arrIn  = fl.getDocumentDOM().library.items;
for each(var item in arrIn)
{
    if
    (
        item.name.indexOf('/assets/game/') == 0 && 
        item.itemType == 'bitmap' && 
        item.allowSmoothing == false
    )
    {
        arrOut.push(item);        
    }
}

Luckily, xJSFL greatly simplifies this task by borrowing techniques from CSS and defining its own selector syntax, whereby a simple set of English keywords (the selectors) are combined to create expressions to quickly and simply identify elements for modification, without the need complex coding.

For example, the expression that would be functionally equivilent to the logic in the above code looks like this:

'/assets/game/*:bitmap[allowSmoothing=false]'

Usage

In order to make the leap from expressions to elements, you'll use Selector functions.

Selector functions are the xJSFL entry-point to convert the English-language expression syntax into the code which does the actual processing to return a set of elements. All Selector functions return a Collection instance appropriate to selection type.

The JSFL for a typical selection to return a subset of library items might look like the following:

var collection = $$('/assets/game/*:bitmap[allowSmoothing=false]');

The $$ syntax is the method name of the ItemSelector function, and first argument is the selector expression used to identify the items in the library.

Once you have called a selector function with an expression, the elements that were selected (in this case, all unsmoothed bitmaps in the assets/games/folder) will be available for you to modify with xJSFL or JSFL code.

Currently there are 2 main Selector functions, and 2 main Collection types:

The Collections that are returned are essentially Arrays on steroids - each with a set of built-in methods that can manipulate the items within that collection in ways appropriate to the typical JSFL developer.

For a table that lists all selectors and for which selector functions they are avlid for, see the Selectors Table at the end of this page.

The anatomy of selection

Grammar

Selectors are the DNA of selection and come in many different flavours, each of which converts to JSFL that compares or analyses properties, positions, relationships and so on, to identify (or select) items of interest.

Simple selectors

Simple selectors analyse a single property or attribute of an item, for example:

$$(':bitmap')                 // a type selector: selects any bitmaps items in the entire library
$$('[allowSmoothing=false]')  // an attribute selector: selects any items with the property "allowSmoothing" set to false

Both this and the Selector function pages will go into more detail about each of the various selector types.

Note that most selectors are case-sensitive, but some (such as names) aren't.

Complex selectors

Simple selectors can be combined into complex selectors, simply by concatenating them:

$$(':bitmap[allowSmoothing=false]')  // a type selector and an attribute selector

This allows you to be far more specific about which items you want to select and modify, in the above case, only bitmaps which have smoothing set to false;.

Grouping

Finally, selectors can be grouped to identify a variety of disparate conditions by separating the various expressions with commas, for example:

$$(':graphic, :movieclip')

This expression would return an ItemCollection containing references to all graphic and movieclip items in the library.

Syntax

Selectors vary in their syntax, but the following list outlines the various syntaxes supported over the whole range of selectors:

name
/librarypath
:type
:pseudo
.Class
.package

[attribute] [attribute=value] [attribute!=value]
[attribute^=value] [attribute$=value] [attribute*=value] [attribute!=value]
[attribute>value] [attribute<value] [attribute>=value] [attribute<=value] :combination(selector)

Wildcards and ranges are also supported for some selectors:

* (wildcards)
{min|max} (ranges)

Pattern-matching

Wildcards: *

Unlike the CSS specification, the asterisk character is not used as a universal selector, but as a wildcard within a selector string to mean "any character or sequence of characters". This allows you to do such things as specify a folder and all its descendents, or any class with a common name, for example:

$$('/assets/game/*')          // any items under the path assets/game/
$$('ui.*Button*')             // any items from the package "ui" with the word "Button" in their linkage class name
Ranges: {min|max}

Ranges allow you identify multiple items based on a minimum and maximum value. You can use a range anywhere it would be appropriate for the values within the curly braces to be swapped out, for example:

$('Item_{1|10}')              // Any elements named "Item_1" or "Item_01" to "Item_100"
$('[x={-100|100}]')           // Any elements with their x property between -100 and 100
$$('/assets/Folder {1|5}/*]') // Any items in "/assets/" folders "Folder 1" to "Folder 5"

Note that both min and max numeric values will match any padded string values, so 1 is equivilent to "1", "01", "001", etc., etc., and you may only use one range per selector.

Core selectors

The following section lists selectors common to all Selector functions. Each of the individual Selector functions will have their own additional types, specific to the context of the domain they work in - for example, the Item Selector function has :children.

Property selectors

name

The name selector matches the specified name of an element or item. In the case of library Items, this will be the name as seen in the UI, rather than the name attribute (which for library items is actually its full path).

Wildcards and ranges can be used with name selectors.

The following example matches any elements on stage whose name starts with the word Item:

$('Item*');
:type

The type selector matches the type of elements as defined by the current context; in the case of the Element Selector function this will be its element types and in the case of Item Selector it will be its item types.

The following example returns all movieclip items from the folder /assets/:

$$('/assets/*:movieclip');
[attribute]

The attribute selector matches elements' attribute name and optionally none, all or a part of their values.

Wildcards and ranges can be used only for attribute values.

For all types, the following syntax flavours are valid:

'[attribute]'        // The element has the particular attribute
'[attribute=value]'  // The element's attribute is equal to the supplied value
'[attribute!=value]' // The element's attribute is not equal to the supplied value

For string types, the following syntax flavours are valid:

'[attribute*=value]' // The element's attribute contains the supplied value
'[attribute^=value]' // The element's attribute starts with the supplied value
'[attribute$=value]' // The element's attribute ends with the supplied value

For numeric types, the following syntax flavours are valid:

'[attribute>value]'  // The element's attribute is greater than to the supplied value
'[attribute<value]'  // The element's attribute is less than the supplied value
'[attribute>=value]' // The element's attribute is greater than or equal to the supplied value
'[attribute<=value]' // The element's attribute is less than or equal to the supplied value

The following example returns an ItemCollection with all bitmap items that have their allowSmoothing property set to false:

$$(':bitmap[allowSmoothing=false]);

Pseudo selectors

:first

The first selector matches the first item or element within a given context:

$$(':first');
:last

The last selector matches the first item or element within a given context:

$$(':last');
:even

The even selector matches all even numbered items or elements (i.e. the 2nd, 4th, 6th, etc) within a given context:

$$(':even');
:odd

The odd selector matches all odd numbered items or elements (i.e. the 1st, 3rd, 5th, etc) within a given context:

$$(':odd');
:random

The random selector randomly matches items or elements (i.e. the 1st, 5th, 10th, etc) within a given context:

$$(':random');
:selected

The selected selector matches items that are selected within the current context, be it the library, or the stage:

$$(':selected');
:empty

The empty selector matches:

  • movieclips, graphics or buttons without any timeline elements
  • folders without and child items

For Stage elements, just use the selector as is:

var elements = $(':folder:empty');

For Library items, to match items with a Timeline, use the selector as-is:

var folders = $$(':empty');

For Library items, to limit the match to only folders, use the :folder type selector as well:

var folders = $$(':folder:empty');

See the Working with items page for the code to recursively delete nested empty folders from the library.

Combination selectors

:not(rule)

The :not() selector takes a rule and negates it, returning the elements that don't match the result.

The following example matches all items in the assets/ folder and below that aren't bitmaps:

$$('/assets/*:not(:bitmap)');
:contains(selector)

Note - this selector is not currently implemented!

The :contains() selector looks inside elements or items and attempts to match the supplied selector. This means you can easily find library items that contain other items, named items, classes and so on.

The following example matches movieclips containing instances of the library item red_button:

$$(':movieclip:contains(/assets/buttons/red_button)');

The following example matches movieclips containing named items on stage named blue button:

$$(':movieclip:contains(blue_button)');
:random(float)

The :random() selector matches elements based on a flat value from 0.0 to 1.0.

The following example randomly matches 10% of elements currently on the stage:

$(':random(0.1)');
:nth(expression)

The :nth() selector (the equivilent CSS3 selector is called nth-child()) attempts to match sequential items or elements according to an expression of the format "2n+1".

The digits, + and - sign of the expression itself can be changed, and the +1 part of the expression is optional. Not only that, but the selector also accepts the values odd, even and random.

The following list demonstrates various expressions, which should hopefully make it easier to understand:

'1'      // Select only the first element
'2'      // Select only the second element
'15' // Select only the fifteenth element
'2n' // Select every second element (signified by the "n" character) '3n' // Select every third element '3n+1' // Select every third element, but offset the sequence by 1 '3n+2' // Select every third element, but offset the sequence by 2 '3n-2' // Select every third element, but offset the sequence by -2
'odd' // Select only odd elements 'even' // Select only even elements 'random' // Randomly select elements

The following example applies a checkerboard pattern to a grid of squares:

$(':nth(3n)').select().attr('brightness', 75);
$(':nth(3n-1)').select().attr('brightness', 50);
$(':nth(3n-2)').select().attr('brightness', 25);

For more information see the SitePoint page Understanding :nth-child Pseudo-class Expressions.

Custom Selectors

It is also possible to create and register your own custom :pseudo and [attribute] selectors that determine whether a Stage Element or Library Item should be included in a collection.

This is done simply by creating a callback function that contains some logic, then registering it as a named selector with the Selectors library, adding the new selector logic to the existing patterns.

Custom :pseudo selectors

Pseudo selectors allow you to evaluate a true/false state of an element or item, against a named selector, for example :blurred.

The following example creates a callback with the correct logic to determine whether an element is blured or not, then registers it:

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:

Custom [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 by the Selector engine, a value, not a Boolean, is returned so that the Selector engine can compare the results of the callback with the supplied CSS expression.

Again, the selector is simply used within an expression:

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

The results of which, are below:

Finally

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();

Selectors Table

The following table outlines all the selectors available to use for both Elements and Items:

Type Name Element Item
Filter
  name x x
  [attribute] x x
  :type x x
  /path x x
  .Class x x
  .package x x
Pseudo (find)
  :first x x
  :last x x
  :even x x
  :odd x x
  :random x x
  :selected x x
  :children   x
  :descendants   x
  :parent   x
Pseudo (filter)
  :empty x x
  :animated x x
  :keyframed x x
  :scripted x x
  :audible x x
  :exported x x
  :scriptable x  
  :filtered x  
  :tinted x  
  :transparent x  
Combination
  :not(expression) x x
  :contains(expression) x x
  :random(value) x x
  :nth(expression) x x
Custom
  :pseudo x x
  [attribute] x x


One Response to Selectors

  1. jQuery Deconstructed | Dave Stewart IO says:

    [...] within the jQuery source code. Discovering how Sizzle worked was instrumental to writing my own selector engine for xJSFL, and gave me lots of ideas that are used in almost all my programming [...]

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>