Copyright © 2008, Levyco Development, LLC. All rights are reserved.
YUI Configurator in PHP...

Intro


The isn't really a demo, but it does explain a tool I use in all my pages to deterine which YUI modules are required (i.e., which ones to load.) In my case, I prefer the server to establish the requirements for the "page" and then let the browser use its normal loading and caching to handle the client side. Others may also require this capability.


The YUI Dependency Configurator has an internal data representation of the required objects and their dependencies (and their obsolescense -- that is, which modules supercede other modules.) The PHP class presented here used that data tree to build a simple PHP configurator.


To use the tool, a page simply instantiates the class (CYUIWrapper) and passes an array of ids. The ids are the YUI elements the page requires. For example, the following call will load all necessary elements for containers and buttons. An optional second parameter determines if the optional components for the elements should be included (true (default) means to include the elements, or false if not to).


$YUIWrapper =& new CYUIWrapper("container","button");

Below is the complete class, however, there are methods in this class to do some site specific things I use, and you may not want or care to use all those features. You can delete whatever parts of the class you do not want or need.



<?



    
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //
    //      cyuiwrapper.php
    //      ===============
    //
    //      this class wraps the yui library to make it a little easier to use
    //
    //      COPYRIGHT (C) 2007, Levyco Development, LLC.  All Rights Are Reserved.
    //
    //      ver 1.0.0 2007-09-09 BLevy
    //
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////


    
class CYUIWrapper {

        var 
$VERSION;
        var 
$DEPENDENCIES;
        var 
$ASSETS;
        var 
$MODULEMAP;
        var 
$ASSETMAP;
        var 
$LOADMODULES;
        var 
$LOADASSETS;

