Attaching the Libraries and Custom Code

Last edit by:
Walter Davis

15 May, 2012

Pages in this section:

Here’s a run-down of everything you need to do within your Actions to integrate with the Softpress FX Actions and Protaculous.

There are a few things you need to do within a “Scripty” Action to communicate with the other Actions that might also be applied to the page.

Firstly, create your Action bundle and create a directory called “Support Files~” in the same directory as the Action file. This directory needs to contain the JavaScript libraries you’ll be linking to. You can download the full set of libraries here.

At the very beginning of your Action somewhere, you need to declare:

var scripty = true;
var debug = false;
var gLibraries = ["builder", "effects", "dragdrop", "controls", "slider", "sound"];

Your functions will also add to and track an object called filesList, at the fwPage level, which will be sorted and normalized at the end of the publish cycle.

The first variable marks your Action as being one of the Scripty Actions, the second will load the normal (not minified) versions of the Prototype and Scriptaculous libraries, which is useful for testing, and the third is used to make sure only the required libraries are loaded in the resulting page.

Next, you need to add the following functions to your <action-javascript> block. (I like to use an action-library for this.)

/*This function runs at publish time, and 
decides if this is the last "scripty" Action 
on the page or not. If it is, then it returns 
true, and the function that called it will 
attach all the necessary files to the head 
of the page.*/

function lastOrders(){
    var actions = fwPage.fwFindAllActions();
    var scripties = new Array();
    for (i in actions){
        if (actions[i].scripty == true) scripties.push(actions[i]);
    }
    return this === scripties[scripties.length -1];
}

/*Clean up the list of libraries by sorting 
them in their correct order (according to 
scripty specs) and removing duplicates*/
var gLibraries = ["builder", "effects", "dragdrop", "controls", "slider", "sound"];
var include = function(arr, obj) {
    for(var i = -1, j = arr.length; ++i < j;)
    if(arr[i] === obj) return true;
    return false;
};
function cleanLibs(){
    // Get rid of duplicates and out of range values
    var out = [];
    for (var i=0; i < fwPage.scriptyLibs.length; i++) {
        if( ! (include(out, fwPage.scriptyLibs[i])) && 
        (fwPage.scriptyLibs[i] < gLibraries.length) && 
        (fwPage.scriptyLibs[i] >= 0) ){
            out.push(fwPage.scriptyLibs[i]);
        }
    };
    fwPage.scriptyLibs = out.sort();
}

/*Build a string containing the scripty 
libraries used, or return "" if all are 
used or none are specified*/

function getLibs()
{
    var scriptyLibs = "";
    if(fwPage.scriptyLibs)
    {
        if(fwPage.scriptyLibs.length == gLibraries.length)
        {
            // All scriptyLibs are being used so don't specify any
        }   
        else
        {
            scriptyLibs += "?load=";
            for(var i in fwPage.scriptyLibs)
                scriptyLibs += gLibraries[fwPage.scriptyLibs[i]] + ",";
            scriptyLibs = scriptyLibs.substring(0, scriptyLibs.length-1);
        }
    }
    return scriptyLibs;
}

/*This function creates a link to a 
JavaScript file in the head of the page.*/

function LinkFileToHead(theTag, file)
{
    // Get the list of individual scriptyLibs and add it to the end of the scripty reference
    var scriptyLibs = getLibs();
    var scriptTag = theTag.fwAdd("script", true);
    scriptTag.src = fwQuote((!file.match("scriptaculous") ? file : file+scriptyLibs));
    scriptTag.type = fwQuote("text/javascript");
    scriptTag.fwAddRawOpt();
    theTag.fwAddRawOpt();
}

/*This function does the same thing, 
only using the Google CDN to deliver 
the files instead of the local versions.*/

