Shortcodes for Drupal

Word­Press’ Short­code API is a really cool thing, and since I’m work­ing on a Dru­pal site these days I’ve been look­ing for some­thing sim­i­lar. Unfor­tu­nately I couldn’t find any­thing… There are some imple­men­ta­tions out there but the ones I found and tested always come pre-bundled with spe­cific tags and don’t always pro­vide an exten­si­ble and sta­ble logic.

So I made mine!

Most of my work sim­ply con­sisted in copying/pasting the code in Word­Press’ shortcodes.php and bind­ing it into a Dru­pal fil­ter. Easy enough.

Now if you want to use it, you have to:

  1. Get the module
  2. Add it to your “mod­ules” directory
  3. Enable it
  4. Add it to one of your setup’s fil­ter bundle
  5. Write your own mod­ule where you’d imple­ment one or more Short­codes (via add_shortcode) and make sure you add “depen­den­cies[] = short­codes” in your .info file

You might expe­ri­ence a nasty “Call to unde­fined func­tion add_shortcode”. If so, you have to change you mod­ule implementation’s weight, either directly in your data­base, or thanks to the cool Util­ity mod­ule. Set it to 10 and you’re set!

Misc. UI Elements

It’s an inter­est­ing thing to see how Google is work­ing on its Chrome OS, in an Open­Source fash­ion, let­ting every­one know where they are going and how all this will/may look like. As a UI nerd I find it absolutely lovely to be able to sneak a peek at what’s com­ing next, and have techy details on it, such as hexa­dec­i­mal val­ues and gra­di­ent stops…

Fire­fox also pro­vides sim­i­lar doc­u­ments on its Wiki, and Chro­matic Pixel tells you every­thing about it.

Speak­ing of UI design, here’s a nice arti­cle about craft­ing sub­tle and real­is­tic ones. You’ll find gems like this one in it, and how it is achieved…

Got sim­i­lar links to share? Do so!

Hey, did you notice I didn’t say any­thing about Flash and/or the iPad? Thank me.

Meebo Cleaner

Using Google Chrome? Using Meebo? Annoyed by the ad at the bot­tom and the blog win­dow when you log in?

I just wrote and pub­lished my first Chrome Exten­sion — Meebo Cleaner, to clean that up!

Pretty sim­ple code, noth­ing rev­o­lu­tion­ary here. Go get it and let me know what you think, or if you have suggestions/ideas…

The Scroll Effect

Facts

So the other day I had an hour to waste, I decided to learn how to use MooTools classes and, as the best way to learn some­thing is to play with it, I played with it.

About 30 min­utes after, I had some­thing  run­ning. Dirty and buggy but still, look­ing cool. It took me an extra 30 min­utes to clean that up, make sure it was work­ing on most browsers, add the Google Ana­lyt­ics tracker, push it online and add it to the projects page…

You prob­a­bly guessed it already, I’m talk­ing about the Scroll Clock. Well this hour might be the least wasted one of my life. Think I’m rad­i­cal? Read on!

Results

After tweet­ing about it twice (once to some­one who’s inter­ested in netart, and once to the MooTools team) things went big. I don’t know exactly how this hap­pened but it (the Scroll Clock page) got love from Giz­modo, swiss­miss, QBN, Ajax­ian, Neatorama and many more. Wow.

A few days after the tsunami, here’s what my Ana­lyt­ics page looks like. My daily aver­age of 600 page views has seri­ously been put to shame, with a cli­max on the 19th of Novem­ber: 313,000+.

Pageviews

Side effects

This is prob­a­bly the fun­ni­est part, not only did I worry for the server the site is hosted on, but a few things happened…

I got 3 job offers ; many friend requests on Face­book, Flickr, Vimeo and so on ; received a dona­tion ; was con­tacted by a Google guy to add the project to chromeexperiments.com, which I did ; and of course had to bother my friends and col­leagues about my new web-fame…

Con­clu­sion

The short one: don’t spit on Twit­ter, it might make you a star. Just jok­ing, keep spit­ting on it.

The long one: the sim­plest and short­est project of mine is the one which received the most vis­i­tors and love, ironic right? What does that mean? Should I stop work­ing on full-fledged AIR apps?

Prove me wrong!

Scroll Clock

I played with MooTools a bit and did that. Use­less, open­source, nerdy.

Scroll Clock

I also set up a gallery, so if you’ve got nice scroll­bars that aren’t here yet, send’ em right away!

BaseObject

I was talk­ing about it, here it is!

This class will come in handy every time you work with syn­chro­nous SQLite data­bases in an AIR project. It’s a real-world imple­men­ta­tion of the Dynam.ize util­ity I pre­sented ear­lier… I will show you an exam­ple of how to work with it, with sim­ple sub-classes. Let’s go!

First things first.

I need to open my data­base and pro­vide that con­nec­tion to BaseObect:

  1. var sqlCon:SQLConnection=new SQLConnection();
  2. sqlCon.open(File.applicationDirectory.resolvePath('data.sqlite'));
  3. BaseObject.defaultConnection=sqlCon;

