/** * @param string $path file path of less file to compile * @param string $topath file path of output css file * @return bool|mixed compile result or the css compiled content */ public static function compileCss($path, $topath = '') { //check system self::requirement(); $parser = new Less_Parser(); $app = JFactory::getApplication(); $tpl = T3_TEMPLATE; $theme = $app->getUserState('vars_theme'); $tofile = null; $todir = null; //pattern $rcomment = '@/\\*[^*]*\\*+([^/][^*]*\\*+)*/@'; $rspace = '@[\\r?\\n]{2,}@'; $rimport = '@^\\s*\\@import\\s+"([^"]*)"\\s*;@im'; $rvarscheck = '@(base|base-bs3|bootstrap|' . preg_quote($tpl) . ')/less/(vars|variables|mixins)\\.less@'; $rexcludepath = '@(base|base-bs3|bootstrap|' . preg_quote($tpl) . ')/less/@'; $rimportvars = '@^\\s*\\@import\\s+".*(variables-custom|variables|vars|mixins)\\.less"\\s*;@im'; $rsplitbegin = '@^\\s*\\#'; $rsplitend = '[^\\s]*?\\s*{\\s*[\\r\\n]*\\s*content:\\s*"([^"]*)";\\s*[\\r\\n]*\\s*}@im'; $rswitchrtl = '@/less/(themes/[^/]*/)?@'; $kvarsep = 'less-content-separator'; $krtlsep = 'rtl-less-content'; if ($topath) { $tofile = JPATH_ROOT . '/' . $topath; $todir = dirname($topath); if (!is_dir(dirname($tofile))) { JFolder::create(dirname($tofile)); } } // check path $realpath = realpath(JPATH_ROOT . '/' . $path); if (!is_file($realpath)) { return; } // get file content $content = JFile::read($realpath); //remove vars.less if (preg_match($rexcludepath, $path)) { $content = preg_replace($rimportvars, '', $content); } // remove comments? - we should keep comment for rtl flip //$content = preg_replace($rcomment, '', $content); // split into array, separated by the import $arr = preg_split($rimport, $content, -1, PREG_SPLIT_DELIM_CAPTURE); // check and add theme less if not is theme less if ($theme && strpos($path, 'themes/') === false) { $themepath = 'themes/' . $theme . '/' . basename($path); if (is_file(T3_TEMPLATE_PATH . '/less/' . $themepath)) { $arr[] = $themepath; $arr[] = ''; } } // variables & mixin $vars = self::getVars(); $output = ''; $importdirs = array(); // compile chunk $import = false; foreach ($arr as $s) { if ($import) { $import = false; $url = T3Path::cleanPath(dirname($path) . '/' . $s); // ignore vars.less and variables.less if they are in template folder // cause there may have other css less file with the same name (eg. font awesome) if (preg_match($rvarscheck, $url)) { continue; } // remember this path when lookup for import $importdirs[dirname(JPATH_ROOT . '/' . $url)] = self::relativePath($todir, dirname($url)); $output .= "\n@import \"{$s}\";\n\n"; // check and add theme less if ($theme && strpos($url, 'themes/') === false) { $theme_rel = 'themes/' . $theme . '/' . basename($url); $theme_path = T3_TEMPLATE_PATH . '/less/' . $theme_rel; if (is_file($theme_path)) { $importdirs[dirname($theme_path)] = self::relativePath($todir, 'templates/' . $tpl . '/less/themes/' . $theme . '/'); $output .= "\n@import \"{$theme_rel}\";\n\n"; } } } else { $import = true; $s = trim($s); if ($s) { $output .= "\n{$s}\n\n"; } } } $rtlcontent = ''; $is_rtl = $app->getUserState('DIRECTION') == 'rtl' && strpos($path, 'rtl/') === false; // convert to RTL if using RTL if ($is_rtl) { // import rtl override // check override for import $import = false; foreach ($arr as $s) { if ($import) { $import = false; $url = T3Path::cleanPath(dirname($path) . '/' . $s); // ignore vars.less and variables.less if they are in template folder // cause there may have other css less file with the same name (eg. font awesome) if (preg_match($rvarscheck, $url)) { continue; } // process import file $rtl_url = preg_replace('@/less/(themes/)?@', '/less/rtl/', $url); if (!is_file(JPATH_ROOT . '/' . $rtl_url)) { continue; } // process import file $importcontent = JFile::read(JPATH_ROOT . '/' . $rtl_url); if (preg_match($rexcludepath, $rtl_url)) { $importcontent = preg_replace($rimportvars, '', $importcontent); } // remember this path when lookup for import if (preg_match($rimport, $importcontent)) { $importdirs[dirname(JPATH_ROOT . '/' . $rtl_url)] = self::relativePath($todir, dirname($rtl_url)); } $rtlcontent .= "\n{$importcontent}\n\n"; // rtl theme overwrite if ($theme && strpos($url, 'themes/') === false) { $rtlthemepath = preg_replace($rswitchrtl, '/less/rtl/' . $theme . '/', $url); if (is_file(JPATH_ROOT . '/' . $rtlthemepath)) { // process import file $importcontent = JFile::read(JPATH_ROOT . '/' . $rtlthemepath); $rtlcontent .= "\n{$importcontent}\n\n"; $importdirs[dirname(JPATH_ROOT . '/' . $rtlthemepath)] = self::relativePath($todir, dirname($rtlthemepath)); } } } else { $import = true; } } // override in template for this file $rtlpath = preg_replace($rswitchrtl, '/less/rtl/', $path); if (is_file(JPATH_ROOT . '/' . $rtlpath)) { // process import file $importcontent = JFile::read(JPATH_ROOT . '/' . $rtlpath); $rtlcontent .= "\n{$importcontent}\n\n"; $importdirs[dirname(JPATH_ROOT . '/' . $rtlpath)] = self::relativePath($todir, dirname($rtlpath)); } // rtl theme if ($theme) { $rtlthemepath = preg_replace($rswitchrtl, '/less/rtl/' . $theme . '/', $path); if (is_file(JPATH_ROOT . '/' . $rtlthemepath)) { // process import file $importcontent = JFile::read(JPATH_ROOT . '/' . $rtlthemepath); $rtlcontent .= "\n{$importcontent}\n\n"; $importdirs[dirname(JPATH_ROOT . '/' . $rtlthemepath)] = self::relativePath($todir, dirname($rtlthemepath)); } } if ($rtlcontent) { $output = $output . "\n#{$krtlsep}{content: \"separator\";}\n\n{$rtlcontent}\n\n"; } } // common place $importdirs[T3_TEMPLATE_PATH . '/less'] = self::relativePath($todir, T3_TEMPLATE_URL); // myself $importdirs[dirname(JPATH_ROOT . '/' . $path)] = self::relativePath($todir, dirname($path)); // ignore all these files foreach (array(T3_PATH, T3_PATH . '/bootstrap', T3_TEMPLATE_PATH) as $know_path) { foreach (array('vars', 'variables', 'mixins') as $know_file) { $realfile = realpath($know_path . '/less/' . $know_file . '.less'); if (is_file($realfile) && !Less_Parser::FileParsed($realfile)) { Less_Parser::AddParsedFile($realfile); } } } // compile less to css using lessphp $parser->SetImportDirs($importdirs); $parser->SetFileInfo(JPATH_ROOT . '/' . $path, self::relativePath($todir, dirname($path))); $source = $vars . "\n#{$kvarsep}{content: \"separator\";}\n" . $output; $parser->parse($source); $output = $parser->getCss(); // remove the duplicate clearfix at the beginning if not bootstrap.css file if (strpos($path, $tpl . '/less/bootstrap.less') === false) { $arr = preg_split($rsplitbegin . $kvarsep . $rsplitend, $output); // ignore first one, it's clearfix if (is_array($arr)) { array_shift($arr); } $output = implode("\n", $arr); } else { $output = preg_replace($rsplitbegin . $kvarsep . $rsplitend, '', $output); } //update url if needed if (defined('T3_DEV_MODE') && T3_DEV_MODE) { $output = T3Path::updateUrl($output, $topath ? T3Path::relativePath(dirname($topath), dirname($path)) : T3_TEMPLATE_URL . '/css/'); } if ($is_rtl) { if ($rtlcontent) { $output = preg_split($rsplitbegin . $krtlsep . $rsplitend, $output, -1, PREG_SPLIT_DELIM_CAPTURE); $rtlcontent = isset($output[2]) ? $output[2] : false; $output = $output[0]; } T3::import('jacssjanus/ja.cssjanus'); $output = JACSSJanus::transform($output, true); //join again if ($rtlcontent) { $output = $output . "\n" . $rtlcontent; } } //remove comments and clean up $output = preg_replace($rcomment, '', $output); $output = preg_replace($rspace, "\n\n", $output); if ($tofile) { $ret = JFile::write($tofile, $output); @chmod($tofile, 0644); return $ret; } return $output; }
/** * Should the import be skipped? * * @return boolean|null */ private function Skip($path, $env) { $path = Less_Parser::winPath(realpath($path)); if ($path && Less_Parser::FileParsed($path)) { if (isset($this->currentFileInfo['reference'])) { return true; } return !isset($this->options['multiple']) && !$env->importMultiple; } }
function compile($env) { $evald = $this->compileForImport($env); $uri = $full_path = false; //get path & uri $evald_path = $evald->getPath(); if ($evald_path && $env->isPathRelative($evald_path)) { foreach (Less_Parser::$import_dirs as $rootpath => $rooturi) { $temp = $rootpath . $evald_path; if (file_exists($temp)) { $full_path = Less_Environment::NormPath($temp); $uri = Less_Environment::NormPath(dirname($rooturi . $evald_path)); break; } } } if (!$full_path) { $uri = $evald_path; $full_path = $evald_path; } //import once $realpath = realpath($full_path); if (!isset($evald->options['multiple']) && $realpath && Less_Parser::FileParsed($realpath)) { $evald->skip = true; } $features = $evald->features ? $evald->features->compile($env) : null; if ($evald->skip) { return array(); } if ($evald->css) { $temp = $this->compilePath($env); return new Less_Tree_Import($this->compilePath($env), $features, $this->options, $this->index); } $parser = new Less_Parser($env); $evald->root = $parser->parseFile($full_path, $uri, true); $ruleset = new Less_Tree_Ruleset(array(), $evald->root->rules); $ruleset->evalImports($env); return $this->features ? new Less_Tree_Media($ruleset->rules, $this->features->value) : $ruleset->rules; }