Remember how we talked about using a static list of ingredients for auto-complete, and downloading that static list to the client during first load? Well, that static list needs to come from somewhere; besides, it’s not really static.

Sometimes, a recipe will come along, quoting an ingredient that the system doesn’t yet have; all ingredients are stored in a database, and it’s relatively easy to add an ingredient there. But hey, we have that static lookup list now, how do we get that to work?

The “static” list is just a JavaScript file that looks similar to the following:

ingredientOptions = [ 
   new Ingredient(“7-up“, 8),
   new Ingredient(“absinthe“, 5),
   new Ingredient(“absolut citron“, 3),
   …
]

Basically, it’s just a list of 500 ingredient names and their popularities (for sorting). This list changes relatively rarely (when new ingredients are added – I’d say once a week at most). However, it does change, so we have to have a way to generate it from the database (copy-paste is a bad idea :-)).

I just used a PHP script that talks to the database, asks for the ingredient list, and generates the entire JS file from scratch. Roughly, the code looks like this:

// Get the list of ingredients from the database
$ data = DataRetrieval::getAllIngredients();

// Create the output string
$ output = “ingredientOptions = [\r\n“;
foreach ($ data as $ item) {
   $ output .= “new Ingredient(\”” . strtolower($ item->Name) . “\”” . $ item->popularity . “)“; 
   if ($ item != $ data[sizeof($ data) – 1]) {
      $ output .= “,\r\n“;
   }
}
$ output .= “\r\n];“;

// Actually write the JavaScript file
$ OUTPUT_FILE_NAME = ‘ingredients.js’;
if (!$ file_handle = fopen($ OUTPUT_FILE_NAME,”w“)) {
   die(“Cannot open file“);
}
if (!fwrite($ file_handle, $ output)) {
   die(“Cannot write to file“);
}

fclose($ file_handle);
echo “Success. Output saved to ” . $ OUTPUT_FILE_NAME . “\n“;

There are many other places in the cocktail builder where I’m using this “js generation” technique. For example, it’s known to be good to have all application UI strings separately from application logic and even presentation. It helps with several things:

1) Localization
2) Strings consistency

One more thing to note is that UI strings may be references in two completely different contexts: in .php files, where strings are used to generate server-side presentation piece, and in .js files, where strings are most frequently error messages or tiny things like the “no matches” string for auto-complete. Some weird strings may appear in either context. But, as you might have guessed, it would be really nice to have all UI strings live in one place, no matter where they are referenced – in client code or in server code.

So I created a table in MySQL, called UIStrings, where all strings will be stored an edited:

Then, I created two scripts – one to generate a server side include file strings.php.inc, and another one for client side strings: strings.js. These scripts are trivially different from the one quoted above.

Here’s a part of the listing of the generated strings.php.inc:

class UIText {
   const COCKTAIL_DETAILS_ACTION_ADD_TO_FAVORITES = “add to favorites“; 
   const
COCKTAIL_DETAILS_ACTION_EMAIL = “email a friend“;
   const COCKTAIL_DETAILS_ACTION_EMAIL_MAIL_SUBJECT = “Cocktail: %s“;
   …
}

In the actual PHP code, if I need to reference a UI string, I’ll just write

UIText:: COCKTAIL_DETAILS_ACTION_EMAIL

Similarly, the listing of the generated strings.js file looks like:

var UIText = [];
UIText.INPUT_BOX_HINT_TEXT = “add ingredient…“;
UIText.INPUT_BOX_NO_MATCHES = “No matches“;
UIText.INPUT_FEEDBACK_HINT_TEXT = “give feedback..“;

And if I need to reference a UI string in JavaScript code, I’ll just write

UIText.INPUT_BOX_HINT_TEXT

One last thing to note is that these generation steps need to be completely automated – they need to be a part of your build or checkin processes.

cb

P.S. I use the same “generated” .js for client-side usage statistics gathering, but that’s a different story. Let me know if you want me to share it 😉

Cocktail Builder: JavaScript Alcoholic