We need clients!

Now, let’s con­sider a data­base with a “client” table (pretty cre­ative, right?), those clients have a name, a URL and a gen­der (male/female), and of course, an ID. So we have a “client” table with 4 fields: id, name, url, male (which is a Boolean: true=male, false=female).

I have mapped a BaseOb­ject sub-class to this table (I will show you how in a few moments), so I can now cre­ate a new client in a pretty sim­ple fashion:

  1. var myClient:Client=Client.create({name:'Joe', url:'http://www.yep.com', male:true});

Cool, I now have a Client instance I can work with and a line has been added in my “client” table. What if I wanted to change its name? Easy.

  1. myClient.setName('Mark');

The “name” field has been updated. Let’s check that.

  1. trace(myClient.getName());

Traces “Mark”? Good. OK, what about updat­ing the URL and name at the same time? Two queries? Nope!

  1. myClient.update({name:'Jack', url:'http://www.yo.net'});

Now let’s grab a client via his ID.

  1. var c1:Client=Client.getFromID(1);

Sim­ple. But what if I wanted to grab more than one client, fox exam­ple what if I wanted all male clients?

  1. var males:Array=Client.getFromQuery('SELECT * FROM client WHERE male=@male', {'@male':true});

You can now loop through this array and inter­act with the Client instances it contains…

What’s the trick?

Noth­ing too hard to under­stand. Client is a sub-class of BaseOb­ject that sim­ply exposes some of its sta­tic and instance meth­ods (get­Fro­mID, get­From­Query, cre­ate, update and so on). It also casts BaseOb­ject return val­ues to the right type: Client. For exam­ple, this is how get­Fro­mID works:

  1. public static function getFromID(id:uint):Client {
  2. return BaseObject._getFromID(getTableData(), id) as Client;
  3. }

Now you might won­der what this get­Table­Data method is. Well it returns data about the table to which Client is bound to, like that:

  1. public static function getTableData():TableData {
  2. if (!_tableData) _tableData=new TableData('client', Client, ['name', 'url', 'male']);
  3. return _tableData;
  4. }

See? We define the table name (client), the cur­rent class (Client) and the fields we need to han­dle (name, url and male)… That’s it.

Our clients bought cars…

That’s right, so we should have a “car” table, right? With id, name, brand, cli­en­tID and pur­chase­Date we should be good. Its Table­Data would look like that:

  1. new TableData('car', Car, ['name', 'brand', 'clientID', 'purchaseDate']);

Note: I didn’t list id as BaseOb­ject sup­poses there’s always an id field.

OK, so our clients bought cars, and we’d like to know who bought what. Let’s write a method in Client to do that:

  1. public function getCars():Array {
  2. return Car.getFromQuery('SELECT * FROM car WHERE clientID=@id', {'@id':id}));
  3. }

That works, cool. But we can do bet­ter, we could cache this Array so we don’t query every time we need it ; there’s a tech­nique for that:

  1. public function getCars(force:Boolean=false):Array {
  2. return (hasCache('cars') && !force) ?
  3. getCache('cars') :
  4. setCache('cars', Car.getFromQuery('SELECT * FROM car WHERE clientID=@id', {'@id':id}));
  5. }

Done. Opti­mized.

We can now see which cars our first client bought:

  1. var c1cars:Array=c1.getCars();

We could also imple­ment the oppo­site: retriev­ing a Client form a Car instance:

  1. public function getClient():Client {
  2. return Client.getFromID(this.getClientID());
  3. }

Notice how I used get­Cli­en­tID? This refers to the table’s cli­en­tID field and returns it.

That’s a wrap.

Well that’s pretty much it, I think I cov­ered the basics!

If you want to play with it, get the class/demo project and tell me what you think. I’ve bun­dled Client, Car and some exam­ple uses…

Dynam.ize

Still while work­ing on this app I was talk­ing about ear­lier I real­ized I was quite used to work­ing with PHP classes’ Magic Meth­ods, and more pre­cisely the way it han­dles over­load­ing. Those lovely __get, __set and __call meth­ods are called when­ever you try to access a property/method that is not explic­itly defined, mak­ing your class dynamic. Of course you don’t need this all the time, and it might even be dan­ger­ous, but it some cases that’s sim­ply perfect.

You can do that with AS3 if you extend flash.utils.Proxy, cool. But wait, no! Not cool! What if I wanted to extend some­thing else? Nah, let’s find some­thing else…