function LinkRemoteFileToHead(theTag, file)
{
    var path = "http://ajax.googleapis.com/ajax/libs/"
    var scriptTag = theTag.fwAdd("script", true);
    // Get the list of individual scriptyLibs and add to the end of the scripty reference
    var scriptyLibs = getLibs();
    if(parseInt(fwFreewayVersion.replace(/.?(wd)?/g, "")) >= 562)
        scriptTag.src = fwQuote(path + (file.match("pro") ? "prototype/1.7.0.0/prototype.js" : "scriptaculous/1.9.0/scriptaculous.js"+scriptyLibs));
    else if(parseFloat(fwFreewayVersion) >= 5.5)
        scriptTag.src = fwQuote(path + (file.match("pro") ? "prototype/1.6.1.0/prototype.js" : "scriptaculous/1.8.3/scriptaculous.js"+scriptyLibs));
    else
        scriptTag.src = fwQuote(path + (file.match("pro") ? "prototype/1.6.0.2/prototype.js" : "scriptaculous/1.8.1/scriptaculous.js"+scriptyLibs));
    scriptTag.type = fwQuote("text/javascript");
    scriptTag.fwAddRawOpt();
    theTag.fwAddRawOpt();
}

And this is the final step in the puzzle: when your Action requests files be attached to the page, it does so through AddFiles. If you pass it a comma-separated list of libraries, you will get that list of files attached to your page. You must include these files in your Action bundle, and you must include “packed” versions of Prototype and Scriptaculous as well.

Due to a bug in Freeway, you can’t pass a variable containing a dot to this function, so while it would be perfectly clear to say AddFiles('foo.txt') to this function, in practice this blows up dramatically. Therefore, AddFiles is limited to JavaScript files with the .js extension. If you have other file types that you want to include, you’ll need to do that long-hand.

function AddFiles(filesString, scriptyLibs /*number or array of numbers*/)
{
    // Cleanup if arguments are missing
    if(filesString.constructor == Number || filesString.constructor == Array)
    {
        scriptyLibs = filesString;
        fileString = "";
    }
    var theHead = fwDocument.fwTags.fwFind("head");
    var connected = function(){
                if(fwShellCommand) {
                    return fwShellCommand('ping -c1 -i1 http://ajax.googleapis.com');
                }else{
                    var osa=new FWOSAInterpreter; 
                    osa.fwWrite('do shell script "curl ajax.googleapis.com"'); 
                    osa.fwCompile(); 
                    return osa.fwRun();
                }
            }
    var useCustom = filesString && filesString.length > 0;
    var path = this.fwPathName;
    var prefix = path.substring(0, path.lastIndexOf(":")) + ':Support Files~:';
    if(parseInt(fwFreewayVersion.replace(/.?(wd)?/g, "")) >= 562)
        var canon = 'prototype1700packer,prototype1700,scriptaculous190packer,scriptaculous190'.split(',');
    else if(parseFloat(fwFreewayVersion) >= 5.5)
        var canon = 'prototype1610packer,prototype1610,scriptaculous183packer,scriptaculous183'.split(',');
    else
        var canon = 'prototype1602packer,prototype1602,scriptaculous181packer,scriptaculous181'.split(',');

    var files = (useCustom) ? filesString.split(',') : canon;

    if(scriptyLibs)
    {
        // Make the scriptyLibs argument an array if it isn't one already
        scriptyLibs = scriptyLibs.constructor == Array ? scriptyLibs : [scriptyLibs];
        // Create or add the libraries used to a page variable
        if(!fwPage.scriptyLibs)
            fwPage.scriptyLibs = scriptyLibs;
        else
            fwPage.scriptyLibs = fwPage.scriptyLibs.concat(scriptyLibs);
    }

    // Make the overall library list object variable if it doesn't exist
    if(!fwPage.libsList)
        fwPage.libsList = new Object();

    for (i in files)
    {
        var file = files[i];
        if (file && !fwPage.libsList[file])
        {
            myFile = new FWFile;
            myFile.fwOpenRead(prefix + file + '.js');
            myFile.fwClose();
            if (fwParameters[file])
            {
                fwParameters[file].fwSpecify(myFile);
                var path = fwParameters[file].toString();
                if(useCustom == true)
                    fwPage.libsList[file] = path;
                fwParameters[file].fwClear();
            }
            else
            {
                fwAlert(ParamString(kFileNotFound, file, ".js"));
            }
        }
    }

    if(lastOrders())
    {
        if(parseInt(fwFreewayVersion.replace(/.?(wd)?/g, "")) >= 562) {
            if(fwPage.libsList['prototype1700packer'] && fwPage.libsList['prototype1700'])
                fwPage.libsList['prototype1700packer'] = null;

            if(fwPage.libsList['scriptaculous190packer'] && fwPage.libsList['scriptaculous190'])
                fwPage.libsList['scriptaculous190packer'] = null;
        } 
        else if(parseFloat(fwFreewayVersion) >= 5.5) {
            if(fwPage.libsList['prototype1610packer'] && fwPage.libsList['prototype1610'])
                fwPage.libsList['prototype1610packer'] = null;

            if(fwPage.libsList['scriptaculous183packer'] && fwPage.libsList['scriptaculous183'])
                fwPage.libsList['scriptaculous183packer'] = null;
        } else {
            if(fwPage.libsList['prototype1602packer'] && fwPage.libsList['prototype1602'])
                fwPage.libsList['prototype1602packer'] = null;

            if(fwPage.libsList['scriptaculous181packer'] && fwPage.libsList['scriptaculous181'])
                fwPage.libsList['scriptaculous181packer'] = null;
        }

        // Clean the list of individual libs
        if(fwPage.scriptyLibs)
            cleanLibs();

        for (i in canon)
        {
            if (fwPage.libsList[canon[i]])
            {
                var file = fwPage.libsList[canon[i]];
                connected() ? LinkRemoteFileToHead(theHead, file) : LinkFileToHead(theHead, file);
                delete fwPage.libsList[canon[i]];
            }
        }
        for ( i in fwPage.libsList )
            LinkFileToHead(theHead, fwPage.libsList[i]);
    }
}

