PATH:
home
/
centosnipponia
/
public_html
/
nipponiacom2
/
plugins
/
system
/
ef4_jmframework
/
includes
/
libraries
<?php /** * @version $Id: template.php 158 2017-05-16 14:23:02Z szymon $ * @package JMFramework * @copyright Copyright (C) 2012 DJ-Extensions.com LTD, All rights reserved. * @license http://www.gnu.org/licenses GNU/GPL * @author url: http://dj-extensions.com * @author email contact@dj-extensions.com * @developer Michal Olczyk - michal.olczyk@design-joomla.eu * * JMFramework is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * JMFramework is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with JMFramework. If not, see <http://www.gnu.org/licenses/>. * */ defined('_JEXEC') or die('Restricted access'); abstract class JMFTemplate { protected $maxgrid = 12; protected $spanX = '/(\s*)span(\d+)(\s*)/'; protected $dscreen = 'default'; protected $screens = array('default', 'wide', 'normal', 'xtablet', 'tablet', 'mobile'); protected $maxcol = array('default' => 6, 'wide' => 6, 'normal' => 6, 'xtablet' => 4, 'tablet' => 2, 'mobile' => 2); protected $minspan = array('default' => 2, 'wide' => 2, 'normal' => 2, 'xtablet' => 3, 'tablet' => 6, 'mobile' => 6); /** * layout config * @var JRegistry */ protected $layoutconfig = null; /** * included blocks */ protected $blocks = null; /** * blocks included only on the front-end / excluded in the Layout Builder */ protected $front_blocks = array('head','debug','offcanvas','jmthemeoverlay'); /** * helper array of already loaded blocks */ protected $loaded_blocks = array(); /** * @var JDocument */ public $document; /** * @var JRegistry */ public $params; /** * * Browser type - handler by Mobile_Detect class [desktop|phone|tablet] * @var string */ public $browser_type; /** * @var bool */ public static $less_js_included = false; /** * * @var JMFTemplate */ protected static $instance = null; /** * @var array */ protected $lessMap = array(); /** * @param JDocument * @param bool Set to true if the object is meant to handle AJAX calls only. It matters only on the front-end */ protected static $style_id = false; function __construct(JDocument &$document, $ajax_listener = false) { jimport('joomla.filesystem.file'); jimport('joomla.filesystem.folder'); $app = JFactory::getApplication(); // Retrieving params from JDocument object $this->params = new JRegistry; $tpl_vars = get_object_vars($document); foreach ($tpl_vars as $name => $value) { if (!empty($value)) { if (is_object($value)) { $this->$name = clone $value; } else { $this->$name = $value; } } } // We're holding a reference to JDocument object $this->document = $document; // Document set-up. We don't need to do it when we're expecting internal AJAX calls on front-end. if (!$ajax_listener) { $this->setup(); } // Getting layout configuration $layout = $this->params->get('layout', 'default'); if($app->isAdmin()) { $layout = $app->input->getCmd('jmlayout', $layout); } else { $layout = $this->params->get('layout', 'default'); //$style_id = @JFactory::getApplication()->getTemplate(true)->id; $style_id = self::getTemplateStyleId(); $file = JPath::clean(JMF_TPL_PATH . '/assets/style/assigns-' . $style_id . '.json'); // get current layout assigns settings if(JFile::exists($file)) { $assigns = new JRegistry; if(JFile::exists($file)) { $assigns->loadString(JFile::read($file)); } $assigns = $assigns->toArray(); // set default layout from configuration if(isset($assigns[0])) $layout = $assigns[0]; $id = $app->input->get('Itemid', 0); if($id > 0) { // change layout if menu assignment is set if(isset($assigns[$id])) $layout = $assigns[$id]; } } } $this->layout = $layout; //$this->debug($layout); $layout_path = JPath::clean(JPATH_ROOT . '/templates/' . JMF_TPL . '/assets/layout/' . $layout . '.json'); $dlayout_path = JPath::clean(JPATH_ROOT . '/templates/' . JMF_TPL . '/assets/layout/' . $layout . '.def'); if (JFile::exists($layout_path) || JFile::exists($dlayout_path)) { $this->layoutconfig = new JRegistry; if (JFile::exists($layout_path)) { $this->layoutconfig->loadString(JFile::read($layout_path)); } else { $this->layoutconfig->loadString(JFile::read($dlayout_path)); } } // Template's post-setup stuff. We don't need to do it when we're expecting internal AJAX calls on front-end. if (!$ajax_listener) { $this->params->set('JMfluidGridContainerLg', $this->getLayoutConfig('#tmplWidth', $this->defaults->get('JMfluidGridContainerLg', '1170px'))); $this->params->set('JMbaseSpace', $this->getLayoutConfig('#tmplSpace', $this->defaults->get('JMbaseSpace', '30px'))); $this->params->set('columnLeftWidth', $this->getLayoutConfig('#leftWidth', $this->defaults->get('columnLeftWidth', '3'))); $this->params->set('columnRightWidth', $this->getLayoutConfig('#rightWidth', $this->defaults->get('columnRightWidth', '3'))); // change paramrs for PowerAdmin if($app->input->get('poweradmin', 0) == 1) { $this->params->set('offCanvas', 0); } //self::debug($this->getLayoutConfig('#tmplWidth')); $this->postSetup(); // override column classes and data for all screens if($app->isSite()) { $class = $this->getAllColumnsClasses(); $this->params->set('class', $class); } } self::$instance = $this; } public static function getInstance() { return self::$instance; } protected function setup() { $app = JFactory::getApplication(); $tplarray = $this->params->toArray(); // Loading joomla core features //JHtml::_('behavior.modal'); //JHtml::_('behavior.tooltip'); JHtml::_('bootstrap.tooltip'); JHtml::_('jquery.ui', array('core', 'sortable')); // Adding layout responsiveness script if($this->params->get('responsiveLayout', '1')) { $this->addScript(JMF_FRAMEWORK_URL.'/includes/assets/template/js/layout.min.js'); } // Adding lazy loading script if($this->params->get('lazyLoading', '0')) { $this->addScript(JMF_FRAMEWORK_URL.'/includes/assets/template/js/lazy.min.js'); } // Adding instant page script if($this->params->get('instantPage', '0')) { $this->addScript(JMF_FRAMEWORK_URL.'/includes/assets/template/js/instantpage-3.0.0.js', 'module', true); } // Adding Font Awesome support if (($this->params->get('advancedFontAwesome', false) == 1) && $app->isSite()) { $this->addStyleSheet(JMF_FRAMEWORK_URL.'/includes/assets/template/fontawesome/css/font-awesome.min.css'); } if (($this->params->get('advancedFontAwesome', false) == 5) && $app->isSite()) { $this->addStyleSheet(JMF_FRAMEWORK_URL.'/includes/assets/template/fontawesome5/css/all.min.css'); $this->addStyleSheet(JMF_FRAMEWORK_URL.'/includes/assets/template/fontawesome5/css/v4-shims.min.css'); } // determine the direction if ($app->input->get('direction') == 'rtl'){ setcookie("jmfdirection", "rtl"); $direction = 'rtl'; } else if ($app->input->get('direction') == 'ltr') { setcookie("jmfdirection", "ltr"); $direction = 'ltr'; } else { if (isset($_COOKIE['jmfdirection'])) { $direction = $_COOKIE['jmfdirection']; } else { $direction = $app->input->get('jmfdirection', $this->document->direction); } } $this->direction = $this->params->set('direction', $direction); // handle JM Option Groups foreach ($tplarray as $param => $value) { if (is_string($value) && strstr($value,';')) { $parts = explode(';', $value); if(is_numeric($parts[0])) $this->params->set($param, $parts[0]); // only numeric to avoid cutting the text options containg semicolons } } // Mobile_Detect class for addtional browser detection if (!class_exists('Mobile_Detect')) { require_once JMF_FRAMEWORK_PATH.DIRECTORY_SEPARATOR. 'includes' .DIRECTORY_SEPARATOR. 'libraries' .DIRECTORY_SEPARATOR. 'Mobile_Detect' .DIRECTORY_SEPARATOR. 'Mobile_Detect.php'; } $detect = new Mobile_Detect; $this->browser_type = ($detect->isMobile() ? ($detect->isTablet() ? 'tablet' : 'phone') : 'desktop'); $themer_mode = ($this->params->get('themermode', false) == '1') ? '1' : '0'; if ($themer_mode && $this->params->get('themeradminaccess', '0') == '1') { $user = JFactory::getUser(); $themer_mode = (bool)($user->authorise('core.admin') || $user->authorise('core.manage')); $this->params->set('themermode', ($themer_mode ? '1' : '0')); } $browser = JBrowser::getInstance(); // Use ThemeCustomiser only when using desktop browser. Mobile devices and bots are excluded $themer_mode = ($app->input->get('tmpl') == 'component' || $this->browser_type != 'desktop' || $browser->isRobot() || $browser->isMobile()) ? '0' : $themer_mode; // Disable ThemeCustomiser unless user turn it on from the front-end if($themer_mode) { $themer_switch = $app->getUserStateFromRequest('themer.switch', 'tc', '0'); if (isset($_REQUEST['tc'])) { JURI::reset(); $uri = JURI::getInstance(); $uri->delVar('tc'); $redir = $uri->toString(); JURI::reset(); $app->redirect($redir); return true; } if($themer_switch !== '1') { $this->params->def('themerswitch', '1'); $this->attachTCSwitch(); $themer_mode = '0'; } } $this->params->set('themermode', $themer_mode); define('JMF_THEMER_MODE', $themer_mode == '1' ? true : false); if ($this->params->get('devmode', false)) { $app->enqueueMessage(JText::_('PLG_SYSTEM_JMFRAMEWORK_WARNING_DEV_MODE_ENABLED')); } // Making sure that custom fonts' CSS files have been generated $font_path = JMF_TPL_PATH.DIRECTORY_SEPARATOR.'fonts'; if (is_dir($font_path)) { $font_folders = JFolder::folders($font_path); if (is_array($font_folders) && !empty($font_folders)) { foreach ($font_folders as $font) { if ($this->generateFontCss($font, $font_path.DIRECTORY_SEPARATOR.$font) && $themer_mode) { $this->addStyleSheet(JMF_TPL_URL.'/fonts/'.$font.'/font.css'); } } } } // Purge obsolete CSS files that doesn't belong to any template style // Since styles have already been deleted, we have to discover somehow which files are no longer needed $db = JFactory::getDbo(); $db->setQuery('SELECT id FROM #__template_styles ORDER BY id'); // list of all style IDs $style_ids = $db->loadColumn(); if (count($style_ids)) { // All LESS files in the template $less_files = JFolder::files(JPath::clean(JMF_TPL_PATH.'/less'), '\.less$'); // All CSS files that contain numerical suffix, e.g. "template.69.css" $css_files = JFolder::files(JPath::clean(JMF_TPL_PATH.'/css'), '\.[0-9]+\.css$'); foreach ($css_files as $css_file) { // strip the extenion $name = JFile::stripExt($css_file); // split name by . (dot) $css_parts = explode('.', $name); // if there is at least one dot if (count($css_parts) > 1) { // discover name of the LESS file $less_name = JFile::stripExt($name); // and the suffix itself $last_part = (int)(end($css_parts)); // if there is corresponding LESS file // and the suffix does not correspond to any template style // and the suffix is actually a number if ($less_name && in_array($less_name.'.less', $less_files) && !in_array($last_part, $style_ids) && $last_part > 0) { // delete obsolete CSS file if (JFile::exists(JPath::clean(JPATH_ROOT.'/templates/'.JMF_TPL.'/css/').$css_file)) { JFile::delete(JPath::clean(JPATH_ROOT.'/templates/'.JMF_TPL.'/css/').$css_file); } $map_file = str_replace('.css', '.map', $css_file); if (JFile::exists(JPath::clean(JPATH_ROOT.'/templates/'.JMF_TPL.'/css/').$map_file)) { JFile::delete(JPath::clean(JPATH_ROOT.'/templates/'.JMF_TPL.'/css/').$map_file); } } } } } $this->defaults = new JRegistry(); $default_settings_file = JPath::clean(JPATH_ROOT . '/templates/' . JMF_TPL . '/templateDefaults.json'); if (JFile::exists($default_settings_file)) { $this->defaults->loadFile($default_settings_file, 'JSON'); } } /** * Template may call this after setup process has been completed */ abstract function postSetUp (); /** * Used for creating stylesheets dynamically, based on template configuration. * @param name of the .php file used for generating CSS output */ public function cacheStyleSheet($generator) { if (JFolder::exists(JMF_TPL_PATH.DIRECTORY_SEPARATOR.'cache') == false) { if (!JFolder::create(JMF_TPL_PATH.DIRECTORY_SEPARATOR.'cache')) { if (JDEBUG) { throw new Exception(JText::_('PLG_SYSTEM_JMFRAMEWORK_CACHE_FOLDER_NOT_ACCESSIBLE')); } else { return false; } } } $tplParamsHash = md5($this->params->toString()); // file name $css = current(explode('.', $generator)).'_'.$tplParamsHash.'.css'; // CSS path //$cssPath = JPATH_ROOT.DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR.'tpl-'.$this->template.DIRECTORY_SEPARATOR.$css; $cssPath = JMF_TPL_PATH.DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR.$css; // CSS URL //$cssURL = JURI::base().'cache/tpl-'.$this->template.'/'.$css; $cssURL = JMF_TPL_URL.'/cache/'.$css; // CSS generator $cssGenerator = JMF_TPL_PATH.DIRECTORY_SEPARATOR.'css'.DIRECTORY_SEPARATOR.$generator; if (!JFile::exists($cssGenerator)) { if (JDEBUG) { throw new Exception(JText::sprintf('PLG_SYSTEM_JMFRAMEWORK_MISSING_CSS_GENERATOR', $generator)); } else { return false; } } if (!JFile::exists($cssPath) || $this->params->get('devmode', false) == true) { if (JFile::exists($cssPath)) { JFile::delete($cssPath); } // if there's nothing in cache, let's cache the css. ob_start(); // PHP file which uses template parameters to generate CSS content include($cssGenerator); $cssContent = ob_get_contents(); ob_end_clean(); if ($cssContent) { if (!JFile::write($cssPath, $cssContent)) { if (JDEBUG) { throw new Exception(JText::_('PLG_SYSTEM_JMFRAMEWORK_CACHE_FOLDER_NOT_ACCESSIBLE')); } else { return false; } } } } // if CSS exists return its URL if (JFile::exists($cssPath)) { return $cssURL; } return false; } /** * The same as JDocumentHTML::countModules(), but before passing the condition it replace * all the module's position names with real module's position names set in the layout configuration */ public function checkModules($condition) { $operators = '(,|\+|\-|\*|\/|==|\!=|\<\>|\<|\>|\<=|\>=|and|or|xor)'; $words = preg_split('# ' . $operators . ' #', $condition, null, PREG_SPLIT_DELIM_CAPTURE); for ($i = 0, $n = count($words); $i < $n; $i += 2) { // odd parts (modules) //$name = strtolower($words[$i]); // why to lower? $words[$i] = $this->getPosition($words[$i]); } $newcond = ''; foreach ($words as $word) { $newcond = ' ' . $word; // merge positions with operators } return $this->countModules(trim($newcond)); // pass condition to JDocument function } /** * Wrapper for JDocumentHTML::countModules() */ public function countModules($condition) { return $this->document->countModules($condition); } /** * Returns real module's position name set in the layout configuration */ public function getPosition($name) { $position = $this->getLayoutConfig($name, $name); if(!is_string($position)) $position = (is_array($position) ? $position['position'] : (isset($position->position) ? $position->position : $position)); return $position; } /** * Wrapper for JDocumentHTML::countMenuChildren() */ public function countMenuChildren() { return $this->document->countMenuChildren(); } /** * Wrapper for JDocumentHTML::addStyleSheet() */ public function addStyleSheet($path, $type = 'text/css', $media = null, $attribs = array()) { return $this->document->addStyleSheet($path, $type, $media, $attribs); } /** * Depending on whether ThemeCustomiser has been enabled or not, adds directly LESS file instead of CSS or compiles LESS to CSS * @param (string) Path to LESS file * @param (bool) If true additional LESS variables from "jm_bootstrap_variables" parameter will be added * @param (bool) Indicates if ThemeCustomiser is being used */ public function addCompiledStyleSheet($path, $useVars = true, $themer = false, $version = null, $options = array()) { if ($themer) { //if (false){ $this->attachThemeCustomiser($useVars); if ($lessPath = $this->getLessUrl($path)){ // compile CSS - just in case $this->lessToCss($path, $useVars); // add Less file to document's HEAD return $this->document->addHeadLink($lessPath, 'stylesheet/less'); } } else { $path = $this->lessToCss($path, $useVars); if ($path) { if ($version) { $options['version'] = $version; } return $this->document->addStyleSheet($path, $options); } } } /** * Compiles LESS to CSS file - without addining it to document's HEAD * @param (string) Path to LESS file * @param (bool) If true additional LESS variables from "jm_bootstrap_variables" parameter will be added * @param (bool) If true, style ID will be added as suffix */ public function compileStyleSheet($path, $useVars = true, $coreStyle = false) { return $this->lessToCss($path, $useVars, $coreStyle); } /** * Wrapper for JDocumentHTML::addStyleDeclaration() */ public function addStyleDeclaration($content, $type = 'text/css'){ return $this->document->addStyleDeclaration($content, $type); } /** * Wrapper for JDocumentHTML::addScript() */ public function addScript($url, $type = "text/javascript", $defer = false, $async = false) { return $this->document->addScript($url, $type, $defer, $async); } /** * Wrapper for JDocumentHTML::addScriptDeclaration() */ public function addScriptDeclaration($content, $type = 'text/javascript') { return $this->document->addScriptDeclaration($content, $type); } /** * Adds custom generated font's CSS file to document's HEAD */ public function addGeneratedFont($font) { $developer_mode = ($this->params->get('devmode', false) == '1') ? true : false; $themer_mode = ($this->params->get('themermode', false) == '1') ? true : false; $font_dir = JMF_TPL_PATH.DIRECTORY_SEPARATOR.'fonts'.DIRECTORY_SEPARATOR.$font; $font_css_path = $font_dir.DIRECTORY_SEPARATOR.'font.css'; $font_css_url = JMF_TPL_URL.'/fonts/'.$font.'/font.css'; if (JFolder::exists($font_dir) == false) { return false; } if (JFile::exists($font_css_path)) { if ($developer_mode) { JFile::delete($font_css_path); } else { return $this->addStyleSheet($font_css_url); } } // Generate new CSS if necessary if ($this->generateFontCss($font, $font_dir)) { return $this->addStyleSheet($font_css_url); } return false; } /** * Generates CSS that imports font definitions from custom fonts' directory * * @param (string) Font Family name * @param (string) Path to a directory in which all available font files have been stored */ public function generateFontCss($font, $font_dir){ if (JFolder::exists($font_dir) == false) { return false; } // use following font files only: .eot, .woff, .ttf, .svg $font_types = array('eot','woff','ttf','svg'); $font_files = array(); foreach($font_types as $type) { if (JFile::exists($font_dir.DIRECTORY_SEPARATOR.$font.'.'.$type)) { $font_files[$type] = true; } } if (empty($font_files)) { return false; } /// building CSS file's content $css_contents = array(); $css_contents[] = '@font-face {'; $css_contents[] = 'font-family: \''.$font.'\';'; if (isset($font_files['eot'])) { $css_contents[] = 'src: url(\''.$font.'.eot\');'; } $src = array(); foreach($font_files as $k=>$v) { if ($k == 'eot') { $src[] = 'url(\''.$font.'.eot?#iefix\') format(\'embedded-opentype\')'; } else if ($k == 'woff') { $src[] = 'url(\''.$font.'.woff\') format(\'woff\')'; } else if ($k == 'ttf') { $src[] = 'url(\''.$font.'.ttf\') format(\'truetype\')'; } else if ($k == 'svg') { $src[] = 'url(\''.$font.'.svg#'.$font.'\') format(\'svg\')'; } } if (!empty($src)) { $css_contents[] = 'src: '.implode(",\n", $src).';'; } $css_contents[] = 'font-weight: normal;'; $css_contents[] = 'font-style: normal;'; $css_contents[] = '}'; $css_content = implode("\n", $css_contents); // saving a file and returning it's path return JFile::write($font_dir.DIRECTORY_SEPARATOR.'font.css', $css_content); } /** * Rendering template's main blocks. This is a main part of the template with sortable blocks. * @param (string | array) The list of default blocks and their order * @param (string | array) The list of blocks excluded from Layout Builder */ public function renderBlocks($default, $exclude = null) { $blocks = $this->getBlocks($default, $exclude); if(count($blocks)) { echo '<div id="jm-blocks">'; foreach($blocks as $block) { $this->renderBlock($block); } echo '</div>'; } } /** * Rendering template's block. Block is usually a set of different module positions * @param (string) Name of a block that corresponds to .php file in a template/tpl/blocks. * @param (bool) Flag that informs whether if we are dealing with a block or complete layout scheme (template/tpl) */ public function renderBlock($block_name, $is_scheme = false) { if(in_array($block_name, $this->loaded_blocks)) return; if(!$is_scheme) $this->loaded_blocks[] = $block_name; $template_name = JFactory::getApplication()->getTemplate(); $block_name = ($is_scheme) ? $block_name : 'blocks/'.$block_name; $layout_file = JPath::clean(JMF_TPL_PATH.'/tpl/'.$block_name.'.php'); $layout_file_override = JPath::clean(JMF_TPL_PATH.'/html/'.$template_name.'/tpl/'.$block_name.'.php'); if (!JFile::exists($layout_file)) { // if block doesn't exist in the template check the default plugin blocks $layout_file = JPath::clean(JMF_FRAMEWORK_PATH.'/includes/assets/template/'.$block_name.'.php'); } if (JFile::exists($layout_file)) { if (JFile::exists($layout_file_override)) { include($layout_file_override); } else { include($layout_file); } } else { throw new Exception(JText::_('PLG_SYSTEM_JMFRAMEWORK_MISSING_BLOCK_FILE').': '.$block_name, 400); } } /** * Wrapper for renderBlock method for rendering layout schemes only * @param (string) Name of the scheme */ public function renderScheme($scheme_name) { if(isset($this->layout)) $scheme_name = $this->layout; return $this->renderBlock($this->layout, true); } /** * Method which renders modules in GRID layout scheme. * It allows to split modules into different rows which gives more possibilities than standard Boostrap framework * * @param (string) Module position * @param (string) Module chrome - style of the module * @param (int) Number of columns in grid layout */ public function renderModules($position, $chrome = 'none', $grid_layout = 12) { if (!$position) return false; $app = JFactory::getApplication(); // Name of module position $posname = $this->getPosition($position); // Output jdoc tag modules' inclusion for JSN PowerAdmin position changer compatibility if($app->input->get('poweradmin', 0) == 1) { return '<jdoc:include type="modules" name="'.$posname.'" style="'.$chrome.'" />'; } jimport( 'joomla.cms.module.helper' ); $renderer = JFactory::getDocument()->loadRenderer('module'); $frontediting = $app->getCfg('frontediting', 1); $version = new JVersion; // Authorisation $user = JFactory::getUser(); $canEdit = $user->id && $frontediting && !($app->isAdmin() && $frontediting < 2) && $user->authorise('core.edit', 'com_modules'); $correctVersion = (bool)version_compare($version->getShortVersion(), '3.2.0', '>='); $menusEditing = ($frontediting == 2) && $user->authorise('core.edit', 'com_menus'); // A counter that tells us how many grid "columns" ther are left in particular row $bootstrap_row_counter = $grid_layout; $html = ''; // Retrieving all modules from module position if ($modules = JModuleHelper::getModules( $posname )) { $attribs['style'] = $chrome; //$html .= '<div class="'.$position.' count_'.count($modules).' '.$this->getClass($position).'">'; $count = count($modules); $wrap = false; for ($i = 0; $i < $count; $i++) { $module_params = new JRegistry; $module_params->loadString($modules[$i]->params); $modules[$i]->_bs_size = (int)$module_params->get('bootstrap_size', 0); if($modules[$i]->_bs_size != 0 && $modules[$i]->_bs_size != 12) { $wrap = true; } } for ($i = 0; $i < $count; $i++) { $bootstrap_size = $modules[$i]->_bs_size; $span_size = ($bootstrap_size == 0) ? $grid_layout : $bootstrap_size; $module_content = $renderer->render($modules[$i], $attribs, null); $module_html = ''; if($wrap) $module_html = '<div class="span'.$bootstrap_size.'">'; $module_html .= $module_content; if($wrap) $module_html .= '</div>'; // Module edit button for logged-in admins if ($correctVersion && $app->isSite() && $canEdit && trim($module_content) != '' && $user->authorise('core.edit', 'com_modules.module.' . $modules[$i]->id)) { $displayData = array('moduleHtml' => &$module_html, 'module' => $modules[$i], 'position' => $posname, 'menusediting' => $menusEditing); JLayoutHelper::render('joomla.edit.frontediting_modules', $displayData); } // If the column limit has been reached, start a new row if ($wrap && $bootstrap_row_counter == $grid_layout) { $html .= '<div class="row-fluid">'; } $html .= $module_html; // Reducing a counter by SPAN SIZE of each module $bootstrap_row_counter -= $span_size; if ($i < $count-1 && $bootstrap_row_counter > 0) { $next_module_params = new JRegistry; $next_module_params->loadString($modules[$i+1]->params); $next_bootstrap_size = (int)$next_module_params->get('bootstrap_size', '0'); $next_span_size = ($next_bootstrap_size == 0) ? $grid_layout : $next_bootstrap_size; if ((int)($bootstrap_row_counter - $next_span_size) < 0) { $bootstrap_row_counter -= $next_span_size; if($wrap) $html .= '</div>'; } } else { if($wrap) $html .= '</div>'; } $bootstrap_row_counter; if ($bootstrap_row_counter <= 0){ $bootstrap_row_counter = $grid_layout; } } //$html .= '</div>'; } return $html; } /** * Mobile-aware block rendering method, it provides bunch of responsiveness feature possible to setup in Layout Builder * * @param (string) Name of a block * @param (string) Module style * @param (int) Number of columns in a Flexiblock * @param (int) Number of columns in grid layout */ public function renderFlexiblock($name, $chrome = 'none', $cols = 6, $grid_layout = 12) { $dscreen = $this->dscreen; $defpos = array(); for($i = 1; $i <= $cols; $i++) $defpos[] = $name.'-'.$i; $poss = $defpos; $vars = array(); $splparams = array(); for ($i = 1; $i <= $this->maxgrid; $i++) { $param = $this->getLayoutConfig('column' . $i . '#' . $name); if (empty($param)) { break; } else { $splparams[] = $param; } } // we have configuration in setting file if (!empty($splparams)) { $poss = array(); foreach ($splparams as $idx => $splparam) { $param = (object)$splparam; $poss[] = isset($param->position) ? $param->position : $defpos[$idx]; } $cols = count($poss); } // check if there's any modules if (!$this->countModules(implode(' or ', $poss))) { return; } //empty - so we will use default configuration if (empty($splparams)) { //generate a optimize default width $default = $this->genWidth($dscreen, $cols); foreach ($poss as $i => $pos) { //is there any configuration param $var = isset($vars[$pos]) ? $vars[$pos] : ''; $param = new stdClass; $param->position = $pos; $param->$dscreen = ($var && isset($var[$dscreen])) ? $var[$dscreen] : 'span' . $default[$i]; if ($var) { foreach($this->screens as $screen){ if (isset($var[$screen])) { $param->$screen = $var[$screen]; } } } $splparams[$i] = $param; } } //update widths when some positions are empty unless full width feature is disabled for this block $blockparam = $this->getLayoutConfig('block#' . $name); if(@!$blockparam->fixedWidth) { $splparams = $this->updateWidths($splparams); } //build data $responsive = $this->params->get('responsiveLayout', '1'); $datas = array(); foreach ($splparams as $splparam) { $param = (object)$splparam; $data = ''; if($responsive){ foreach($this->screens as $screen){ if(isset($param->$screen)){ if(strpos(' ' . $param->$screen . ' ', ' hidden ') !== false){ $param->$screen = str_replace(' hidden ', ' hidden-' . $screen . ' ', ' ' . $param->$screen . ' '); } $data .= ' data-' . $screen . '="' . $param->$screen . '"'; } } } $datas[] = $data; } $html = '<div class="row-fluid jm-flexiblock jm-'.$name.'">'; foreach($splparams as $i => $splparam) { $param = (object)$splparam; if(@!$blockparam->fixedWidth && !$this->countModules($param->position)) continue; $html.= '<div class="'.$param->default.'" '.$datas[$i].'>'; if($this->countModules($param->position)) { $html.= $this->renderModules($param->position, $chrome, $grid_layout); } else { $html.= '<!-- empty module position -->'; } $html.= '</div>'; } $html.= '</div>'; return $html; } /** * Return number of modules in a Flexiblock * @param (string) Name of a block/position * @param (int) Number of columns in a Flexiblock */ public function countFlexiblock($name, $cols = 4) { $poss = array(); for ($i = 1; $i <= $this->maxgrid; $i++) { $param = $this->getLayoutConfig('column' . $i . '#' . $name); if (empty($param)) { break; } else { $param = (object)$param; $poss[] = isset($param->position) ? $param->position : ''; } } if (empty($poss)) { for($i = 1; $i <= $cols; $i++) $poss[] = $name.'-'.$i; } return $this->countModules(implode(' or ', $poss)); } protected function fitWidth($numpos) { $result = array(); $avg = floor($this->maxgrid / $numpos); $sum = 0; for ($i = 0; $i < $numpos - 1; $i++) { $result[] = $avg; $sum += $avg; } $result[] = $this->maxgrid - $sum; return $result; } protected function genWidth($layout, $numpos) { $cminspan = $this->minspan[$layout]; $total = $cminspan * $numpos; if ($total < $this->maxgrid) { return $this->fitWidth($numpos); } else { $result = array(); $rows = ceil($total / $this->maxgrid); $cols = ceil($numpos / $rows); for ($i = 0; $i < $rows - 1; $i++) { $result = array_merge($result, $this->fitWidth($cols)); $numpos -= $cols; } $result = array_merge($result, $this->fitWidth($numpos)); } return $result; } /** * Getting updated widths for full width flexiblock depending on the module count */ protected function updateWidths($params){ //$start = microtime(true); foreach($this->screens as $screen){ // init row $row = array(); $gsize = in_array($screen, array('mobile', 'tablet')) ? 100 : 12; foreach($params as $i => $param) { // copy default classes to screen settings - it's required for recalculation $dscreen = $this->dscreen; if(!isset($param->$screen)) $param->$screen = $param->$dscreen; // end of a row, recalculate widths for module positions if(strstr($param->$screen, 'first-span')!==false && count($row)) { $row = $this->fulfillRow($row, $gsize); foreach($row as $x => $w) { $params[$x]->$screen = preg_replace('/span(\d+)/', 'span'.$w, $params[$x]->$screen); } // reset row $row = array(); } // add position to the row only if it contains published, not empty modules if($this->countModules($param->position)) { preg_match('/span(\d+)/', $param->$screen, $match); if(count($match)>1) { $row[$i] = $match[1]; } } } // end of a last row, recalculate widths for module positions if(count($row)) { $row = $this->fulfillRow($row, $gsize); foreach($row as $x => $w) { $params[$x]->$screen = preg_replace('/span(\d+)/', 'span'.$w, $params[$x]->$screen); } } } //$time = microtime(true) - $start; //$this->debug('updateWidths() time: '.$time); return $params; } /** * Fulfilling the row to be the full grid size */ protected function fulfillRow($row, $gsize) { asort($row); // empty spans left to fulfill the row $es = $gsize - array_sum($row); foreach($row as $i => $w) { if($es <= 0) return $row; $step = ($gsize > 12 ? 50 : 1); $row[$i] = $w + $step; $es -= $step; } return $this->fulfillRow($row, $gsize); } /** * Getting a classes for HTML layout wrapper */ public function getClass($name, $cls = array()) { $data = ''; $param = $this->getLayoutConfig($name, ''); if (empty($param)) { if (is_string($cls)) { $data = ' ' . $cls; } else if (is_array($cls)) { $param = (object)$cls; } } if (!empty($param)) { if($this->params->get('responsiveLayout', '1')) { foreach ($this->maxcol as $screen => $span) { //convert hidden class if(!empty($param->$screen) && strpos(' ' . $param->$screen . ' ', ' hidden ') !== false){ $param->$screen = str_replace(' hidden ', ' hidden-' . $screen . ' ', ' ' . $param->$screen . ' '); } if(!empty($param->$screen)){ $data .= ' data-' . $screen . '="' . trim($param->$screen) . '"'; } } $dscreen = $this->dscreen; if(!empty($data)){ $data = (isset($param->$dscreen) ? ' ' . $param->$dscreen : '') . ' jm-responsive"' . substr($data, 0, strrpos($data, '"')); } } else { $dscreen = $this->dscreen; // responsive layout is disabled, so we take 'normal' screen classes or default classes $data = (!empty($param->normal) ? $param->normal : (!empty($param->$dscreen) ? $param->$dscreen : '')); // we don't use hidden feature when layout is not responsive $date = str_replace(' hidden ', ' ', ' ' . $data . ' '); } if(isset($param->fullWidth) && $param->fullWidth) $data = ' full-width' . $data; } return $data; } /** * Getting a list of blocks to render for given layout * @param (array/string) list of a default blocks included to the layout * @param (array/string) list of the blocks excluded from the layout builder */ public function getBlocks($default, $exclude = null) { if(is_null($this->blocks)) { $this->blocks = array(); $dblocks = is_array($default) ? $default : explode(',', $default); $path = JPath::clean(JMF_TPL_PATH . '/tpl/blocks'); $files = JFolder::files($path, '\.php'); foreach($files as $file) { $block_name = trim(JFile::stripExt($file)); $param = $this->getLayoutConfig('block#'.$block_name); if(!empty($param)) $this->blocks[$param->ordering] = $block_name; } if(!empty($this->blocks)){ // sort blocks by ordering key ksort($this->blocks); } else { $this->blocks = $dblocks; } $this->blocks[] = 'debug'; array_unshift($this->blocks, 'jmthemeoverlay'); // handling exclude blocks if($exclude) { $fblocks = is_array($exclude) ? $exclude : explode(',', $exclude); $this->front_blocks = array_merge($this->front_blocks, $fblocks); } } return $this->blocks; } /** * Getting value of the layout element from layout configuration * @param (string) Name of the layout element */ public function getLayoutConfig($name, $default = null) { return isset($this->layoutconfig) ? $this->layoutconfig->get($name, $default) : $default; } /** * Method that compiles LESS to CSS file * @param (string) Path to LESS file * @param (bool) If true additional LESS variables from "jm_bootstrap_variables" parameter will be added * @param (bool) Indicates if we are dealing with a file that belongs to template's core. * If yes, it means that we should add suffix for CSS file because different template styles may use * different variables * @param (bool) When true old version of LessC will be used. Otherwise Less_Parser class. */ protected function lessToCss($lessPath, $useVars = true, $coreStyle = true, $legacyCompiler = false) { if (class_exists('lessc') == false && $legacyCompiler) { require_once JMF_FRAMEWORK_PATH.DIRECTORY_SEPARATOR. 'includes' .DIRECTORY_SEPARATOR. 'libraries' .DIRECTORY_SEPARATOR. 'lessc' .DIRECTORY_SEPARATOR. 'lessc.inc.0.4.0.php'; } if (class_exists('Less_Parser') == false && !$legacyCompiler) { //require_once JMF_FRAMEWORK_PATH.DIRECTORY_SEPARATOR. 'includes' .DIRECTORY_SEPARATOR. 'libraries' .DIRECTORY_SEPARATOR. 'less_parser' .DIRECTORY_SEPARATOR. 'Less.php'; require_once JMF_FRAMEWORK_PATH.DIRECTORY_SEPARATOR. 'includes' .DIRECTORY_SEPARATOR. 'libraries' .DIRECTORY_SEPARATOR. 'less_parser' .DIRECTORY_SEPARATOR. 'Autoloader.php'; Less_Autoloader::register(); } $developer_mode = ($this->params->get('devmode', false) == '1') ? true : false; $filename = JFile::stripExt(JFile::getName($lessPath)); //$style_id = @JFactory::getApplication()->getTemplate(true)->id; $style_id = self::getTemplateStyleId(); $css_suffix = ''; // A suffix is simply ID of template style, eg. template.10.css if ($style_id > 0 && $coreStyle) { $css_suffix = '.'.$style_id; } // Establishing path to CSS file $cssPath = JPath::clean(JMF_TPL_PATH . '/css/' . $filename.$css_suffix. '.css'); // Checking if LESS file exists. If not we should make sure that we're looking in correct directory if (!JFile::exists($lessPath)) { $lessPath = JPath::clean(JMF_TPL_PATH . '/less/' . $filename. '.less'); } // If developer mode is disabled and CSS file is not older than LESS file, we do not have to compile LESS file. if (JFile::exists($lessPath) && JFile::exists($cssPath)) { $lessTime = filemtime($lessPath); $cssTime = filemtime($cssPath); // checking all dependent less files $forceCompile = false; if (!empty($this->lessMap) && !empty($this->lessMap[$filename.'.less'])) { $depLess = $this->lessMap[$filename.'.less']; foreach ($depLess as $depLessFile) { $depName = JPath::clean(JMF_TPL_PATH.'/less/'.$depLessFile); if (JFile::exists($depName)) { $depTime = filemtime($depName); if ($depTime > $cssTime) { $forceCompile = true; break; } } } } if ($lessTime <= $cssTime && $forceCompile == false && $developer_mode == false) { return JMF_TPL_URL. '/css/' . $filename.$css_suffix.'.css'; } } // At this point, either we are in developer mode or CSS file does not exist or is older than LESS file. // But if CSS file does exist, we should delete it if (JFile::exists($cssPath)) { JFile::delete($cssPath); } try { if ($legacyCompiler) { // Initialising LessC compiler $less = new lessc(); // Additional LESS variables if ($useVars) { $variables = $this->params->get('jm_bootstrap_variables', array()); if (!empty($variables)) { $less->setVariables($variables); } } // Checked Compile - LessC $less->checkedCompile($lessPath, $cssPath); } else { // Less_Parser compiler $less_parser_options = array( 'compress'=> ($this->params->get('lessCompress','1')=='1' ? true : false), 'relativeUrls' => false, 'sourceMap' => false ); if ($this->params->get('sourceMap', false) == '1') { // maps don't work when compression is enabled $less_parser_options['compress'] = false; $less_parser_options['sourceMap'] = true; $less_parser_options['sourceMapWriteTo'] = JPath::clean(JMF_TPL_PATH . '/css/' . $filename.$css_suffix. '.map'); $less_parser_options['sourceMapURL'] = JUri::base(true).'/templates/'.JMF_TPL.'/css/' . $filename.$css_suffix.'.map'; $less_parser_options['sourceMapFilename'] = JUri::base(true).'/templates/'.JMF_TPL.'/css/' . $filename.$css_suffix.'.css'; $less_parser_options['sourceMapBasepath'] = str_replace(DIRECTORY_SEPARATOR, '/', JPATH_ROOT); $less_parser_options['sourceRoot'] = JUri::base(false); } $less_parser = new Less_Parser($less_parser_options); // Additional LESS variables if ($useVars) { $variables = $this->params->get('jm_bootstrap_variables', array()); if (!empty($variables)) { // Less_Parser $less_parser->ModifyVars($variables); } } // Less_Parser - LESS file $less_parser->parseFile($lessPath, JMF_TPL_URL.'/css'); // Compilation - Less_Parser if ($css_content = $less_parser->getCss()){ if (JFile::write($cssPath, $css_content) == false) { throw new Exception('Cannot save CSS file. Please check your directory permissions.'); } } } } catch (exception $e) { throw new Exception(JText::sprintf('PLG_SYSTEM_JMFRAMEWORK_LESS_ERROR', $e->getMessage())); } // Returning CSS file's URL return JMF_TPL_URL. '/css/' . $filename.$css_suffix.'.css'; } /** * Method that converts template LESS file's path to an URL * @param (string) Path to LESS file. */ protected function getLessUrl($lessPath) { $filename = JFile::stripExt(JFile::getName($lessPath)); if (!JFile::exists($lessPath)) { $lessPath = JMF_TPL_PATH . DIRECTORY_SEPARATOR. 'less' .DIRECTORY_SEPARATOR. $filename. '.less'; } if (JFile::exists($lessPath)) { if (JPATH_ROOT && JPATH_ROOT != '/') { $lessPath = str_replace(JPATH_ROOT, '', realpath($lessPath)); } $lessPath = str_replace(DIRECTORY_SEPARATOR, '/', $lessPath); if(substr($lessPath, 0, 1) == '/') { $lessPath = substr($lessPath, 1); } return JURI::root(false) . $lessPath; } return false; } /** * Initialising Theme Customiser Switch */ protected function attachTCSwitch(){ // Load only toggler styles - inline for better performance $this->addStyleDeclaration(" #jmthemetoggler { display: block; left: 0; top: 50%; margin-top: -25px; position: fixed; background: #383e49; color: #fff; width: 50px; height: 50px; overflow: hidden; z-index: 9999; cursor: pointer; text-align: center; vertical-align: middle; border-radius: 0 8px 8px 0; -webkit-border-radius: 0 8px 8px 0; border-bottom: 1px solid #2a2e37; border-left: 1px solid #2a2e37; box-shadow: inset 1px 1px 0px 0px rgba(255, 255, 255, 0.2); -webkit-box-shadow: inset 1px 1px 0px 0px rgba(255, 255, 255, 0.2); } #jmthemetoggler:hover { background: #454b55; } #jmthemetoggler::after { background: url('". JMF_FRAMEWORK_URL."/includes/assets/template/themecustomiser/tc-sprites.png') no-repeat 0 -23px; width: 22px; height: 22px; position: absolute; content: ''; left: 14px; top: 14px; -webkit-transition: all 0.8s ease; -moz-transition: all 0.8s ease; -ms-transition: all 0.8s ease; -o-transition: all 0.8s ease; transition: all 0.8s ease; } #jmthemetoggler:after { animation: 2s spinnow infinite linear; -moz-animation: 2s spinnow infinite linear; -webkit-animation: 2s spinnow infinite linear; -ms-animation: 2s spinnow infinite linear; } @-webkit-keyframes spinnow { 100% { transform: rotate(360deg); -webkit-transform: rotate(360deg); } } @-moz-keyframes spinnow { 100% { transform: rotate(360deg); -moz-transform: rotate(360deg); } } @-ms-keyframes spinnow { 100% { transform: rotate(360deg); -ms-transform: rotate(360deg); } } "); JURI::reset(); $uri = JURI::getInstance(); $uri->setVar('tc','1'); $url_on = $uri->toString(); JURI::reset(); $this->addScriptDeclaration(" jQuery(window).load(function(){ var url_on = '".$url_on."'; jQuery('body').append('<span id=\"jmthemetoggler\"></span>'); jQuery('#jmthemetoggler').on('click', function(){ jQuery('#jmthemeoverlay').addClass('visible'); setTimeout(function(){ jQuery.post(url_on).always(function(){ jQuery('#jmthemetogglerform').submit(); }); }, 600); }); }); "); } /** * Initialising Theme Customiser if necessary * @param (bool) If true, additional LESS variables will be added to Theme Customiser */ protected function attachThemeCustomiser($useVars = true){ if (self::$less_js_included == false) { //JHTML::_('behavior.framework', true); JHtml::_('jquery.ui', array('core', 'sortable')); // For standard color picker JHtml::_('script', 'system/html5fallback.js', false, true); JHtml::_('behavior.colorpicker'); if(!defined('JMF_TPL_ASSETS')){ define('JMF_TPL_ASSETS', JURI::root(false).'plugins/system/ef4_jmframework/includes/assets/admin/'); } $app = JFactory::getApplication(); $jconf = JFactory::getConfig(); $cookie_path = ($jconf->get('cookie_path') == '') ? JUri::base(true) : $jconf->get('cookie_path'); $cookie_domain = ($jconf->get('cookie_domain') == '') ? $_SERVER['HTTP_HOST'] : $jconf->get('cookie_domain'); $global_vars = array(); // taking LESS initial variables generated by the template (based on parameters) if ($useVars) { $params = $this->document->params->toArray(); $variables = $this->params->get('jm_bootstrap_variables', array()); $variables = array_merge($params, $variables); if (!empty($variables)){ foreach($variables as $k=>$v) { $global_vars['@'.$k] = $v; } } } // Making sure that variables don't start with @. // Less.js doesn't want @ before variable name, whicle LessC PHP compiler requires it. $form_vars = array(); $values_black_list = array('<script', 'script', 'object', '<object', 'embed', '<embed'); foreach ($global_vars as $k=>$v) { // Skiping unsafe variables $skip = false; if (is_scalar($v)) { foreach($values_black_list as $block) { if (strpos($v, $block) !== false) { $skip = true; break; } } } if ($skip) continue; $form_vars[str_replace('@','',$k)] = $v; } // Including and merging variables stored in a Cookie by Theme Customiser, which override default params. $ts_cookie = JFactory::getApplication()->input->cookie->get('JMTH_TIMESTAMP_'.$this->template, 0); if ((int)$ts_cookie != -1) { //$form_cookie_vars = JFactory::getApplication()->input->cookie->get('JM_form_vars_'.$this->template, false, 'raw'); $form_cookie_vars = JFactory::getApplication()->getUserState($this->template.'.themer.state', false); if ($form_cookie_vars) { $cashed_vars = json_decode($form_cookie_vars, true); foreach ($cashed_vars as $k=>$v) { if (preg_replace('#[^0-9a-z]#i', '', $v) != '') { $form_vars[$k] = $v; } } } } JFactory::getApplication()->input->cookie->set('JMTH_TIMESTAMP_'.$this->template, time(), 0, $cookie_path); // Saving all set of variables into Cookie. Just to be sure they won't get lost somewhere. //JFactory::getApplication()->input->cookie->set('JM_form_vars_'.$this->template, json_encode($form_vars), 0, $cookie_path); JFactory::getApplication()->setUserState($this->template.'.themer.state', json_encode($form_vars)); // All LESS vars that go directly in LESS object start with 'JM'. We don't need to pass any other variables. $less_vars = array(); foreach($form_vars as $k=>$v) { if (substr($k, 0, 2) == 'JM') { $less_vars[$k] = $v; } } $developer_mode = ($this->params->get('devmode', false) == '1') ? true : false; $less_mode = ($developer_mode) ? 'development' : 'production'; $less_log = ($developer_mode) ? '2' : '0'; $less_dump = ($developer_mode) ? 'comments' : ''; $script_init = ' less = { env: "'.$less_mode.'", mode: "browser", async: false, logLevel: '.$less_log.', fileAsync: false, poll: 1000, functions: {}, dumpLineNumbers: "'.$less_dump.'", relativeUrls: false, rootpath: "'.JMF_TPL_URL.'/less/", globalVars: '.json_encode($less_vars).' };'; // Must use addCustomTag() instead of addScript(), because LESS's init script has to go before LESS library. $this->document->addCustomTag('<script type="text/javascript">'.$script_init.'</script>'); $this->document->addCustomTag('<script type="text/javascript" src="'. JMF_FRAMEWORK_URL.'/includes/assets/template/themecustomiser/less-1.7.0.min.js' .'"></script>'); $this->document->addCustomTag('<script type="text/javascript" src="'. JMF_FRAMEWORK_URL.'/includes/assets/template/themecustomiser/jmthemecustomiser.jquery.js' .'" defer="defer"></script>'); $language = array( 'LANG_PLEASE_WAIT' => JText::_('PLG_SYSTEM_JMFRAMEWORK_THEMER_WAIT'), 'LANG_PLEASE_WAIT_APPLYING' => JText::_('PLG_SYSTEM_JMFRAMEWORK_THEMER_WAIT_APPLYING'), 'LANG_PLEASE_WAIT_SAVING' => JText::_('PLG_SYSTEM_JMFRAMEWORK_THEMER_WAIT_SAVING'), 'LANG_PLEASE_WAIT_RELOADING' => JText::_('PLG_SYSTEM_JMFRAMEWORK_THEMER_WAIT_RELOADING'), 'LANG_ERROR_FORBIDDEN' => JText::_('PLG_SYSTEM_JMFRAMEWORK_THEME_LOGIN_ERROR'), 'LANG_ERROR_UNAUTHORISED' => JText::_('PLG_SYSTEM_JMFRAMEWORK_THEME_ACCESS_ERROR'), 'LANG_ERROR_BAD_REQUEST' => JText::_('PLG_SYSTEM_JMFRAMEWORK_THEME_BAD_REQUEST_ERROR') ); // extending JMThemeCustomiser with some variables and initialising Theme Customiser $script_interface = " jQuery(document).ready(function(){ jQuery.extend(JMThemeCustomiser, { url: '" . JFactory::getURI()->toString() . "', lang: ".json_encode($language).", lessVars: ".json_encode($form_vars).", cookie: {path: '".$cookie_path."', domain: '".$cookie_domain."'}, styleId : ".(int)self::getTemplateStyleId().", login_form : ".(int)$this->document->params->get('themerlogin', 0)." }); JMThemeCustomiser.init(\"".$this->template."\"); JMThemeCustomiser.render(); jQuery(document).trigger('JMFrameworkInit'); var wrapper = jQuery('#jmthemewrapper'), toggler = jQuery('#jmthemetoggler'), close = jQuery('<span id=\"jmthemeclose\"></span>'); toggler.on('click', function(event){ if(wrapper.hasClass('active')) { JMThemeCustomiser.setCookie('jmthemeclose', '0'); } else { JMThemeCustomiser.setCookie('jmthemeclose', '1'); } }); wrapper.append(close); close.click(function(){ jQuery('#jmthemetogglerform').submit(); }); var closed = JMThemeCustomiser.getCookie('jmthemeclose'); if(closed!='1') { toggler.trigger('click'); } }); "; $this->document->addCustomTag('<script type="text/javascript">'.$script_interface.'</script>'); // Adding all scripts manually $this->document->addStyleSheet(JMF_FRAMEWORK_URL.'/includes/assets/template/themecustomiser/jmthemecustomiser.css'); //$this->document->addStyleSheet(JURI::root(false).'plugins/system/ef4_jmframework/includes/assets/admin/formfields/jmiriscolor/iris.min.css'); $this->document->addScript(JURI::root(false).'plugins/system/ef4_jmframework/includes/assets/admin/js/jquery/jquery.ui.draggable.js'); $this->document->addScript(JURI::root(false).'plugins/system/ef4_jmframework/includes/assets/admin/js/jquery/jquery.ui.slider.js'); $this->document->addScript(JURI::root(false).'plugins/system/ef4_jmframework/includes/assets/admin/js/jquery/jquery.ui.accordion.js'); //$this->document->addScript(JURI::root(false).'plugins/system/ef4_jmframework/includes/assets/admin/formfields/jmiriscolor/iris.js'); $this->document->addScript(JURI::root(false).'plugins/system/ef4_jmframework/includes/assets/admin/js/jmoptiongroups.js'); $this->document->addScript(JURI::root(false).'plugins/system/ef4_jmframework/includes/assets/admin/js/jmgooglefont.js'); $this->document->addScriptDeclaration(" jQuery(document).on('JMFrameworkInit', function(){ jQuery('#jmthemewrapper .jmirispicker').each(function() { jQuery(this).iris({ hide: true, palettes: true }); }); jQuery('#jmthemewrapper .minicolors').each(function() { jQuery(this).minicolors({ control: jQuery(this).attr('data-control') || 'hue', position: jQuery(this).attr('data-position') || 'right', theme: 'bootstrap' }); }); jQuery(document).on('click',function(event){ jQuery('#jmthemewrapper .jmirispicker').each(function() { if (event.target != this && typeof jQuery(this).iris != 'undefined') { jQuery(this).iris('hide'); } }); }); var JMThemerGoogleFonts = new JMGoogleFontHelper('.google-font-url').initialise(); }); "); self::$less_js_included = true; } } /** * Displays the component block, but only if it hasn't been disabled for current menu item. */ public function displayComponent(){ $app = JFactory::getApplication(); $display = !in_array($app->input->get('Itemid'), (array)$this->params->get('DisableComponentDisplay', array())); if(!$display) { // check if current view is the same as menu item $menu = $app->getMenu(); // Get active menu $active = $menu->getActive(); // if no active menu then try to get menu item by current Itemid if(!$active) $active = $menu->getItem($app->input->get('Itemid')); // no active menu item if(!$active) return true; // compare current option and view with real menu item query foreach($active->query as $param => $value) { if($app->input->get($param, '') != $value) $display = true; } } return $display; } /** * Displays the message block, but only if there are any messages to show */ public function displayMessage(){ $app = JFactory::getApplication(); $queue = $app->getMessageQueue(); return count($queue) > 0 ? true : false; } /** * Returns column classes and data-* for all screens */ public function getAllColumnsClasses() { $class = array(); $leftClass = $this->getClass('left-column'); $rightClass = $this->getClass('right-column'); $scheme = $this->getLayoutConfig('#scheme','lcr'); $left = $this->params->get('columnLeftWidth', '3'); $right = $this->params->get('columnRightWidth', '3'); $content = 12 - $left - $right; if ((!$this->checkModules('left-column')) && (!$this->checkModules('right-column'))) { $content = 12; $scheme = str_replace(array('l','r'), '', $scheme); $right = 0; $left = 0; } else if (($this->checkModules('left-column')) && (!$this->checkModules('right-column'))) { $content = 12 - $left; $scheme = str_replace(array('r'), '', $scheme); $right = 0; } else if ((!$this->checkModules('left-column')) && ($this->checkModules('right-column'))) { $content = 12 - $right; $scheme = str_replace(array('l'), '', $scheme); $left = 0; } // get default classes $class = self::getColumnClasses($scheme, $content, $left, $right); // wide and normal screens foreach(array('wide','normal') as $screen) { $l = strpos($leftClass, 'hidden-'.$screen) !== false ? 0 : $left; $r = strpos($rightClass, 'hidden-'.$screen) !== false ? 0 : $right; if($l != $left || $r != $right) { $s = $scheme; $c = $content; if($l != $left) { $s = str_replace(array('l'), '', $s); $c += $left; } if($r != $right) { $s = str_replace(array('r'), '', $s); $c += $right; } $sclass = $this->getColumnClasses($s, $c, $l, $r, $screen); foreach($class as $col => $cls) { $class[$col] .= '" data-'.$screen.'="'.$sclass[$col]; } } } // tablet and mobile screens foreach(array('xtablet','tablet','mobile') as $screen) { $c = 12; $l = strpos($leftClass, 'hidden-'.$screen) !== false ? 0 : $left ? ($screen == 'mobile' ? 12 : 6) : 0; $r = strpos($rightClass, 'hidden-'.$screen) !== false ? 0 : $right ? ($screen == 'mobile' ? 12 : 6) : 0; $sclass = $this->getColumnClasses($screen, $c, $l, $r, $screen); foreach($class as $col => $cls) { $class[$col] .= '" data-'.$screen.'="'.$sclass[$col]; } } return $class; } /** * Returns names of main column classes depending on given scheme * * @param (string) Scheme short name, eg. "lcr" = "Left Content Right" * @param (int) Content offset * @param (int) Left column offset * @param (int) Right column offset */ public function getColumnClasses($s, $c, $l, $r, $screen = false) { $class = array('content'=>'', 'left'=> $screen ? 'hidden-'.$screen : '', 'right'=> $screen ? 'hidden-'.$screen : ''); switch($s) { case 'lcr': $class['content'] = "span$c offset$l"; $class['left'] = "span$l offset-".($c+$l); $class['right'] = "span$r"; break; case 'clr': $class['content'] = "span$c"; $class['left'] = "span$l"; $class['right'] = "span$r"; break; case 'crl': $class['content'] = "span$c"; $class['left'] = "span$l offset$r"; $class['right'] = "span$r offset-".($l+$r); break; case 'rcl': $class['content'] = "span$c offset$r"; $class['left'] = "span$l"; $class['right'] = "span$r offset-".($c+$l+$r); break; case 'lrc': $class['content'] = "span$c offset".($l+$r); $class['left'] = "span$l offset-".($c+$l+$r); $class['right'] = "span$r offset-".($c+$r); break; case 'rlc': $class['content'] = "span$c offset".($l+$r); $class['left'] = "span$l offset-".($c+$l); $class['right'] = "span$r offset-".($c+$l+$r); break; case 'cl': $class['content'] = "span$c"; $class['left'] = "span$l"; break; case 'cr': $class['content'] = "span$c"; $class['right'] = "span$r"; break; case 'lc': $class['content'] = "span$c offset$l"; $class['left'] = "span$l offset-".($c+$l); break; case 'rc': $class['content'] = "span$c offset$r"; $class['right'] = "span$r offset-".($c+$r); break; case 'c': $class['content'] = "span$c"; break; default: if($l && $r) { $class['content'] = "span".($s == 'tablet' || $s == 'mobile' ? floor(100 * $c / 12) : $c); $class['left'] = "span".($s == 'tablet' || $s == 'mobile' ? floor(100 * $l / 12) : $l); $first = false; if($c+$l > 12) { $class['left'] .= ' first-span'; $first = true; } $class['right'] = "span".($s == 'tablet' || $s == 'mobile' ? floor(100 * $r / 12) : $r); if($first && $l+$r > 12) { $class['right'] .= ' first-span'; } else if(!$first && $c+$l+$r > 12) { $class['right'].= ' first-span'; } } else if($l) { if($c+$l > 12) { $class['content'] = 'span12'; $class['left'] = 'span12 first-span'; } else { $class['content'] = "span".($s == 'tablet' || $s == 'mobile' ? floor(100 * $c / 12) : $c); $class['left'] = "span".($s == 'tablet' || $s == 'mobile' ? floor(100 * $l / 12) : $l); } } else if($r) { if($c+$r > 12) { $class['content'] = 'span12'; $class['right'] = 'span12 first-span'; } else { $class['content'] = "span".($s == 'tablet' || $s == 'mobile' ? floor(100 * $c / 12) : $c); $class['right'] = "span".($s == 'tablet' || $s == 'mobile' ? floor(100 * $r / 12) : $r); } } else { $class['content'] = 'span12'; } break; } return $class; } /** * Utility method for internal framework's AJAX calls. Not for template developers */ public function ajax(){ $app = JFactory::getApplication(); $jmajax = $app->input->getCmd('jmajax'); $task = $app->input->getCmd('jmtask'); if($jmajax == 'themer') { // Themer tasks // clear the buffer from any output if (!count(array_diff(ob_list_handlers(), array('default output handler'))) || ob_get_length()) { @ob_clean(); } $output = ''; $ctype = 'text/plain'; switch($task) { case 'display': $output = $this->renderThemer(); break; case 'save': $output = $this->saveThemerConfig(false); break; case 'save_file': $output = $this->saveThemerConfig(true); break; case 'get_state': $output = $this->getThemerState(); break; case 'set_state': $output = $this->setThemerState(); break; default: $output = self::renderAlert(JText::_('PLG_SYSTEM_JMFRAMEWORK_UNKNOWN_TASK')); } if (!headers_sent()) { $document = JFactory::getDocument(); header('Content-Type: '.$ctype.'; charset='.$document->_charset); } echo $output; // close application $app->close(); } } /** * Stores configuration created with Theme Customiser. Not for template developers. * @param (bool) If true, configuration will be stored in JSON file. If not - in the database. */ public function saveThemerConfig($save_to_file = true){ $app = JFactory::getApplication(); $input = $app->input; $db = JFactory::getDbo(); $user = JFactory::getUser(); $result = new JObject; $actions = JAccess::getActionsFromFile(JPATH_ADMINISTRATOR . '/components/com_templates/access.xml', "/access/section[@name='component']/"); foreach ($actions as $action) { $result->set($action->name, $user->authorise($action->name, 'com_templates')); } $hasAccess = false; $isLoggedIn = $user->guest ? false : true; if ($result->get('core.edit')) { $hasAccess = true; } if (!$isLoggedIn) { $msg = JText::_('PLG_SYSTEM_JMFRAMEWORK_THEME_LOGIN_ERROR'); throw new Exception($msg, 403); return false; } else if (!$hasAccess) { $msg = JText::_('PLG_SYSTEM_JMFRAMEWORK_THEME_ACCESS_ERROR'); throw new Exception($msg, 401); return false; } $style_id = $input->getInt('jmstyleid', 0); if (!$style_id) { $msg = JText::_('PLG_SYSTEM_JMFRAMEWORK_THEME_BAD_REQUEST_ERROR'); throw new Exception($msg, 400); return false; } $data = $input->get('jmvars', array(), 'array'); if (empty($data)) { return false; } $db->setQuery('SELECT params FROM #__template_styles WHERE id='.(int)$style_id.' LIMIT 1'); $params = $db->loadResult(); $params = (!empty($params)) ? json_decode($params, true) : false; if (empty($params)) { return false; } foreach($data as $k=>$v) { if (is_scalar($v) /*&& array_key_exists($k, $params)*/) { $params[$k] = $v; } } // We decided not to delete CSS files. They will be deleted when user disables TC and save the config in the back-end. // $this->purgeStyleSheets($style_id); if ($save_to_file) { $path = JMF_TPL_PATH . DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'config'; if (JFolder::exists($path) == false) { JFolder::create($path); } $base_name = 'custom_style'; if (!empty($params['templateStyle'])) { $base_name .= '_'.$params['templateStyle']; } else { $base_name .= '_0'; } $iterator = 0; $file_name = $base_name.'.cfg.json'; while(JFile::exists($path.DIRECTORY_SEPARATOR.$file_name)) { $iterator++; $suffix = '_'.$iterator; $file_name = $base_name.$suffix.'.cfg.json'; } $params = json_encode($params); if(JFile::write($path.DIRECTORY_SEPARATOR.$file_name, $params)) { return JText::sprintf('PLG_SYSTEM_JMFRAMEWORK_THEME_SETTINGS_SAVED_TO_FILE', $file_name); } else { return JText::_('PLG_SYSTEM_JMFRAMEWORK_THEME_SETTINGS_SAVING_ERROR'); } } else { $params = json_encode($params); $db->setQuery('UPDATE #__template_styles SET params='.$db->quote($params).' WHERE id='.(int)$style_id); if ($db->query() == false) { return $db->getErrorMsg(); } if (defined('JMF_TPL')) { // dump CSS sheets which were made from LESS files $suffix = ($style_id > 0) ? '.'.$style_id : ''; $less_files = JFolder::files(JPath::clean(JPATH_ROOT.'/templates/'.JMF_TPL.'/less'), '\.less$'); $css_files = JFolder::files(JPath::clean(JPATH_ROOT.'/templates/'.JMF_TPL.'/css'), '\.css$'); foreach ($less_files as $less) { $name = JFile::stripExt($less); /*if (in_array($name.'.css', $css_files)) { JFile::delete(JPath::clean(JPATH_ROOT.'/templates/'.JMF_TPL.'/css/').$name.'.css'); }*/ if (in_array($name.$suffix.'.css', $css_files)) { JFile::delete(JPath::clean(JPATH_ROOT.'/templates/'.JMF_TPL.'/css/').$name.$suffix.'.css'); } } } return JText::_('PLG_SYSTEM_JMFRAMEWORK_THEME_SETTINGS_SAVED_TO_DB'); } } /** * Rendering Theme Customiser's form. Not for template developers. */ public function renderThemer() { $form = new JForm('jmframework.themecustomiser'); jimport('joomla.filesystem.path'); $plg_file = JPath::find(JMF_FRAMEWORK_PATH . DS. 'includes' . DS .'assets' . DS . 'admin' . DS . 'params', 'template.xml'); $tpl_file = JPath::find(JPATH_ROOT . DS. 'templates' . DS . JMF_TPL, 'templateDetails.xml'); if (!$tpl_file && !$plg_file) { return false; } if ($plg_file){ $form->loadFile($plg_file, false, '//form'); } if ($tpl_file){ $form->loadFile($tpl_file, false, '//config//fields[@name="themecustomiser"]'); $form->loadFile($tpl_file, false, '//tplconfig//fields[@name="themecustomiser"]'); } $fieldSets = $form->getFieldsets('themecustomiser'); if (empty($fieldSets)){ return false; } $path = JPath::clean(JMF_FRAMEWORK_PATH.'/includes/assets/admin/layouts/themecustomiser.php'); ob_start(); if (JFile::exists($path)) { include($path); } else { throw new Exception('Missing file: '.$layoutbuilder_path, 500); } $html = ob_get_contents(); ob_end_clean(); return $html; } /** * Getter for current set of settings in Theme Customiser */ public function getThemerState() { $app = JFactory::getApplication(); return $app->getUserState(JMF_TPL.'.themer.state', ''); } /** * Setter for current set of settings in Theme Customiser */ public function setThemerState() { $app = JFactory::getApplication(); $data = $app->input->get('jmvars', null, 'raw'); /*if (!$data) { return ''; }*/ $app->setUserState(JMF_TPL.'.themer.state', $data); return $data; } /** * Method that purges all CSS files that were created out of LESS files. */ public static function purgeStyleSheets($style_id = 0) { $css_files = JFolder::files(JPath::clean(JPATH_ROOT.'/templates/'.JMF_TPL.'/css'), '\.css$'); $less_files = JFolder::files(JPath::clean(JPATH_ROOT.'/templates/'.JMF_TPL.'/less'), '\.less$'); if (is_array($less_files)) { $suffix = ($style_id > 0) ? '.'.$style_id : ''; foreach ($less_files as $less) { $name = JFile::stripExt($less); /*if (in_array($name.'.css', $css_files)) { JFile::delete(JPath::clean(JPATH_ROOT.'/templates/'.JMF_TPL.'/css/').$name.'.css'); }*/ if (in_array($name.$suffix.'.css', $css_files)) { JFile::delete(JPath::clean(JPATH_ROOT.'/templates/'.JMF_TPL.'/css/').$name.$suffix.'.css'); } } } return true; } public static function getTemplateStyleId() { if (self::$style_id !== false) { return self::$style_id; } $app = JFactory::getApplication(); if ($app->isAdmin()) { $option = $app->input->get('option', null, 'string'); $view = $app->input->get('view', null, 'string'); $task = $app->input->get('task', '', 'string'); $controller = current(explode('.',$task)); $id = $app->input->get('id', null, 'int'); if ($option == 'com_templates' && ($view == 'style' || $controller == 'style' || $task == 'apply' || $task == 'save' || $task == 'save2copy') && $id > 0) { self::$style_id = $id; } } else { $id = @JFactory::getApplication()->getTemplate(true)->id; if (!$id) { $menu = $app->getMenu(); $item = $menu->getActive(); if (!$item) { $item = $menu->getItem($app->input->getInt('Itemid', null)); } $id = 0; if (is_object($item)) { // Valid item retrieved $id = $item->template_style_id; } $tid = $app->input->getUint('templateStyle', 0); if (is_numeric($tid) && (int) $tid > 0) { $id = (int) $tid; } // Load styles $db = JFactory::getDbo(); $query = $db->getQuery(true) ->select('id, home, template, s.params') ->from('#__template_styles as s') ->where('s.client_id = 0') ->where('e.enabled = 1') ->join('LEFT', '#__extensions as e ON e.element=s.template AND e.type=' . $db->quote('template') . ' AND e.client_id=s.client_id'); $db->setQuery($query); $templates = $db->loadObjectList('id'); $template = false; foreach ($templates as &$template) { // Create home element if (($template->home == 1 && !isset($templates[0])) || ($app->getLanguageFilter() && $template->home == $app->getLanguage()->getTag())) { $templates[0] = clone $template; } } if (isset($templates[$id])) { $template = $templates[$id]; } else { $template = $templates[0]; } self::$style_id = $template->id; } else { self::$style_id = $id; } } return self::$style_id; } /** * Utility method that renders messages. Not for template developers. */ public static function renderAlert($msg) { return $msg; } /** * Utility method for quick debugging. */ public static function debug($data, $exit = false, $type = 'warning'){ $app = JFactory::getApplication(); if($exit) { echo "JMF DEBUG:"; echo "<pre>".print_r($data,true)."</pre>"; $app->close(); } else { $app->enqueueMessage("<pre>JMF DEBUG:\n".print_r($data,true)."</pre>", $type); } } }
[+]
..
[-] admin.php
[edit]
[-] index.html
[edit]
[+]
less
[+]
lessc
[+]
less_parser
[+]
minify
[+]
Mobile_Detect
[-] modulehelper.php
[edit]
[+]
opengraph
[-] template.php
[edit]
[-] .htaccess.disabled
[edit]