I came up with the idea of dynam­i­cally cre­at­ing get­ter and set­ter func­tions on a class instance for pre­de­fined prop­er­ties. Now those aren’t really get­ters and set­ters but let me show you what it looks like so you under­stand bet­ter… Here’s an example:

  1. package {
  2. import net.tw.util.Dynam;
  3. // This is my class, that has to be dynamic
  4. public dynamic class DynClass {
  5. // This Array will be used to store the properties' values...
  6. protected var _data:Array=[];
  7. public function DynClass() {
  8. // In the constructor I call the Dynam.ize method on this, so it builds the getters and setters for the supplied properties
  9. Dynam.ize(this, ['abc', 'def', 'ghi'], getter, setter);
  10. }
  11. // Here are the functions that will be called when I try to get or set one of the properties I listed in Dynam.ize
  12. protected function getter(key:String):* {
  13. return _data[key];
  14. }
  15. protected function setter(key:String, v:*):void {
  16. _data[key]=v;
  17. }
  18. }
  19. }

Now let’s instan­ti­ate this class and play with it:

  1. var dc:DynClass=new DynClass();

We can call getAbc() or setAbc() on it:

  1. dc.setAbc('my value');
  2. trace('get abc', dc.getAbc());

Every­thing should be OK. It would work the same with get/setDef and get/setGhi… This exam­ple might not seem very use­ful but you could do any­thing within the get­ters and set­ters ; for exam­ple access Share­dOb­jects, send­ing data to a server and so on…

Find the class and a demo project on as3-bits!

Com­ing up next: my imple­men­ta­tion of this con­cept for AIR’s SQLite databases!

Thoughts?

Flex — GradientLabel

If you’ve ever won­dered whether it’s pos­si­ble to apply a gra­di­ent on a Flex Label, well it is ; but that’s not very straight for­ward… As I’m work­ing on a app that requires this kind of glit­ter I decided to try and see what could be done.

I started with a basic Action­Script project (no Flex involved) and came up with this. Quite func­tional, could prob­a­bly be opti­mized but my goal was actu­ally a Flex com­po­nent and I knew that was tech­ni­cally fea­si­ble. I then sim­ply extended Flex’s Label class and basi­cally copied/pasted the logic into it. Just had to fig­ure out which event to lis­ten to and I was good to go…

Here’s a demo app for your play­ing pleasure.

Go get Flash!

You may notice that in this exam­ple I embed the font so it looks nicer, but this is not mandatory…

All this is open­source (class+project) and you can grab it at my brand new Google Code dump: as3-bits. Help yourself.

As always, feed­back welcome.

FileWatch

I wanted to try Flex 4 with a “real life” project so I wrote this lit­tle thing. Rough draft.

FileWatch

The app will allow you to mon­i­tor files changes: select a text file and you’ll be prompted when it’s updated. Basic. By the way, did I say “rough draft” before?

Every­thing in it is Open­Source, from the Illus­tra­tor files to the MXML and CSS stuff, so play with it! For those who only want the .air, here it is.

Now, why is it cool?

  • Build with the brand new Flex 4 (Gumbo) framework
  • Uses a home-brewed Icon­But­ton class, because Gumbo doesn’t pro­vide any
  • Uses the new Spark cus­tom skins logic (on But­ton, Scroll­Bar and more…)
  • Uses the new states’ logic and transitions
  • Based on as3corelib’s File­Mon­i­tor class
  • Shows you how to build a multi-instance AIR app
  • Con­tains Illustrator/Photoshop UI files

And why is it not that cool?

  • Prob­a­bly still buggy, wait for updates!
  • Flex 4 is not done yet, so the code might break at any time
  • No icons yet
  • No or very few comments
  • Pretty use­less app!

If you’re try­ing to learn Flex/Flex 4 or won­der­ing what’s new in it and how to use it you should defin­i­tively give it a go…

Have ques­tions? Drop’em!

Snips2

Remem­ber my first and only Word­Press plu­gin? Well it just got better.

Snips2

Snips 2.0 is basi­cally Snips rewrit­ten from scratch, updated to fit Word­Press’ Short­code API. Let’s see how good it is…

Tired of hav­ing to copy paste nasty HTML code from sites such as YouTube, Vimeo and so on? Look­ing for a way to insert recur­rent con­tent in your posts with­out hav­ing to type it every time? Would like to be able to inject para­me­ters in these snip­pets? Well, now you can.

Just install Snips and use the bun­dled short­codes or create/edit your own!

Each Snip is a com­bi­na­tion of a name, a model and optional para­me­ters. The name defines the short­code tag you will be able to use, the model is the con­tent that will replace your short­code calls and the para­me­ters (that look like #the-parameter# in the model) are por­tions of the model that can change from a call to an other. Those para­me­ters can have default val­ues or can be left empty and then become mandatory.

All of this can be edited via a sim­ple UI, found under Set­tings > Snips… Here’s screenshot:

Snips2 screenshot

For those that used Snips’ first ver­sion: (0.2) every­thing should be OK, the pre­vi­ous syn­tax will work ; but I rec­om­mend using the new one and the cor­re­spond­ing updated model files (ex: yt becomes yt2). Also, the #up# para­me­ter (used in mp3 and swf snips) has to be set man­u­ally to your blog’s upload path.

If you use it and find bugs, please let me know! This is the first time I use jQuery behav­ior (for the para­me­ters’ detec­tion in the Set­tings page) so it could act a lit­tle weird.