Here’s an example of a call to this function, from within Protaculous. I encourage further study of that Action for more details about this technique.

First, we set up the file references, outside of the <action-javascript>:

<action-file name ="prototype1700packer" var/>
<action-file name ="scriptaculous190packer" var/>
<action-file name ="prototype1610packer" var/>
<action-file name ="scriptaculous183packer" var/>
<action-file name ="prototype1602packer" var/>
<action-file name ="scriptaculous181packer" var/>
<action-popup name="lib" title="Use Library">
<value name="prototype">
<value name="prototype-packed">
<value name="scriptaculous">
<value name="scriptaculous-packed">
</action-popup>

Next, we instantiate the libsList object to store file references. I do this in fwInterface and in some Actions I back it up in the main execution function as well.

function fwInterface(){
    fwPage.libsList = new Object();
}   

Finally, here’s the call to load the files:

function fwAfterStartHead()
{
    var filesString = '';
    if(fwParameters['lib'].fwValue == 'scriptaculous-packed'){
        filesString = 'prototype1610packer,scriptaculous183packer';
    }
    if(fwParameters['lib'].fwValue == 'prototype-packed'){
        filesString = 'prototype1610packer';
    }
    if(fwParameters['lib'].fwValue == 'scriptaculous'){
        filesString = 'prototype1610,scriptaculous183';
    }
    if(fwParameters['lib'].fwValue == 'prototype'){
        filesString = 'prototype1610';
    }

    /* Use the following table to request particular libraries within Scriptaculous:
            0 = Builder
            1 = Effects
            2 = Dragdrop
            3 = Controls
            4 = Slider
            5 = Sound
            "" = All libraries
     */

    if(parseInt(fwFreewayVersion.replace(/.?(wd)?/g, "")) >= 562) {
        AddFiles('prototype1700packer,scriptaculous190packer', [1]);
    } else if(parseFloat(fwFreewayVersion) >= 5.5) {
        AddFiles('prototype1610packer,scriptaculous183packer', [1]);
    } else {
        AddFiles('prototype1602packer,scriptaculous181packer', [1]);
    }
}

Here’s a breadkown of adding libraries:

// Use all Scripty libraries
AddFiles(filesString);

// Use the Effects library only
AddFiles(filesString, 1);

// Use the Effects and Dragdrop libraries
AddFiles(filesString, [1,2]);

Register or log in to view or add comments.

FreewayCast

Learn by watching! Screencasts show you how to do it in Freeway. Visit FreewayCast today!