/** * Update head - detect if devmode or themermode is enabled and less file existed, use less file instead of css * We also detect and update jQuery, Bootstrap to use T3 assets * * @return null */ function updateHead() { //state parameters $devmode = $this->getParam('devmode', 0); $themermode = $this->getParam('themermode', 1) && defined('T3_THEMER'); $theme = $this->getParam('theme', ''); $minify = $this->getParam('minify', 0); $minifyjs = $this->getParam('minify_js', 0); // detect RTL $doc = JFactory::getDocument(); $dir = $doc->direction; $is_rtl = $dir == 'rtl'; // As Joomla 3.0 bootstrap is buggy, we will not use it // We also prevent both Joomla bootstrap and T3 bootsrap are loaded // And upgrade jquery as our Framework require jquery 1.7+ if we are loading jquery from google $scripts = array(); if (version_compare(JVERSION, '3.0', 'ge')) { $t3bootstrap = false; $jabootstrap = false; foreach ($doc->_scripts as $url => $script) { if (strpos($url, T3_URL . '/bootstrap/js/bootstrap.js') !== false) { $t3bootstrap = true; if ($jabootstrap) { //we already have the Joomla bootstrap and we also replace to T3 bootstrap continue; } } if (preg_match('@media/jui/js/bootstrap(.min)?.js@', $url)) { if ($t3bootstrap) { //we have T3 bootstrap, no need to add Joomla bootstrap continue; } else { $scripts[T3_URL . '/bootstrap/js/bootstrap.js'] = $script; } $jabootstrap = true; } else { $scripts[$url] = $script; } } $doc->_scripts = $scripts; $scripts = array(); } // VIRTUE MART / JSHOPPING compatible foreach ($doc->_scripts as $url => $script) { $replace = false; if (strpos($url, '//ajax.googleapis.com/ajax/libs/jquery/') !== false && preg_match_all('@/jquery/(\\d+(\\.\\d+)*)?/@msU', $url, $jqver) || preg_match_all('@(^|\\/)jquery([-_]*(\\d+(\\.\\d+)+))?(\\.min)?\\.js@i', $url, $jqver)) { $idx = strpos($url, '//ajax.googleapis.com/ajax/libs/jquery/') !== false ? 1 : 3; if (is_array($jqver) && isset($jqver[$idx]) && isset($jqver[$idx][0])) { $jqver = explode('.', $jqver[$idx][0]); if (isset($jqver[0]) && (int) $jqver[0] <= 1 && isset($jqver[1]) && (int) $jqver[1] < 7) { $scripts[T3_URL . '/js/jquery-1.11.2' . ($devmode ? '' : '.min') . '.js'] = $script; $replace = true; } } } if (!$replace) { $scripts[$url] = $script; } } $doc->_scripts = $scripts; // end update javascript //Update css/less based on devmode and themermode $root = JURI::root(true); $current = JURI::current(); // $regex = '@' . preg_quote(T3_TEMPLATE_REL) . '/css/(rtl/)?(.*)\.css((\?|\#).*)?$@i'; $regex = '@' . preg_quote(T3_TEMPLATE_REL) . '/(.*)\\.css((\\?|\\#).*)?$@i'; $stylesheets = array(); foreach ($doc->_styleSheets as $url => $css) { // detect if this css in template css if (preg_match($regex, $url, $match)) { $fname = $match[1]; // remove rtl $fname = preg_replace('@(^|/)rtl/@mi', '\\1', $fname); // remove local $fname = preg_replace('@^local/@mi', '', $fname); // if (($devmode || $themermode) && is_file(T3_TEMPLATE_PATH . '/less/' . $fname . '.less')) { if ($devmode || $themermode) { // less file $lfname = preg_replace('@(^|/)css/@mi', '\\1less/', $fname); if (is_file(T3_TEMPLATE_PATH . '/' . $lfname . '.less')) { if ($themermode) { $newurl = T3_TEMPLATE_URL . '/' . $lfname . '.less'; $css['mime'] = 'text/less'; } else { T3::import('core/less'); $newurl = T3Less::buildCss(T3Path::cleanPath(T3_TEMPLATE_REL . '/' . $lfname . '.less'), true); } $stylesheets[$newurl] = $css; continue; } } $uri = null; // detect css available base on direction & theme if ($is_rtl && $theme) { // rtl css file $altfname = preg_replace('@(^|/)css/@mi', '\\1css/rtl/' . $theme . '/', $fname); $uri = T3Path::getUrl($altfname . '.css'); } if (!$uri && $is_rtl) { $altfname = preg_replace('@(^|/)css/@mi', '\\1css/rtl/', $fname); $uri = T3Path::getUrl($altfname . '.css'); } if (!$uri && $theme) { $altfname = preg_replace('@(^|/)css/@mi', '\\1css/themes/' . $theme . '/', $fname); $uri = T3Path::getUrl($altfname . '.css'); } if (!$uri) { $uri = T3Path::getUrl($fname . '.css'); } if ($uri) { $stylesheets[$uri] = $css; } continue; } $stylesheets[$url] = $css; } // update back $doc->_styleSheets = $stylesheets; //only check for minify if devmode is disabled if (!$devmode && ($minify || $minifyjs)) { T3::import('core/minify'); if ($minify) { T3Minify::optimizecss($this); } if ($minifyjs) { T3Minify::optimizejs($this); } } }
public static function addAssets() { $japp = JFactory::getApplication(); $user = JFactory::getUser(); //do nothing when site is offline and user has not login (the offline page is only show login form) if ($japp->getCfg('offline') && !$user->authorise('core.login.offline')) { return; } $jdoc = JFactory::getDocument(); $params = $japp->getTemplate(true)->params; if (defined('T3_THEMER') && $params->get('themermode', 1)) { $jdoc->addStyleSheet(T3_URL . '/css/thememagic.css'); $jdoc->addScript(T3_URL . '/js/thememagic.js'); $theme = $params->get('theme'); $params = new JRegistry(); $themeinfo = new stdClass(); if ($theme) { $themepath = T3_TEMPLATE_PATH . '/less/themes/' . $theme; if (file_exists($themepath . '/variables-custom.less')) { if (!class_exists('JRegistryFormatLESS')) { include_once T3_ADMIN_PATH . '/includes/format/less.php'; } //default variables $varfile = T3_TEMPLATE_PATH . '/less/variables.less'; if (file_exists($varfile)) { $params->loadString(JFile::read($varfile), 'LESS'); //get all less files in "theme" folder $others = JFolder::files($themepath, '.less'); foreach ($others as $other) { //get those developer custom values if ($other == 'variables.less') { $devparams = new JRegistry(); $devparams->loadString(JFile::read($themepath . '/variables.less'), 'LESS'); //overwrite the default variables foreach ($devparams->toArray() as $key => $value) { $params->set($key, $value); } } //ok, we will import it later if ($other != 'variables-custom.less' && $other != 'variables.less') { $themeinfo->{$other} = true; } } //load custom variables $cparams = new JRegistry(); $cparams->loadString(JFile::read($themepath . '/variables-custom.less'), 'LESS'); //and overwrite those defaults variables foreach ($cparams->toArray() as $key => $value) { $params->set($key, $value); } } } } $cache = array(); // a little security if ($user->authorise('core.manage', 'com_templates') || isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], JUri::base() . 'administrator') !== false) { T3::import('core/path'); $baseurl = JUri::base(); //should we provide a list of less path foreach (array(T3_TEMPLATE_PATH . '/less', T3_PATH . '/bootstrap/less', T3_PATH . '/less') as $lesspath) { if (is_dir($lesspath)) { $lessfiles = JFolder::files($lesspath, '.less', true, true); if (is_array($lessfiles)) { foreach ($lessfiles as $less) { $path = ltrim(str_replace(array(JPATH_ROOT, '\\'), array('', '/'), $less), '/'); $path = T3Path::cleanPath($path); $fullurl = $baseurl . preg_replace('@(\\+)|(/+)@', '/', $path); $cache[$fullurl] = JFile::read($less); } } } } } $jdoc->addScriptDeclaration(' var T3Theme = window.T3Theme || {}; T3Theme.vars = ' . json_encode($params->toArray()) . '; T3Theme.others = ' . json_encode($themeinfo) . '; T3Theme.theme = \'' . $theme . '\'; T3Theme.template = \'' . T3_TEMPLATE . '\'; T3Theme.base = \'' . JURI::base() . '\'; T3Theme.cache = ' . json_encode($cache) . '; if(typeof less != \'undefined\'){ //we need to build one - cause the js will have unexpected behavior try{ if(window.parent != window && window.parent.T3Theme && window.parent.T3Theme.applyLess){ window.parent.T3Theme.applyLess(true); } else { less.refresh(); } } catch(e){ } }'); } }
public static function cb_import_path($match) { $f = $match[1]; $newf = T3Path::cleanPath(self::$_path . $f); return str_replace($f, $newf, $match[0]); }
public static function addStylesheet($lesspath) { // build less vars, once only static $vars_built = false; $t3less = T3Less::getInstance(); if (!$vars_built) { self::buildVars(); $vars_built = true; } $app = JFactory::getApplication(); $tpl = $app->getTemplate(true); $theme = $tpl->params->get('theme'); $doc = JFactory::getDocument(); if (defined('T3_THEMER')) { // in Themer mode, using js to parse less for faster $doc->addStylesheet(JURI::base(true) . '/' . T3Path::cleanPath($lesspath), 'text/less'); // Add lessjs to process lesscss $doc->addScript(T3_URL . '/js/less-1.3.3.js'); } else { // in development mode, using php to compile less for a better view of development if (preg_match('#(template(-responsive)?.less)#', $lesspath)) { // Development mode is on, try to include less file inside folder less/ // get the less content $lessContent = JFile::read(JPATH_ROOT . '/' . $lesspath); $path = dirname($lesspath); // parse less content if (preg_match_all('#^\\s*@import\\s+"([^"]*)"#im', $lessContent, $matches)) { foreach ($matches[1] as $url) { if ($url == 'vars.less') { continue; } $url = $path . '/' . $url; $cssurl = $t3less->buildCss(T3Path::cleanPath($url)); $doc->addStyleSheet($cssurl); } } } else { $cssurl = $t3less->buildCss(T3Path::cleanPath($lesspath)); $doc->addStyleSheet($cssurl); } // check and add theme less if ($theme && !preg_match('#bootstrap#', $lesspath)) { $themepath = str_replace('/less/', '/less/themes/' . $theme . '/', $lesspath); if (is_file(JPATH_ROOT . '/' . $themepath)) { $cssurl = $t3less->buildCss(T3Path::cleanPath($themepath)); $doc->addStyleSheet($cssurl); } } } }
/** * 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); } } }