Source of file HeadJsBackend.php
Size: 8,526 Bytes - Last Modified: 2021-12-23T10:37:55+00:00
/var/www/docs.ssmods.com/process/src/code/HeadJsBackend.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 | <?php class HeadJsBackend extends Requirements_Backend { public $write_js_to_body = false; public static $do_not_wrap = array(); /** * Store all relevant callbacks for onLoad of files here * @var array */ public $callbacks = array(); /** * Helper method to know if we are in the admin * @return bool */ public function isBackendController() { return is_subclass_of(Controller::curr(), "LeftAndMain"); } /** * Do not wrap in head.ready a given customScript * @param string $code */ public static function doNotWrap($code) { self::$do_not_wrap[] = $code; } /** * Show the name of files in includes * @return boolean */ public static function getNamedFiles() { return Config::inst()->get('HeadJsBackend', 'named_files'); } /** * Get the CDN source for headjs * @return string */ public static function getCdnSource() { return Config::inst()->get('HeadJsBackend', 'cdn_source'); } /** * Get the local filesystem source * @return string */ public static function getJavascriptSource() { return Config::inst()->get('HeadJsBackend', 'javascript_source'); } /** * Get the head js url * @return string */ public static function getHeadJsUrl() { if (self::getJavascriptSource()) { return self::getJavascriptSource(); } return self::getCdnSource(); } /* * Add a callback to the file load after HeadJS has load()'ed the file * @param string $fileOrID */ public function add_callback($fileOrID, $callback) { $this->callbacks[$fileOrID] = $callback; } /** * Remove all the callbacks associated with $fileOrID * @param string $fileOrID */ public function remove_callback($fileOrID){ if(isset($this->callbacks[$fileOrID])) unset($this->callbacks[$fileOrID]); } /** * Get all the callbacks associated with $fileOrID * @param string $fileOrID */ public function get_callback($fileOrID){ if(isset($this->callbacks[$fileOrID])) return $this->callbacks[$fileOrID]; return false; } /** * Add a dependency for a file or path * @param string $child - the file or path of a file that should be loaded after the $parent * @param string $parent - the file or path that is required for the $child to work */ public function add_dependency($child, $parent) { if(array_key_exists($child, $this->css) || array_key_exists($child, $this->javascript)){ $path = Convert::raw2xml($this->path_for_file($child)); }elseif(array_key_exists($child, $this->customCSS) || array_key_exists($child, $this->customScript)){ $code = (array_key_exists($child, $this->customCSS))?$this->customCSS[$child]:$this->customScript[$child]; }else{ $path = $child; } $path = (isset($path))?str_replace('&', '&', $path):false; $this->block($child); if(isset($code)) $this->add_callback($parent, $code); else $this->add_callback($parent, "head.load(\"" . $path . "\");\n"); } /** * Update the given HTML content with the appropriate include tags for the registered * requirements. Needs to receive a valid HTML/XHTML template in the $content parameter, * including a <head> tag. The requirements will insert before the closing <head> tag automatically. * * @todo Calculate $prefix properly * * @param string $templateFilePath Absolute path for the *.ss template file * @param string $content HTML content that has already been parsed from the $templateFilePath through {@link SSViewer}. * @return string HTML content thats augumented with the requirements before the closing <head> tag. */ function includeInHTML($templateFile, $content) { if ($this->isBackendController()) { //currently, it's not loading tinymce otherwise return parent::includeInHTML($templateFile, $content); } $hasHead = (strpos($content, '</head>') !== false || strpos($content, '</head ') !== false); $hasRequirements = ($this->css || $this->javascript || $this->customCSS || $this->customScript || $this->customHeadTags); if (!$hasHead || !$hasRequirements) { return $content; } $script_template = "<script type=\"text/javascript\">\n//<![CDATA[\n". "%s" . "\n//]]>\n</script>\n"; $ready_template = "head.ready(function() {\n" . "%s" . "\n});\n"; $readyRequirements = $cleanRequirements = ''; // Include HeadJS, the only script in your head $headerRequirements = "<script type=\"text/javascript\" src=\"" . self::getHeadJsUrl() . "\"></script>\n"; // Combine files - updates $this->javascript and $this->css $this->process_combined_files(); $named_files = self::getNamedFiles(); // add the css requirements, even allow a callback $cssFiles = array_diff_key($this->css, $this->blocked); if (!empty($cssFiles)) { foreach ($cssFiles as $file => $params) { $name = str_replace('-','',basename($file, '.css')); $path = Convert::raw2xml($this->path_for_file($file)); if ($path) { if((isset($params['media']) && !empty($params['media']))){ $headerRequirements .= "<link rel=\"stylesheet\" type=\"text/css\" media=\"{$params['media']}\" href=\"$path\" />\n"; }else{ $path = str_replace('&', '&', $path); if($named_files) { $path = $name . '":"' . $path; } $callback = (($this->get_callback($file))?", function(){".$this->get_callback($file)."}":""); $readyRequirements .= "head.load(\"" . $path . "\"{$callback});\n"; } } } } $jsFiles = array_diff_key($this->javascript, $this->blocked); if (!empty($jsFiles)) { foreach ($jsFiles as $file => $dummy) { $name = str_replace('-','',basename($file, '.js')); $path = Convert::raw2xml($this->path_for_file($file)); $path = str_replace('&', '&', $path); if ($path) { if($named_files) { $path = $name . '":"' . $path; } $callback = (($this->get_callback($file))?", function(){".$this->get_callback($file)."}":""); $readyRequirements .= "head.load(\"" . $path . "\"{$callback});\n"; } } } // @todo: store all css files in arrays with media param as the key, then do a headjs test for each mediaparam // store all "custom" css in the header, because this may have critical styling to fix FOUC issues $customCSS = array_diff_key($this->customCSS, $this->blocked); if (!empty($customCSS)) { foreach ($customCSS as $css) { $headerRequirements .= "<style type=\"text/css\">\n$css\n</style>\n"; } } // add all inline javascript *after* including external files which // they might rely on $customJS = array_diff_key($this->customScript, $this->blocked); if (!empty($customJS)) { foreach ($customJS as $script) { if(in_array($script, self::$do_not_wrap)){ $cleanRequirements .= $script; }else{ $readyRequirements .= $script; } } } foreach (array_diff_key($this->customHeadTags, $this->blocked) as $customHeadTag) { $headerRequirements .= "$customHeadTag\n"; } // put the core js just before the </head> $content = preg_replace("/(<\/head>)/i", $headerRequirements . "\\1", $content); $readyRequirements = ($readyRequirements=="")?"":sprintf($ready_template, $readyRequirements); $readyRequirements = sprintf($script_template, $readyRequirements.$cleanRequirements); if ($this->force_js_to_bottom) { // Remove all newlines from code to preserve layout $readyRequirements = preg_replace('/>\n*/', '>', $readyRequirements); // We put script tags into the body, for performance. // We forcefully put it at the bottom instead of before // the first script-tag occurence $content = preg_replace("/(<\/body[^>]*>)/i", $readyRequirements . "\\1", $content); } elseif ($this->write_js_to_body) { // Remove all newlines from code to preserve layout $readyRequirements = preg_replace('/>\n*/', '>', $readyRequirements); // We put script tags into the body, for performance. // If your template already has script tags in the body, then we put our script // tags just before those. Otherwise, we put it at the bottom. $p2 = stripos($content, '<body'); $p1 = stripos($content, '<script', $p2); // @todo - should we move the inline script tags below everything else? // we could do this with regex, or a while loop... if ($p1 !== false) { $content = substr($content, 0, $p1) . $readyRequirements . substr($content, $p1); } else { $content = preg_replace("/(<\/body[^>]*>)/i", $readyRequirements . "\\1", $content); } } else { $content = preg_replace("/(<\/head>)/i", $readyRequirements . "\\1", $content); } return $content; } } |