public function filterLoad(AssetInterface $asset) { $lc = new \lessc(); if ($dir = $asset->getSourceDirectory()) { $lc->importDir = $dir; } foreach ($this->loadPaths as $loadPath) { $lc->addImportDir($loadPath); } foreach ($this->customFunctions as $name => $callable) { $lc->registerFunction($name, $callable); } if ($this->formatter) { $lc->setFormatter($this->formatter); } if (null !== $this->preserveComments) { $lc->setPreserveComments($this->preserveComments); } $asset->setContent($lc->parse($asset->getContent(), $this->presets)); }
/** * Compile less to css. Creates a cache-file of the last compiled less-file. * * This code is originally from the manual of lessphp. * * @param string $inputFile the filename of the less-file. * @param string $outputFile the filename of the css-file to be created. * @param array $config with configuration details. * * @return void */ function autoCompileLess($inputFile, $outputFile, $config) { $cacheFile = $inputFile . ".cache"; if (file_exists($cacheFile)) { $cache = unserialize(file_get_contents($cacheFile)); } else { $cache = $inputFile; } $less = new lessc(); // Add custom less functions if (isset($config['functions'])) { foreach ($config['functions'] as $key => $val) { $less->registerFunction($key, $val); } } // Add import dirs if (isset($config['imports'])) { foreach ($config['imports'] as $val) { $less->addImportDir($val); } } // Set output formatter if (isset($config['formatter'])) { $less->setFormatter($config['formatter']); } // Preserve comments if (isset($config['comments'])) { $less->setPreserveComments($config['comments']); } // Compile a new cache $newCache = $less->cachedCompile($cache); if (!is_array($cache) || $newCache["updated"] > $cache["updated"]) { file_put_contents($cacheFile, serialize($newCache)); file_put_contents($outputFile, $newCache['compiled']); } }
/** * @return lessc */ protected function _initProcessor() { // lazy load if (!class_exists('lessc')) { require_once dirname(__FILE__) . '/class.less.leafo.php'; } $less = new lessc(); if ($this->_isDebug()) { $formatter = new lessc_formatter_lessjs(); // configurate css view $formatter->openSingle = " { "; $formatter->closeSingle = "}\n"; $formatter->close = "}\n"; $formatter->indentChar = " "; $formatter->disableSingle = true; $formatter->breakSelectors = true; $formatter->assignSeparator = ": "; $formatter->selectorSeparator = ", "; } else { // compress mode $formatter = new lessc_formatter_compressed(); $formatter->closeSingle = "}\n"; $formatter->close = "}\n"; } // set formatter $less->setFormatter($formatter); $less->setPreserveComments(false); // add paths for imports $less->addImportDir($this->_tpl->lessFull); $less->addImportDir(JPATH_ROOT); // from php $less->setVariables(array('css' => str_replace($this->_tpl->baseurl, '', $this->_tpl->css), 'less' => str_replace($this->_tpl->baseurl, '', $this->_tpl->less), 'images' => str_replace($this->_tpl->baseurl, '', $this->_tpl->img), 'debug' => (int) $this->_isDebug())); // add custom functions $less->registerFunction('data-uri', array($this, 'lib_dataUri')); return $less; }
/** * Lessify the stylesheet and return the href of the compiled file * * @param string $src Source URL of the file to be parsed * @param string $handle An identifier for the file used to create the file name in the cache * @return string URL of the compiled stylesheet */ public function parse_stylesheet($src, $handle) { // we only want to handle .less files if (!preg_match('/\\.less(\\.php)?$/', preg_replace('/\\?.*$/', '', $src))) { return $src; } // get file path from $src if (!strstr($src, '?')) { $src .= '?'; } // prevent non-existent index warning when using list() & explode() // Match the URL schemes between WP_CONTENT_URL and $src, // so the str_replace further down will work $src_scheme = parse_url($src, PHP_URL_SCHEME); $wp_content_url_scheme = parse_url(WP_CONTENT_URL, PHP_URL_SCHEME); if ($src_scheme != $wp_content_url_scheme) { $src = set_url_scheme($src, $wp_content_url_scheme); } list($less_path, $query_string) = explode('?', str_replace(WP_CONTENT_URL, WP_CONTENT_DIR, $src)); // output css file name $css_path = trailingslashit($this->get_cache_dir()) . "{$handle}.css"; // automatically regenerate files if source's modified time has changed or vars have changed try { // initialise the parser $less = new lessc(); // load the cache $cache_path = "{$css_path}.cache"; if (file_exists($cache_path)) { $cache = unserialize(file_get_contents($cache_path)); } // vars to pass into the compiler - default @themeurl var for image urls etc... $this->vars['themeurl'] = '~"' . get_stylesheet_directory_uri() . '"'; $this->vars['lessurl'] = '~"' . dirname($src) . '"'; $this->vars = apply_filters('less_vars', $this->vars, $handle); // If the cache or root path in it are invalid then regenerate if (empty($cache) || empty($cache['less']['root']) || !file_exists($cache['less']['root'])) { $cache = array('vars' => $this->vars, 'less' => $less_path); } // less config $less->setFormatter(apply_filters('less_compression', $this->compression)); $less->setPreserveComments(apply_filters('less_preserve_comments', $this->preserve_comments)); $less->setVariables($this->vars); // add directories to scan for imports $import_dirs = apply_filters('less_import_dirs', $this->import_dirs); if (!empty($import_dirs)) { foreach ((array) $import_dirs as $dir) { $less->addImportDir($dir); } } // register and unregister functions foreach ($this->registered_functions as $name => $callable) { $less->registerFunction($name, $callable); } foreach ($this->unregistered_functions as $name) { $less->unregisterFunction($name); } // allow devs to mess around with the less object configuration do_action_ref_array('lessc', array(&$less)); // $less->cachedCompile only checks for changed file modification times // if using the theme customiser (changed variables not files) then force a compile if ($this->vars !== $cache['vars']) { $force = true; } else { $force = false; } $less_cache = $less->cachedCompile($cache['less'], apply_filters('less_force_compile', $force)); if (empty($cache) || empty($cache['less']['updated']) || $less_cache['updated'] > $cache['less']['updated'] || $this->vars !== $cache['vars']) { file_put_contents($cache_path, serialize(array('vars' => $this->vars, 'less' => $less_cache))); file_put_contents($css_path, $less_cache['compiled']); } } catch (exception $ex) { wp_die($ex->getMessage()); } // restore query string it had if any $url = trailingslashit($this->get_cache_dir(false)) . "{$handle}.css" . (!empty($query_string) ? "?{$query_string}" : ''); // restore original url scheme $url = set_url_scheme($url, $src_scheme); return add_query_arg('ver', $less_cache['updated'], $url); }
/** * Lessify the stylesheet and return the href of the compiled file * * @param string $src Source URL of the file to be parsed * @param string $handle An identifier for the file used to create the file name in the cache * @return string URL of the compiled stylesheet */ public function parse_stylesheet($src, $handle) { // we only want to handle .less files if (!preg_match('/\\.less(\\.php)?$/', preg_replace('/\\?.*$/', '', $src))) { return $src; } // get file path from $src if (!strstr($src, '?')) { $src .= '?'; } // prevent non-existent index warning when using list() & explode() // Match the URL schemes between WP_CONTENT_URL and $src, // so the str_replace further down will work $src_scheme = parse_url($src, PHP_URL_SCHEME); $wp_content_url_scheme = parse_url(WP_CONTENT_URL, PHP_URL_SCHEME); if ($src_scheme != $wp_content_url_scheme) { $src = set_url_scheme($src, $wp_content_url_scheme); } list($less_path, $query_string) = explode('?', str_replace(WP_CONTENT_URL, WP_CONTENT_DIR, $src)); $cache = $this->get_cached_file_data($handle); // vars to pass into the compiler - default @themeurl var for image urls etc... $this->vars['themeurl'] = '~"' . get_stylesheet_directory_uri() . '"'; $this->vars['lessurl'] = '~"' . dirname($src) . '"'; $this->vars = apply_filters('less_vars', $this->vars, $handle); // The overall "version" of the LESS file is all it's vars, src etc. $less_version = md5(serialize(array($this->vars, $src))); /** * Give the ability to disable always compiling the LESS with lessc() * and instead just use the $vars and $version of the LESS file to * dictate whether the LESS should be (re)generated. * * This means we don't need to run everything through the lessc() compiler * on every page load. The tradeoff is making a change in a LESS file will not * necessarily cause a (re)generation, one would need to bump the $ver param * on wp_enqueue_script() to cause that. */ if (!get_option('wp_less_always_compile_less', true)) { if (!empty($cache['version']) && $cache['version'] === $less_version) { // restore query string it had if any $url = $cache['url'] . (!empty($query_string) ? "?{$query_string}" : ''); $url = set_url_scheme($url, $src_scheme); return add_query_arg('ver', $less_version, $url); } } // automatically regenerate files if source's modified time has changed or vars have changed try { // initialise the parser if (!class_exists('lessc')) { return $url; //wp_die( 'the lessphp library is missing, aborting, run composer update' ); } // If the cache or root path in it are invalid then regenerate if (empty($cache) || empty($cache['less']['root']) || !file_exists($cache['less']['root'])) { $cache = array('vars' => $this->vars, 'less' => $less_path); } if (empty($cache['url'])) { $cache['url'] = trailingslashit($this->get_cache_dir(false)) . "{$handle}.css"; } // less config $less = new lessc(); $less->setFormatter(apply_filters('less_compression', $this->compression)); $less->setPreserveComments(apply_filters('less_preserve_comments', $this->preserve_comments)); $less->setVariables($this->vars); // add directories to scan for imports $import_dirs = apply_filters('less_import_dirs', $this->import_dirs); if (!empty($import_dirs)) { foreach ((array) $import_dirs as $dir) { $less->addImportDir($dir); } } // register and unregister functions foreach ($this->registered_functions as $name => $callable) { $less->registerFunction($name, $callable); } foreach ($this->unregistered_functions as $name) { $less->unregisterFunction($name); } // allow devs to mess around with the less object configuration do_action_ref_array('lessc', array(&$less)); // $less->cachedCompile only checks for changed file modification times // if using the theme customiser (changed variables not files) then force a compile if ($this->vars !== $cache['vars']) { $force = true; } else { $force = false; } $force = apply_filters('less_force_compile', $force); $less_cache = $less->cachedCompile($cache['less'], $force); // if they have the same values but differing order, they wont match //sort( $cache['less'] ); //sort( $less_cache ); if (empty($cache) || empty($cache['less']['updated']) || md5($less_cache['compiled']) !== md5($cache['less']['compiled']) || $this->vars !== $cache['vars']) { // output css file name $css_path = trailingslashit($this->get_cache_dir()) . "{$handle}.css"; $cache = array('vars' => $this->vars, 'url' => trailingslashit($this->get_cache_dir(false)) . "{$handle}.css", 'version' => $less_version, 'less' => null); /** * If the option to not have LESS always compiled is set, * then we dont store the whole less_cache in the options table as it's * not needed because we only do a comparison based off $vars and $src * (which includes the $ver param). * * This saves space on the options table for high performance environments. */ if (get_option('wp_less_always_compile_less', true)) { $cache['less'] = $less_cache; } $payload = '<strong>Rebuilt stylesheet with handle: "' . $handle . '"</strong><br>'; if ($this->vars != $cache['vars']) { $payload .= '<em>Variables changed</em>'; $difference = array_merge(array_diff_assoc($cache['vars'], $this->vars), array_diff_assoc($this->vars, $cache['vars'])); $payload .= '<pre>' . print_r($difference, true) . '</pre>'; } else { if (empty($cache) || empty($cache['less']['updated'])) { $payload .= '<em>Empty cache or empty last update time</em>'; } else { if ($less_cache['updated'] > $cache['less']['updated']) { $payload .= '<em>Update times different</em>'; } else { $payload .= '<em><strong>Unknown! Contact the developers poste haste!!!!!!!</em><strong></em>'; } } } $payload .= '<br>src: <code>"' . $src . '"</code> css path: <code>"' . $css_path . '"</code> and cache path: <code>"' . $cache_path . '"</code> and scheme <code>"' . $src_scheme . '"</code>'; $this->add_message(array('time' => time(), 'payload' => $payload)); $this->save_parsed_css($css_path, $less_cache['compiled']); $this->update_cached_file_data($handle, $cache); } } catch (exception $ex) { $this->add_message(array('time' => time(), 'payload' => '<strong>Lessphp failure</strong> ' . $ex->GetMessage())); wp_die(wp_strip_all_tags($ex->getMessage())); } // restore query string it had if any $url = $cache['url'] . (!empty($query_string) ? "?{$query_string}" : ''); // restore original url scheme $url = set_url_scheme($url, $src_scheme); if (get_option('wp_less_always_compile_less', true)) { return add_query_arg('ver', $less_cache['updated'], $url); } return add_query_arg('ver', $less_version, $url); }
/** * @param string $content * @param bool $compress * @return string */ private function _compileLess($content, $compress) { $render = $this->_render; $lessCompiler = new lessc(); $lessCompiler->registerFunction('image', function ($arg) use($render) { /** @var CM_Frontend_Render $render */ list($type, $delimiter, $values) = $arg; return array('function', 'url', array('string', $delimiter, array($render->getUrlResource('layout', 'img/' . $values[0])))); }); $lessCompiler->registerFunction('image-inline', function ($arg) use($render) { /** @var CM_Frontend_Render $render */ list($type, $delimiter, $values) = $arg; if (2 == sizeof($values) && is_array($values[0]) && is_array($values[1])) { $delimiter = (string) $values[0][1]; $path = (string) $values[0][2][0]; $size = (int) $values[1][1]; } else { $path = $values[0]; $size = 0; } $imagePath = $render->getLayoutPath('resource/img/' . $path, null, null, true, true); $cache = CM_Cache_Persistent::getInstance(); $imageBase64 = $cache->get($cache->key(__METHOD__, md5($imagePath), 'size:' . $size), function () use($imagePath, $size) { $file = new CM_File($imagePath); $img = new CM_Image_Image($file->read()); if ($size > 0) { $img->resize($size, $size); } $img->setFormat(CM_Image_Image::FORMAT_GIF); return base64_encode($img->getBlob()); }); $url = 'data:image/gif;base64,' . $imageBase64; return array('function', 'url', array('string', $delimiter, array($url))); }); $lessCompiler->registerFunction('urlFont', function ($arg) use($render) { /** @var CM_Frontend_Render $render */ list($type, $delimiter, $values) = $arg; return array($type, $delimiter, array($render->getUrlStatic('/font/' . $values[0]))); }); if ($compress) { $lessCompiler->setFormatter('compressed'); } return $lessCompiler->compile($content); }
function compileLess($inputFile, $outputFile) { if (!class_exists('lessc')) { require_once KPATH_FRAMEWORK . '/external/lessc/lessc.php'; } // Load the cache. $cacheDir = JPATH_CACHE . '/kunena'; if (!is_dir($cacheDir)) { KunenaFolder::create($cacheDir); } $cacheFile = "{$cacheDir}/kunena.{$this->name}.{$inputFile}.cache"; if (is_file($cacheFile)) { $cache = unserialize(file_get_contents($cacheFile)); } else { $cache = JPATH_SITE . '/' . $this->getFile($inputFile, false, 'less'); } $outputDir = KPATH_MEDIA . "/cache/{$this->name}/css"; if (!is_dir($outputDir)) { KunenaFolder::create($outputDir); } $outputFile = "{$outputDir}/{$outputFile}"; $less = new lessc(); $class = $this; $less->registerFunction('url', function ($arg) use($class) { list($type, $q, $values) = $arg; $value = reset($values); return "url({$q}{$class->getFile($value, true, 'media', 'media/kunena')}{$q})"; }); $less->setVariables($this->style_variables); $newCache = $less->cachedCompile($cache); if (!is_array($cache) || $newCache['updated'] > $cache['updated'] || !is_file($outputFile)) { $cache = serialize($newCache); KunenaFile::write($cacheFile, $cache); KunenaFile::write($outputFile, $newCache['compiled']); } }
public function inject(lessc $instance) { $instance->registerFunction('hsvsaturation', array($this, 'function_hsvsaturation')); }
/** * @param string $content * @param bool $compress * @return string */ private function _compileLess($content, $compress) { $render = $this->_render; $lessCompiler = new lessc(); $lessCompiler->registerFunction('image', function ($arg) use($render) { /** @var CM_Frontend_Render $render */ list($type, $delimiter, $values) = $arg; return array('function', 'url', array('string', $delimiter, array($render->getUrlResource('layout', 'img/' . $values[0])))); }); $lessCompiler->registerFunction('urlFont', function ($arg) use($render) { /** @var CM_Frontend_Render $render */ list($type, $delimiter, $values) = $arg; return array($type, $delimiter, array($render->getUrlStatic('/font/' . $values[0]))); }); if ($compress) { $lessCompiler->setFormatter('compressed'); } return $lessCompiler->compile($content); }
/** * * @param array $variables * @param array $functions * @return \lessc|boolean */ function get_less_parser($variables, $functions) { if (!(include_once LESSPHP_INC . 'lessc.inc.php')) { trigger_error('Unable to process .less file -- LESSPHP not configured correctly on your server. Check the LESSPHP_INC setting in settings/package_settings.php.'); return false; } $less = new lessc(); $less->setFormatter('compressed'); $less->setVariables($variables); foreach ($functions as $name => $func) { $less->registerFunction($name, $func); } return $less; }
/** * Compile a less file * * @param \Zend_View $view * @param string $href The less file * @param boolean $always Always compile * @return boolean True when changed */ public function compile(\Zend_View $view, $href, $always = false) { if (\MUtil_String::startsWith($href, 'http', true)) { // When a local url, strip the serverUrl and basepath $base = $view->serverUrl() . $view->baseUrl(); if (\MUtil_String::startsWith($href, $base, true)) { // Only strip when urls match $href = substr($href, strlen($base)); } } // Add full path to the webdir $inFile = $this->_webroot . '/' . $href; $outFile = substr($inFile, 0, -strlen(pathinfo($inFile, PATHINFO_EXTENSION))) . 'css'; // Try compiling try { // \MUtil_Echo::track($inFile, $outFile); $lessc = new lessc(); $lessc->registerFunction('base64encode', array($this, 'base64encode')); if ($always || array_key_exists('compilecss', \Zend_Controller_Front::getInstance()->getRequest()->getParams())) { $result = (bool) $lessc->compileFile($inFile, $outFile); } else { $result = $lessc->checkedCompile($inFile, $outFile); } } catch (\Exception $exc) { // If we have an error, present it if not in production if (APPLICATION_ENV !== 'production' || APPLICATION_ENV !== 'acceptance') { \MUtil_Echo::pre($exc->getMessage()); } $result = null; } return $result; }
/** * @param lessc $c * * Register less functions in a lessc object */ function registerFunctions(&$c) { $c->registerFunction('length', array($this, 'length')); }
/** * Add a less-based stylesheet * @param string $url * @param string $media optional media attribute * @param boolean $add_to_top * @param array $wrapper * @param array $less_variables * @param array $less_functions * @return boolean success */ function add_less_stylesheet($url, $media = '', $add_to_top = false, $wrapper = array('before' => '', 'after' => ''), $less_variables = array(), $less_functions = array()) { if (substr($url, 0, 1) != '/') { trigger_error('Less stylesheets must be specified relative to server root (i.e. starting with "/"). Path given (' . $url . ') does not conform to this specification. Stylesheet not added.'); return false; } if (!(include_once LESSPHP_INC . 'lessc.inc.php')) { trigger_error('Unable to process .less file -- LESSPHP not configured correctly on your server. Check the LESSPHP_INC setting in settings/package_settings.php.'); return false; } $input_path = WEB_PATH . substr($url, 1); if (!file_exists($input_path)) { trigger_error('Less stylesheet not found at "' . $input_path . '". Stylesheet not added.'); return false; } $hash = md5($input_path . serialize($less_variables) . serialize(array_keys($less_functions))); $first2 = substr($hash, 0, 2); $output_filename = $hash . '_' . filemtime($input_path) . '.css'; $output_url = WEB_TEMP . 'less_compiled/' . $first2 . '/' . $output_filename; $base_output_directory = WEB_PATH . substr(WEB_TEMP, 1) . 'less_compiled/'; if (!file_exists($base_output_directory)) { mkdir($base_output_directory); } $output_directory = $base_output_directory . $first2 . '/'; if (!file_exists($output_directory)) { mkdir($output_directory); } $output_path = $output_directory . $output_filename; $cache_path = $output_directory . $hash . '.cache'; $less = new lessc(); $less->setFormatter('compressed'); $less->setVariables($less_variables); foreach ($less_functions as $less_function_name => $php_function) { $less->registerFunction($less_function_name, $php_function); } try { if ($this->less_cached_compile($input_path, $output_path, $less, $cache_path)) { $compiled = true; // something has changed if ($this->delete_old_less_css && ($handle = opendir($output_directory))) { while (false !== ($entry = readdir($handle))) { if ($entry != $output_filename && strpos($entry, $hash . '_') === 0 && substr($entry, -4) == '.css') { unlink($output_directory . $entry); } } } else { trigger_error('Unable to delete old less css files'); } } else { $compiled = false; // nothing has changed } } catch (Exception $ex) { trigger_error('lessphp unable to compile less at "' . $input_path . '". Stylesheet not added. Message: ' . $ex->getMessage()); return; } return $this->add_stylesheet($output_url, $media, $add_to_top, $wrapper); return true; }
function validateLESS($templateDir, &$errors) { $input = array('type' => 'css', 'params' => array('@font-swatch1-font-family' => '"Futura", "Helvetica", sans-serif', '@font-swatch1-font-size' => '24px', '@font-swatch1-font-weight' => '400', '@font-swatch1-line-height' => '34px', '@font-swatch1-color' => '@color-swatch6', '@font-swatch2-font-family' => '"Futura", "Helvetica", sans-serif', '@font-swatch2-font-size' => '24px', '@font-swatch2-font-weight' => '400', '@font-swatch2-line-height' => '34px', '@font-swatch2-color' => '@color-swatch3', '@font-swatch3-font-family' => '"Futura", "Helvetica", sans-serif', '@font-swatch3-font-size' => '18px', '@font-swatch3-font-weight' => '400', '@font-swatch3-line-height' => '28px', '@font-swatch3-color' => '@color-swatch3', '@font-swatch4-font-family' => '"Futura", "Helvetica", sans-serif', '@font-swatch4-font-size' => '14px', '@font-swatch4-font-weight' => '400', '@font-swatch4-line-height' => '24px', '@font-swatch4-color' => '@color-swatch3', '@font-swatch5-font-family' => '"Futura", "Helvetica", sans-serif', '@font-swatch5-font-size' => '14px', '@font-swatch5-font-weight' => '400', '@font-swatch5-line-height' => '24px', '@font-swatch5-color' => '@color-swatch5', '@color-swatch1' => '#4a979d', '@color-swatch2' => '#eafffc', '@color-swatch3' => '#3e3e3e', '@color-swatch4' => '#6a6a6a', '@color-swatch5' => '#bdbdbd', '@siteBackgroundColor' => 'transparent', '@siteBackgroundGradientType' => 'vertical', '@siteBackgroundGradientFrom' => 'transparent', '@siteBackgroundGradientTo' => 'transparent', '@siteBackgroundImageScale' => 'original', '@siteBackgroundImage' => 'none', '@siteBackgroundPositionX' => 'center', '@siteBackgroundPositionY' => 'top', '@siteBackgroundRepeat' => 'no-repeat', '@font-swatch1-letter-spacing' => 'inherit', '@font-swatch2-letter-spacing' => 'inherit', '@font-swatch3-letter-spacing' => 'inherit', '@font-swatch4-letter-spacing' => 'inherit', '@font-swatch5-letter-spacing' => 'inherit', '@font-swatch6-font-family' => '"Futura", "Helvetica", sans-serif', '@font-swatch6-font-size' => '16px', '@font-swatch6-font-weight' => '400', '@font-swatch6-line-height' => '26px', '@font-swatch6-letter-spacing' => 'inherit', '@font-swatch6-color' => '@color-swatch5', '@font-swatch6-color-hover' => '@color-swatch5', '@font-swatch6-background-color' => 'transparent', '@font-swatch6-background-color-hover' => 'transparent', '@font-swatch7-font-family' => '"Futura", "Helvetica", sans-serif', '@font-swatch7-font-size' => '18px', '@font-swatch7-font-weight' => '400', '@font-swatch7-line-height' => '28px', '@font-swatch7-letter-spacing' => 'inherit', '@font-swatch7-color' => '@color-swatch5', '@font-swatch7-background-color' => 'transparent', '@font-swatch7-background-color-hover' => 'darken(@color-swatch1,5%)', '@color-swatch6' => '#ffffff', '@color-swatch7' => '#f4f4f4', '@font-swatch8-font-family' => '"Futura", "Helvetica", sans-serif', '@font-swatch8-font-size' => '18px', '@font-swatch8-font-weight' => '400', '@font-swatch8-line-height' => '28px', '@font-swatch8-letter-spacing' => 'inherit', '@font-swatch8-color' => '@color-swatch5', '@font-swatch9-font-family' => '"Futura", "Helvetica", sans-serif', '@font-swatch9-font-size' => '18px', '@font-swatch9-font-weight' => '400', '@font-swatch9-line-height' => '28px', '@font-swatch9-letter-spacing' => 'inherit', '@font-swatch9-color' => '@color-swatch5', '@font-swatch10-font-family' => '"Futura", "Helvetica", sans-serif', '@font-swatch10-font-size' => '24px', '@font-swatch10-font-weight' => '400', '@font-swatch10-line-height' => '34px', '@font-swatch10-letter-spacing' => 'inherit', '@font-swatch10-color' => '@color-swatch5'), 'options' => array('compress' => 1)); $lessc = new lessc(); $lessc->setImportDir(array($templateDir, __DIR__ . '../templates')); // convert any relative image URL's to use the FQDN $assetDomain = null; $assetVersion = null; $templateDirectory = $templateDir; $templateHash = null; $lessc->registerFunction('image', function ($arg) use($assetDomain, $templateDirectory, $templateHash, $assetVersion) { list($type, $delim, $path) = $arg; $url = sprintf('//%s/%s/templates', $assetDomain, $templateHash ? $templateHash : $assetVersion); if ($templateDirectory) { $url .= "/{$templateDirectory}"; } $url .= $path[0]; return array($type, '', array(" url({$url})")); }); $lessc->registerFunction('bkscale', function ($arg) { list($type, $delim, $args) = $arg; $value = isset($args[0]) && isset($args[0][1]) ? $args[0][1] : ''; $unit = isset($args[0]) && isset($args[0][2]) ? $args[0][2] : ''; $scale = isset($args[1]) && isset($args[1][1]) ? $args[1][1] : ''; $intValue = intval($value); $floatScale = floatval($scale); $returnValue = array(); if ($intValue > 0 && $floatScale > 0) { $newScale = $intValue * $floatScale; $returnValue = array('string', '', array($newScale . $unit)); } else { // return back the original value $returnValue = array('string', '', array($value)); } return $returnValue; }); if (null !== $templateDirectory) { $input['params']['@templateLocal'] = '"' . $templateDirectory . '"'; } else { $input['params']['@templateLocal'] = '""'; } $input['params']['@templateCommon'] = '"../templates/common"'; // Any passed in variables used to populate the parsed CSS if (isset($input['params']) && is_array($input['params']) && count($input['params']) > 0) { $lessc->setVariables($input['params']); } if (isset($input['options']) && isset($input['options']['compress']) && $input['options']['compress'] == true) { $lessc->setFormatter("compressed"); } try { recruseImports($lessc, $templateDir, $templateDir . '/stylesheet.less'); } catch (\Exception $e) { $errors[] = "LESS Error: " . $e->getMessage(); } }
/** * Get the CSS for the given style and preset * * @param $style * @param $preset * @return string */ function create_css($style, $preset) { $paths = $this->get_widget_paths(); $style_file = false; // Find the file - exit if it can't be found. foreach ($paths as $path) { if (file_exists($path . '/' . $this->origin_id . '/styles/' . $style . '.less')) { $style_file = $path . '/' . $this->origin_id . '/styles/' . $style . '.less'; break; } } if (empty($style_file)) { return ''; } if (!class_exists('lessc')) { include plugin_dir_path(__FILE__) . 'lib/lessc.inc.php'; } foreach ($this->get_widget_folders() as $folder => $folder_url) { $filename = rtrim($folder, '/') . '/' . $this->origin_id . '/styles/' . $style . '.less'; if (file_exists($filename)) { $less = file_get_contents($filename); break; } } // Add in the mixins $less = str_replace('@import "../../../less/mixins";', "\n\n" . file_get_contents(plugin_dir_path(__FILE__) . 'less/mixins.less'), $less); // Apply the preset variables to the LESS file $presets = $this->get_style_presets($style); if (!empty($presets[$preset]) && is_array($presets[$preset])) { foreach ($presets[$preset] as $k => $v) { $less = preg_replace('/@' . preg_quote($k) . ':(.*);/', '@' . $k . ': ' . $v . ';', $less); } } // Scope the CSS with the wrapper we'll be adding $less = '.origin-widget.origin-widget-' . $this->origin_id . '-' . $style . '-' . $preset . ' {' . $less . '}'; $lc = new lessc(); $lc->setPreserveComments(false); $lc->registerFunction('lumlighten', 'origin_widgets_less_lumlighten'); $lc->registerFunction('lumdarken', 'origin_widgets_less_lumdarken'); $lc->registerFunction('texture', 'origin_widgets_less_texture'); $lc->registerFunction('widgetimage', 'origin_widgets_less_widgetimage'); // Create the CSS return $lc->compile($less); }
/** * Execute lessphp on a .less file or a lessphp cache structure * * The lessphp cache structure contains information about a specific * less file having been parsed. It can be used as a hint for future * calls to determine whether or not a rebuild is required. * * The cache structure contains two important keys that may be used * externally: * * compiled: The final compiled CSS * updated: The time (in seconds) the CSS was last compiled * * The cache structure is a plain-ol' PHP associative array and can * be serialized and unserialized without a hitch. * * @param mixed $in Input * @param bool $force Force rebuild? * @param array $initial_variables Initial input variables * @param array $functions Functions to register into the created Less instance * @return array lessphp cache structure */ public static function cexecute($in, $force = false, $initial_variables = null, $functions = null) { // assume no root $root = null; if (is_string($in)) { $root = $in; } elseif (is_array($in) and isset($in['root'])) { if ($force or !isset($in['files'])) { // If we are forcing a recompile or if for some reason the // structure does not contain any file information we should // specify the root to trigger a rebuild. $root = $in['root']; } elseif (isset($in['files']) and is_array($in['files'])) { foreach ($in['files'] as $fname => $ftime) { if (!file_exists($fname) or filemtime($fname) > $ftime) { // One of the files we knew about previously has changed // so we should look at our incoming root again. $root = $in['root']; break; } } } } else { // TODO: Throw an exception? We got neither a string nor something // that looks like a compatible lessphp cache structure. return null; } if ($root !== null) { // If we have a root value which means we should rebuild. $less = new lessc($root); if (is_array($functions)) { foreach ($functions as $name => $function) { if (is_callable($function)) { $less->registerFunction($name, $function); } } } $out = array(); $out['root'] = $root; $out['compiled'] = $less->parse(null, $initial_variables); $out['files'] = $less->allParsedFiles(); $out['updated'] = time(); return $out; } else { // No changes, pass back the structure // we were given initially. return $in; } }
/** * Returns LESS compiler set up for use with MediaWiki * * @param Config $config * @throws MWException * @since 1.22 * @return lessc */ public static function getLessCompiler(Config $config) { // When called from the installer, it is possible that a required PHP extension // is missing (at least for now; see bug 47564). If this is the case, throw an // exception (caught by the installer) to prevent a fatal error later on. if (!class_exists('lessc')) { throw new MWException('MediaWiki requires the lessphp compiler'); } if (!function_exists('ctype_digit')) { throw new MWException('lessc requires the Ctype extension'); } $less = new lessc(); $less->setPreserveComments(true); $less->setVariables(self::getLessVars($config)); $less->setImportDir($config->get('ResourceLoaderLESSImportPaths')); foreach ($config->get('ResourceLoaderLESSFunctions') as $name => $func) { $less->registerFunction($name, $func); } return $less; }
/** * Processing less file. * * @param $path * @param string $cacheFolder * @return null|string * @throws \Exception */ public function lessProcess($path, $cacheFolder = 'styles') { $output = null; $ext = pathinfo($path, PATHINFO_EXTENSION); if (!$ext) { $path .= '.less'; } $systemPath = $path; $segments = explode('/', $path); $lessFolder = ROOT . DS . 'webroot' . DS . 'less'; list($plugin, $path) = $this->_View->pluginSplit($path, false); $webRoot = ROOT . DS . 'webroot' . DS; $isPlugin = Plugin::loaded($plugin); $this->_imageFull = WWW_ROOT . DS . 'img' . DS; // Set data for plugin less. if ($plugin && $isPlugin) { $pluginPath = Plugin::path($plugin); $lessFolder = $pluginPath . 'webroot' . DS . 'less'; $webRootPlg = $pluginPath . 'webroot' . DS; $this->_type = 'plugin:' . $plugin; $this->_imageFull = $webRootPlg . 'img' . DS; } $lessFile = $lessFolder . DS . $path; // Set data for module less. if (strpos($segments[0], ':')) { list($type, $name) = explode(':', $segments[0]); if ($type == 'modules') { $modulePath = ROOT . DS . 'modules' . DS . $name . DS . 'assets' . DS; $lessFile = $modulePath . 'less' . DS . $segments[1]; $this->_type = 'modules:' . $name; $this->_imageFull = $modulePath . 'img' . DS; } } if (file_exists($lessFile)) { $less = new \lessc(); $fileHash = md5(serialize(md5_file($lessFile))); $cssFileName = $fileHash . '.css'; $less->registerFunction('url', array($this, 'lessPhpUrl')); $less->addImportDir(Plugin::path('Union/Core') . 'webroot' . DS . 'less' . DS); if (!DEBUG) { $formatter = new \lessc_formatter_compressed(); $less->setFormatter($formatter); $less->setPreserveComments(false); $cssFileName = $fileHash . '.min.css'; } $updateFile = false; try { $cssFile = $webRoot . 'cache' . DS . $cacheFolder . DS . $cssFileName; if (file_exists($cssFile)) { $cacheRes = fopen($cssFile, 'r'); $firstLine = fgets($cacheRes); fclose($cacheRes); if (!preg_match("#{$fileHash}#i", $firstLine)) { $updateFile = true; } } else { $updateFile = true; } $output = '/cache/' . $cacheFolder . '/' . $cssFileName; if ($this->_lessCompile) { $updateFile = true; } if ($updateFile) { $css = $less->compileFile($lessFile); $css = $this->_getLessFileComment($fileHash, $systemPath) . $css; $file = new File($cssFile, true); $file->write($css); $file->close(); } } catch (Exception $error) { die('<strong>' . __d('union_dev', 'Less Error:') . '</strong><br/><pre>' . $error->getMessage() . '</pre>'); } } return $output; }