|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?PHP 00017 define('YUI_AFTER', 'after'); 00018 define('YUI_BASE', 'base'); 00019 define('YUI_CSS', 'css'); 00020 define('YUI_DATA', 'DATA'); 00021 define('YUI_DEPCACHE', 'depCache'); 00022 define('YUI_DEBUG', 'DEBUG'); 00023 define('YUI_EMBED', 'EMBED'); 00024 define('YUI_FILTERS', 'filters'); 00025 define('YUI_FULLPATH', 'fullpath'); 00026 define('YUI_FULLJSON', 'FULLJSON'); 00027 define('YUI_GLOBAL', 'global'); 00028 define('YUI_JS', 'js'); 00029 define('YUI_JSON', 'JSON'); 00030 define('YUI_MODULES', 'modules'); 00031 define('YUI_SUBMODULES', 'submodules'); 00032 define('YUI_EXPOUND', 'expound'); 00033 define('YUI_NAME', 'name'); 00034 define('YUI_OPTIONAL', 'optional'); 00035 define('YUI_OVERRIDES', 'overrides'); 00036 define('YUI_PATH', 'path'); 00037 define('YUI_PKG', 'pkg'); 00038 define('YUI_PREFIX', 'prefix'); 00039 define('YUI_PROVIDES', 'provides'); 00040 define('YUI_RAW', 'RAW'); 00041 define('YUI_REPLACE', 'replace'); 00042 define('YUI_REQUIRES', 'requires'); 00043 define('YUI_ROLLUP', 'rollup'); 00044 define('YUI_SATISFIES', 'satisfies'); 00045 define('YUI_SEARCH', 'search'); 00046 define('YUI_SKIN', 'skin'); 00047 define('YUI_SKINNABLE', 'skinnable'); 00048 define('YUI_SUPERSEDES', 'supersedes'); 00049 define('YUI_TAGS', 'TAGS'); 00050 define('YUI_TYPE', 'type'); 00051 define('YUI_URL', 'url'); 00052 00053 00059 class YAHOO_util_Loader { 00060 00067 var $base = ""; 00068 00078 var $filter = ""; 00079 00086 var $filters = array(); 00087 00095 var $filterList = null; 00096 00103 var $allowRollups = true; 00104 00111 var $loadOptional = false; 00112 00120 var $rollupsToTop = false; 00121 00129 var $processedModuleTypes = array(); 00130 00137 var $requests = array(); 00138 00145 var $loaded = array(); 00146 00153 var $superceded = array(); 00154 00161 var $undefined = array(); 00162 00169 var $dirty = true; 00170 00177 var $sorted = null; 00178 00185 var $accountedFor = array(); 00186 00193 var $skins = array(); 00194 00201 var $modules = array(); 00202 00209 var $fullCacheKey = null; 00210 00217 var $baseOverrides = array(); 00218 00225 var $cacheFound = false; 00226 00233 var $delayCache = false; 00234 00235 /* If the version is set, a querystring parameter is appended to the 00236 * end of all generated URLs. This is a cache busting hack for environments 00237 * that always use the same path for the current version of the library. 00238 * @property version 00239 * @type string 00240 * @default null 00241 */ 00242 var $version = null; 00243 var $versionKey = "_yuiversion"; 00244 00245 /* Holds the calculated skin definition 00246 * @property skin 00247 * @type array 00248 * @default 00249 */ 00250 var $skin = array(); 00251 00252 /* Holds the module rollup metadata 00253 * @property rollupModules 00254 * @type array 00255 * @default 00256 */ 00257 var $rollupModules = array(); 00258 00259 /* Holds global module information. Used for global dependency support. 00260 * Note: Does not appear to be in use by recent metadata. Might be deprecated? 00261 * @property globalModules 00262 * @type array 00263 * @default 00264 */ 00265 var $globalModules = array(); 00266 00267 /* Holds information about what modules satisfy the requirements of others 00268 * @property satisfactionMap 00269 * @type array 00270 * @default 00271 */ 00272 var $satisfactionMap = array(); 00273 00274 /* Holds a cached module dependency list 00275 * @property depCache 00276 * @type array 00277 * @default 00278 */ 00279 var $depCache = array(); 00280 00288 var $combine = false; 00289 00298 var $comboBase = "http://yui.yahooapis.com/combo?"; 00299 00308 var $cssComboLocation = null; 00309 00318 var $jsComboLocation = null; 00319 00330 function YAHOO_util_Loader($yuiVersion, $cacheKey=null, $modules=null, $noYUI=false) { 00331 if (!isset($yuiVersion)) { 00332 die("Error: The first parameter of YAHOO_util_Loader must specify which version of YUI to use!"); 00333 } 00334 00335 /* 00336 * Include the metadata config file that corresponds to the requested YUI version 00337 * Note: we attempt to find a prebuilt config_{version}.php file which contains an associative array, 00338 * but if not available we'll attempt to find and parse the YUI json dependency file. 00339 */ 00340 $parentDir = dirname(dirname(__FILE__)); 00341 $phpConfigFile = $parentDir . '/lib/meta/config_' . $yuiVersion . '.php'; 00342 $jsonConfigFile = $parentDir . '/lib/meta/json_' . $yuiVersion . '.txt'; 00343 00344 if (file_exists($phpConfigFile) && is_readable($phpConfigFile)) { 00345 require($phpConfigFile); 00346 } else if (file_exists($jsonConfigFile) && is_readable($jsonConfigFile) && function_exists('json_encode')) { 00347 $jsonConfigString = file_get_contents($jsonConfigFile); 00348 $inf = json_decode($jsonConfigString, true); 00349 $GLOBALS['yui_current'] = $inf; 00350 } else { 00351 die("Unable to find a suitable YUI metadata file!"); 00352 } 00353 00354 global $yui_current; 00355 00356 $this->apcttl = 0; 00357 $this->curlAvail = function_exists('curl_exec'); 00358 $this->apcAvail = function_exists('apc_fetch'); 00359 $this->jsonAvail = function_exists('json_encode'); 00360 $this->customModulesInUse = empty($modules) ? false : true; 00361 $this->base = $yui_current[YUI_BASE]; 00362 $this->comboDefaultVersion = $yuiVersion; 00363 $this->fullCacheKey = null; 00364 $cache = null; 00365 00366 if ($cacheKey && $this->apcAvail) { 00367 $this->fullCacheKey = $this->base . $cacheKey; 00368 $cache = apc_fetch($this->fullCacheKey); 00369 } 00370 00371 if ($cache) { 00372 $this->cacheFound = true; 00373 $this->modules = $cache[YUI_MODULES]; 00374 $this->skin = $cache[YUI_SKIN]; 00375 $this->rollupModules = $cache[YUI_ROLLUP]; 00376 $this->globalModules = $cache[YUI_GLOBAL]; 00377 $this->satisfactionMap = $cache[YUI_SATISFIES]; 00378 $this->depCache = $cache[YUI_DEPCACHE]; 00379 $this->filters = $cache[YUI_FILTERS]; 00380 } else { 00381 // set up the YUI info for the current version of the lib 00382 if ($noYUI) { 00383 $this->modules = array(); 00384 } else { 00385 $this->modules = $yui_current['moduleInfo']; 00386 } 00387 00388 if ($modules) { 00389 $this->modules = array_merge_recursive($this->modules, $modules); 00390 } 00391 00392 $this->skin = $yui_current[YUI_SKIN]; 00393 $this->skin['overrides'] = array(); 00394 $this->skin[YUI_PREFIX] = "skin-"; 00395 $this->filters = array( 00396 YUI_RAW => array( 00397 YUI_SEARCH => "/-min\.js/", 00398 YUI_REPLACE => ".js" 00399 ), 00400 YUI_DEBUG => array( 00401 YUI_SEARCH => "/-min\.js/", 00402 YUI_REPLACE => "-debug.js" 00403 ) 00404 ); 00405 00406 foreach ($this->modules as $name=>$m) { 00407 00408 if (isset($m[YUI_GLOBAL])) { 00409 $this->globalModules[$name] = true; 00410 } 00411 00412 if (isset($m[YUI_SUPERSEDES])) { 00413 $this->rollupModules[$name] = $m; 00414 foreach ($m[YUI_SUPERSEDES] as $sup) { 00415 $this->mapSatisfyingModule($sup, $name); 00416 } 00417 } 00418 } 00419 } 00420 } 00421 00426 function updateCache() { 00427 if ($this->fullCacheKey) { 00428 $cache = array(); 00429 $cache[YUI_MODULES] = $this->modules; 00430 $cache[YUI_SKIN] = $this->skin; 00431 $cache[YUI_ROLLUP] = $this->rollupModules; 00432 $cache[YUI_GLOBAL] = $this->globalModules; 00433 $cache[YUI_DEPCACHE] = $this->depCache; 00434 $cache[YUI_SATISFIES] = $this->satisfactionMap; 00435 $cache[YUI_FILTERS] = $this->filters; 00436 apc_store($this->fullCacheKey, $cache, $this->apcttl); 00437 } 00438 } 00439 00445 function load() { 00446 //Expects N-number of named components to load 00447 $args = func_get_args(); 00448 foreach ($args as $arg) { 00449 $this->loadSingle($arg); 00450 } 00451 } 00452 00458 function setProcessedModuleType($moduleType='ALL') { 00459 $this->processedModuleTypes[$moduleType] = true; 00460 } 00461 00467 function hasProcessedModuleType($moduleType='ALL') { 00468 return isset($this->processedModuleTypes[$moduleType]); 00469 } 00470 00476 function setLoaded() { 00477 $args = func_get_args(); 00478 00479 foreach ($args as $arg) { 00480 if (isset($this->modules[$arg])) { 00481 $this->loaded[$arg] = $arg; 00482 $mod = $this->modules[$arg]; 00483 00484 $sups = $this->getSuperceded($arg); 00485 // accounting for by way of supersede 00486 foreach ($sups as $supname=>$val) { 00487 $this->loaded[$supname] = $supname; 00488 } 00489 00490 // prevent rollups for this module type 00491 $this->setProcessedModuleType($mod[YUI_TYPE]); 00492 } else { 00493 $msg = "YUI_LOADER: undefined module name provided to setLoaded(): " . $arg; 00494 error_log($msg, 0); 00495 } 00496 } 00497 } 00498 00505 function skinSetup($name) { 00506 $skinName = null; 00507 $dep = $this->modules[$name]; 00508 00509 if ($dep && isset($dep[YUI_SKINNABLE])) { 00510 $s = $this->skin; 00511 00512 if (isset($s[YUI_OVERRIDES][$name])) { 00513 foreach ($s[YUI_OVERRIDES][$name] as $name2 => $over2) { 00514 $skinName = $this->formatSkin($over2, $name); 00515 } 00516 } else { 00517 $skinName = $this->formatSkin($s["defaultSkin"], $name); 00518 } 00519 00520 // adding new skin module 00521 $this->skins[] = $skinName; 00522 $skin = $this->parseSkin($skinName); 00523 00524 // module-specific 00525 if (isset($skin[2])) { 00526 $dep = $this->modules[$skin[2]]; 00527 $package = (isset($dep[YUI_PKG])) ? $dep[YUI_PKG] : $skin[2]; 00528 $path = $package . '/' . $s[YUI_BASE] . $skin[1] . '/' . $skin[2] . '.css'; 00529 $this->modules[$skinName] = array( 00530 "name" => $skinName, 00531 "type" => YUI_CSS, 00532 "path" => $path, 00533 "after" => $s[YUI_AFTER] 00534 ); 00535 00536 // rollup skin 00537 } else { 00538 $path = $s[YUI_BASE] . $skin[1] . '/' . $s[YUI_PATH]; 00539 $newmod = array( 00540 "name" => $skinName, 00541 "type" => YUI_CSS, 00542 "path" => $path, 00543 "rollup" => 3, 00544 "after" => $s[YUI_AFTER] 00545 ); 00546 $this->modules[$skinName] = $newmod; 00547 $this->rollupModules[$skinName] = $newmod; 00548 } 00549 00550 } 00551 00552 return $skinName; 00553 } 00554 00561 function parseSkin($moduleName) { 00562 if (strpos( $moduleName, $this->skin[YUI_PREFIX] ) === 0) { 00563 return explode('-', $moduleName); 00564 } 00565 00566 return null; 00567 } 00568 00576 function formatSkin($skin, $moduleName) { 00577 $prefix = $this->skin[YUI_PREFIX]; 00578 $s = $prefix . $skin; 00579 if ($moduleName) { 00580 $s = $s . '-' . $moduleName; 00581 } 00582 00583 return $s; 00584 } 00585 00592 function loadSingle($name) { 00593 $skin = $this->parseSkin($name); 00594 00595 if ($skin) { 00596 $this->skins[] = $name; 00597 $this->dirty = true; 00598 return true; 00599 } 00600 00601 if (!isset($this->modules[$name])) { 00602 $this -> undefined[$name] = $name; 00603 return false; 00604 } 00605 00606 if (isset($this->loaded[$name]) || isset($this->accountedFor[$name])) { 00607 // skip 00608 } else { 00609 $this->requests[$name] = $name; 00610 $this->dirty = true; 00611 } 00612 00613 return true; 00614 } 00615 00621 function script() { 00622 return $this->tags(YUI_JS); 00623 } 00624 00630 function css() { 00631 return $this->tags(YUI_CSS); 00632 } 00633 00641 function tags($moduleType=null, $skipSort=false) { 00642 return $this->processDependencies(YUI_TAGS, $moduleType, $skipSort); 00643 } 00644 00650 function script_embed() { 00651 return $this->embed(YUI_JS); 00652 } 00653 00659 function css_embed() { 00660 return $this->embed(YUI_CSS); 00661 } 00662 00670 function embed($moduleType=null, $skipSort=false) { 00671 return $this->processDependencies(YUI_EMBED, $moduleType, $skipSort); 00672 } 00673 00679 function script_data() { 00680 return $this->data(YUI_JS); 00681 } 00682 00688 function css_data() { 00689 return $this->data(YUI_CSS); 00690 } 00691 00700 function data($moduleType=null, $allowRollups=false, $skipSort=false) { 00701 if (!$allowRollups) { 00702 $this->setProcessedModuleType($moduleType); 00703 } 00704 00705 $type = YUI_DATA; 00706 00707 return $this->processDependencies($type, $moduleType, $skipSort); 00708 } 00709 00715 function script_json() { 00716 return $this->json(YUI_JS); 00717 } 00718 00724 function css_json() { 00725 return $this->json(YUI_CSS); 00726 } 00727 00737 function json($moduleType=null, $allowRollups=false, $skipSort=false, $full=false) { 00738 if (!$allowRollups) { 00739 $this->setProcessedModuleType($moduleType); 00740 } 00741 00742 // the original JSON output only sent the provides data, not the requires 00743 $type = YUI_JSON; 00744 00745 if ($full) { 00746 $type = YUI_FULLJSON; 00747 } 00748 00749 return $this->processDependencies($type, $moduleType, $skipSort); 00750 } 00751 00757 function script_raw() { 00758 return $this->raw(YUI_JS); 00759 } 00760 00766 function css_raw() { 00767 return $this->raw(YUI_CSS); 00768 } 00769 00778 function raw($moduleType=null, $allowRollups=false, $skipSort=false) { 00779 return $this->processDependencies(YUI_RAW, $moduleType, $skipSort); 00780 } 00781 00787 function log($msg) { 00788 error_log($msg, 0); 00789 } 00790 00796 function accountFor($name) { 00797 $this->accountedFor[$name] = $name; 00798 00799 if (isset($this->modules[$name])) { 00800 $dep = $this->modules[$name]; 00801 $sups = $this->getSuperceded($name); 00802 foreach ($sups as $supname=>$val) { 00803 // accounting for by way of supersede package 00804 $this->accountedFor[$supname] = true; 00805 } 00806 } 00807 } 00808 00816 function prune($deps, $moduleType) { 00817 if ($moduleType) { 00818 $newdeps = array(); 00819 foreach ($deps as $name=>$val) { 00820 $dep = $this->modules[$name]; 00821 if ($dep[YUI_TYPE] == $moduleType) { 00822 $newdeps[$name] = true; 00823 } 00824 } 00825 return $newdeps; 00826 } else { 00827 return $deps; 00828 } 00829 } 00830 00837 function getSuperceded($name) { 00838 $key = YUI_SUPERSEDES . $name; 00839 00840 if (isset($this->depCache[$key])) { 00841 return $this->depCache[$key]; 00842 } 00843 00844 $sups = array(); 00845 00846 if (isset($this->modules[$name])) { 00847 $m = $this->modules[$name]; 00848 if (isset($m[YUI_SUPERSEDES])) { 00849 foreach ($m[YUI_SUPERSEDES] as $supName) { 00850 $sups[$supName] = true; 00851 if (isset($this->modules[$supName])) { 00852 $supsups = $this->getSuperceded($supName); 00853 if (count($supsups) > 0) { 00854 $sups = array_merge($sups, $supsups); 00855 } 00856 } 00857 } 00858 } 00859 } 00860 00861 $this->depCache[$key] = $sups; 00862 return $sups; 00863 } 00864 00873 function getAllDependencies($mname, $loadOptional=false, $completed=array()) { 00874 $key = YUI_REQUIRES . $mname; 00875 if ($loadOptional) { 00876 $key .= YUI_OPTIONAL; 00877 } 00878 00879 if (isset($this->depCache[$key])) { 00880 return $this->depCache[$key]; 00881 } 00882 00883 $m = $this->modules[$mname]; 00884 $mProvides = $this->getProvides($mname); 00885 $reqs = array(); 00886 00887 //Some modules pretend to be others (override if this is the case) 00888 if (isset($this->modules[$mname][YUI_EXPOUND])) { 00889 if (!isset($completed[$mname])) { 00890 $reqs = array_merge($completed, $this->getAllDependencies($this->modules[$mname][YUI_EXPOUND], $loadOptional, array($mname => true))); 00891 } 00892 } 00893 00894 //Add any requirements defined on the module itself 00895 if (isset($m[YUI_REQUIRES])) { 00896 $origreqs = $m[YUI_REQUIRES]; 00897 foreach($origreqs as $r) { 00898 if (!isset($reqs[$r])) { 00899 $reqs[$r] = true; 00900 $reqs = array_merge($reqs, $this->getAllDependencies($r, $loadOptional, $reqs)); 00901 } 00902 } 00903 } 00904 00905 //Add any submodule requirements not provided by the rollups 00906 if (isset($m[YUI_SUBMODULES])) { 00907 foreach($m[YUI_SUBMODULES] as $submodule) { 00908 $subreqs = $submodule[YUI_REQUIRES]; 00909 foreach($subreqs as $sr) { 00910 if (!in_array($sr, $mProvides) && !in_array($sr, $this->accountedFor)) { 00911 if (!isset($reqs[$sr])) { 00912 $reqs[$sr] = true; 00913 $reqs = array_merge($reqs, $this->getAllDependencies($sr, $loadOptional, $reqs)); 00914 } 00915 } 00916 } 00917 } 00918 } 00919 00920 //Add any superseded requirements not provided by the rollup and/or rollup submodules 00921 if (isset($m[YUI_SUPERSEDES])) { 00922 foreach($m[YUI_SUPERSEDES] as $supersededModule) { 00923 if (isset($this->modules[$supersededModule][YUI_REQUIRES])) { 00924 foreach($this->modules[$supersededModule][YUI_REQUIRES] as $supersededModuleReq) { 00925 if (!in_array($supersededModuleReq, $mProvides)) { 00926 if (!isset($reqs[$supersededModuleReq])) { 00927 $reqs[$supersededModuleReq] = true; 00928 $reqs = array_merge($reqs, $this->getAllDependencies($supersededModuleReq, $loadOptional, $reqs)); 00929 } 00930 } 00931 } 00932 } 00933 00934 //Add any submodule requirements not provided by the rollup or originally requested module 00935 if (isset($this->modules[$supersededModule][YUI_SUBMODULES])) { 00936 foreach($this->modules[$supersededModule][YUI_SUBMODULES] as $supersededSubmodule) { 00937 $ssmProvides = $this->getProvides($supersededModule); 00938 $supersededSubreqs = $supersededSubmodule[YUI_REQUIRES]; 00939 foreach($supersededSubreqs as $ssr) { 00940 if (!in_array($ssr, $ssmProvides)) { 00941 if (!isset($reqs[$ssr])) { 00942 $reqs[$ssr] = true; 00943 $reqs = array_merge($reqs, $this->getAllDependencies($ssr, $loadOptional, $reqs)); 00944 } 00945 } 00946 } 00947 } 00948 } 00949 } 00950 } 00951 00952 if ($loadOptional && isset($m[YUI_OPTIONAL])) { 00953 $o = $m[YUI_OPTIONAL]; 00954 foreach($o as $opt) { 00955 $reqs[$opt] = true; 00956 } 00957 } 00958 00959 $this->depCache[$key] = $reqs; 00960 00961 return $reqs; 00962 } 00963 00964 // @todo restore global dependency support 00965 function getGlobalDependencies() { 00966 return $this->globalModules; 00967 } 00968 00973 function moduleSatisfies($satisfied, $satisfier) { 00974 if($satisfied == $satisfier) { 00975 return true; 00976 } 00977 00978 if (isset($this->satisfactionMap[$satisfied])) { 00979 $satisfiers = $this->satisfactionMap[$satisfied]; 00980 return isset($satisfiers[$satisfier]); 00981 } 00982 00983 return false; 00984 } 00985 00992 function overrideBase($base, $modules) { 00993 foreach ($modules as $name) { 00994 $this->baseOverrides[$name] = $base; 00995 } 00996 } 00997 01005 function listSatisfies($satisfied, $moduleList) { 01006 if (isset($moduleList[$satisfied])) { 01007 return true; 01008 } else { 01009 if (isset($this->satisfactionMap[$satisfied])) { 01010 $satisfiers = $this->satisfactionMap[$satisfied]; 01011 foreach ($satisfiers as $name=>$val) { 01012 if (isset($moduleList[$name])) { 01013 return true; 01014 } 01015 } 01016 } 01017 } 01018 01019 return false; 01020 } 01021 01029 function checkThreshold($module, $moduleList) { 01030 if (count($moduleList) > 0 && isset($module[YUI_ROLLUP])) { 01031 $matched = 0; 01032 $thresh = $module[YUI_ROLLUP]; 01033 foreach ($moduleList as $moduleName=>$moddef) { 01034 if (in_array($moduleName, $module[YUI_SUPERSEDES])) { 01035 $matched++; 01036 } 01037 } 01038 01039 return ($matched >= $thresh); 01040 } 01041 01042 return false; 01043 } 01044 01052 function sortDependencies($moduleType, $skipSort=false) { 01053 $reqs = array(); 01054 $top = array(); 01055 $bot = array(); 01056 $notdone = array(); 01057 $sorted = array(); 01058 $found = array(); 01059 01060 // add global dependenices so they are included when calculating rollups 01061 $globals = $this->getGlobalDependencies($moduleType); 01062 01063 foreach ($globals as $name=>$dep) { 01064 $reqs[$name] = true; 01065 } 01066 01067 // get and store the full list of dependencies. 01068 foreach ($this->requests as $name=>$val) { 01069 $reqs[$name] = true; 01070 $dep = $this->modules[$name]; 01071 $newreqs = $this->getAllDependencies($name, $this->loadOptional); 01072 01073 foreach ($newreqs as $newname=>$newval) { 01074 if (!isset($reqs[$newname])) { 01075 $reqs[$newname] = true; 01076 } 01077 } 01078 } 01079 01080 // if we skip the sort, we just return the list that includes everything that 01081 // was requested, all of their requirements, and global modules. This is 01082 // filtered by module type if supplied 01083 if ($skipSort) { 01084 return $this->prune($reqs, $moduleType); 01085 } 01086 01087 // if we are sorting again after new modules have been requested, we 01088 // do not rollup, and we can remove the accounted for modules 01089 if (count($this->accountedFor) > 0 || count($this->loaded) > 0) { 01090 foreach ($this->accountedFor as $name=>$val) { 01091 if (isset($reqs[$name])) { 01092 unset($reqs[$name]); 01093 } 01094 } 01095 01096 // removing satisfied req (loaded) 01097 foreach ($this->loaded as $name=>$val) { 01098 if (isset($reqs[$name])) { 01099 unset($reqs[$name]); 01100 } 01101 } 01102 } else if ($this->allowRollups) { 01103 // First we go through the meta-modules we know about to 01104 // see if the replacement threshold has been met. 01105 $rollups = $this->rollupModules; 01106 01107 if (count($rollups > 0)) { 01108 foreach ($rollups as $name => $rollup) { 01109 if (!isset($reqs[$name]) && $this->checkThreshold($rollup, $reqs) ) { 01110 $reqs[$name] = true; 01111 $dep = $this->modules[$name]; 01112 $newreqs = $this->getAllDependencies($name, $this->loadOptional, $reqs); 01113 foreach ($newreqs as $newname=>$newval) { 01114 if (!isset($reqs[$newname])) { 01115 $reqs[$newname] = true; 01116 } 01117 } 01118 } 01119 } 01120 } 01121 } 01122 01123 // clear out superceded packages 01124 foreach ($reqs as $name => $val) { 01125 $dep = $this->modules[$name]; 01126 01127 if (isset($dep[YUI_SUPERSEDES])) { 01128 $override = $dep[YUI_SUPERSEDES]; 01129 01130 foreach ($override as $i=>$val) { 01131 if (isset($reqs[$val])) { 01132 unset($reqs[$val]); 01133 } 01134 01135 if (isset($reqs[$i])) { 01136 unset($reqs[$i]); 01137 } 01138 } 01139 } 01140 } 01141 01142 // move globals to the top 01143 foreach ($reqs as $name => $val) { 01144 $dep = $this->modules[$name]; 01145 if (isset($dep[YUI_GLOBAL]) && $dep[YUI_GLOBAL]) { 01146 $top[$name] = $name; 01147 } else { 01148 $notdone[$name] = $name; 01149 } 01150 } 01151 01152 // merge new order if we have globals 01153 if (count($top > 0)) { 01154 $notdone = array_merge($top, $notdone); 01155 } 01156 01157 // keep track of what is accounted for 01158 foreach ($this->loaded as $name=>$module) { 01159 $this->accountFor($name); 01160 } 01161 01162 // keep going until everything is sorted 01163 $count = 0; 01164 while (count($notdone) > 0) { 01165 if ($count++ > 200) { 01166 $msg = "YUI_LOADER ERROR: sorting could not be completed, there may be a circular dependency"; 01167 error_log($msg, 0); 01168 return array_merge($sorted, $notdone); 01169 } 01170 01171 // each pass only processed what has not been completed 01172 foreach ($notdone as $name => $val) { 01173 $dep = $this->modules[$name]; 01174 $newreqs = $this->getAllDependencies($name, $this->loadOptional); 01175 $this->accountFor($name); 01176 01177 //Detect if this module needs to be included after another one of the upcoming dependencies 01178 if (isset($dep[YUI_AFTER])) { 01179 $after = $dep[YUI_AFTER]; 01180 01181 foreach($after as $a) { 01182 if (in_array($a, $notdone)) { 01183 $newreqs[$a] = true; 01184 } 01185 } 01186 } 01187 01188 if (!empty($newreqs)) { 01189 foreach ($newreqs as $depname=>$depval) { 01190 // check if the item is accounted for in the $done list 01191 if (isset($this->accountedFor[$depname]) || $this->listSatisfies($depname, $sorted)) { 01192 //unset($notdone[$depname]); 01193 } else { 01194 $tmp = array(); 01195 $found = false; 01196 foreach ($notdone as $newname => $newval) { 01197 if ($this->moduleSatisfies($depname, $newname)) { 01198 $tmp[$newname] = $newname; 01199 unset($notdone[$newname]); 01200 $found = true; 01201 break; // found something that takes care of the dependency, so jump out 01202 } 01203 } 01204 01205 if ($found) { 01206 // this should put the module that handles the dependency on top, immediately 01207 // over the the item with the missing dependency 01208 $notdone = array_merge($tmp, $notdone); 01209 } else { 01210 //Requirement was missing and not found within the current notdone list. Add and try again. 01211 $notdone[$depname] = $depname; 01212 } 01213 01214 break(2); // break out of this iteration so we can get the missed dependency 01215 } 01216 } 01217 } 01218 01219 $sorted[$name] = $name; 01220 unset($notdone[$name]); 01221 } 01222 } 01223 01224 //Deal with module skins 01225 foreach ($sorted as $name => $val) { 01226 $skinName = $this->skinSetup($name); 01227 } 01228 01229 if ( count($this->skins) > 0 ) { 01230 foreach ($this->skins as $name => $val) { 01231 $sorted[$val] = true; 01232 } 01233 } 01234 01235 $this->dirty = false; 01236 $this->sorted = $sorted; 01237 01238 // store the results, set clear the diry flag 01239 return $this->prune($sorted, $moduleType); 01240 } 01241 01242 function mapSatisfyingModule($satisfied, $satisfier) { 01243 if (!isset($this->satisfactionMap[$satisfied])) { 01244 $this->satisfactionMap[$satisfied] = array(); 01245 } 01246 01247 $this->satisfactionMap[$satisfied][$satisfier] = true; 01248 } 01249 01260 function processDependencies($outputType, $moduleType, $skipSort=false, $showLoaded=false) { 01261 $html = ''; 01262 01263 // sort the output with css on top unless the output type is json 01264 if ((!$moduleType) && (strpos($outputType, YUI_JSON) === false) && $outputType != YUI_DATA) { 01265 $this->delayCache = true; 01266 $css = $this->processDependencies($outputType, YUI_CSS, $skipSort, $showLoaded); 01267 $js = $this->processDependencies($outputType, YUI_JS, $skipSort, $showLoaded); 01268 01269 // If the data has not been cached, cache what we have 01270 if (!$this->cacheFound) { 01271 $this->updateCache(); 01272 } 01273 01274 return $css . $js; 01275 } 01276 01277 $json = array(); 01278 01279 if ($showLoaded || (!$this->dirty && count($this->sorted) > 0)) { 01280 $sorted = $this->prune($this->sorted, $moduleType); 01281 } else { 01282 $sorted = $this->sortDependencies($moduleType, $skipSort); 01283 } 01284 01285 foreach ($sorted as $name => $val) { 01286 if ($showLoaded || !isset($this->loaded[$name])) { 01287 $dep = $this->modules[$name]; 01288 // only generate the tag once 01289 switch ($outputType) { 01290 case YUI_EMBED: 01291 $html .= $this->getContent($name, $dep[YUI_TYPE])."\n"; 01292 break; 01293 case YUI_RAW: 01294 $html .= $this->getRaw($name)."\n"; 01295 break; 01296 case YUI_JSON: 01297 case YUI_DATA: 01298 //$json[$dep[YUI_TYPE]][$this->getUrl($name)] = $this->getProvides($name); 01299 $json[$dep[YUI_TYPE]][] = array( 01300 $this->getUrl($name) => $this->getProvides($name) 01301 ); 01302 break; 01303 case YUI_FULLJSON: 01304 $json[$dep[YUI_NAME]] = array(); 01305 $item = $json[$dep[YUI_NAME]]; 01306 $item[YUI_TYPE] = $dep[YUI_TYPE]; 01307 $item[YUI_URL] = $this->getUrl($name); 01308 $item[YUI_PROVIDES] = $this->getProvides($name); 01309 $item[YUI_REQUIRES] = $dep[YUI_REQUIRES]; 01310 $item[YUI_OPTIONAL] = $dep[YUI_OPTIONAL]; 01311 break; 01312 case YUI_TAGS: 01313 default: 01314 if ($this->combine === true && $this->customModulesInUse === false) { 01315 $this->addToCombo($name, $dep[YUI_TYPE]); 01316 $html = $this->getComboLink($dep[YUI_TYPE]); 01317 } else { 01318 $html .= $this->getLink($name, $dep[YUI_TYPE])."\n"; 01319 } 01320 } 01321 } 01322 } 01323 01324 // If the data has not been cached, and we are not running two 01325 // rotations for separating css and js, cache what we have 01326 if (!$this->cacheFound && !$this->delayCache) { 01327 $this->updateCache(); 01328 } 01329 01330 if (!empty($json)) { 01331 if ($this->canJSON()) { 01332 $html .= json_encode($json); 01333 } else { 01334 $html .= "<!-- JSON not available, request failed -->"; 01335 } 01336 } 01337 01338 // after the first pass we no longer try to use meta modules 01339 $this->setProcessedModuleType($moduleType); 01340 01341 // keep track of all the stuff we loaded so that we don't reload 01342 // scripts if the page makes multiple calls to tags 01343 $this->loaded = array_merge($this->loaded, $sorted); 01344 if ($this->combine === true) { 01345 $this->clearComboLink($outputType); 01346 } 01347 01348 // return the raw data structure 01349 if ($outputType == YUI_DATA) { 01350 return $json; 01351 } 01352 01353 if ( count($this->undefined) > 0 ) { 01354 $html .= "<!-- The following modules were requested but are not defined: " . join($this -> undefined, ",") . " -->\n"; 01355 } 01356 01357 return $html; 01358 } 01359 01365 function getUrl($name) { 01366 // figure out how to set targets and filters 01367 $url = ""; 01368 $b = $this->base; 01369 if (isset($this->baseOverrides[$name])) { 01370 $b = $this->baseOverrides[$name]; 01371 } 01372 01373 if (isset($this->modules[$name])) { 01374 $m = $this->modules[$name]; 01375 if (isset($m[YUI_FULLPATH])) { 01376 $url = $m[YUI_FULLPATH]; 01377 } else { 01378 $url = $b . $m[YUI_PATH]; 01379 } 01380 } else { 01381 $url = $b . $name; 01382 } 01383 01384 if ($this->filter) { 01385 if (count($this->filterList) > 0 && !isset($this->filterList[$name])) { 01386 // skip the filter 01387 } else if (isset($this->filters[$this->filter])) { 01388 $filter = $this->filters[$this->filter]; 01389 $url = preg_replace($filter[YUI_SEARCH], $filter[YUI_REPLACE], $url); 01390 } 01391 } 01392 01393 if ($this->version) { 01394 $pre = (strstr($url, '?')) ? '&' : '?'; 01395 $url .= $pre . $this->versionKey . '=' . $this->version; 01396 } 01397 01398 return $url; 01399 } 01400 01407 function getRemoteContent($url) { 01408 $remote_content = null; 01409 if ($this->apcAvail === true) { 01410 $remote_content = apc_fetch($url); 01411 } 01412 01413 if (!$remote_content) { 01414 if($this->curlAvail === true) { 01415 $ch = curl_init(); 01416 curl_setopt($ch, CURLOPT_URL, $url); 01417 curl_setopt($ch, CURLOPT_FAILONERROR, 1); 01418 01419 //Doesn't work in safe mode or with openbase_dir enabled, see http://au.php.net/manual/ro/function.curl-setopt.php#71313. 01420 $open_basedir = ini_get("open_basedir"); 01421 if (empty($open_basedir) && !ini_get('safe_mode')) { 01422 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);// allow redirects 01423 } 01424 01425 curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // return into a variable 01426 // curl_setopt($ch, CURLOPT_TIMEOUT, 3); // times out after 4s 01427 01428 $remote_content = curl_exec($ch); 01429 01430 // save the contents of the remote url for 30 minutes 01431 if ($this->apcAvail === true) { 01432 apc_store($url, $remote_content, $this->apcttl); 01433 } 01434 01435 curl_close ($ch); 01436 } else { 01437 $remote_content = "<!--// cURL was not detected, so the content cannot be fetched -->"; 01438 } 01439 } 01440 01441 return $remote_content; 01442 } 01443 01450 function getRaw($name) { 01451 if(!$this->curlAvail) { 01452 return "<!--// cURL was not detected, so the content cannot be fetched -->"; 01453 } 01454 01455 $url = $this->getUrl($name); 01456 return $this->getRemoteContent($url); 01457 } 01458 01466 function getContent($name, $type) { 01467 if(!$this->curlAvail) { 01468 return "<!--// cURL was not detected, so the content cannot be fetched/embedded -->" . $this->getLink($name, $type); 01469 } 01470 01471 $url = $this->getUrl($name); 01472 01473 if (!$url) { 01474 return '<!-- PATH FOR "'. $name . '" NOT SPECIFIED -->'; 01475 } else if ($type == YUI_CSS) { 01476 return '<style type="text/css">' . $this->getRemoteContent($url) . '</style>'; 01477 } else { 01478 return '<script type="text/javascript">' . $this->getRemoteContent($url) . '</script>'; 01479 } 01480 } 01481 01489 function getLink($name, $type) { 01490 $url = $this->getUrl($name); 01491 01492 if (!$url) { 01493 return '<!-- PATH FOR "'. $name . '" NOT SPECIFIED -->'; 01494 } else if ($type == YUI_CSS) { 01495 return '<link rel="stylesheet" type="text/css" href="' . $url . '" />'; 01496 } else { 01497 return '<script type="text/javascript" src="' . $url . '"></script>'; 01498 } 01499 } 01500 01507 function getComboLink($type) { 01508 $url = ''; 01509 01510 if ($type == YUI_CSS) { 01511 if ($this->cssComboLocation !== null) { 01512 $url = "<link rel=\"stylesheet\" type=\"text/css\" href=\"{$this->cssComboLocation}\" />"; 01513 } else { 01514 $url = "<!-- NO YUI CSS COMPONENTS IDENTIFIED -->"; 01515 } 01516 } else if ($type == YUI_JS) { 01517 if ($this->jsComboLocation !== null) { 01518 if ($this->cssComboLocation !== null) { 01519 $url = "\n"; 01520 } 01521 $url .= "<script type=\"text/javascript\" src=\"{$this->jsComboLocation}\"></script>"; 01522 } else { 01523 $url = "<!-- NO YUI JAVASCRIPT COMPONENTS IDENTIFIED -->"; 01524 } 01525 } 01526 01527 //Allow for RAW & DEBUG over minified default 01528 if ($this->filter) { 01529 if (count($this->filterList) > 0 && !isset($this->filterList[$name])) { 01530 // skip the filter 01531 } else if (isset($this->filters[$this->filter])) { 01532 $filter = $this->filters[$this->filter]; 01533 $url = preg_replace($filter[YUI_SEARCH], $filter[YUI_REPLACE], $url); 01534 } 01535 } 01536 01537 return $url; 01538 } 01539 01546 function clearComboLink($type) { 01547 if ($type == YUI_CSS) { 01548 $this->cssComboLocation = null; 01549 } else if ($type == YUI_JS) { 01550 $this->jsComboLocation = null; 01551 } else { 01552 $this->cssComboLocation = null; 01553 $this->jsComboLocation = null; 01554 } 01555 } 01556 01563 function addToCombo($name, $type) { 01564 $pathToModule = $this->comboDefaultVersion . '/build/' . $this->modules[$name][YUI_PATH]; 01565 if ($type == YUI_CSS) { 01566 //If this is the first css component then add the combo base path 01567 if ($this->cssComboLocation === null) { 01568 $this->cssComboLocation = $this->comboBase . $pathToModule; 01569 } else { 01570 //Prep for next component 01571 $this->cssComboLocation .= '&' . $pathToModule; 01572 } 01573 } else { 01574 //If this is the first js component then add the combo base path 01575 if ($this->jsComboLocation === null) { 01576 $this->jsComboLocation = $this->comboBase . $pathToModule; 01577 } else { 01578 //Prep for next component 01579 $this->jsComboLocation .= '&' . $pathToModule; 01580 } 01581 } 01582 } 01583 01589 function canJSON() { 01590 return $this->jsonAvail; 01591 } 01592 01599 function getProvides($name) { 01600 $p = array($name); 01601 if (isset($this->modules[$name])) { 01602 $m = $this->modules[$name]; 01603 if (isset($m[YUI_SUPERSEDES])) { 01604 foreach ($m[YUI_SUPERSEDES] as $i) { 01605 $p[] = $i; 01606 } 01607 } 01608 } 01609 01610 return $p; 01611 } 01612 01618 function getLoadedModules() { 01619 $loaded = array(); 01620 foreach ($this->loaded as $i=>$value) { 01621 if (isset($this->modules[$i])) { 01622 $dep = $this->modules[$i]; 01623 $loaded[$dep[YUI_TYPE]][] = array( 01624 $this->getUrl($i) => $this->getProvides($i) 01625 ); 01626 } else { 01627 $msg = "YUI_LOADER ERROR: encountered undefined module: " . $i; 01628 error_log($msg, 0); 01629 } 01630 } 01631 return $loaded; 01632 } 01633 01639 function getLoadedModulesAsJSON() { 01640 if (!$this->canJSON()) { 01641 return "{\"Error\", \"json library not available\"}"; 01642 } 01643 01644 return json_encode($this->getLoadedModules()); 01645 } 01646 } 01647 01648 ?>