        var 
$LOAD;
        var 
$YUIMAP;

        
// function to init the module/dependency table

        
function initModuleTable() {

            
// are we using the "min" versions (should be "-min" or "")

            
$MIN "-min";

            
// this is derived from the requrements/dependency table from yuiloader-beta.js (version 2.5.1)

            
$this->YUIMAP = array (

                
'yahoo' => array (
                    
'type' => 'js',
                    
'path' => "yahoo/yahoo${MIN}.js"
                
),

                
'reset' => array (
                    
'type' => 'css',
                    
'path' => "reset/reset${MIN}.css"
                
),

                
'fonts' => array (
                    
'type' => 'css',
                    
'path' => "fonts/fonts${MIN}.css"
                
),

                
'grids' => array (
                    
'type' => 'css',
                    
'path' => "grids/grids${MIN}.css",
                    
'requires' => array ('fonts'),
                    
'optional' => array ('reset')
                ),

                
'base' => array (
                    
'type' => 'css',
                    
'path' => "base/base${MIN}.css",
                    
'after' => array ('reset''fonts''grids')
                ),

                
'reset-fonts' => array (
                    
'type' => 'css',
                    
'path' => "reset-fonts/reset-fonts.css",
                    
'supersedes' => array ('reset''fonts'),
                    
'rollup' => 2
                
),

                
'reset-fonts-grids' => array (
                    
'type' => 'css',
                    
'path' => "reset-fonts-grids/reset-fonts-grids.css",
                    
'supersedes' => array ('reset''fonts''grids''reset-fonts'),
                    
'rollup' => 4
                
),

                
'sam-skin' => array (
                    
'type' => 'css',
                    
'path' => "build/assets/skins/sam/skin.css"
                
),

                
'cookie' => array (
                    
'type' => 'js',
                    
//'path' => "cookie/cookie-beta${MIN}.js", // 251
                    
'path' => "cookie/cookie${MIN}.js",
                    
'requires' => array ('yahoo')
                ),

                
'dom' => array (
                    
'type' => 'js',
                    
'path' => "dom/dom${MIN}.js",
                    
'requires' => array ('yahoo')
                ),

                
'event' => array (
                    
'type' => 'js',
                    
'path' => "event/event${MIN}.js",
                    
'requires' => array ('yahoo')
                ),

                
'element' => array (
                    
'type' => 'js',
                    
//'path' => "element/element-beta${MIN}.js", // 260
                    
'path' => "element/element{MIN}.js",
                    
'requires' => array ('dom''event')
                ),

                
'json' => array (
                    
'type' => 'js',
                    
'path' => "json/json${MIN}.js",
                    
'requires' => array ('yahoo')
                ),

                
'utilities' => array (
                    
'type' => 'js',
                    
'path' => "utilities/utilities.js",
                    
'supersedes' => array ('yahoo''event''dragdrop''animation''dom''connection''element''yahoo-dom-event''get''yuiloader''yuiloader-dom-event'),
                    
'rollup' => 8
                
),

                
'yahoo-dom-event' => array (
                    
'type' => 'js',
                    
'path' => "yahoo-dom-event/yahoo-dom-event.js",
                    
'supersedes' => array ('yahoo''event''dom'),
                    
'rollup' => 3
                
),

                
'yuiloader-dom-event' => array (
                    
'type' => 'js',
                    
'path' => "yuiloader-dom-event/yuiloader-dom-event.js",
                    
'supersedes' => array ('yahoo''dom''event''get''yuiloader''yahoo-dom-event'),
                    
'rollup' => 5
                
),

                
'animation' => array (
                    
'type' => 'js',
                    
'path' => "animation/animation${MIN}.js",
                    
'requires' => array ('dom''event')
                ),

                
'containercore' => array (
                    
'type' => 'js',
                    
'path' => "container/container_core${MIN}.js",
                    
'requires' => array ('dom''event'),
                    
'pkg' => 'container'
                
),

                
'button' => array (
                    
'type' => 'js',
                    
'path' => "button/button${MIN}.js",
                    
'requires' => array ('element'),
                    
'optional' => array ('menu'),
                    
'skin' => "button/assets/skins/sam/button.css"
                
),

                
'calendar' => array (
                    
'type' => 'js',
                    
'path' => "calendar/calendar${MIN}.js",
                    
'requires' => array ('event''dom'),
                    
'skin' => "calendar/assets/skins/sam/calendar.css"
                
),

                
'connection' => array (
                    
'type' => 'js',
                    
'path' => "connection/connection${MIN}.js",
                    
'requires' => array ('event')
                ),

                
'dragdrop' => array (
                    
'type' => 'js',
                    
'path' => "dragdrop/dragdrop${MIN}.js",
                    
'requires' => array ('dom''event')
                ),

                
'get' => array (
                    
'type' => 'js',
                    
'path' => "get/get${MIN}.js",
                    
'requires' => array ('yahoo')
                ),

                
'history' => array (
                    
'type' => 'js',
                    
'path' => "history/history${MIN}.js",
                    
'requires' => array ('event')
                ),

                
'container' => array (
                    
'type' => 'js',
                    
'path' => "container/container${MIN}.js",
                    
'requires' => array ('dom''event'),
                    
'optional' => array ('dragdrop''animation''connection''button'),
                    
'supersedes' => array ('containercore'),
                    
'skin' => "container/assets/skins/sam/container.css"
                
),

                
'datasource' => array (
                    
'type' => 'js',
                    
//'path' => "datasource/datasource-beta${MIN}.js", // 251
                    
'path' => "datasource/datasource${MIN}.js",
                    
'requires' => array ('event'),
                    
'optional' => array ('connection')
                ),

                
'datatable' => array (
                    
'type' => 'js',
                    
// 'path' => "datatable/datatable-beta${MIN}.js", // 251
                    
'path' => "datatable/datatable${MIN}.js",
                    
'requires' => array ('element''datasource'),
                    
'optional' => array ('calendar''dragdrop'),
                    
'skin' => "datatable/assets/skins/sam/datatable.css"
                
),

                
'menu' => array (
                    
'type' => 'js',
                    
'path' => "menu/menu${MIN}.js",
                    
'requires' => array ('containercore'),
                    
'skin' => "menu/assets/skins/sam/menu.css"
                
),

                
'autocomplete' => array (
                    
'type' => 'js',
                    
'path' => "autocomplete/autocomplete${MIN}.js",
                    
'requires' => array ('dom''event'),
                    
'optional' => array ('connection''animation'),
                    
'skin' => "autocomplete/assets/skins/sam/autocomplete.css"
                
),

                
'charts' => array (
                    
'type' => 'js',
                    
'path' => "charts/charts-experimental${MIN}.js",
                    
'requires' => array ('element''json''datasource')
                ),

                
'slider' => array (
                    
'type' => 'js',
                    
'path' => "slider/slider${MIN}.js",
                    
'requires' => array ('dragdrop'),
                    
'optional' => array ('animation')
                ),

                
'colorpicker' => array (
                    
'type' => 'js',
                    
'path' => "colorpicker/colorpicker${MIN}.js",
                    
'requires' => array ('slider''element'),
                    
'optional' => array ('animation'),
                    
'skin' => "colorpicker/assets/skins/sam/colorpicker.css"
                
),

                
'editor' => array (
                    
'type' => 'js',
                    
//'path' => "editor/editor-beta${MIN}.js", // 251
                    
'path' => "editor/editor${MIN}.js",
                    
'requires' => array ('menu''element''button'),
                    
'optional' => array ('animation''dragdrop'),
                    
'skin' => "assets/skins/sam/skin.css"
                
),

                
'resize' => array (
                    
'type' => 'js',
                    
// 'path' => "resize/resize-beta${MIN}.js", // 251
                    
'path' => "resize/resize${MIN}.js",
                    
'requires' => array ('dom''event''dragdrop''element'),
                    
'optional' => array ('animation'),
                    
'skin' => true
                
),

                
'imagecropper' => array (
                    
'type' => 'js',
                    
'path' => "imagecropper/imagecropper-beta${MIN}.js",
                    
'requires' => array ('dom''event''dragdrop''element''resize'),
                    
'skin' => true
                
),

                
'imageloader' => array (
                    
'type' => 'js',
                    
'path' => "imageloader/imageloader${MIN}.js",
                    
'requires' => array ('event''dom')
                ),

                
'selector' => array (
                    
'type' => 'js',
                    
//'path' => "selector/selector-beta${MIN}.js", // 260
                    
'path' => "selector/selector${MIN}.js",
                    
'requires' => array ('yahoo''dom')
                ),

                
'layout' => array (
                    
'type' => 'js',
                    
// 'path' => "layout/layout-beta${MIN}.js", // 251
                    
'path' => "layout/layout${MIN}.js",
                    
'requires' => array ('dom''event''element'),
                    
'optional' => array ('animation''dragdrop''resize''selector'),
                    
'skin' => true
                
),

                
'logger' => array (
                    
'type' => 'js',
                    
'path' => "logger/logger${MIN}.js",
                    
'requires' => array ('event''dom'),
                    
'optional' => array ('dragdrop'),
                    
'skin' => true
                
),

                
'profiler' => array (
                    
'type' => 'js',
                    
// 'path' => "profiler/profiler-beta${MIN}.js", // 251
                    
'path' => "profiler/profiler${MIN}.js",
                    
'requires' => array ('yahoo')
                ),

                
'yuiloader' => array (
                    
'type' => 'js',
                    
// 'path' => "yuiloader/yuiloader-beta${MIN}.js", // 251
                    
'path' => "yuiloader/yuiloader${MIN}.js",
                    
'supersedes' => array ('yahoo''get')
                ),

                
'profilerviewer' => array (
                    
'type' => 'js',
                    
'path' => "profilerviewer/profilerviewer-beta${MIN}.js",
                    
'requires' => array ('profiler''yuiloader''element'),
                    
'skin' => true
                
),

                
'simpleeditor' => array (
                    
'type' => 'js',
                    
// 'path' => "editor/simpleeditor-beta${MIN}.js", // 251
                    
'path' => "editor/simpleeditor${MIN}.js",
                    
'requires' => array ('element'),
                    
'optional' => array ('containercore''menu''button''animation''dragdrop'),
                    
'skin' => true,
                    
'pkg' => 'editor'
                
),

                
'tabview' => array (
                    
'type' => 'js',
                    
'path' => "tabview/tabview${MIN}.js",
                    
'requires' => array ('element'),
                    
'optional' => array ('connection'),
                    
'skin' => "tabview/assets/skins/sam/tabview.css"
                
),

                
'treeview' => array (
                    
'type' => 'js',
                    
'path' => "treeview/treeview${MIN}.js",
                    
'requires' => array ('event'),
                    
'skin' => "treeview/assets/skins/sam/treeview.css"
                
),

                
'uploader' => array (
                    
'type' => 'js',
                    
'path' => "uploader/uploader-experimental.js",
                    
'requires' => array ('yahoo')
                ),

                
'yuitest' => array (
                    
'type' => 'js',
                    
'path' => "yuitest/yuitest${MIN}.js",
                    
'requires' => array ('logger'),
                    
'skin' => true
                
)

            );

        }


        
// function to clear the loading directives

        
function clear () {

            
// init the loadmap

            
$this->LOAD = array();
            foreach (
$this->YUIMAP as $key => $value) {
                
$this->LOAD["$key"] = 0;
            }
        }


        
// function to include a module and its dependencies

        
function includeModule ($id$options) {

            
// normalize the name

            
$id strtolower($id);

            
// have we already handled this module?

            
if ($this->LOAD["$id"] == 1) return;

            
// see if this is a known module

            
$this->LOAD["$id"] = 1;

            
// get any dependencies

            
if (isset($this->YUIMAP["$id"])) {

                
// load the required dependencies

                
if (isset($this->YUIMAP["$id"]['requires'])) {
                    if (
is_array($this->YUIMAP["$id"]['requires'])) {
                        foreach (
$this->YUIMAP["$id"]['requires'] as $key => $value) {
                            
$this->includeModule ($value$options);
                        }
                    }
                }

                
// load the optional dependencies

                
if ($options) {
                    if (isset(
$this->YUIMAP["$id"]['optional'])) {
                        if (
is_array($this->YUIMAP["$id"]['optional'])) {
                            foreach (
$this->YUIMAP["$id"]['optional'] as $key => $value) {
                                
$this->includeModule ($value$options);
                            }
                        }
                    }
                }

            }

        }


        
// function to load all the required libraries (and dependencies)

        
function loadLibrary ($modules$options) {

            global 
$SITEHOME;

            
// init the list of modules and assets we need

            
$this->clear();

            
// load the default module(s) -- these are the ones we always require

            
$this->includeModule ("reset-fonts-grids"$options);
            
$this->includeModule ("utilities"$options);

            
// include each of the additional modules we may need

            
if (is_array($modules)) {
                foreach (
$modules as $key => $value) {
                    
$this->includeModule ($value$options);
                }
            }

            
// remove unnecessary elements

            
foreach ($this->LOAD as $id => $value) {
                if (isset(
$this->YUIMAP["$id"])) {
                    if (isset(
$this->YUIMAP["$id"]['supersedes'])) {
                        if (
is_array($this->YUIMAP["$id"]['supersedes'])) {
                            foreach (
$this->YUIMAP["$id"]['supersedes'] as $key => $value) {
                                if (isset(
$this->LOAD["$value"])) $this->LOAD["$value"] = -1;
                            }
                        }
                    }
                }
            }

            
// what version of the library are we using?

            
$YUISOURCE "${SITEHOME}yui" str_replace(".","",$this->VERSION) . "/build/";

            
// generate the necessary includes to get what we want

            
$styles "";
            
$scripts "";

            foreach (
$this->LOAD as $id => $value) {
                if (
$value == 1) {
                    switch (
$this->YUIMAP["$id"]['type']) {
                        case 
'css':
                            
$styles .= "<link type=\"text/css\" rel=\"stylesheet\" href=\"$YUISOURCE$this->YUIMAP["$id"]['path'] . "\">\n";
                        break;
                        case 
'js':
                            
$scripts .= "<script type=\"text/javascript\" src=\"$YUISOURCE$this->YUIMAP["$id"]['path'] . "\"></script>\n";
                            if (isset(
$this->YUIMAP["$id"]['skin']) && is_string($this->YUIMAP["$id"]['skin'])) {
                                
$styles .= "<link type=\"text/css\" rel=\"stylesheet\" href=\"$YUISOURCE$this->YUIMAP["$id"]['skin'] . "\">\n";
                            }
                        break;
                    }
                }
            }

            
// output the includes

            //echo ("$styles\n$scripts\n");

            
echo ("<link type=\"text/css\" rel=\"stylesheet\" href=\"${YUISOURCE}reset-fonts-grids/reset-fonts-grids.css\">\n");
            echo (
"<link type=\"text/css\" rel=\"stylesheet\" href=\"${YUISOURCE}assets/skins/sam/skin.css\">\n");
            echo (
"$scripts\n");

        }


        
// function to generate all the necessary imports for the required features

        
function generateImports ($modules = -1$options true) {

            
// see if we have NO modules to load

            
if (is_int($modules)) return;

            
// init the module table

            
$this->initModuleTable();

            
// load the requested module(s)

            
if (is_string($modules)) {
                
$this->loadLibrary (array($modules), $options);
            }
            elseif (
is_array($modules)) {
                
$this->loadLibrary ($modules$options);
            }

        }


        
// function to generate the json for a menu

        
function generateAppMenuItems ($def = -1) {

            
// do we have something to do

            
if (!is_array($def)) return;

            
// how many menus are we doing

            
$count sizeof($def);
            if (
$count 1) return;

            
// de we need extra object levels?

            
$extraBrackets 0;
            for (
$i=0$i<$count && !$extraBrackets$i++) {
                
$caption $def[$i]["caption"];
                if (
substr($caption,0,2) == "--"$extraBrackets 1;
            }

            
// generate the json for this level

            
if ($extraBrackets == 1) echo ("[");

            for (
$i=0$i<$count$i++) {
                
$caption $def[$i]["caption"];
                
$id $def[$i]["id"];
                
$disabled = (isset($def[$i]["disabled"]) ? (int)$def[$i]["disabled"] : 0);
                
$checked = (isset($def[$i]["checked"]) ? (int)$def[$i]["checked"] : 0);
                
$selected = (isset($def[$i]["selected"]) ? (int)$def[$i]["selected"] : 0);
                
$target = (isset($def[$i]["target"]) ? (int)$def[$i]["target"] : "");
                
$items $def[$i]["items"];
                if (
is_array($items)) {
                    echo (
"{ text:\"$caption\"" . ($disabled != ", disabled:true" "") . ($checked != ", checked:true" "") . ($selected != ", selected:true" "") . ($target != "" ", target:\"$target\"" "") . ", submenu:{ " . ($id != "" "id:\"$id\", " "") . "itemdata:[\n");
                    
$this->generateAppMenuItems($items);
                    echo (
"\n]}\n");
                    echo (
"}");
                    echo ((
$i < ($count-1) ? "," "") . "\n");
                }
                elseif (
is_string($items)) {
                    if (
substr($caption,0,2) != "--") {
                        echo (
"{ text:\"$caption\"" . ($disabled != ", disabled:true" "") . ($checked != ", checked:true" "") . ($selected != ", selected:true" "") . ($target != "" ", target:\"$target\"" "") . ($items != "" ", url:\"$items\"" "") . " }");
                        if (
$i $count-1) {
                            if (
substr($def[$i+1]["caption"],0,2) == "--") {
                                echo (
"\n],[\n");
                            }
                            else {
                                echo (
",\n");
                            }
                        }
                    }
                }
            }

            if (
$extraBrackets == 1) echo ("]\n");

        }


        
// function to generate an app menu bar (at the top) of the page

        
function generateAppMenu ($MENUS = -1$LEFT 0$TOP 0) {

            
// make sure we got something to define

            
if (!is_array($MENUS)) return;

            
// build the definition code for the menu

            
echo ("<scr"."ipt type=\"text/javascript\">\n");
            echo (
"<!--\n");
            echo (
"addAppMenu = function (stype) {\n");
            echo (
"var menudef = [\n\n");
            
$this->generateAppMenuItems($MENUS);
            echo (
"\n];\n");
            echo (
"var menuBar = new YAHOO.widget.MenuBar(\"appmenu\", { x:\"${LEFT}px\", y:$TOP, zIndex:1000, lazyload:false, hidedelay:1000 });\n");
            echo (
"menuBar.addItems (menudef);\n");
            echo (
"menuBar.render('menudiv');\n");
            echo (
"}\n");
            echo (
"//-->\n");
            echo (
"</scr"."ipt>\n");

        }


        
// function to spit out the table navigatotr buttons, etc

        
function generateTableNavigator ($nameext$data$table$pager$slider=false$extrabuttons="") {

            global 
$IMGDIR;

            
$pagelist = ($slider ",'selPages$nameext'" "");
            echo (
"<table cellpadding=\"0\" cellspacing=\"0\"><tr>");
            echo (
"<td valign=\"middle\"><button id=\"cmdStart$nameext\" onclick=\"tableManager_Navigate(1,$pager,$data,$table$pagelist)\"><img src=\"${IMGDIR}lft2.gif\"> First</button></td>\n");
            echo (
"<td valign=\"middle\"><button id=\"cmdPrev$nameext\" onclick=\"tableManager_Navigate(2,$pager,$data,$table$pagelist)\"><img src=\"${IMGDIR}lft1.gif\"> Prev</button></td>\n");
            if (
$slider) echo ("<td valign=\"middle\"><img src=\"${IMGDIR}t_page.gif\"></td><td valign=\"middle\"><select id=\"selPages$nameext\" onchange=\"tableManager_Navigate(5,$pager,$data,$table,'selPages$nameext',this.options[this.selectedIndex].value)\"><option value=\"0\">0</option></select>&nbsp;</td>\n");
            echo (
"<td valign=\"middle\"><button id=\"cmdNext$nameext\" onclick=\"tableManager_Navigate(3,$pager,$data,$table$pagelist)\">Next <img src=\"${IMGDIR}rt1.gif\"></button></td>\n");
            echo (
"<td valign=\"middle\"><button id=\"cmdEnd$nameext\" onclick=\"tableManager_Navigate(4,$pager,$data,$table$pagelist)\">Last <img src=\"${IMGDIR}rt2.gif\"></button></td>\n");
            if (
is_array($extrabuttons)) {
                for (
$i=0$i<sizeof($extrabuttons); $i++) echo ("<td valign=\"middle\">".$extrabuttons[$i]."</td>\n");
            }
            elseif (
is_string($extrabuttons)) {
                if (
$extrabuttons != "") {
                    echo (
"<td valign=\"middle\">$extrabuttons</td>\n");
                }
            }
            echo (
"</table>\n");

        }

        
// class initialization

        
function CYUIWrapper ($modules = -1) {

            
// import any modules required

            //$this->VERSION = "2.5.1";
            //$this->VERSION = "2.6.0";
            
$this->VERSION "2.7.0";
            
$this->generateImports ($modules);

        }

    }


?>
1

This class was created back in YUI 2.2 (or so), and has been recently revved up to 2.6, but may not include anything completely new or different in 2.6 yet (I have used it extensively up to YUI 2.5.1, and am using it with no problem now in 2.6)! This help page is actually loading the live script (PHP) code I use, so any changes to it will always be immediately reflected on this page!


One little warning (or hint if you will): the order that the elements is listed is important to how the class decides what to include! If you take this and move things around (or add things) in the "wrong" order, you can cause the wrong modules to load (or to load in the wrong order).