CSS-style selection for the Library panel

Categories:Blog

I've just completed one of the xJSFL features I've been dying to do since starting the project, and that's CSS-style selection for the library panel.

Basically, instead of selecting library items by specifying paths, indices, or writing expressions within loops, you can now simply select (or just return) library items with an expression:

var items = $$(expr);

Selector syntax

The following basic selector types are supported:

#name of item
path/to/item
:itemtype
:Class
[attribute]
[attribute=value]
[attribute^=value]
[attribute$=value]
[attribute*=value]
[attribute!=value]
wildcards*
comma,separated,selections

Selectors can also be combined, to make a selection more specific:

assets/player/:graphic
#*Skin:movieclip
#*Skin:movieclip[linkageExportInFirstFrame=false]

At the moment, selector expressions must be strings, but I'll add support for regular expressions at some point.

Making selections

Selections are made using the library Item Selector function, which is currently shortcut to $$:

var items = $$('assets/bitmaps/*');

The function returns an ItemCollection (rather than an Array of  Items) which is a subclass of the xJSFL Collection class. The Collection class has some core methods for iterating through collections of classes or objects, such as each(), add(), filter(), etc.

The ItemCollection class deals with Library Items, and has methods specific to the Library and Item classes, such as attr(), rename(), remove() and select(). For your convenience, all Collections print a mini summary to the Output Panel when traced:

[ItemCollection: 7 elements]

Let's look next at a concrete example of how selection and manipulation is combined using the ItemSelector function and ItemCollection class.

Code examples

Smooth all bitmaps

One of the more ubiquitous JSFL scripts on the web is "smooth all bitmaps". A quick Google, and you'll see a bunch of different scripts that accomplish roughly the same thing.

The typical JSFL script would be something like this:

var items = fl.getDocumentDOM().library.items;
for (var i = 0; i < items.length; i++){
if(items[i].itemType == "bitmap"){
		items[i].allowSmoothing = true;
	}
}

We can now select and manipulate in one line:

$$(':bitmap').attr('allowSmoothing', true);

Not only that, but we can do more complex manipulations, such as, only smoothing PNGs in a certain folder, and selecting them as well:

$$('assets/*.png').attr('allowSmoothing', true).select();

I'll let you imagine what else you could do in one line of code, and move onto another example.

Add exported items to current frame

Another script I found online was someone wanting to add all exported movieclips to the selected frame:

var library = fl.getDocumentDOM().library;
var items = library.items;

for(var i = 0; i < items.length; i++){
	var item = items[i]
	if(item.itemType != "folder"){
		if(item.linkageExportForAS != undefined){
			document.addItem( {x:0, y:i * 50}, item )
		}
	}
}

You can do the same with an ItemCollection, each(), and a callback:

function addToFrame(item, index){
	dom.addItem( {x:0, y:index * 50}, item );
	}
$$('[linkageExportForAS]').each(addToFrame);

If you're really one for short code, and you just want the items on the stage, you could do this:

$$('[linkageExportForAS]').each(function(e){dom.addItem({x:0,y:0},e)});

Alternatively, you could augment the ItemCollection class with your own addToStage() method and come up with something like this:

$$('[linkageExportForAS]').addToStage();

As you can see, we've gone from 7 or 8 lines of fiddly code to a single command. Yay, frameworks!

A quick note on callbacks

As you can see in the example above, each() is method on the Collection class that allows you to process each item in a collection with a custom callback. Callbacks are run in the scope of the collection, and are always passed the same arguments:

function(item, index, elements)
{
	// your code here...
}

I'll certainly be adding more methods to the ItemCollection class before release, but realise that callbacks can always provide whatever custom functionality you need to add if a method does not already exist.

That's it!

More updates to come in the next couple of weeks or so, along with stage selectors, once I figure out a decent syntax.

Bear in mind that I'm designing this sort of code to be easily-run from either Komodo IDE, or the xJSFL Console, which will be an interactive scripting Flash Panel within the main Flash IDE. With that sort of convenience and power, scripters will just be able to look up the syntax for the something they want to update, then just rattle off some xJSFL and get on with their day.

