File manager - Edit - /home/ferretapmx/public_html/parser.tar
Back
addons.php 0000644 00000005276 15231056562 0006544 0 ustar 00 <?php /** * @package SP Page Builder * @author JoomShaper http://www.joomshaper.com * @copyright Copyright (c) 2010 - 2023 JoomShaper * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 or later */ // No direct access defined('_JEXEC') or die('Restricted access'); use Joomla\CMS\Filesystem\File; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Uri\Uri; /** * Addons class * * @since 1.0.0 */ abstract class SppagebuilderAddons { /** * The addon information * * @var object|null */ protected $addon = null; /** * The layout path for the easystore * * @var string */ protected $easystoreLayoutPath = JPATH_ROOT . '/components/com_easystore/layouts'; /** * Constructor function * * @param array $addon * * @return mixed * @since 1.0.0 */ public function __construct($addon) { if (!$addon) { return false; } $this->addon = $addon; } /** * Check placeholder file path for each media image * * @return mixed * * @since 1.0.0 */ protected function get_image_placeholder($src) { $config = ComponentHelper::getParams('com_sppagebuilder'); $lazyload = $config->get('lazyloadimg', '0'); if ($lazyload) { $filename = basename($src); $mediaPath = 'media/com_sppagebuilder/placeholder'; $basePath = JPATH_ROOT . '/' . $mediaPath . '/' . $filename; $defaultImg = 'https://sppagebuilder.com/addons/image/image1.jpg'; if (File::exists($basePath)) { return $mediaPath . '/' . $filename; } elseif ($src == $defaultImg) { return $src; } else { $placeholderUrl = $config->get('lazyplaceholder', '/components/com_sppagebuilder/assets/images/lazyloading-placeholder.svg'); $pattern = '/^https?:\/\//'; if (preg_match($pattern, $placeholderUrl)) { return $placeholderUrl; } return Uri::root(true) . $placeholderUrl; } } return false; } /** * Get any valid image dimension * * @return array * * @since 1.0.0 */ protected function get_image_dimension($src) { $src = JPATH_BASE . Path::clean($src); if (!File::exists($src)) { return []; } preg_match('/\__(.*?)\./', $src, $match); if (count($match) > 1) { $dimension = explode('x', $match[1]); return ['width="' . $dimension[0] . '"', 'height="' . $dimension[1] . '"']; } $validImageExtensions = ['jpg', 'jpeg', 'png']; $extension = strtolower(pathinfo($src, PATHINFO_EXTENSION)); if (\in_array($extension, $validImageExtensions)) { $dimension = \getimagesize($src); if (!empty($dimension)) { return ['width="' . $dimension[0] . '"', 'height="' . $dimension[1] . '"']; } } return []; } } addon-utils.php 0000644 00000001722 15231056562 0007507 0 ustar 00 <?php /** * @package SP Page Builder * @author JoomShaper https://www.joomshaper.com * @copyright Copyright (c) 2010 - 2023 JoomShaper * @license https://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 or later */ // No direct access defined('_JEXEC') or die('Restricted access'); /** * Helper class for handling the lodash string. * * @since 4.0.0 */ final class AddonUtils { public static $defaultDevice = 'xl'; public static function parseMediaData($media) { if (empty($media)) { return ''; } if (\is_object($media) && isset($media->src)) { return $media->src; } if (\is_array($media) && isset($media['src'])) { return $media['src']; } return $media; } public static function parseDeviceData($data, $device = '') { if (empty($data)) { return ''; } $device = !empty($device) ? $device : self::$defaultDevice; if (\is_object($data) && isset($data->$device)) { return $data->$device; } return $data; } } addon-parser.php 0000644 00000117224 15231056562 0007650 0 ustar 00 <?php /** * @package SP Page Builder * @author JoomShaper http://www.joomshaper.com * @copyright Copyright (c) 2010 - 2023 JoomShaper * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 or later */ use Joomla\CMS\Factory; use Joomla\CMS\Uri\Uri; use Joomla\CMS\Access\Access; use Joomla\CMS\Filesystem\File; use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Layout\FileLayout; use Joomla\CMS\Plugin\PluginHelper; // No direct access defined('_JEXEC') or die('Restricted access'); require_once __DIR__ . '/addons.php'; require_once __DIR__ . '/../helpers/helper.php'; require_once __DIR__ . '/../helpers/addon-helper.php'; require_once JPATH_ROOT . '/components/com_sppagebuilder/builder/classes/base.php'; require_once JPATH_ROOT . '/components/com_sppagebuilder/builder/classes/config.php'; /** * Addon Parser Class. * * @since 1.0.0 */ class AddonParser { public static $loaded_addon = array(); public static $css_content = array(); public static $module_css_content = array(); public static $js_content = ''; private static $sppagebuilderAddonTags = array(); private static $template = ''; public static $authorised = array(); public static $addon_interactions = array(); private static $contents = array(); private static $module_contents = array(); private static $deepAddonList = ['accordion' => 'sp_accordion_item', 'tab' => 'sp_tab_item']; public static function addAddon($tag, $func) { if (is_callable($func)) self::$sppagebuilderAddonTags[$tag] = $func; } public static function spDoAddon($content) { if (false === strpos($content, '[')) { return $content; } if (empty(self::$sppagebuilderAddonTags) || !is_array(self::$sppagebuilderAddonTags)) return $content; $pattern = self::getAddonRegex(); return preg_replace_callback("/$pattern/s", array('AddonParser', 'doAddonTag'), $content); } /** * Import/Include addon file * * @param string $file_name The addon name. Optional * * @since 1.0.8 */ public static function getAddonPath($addon_name = '') { $isEasyStoreAddon = stripos($addon_name, 'easystore_') === 0; if ($isEasyStoreAddon && ApplicationHelper::isProVersion()) { $addonPath = explode('_', $addon_name); $componentName = 'com_' . array_shift($addonPath); $addonGroupName = array_shift($addonPath); $addonName = implode('_', $addonPath); $fullAddonPath = JPATH_ROOT . "/components/{$componentName}/sppagebuilder/{$addonGroupName}/{$addonName}"; if (file_exists($fullAddonPath . '/site.php')) { return $fullAddonPath; } } $template_path = JPATH_ROOT . '/templates/' . self::$template; $plugins = self::getPluginsAddons(); if (file_exists($template_path . '/sppagebuilder/addons/' . $addon_name . '/site.php')) { return $template_path . '/sppagebuilder/addons/' . $addon_name; } elseif (file_exists(JPATH_ROOT . '/components/com_sppagebuilder/addons/' . $addon_name . '/site.php')) { return JPATH_ROOT . '/components/com_sppagebuilder/addons/' . $addon_name; } else { // Load from plugin if (isset($plugins[$addon_name]) && $plugins[$addon_name]) { return $plugins[$addon_name]; } } } private static function getAddonRegex() { $tagnames = array_keys(self::$sppagebuilderAddonTags); $tagregexp = join('|', array_map('preg_quote', $tagnames)); // WARNING! Do not change this regex without changing do_addon_tag() and strip_addon_tag() // Also, see addon_unautop() and shortcode.js. return '\\[' // Opening bracket . '(\\[?)' // 1: Optional second opening bracket for escaping shortcodes: [[tag]] . "($tagregexp)" // 2: Shortcode name . '(?![\\w-])' // Not followed by word character or hyphen . '(' // 3: Unroll the loop: Inside the opening shortcode tag . '[^\\]\\/]*' // Not a closing bracket or forward slash . '(?:' . '\\/(?!\\])' // A forward slash not followed by a closing bracket . '[^\\]\\/]*' // Not a closing bracket or forward slash . ')*?' . ')' . '(?:' . '(\\/)' // 4: Self closing tag ... . '\\]' // ... and closing bracket . '|' . '\\]' // Closing bracket . '(?:' . '(' // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags . '[^\\[]*+' // Not an opening bracket . '(?:' . '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag . '[^\\[]*+' // Not an opening bracket . ')*+' . ')' . '\\[\\/\\2\\]' // Closing shortcode tag . ')?' . ')' . '(\\]?)'; // 6: Optional second closing brocket for escaping shortcodes: [[tag]] } private static function doAddonTag($m) { // allow [[foo]] syntax for escaping a tag if ($m[1] == '[' && $m[6] == ']') { return substr($m[0], 1, -1); } $tag = $m[2]; $attr = self::addonParseAtts($m[3]); if (isset($m[5])) { // enclosing tag - extra parameter return $m[1] . call_user_func(self::$sppagebuilderAddonTags[$tag], $attr, $m[5], $tag) . $m[6]; } else { // self-closing tag return $m[1] . call_user_func(self::$sppagebuilderAddonTags[$tag], $attr, null, $tag) . $m[6]; } } private static function addonParseAtts($text) { $atts = array(); $pattern = '/(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/'; $text = preg_replace("/[\x{00a0}\x{200b}]+/u", " ", $text); if (preg_match_all($pattern, $text, $match, PREG_SET_ORDER)) { foreach ($match as $m) { if (!empty($m[1])) $atts[strtolower($m[1])] = stripcslashes($m[2]); elseif (!empty($m[3])) $atts[strtolower($m[3])] = stripcslashes($m[4]); elseif (!empty($m[5])) $atts[strtolower($m[5])] = stripcslashes($m[6]); elseif (isset($m[7]) and strlen($m[7])) $atts[] = stripcslashes($m[7]); elseif (isset($m[8])) $atts[] = stripcslashes($m[8]); } } else { $atts = ltrim($text); } return $atts; } public static function getAddons() { self::$template = self::getTemplateName(); require_once JPATH_ROOT . '/components/com_sppagebuilder/addons/module/site.php'; //include module manually $template_path = JPATH_ROOT . '/templates/' . self::$template; $tmpl_folders = array(); if (file_exists($template_path . '/sppagebuilder/addons')) { $tmpl_folders = Folder::folders($template_path . '/sppagebuilder/addons'); } $folders = Folder::folders(JPATH_ROOT . '/components/com_sppagebuilder/addons'); if ($tmpl_folders) { $merge_folders = array_merge($folders, $tmpl_folders); $folders = array_unique($merge_folders); } if (count((array) $folders)) { foreach ($folders as $folder) { $tmpl_file_path = $template_path . '/sppagebuilder/addons/' . $folder . '/site.php'; $com_file_path = JPATH_ROOT . '/components/com_sppagebuilder/addons/' . $folder . '/site.php'; if ($folder != 'module') { if (file_exists($tmpl_file_path)) { require_once $tmpl_file_path; } else if (file_exists($com_file_path)) { require_once $com_file_path; } } } } } private function checkObjectKeyValue($object) { if (!is_object($object)) { return false; } } private static function getRowById($id, $pageName) { $newContents = $pageName == "module" ? self::$module_contents : self::$contents; if (empty($newContents)) { return null; } for ($i = count($newContents) - 1; $i >= 0; $i--) { if ($newContents[$i]->id === $id) { return $newContents[$i]; } } return null; } public static function viewAddons($content, $fluid = 0, $pageName = 'none', $level = 1, $newModule = true, $storeData = []) { SpPgaeBuilderBase::loadAddons(); $addon_list = SpAddonsConfig::$addons; if (!\class_exists('SppagebuilderHelperSite')) { require_once JPATH_ROOT . '/components/com_sppagebuilder/helpers/helper.php'; } if ($newModule && $pageName == 'module') { self::$module_contents = $content; } if (empty(self::$contents) && $pageName != 'module') { self::$contents = $content; } self::$authorised = Access::getAuthorisedViewLevels(Factory::getUser()->get('id')); $layout_path = JPATH_ROOT . '/components/com_sppagebuilder/layouts'; $layouts = new stdClass; $layouts->row_start = new FileLayout('row.start', $layout_path); $layouts->row_end = new FileLayout('row.end', $layout_path); $layouts->row_css = new FileLayout('row.css', $layout_path); $layouts->column_start = new FileLayout('column.start', $layout_path); $layouts->column_end = new FileLayout('column.end', $layout_path); $layouts->column_css = new FileLayout('column.css', $layout_path); $layouts->addon_start = new FileLayout('addon.start', $layout_path); $layouts->addon_end = new FileLayout('addon.end', $layout_path); $layouts->addon_css = new FileLayout('addon.css', $layout_path); $doc = Factory::getDocument(); $content = is_object($content) ? (array) $content : $content; if (is_array($content)) { $output = ''; foreach ($content as $row) { if (!isset($row)) break; $row->settings->dynamicId = $row->id; // Row Visibility and ACL if (isset($row->visibility) && !$row->visibility) { continue; } if ($level <= 1 && !empty($row->parent) && $row->parent !== false) { continue; } if ($fluid === 1 || !empty($row->parent)) { $row->settings->fullscreen = 1; } $row_css = $layouts->row_css->render(array('options' => $row->settings)); if ($pageName === 'module') { array_push(self::$module_css_content, $row_css); } else { array_push(self::$css_content, $row_css); } $row->settings->isNestedRow = isset($row->parent) && $row->parent !== false; Factory::getApplication()->triggerEvent('onBeforeRowRender', array(&$row)); $output .= $layouts->row_start->render(array('options' => $row->settings)); foreach ($row->columns as $column) { if (!\is_object($column->settings)) { $column->settings = !empty($column->settings) && \is_array($column->settings) ? (object) $column->settings : new \stdClass; } $column->settings->cssClassName = $column->class_name; $column->settings->cssClassName = str_replace('column-parent ', '', $column->settings->cssClassName); $column->settings->cssClassName = str_replace('active-column-parent', '', $column->settings->cssClassName); $column->settings->dynamicId = $column->id; // Column Visibility and ACL if (isset($column->visibility) && !$column->visibility) { continue; } /** Inject the column width to the column settings. */ if (!isset($column->settings->width)) { $width = !empty($column->width) ? $column->width : SppagebuilderHelperSite::getColumnWidth($column); $column->settings->width = $width; if (isset($column->settings->width->unit)) { unset($column->settings->width->unit); } } $column->settings->width = SppagebuilderHelperSite::purifyColumnWidth($column->settings->width); $column_css = $layouts->column_css->render(array('options' => $column->settings)); if ($pageName === 'module') { array_push(self::$module_css_content, $column_css); } else { array_push(self::$css_content, $column_css); } $output .= $layouts->column_start->render(array('options' => $column->settings)); foreach ($column->addons as $key => $addon) { // Interaction if (isset($addon->settings->mouse_movement) || isset($addon->settings->while_scroll_view)) { $selectors = ['while_scroll_view', 'mouse_movement']; if (!isset($addon->id)) { continue; } self::parseInteractions($addon->id, $addon->settings, $selectors); } /** Addon Visibility */ if (isset($addon->visibility) && !$addon->visibility) { continue; } /** Check for the ACL */ if (!self::checkAddonACL($addon)) { continue; } if (isset($addon->type) && $addon->type === 'nested_row') { $newPageName = $pageName === 'module' ? 'module' : 'none'; $nestedRow = self::getRowById($addon->id, $newPageName); $output .= self::viewAddons([$nestedRow], 0, $newPageName, 2, false, $storeData); } elseif (!empty($addon->name) && $addon->name === 'div' && empty($addon->parent)) { $output .= self::getDivHTMLView($addon, $column->addons, $layouts, $pageName, $storeData); } // elseif (!empty($addon->name) && $addon->name === 'collection' && empty($addon->parent)) // { // $output .= self::getCollectionHTMLView($addon, $layouts, $pageName, $storeData); // } else { $addon->pageName = $pageName; $addon->layouts = $layouts; $addon->storeData = $storeData; $addon->settings->row_id = $row->id; $addon->settings->column_id = $column->id; $output .= self::getAddonHtmlView($addon, $layouts, $pageName, false, $storeData); } } $output .= $layouts->column_end->render(array('options' => $column->settings)); } $output .= $layouts->row_end->render(array('options' => $row->settings)); } // interaction js if (count(self::$addon_interactions) > 0 && $pageName != 'none' && $pageName != 'module') { $doc->addScriptDeclaration('var addonInteraction = ' . json_encode(self::$addon_interactions) . ';'); } if ($pageName === 'module') { return AddonParser::spDoAddon($output) . '<style type="text/css">' . self::convertCssArrayToString(self::minifyCss(self::$module_css_content)) . '</style>'; } else { if ($pageName !== 'none') { $app = Factory::getApplication(); $params = $app->getParams('com_sppagebuilder'); $production_mode = $params->get('production_mode', 0); $inline_css = self::convertCssArrayToString(self::minifyCss(self::$css_content)); if ($production_mode) { $css_folder_path = JPATH_ROOT . '/media/com_sppagebuilder/css'; $css_file_path = $css_folder_path . '/' . $pageName . '.css'; $css_file_url = Uri::base(true) . '/media/com_sppagebuilder/css/' . $pageName . '.css'; if (!Folder::exists($css_folder_path)) { Folder::create($css_folder_path); } file_put_contents($css_file_path, $inline_css); if (file_exists($css_file_path)) { $doc->addStylesheet($css_file_url); } else { $doc->addStyleDeclaration($inline_css); } } else { $doc->addStyleDeclaration($inline_css); } } return AddonParser::spDoAddon($output); } } else { return '<p>' . $content . '</p>'; } } private static function getAddonById($addons, $id) { foreach ($addons as $index => $addon) { if ($addon->id === $id) { return [$index, $addon]; } } return [-1, null]; } public static function generateCollectionCSS($addon, $pageName, $layouts) { if (empty($addon->name)) { return ''; } $addonPath = AddonParser::getAddonPath($addon->name); $output = ''; if (file_exists($addonPath . '/site.php')) { require_once $addonPath . '/site.php'; $addonClassName = ApplicationHelper::generateSiteClassName($addon->name); $addonInstance = new $addonClassName($addon); $addonCss = $layouts->addon_css->render(array('addon' => $addon)); self::$css_content[] = $addonCss; if (method_exists($addonClassName, 'css')) { if ($pageName === 'module') { $output .= '<style type="text/css">' . $addonCss . '</style>'; $output .= '<style type="text/css">' . $addonInstance->css() . '</style>'; } else { $cssContent = $addonInstance->css(); self::$css_content[] = $cssContent; } } } return $output; } private static function generateDivCSS($addon, $pageName, $layouts) { if (empty($addon->name)) { return ''; } $addonPath = AddonParser::getAddonPath($addon->name); $output = ''; if (file_exists($addonPath . '/site.php')) { require_once $addonPath . '/site.php'; $addonClassName = ApplicationHelper::generateSiteClassName($addon->name); $addonInstance = new $addonClassName($addon); $addonCss = $layouts->addon_css->render(array('addon' => $addon)); self::$css_content[] = $addonCss; if (method_exists($addonClassName, 'css')) { if ($pageName === 'module') { $output .= '<style type="text/css">' . $addonCss . '</style>'; $output .= '<style type="text/css">' . $addonInstance->css() . '</style>'; } else { $cssContent = $addonInstance->css(); self::$css_content[] = $cssContent; } } } return $output; } public static function generateAnimation($addon) { $animationClass = ''; $animationAttributes = ''; $settings = $addon->settings; if (!empty($settings->global_use_animation) && !empty($settings->global_animation)) { $animationClass .= ' sppb-wow ' . $settings->global_animation; } if (!empty($settings->global_animationduration)) { $animationAttributes .= ' data-sppb-wow-duration="' . $settings->global_animationduration . 'ms"'; } if (!empty($settings->global_animationdelay)) { $animationAttributes .= ' data-sppb-wow-delay="' . $settings->global_animationdelay . 'ms"'; } return [ 'class' => $animationClass, 'attributes' => $animationAttributes ]; } public static function getCollectionHTMLView($addon, $layouts, $pageName, $storeData = []) { $collectionElement = ''; if (isset($addon->visited) && $addon->visited) { return $collectionElement; } if (!empty($addon->name)) { if ($addon->name === 'easystore_common_productlist') { $animation = self::generateAnimation($addon); $custom_class = ""; $custom_class .= (isset($addon->settings->hidden_md) && filter_var($addon->settings->hidden_md, FILTER_VALIDATE_BOOLEAN)) ? 'sppb-hidden-md sppb-hidden-lg ' : ''; $custom_class .= (isset($addon->settings->hidden_sm) && filter_var($addon->settings->hidden_sm, FILTER_VALIDATE_BOOLEAN)) ? 'sppb-hidden-sm ' : ''; $custom_class .= (isset($addon->settings->hidden_xs) && filter_var($addon->settings->hidden_xs, FILTER_VALIDATE_BOOLEAN)) ? 'sppb-hidden-xs ' : ''; $collectionElement .= self::generateCollectionCSS($addon, $pageName, $layouts); $collectionElement .= '<div id="sppb-addon-wrapper-' . $addon->id . '" class="sppb-addon-wrapper">'; $collectionElement .= '<div id="sppb-addon-' . $addon->id . '" class="sppb-collection-addon ' . $addon->settings->class . $custom_class . $animation['class'] . '" ' . $animation['attributes'] . '>'; } else { $collectionElement .= self::getAddonHtmlView($addon, $layouts, $pageName, true, $storeData); } } $list = isset($storeData['easystoreList']) ? $storeData['easystoreList'] : []; $page = 0; $itemsPerPage = $addon->settings->items_per_page ?? 10; $startItem = $page * $itemsPerPage; $slicedList = array_slice($list, $startItem, $startItem + $itemsPerPage); if (!empty($addon->items)) { foreach ($slicedList as $index => $_) { $collectionElement .= '<div class="sppb-collection-item">'; foreach($addon->items[0] as $itemAddon) { if(!empty($itemAddon->parent)) { continue; } $collectionElement .= self::getDivHTMLView($itemAddon, $addon->items[0], $layouts, $pageName, $storeData, $index); } $collectionElement .= '</div>'; } } if (!empty($addon->name) && $addon->name === 'easystore_common_productlist') { $collectionElement .= '</div></div>'; } return $collectionElement; } /** * Generate the HTML structure of the nested DIV addon. * The DIV addon can accepts other addons as a child addon, * and the nesting could be more than one. * * @param stdClass $addon The addon object with all the addon settings. * @param array $addonList The list of addons inside the parent column. * @param stdClass $layouts The layout object containing the addon_start, addon_end etc. * @param string $pageName The flag for defining is the addon is rendering inside a module or page. * * @return string The generated HTML for the DIV addon(s). * @since 4.0.0 */ public static function getDivHTMLView($addon, &$addonList, $layouts, $pageName, $storeData = [], $storeListIndex = 0) { $divElement = ''; if (isset($addon->visited) && $addon->visited) { return $divElement; } if (!empty($addon->name)) { if ($addon->name === 'div') { $animation = self::generateAnimation($addon); $responsive_hidden_class = ""; $responsive_hidden_class .= (isset($addon->settings->hidden_xl) && filter_var($addon->settings->hidden_xl, FILTER_VALIDATE_BOOLEAN)) ? 'sppb-hidden-xl ' : ''; $responsive_hidden_class .= (isset($addon->settings->hidden_lg) && filter_var($addon->settings->hidden_lg, FILTER_VALIDATE_BOOLEAN)) ? 'sppb-hidden-lg ' : ''; $responsive_hidden_class .= (isset($addon->settings->hidden_md) && filter_var($addon->settings->hidden_md, FILTER_VALIDATE_BOOLEAN)) ? 'sppb-hidden-md ' : ''; $responsive_hidden_class .= (isset($addon->settings->hidden_sm) && filter_var($addon->settings->hidden_sm, FILTER_VALIDATE_BOOLEAN)) ? 'sppb-hidden-sm ' : ''; $responsive_hidden_class .= (isset($addon->settings->hidden_xs) && filter_var($addon->settings->hidden_xs, FILTER_VALIDATE_BOOLEAN)) ? 'sppb-hidden-xs ' : ''; $divElement .= self::generateDivCSS($addon, $pageName, $layouts); $divElement .= '<div id="sppb-addon-wrapper-' . $addon->id . '" class="sppb-addon-wrapper ' . $responsive_hidden_class . '">'; $divElement .= '<div id="sppb-addon-' . $addon->id . '" class="sppb-div-addon ' . $addon->settings->class . $animation['class'] . '" ' . $animation['attributes'] . '>'; } else { $divElement .= self::getAddonHtmlView($addon, $layouts, $pageName, true, $storeData, $storeListIndex); } } if (!empty($addon->children)) { foreach ($addon->children as $child) { list($index, $childAddon) = self::getAddonById($addonList, $child); if (!($index > -1)) { continue; } /** Addon Visibility */ if (isset($childAddon->visibility) && !$childAddon->visibility) { $addonList[$index]->visited = true; continue; } /** Check for the ACL */ if (!self::checkAddonACL($childAddon)) { $addonList[$index]->visited = true; continue; } $divElement .= self::getDivHTMLView($childAddon, $addonList, $layouts, $pageName, $storeData, $storeListIndex); $addonList[$index]->visited = true; } } if (!empty($addon->name) && $addon->name === 'div') { $divElement .= '</div></div>'; } return $divElement; } public static function getDivHTMLViewForCollection($addon, &$addonList, $layouts, $pageName, $storeData = [], $storeListIndex = 0) { $divElement = ''; if (!empty($addon->name)) { if ($addon->name === 'div') { $animation = self::generateAnimation($addon); $custom_class = ""; $custom_class .= (isset($addon->settings->hidden_md) && filter_var($addon->settings->hidden_md, FILTER_VALIDATE_BOOLEAN)) ? 'sppb-hidden-md sppb-hidden-lg ' : ''; $custom_class .= (isset($addon->settings->hidden_sm) && filter_var($addon->settings->hidden_sm, FILTER_VALIDATE_BOOLEAN)) ? 'sppb-hidden-sm ' : ''; $custom_class .= (isset($addon->settings->hidden_xs) && filter_var($addon->settings->hidden_xs, FILTER_VALIDATE_BOOLEAN)) ? 'sppb-hidden-xs ' : ''; // $addonId = SppagebuilderHelperSite::nanoid(); $divElement .= self::generateDivCSS($addon, $pageName, $layouts); $divElement .= '<div id="sppb-addon-wrapper-' . $addon->id . '" class="sppb-addon-wrapper">'; $divElement .= '<div id="sppb-addon-' . $addon->id . '" class="sppb-div-addon ' . $addon->settings->class . $custom_class . $animation['class'] . '" ' . $animation['attributes'] . '>'; if (!empty($addon->children)) { foreach ($addon->children as $child) { list($index, $childAddon) = self::getAddonById($addonList, $child); if (!($index > -1)) { continue; } /** Addon Visibility */ if (isset($childAddon->visibility) && !$childAddon->visibility) { continue; } /** Check for the ACL */ if (!self::checkAddonACL($childAddon)) { continue; } $divElement .= self::getDivHTMLViewForCollection($childAddon, $addonList, $layouts, $pageName, $storeData, $storeListIndex); } } } else { $divElement .= self::getAddonHtmlView($addon, $layouts, $pageName, true, $storeData, $storeListIndex); } } if (!empty($addon->name) && $addon->name === 'div') { $divElement .= '</div></div>'; } return $divElement; } public static function getAddonHtmlView($addon, $layouts, $pageName = 'none', $isChild = false, $storeData = [], $storeListIndex = 0) { /** * If the addons ia a DIV addon then skip rendering the addon. */ if (isset($addon->name) && $addon->name === 'div') { return ''; } /** Addon Visibility */ if (isset($addon->visibility) && !$addon->visibility) { return; } /** * If the addon has parent property and not forced to render * i.e. the addon is not a child of a parent addon then skip. */ if (isset($addon->parent) && $addon->parent && !$isChild) { return ''; } if (!isset($addon->name)) { return ''; } $addon_list = SpAddonsConfig::$addons; $addon_name = $addon->name; $class_name = ApplicationHelper::generateSiteClassName($addon_name); $addon_path = AddonParser::getAddonPath($addon_name); $doc = Factory::getDocument(); $output = ''; if (file_exists($addon_path . '/site.php')) { $addon_options = array(); if (isset($addon_list[$addon->name]['attr']) && $addon_list[$addon->name]['attr']) { $addon_groups = $addon_list[$addon->name]['attr']; if (is_array($addon_groups)) { foreach ($addon_groups as $addon_group) { $addon_options += $addon_group; } } } $store = new \stdClass; foreach ($addon->settings as $key => &$setting) { $deviceObject = (object) [ 'xl' => '', 'lg' => '', 'md' => '', 'sm' => '', 'xs' => '', ]; /** If the data is old one, then- */ if (isset($setting->md) && !isset($setting->xl)) { $deviceObject->xl = $setting->md; $deviceObject->lg = $setting->md; } if (\is_object($setting)) { $original = \json_decode(\json_encode($setting)); } $originalKey = $key . '_original'; if (SppagebuilderHelperSite::hasMultiDeviceSettings($setting)) { foreach ($deviceObject as $device => $_) { if (isset($setting->$device)) { $deviceObject->$device = $setting->$device; } } $unit = (isset($setting->unit) && $addon_name !== 'clients') ? $setting->unit : ""; if (!empty($unit)) { $deviceObject->unit = $unit; } $store->$originalKey = $deviceObject; $defaultDevice = SpPgaeBuilderBase::$defaultDevice; $store->$key = $deviceObject->$defaultDevice; $keySm = $key . '_sm'; $keyXs = $key . '_xs'; $keyLg = $key . '_lg'; $keyXl = $key . '_xl'; $keyMd = $key . '_md'; $addon->settings->$keySm = \is_string($deviceObject->sm) ? $deviceObject->sm . $unit : $deviceObject->sm; $addon->settings->$keyXs = \is_string($deviceObject->xs) ? $deviceObject->xs . $unit : $deviceObject->xs; $addon->settings->$keyXl = \is_string($deviceObject->xl) ? $deviceObject->xl . $unit : $deviceObject->xl; $addon->settings->$keyLg = \is_string($deviceObject->lg) ? $deviceObject->lg . $unit : $deviceObject->lg; $addon->settings->$keyMd = \is_string($deviceObject->md) ? $deviceObject->md . $unit : $deviceObject->md; } if (isset($addon_options[$key]['selector'])) { $addon_selector = $addon_options[$key]['selector']; if (isset($addon->settings->$key) && !empty($addon->settings->$key)) { $selector_value = $addon->settings->$key; $keySelector = $key . '_selector'; $addon->settings->$keySelector = str_replace('{{ VALUE }}', $selector_value, $addon_selector); } } } unset($setting); foreach ($store as $key => $value) { $addon->settings->$key = $value; } //plugin support for addonRender PluginHelper::importPlugin('system'); Factory::getApplication()->triggerEvent('onBeforeAddonRender', array(&$addon)); // End plugin support for addonRender $output .= $layouts->addon_start->render(array('addon' => $addon)); // start addon require_once $addon_path . '/site.php'; $hasRepeatableItems = self::checkRepeatableItems($addon->settings, $addon->name); if (!empty($hasRepeatableItems)) { self::processRepeatableItems($hasRepeatableItems, $addon->name, $layouts, $pageName, $storeData); } if (class_exists($class_name)) { $addon->easystoreItem = $storeData['easystoreItem'] ?? null; $addon->easystoreList = $storeData['easystoreList'] ?? []; $addon->listIndex = $storeListIndex; // Instantiate addon class $addon_obj = new $class_name($addon); $output .= $addon_obj->render(); // Scripts if (method_exists($class_name, 'scripts')) { $scripts = $addon_obj->scripts(); if (!empty($scripts)) { foreach ($scripts as $key => $script) { $doc->addScript($script); } } } // JS if (method_exists($class_name, 'js')) { if (!empty($addon_obj->js())) { $doc->addScriptDeclaration($addon_obj->js()); } } // Stylesheets if (method_exists($class_name, 'stylesheets')) { $stylesheets = $addon_obj->stylesheets(); if (!empty($stylesheets)) { foreach ($stylesheets as $key => $stylesheet) { $doc->addStyleSheet($stylesheet); } } } $addon_css = $layouts->addon_css->render(array('addon' => $addon)); if ($pageName == 'module') { $output .= '<style type="text/css">' . $addon_css . '</style>'; } else if($storeListIndex === 0) { // array_unshift(self::$css_content, $addon_css); array_push(self::$css_content, $addon_css); } // css if (method_exists($class_name, 'css')) { if ($pageName == 'module') { $output .= '<style type="text/css">' . $addon_obj->css() . '</style>'; } else if($storeListIndex === 0) { $cssContent = $addon_obj->css(); // array_unshift(self::$css_content, $cssContent); array_push(self::$css_content, $cssContent); } } } else { $output .= htmlspecialchars_decode(AddonParser::spDoAddon(AddonParser::generateShortcode($addon))); } $output .= $layouts->addon_end->render(); } return $output; } public static function checkRepeatableItems($settings, $addon_name) { $repeatableItems = []; $itemKey = 'sp_' . $addon_name . '_item'; $minimalItemKey = $addon_name . '_item'; $isRepeatable = isset($settings->$itemKey) && !empty($settings->$itemKey); if ($isRepeatable) { array_push($repeatableItems, $settings->$itemKey); } if (isset($settings->$minimalItemKey) && !empty($settings->$minimalItemKey)) { array_push($repeatableItems, $settings->$minimalItemKey); } return $repeatableItems; } public static function processRepeatableItems($repeatableItems, $addon_name, $layouts, $pageName, $storeData = []) { $items = $repeatableItems; $newContent = ''; foreach ($items as &$settings) { if (!empty($settings)) { foreach ($settings as $key => &$item) { if (isset($item->content) && is_array($item->content)) { $newContent = ''; foreach ($item->content as $contentAddon) { // Addon Visibility and ACL if (isset($contentAddon->visibility) && !$contentAddon->visibility) { continue; } // Check for ACL $access = self::checkAddonACL($contentAddon); if (!$access) { continue; } if (isset($contentAddon->type) && $contentAddon->type === 'nested_row') { $newPageName = $pageName === 'module' ? 'module' : 'none'; $nestedRow = self::getRowById($contentAddon->id, $newPageName); $newContent .= self::viewAddons([$nestedRow], 0, $newPageName, 2, false, $storeData); } else { $newContent .= self::getAddonHtmlView($contentAddon, $layouts, $pageName, $storeData); } } $item->content = $newContent; } else { $repeatableItems = self::checkRepeatableItems($item, $addon_name); if (!empty($repeatableItems)) { $repeatableItems = self::processRepeatableItems($repeatableItems, $addon_name, $layouts, $pageName, $storeData); } } } unset($item); } } unset($settings); return $items; } public static function minifyCss($cssCode) { // Remove comments $cssCode = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $cssCode); // Remove space after colons $cssCode = str_replace(': ', ':', $cssCode); // Remove whitespace $cssCode = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $cssCode); // Remove Empty Selectors without any properties $cssCode = preg_replace('/(?:(?:[^\r\n{}]+)\s?{[\s]*})/', '', $cssCode); // Remove Empty Media Selectors without any properties or selector $cssCode = preg_replace('/@media\s?\((?:[^\r\n,{}]+)\s?{[\s]*}/', '', $cssCode); return $cssCode; } public static function generateShortcode($addon) { if (!empty($addon->settings)) { $addon->settings->dynamicId = $addon->id; $ops = AddonParser::generateShortcodeOps($addon->settings); } $output = '[sp_' . $addon->name; if (isset($ops['default'])) { $output .= $ops['default']; } $output .= ']'; if (isset($ops['repeat'])) { $output .= $ops['repeat']; } $output .= '[/sp_' . $addon->name . ']'; return $output; } public static function generateShortcodeOps($ops) { $default = ''; $repeat = ''; foreach ($ops as $key => $val) { if (is_string($val)) { $default .= ' ' . $key . '="' . htmlspecialchars($val) . '"'; } elseif (is_array($val)) { $temp = ''; foreach ($val as $innerKey => $innerVal) { $temp .= '[' . $key; foreach ($innerVal as $inner_key => $inner_val) { if (is_string($inner_val)) { $temp .= ' ' . $inner_key . '="' . htmlspecialchars($inner_val) . '"'; } } $temp .= '][/' . $key . ']'; } $repeat .= $temp; } } if ($default) $result['default'] = $default; if ($repeat) $result['repeat'] = $repeat; return $result; } // Get list of plugin addons private static function getPluginsAddons() { $path = JPATH_PLUGINS . '/sppagebuilder'; if (!Folder::exists($path)) return; $plugins = Folder::folders($path); if (!count((array) $plugins)) return; $elements = array(); $addonPaths = []; foreach ($plugins as $plugin) { if (PluginHelper::isEnabled('sppagebuilder', $plugin)) { $addonPaths[] = $path . '/' . $plugin . '/addons'; } } foreach ($addonPaths as $addonsPath) { if (Folder::exists($addonsPath)) { $addons = Folder::folders($addonsPath); foreach ($addons as $addon) { $addonPath = $addonsPath . '/' . $addon; if (File::exists($addonPath . '/site.php')) { $elements[$addon] = $addonPath; } } } } return $elements; } private static function getTemplateName() { $db = Factory::getDbo(); $query = $db->getQuery(true); $query->select($db->quoteName(array('template'))); $query->from($db->quoteName('#__template_styles')); $query->where($db->quoteName('client_id') . ' = 0'); $query->where($db->quoteName('home') . ' = 1'); $db->setQuery($query); return $db->loadObject()->template; } public static function convertCssArrayToString($cssArray = array()) { $cssString = ''; if (count((array) $cssArray) > 0) { foreach ($cssArray as $cssItem) { $cssString .= $cssItem; } } return $cssString; } public static function checkAddonACL($addon) { $access = true; if (isset($addon->settings->acl) && $addon->settings->acl) { $access_list = $addon->settings->acl; $access = false; if(is_string($access_list)) { $access_list = [$addon->settings->acl]; } foreach ($access_list as $acl) { if (in_array($acl, self::$authorised)) { $access = true; } } unset($addon->settings->acl); } return $access; } /** * Print interaction css and javascript object */ private static function parseInteractions($addonId, &$addonSettings, $selectors) { foreach ($selectors as $selector) { $interactions = isset($addonSettings->$selector) ? $addonSettings->$selector : []; if (!empty($interactions)) { $interactions = $interactions[0]; $animationCollection = new \stdClass; $animationCollection->addonId = $addonId; $animationCollection->enable_mobile = isset($interactions->enable_mobile) && $interactions->enable_mobile; $animationCollection->scrolling_options = isset($addonSettings->scrolling_options) ? $addonSettings->scrolling_options : 'viewport'; $animationCollection->enable_tablet = isset($interactions->enable_tablet) && $interactions->enable_tablet; if ($selector === 'while_scroll_view' && $interactions->enable_while_scroll_view) { $animation = isset($interactions->on_scroll_actions) ? $interactions->on_scroll_actions : []; if (count($animation) > 1) { usort($animation, function ($x, $y) { return $x->keyframe - $y->keyframe; }); } $animationCollection->animation = $animation; $animationCollection->name = 'custom'; $addonSettings_transition_origin_x = isset($addonSettings->transition_origin_x) ? $addonSettings->transition_origin_x : ''; $addonSettings_transition_origin_y = isset($addonSettings->transition_origin_y) ? $addonSettings->transition_origin_y : ''; $interaction_transition_origin_x = isset($interactions->transition_origin_x) ? $interactions->transition_origin_x : ''; $interaction_transition_origin_y = isset($interactions->transition_origin_y) ? $interactions->transition_origin_y : ''; $xOffset = !empty($addonSettings_transition_origin_x) ? $addonSettings_transition_origin_x : $interaction_transition_origin_x; $yOffset = !empty($addonSettings_transition_origin_y) ? $addonSettings_transition_origin_y : $interaction_transition_origin_y; $animationCollection->origin = ['x_offset' => $xOffset, 'y_offset' => $yOffset]; if (isset(self::$addon_interactions[$selector])) { array_push(self::$addon_interactions[$selector], $animationCollection); } else { self::$addon_interactions[$selector] = array($animationCollection); } } if ($selector === 'mouse_movement' && $interactions->enable_tilt_effect) { $animationCollection->animation = $interactions; if (isset(self::$addon_interactions[$selector])) { array_push(self::$addon_interactions[$selector], $animationCollection); } else { self::$addon_interactions[$selector] = array($animationCollection); } } } } } private static function shortByKeyFrame($x, $y) { return $x['keyframe'] - $y['keyframe']; } } function spAddonAtts($pairs, $atts, $shortcode = '') { $atts = (array)$atts; $out = array(); foreach ($pairs as $name => $default) { if (array_key_exists($name, $atts)) $out[$name] = $atts[$name]; else $out[$name] = $default; } return $out; } AddonParser::getAddons(); helper-base.php 0000644 00000005324 15231056562 0007455 0 ustar 00 <?php /** * @package SP Page Builder * @author JoomShaper http://www.joomshaper.com * @copyright Copyright (c) 2010 - 2023 JoomShaper * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 or later */ /** No direct access. */ defined('_JEXEC') or die('Restricted access'); /** * The Base migrator class. * * @since 4.0.0 */ class HelperBase { /** * The addon ID selector. * * @var string * @since 4.0.0 */ protected $id; /** * The device lists array. * * @var array * @since 4.0.0 */ protected $deviceList = ["xl", "lg", "md", "sm", "xs"]; /** * The CSS migration constructor. * * @param string $id The ID selector. * @param bool $force Flag to set the ID as whatever it is provided, no sanitization is required. * * @since 4.0.0 */ public function __construct(string $id, bool $force = false) { $this->setID($id, $force); } /** * Get the addon ID selector. * * @return string The addon ID selector provided. * @since 4.0.0 */ public function getID(): string { return $this->id; } /** * Set/update the addon ID selector. * * @param string $id The new addon ID selector. * @param bool $force Set the ID whatever the id is provided, no * sanitization is required. * * * @since 4.0.0 */ public function setID(string $id, bool $force = false) { if ($force) { $this->id = $id; } else { $this->id = $this->sanitizeID($id); } } private function sanitizeID(string $id): string { return \strpos($id, '#') !== 0 ? '#' . $id : $id; } /** * Get the device list all except the default one. * * @return array * @since 4.0.0 * @todo Currently the `xl` device is excluded. It will be included * while deciding about the desktop/large devices. */ protected function getDeviceListExcludeDefault(): array { return array_filter($this->deviceList, function ($device) { return $device !== SpPgaeBuilderBase::$defaultDevice; }); } /** * Generate The Selector from the raw selector and the ID selector. * * @param string $selector The selectors provided. * @return string * @since 4.0.0 */ protected function generateSelector(string $selector): string { $selector = preg_replace("@\s+@", " ", trim($selector)); if (empty($selector) || $selector === ':id' || $selector === ':self') { return $this->getID(); } $selectorArray = array_map(function ($item) { $item = preg_replace("@\s+@", " ", trim($item)); if (!$item) return; if (strpos($item, '&') !== false && strpos($item, '&') === 0) { return $this->getID() . trim(substr($item, 1)); } return $this->getID() . ' ' . $item; }, explode(',', $selector)); return implode(',', $selectorArray); } } css-helper.php 0000644 00000054603 15231056562 0007337 0 ustar 00 <?php /** * @package SP Page Builder * @author JoomShaper http://www.joomshaper.com * @copyright Copyright (c) 2010 - 2023 JoomShaper * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 or later */ use Joomla\CMS\Factory; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Uri\Uri; /** No direct access. */ defined('_JEXEC') or die('Restricted access'); /** * Migrate the CSS method used in the site.php file. * * @since 4.0.0 */ class CSSHelper extends HelperBase { /** * The default device * * @var string * @since 4.0.0 */ private static $device; /** * The font registry array. Registering all the fonts here. * * @var array * @since 4.0.0 */ private $fontRegistry = []; /** * The constructor function of the CSS Migrator. * * @param string $id The addon ID selector. * @param bool $force Flag to set the ID as whatever it is provided, no sanitization is required. * * @since 4.0.0 */ public function __construct(string $id, bool $force = false) { parent::__construct($id, $force); self::$device = SpPgaeBuilderBase::$defaultDevice; } private function getFallbackValue($settings, $prop) { $keys = explode('.', $prop, 2); if (empty($keys)) return null; if (count($keys) > 1) { list($key1, $key2) = $keys; $originalKey1 = $key1 . '_original'; $originalKey2 = $key2 . '_original'; if (isset($settings->$originalKey1)) { $key1 = $originalKey1; } if (isset($settings->$originalKey2)) { $key2 = $originalKey2; } return isset($settings->$key1->$key2) ? $settings->$key1->$key2 : null; } $key1 = $keys[0]; $originalKey = $key1 . '_original'; if (isset($settings->$originalKey)) { $key1 = $originalKey; } return isset($settings->$key1) ? $settings->$key1 : null; } /** * Register a font name to the font registry. * * @param string $fontName The font name which will be stored to the registry. * * @return void * @since 4.0.0 */ private function registerFont(string $fontName) { if (!\in_array($fontName, $this->fontRegistry)) { $this->fontRegistry[] = $fontName; } } /** * Get the font registry array. * * @return array * @since 4.0.0 */ private function getFontRegistry(): array { return $this->fontRegistry; } /** * Load the google font for the typography fields. * * @return void * @since 4.0.0 */ public function loadGoogleFont(string $fontName) { $systemFonts = array( 'Arial', 'Tahoma', 'Verdana', 'Helvetica', 'Times New Roman', 'Trebuchet MS', 'Georgia' ); if (!empty($fontName)) { if (!\in_array($fontName, $systemFonts)) { $fontPath = '/media/com_sppagebuilder/assets/google-fonts/' . $fontName . '/stylesheet.css'; $params = ComponentHelper::getParams('com_sppagebuilder'); $disableGoogleFonts = (bool) $params->get('disable_google_fonts', 0); if ($disableGoogleFonts) { return; } if (file_exists(JPATH_ROOT . $fontPath)) { Factory::getDocument()->addStylesheet(Uri::root(true) . $fontPath); } else { $linkTagUrl = "https://fonts.googleapis.com/css?family=" . $fontName . ":100,100italic,200,200italic,300,300italic,400,400italic,500,500italic,600,600italic,700,700italic,800,800italic,900,900italic&display=swap"; Factory::getDocument()->addStylesheet($linkTagUrl); } } } } public function loadLocalFont(string $fontName) { $fontPath = '/media/com_sppagebuilder/assets/custom-fonts/' . $fontName . '/stylesheet.css'; if (file_exists(JPATH_ROOT . $fontPath)) { Factory::getDocument()->addStylesheet(Uri::root(true) . $fontPath); } } private function purifyTypographyObject($obj) { $device = SpPgaeBuilderBase::$defaultDevice; $obj = $obj ?? ''; if (!\is_object($obj)) { if (preg_match("@[^-|\d+]@", $obj)) { $obj = \preg_replace("@\D+$@", '', $obj); } $newObject = AddonHelper::initDeviceObject(); foreach ($newObject as $k => &$v) { // Todo: need to replace unit value "px" with dynamic $obj unit value. $v = (object) ['value' => $k === $device ? $obj : '', 'unit' => 'px']; } unset($v); return $newObject; } else { foreach ($obj as $k => &$v) { if (!\is_object($v)) { $v = (object) ['value' => $v, 'unit' => 'px']; } } unset($v); } return $obj; } /** * Typography style generation by using the settings and fallback array. * * @param string $selector The CSS selector. * @param object $settings The settings object. * @param string $prop The settings prop or the typography field name. * @param array $fallback The fallback array. * * @return string * @since 4.0.0 */ public function typography($selector, $settings, $prop, $fallback = []) { $hasFallback = !empty($fallback) && !isset($settings->$prop); if ($hasFallback) { $font = array_key_exists('font', $fallback) ? $fallback['font'] : ""; $size = array_key_exists('size', $fallback) ? $fallback['size'] : ""; $lineHeight = array_key_exists('line_height', $fallback) ? $fallback['line_height'] : ""; $letterSpacing = array_key_exists('letter_spacing', $fallback) ? $fallback['letter_spacing'] : ""; $uppercase = array_key_exists('uppercase', $fallback) ? $fallback['uppercase'] : ""; $italic = array_key_exists('italic', $fallback) ? $fallback['italic'] : ""; $underline = array_key_exists('underline', $fallback) ? $fallback['underline'] : ""; $weight = array_key_exists('weight', $fallback) ? $fallback['weight'] : ""; $settings->$prop = new \stdClass; $settings->$prop->font = $this->getFallbackValue($settings, $font); $settings->$prop->weight = $this->getFallbackValue($settings, $weight); $settings->$prop->uppercase = $this->getFallbackValue($settings, $uppercase); $settings->$prop->italic = $this->getFallbackValue($settings, $italic); $settings->$prop->underline = $this->getFallbackValue($settings, $underline); $settings->$prop->size = $this->getFallbackValue($settings, $size); $settings->$prop->line_height = $this->getFallbackValue($settings, $lineHeight); $settings->$prop->letter_spacing = $this->getFallbackValue($settings, $letterSpacing); } if (!isset($settings->$prop)) return ''; $typography = $settings->$prop; $objectKeys = ["letter_spacing", "line_height", "size"]; foreach ($objectKeys as $key) { if (isset($typography->$key)) { $typography->$key = $this->purifyTypographyObject($typography->$key); } } if (!empty($typography->weight) && \preg_match("@[^\d]+@", $typography->weight)) { $typography->weight = (int) $typography->weight; } /** If font exists to the typography field then register the font and load it. */ if (!empty($typography->font)) { $this->registerFont($typography->font); if (isset($typography->type) && $typography->type === 'local') { $this->loadLocalFont($typography->font); } else { $this->loadGoogleFont($typography->font); } } $props = [ 'font' => isset($typography->font) && !empty($typography->font) ? 'font-family' : null, 'weight' => isset($typography->weight) && !empty($typography->weight) ? 'font-weight' : null, 'uppercase' => isset($typography->uppercase) && !empty($typography->uppercase) ? 'text-transform' : null, 'italic' => isset($typography->italic) && !empty($typography->italic) ? 'font-style' : null, 'underline' => isset($typography->underline) && !empty($typography->underline) ? 'text-decoration' : null, 'size' => isset($typography->size) && !empty($typography->size) ? 'font-size' : null, 'line_height' => isset($typography->line_height) && !empty($typography->line_height) ? 'line-height' : null, 'letter_spacing' => isset($typography->letter_spacing) && !empty($typography->letter_spacing) ? 'letter-spacing' : null ]; $units = ['font' => false, 'weight' => false, 'size' => false, 'uppercase' => false, 'italic' => false, 'underline' => false]; $modifiers = []; $defaults = ['uppercase' => 'uppercase', 'italic' => 'italic', 'underline' => 'underline']; $typographyStyle = $this->generateStyle($selector, $typography, $props, $units, $modifiers, $defaults); return $typographyStyle; } /** * Parse the color and generate a valid color property value. * * @param mixed $color Object or string value of the color. * * @return string Returns the color value string. * @since 4.0.0 */ public static function parseColor($settings, $prop): string { $originalProp = $prop . '_original'; if (isset($settings->$originalProp)) { $prop = $originalProp; } $color = isset($settings->$prop) ? $settings->$prop : ''; if (\is_string($color)) { return $color; } if (\is_object($color)) { if (isset($color->type)) { $color1 = "#398AF1"; $color2 = "#5EDCED"; if (!empty($color->color)) { $color1 = !empty(preg_replace("@\s+@", "", $color->color)) ? $color->color : '#398AF1'; } if (!empty($color->color2)) { $color2 = !empty(preg_replace("@\s+@", "", $color->color2)) ? $color->color2 : '#5EDCED'; } switch ($color->type) { case 'solid': return preg_replace("@\s+@", "", $color->color); case 'linear': $start = $color->pos ?? 0; $end = $color->pos2 ?? 100; return 'linear-gradient(' . ($color->deg ?? 0) . 'deg, ' . $color1 . ' ' . $start . '%, ' . $color2 . ' ' . $end . '%)'; case 'radial': $start = $color->pos ?? 0; $end = $color->pos2 ?? 100; $position = $color->radialPos ?? 'center center'; return 'radial-gradient(at ' . $position . ', ' . $color1 . ' ' . $start . '%, ' . $color2 . ' ' . $end . '%)'; default: return $color->color ?? ''; } } } return ''; } /** * Parse the alignment prop and generate the alignment value. * * @param object $settings The settings object. * @param string $prop The alignment prop name. * @param bool $flex If the alignment for the flex or not. * * @return string The alignment value. * @since 4.0.0 */ public static function parseAlignment($settings, $prop, $flex = false) { $primitiveProp = $prop; $originalProp = $prop . '_original'; $prop = isset($settings->$originalProp) ? $originalProp : $prop; if (!isset($settings->$prop)) { return ''; } $alignmentMap = [ 'sppb-text-center' => 'center', 'sppb-text-left' => 'left', 'sppb-text-right' => 'right', ]; $flexMap = [ 'center' => 'center', 'left' => 'flex-start', 'right' => 'flex-end' ]; $alignment = $settings->$prop; if (self::hasMultiDeviceSettings($alignment)) { if ($flex) { foreach ($alignment as &$value) { $value = isset($flexMap[$value]) ? $flexMap[$value] : $value; } unset($value); } else { foreach ($alignment as &$value) { $value = isset($alignmentMap[$value]) ? $alignmentMap[$value] : $value; } unset($value); } return $alignment; } $align = isset($alignmentMap[$alignment]) ? $alignmentMap[$alignment] : $alignment; return $flex && isset($flexMap[$align]) ? $flexMap[$align] : $align; } private static function isEnabledBoxShadow($shadow) { if (empty($shadow)) { return false; } if (\is_string($shadow)) { $shadow = preg_replace("@\s+@", ' ', $shadow); $shadow = explode(' ', $shadow); $shadow = (object) $shadow; } $numberKeys = ['ho', 'vo', 'blur', 'spread']; if (\is_object($shadow)) { if (isset($shadow->enabled)) { return $shadow->enabled; } foreach ($shadow as $key => &$value) { if (\in_array($key, $numberKeys)) { $value = (float) $value; if (!empty($value)) { return true; } } if ($key === 'color') { $value = strtolower($value); return !($value === '#fff' || $value === '#ffffff'); } } unset($value); } return false; } /** * Parse the box shadow values and generate the box-shadow CSS property. * * @param object $settings The addon settings. * @param string $prop The box-shadow settings key inside the $settings object. * @param boolean $isTextShadow Data comes from text-shadow or box shadow. * * @return string The generated box-shadow. * @since 4.0.0 */ public static function parseBoxShadow($settings, string $prop, $isTextShadow = false): string { if (!isset($settings->$prop)) { return ''; } $box = $settings->$prop; if (\is_object($box)) { $horizontalOffset = !empty($box->ho) ? $box->ho . 'px' : '0px'; $verticalOffset = !empty($box->vo) ? $box->vo . 'px' : '0px'; $blur = !empty($box->blur) ? $box->blur . 'px' : '0px'; $spread = (!$isTextShadow) ? (!empty($box->spread) ? $box->spread . 'px' : '0px') : ' '; $color = !empty($box->color) ? $box->color : ''; return self::isEnabledBoxShadow($box) ? $horizontalOffset . " " . $verticalOffset . " " . $blur . " " . $spread . " " . $color : ''; } if ($box === '0 0 0 0 #fff') { return ''; } return $box; } /** * Check if the value has a multi-device settings. * * @param mixed $value The settings value. * * @return boolean * @since 4.0.0 */ private static function hasMultiDeviceSettings($value): bool { return isset($value->xl) || isset($value->lg) || isset($value->md) || isset($value->sm) || isset($value->xs); } /** * Extract the value field, if the field has a unit property then add the unit with it. * * @param object $value The value object. * * @return string The extracted string value. * @since 4.0.0 */ private function extractValue($value): string { if (\is_object($value)) { $_value = ''; if (isset($value->value)) { $_value = is_object($value->value) ? $value->value->value : $value->value; } if (!empty($_value) && isset($value->unit)) { $_value .= is_object($value->unit) ? $value->unit->unit : $value->unit; } return $_value; } if (\is_array($value) && empty($value)) { return $value = ''; } return (string) $value; } /** * Generate style for a specific selector with help of settings object, prop map, units etc. * * @param string $selector The selector string where to apply the styles. * @param \stdClass $settings The settings object. * @param array $propMap The property map. The structure of the array is [prop => cssProp | [cssProps]] * @param mixed $unit The unit array. The structure of the array is [prop => unitValue | false] * @param array $modifier The modifier array. This array says if any modifier is needed to apply * to this property. Currently we are covering the spacing property. * if [prop => 'spacing'] is provided then handle the value as spacing value. * @param mixed $default The default values. This would be useful if we don't want to * use the $settings->$prop value as a result but want * user specific value as a value. * @param boolean $important The important specifier says if the property need * to append !important; at the end or not. * @param string $static Provided any static style value. If provided that would be contacted. * * @return string The CSS style with media query. * @since 4.0.0 */ public function generateStyle(string $selector, $settings, $propMap, $unit = 'px', $modifier = [], $default = null, $important = false, $static = ''): string { $device = self::$device; $selector = $this->generateSelector($selector); $css = []; $media = []; $_unit = 'px'; $css[] = $selector . "{"; if (!empty($static)) { $css[] = $static; } foreach ($propMap as $prop => $cssProp) { if (\is_null($cssProp)) { continue; } $primitiveProp = $prop; $originalProp = $prop . '_original'; if (isset($settings->$originalProp)) { $prop = $originalProp; } $_unit = \is_array($unit) ? ($unit[$primitiveProp] ?? 'px') : $unit; $_important = \is_array($important) ? ($important[$primitiveProp] ?? false) : $important; $_default = \is_array($default) ? ($default[$primitiveProp] ?? null) : $default; if (!isset($settings->$prop) && \is_null($_default)) { continue; } if (isset($settings->$prop) && \is_string($settings->$prop) && preg_replace("@\s+@", '', $settings->$prop) === '' && \is_null($_default)) { continue; } if (\is_string($cssProp)) { $cssProp = [$cssProp]; } if (!\is_null($_default)) { $str = ''; foreach ($cssProp as $attr) { $str .= $attr . ': ' . $_default . ';'; } $css[] = $str; continue; } if (self::hasMultiDeviceSettings($settings->$prop)) { $multiDeviceData = null; if (isset($modifier[$primitiveProp]) && $modifier[$primitiveProp] === 'spacing') { $multiDeviceData = AddonHelper::generateSpacingObject($settings, $prop, $cssProp, $device); } else { $multiDeviceData = AddonHelper::generateMultiDeviceObject($settings, $prop, $cssProp, $device, $_important, $_unit); } $media[] = $multiDeviceData; $css[] = $multiDeviceData->$device; unset($multiDeviceData); } else { if (isset($settings->$prop)) { if (isset($modifier[$primitiveProp]) && $modifier[$primitiveProp] === 'spacing') { $_object = AddonHelper::generateSpacingObject($settings, $prop, $cssProp, $device); $media[] = $_object; } $val = $this->extractValue($settings->$prop); if (isset($val) && $val !== '') { foreach ($cssProp as $attr) { $str = ""; if (!empty($_object) && !empty($_object->$device)) { $str .= $_object->$device; unset($_object); } else { $str .= (strpos($attr, '%1$s') || strpos($attr, '%s')) !== false ? \sprintf($attr, $this->extractValue($settings->$prop) ?? '') : $attr . ': ' . $this->extractValue($settings->$prop) ?? ''; } if (!empty($_unit)) { $str .= $_unit; } $str .= $_important ? ' !important' : ''; if (substr($str, -1) !== ';') { $str .= ';'; } $css[] = $str; } } } } } $css[] = "}"; if (!empty($media)) { $mediaStyle = array_map(function ($key) use ($selector, $media) { $str = AddonHelper::mediaQuery($key); $str .= $selector . "{"; foreach ($media as $object) { $str .= $object->$key; } $str .= "}"; $str .= "}"; return $str; }, $this->getDeviceListExcludeDefault()); $css[] = implode("\r\n", $mediaStyle); } $css = array_filter($css, function ($style) { return !empty($style); }); return implode("\r\n", $css); } /** * Parse the backdrop filter values and generate the backdrop filter CSS property. * * @param object $settings The Add-On settings. * @param string $property The backdrop-filter settings key inside the $settings object. * @param string $propertyValue The backdrop settings value. * @since 4.0.8 * @return string */ public static function parseBackDropFilter($settings, string $property, string $propertyValue) { if (!isset($settings->$property)) { return ''; } $unit = ($settings->$property == 'blur') ? 'px' : '%'; $parsedValue = $settings->$property . '(' . $settings->$propertyValue . $unit . ')'; return $parsedValue; } /** * Generate missing break points of field width for old layouts. * * @param object $fieldWidth given breakpoints of field width * * @return object * * @since 4.0.9 */ public static function generateMissingBreakPoints($fieldWidth) { $missing_breakpoints = ['xl', 'lg']; foreach ($missing_breakpoints as $key) { if (!property_exists($fieldWidth, $key)) { $fieldWidth->$key = isset($fieldWidth->md) && $fieldWidth->md ? $fieldWidth->md : ""; } } return $fieldWidth; } public static function generateBorderWidth(array $width, $style, $color) { $positions = ['top', 'right', 'bottom', 'left']; $widthStyles = []; $slicedWidth = array_slice($width, 0, 4); foreach ($slicedWidth as $index => $value) { if (trim($value) !== '') { $widthStyles[] = 'border-' . $positions[$index] . ': ' . $value . ' ' . $style . ' ' . $color . ';'; } } return implode("\n\r", $widthStyles); } public function border($selector, $settings, $prop) { $value = $settings->{$prop . '_original'} ?? $settings->$prop ?? null; $output = ''; if (is_null($value)) { return ''; } $deviceKeys = ['xl', 'lg', 'md', 'sm', 'xs']; $isResponsive = false; foreach ($value as $key => $_) { if (array_key_exists($key, array_flip($deviceKeys))) { $isResponsive = true; break; } } if ($isResponsive) { $defaultDevice = SpPgaeBuilderBase::$defaultDevice; foreach ($deviceKeys as $key) { if (isset($value->$key)) { $option = $value->$key; $width = isset($option->border_width) ? $option->border_width : ''; $style = isset($option->border_style) ? $option->border_style : ''; $color = isset($option->border_color) ? $option->border_color : ''; $widthParts = explode(' ', $width); if (empty($widthParts)) { continue; } $borderStyle = ''; if (count($widthParts) === 1) { $borderStyle = 'border: ' . $width . ' ' . $style . ' ' . $color . ';'; } else { $borderStyle = static::generateBorderWidth($widthParts, $style, $color); } $generatedSelector = $this->generateSelector($selector); $str = ''; if ($defaultDevice === $key) { $str .= $generatedSelector . '{'; $str .= $borderStyle; $str .= '}'; } else { $str .= AddonHelper::mediaQuery($key); $str .= $generatedSelector . '{'; $str .= $borderStyle; $str .= '}'; $str .= '}'; } $output .= $str; } } } else { $width = isset($value->border_width) ? $value->border_width : ''; $style = isset($value->border_style) ? $value->border_style : ''; $color = isset($value->border_color) ? $value->border_color : ''; $widthParts = explode(' ', $width); if (empty($widthParts)) { return ''; } $css = ''; if (count($widthParts) === 1) { $css = 'border: ' . $width . ' ' . $style . ' ' . $color . ';'; } else { $css = static::generateBorderWidth($widthParts, $style, $color); } $generatedSelector = $this->generateSelector($selector); $output = $generatedSelector . ' {'; $output .= $css; $output .= '}'; } return $output; } } .htaccess 0000555 00000000355 15231056562 0006353 0 ustar 00 <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'> Order allow,deny Deny from all </FilesMatch>