/** * */ public function renderMaster() { // Build the master view if necessary if (in_array($this->_DeliveryType, array(DELIVERY_TYPE_ALL))) { $this->MasterView = $this->masterView(); // Only get css & ui components if this is NOT a syndication request if ($this->SyndicationMethod == SYNDICATION_NONE && is_object($this->Head)) { $CssAnchors = AssetModel::getAnchors(); $this->EventArguments['CssFiles'] =& $this->_CssFiles; $this->fireEvent('BeforeAddCss'); $ETag = AssetModel::eTag(); $CombineAssets = c('Garden.CombineAssets'); $ThemeType = isMobile() ? 'mobile' : 'desktop'; // And now search for/add all css files. foreach ($this->_CssFiles as $CssInfo) { $CssFile = $CssInfo['FileName']; if (!array_key_exists('Options', $CssInfo) || !is_array($CssInfo['Options'])) { $CssInfo['Options'] = array(); } $Options =& $CssInfo['Options']; // style.css and admin.css deserve some custom processing. if (in_array($CssFile, $CssAnchors)) { if (!$CombineAssets) { // Grab all of the css files from the asset model. $AssetModel = new AssetModel(); $CssFiles = $AssetModel->getCssFiles($ThemeType, ucfirst(substr($CssFile, 0, -4)), $ETag); foreach ($CssFiles as $Info) { $this->Head->addCss($Info[1], 'all', true, $CssInfo); } } else { $Basename = substr($CssFile, 0, -4); $this->Head->addCss(url("/asset/css/{$ThemeType}/{$Basename}-{$ETag}.css", '//'), 'all', false, $CssInfo['Options']); } continue; } $AppFolder = $CssInfo['AppFolder']; $LookupFolder = !empty($AppFolder) ? $AppFolder : $this->ApplicationFolder; $Search = AssetModel::CssPath($CssFile, $LookupFolder, $ThemeType); if (!$Search) { continue; } list($Path, $UrlPath) = $Search; if (isUrl($Path)) { $this->Head->AddCss($Path, 'all', val('AddVersion', $Options, true), $Options); continue; } else { // Check to see if there is a CSS cacher. $CssCacher = Gdn::factory('CssCacher'); if (!is_null($CssCacher)) { $Path = $CssCacher->get($Path, $AppFolder); } if ($Path !== false) { $Path = substr($Path, strlen(PATH_ROOT)); $Path = str_replace(DS, '/', $Path); $this->Head->addCss($Path, 'all', true, $Options); } } } // Add a custom js file. if (arrayHasValue($this->_CssFiles, 'style.css')) { $this->addJsFile('custom.js'); // only to non-admin pages. } $Cdns = array(); if (!c('Garden.Cdns.Disable', false)) { $Cdns = array('jquery.js' => "//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"); } // And now search for/add all JS files. $this->EventArguments['Cdns'] =& $Cdns; $this->fireEvent('AfterJsCdns'); $this->Head->addScript('', 'text/javascript', false, array('content' => $this->definitionList(false))); foreach ($this->_JsFiles as $Index => $JsInfo) { $JsFile = $JsInfo['FileName']; if (!is_array($JsInfo['Options'])) { $JsInfo['Options'] = array(); } $Options =& $JsInfo['Options']; if (isset($Cdns[$JsFile])) { $JsFile = $Cdns[$JsFile]; } $AppFolder = $JsInfo['AppFolder']; $LookupFolder = !empty($AppFolder) ? $AppFolder : $this->ApplicationFolder; $Search = AssetModel::JsPath($JsFile, $LookupFolder, $ThemeType); if (!$Search) { continue; } list($Path, $UrlPath) = $Search; if ($Path !== false) { $AddVersion = true; if (!isUrl($Path)) { $Path = substr($Path, strlen(PATH_ROOT)); $Path = str_replace(DS, '/', $Path); $AddVersion = val('AddVersion', $Options, true); } $this->Head->addScript($Path, 'text/javascript', $AddVersion, $Options); continue; } } } // Add the favicon. $Favicon = C('Garden.FavIcon'); if ($Favicon) { $this->Head->setFavIcon(Gdn_Upload::url($Favicon)); } // Make sure the head module gets passed into the assets collection. $this->addModule('Head'); } // Master views come from one of four places: $MasterViewPaths = array(); if (strpos($this->MasterView, '/') !== false) { $MasterViewPaths[] = combinePaths(array(PATH_ROOT, str_replace('/', DS, $this->MasterView) . '.master*')); } else { if ($this->Theme) { // 1. Application-specific theme view. eg. root/themes/theme_name/app_name/views/ $MasterViewPaths[] = combinePaths(array(PATH_THEMES, $this->Theme, $this->ApplicationFolder, 'views', $this->MasterView . '.master*')); // 2. Garden-wide theme view. eg. /path/to/application/themes/theme_name/views/ $MasterViewPaths[] = combinePaths(array(PATH_THEMES, $this->Theme, 'views', $this->MasterView . '.master*')); } // 3. Plugin default. eg. root/plugin_name/views/ $MasterViewPaths[] = combinePaths(array(PATH_ROOT, $this->ApplicationFolder, 'views', $this->MasterView . '.master*')); // 4. Application default. eg. root/app_name/views/ $MasterViewPaths[] = combinePaths(array(PATH_APPLICATIONS, $this->ApplicationFolder, 'views', $this->MasterView . '.master*')); // 5. Garden default. eg. root/dashboard/views/ $MasterViewPaths[] = combinePaths(array(PATH_APPLICATIONS, 'dashboard', 'views', $this->MasterView . '.master*')); } // Find the first file that matches the path. $MasterViewPath = false; foreach ($MasterViewPaths as $Glob) { $Paths = safeGlob($Glob); if (is_array($Paths) && count($Paths) > 0) { $MasterViewPath = $Paths[0]; break; } } $this->EventArguments['MasterViewPath'] =& $MasterViewPath; $this->fireEvent('BeforeFetchMaster'); if ($MasterViewPath === false) { trigger_error(errorMessage("Could not find master view: {$this->MasterView}.master*", $this->ClassName, '_FetchController'), E_USER_ERROR); } /// A unique identifier that can be used in the body tag of the master view if needed. $ControllerName = $this->ClassName; // Strip "Controller" from the body identifier. if (substr($ControllerName, -10) == 'Controller') { $ControllerName = substr($ControllerName, 0, -10); } // Strip "Gdn_" from the body identifier. if (substr($ControllerName, 0, 4) == 'Gdn_') { $ControllerName = substr($ControllerName, 4); } $this->setData('CssClass', $this->Application . ' ' . $ControllerName . ' ' . $this->RequestMethod . ' ' . $this->CssClass, true); // Check to see if there is a handler for this particular extension. $ViewHandler = Gdn::factory('ViewHandler' . strtolower(strrchr($MasterViewPath, '.'))); if (is_null($ViewHandler)) { $BodyIdentifier = strtolower($this->ApplicationFolder . '_' . $ControllerName . '_' . Gdn_Format::alphaNumeric(strtolower($this->RequestMethod))); include $MasterViewPath; } else { $ViewHandler->render($MasterViewPath, $this); } }
/** * Resolve relative static resources into full paths * * This method is used to translate CSS, Js and Template relative file lists * into absolute paths. * * Element values should conform to the following format: * * [] => array( * 'FileName' => // filename (relative, absolute, or URL) * 'AppFolder' => // optional application folder to target (default controller app) * ); * * @param array $resourceList * @param string $stub * @param array $options Optional. List of check options. * - 'GlobalLibrary' // Check $Stub/library in global section * - 'StripRoot' // Strip PATH_ROOT from final results * - 'CDNS' // List of external CDN replacements * @param array $checkLocations Optional. List of locations to check. * - 'themes' * - 'plugins' * - 'applications' * - 'global' */ public static function resolveStaticResources($resourceList, $stub, $options = null, $checkLocations = null) { // All locations by default if (!is_array($checkLocations)) { $checkLocations = array('themes', 'plugins', 'applications', 'global'); } // Default options $defaultOptions = array('GlobalLibrary' => true, 'StripRoot' => true, 'CDNS' => array(), 'AutoVersion' => true); if (!is_array($options)) { $options = array(); } $options = array_merge($defaultOptions, $options); // Parse options $checkGlobalLibrary = val('GlobalLibrary', $options); $stripRoot = val('StripRoot', $options); $autoDetectVersion = val('AutoVersion', $options); // See if we're allowing any CDN replacements $CDNs = val('CDNS', $options, array()); // Pre-get controller info $controllerAppFolder = false; $controllerTheme = false; if (Gdn::Controller() instanceof Gdn_Controller) { $controllerAppFolder = Gdn::controller()->ApplicationFolder; $controllerTheme = Gdn::controller()->Theme; } $fileList = array(); foreach ($resourceList as $index => $resourceInfo) { $resourceFile = $resourceInfo['FileName']; $resourceFolder = val('AppFolder', $resourceInfo); $resourceOptions = (array) val('Options', $resourceInfo, false); if ($resourceFile === false) { if (!$resourceOptions) { continue; } $rawCSS = val('Css', $resourceOptions, false); if (!$rawCSS) { continue; } $cssHash = md5($rawCSS); $fileList[$resourceFolder] = array('options' => $resourceOptions); continue; } $skipFileCheck = false; // Resolve CDN resources if (array_key_exists($resourceFile, $CDNs)) { $resourceFile = $CDNs[$resourceFile]; } if (strpos($resourceFile, '//') !== false) { // This is a link to an external file. $skipFileCheck = true; $testPaths = array($resourceFile); } elseif (strpos($resourceFile, '/') === 0) { // A direct path to the file was given. $testPaths = array(paths(PATH_ROOT, $resourceFile)); } elseif (strpos($resourceFile, '~') === 0) { $skipFileCheck = true; $resourceFile = substr($resourceFile, 1); $testPaths = array(paths(PATH_ROOT, $resourceFile)); } else { // Relative path $appFolder = val('AppFolder', $resourceInfo, false); if ($appFolder == '') { $appFolder = $controllerAppFolder; } if ($appFolder == 'false') { $appFolder = false; } // Resources can come from: // - a theme // - an application // - a plugin // - global garden resource-specific folder // - global garden resource-specific library folder $testPaths = array(); // Theme if (in_array('themes', $checkLocations) && $controllerTheme) { // Application-specific theme override if ($appFolder) { $testPaths[] = paths(PATH_THEMES, $controllerTheme, $appFolder, $stub, $resourceFile); } // Garden-wide theme override $testPaths[] = paths(PATH_THEMES, $controllerTheme, $stub, $resourceFile); } // Application or plugin $isPluginFolder = stringBeginsWith(trim($appFolder, '/'), 'plugins/', true, false); if ($isPluginFolder) { $pluginFolder = stringBeginsWith(trim($appFolder, '/'), 'plugins/', true, true); } if (in_array('plugins', $checkLocations) && $isPluginFolder) { // Plugin $testPaths[] = paths(PATH_PLUGINS, $pluginFolder, $stub, $resourceFile); $testPaths[] = paths(PATH_PLUGINS, $pluginFolder, $resourceFile); } if (in_array('applications', $checkLocations) && !$isPluginFolder) { // Application if ($appFolder) { $testPaths[] = paths(PATH_APPLICATIONS, $appFolder, $stub, $resourceFile); } // Dashboard app is added by default if ($appFolder != 'dashboard') { $testPaths[] = paths(PATH_APPLICATIONS, 'dashboard', $stub, $resourceFile); } } if (in_array('global', $checkLocations)) { // Global folder. eg. root/js/ $testPaths[] = paths(PATH_ROOT, $stub, $resourceFile); if ($checkGlobalLibrary) { // Global library folder. eg. root/js/library/ $testPaths[] = paths(PATH_ROOT, $stub, 'library', $resourceFile); } } } // Find the first file that matches the path. $resourcePath = false; if (!$skipFileCheck) { foreach ($testPaths as $glob) { $paths = safeGlob($glob); if (is_array($paths) && count($paths) > 0) { $resourcePath = $paths[0]; break; } } // Get version $version = val('Version', $resourceInfo, false); // If a path was matched, make sure it has a version if ($resourcePath && !$version && $autoDetectVersion) { // Theme file if (!$version && preg_match('`themes/([^/]+)/`i', $resourcePath, $matches)) { $themeName = $matches[1]; $themeInfo = Gdn::themeManager()->getThemeInfo($themeName); $version = val('Version', $themeInfo); $versionSource = "theme {$themeName}"; } // Plugin file if (!$version && preg_match('`plugins/([^/]+)/`i', $resourcePath, $matches)) { $pluginName = $matches[1]; $pluginInfo = Gdn::pluginManager()->getPluginInfo($pluginName, Gdn_PluginManager::ACCESS_PLUGINNAME); $version = val('Version', $pluginInfo); $versionSource = "plugin {$pluginName}"; } // Application file if (!$version && preg_match('`applications/([^/]+)/`i', $resourcePath, $matches)) { $applicationName = $matches[1]; $applicationInfo = Gdn::applicationManager()->getApplicationInfo($applicationName); $version = val('Version', $applicationInfo); $versionSource = "app {$applicationName}"; } } } else { $version = null; } // Global file if (!$version) { $version = APPLICATION_VERSION; } // If a path was succesfully matched if ($resourcePath !== false || $skipFileCheck) { // We enact SkipFileCheck for virtual paths, targeting controllers // perhaps, or full URLs from the CDN resolver. if ($skipFileCheck) { $resourcePath = array_pop($testPaths); } // Strip PATH_ROOT from absolute path $resourceResolved = $resourcePath; if ($stripRoot) { $resourceResolved = str_replace(array(PATH_ROOT, DS), array('', '/'), $resourcePath); } // Bring options into response structure $resource = array('path' => $resourcePath); $resourceOptions = (array) val('Options', $resourceInfo, array()); touchValue('version', $resource, $version); if ($resourceOptions) { touchValue('options', $resource, $resourceOptions); } $fileList[$resourceResolved] = $resource; } } return $fileList; }
/** * Crawl the various addons and locales for all of the applicable translation files. * * @param string[] $applicationWhiteList An array of enabled application folders. * @param string[] $pluginWhiteList An array of enabled plugin folders. * @return array Returns an array keyed by locale names where each value is an array of translation paths for that locale. */ public function crawlAllLocaleSources($applicationWhiteList, $pluginWhiteList) { $result = array(); // Get all of the locale files for the applications. $this->crawlAddonLocaleSources(PATH_APPLICATIONS, $applicationWhiteList, $result); // Get locale-based locale definition files. $enabledLocales = C('EnabledLocales'); if (is_array($enabledLocales)) { foreach ($enabledLocales as $localeKey => $locale) { $locale = self::canonicalize($locale); // Grab all of the files in the locale's folder. $translationPaths = safeGlob(PATH_ROOT . "/locales/{$localeKey}/*.php"); foreach ($translationPaths as $translationPath) { $result[$locale][] = $translationPath; } } } // Get all of the locale files for plugins. // Notice that the plugins are processed here so that they have overriding power. $this->crawlAddonLocaleSources(PATH_PLUGINS, $pluginWhiteList, $result); // Get theme-based locale definition files. $theme = C('Garden.Theme'); if ($theme) { $this->crawlAddonLocaleSources(PATH_THEMES, array($theme), $result); } // Look for a global locale. $configLocale = PATH_CONF . '/locale.php'; if (file_exists($configLocale)) { foreach (array_keys($result) as $locale) { $result[$locale][] = $configLocale; } } // Look for locale specific config locales. $paths = SafeGlob(PATH_CONF . '/locale-*.php'); foreach ($paths as $path) { if (preg_match('`^locale-([\\w-]+)$`i', basename($path, '.php'), $matches)) { $locale = self::canonicalize($matches[1]); $result[$locale][] = $path; } } return $result; }
/** * * * @param $Path * @param null $Skip * @return array */ public function loadDefinitions($Path, $Skip = null) { $Skip = (array) $Skip; $Paths = safeGlob($Path . '/*.php'); $Definition = array(); foreach ($Paths as $Path) { if (in_array($Path, $Skip)) { continue; } include $Path; } return $Definition; }