public static function compile($source, $path, $todir, $importdirs) { // call Less to compile $parser = new lessc(); $parser->setImportDir(array_keys($importdirs)); $parser->setPreserveComments(true); $output = $parser->compile($source); // update url $arr = preg_split(T3Less::$rsplitbegin . T3Less::$kfilepath . T3Less::$rsplitend, $output, -1, PREG_SPLIT_DELIM_CAPTURE); $output = ''; $file = $relpath = ''; $isfile = false; foreach ($arr as $s) { if ($isfile) { $isfile = false; $file = $s; $relpath = T3Less::relativePath($todir, dirname($file)); $output .= "\n#" . T3Less::$kfilepath . "{content: \"{$file}\";}\n"; } else { $output .= ($file ? T3Path::updateUrl($s, $relpath) : $s) . "\n\n"; $isfile = true; } } return $output; }
function compileCss($path, $topath = '') { $app = JFactory::getApplication(); $theme = $app->getUserState('vars_theme'); $realpath = realpath(JPATH_ROOT . '/' . $path); // check path if (!is_file($realpath)) { //if (!JPath::check ($realpath)){ return; } // Get file content $content = JFile::read($realpath); // remove comments $content = preg_replace('!/\\*[^*]*\\*+([^/][^*]*\\*+)*/!', '', $content); // split into array, separated by the import $arr = preg_split('#^\\s*@import\\s+"([^"]*)"\\s*;#im', $content, -1, PREG_SPLIT_DELIM_CAPTURE); // check and add theme less if not is theme less if ($theme && !preg_match('#themes/#', $path)) { $themepath = 'themes/' . $theme . '/' . basename($path); if (is_file(T3_TEMPLATE_PATH . '/less/' . $themepath)) { $arr[] = $themepath; $arr[] = ''; } } // variables & mixin $vars = $this->getVars(); // add vars //$this->setImportDir (array(dirname($realpath), T3_TEMPLATE_PATH.'/less/')); $importdirs = array(); // compile chuck $import = false; $output = ''; foreach ($arr as $s) { if ($import) { $import = false; if ($s == 'vars.less') { continue; } // process import file $url = T3Path::cleanPath(dirname($path) . '/' . $s); $importcontent = JFile::read(JPATH_ROOT . '/' . $url); if (preg_match('#^\\s*@import\\s+"([^"]*)"\\s*;#im', $importcontent)) { $importdirs[] = dirname(JPATH_ROOT . '/' . $url); } $output .= "#less-file-path{content: \"{$url}\";}\n" . $importcontent . "\n\n"; } else { $import = true; $s = trim($s); if ($s) { $output .= "#less-file-path{content: \"{$path}\";}\n" . $s . "\n\n"; } } } $importdirs[] = dirname($realpath); $importdirs[] = T3_TEMPLATE_PATH . '/less/'; $this->setImportDir($importdirs); $output = $this->compile($vars . "\n" . $output); $arr = preg_split('#^\\s*\\#less-file-path\\s*{\\s*[\\r\\n]*\\s*content:\\s*"([^"]*)";\\s*[\\r\\n]*\\s*}#im', $output, -1, PREG_SPLIT_DELIM_CAPTURE); $output = ''; $file = ''; $isfile = false; foreach ($arr as $s) { if ($isfile) { $isfile = false; $file = $s; $relpath = $topath ? T3Path::relativePath(dirname($topath), dirname($file)) : JURI::base(true) . '/' . dirname($file); } else { $output .= ($file ? T3Path::updateUrl($s, $relpath) : $s) . "\n\n"; $isfile = true; } } // remove the dupliate clearfix at the beggining if not bootstrap.css file if (!preg_match('#bootstrap.less#', $path)) { $arr = preg_split('/[\\r?\\n]{2,}/', $output); // ignore first one, it's clearfix array_shift($arr); $output = implode("\n", $arr); } if ($topath) { $tofile = JPATH_ROOT . '/' . $topath; if (!is_dir(dirname($tofile))) { JFolder::create(dirname($tofile)); } $ret = JFile::write($tofile, $output); @chmod($tofile, 0644); return $ret; } return $output; }
public static function optimizecss($tpl) { $outputpath = JPATH_ROOT . '/' . $tpl->getParam('t3-assets', 't3-assets') . '/css'; $outputurl = JURI::root(true) . '/' . $tpl->getParam('t3-assets', 't3-assets') . '/css'; if (!JFile::exists($outputpath)){ JFolder::create($outputpath); @chmod($outputpath, 0755); } if (!is_writeable($outputpath)) { return false; } $doc = JFactory::getDocument(); //======================= Group css ================= // $cssgroups = array(); $stylesheets = array(); $ielimit = 4095; $selcounts = 0; $regex = '/\{.+?\}|,/s'; //selector counter $csspath = ''; foreach ($doc->_styleSheets as $url => $stylesheet) { $url = self::fixUrl($url); if ($stylesheet['mime'] == 'text/css' && ($csspath = self::cssPath($url))) { $stylesheet['path'] = $csspath; $stylesheet['data'] = JFile::read($csspath); $selcount = preg_match_all($regex, $stylesheet['data'], $matched); if(!$selcount) { $selcount = 1; //just for sure } //if we found an @import rule or reach IE limit css selector count, break into the new group if (preg_match('#@import\s+.+#', $stylesheet['data']) || $selcounts + $selcount >= $ielimit) { if(count($stylesheets)){ $cssgroup = array(); $groupname = array(); foreach ( $stylesheets as $gurl => $gsheet ) { $cssgroup[$gurl] = $gsheet; $groupname[] = $gurl; } $cssgroup['groupname'] = implode('', $groupname); $cssgroups[] = $cssgroup; } $stylesheets = array($url => $stylesheet); // empty - begin a new group $selcounts = $selcount; } else { $stylesheets[$url] = $stylesheet; $selcounts += $selcount; } } else { // first get all the stylsheets up to this point, and get them into // the items array if(count($stylesheets)){ $cssgroup = array(); $groupname = array(); foreach ( $stylesheets as $gurl => $gsheet ) { $cssgroup[$gurl] = $gsheet; $groupname[] = $gurl; } $cssgroup['groupname'] = implode('', $groupname); $cssgroups[] = $cssgroup; } //mark ignore current stylesheet $cssgroup = array($url => $stylesheet, 'ignore' => true); $cssgroups[] = $cssgroup; $stylesheets = array(); // empty - begin a new group } } if(count($stylesheets)){ $cssgroup = array(); $groupname = array(); foreach ( $stylesheets as $gurl => $gsheet ) { $cssgroup[$gurl] = $gsheet; $groupname[] = $gurl; } $cssgroup['groupname'] = implode('', $groupname); $cssgroups[] = $cssgroup; } //======================= Group css ================= // $output = array(); foreach ($cssgroups as $cssgroup) { if(isset($cssgroup['ignore'])){ unset($cssgroup['ignore']); foreach ($cssgroup as $furl => $fsheet) { $output[$furl] = $fsheet; } } else { $groupname = 'css-' . substr(md5($cssgroup['groupname']), 0, 5) . '.css'; $groupfile = $outputpath . '/' . $groupname; $grouptime = JFile::exists($groupfile) ? @filemtime($groupfile) : -1; $rebuild = $grouptime < 0; //filemtime == -1 => rebuild unset($cssgroup['groupname']); foreach ($cssgroup as $furl => $fsheet) { if(!$rebuild && @filemtime($fsheet['path']) > $grouptime){ $rebuild = true; } } if($rebuild){ $cssdata = array(); foreach ($cssgroup as $furl => $fsheet) { $cssdata[] = "\n\n/*==============================="; $cssdata[] = $furl; $cssdata[] = "================================================================================*/"; $cssmin = Minify_CSS_Compressor::process($fsheet['data']); $cssmin = T3Path::updateUrl($cssmin, T3Path::relativePath($outputurl, dirname($furl))); $cssdata[] = $cssmin; } $cssdata = implode("\n", $cssdata); JFile::write($groupfile, $cssdata); @chmod($groupfile, 0644); } $output[$outputurl . '/' . $groupname] = array( 'mime' => 'text/css', 'media' => null, 'attribs' => array() ); } } //apply the change make change $doc->_styleSheets = $output; }
/** * Update url for background, import according to output path * * @param $css the compiled css * @param $path the source less path * @param $output_dir destination of css file * @param $split split into small files or not * @return if $split then return an array of sub file, else return the whole css */ public static function updateUrl($css, $path, $output_dir, $split) { //update path and store to files $split_contents = preg_split(self::$rsplitbegin . self::$kfilepath . self::$rsplitend, $css, -1, PREG_SPLIT_DELIM_CAPTURE); $file_contents = array(); $file = $path; $isfile = false; $output = ''; // split foreach ($split_contents as $chunk) { if ($isfile) { $isfile = false; $file = $chunk; } else { $content = T3Path::updateUrl(trim($chunk), T3Path::relativePath($output_dir, dirname($file))); $file_contents[$file] = (isset($file_contents[$file]) ? $file_contents[$file] : '') . "\n" . $content . "\n\n"; $output .= $content . "\n"; $isfile = true; } } return $split ? $file_contents : trim($output); }
/** * Special compilation for template.css file when development mode is on * @param $path * @return bool */ public static function divide($path) { //check system self::requirement(); $parser = new Less_Parser(); $app = JFactory::getApplication(); $doc = JFactory::getDocument(); $tpl = T3_TEMPLATE; $theme = $app->getTemplate(true)->params->get('theme'); $is_rtl = $doc->direction == 'rtl' && strpos($path, 'rtl/') === false; $subdir = ($is_rtl ? 'rtl/' : '') . ($theme ? $theme . '/' : ''); $topath = T3_DEV_FOLDER . '/' . $subdir; $tofile = null; $root = JUri::root(true); //pattern $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/[^/]*/)?@'; $kfilepath = 'less-file-path'; $kvarsep = 'less-content-separator'; $krtlsep = 'rtl-less-content'; if ($topath) { if (!is_dir(JPATH_ROOT . '/' . $topath)) { JFolder::create(JPATH_ROOT . '/' . $topath); } } // 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); } // 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)) { $content = $content . "\n@import \"{$themepath}\"; \n\n"; } } // split into array, separated by the import $split_contents = preg_split($rimport, $content, -1, PREG_SPLIT_DELIM_CAPTURE); //check if we need to rebuild $rebuild = false; $vars_lm = $app->getUserState('vars_last_modified', 0); $file_lm = @filemtime(JPATH_ROOT . '/' . $path); //check for this file and rtl $cssfile = $topath . str_replace('/', '.', $path) . '.css'; $css_lm = is_file(JPATH_ROOT . '/' . $cssfile) ? @filemtime(JPATH_ROOT . '/' . $cssfile) : -1; //rebuild? if ($css_lm < $vars_lm || $css_lm < $file_lm) { $rebuild = true; } else { $doc->addStylesheet($root . '/' . $cssfile); } //check for rebuild if this rtl overwrite file has just modified if (!$rebuild && $is_rtl) { $rtl_url = preg_replace('@/less/(themes/)?@', '/less/rtl/', $path); $rtl_lm = is_file(JPATH_ROOT . '/' . $rtl_url) ? @filemtime(JPATH_ROOT . '/' . $rtl_url) : 0; $rebuild = $css_lm < $rtl_lm; } if (!$rebuild) { $import = false; foreach ($split_contents as $chunk) { if ($import) { $import = false; $url = T3Path::cleanPath(dirname($path) . '/' . $chunk); if (is_file(JPATH_ROOT . '/' . $url)) { //$css_lm should be the same as templates.css $file_lm = @filemtime(JPATH_ROOT . '/' . $url); $theme_lm = -1; $rtl_lm = -1; $theme_rtl_lm = -1; if ($theme && strpos($url, 'themes/') === false) { $themepath = 'themes/' . $theme . '/' . basename($path); if (is_file(T3_TEMPLATE_PATH . '/less/' . $themepath)) { $theme_lm = @filemtime(T3_TEMPLATE_PATH . '/less/' . $themepath); } if ($is_rtl) { $rtlthemepath = preg_replace($rswitchrtl, '/less/rtl/' . $theme . '/', $url); if (is_file(JPATH_ROOT . '/' . $rtlthemepath)) { $theme_rtl_lm = @filemtime(JPATH_ROOT . '/' . $rtlthemepath); } } } if ($is_rtl) { $rtl_url = preg_replace('@/less/(themes/)?@', '/less/rtl/', $url); if (is_file(JPATH_ROOT . '/' . $rtl_url)) { $rtl_lm = @filemtime(JPATH_ROOT . '/' . $rtl_url); } } if (!is_file(JPATH_ROOT . '/' . $cssfile) || $css_lm < $vars_lm || $css_lm < $file_lm || $css_lm < $theme_lm || $css_lm < $rtl_lm || $css_lm < $theme_rtl_lm) { $rebuild = true; // rebuild for sure break; //no need further check } else { $doc->addStylesheet($root . '/' . $topath . str_replace('/', '.', $url) . '.css'); } } } else { $import = true; } } } // so, no need to rebuild? if (!$rebuild) { // add RTL css if needed if ($is_rtl) { $cssfile = $topath . str_replace('/', '.', str_replace('.less', '-rtl.less', $path)) . '.css'; if (is_file(JPATH_ROOT . '/' . $cssfile)) { $doc->addStylesheet($root . '/' . $cssfile); } } return false; } // variables & mixin $vars = self::getVars(); $output = ''; $importdirs = array(); // iterate to each chunk and add separator mark $import = false; foreach ($split_contents as $chunk) { if ($import) { $import = false; $url = T3Path::cleanPath(dirname($path) . '/' . $chunk); // 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)] = $root . '/' . dirname($url) . '/'; $output .= "#{$kfilepath}{content: \"{$url}\";}\n@import \"{$chunk}\";\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)] = T3_TEMPLATE_URL . dirname($theme_rel) . '/'; $output .= "#{$kfilepath}{content: \"" . ('templates/' . T3_TEMPLATE . '/less/' . $theme_rel) . "\";}\n@import \"{$theme_rel}\";\n\n"; } } } else { $import = true; $chunk = trim($chunk); if ($chunk) { $output .= "#{$kfilepath}{content: \"{$path}\";}\n{$chunk}\n\n"; } } } // compile RTL overwrite when in RTL mode if ($is_rtl) { $rtlcontent = ''; // import rtl override $import = false; foreach ($split_contents as $chunk) { if ($import) { $import = false; $url = T3Path::cleanPath(dirname($path) . '/' . $chunk); // 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); // is there overwrite file? 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)] = $root . '/' . 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)] = $root . '/' . 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)] = $root . '/' . 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)] = $root . '/' . dirname($rtlthemepath) . '/'; } } if ($rtlcontent) { //rtl content will be treat as a new file $rtlfile = str_replace('.less', '-rtl.less', $path); $output = $output . "\n#{$kfilepath}{content: \"{$rtlfile}\";}\n\n#{$krtlsep}{content: \"separator\";}\n\n{$rtlcontent}\n\n"; } } // common place $importdirs[T3_TEMPLATE_PATH . '/less'] = T3_TEMPLATE_URL . '/less/'; // myself $importdirs[dirname(JPATH_ROOT . '/' . $path)] = $root . '/' . dirname($path) . '/'; // compile less to css using lessphp $parser->SetImportDirs($importdirs); $parser->SetFileInfo(JPATH_ROOT . '/' . $path, $root . '/' . dirname($path) . '/'); $source = $vars . "\n#{$kvarsep}{content: \"separator\";}\n" . $output; $parser->parse($source); $output = $parser->getCss(); //use cssjanus to transform the content 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); if ($rtlcontent) { $output = $output . "\n" . $rtlcontent; } } //update path and store to files $split_contents = preg_split($rsplitbegin . $kfilepath . $rsplitend, $output, -1, PREG_SPLIT_DELIM_CAPTURE); $file_contents = array(); $file = $path; //default $relpath = JURI::base(true) . '/' . dirname($file); $isfile = false; foreach ($split_contents as $chunk) { if ($isfile) { $isfile = false; $file = $chunk; $relpath = $topath ? T3Path::relativePath($topath, dirname($file)) : JURI::base(true) . '/' . dirname($file); } else { $file_contents[$file] = (isset($file_contents[$file]) ? $file_contents[$file] : '') . "\n" . ($file ? T3Path::updateUrl($chunk, $relpath) : $chunk) . "\n\n"; $isfile = true; } } if (!empty($file_contents)) { // remove the duplicate clearfix at the beginning $split_contents = preg_split($rsplitbegin . $kvarsep . $rsplitend, reset($file_contents)); // ignore first one, it's clearfix if (is_array($split_contents)) { array_shift($split_contents); } $file_contents[key($file_contents)] = implode("\n", $split_contents); //output the file to content and add to document foreach ($file_contents as $file => $content) { $cssfile = $topath . str_replace('/', '.', $file) . '.css'; JFile::write(JPATH_ROOT . '/' . $cssfile, $content); $doc->addStylesheet($root . '/' . $cssfile); } } }
function compileCss($path, $topath = '') { $app = JFactory::getApplication(); $tpl = T3_TEMPLATE; $theme = $app->getUserState('vars_theme'); $tofile = null; //pattern $rcomment = '@/\\*[^*]*\\*+([^/][^*]*\\*+)*/@'; $rspace = '@[\\r?\\n]{2,}@'; $rimport = '@^\\s*\\@import\\s+"([^"]*)"\\s*;@im'; $rvarscheck = '@(base|bootstrap|' . preg_quote($tpl) . ')/less/(vars|variables|mixins)\\.less@'; $rexcludepath = '@(base|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'; $kfilepath = 'less-file-path'; $kvarsep = 'less-content-separator'; $krtlsep = 'rtl-less-content'; if ($topath) { $tofile = JPATH_ROOT . '/' . $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 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 = $this->getVars(); $importdirs = array(); // compile chunk $import = false; $output = ''; 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 $importcontent = JFile::read(JPATH_ROOT . '/' . $url); if (preg_match($rexcludepath, $url)) { $importcontent = preg_replace($rimportvars, '', $importcontent); } // remember this path when lookup for import if (preg_match($rimport, $importcontent)) { $importdirs[] = dirname(JPATH_ROOT . '/' . $url); } $output .= "#{$kfilepath}{content: \"{$url}\";}\n{$importcontent}\n\n"; } else { $import = true; $s = trim($s); if ($s) { $output .= "#{$kfilepath}{content: \"{$path}\";}\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 $url = preg_replace('/\\/less\\/(themes\\/)?/', '/less/rtl/', $url); if (!is_file(JPATH_ROOT . '/' . $url)) { continue; } // process import file $importcontent = JFile::read(JPATH_ROOT . '/' . $url); if (preg_match($rexcludepath, $url)) { $importcontent = preg_replace($rimportvars, '', $importcontent); } // remember this path when lookup for import if (preg_match($rimport, $importcontent)) { $importdirs[] = dirname(JPATH_ROOT . '/' . $url); } $rtlcontent .= "#{$kfilepath}-rtl{content: \"{$url}\";}\n{$importcontent}\n\n"; } else { $import = true; } } // override in template for this file $rtlpath = preg_replace('/\\/less\\/(themes\\/[^\\/]*\\/)?/', '/less/rtl/', $path); if (is_file(JPATH_ROOT . '/' . $rtlpath)) { // process import file $importcontent = JFile::read(JPATH_ROOT . '/' . $rtlpath); $rtlcontent .= "#{$kfilepath}-rtl{content: \"{$rtlpath}\";}\n{$importcontent}\n\n"; } // rtl theme if ($theme) { $rtlthemepath = preg_replace('/\\/less\\/(themes\\/[^\\/]*\\/)?/', '/less/rtl/' . $theme . '/', $path); if (is_file(JPATH_ROOT . '/' . $rtlthemepath)) { // process import file $importcontent = JFile::read(JPATH_ROOT . '/' . $rtlthemepath); $rtlcontent .= "#{$kfilepath}-rtl{content: \"{$rtlthemepath}\";}\n{$importcontent}\n\n"; } } if ($rtlcontent) { $output = $output . "#{$krtlsep}{content: \"separator\";}\n\n{$rtlcontent}\n\n"; } } $importdirs[] = dirname($realpath); $importdirs[] = T3_TEMPLATE_PATH . '/less/'; $this->setImportDir($importdirs); $this->setPreserveComments(true); $source = $vars . "\n#{$kvarsep}{content: \"separator\";}\n" . $output; // compile less to css using lessphp $output = $this->compile($source); $arr = preg_split($rsplitbegin . $kfilepath . $rsplitend, $output, -1, PREG_SPLIT_DELIM_CAPTURE); $output = ''; $file = ''; $isfile = false; foreach ($arr as $s) { if ($isfile) { $isfile = false; $file = $s; $relpath = $topath ? T3Path::relativePath(dirname($topath), dirname($file)) : JURI::base(true) . '/' . dirname($file); } else { $output .= ($file ? T3Path::updateUrl($s, $relpath) : $s) . "\n\n"; $isfile = true; } } // remove the dupliate clearfix at the beggining 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); } 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); 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; }
/** * @param $tpl template object * @return bool optimize success or not */ public static function optimizecss($tpl) { $outputpath = JPATH_ROOT . '/' . $tpl->getParam('t3-assets', 't3-assets') . '/css'; $outputurl = JURI::root(true) . '/' . $tpl->getParam('t3-assets', 't3-assets') . '/css'; if (!JFile::exists($outputpath)) { JFolder::create($outputpath); @chmod($outputpath, 0755); } if (!is_writeable($outputpath)) { return false; } //prepare config self::prepare($tpl); $doc = JFactory::getDocument(); //======================= Group css ================= // $mediagroup = array(); $cssgroups = array(); $stylesheets = array(); $ielimit = 4095; $selcounts = 0; $regex = '/\\{.+?\\}|,/s'; //selector counter $csspath = ''; // group css into media $mediagroup['all'] = array(); $mediagroup['screen'] = array(); foreach ($doc->_styleSheets as $url => $stylesheet) { $media = $stylesheet['media'] ? $stylesheet['media'] : 'all'; if (empty($mediagroup[$media])) { $mediagroup[$media] = array(); } $mediagroup[$media][$url] = $stylesheet; } foreach ($mediagroup as $media => $group) { $stylesheets = array(); // empty - begin a new group foreach ($group as $url => $stylesheet) { $url = self::fixUrl($url); if ($stylesheet['mime'] == 'text/css' && ($csspath = self::cssPath($url))) { $stylesheet['path'] = $csspath; $stylesheet['data'] = file_get_contents($csspath); $selcount = preg_match_all($regex, $stylesheet['data'], $matched); if (!$selcount) { $selcount = 1; //just for sure } //if we found an @import rule or reach IE limit css selector count, break into the new group if (preg_match('#@import\\s+.+#', $stylesheet['data']) || $selcounts + $selcount >= $ielimit) { if (count($stylesheets)) { $cssgroup = array(); $groupname = array(); $grouptime = 0; foreach ($stylesheets as $gurl => $gsheet) { $cssgroup[$gurl] = $gsheet; $groupname[] = $gurl; $ftime = @filemtime($gsheet['path']); if ($ftime > $grouptime) { $grouptime = $ftime; } } $cssgroup['groupname'] = implode('', $groupname); $cssgroup['grouptime'] = $grouptime; $cssgroup['media'] = $media; $cssgroups[] = $cssgroup; } $stylesheets = array($url => $stylesheet); // empty - begin a new group $selcounts = $selcount; } else { $stylesheets[$url] = $stylesheet; $selcounts += $selcount; } } else { // first get all the stylsheets up to this point, and get them into // the items array if (count($stylesheets)) { $cssgroup = array(); $groupname = array(); $grouptime = 0; foreach ($stylesheets as $gurl => $gsheet) { $cssgroup[$gurl] = $gsheet; $groupname[] = $gurl; $ftime = @filemtime($gsheet['path']); if ($ftime > $grouptime) { $grouptime = $ftime; } } $cssgroup['groupname'] = implode('', $groupname); $cssgroup['grouptime'] = $grouptime; $cssgroup['media'] = $media; $cssgroups[] = $cssgroup; } //mark ignore current stylesheet $cssgroup = array($url => $stylesheet, 'ignore' => true); $cssgroups[] = $cssgroup; $stylesheets = array(); // empty - begin a new group } } if (count($stylesheets)) { $cssgroup = array(); $groupname = array(); $grouptime = 0; foreach ($stylesheets as $gurl => $gsheet) { $cssgroup[$gurl] = $gsheet; $groupname[] = $gurl; $ftime = @filemtime($gsheet['path']); if ($ftime > $grouptime) { $grouptime = $ftime; } } $cssgroup['groupname'] = implode('', $groupname); $cssgroup['grouptime'] = $grouptime; $cssgroup['media'] = $media; $cssgroups[] = $cssgroup; } } //======================= Group css ================= // $output = array(); foreach ($cssgroups as $cssgroup) { if (isset($cssgroup['ignore'])) { unset($cssgroup['ignore']); unset($cssgroup['groupname']); unset($cssgroup['media']); foreach ($cssgroup as $furl => $fsheet) { $output[$furl] = $fsheet; } } else { $rebuildCheck = self::checkRebuild($cssgroup, 'css', $outputpath); $media = $cssgroup['media']; unset($cssgroup['groupname']); unset($cssgroup['grouptime']); unset($cssgroup['media']); $groupname = $rebuildCheck['filename']; if ($rebuildCheck['rebuild']) { $groupfile = $outputpath . '/' . $groupname; $cssdata = array(); foreach ($cssgroup as $furl => $fsheet) { $cssdata[] = "\n\n/*==============================="; $cssdata[] = $furl; $cssdata[] = "================================================================================*/"; $cssmin = self::minifyCss($fsheet['data']); $cssmin = T3Path::updateUrl($cssmin, T3Path::relativePath($outputurl, dirname($furl))); $cssdata[] = $cssmin; } $cssdata = implode("\n", $cssdata); if (!JFile::write($groupfile, $cssdata)) { // cannot write file, ignore minify return false; } $grouptime = @filemtime($groupfile); @chmod($groupfile, 0644); } $output[$outputurl . '/' . $groupname] = array('mime' => 'text/css', 'media' => $media == 'all' ? NULL : $media, 'attribs' => array()); } } //apply the change make change $doc->_styleSheets = $output; }