Cheers for now,

Dave

11 Responses to CSS-style selection for the Library panel

  1. Joe says:

    Just an OT question.
    What’s for you the most missing ‘littles features’ in JSFL?

  2. Dave Stewart says:

    Hey Joe,
    Hmm… not sure to be honest.

    Generally the thing I find is missing from JSFL is just a decent structure. So many methods are just crammed into the Document or Flash classes, and generally it just all feels badly organised.

    Apart from that, the workflow can just feel so backwards – for example, having to select an object then change the document fill to change its color.

    Generally, I’ve found most things I need are in there somewhere, it’s just a question of finding out how to properly leverage them.

    Actually, the one main thing that bugs me about JSFL (and took me ages to develop a decent workaround) is the fact that externally executed scripts appear to be sandboxed for the duration of the execution. Variables are persistent via running from Commands or within Flash panels, but if you run a JSFL from the command line, or OS, your variables come and go in an instant, so you can’t load libraries once, then use them in subsequent calls.

    But as I said, I have a workaround for that!

    What about you?

  3. Joe says:

    3 things :

    – more fl.addEventListener events. To know when a symbol is selected/deselected/moved on the stage. And when items are selected/deselected in the Library panel
    – in the library, you show the item used count. You can’t access it with JSFL. And, more important, you can’t know what items use it. It’s really an important missing thing for me.
    – the possibility to open/close/show panels. And know if a panel is visible. For example, set library to front if it’s the property panel is in front and the library is back (not shown in the IDE).

    What do you think?

  4. Dave Stewart says:

    Yeah, those are all really good wants. I haven’t found a way round them either.

    The first one is also something I would really like.
    The second is definitely a good idea
    The third, I am kinda in 2 minds about. It could be really open to abuse, but it could certainly be useful.

    Also, I’d love access to keyboard shortcuts.

  5. Joe says:

    Probably a stupid question, but, did you know when you release xJSFL? ;)
    I’m very curious to test it and check the code!

    I see that xJSFL is joined with a nice panel and loads several scripts to setup. But can we use xJSFL in a standalone mode?
    For example, in this post you write:

    $$(‘:bitmap’).attr(‘allowSmoothing’, true);

    This is very kick-ass!
    It will be possible to just load the selector engine to perform this single line? Or did we need to load the full package to run this line?

    Also, the project will be opensource, hosted on github/googlecode?

  6. Dave Stewart says:

    I should be releasing sometime in June. I can hardly believe it myself :)

    Yep, you can run xJSFL standalone – that is the main point of the framework. The framework comes with Komodo Edit, an open source IDE, and I’ve written full autocomplete files for JSFL, as well as a bunch of macros that make it really easy to run scripts externally – so you edit and run from Komodo, and see the results straight away in Flash.

    You can also use xJSFL standalone in external scripts, Flash panels and Commands, with once caveat – xjsfl.init(this) has to have been called at least once – as it copies the framework code and classes into the namespace you’re running in, i.e. Panel, Command, or External. Commands and Panels only need to have init() run once, but for external scripts, it needs to be called for each execution.

    As for open source – not sure yet. It’s a nice idea in theory, but a) I’ve never run a fully open source project before and b) I want to maintain control over the direction of the framework, at least for now. I may put the code on Github at some point, but I’ll need to think about how I will accept patches and deal with forks.

    I have some friends who are core devs on the Kohana project, so I’ll probably ask their advice before I do anything.

  7. Joe says:

    Cool, waiting for june!
    Thanks for all your anwsers.

  8. Dave Stewart says:

    No problem. I’ll have the forum back online at some point, so you’ll be able to ask as many questions, and pose as many comments, as you like :)

  9. Dave Stewart says:

    I ran the wrong git command today and lost this library before I could commit it. Then my recovery software couldn’t retrieve a non-corrupted version, so I have to write the whole thing again… *sigh*

  10. Dave Stewart says:

    OK, all rewritten, and luckily (as only some rewrites go) actually better. Although there was a time there when I thought I’d forgotten how to do some of the key bits.