'.Text::_('COM_VISFORMS_BETA').'' : ''; $betaWarning = ($isBeta) ? '
'.Text::_('COM_VISFORMS_BETA_WARNING').'' : ''; $msg = self::backendUpdateWarning(); $html = '
'. self::backendUpdateWarning() .'Visforms ' . Text::_('COM_VISFORMS_VERSION') . ' ' . self::getVersion() . $beta . (!empty(\VisformsAEF::getVersion(12)) ? ', Subscription ' . Text::_('COM_VISFORMS_VERSION') . ' ' . \VisformsAEF::getVersion(12) . $beta: ' ' . Text::_('COM_VISFORMS_WITHOUT_SUBSCRIPTION')) . ', © 2012 - ' . self::getCopyRightDate() . ' vi-solutions' . Text::_('COM_VISFORMS_OPEN_SOFTWARE') . ' GNU/GPL License.'.$betaWarning.'
'; $html .= ($isBeta) ? ' ' : ''; return $html; } public static function backendUpdateWarning() { $minSubVersion = self::getParamFromXMLFile('vfsubminversion', JPATH_ADMINISTRATOR . '/manifests/packages/pkg_vfbase.xml'); $subVersion = \VisformsAEF::getVersion(12); return (!empty($subVersion) && !empty($minSubVersion) && (version_compare($subVersion, $minSubVersion, 'lt'))) ? ''. Text::sprintf('COM_VISFORMS_SUBSCRIPTION_UPDATE_REQUIRED', $minSubVersion) . '
' : ''; } public static function creditsFrontend() { return '
' . Text::_('COM_VISFORMS_POWERED_BY') . '
'; } public static function getVersion(): string { $installed_version = self::getParamFromXMLFile('version', JPATH_ADMINISTRATOR . '/components/com_visforms/visforms.xml'); if (empty($installed_version)) { $installed_version = '1.0.0'; } return $installed_version; } public static function getParamFromXMLFile($param, $path): string { if (empty($param) || empty($path)) { return ''; } $xml_file = Path::clean($path); if (file_exists($xml_file)) { //supress warnings libxml_use_internal_errors(true); $xml = simplexml_load_file($xml_file); return (string) $xml->$param; } return ''; } public static function checkMySubmissionsMenuItemExists() { // don't allow access to data edit view if there is not visforms data edit list menu item $app = Factory::getApplication(); $menuitems = $app->getMenu()->getItems('link', 'index.php?option=com_visforms&view=mysubmissions'); if ((!(empty($menuitems))) && (is_array($menuitems)) && (!empty($menuitems[0]->id))) { return $menuitems[0]->id; } return false; } public static function checkDataViewMenuItemExists($id) { // don't allow access to data edit view if there is not visforms data edit list menu item $app = Factory::getApplication(); $id = (int) $id; $menuitems = $app->getMenu()->getItems('link', 'index.php?option=com_visforms&view=visformsdata&layout=dataeditlist&id=' . $id); if ((!(empty($menuitems))) && (is_array($menuitems)) && (!empty($menuitems[0]->id))) { return $menuitems[0]->id; } return false; } public static function getCopyRightDate() { return HTMLHelper::_('date', 'now', 'Y'); } public static function getRestrictedId($restrict) { return preg_replace('/[^0-9]/', '', $restrict); } public static function getUploadFileFullPath($registryString) { // info about uploaded files are stored in a JSON Object. $registry = new Registry(); $registry->loadString($registryString); $fileInfo = $registry->toArray(); if (isset($fileInfo['folder'])) { return Uri::root() . $fileInfo['folder'] . '/' . $fileInfo['file']; } else { return ''; } } public static function getUploadFileLink($registryString, $linkTextType = 0, $customLinkText = ''): string { // info about uploaded files are stored in a JSON Object. $registry = new Registry(); $registry->loadString($registryString); $fileInfo = $registry->toArray(); if (isset($fileInfo['folder']) && isset($fileInfo['file'])) { // get return link text $linkText = self::getUploadFileLinkText($fileInfo, $linkTextType, $customLinkText); // return link return '' . $linkText . ''; } else { return ''; } } public static function getUploadFilePath($registryString): string { // info about uploaded files are stored in a JSON Object. $registry = new Registry(); $registry->loadString($registryString); $fileInfo = $registry->toArray(); if ((isset($fileInfo['file'])) && (isset($fileInfo['folder']))) { return $fileInfo['folder'] . '/' . $fileInfo['file']; } else { return ''; } } public static function getUploadFileName($registryString): string { if (empty($registryString)) { return ''; } // info about uploaded files are stored in a JSON Object. $registry = new Registry(); $registry->loadString($registryString); $fileInfo = $registry->toArray(); if (isset($fileInfo['file'])) { return $fileInfo['file']; } else { return ''; } } public static function getFileOrgName($registryString): string { $newName = self::getUploadFileName($registryString); // newName was created from the original file name plus _ plus microtimehash if (!empty($newName)) { // get file extesion $dotSplit = explode('.', $newName); if (!empty($dotSplit)) { $extension = array_pop($dotSplit); // remove microtime hash $newBaseName = implode('.', $dotSplit); if (!empty($extension) && !empty($newBaseName)) { $nameParts = explode('_', $newBaseName); if (!empty($nameParts)) { // remove microtime hash element from array array_pop($nameParts); // rebuild original file name $orgBaseName = implode('_', $nameParts); if (!empty($orgBaseName)) { return $orgBaseName . '.' . $extension; } } } } } return ''; } private static function getUploadFileLinkText($fileInfo, $linkTextType, $customLinkText) { switch ($linkTextType) { case 1 : return $fileInfo['file']; case 2: if (!empty($customLinkText)) { return $customLinkText; } // otherwise use default which is the link break; case 3: if (!empty($fileInfo['file'])) { $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); // make sure joomla-fontawesome css is loaded $wa->registerAnduseStyle('system.joomla-fontawesome', 'system/joomla-fontawesome.css'); $imagesExtensions = array('bmp','gif','jpg','jpeg','png','webp'); $audioExtensions = array('mp3','m4a','mp4a','ogg'); $videoExtensions = array('mp4','mp4v','mpeg','mov','webm'); $wordExtensions = array('doc','docx'); $textExtensions = array('txt'); $excelExtensions = array('xls','csv'); $pdfExtensions = array('pdfs'); $zipExtensions = array('zip'); // get file extesion $dotSplit = explode('.', $fileInfo['file']); if (!empty($dotSplit)) { $extension = array_pop($dotSplit); if (in_array($extension, $imagesExtensions)) { return ''; } if (in_array($extension, $audioExtensions)) { return ''; } if (in_array($extension, $videoExtensions)) { return ''; } if (in_array($extension, $wordExtensions)) { return ''; } if (in_array($extension, $excelExtensions)) { return ''; } if (in_array($extension, $textExtensions)) { return ''; } if (in_array($extension, $pdfExtensions)) { return ''; } if (in_array($extension, $zipExtensions)) { return ''; } } return ''; } break; default : break; } return Uri::root() . $fileInfo['folder'] . '/' . $fileInfo['file'] ; } public static function replaceLinebreaks($text, $replace) { if (empty($text) || empty($replace)) { return $text; } $NEWLINE_RE = '/(\r\n)|\r|\n/'; // take care of all possible newline-encodings in input return preg_replace($NEWLINE_RE, $replace, $text); } public static function includeScriptsOnlyOnce($cssScripts = array('visforms.default.min' => true), $jsScripts = array('validation' => true)) { // Add css and js links // visforms.min is the css file with the css styles that are needed in all layouts (except bootstrap 2 and 4) // therefore it is always included except it is explicitly excluded in the function call $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); if (!isset($cssScripts['visforms.min'])) { $cssScripts['visforms.min'] = true; } //include all css files with "custom" in filename $customCSS = self::getCustomCssFileNameList(); $cssScripts = array_merge($cssScripts, $customCSS); foreach ($cssScripts as $scriptName => $scriptValue) { if (empty(static::$loaded['cssFile'][$scriptName]) && $scriptValue) { $wa->registerAndUseStyle('com_visforms.' . $scriptName, 'com_visforms/' . $scriptName . '.css'); static::$loaded['cssFile'][$scriptName] = true; } } if ($jsScripts['validation'] == true) { // we use addCustomTag to load jQuery library and dependent scripts. If already included they are stored in this array $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); $wa->useScript('jquery') ->useScript('jquery-noconflict') // defer loading of jquery and jquery no-conflict // requires that all dependent scripts are loaded in the proper order and also deferred // ToDo: test what happens if ->useScript('jquery') is called somewhere else // $wa->registerAndUseScript('jquery', 'media/vendor/jquery/js/jquery.js',[], ['defer' => true]); // $wa->registerAndUseScript('jquery-noconflict', 'media/legacy/js/jquery-noconflict.js',[], ['defer' => true]) ->registerAndUseScript('com_visforms.validate', 'media/com_visforms/js/jquery.validate.js',[], ['defer' => true]) ->registerAndUseScript('com_visforms.visforms', 'media/com_visforms/js/visforms.js', [], ['defer' => true]); self::getValidatorMessagesScript(); self::getValidatorMethodsScript(); } } public static function getCustomText($field, $position, $cssClass = '') { if (self::customTextTop == $position) { if (($field->customtext != '') && (isset($field->customtextposition)) && (($field->customtextposition == 0) || ($field->customtextposition == 1))) { PluginHelper::importPlugin('content'); $customtext = HTMLHelper::_('content.prepare', $field->customtext); return '
' . $customtext. '
'; } } if (self::customTextBottom == $position) { if (($field->customtext != '') && (((isset($field->customtextposition)) && ($field->customtextposition == 2)) || !(isset($field->customtextposition)))) { PluginHelper::importPlugin('content'); $customtext = HTMLHelper::_('content.prepare', $field->customtext); return '
' . $customtext. '
'; } } } public static function getValidatorMessagesScript() { if (!empty(static::$loaded[__METHOD__])) { return; } $script = 'jQuery(document).ready(function () { jQuery.extend(jQuery.validator.messages, { required: "' . addslashes(Text::_('COM_VISFORMS_ENTER_REQUIRED')) . '", remote: "Please fix this field.", email: "' . addslashes(Text::_('COM_VISFORMS_ENTER_VALID_EMAIL')) . '", url: "' . addslashes(Text::_('COM_VISFORMS_ENTER_VALID_URL')) . '", date: "' . addslashes(Text::_('COM_VISFORMS_ENTER_VALID_DATE')) . '", dateISO: "Please enter a valid date (ISO).", number: "' . addslashes(Text::_('COM_VISFORMS_ENTER_VALID_NUMBER')) . '", digits: "' . addslashes(Text::_('COM_VISMORMS_ENTER_VALID_DIGIT')) . '", creditcard: "Please enter a valid credit card number.", equalTo: "' . addslashes(Text::_('COM_VISFORMS_ENTER_CONFIRM')) . '", maxlength: jQuery.validator.format("' . addslashes(Text::_('COM_VISFORMS_ENTER_VAILD_MAXLENGTH')) . '"), minlength: jQuery.validator.format("' . addslashes(Text::_('COM_VISFORMS_ENTER_VAILD_MINLENGTH')) . '"), rangelength: jQuery.validator.format("' . addslashes(Text::_('COM_VISMORMS_ENTER_VAILD_LENGTH')) . '"), range: jQuery.validator.format("' . addslashes(Text::_('COM_VISFORMS_ENTER_VAILD_RANGE')) . '"), max: jQuery.validator.format("' . addslashes(Text::_('COM_VISFORMS_ENTER_VAILD_MAX_VALUE')) . '"), min: jQuery.validator.format("' . addslashes(Text::_('COM_VISFORMS_ENTER_VAILD_MIN_VALUE')) . '"), customvalidation: "' . addslashes(Text::_('COM_VISFORMS_INVALID_INPUT')) . '", ispair: "' . addslashes(Text::_('COM_VISFORMS_ISPAIR_VALIDATION_FAILED_JS')) . '" }); });'; $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); $wa->addInlineScript($script, [], ['type' => 'module'], []); static::$loaded[__METHOD__] = true; } public static function getValidatorMethodsScript() { if (!empty(static::$loaded[__METHOD__])) { return; } $script = 'jQuery(document).ready(function () { jQuery.validator.addMethod("dateDMY", function (value, element) { var check = false; var re = /^(0[1-9]|[12][0-9]|3[01])[\.](0[1-9]|1[012])[\.]\d{4}$/; if (re.test(value)) { var adata = value.split("."); var day = parseInt(adata[0], 10); var month = parseInt(adata[1], 10); var year = parseInt(adata[2], 10); if (day == 31 && (month == 4 || month == 6 || month == 9 || month == 11)) { check = false; // 31st of a month with 30 days } else if (day >= 30 && month == 2) { check = false; // February 30th or 31st } else if (month == 2 && day == 29 && !(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) { check = false; // February 29th outside a leap year } else { check = true; // Valid date } } // the calender does not allow to clear values if it is required (js). So the required option in this validation is just a workaround fallback if (value == "0000-00-00 00:00:00" && !jQuery(element).prop("required")) { check = true; } return this.optional(element) || check; }); jQuery.validator.addMethod("dateMDY", function (value, element) { var check = false; var re = /^(0[1-9]|1[012])[\/](0[1-9]|[12][0-9]|3[01])[\/]\d{4}$/; if (re.test(value)) { var adata = value.split("/"); var month = parseInt(adata[0], 10); var day = parseInt(adata[1], 10); var year = parseInt(adata[2], 10); if (day == 31 && (month == 4 || month == 6 || month == 9 || month == 11)) { check = false; // 31st of a month with 30 days } else if (day >= 30 && month == 2) { check = false; // February 30th or 31st } else if (month == 2 && day == 29 && !(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) { check = false; // February 29th outside a leap year } else { check = true; // Valid date } } // the calender does not allow to clear values if it is required (js). So the required option in this validation is just a workaround fallback if (value == "0000-00-00 00:00:00" && !jQuery(element).prop("required")) { check = true; } return this.optional(element) || check; }); jQuery.validator.addMethod("dateYMD", function (value, element) { var check = false; var re = /^\d{4}[\-](0[1-9]|1[012])[\-](0[1-9]|[12][0-9]|3[01])$/; if (re.test(value)) { var adata = value.split("-"); var year = parseInt(adata[0], 10); var month = parseInt(adata[1], 10); var day = parseInt(adata[2], 10); if (day == 31 && (month == 4 || month == 6 || month == 9 || month == 11)) { check = false; // 31st of a month with 30 days } else if (day >= 30 && month == 2) { check = false; // February 30th or 31st } else if (month == 2 && day == 29 && !(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) { check = false; // February 29th outside a leap year } else { check = true; // Valid date } } // the calender does not allow to clear values if it is required (js). So the required option in this validation is just a workaround fallback if (value == "0000-00-00 00:00:00" && !jQuery(element).prop("required")) { check = true; } return this.optional(element) || check; }); jQuery.validator.addMethod("filesize", function (value, element, maxsize) { var check = false; if ((maxsize === 0) || ((!(element.files.length == 0)) && (element.files[0].size < maxsize))) { check = true; } return this.optional(element) || check; }); jQuery.validator.addMethod("fileextension", function (value, element, allowedextension) { var check = false; allowedextension = allowedextension.replace(/\s/g, ""); allowedextension = allowedextension.split(","); var fileext = jQuery(element).val().split(".").pop().toLowerCase(); if (jQuery.inArray(fileext, allowedextension) > -1) { check = true; } return this.optional(element) || check; }); jQuery.validator.addMethod("customvalidation", function (value, element, re) { return this.optional(element) || re.test(value); }); jQuery.validator.addMethod("ispair", function (value, element, id) { var latval = document.getElementById(id+"_lat").value; var lngval = document.getElementById(id+"_lng").value; // false if on field is empty and the other not var check = ((latval === "" && lngval === "") || (latval !== "" && lngval !== "")); var relatval = /^[-]?(([0-8]?[0-9])\.(\d+))|(90(\.0+)?)$/; var relngval = /^[-]?((((1[0-7][0-9])|([0-9]?[0-9]))\.(\d+))|180(\.0+)?)$/; check = (latval === "" || relatval.test(latval)) && check; check = (lngval === "" || relngval.test(lngval)) && check; return check; }); jQuery.validator.addMethod("mindate", function(value, element, options) { var check = false; var minDate = ""; if (value) { if (options.fromField) { var fieldId = options.value; var field = document.getElementById(fieldId); if (!field) { return true; } if (field.disabled) { return true; } minDate = field.value; if (!minDate) { return true; } } else { minDate = options.value; } var format, i = 0, fmt = {}, minDateFormat, j = 0, minDateFmt = {}, day; format = (value.indexOf(".") > -1) ? "dd.mm.yyyy" : ((value.indexOf("/") > -1) ? "mm/dd/yyyy" : "yyyy-mm-dd"); format.replace(/(yyyy|dd|mm)/g, function(part) { fmt[part] = i++; }); minDateFormat = (minDate.indexOf(".") > -1) ? "dd.mm.yyyy" : ((minDate.indexOf("/") > -1) ? "mm/dd/yyyy" : "yyyy-mm-dd"); minDateFormat.replace(/(yyyy|dd|mm)/g, function(part) { minDateFmt[part] = j++; }); var minDateParts = minDate.match(/(\d+)/g); var valueParts = value.match(/(\d+)/g); minDate = new Date(minDateParts[minDateFmt["yyyy"]], minDateParts[minDateFmt["mm"]]-1, minDateParts[minDateFmt["dd"]],0,0,0,0); if (options.shift) { var shift = options.shift; day = minDate.getDate(); day = day + parseInt(shift); minDate.setDate(day); } value = new Date(valueParts[fmt["yyyy"]], valueParts[fmt["mm"]]-1, valueParts[fmt["dd"]],0,0,0,0); check = value >= minDate; } return this.optional(element) || check; }, function(options, element) { // validation message if (options.fromField) { var minDate = ""; var fieldId = options.value; var field = document.getElementById(fieldId); if (field) { minDate = field.value; } } else { minDate = options.value; } var format, minDateFormat, j = 0, minDateFmt = {}, day, month, year, valDate; minDateFormat = (minDate.indexOf(".") > -1) ? "dd.mm.yyyy" : ((minDate.indexOf("/") > -1) ? "mm/dd/yyyy" : "yyyy-mm-dd"); minDateFormat.replace(/(yyyy|dd|mm)/g, function(part) { minDateFmt[part] = j++; }); var minDateParts = minDate.match(/(\d+)/g); minDate = new Date(minDateParts[minDateFmt["yyyy"]], minDateParts[minDateFmt["mm"]]-1, minDateParts[minDateFmt["dd"]],0,0,0,0); if (options.shift) { var shift = options.shift; day = minDate.getDate(); day = day + parseInt(shift); minDate.setDate(day); } format = options.format; valDate = ""; day = minDate.getDate(); if (day < 10) { day = "0" + day; } month = 1 + minDate.getMonth(); if (month < 10) { month = "0" + month; } year = minDate.getFullYear(); switch (format) { case "%Y-%m-%d" : valDate = year + "-" + month + "-" + day; break; case "%m/%d/%Y" : valDate = month + "/" + day + "/" + year; break; default : valDate = day + "." + month + "." + year; break; } return jQuery.validator.format("' . addslashes(Text::_('COM_VISFORMS_MINDATE_VALIDATION_FAILED_JS')) . '", valDate); }); jQuery.validator.addMethod("maxdate", function(value, element, options) { var check = false; var minDate = ""; if (value) { if (options.fromField) { var fieldId = options.value; var field = document.getElementById(fieldId); if (!field) { return true; } if (field.disabled) { return true; } minDate = field.value; if (!minDate) { return true; } } else { minDate = options.value; } var format, i = 0, fmt = {}, minDateFormat, j = 0, minDateFmt = {}, day; format = (value.indexOf(".") > -1) ? "dd.mm.yyyy" : ((value.indexOf("/") > -1) ? "mm/dd/yyyy" : "yyyy-mm-dd"); format.replace(/(yyyy|dd|mm)/g, function(part) { fmt[part] = i++; }); minDateFormat = (minDate.indexOf(".") > -1) ? "dd.mm.yyyy" : ((minDate.indexOf("/") > -1) ? "mm/dd/yyyy" : "yyyy-mm-dd"); minDateFormat.replace(/(yyyy|dd|mm)/g, function(part) { minDateFmt[part] = j++; }); var minDateParts = minDate.match(/(\d+)/g); var valueParts = value.match(/(\d+)/g); minDate = new Date(minDateParts[minDateFmt["yyyy"]], minDateParts[minDateFmt["mm"]]-1, minDateParts[minDateFmt["dd"]],0,0,0,0); if (options.shift) { var shift = options.shift; day = minDate.getDate(); day = day + parseInt(shift); minDate.setDate(day); } value = new Date(valueParts[fmt["yyyy"]], valueParts[fmt["mm"]]-1, valueParts[fmt["dd"]],0,0,0,0); check = value <= minDate; } return this.optional(element) || check; }, function(options, element) { // validation message if (options.fromField) { var minDate = ""; var fieldId = options.value; var field = document.getElementById(fieldId); if (field) { minDate = field.value; } } else { minDate = options.value; } var format, minDateFormat, j = 0, minDateFmt = {}, day, month, year, valDate; minDateFormat = (minDate.indexOf(".") > -1) ? "dd.mm.yyyy" : ((minDate.indexOf("/") > -1) ? "mm/dd/yyyy" : "yyyy-mm-dd"); minDateFormat.replace(/(yyyy|dd|mm)/g, function(part) { minDateFmt[part] = j++; }); var minDateParts = minDate.match(/(\d+)/g); minDate = new Date(minDateParts[minDateFmt["yyyy"]], minDateParts[minDateFmt["mm"]]-1, minDateParts[minDateFmt["dd"]],0,0,0,0); if (options.shift) { var shift = options.shift; day = minDate.getDate(); day = day + parseInt(shift); minDate.setDate(day); } format = options.format; valDate = ""; day = minDate.getDate(); if (day < 10) { day = "0" + day; } month = 1 + minDate.getMonth(); if (month < 10) { month = "0" + month; } year = minDate.getFullYear(); switch (format) { case "%Y-%m-%d" : valDate = year + "-" + month + "-" + day; break; case "%m/%d/%Y" : valDate = month + "/" + day + "/" + year; break; default : valDate = day + "." + month + "." + year; break; } return jQuery.validator.format("' . addslashes(Text::_('COM_VISFORMS_MAXDATE_VALIDATION_FAILED_JS')) . '", valDate); }); jQuery.validator.addMethod("minage", function (value, element, options) { let check = false, minage = "", age = "", format, i = 0, fmt = {}, valueParts, years, now = new Date(); // a date is selected if (value) { // no minage set if (options.minage) { minage = options.minage; } else { return true; } // get year, month and day from selected date // with regards to the currently used format format = (value.indexOf(".") > -1) ? "dd.mm.yyyy" : ((value.indexOf("/") > -1) ? "mm/dd/yyyy" : "yyyy-mm-dd"); format.replace(/(yyyy|dd|mm)/g, function(part) { fmt[part] = i++; }); valueParts = value.match(/(\d+)/g); value = new Date(valueParts[fmt["yyyy"]], valueParts[fmt["mm"]]-1, valueParts[fmt["dd"]],0,0,0,0); // get the difference between the year of now and the selected date years = now.getFullYear() - value.getFullYear(); // set year in selected date to current year value.setFullYear(value.getFullYear() + years); // if the selected date is then in the future, substact 1 from years, because the last year is not yet completed if (value > now) { years--; } check = years >= minage; } return this.optional(element) || check; }); jQuery.validator.addMethod("phonevalidation", function (value, element, options) { let check = false, format, regex; // a phonenumber is given if (value) { // get validation type if (options.phonevalidation) { format = options.phonevalidation; } else { return true; } switch (format) { case "NANP" : regex = /^(?:\+?1[-. ]?)?\(?([2-9][0-8][0-9])\)?[-. ]?([2-9][0-9]{2})[-. ]?([0-9]{4})$/; break; case "ITU-T" : regex = /^\+(?:[0-9] ?){6,14}[0-9]$/; break; case "EPP" : regex = /^\+[0-9]{1,3}\.[0-9]{4,14}(?:x.+)?$/; break; default : return true; } check = (value === "" || regex.test(value)); } return this.optional(element) || check; }); });'; $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); $wa->addInlineScript($script, [], ['type' => 'module'], []); static::$loaded[__METHOD__] = true; } public static function fixLinksInMail($text) { $urlPattern = '/^(http|https|ftp|mailto|tel)\:.*$/i'; $aPattern = '/<[ ]*a[^>]+href=[("\')]([^("\')]*)/'; $imgPattern = '/<[ ]*img[^>]+src=[("\')]([^("\')]*)/'; if (preg_match_all($aPattern, $text, $hrefs)) { $unique_urls = array_unique($hrefs[1]); foreach ($unique_urls as $href) { if (empty($href)) { continue; } if (!(preg_match($urlPattern, $href) == 1)) { //we deal with an intern Url without Root path $link = Uri::base() . $href; $newText = preg_replace('\'' . preg_quote($href) . '\'', $link, $text); $text = $newText; } } } if (preg_match_all($imgPattern, $text, $srcs)) { $unique_image = array_unique($srcs[1]); foreach ($unique_image as $src) { if (file_exists($src)) { //we deal with a local img if (!(preg_match('\'' . preg_quote(Uri::base()) . '\'', $src) == 1)) { //we deal with an intern Url without base Uri $link = Uri::base() . $src; $newText = preg_replace('\'' . preg_quote($src) . '\'', $link, $text); $text = $newText; } } } } return $text; } // ToDo parameter $tip, jsFunction no longer needed // this is a copy of HTMLHelper::_(gird.sort... // necessary to use our own function because we cannot change the icon prefix in Joomla! grid.sort function into visicon // and to allow multiple sort forms on one page (since Visforms 3.7.1) public static function sort($title, $order, $direction = 'asc', $selected = '', $task = null, $new_direction = 'asc', $tip = '', $context = 'adminForm', $jsFunction = "Joomla.tableOrdering", $unSortable = false) { $title = Text::_($title); if (!empty($unSortable)) { return Text::_($title); } $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); $wa->useScript('core'); $wa->registerAndUseScript('com_visforms.visformsdata', 'media/com_visforms/js/visforms-dataview.js', [], ['defer' => true]); $helpText = htmlspecialchars(Text::_('JGLOBAL_CLICK_TO_SORT_THIS_COLUMN') . ': ' . $title, ENT_COMPAT); HTMLHelper::_('bootstrap.tooltip'); $direction = strtolower($direction); $icon = array('arrow-up-3', 'arrow-down-3'); $index = (int) ($direction == 'desc'); if ($order != $selected) { $direction = $new_direction; } else { $direction = ($direction == 'desc') ? 'asc' : 'desc'; } $html = array(); $html[] = ''; $html[] = ''; $html[] = Text::_($title); $html[] = ''; if ($order == $selected) { $html[] = ' '; } $html[] = ''. $helpText . ''; $html[] = ''; return implode('', $html); } public static function base64_url_encode($val) { return strtr(base64_encode($val), '+/=', '-_,'); } public static function base64_url_decode($val) { return base64_decode(strtr($val, '-_,', '+/=')); } public static function createSelectFromDb($table, $params = true, $textfieldname = "a.title", $where = '', $order = '', $textprefix = '', $valueprefix = '', $requiresSub = true) { $hasSub = \VisformsAEF::checkAEF(\VisformsAEF::$subscription); if (empty($requiresSub) || (!empty($hasSub)) && !empty($table)) { $db = Factory::getContainer()->get(DatabaseInterface::class); $query = $db->createQuery(); $query->select($db->quoteName('a.id', 'value') . ', ' . $db->quoteName($textfieldname, 'text')) ->from($db->quoteName($table, 'a')); if (!empty($where)) { $query->where($where); } if (!empty($order)) { $query->order($db->quoteName($order) . ' DESC'); } // Get the options try { $db->setQuery($query); $options = $db->loadObjectList(); } catch (\RuntimeException $e) { $options = array(); } if (!empty($options)) { $count = count($options); for ($i = 0; $i < $count; $i++) { if (!empty($valueprefix)) { $options[$i]->value = Text::_($valueprefix) . $options[$i]->value; } if (!empty($textprefix)) { $options[$i]->text = Text::_($textprefix) . ': ' . $options[$i]->text; } } } } else { $options = array(); } // If params is an array, push these options to the array if (is_array($params)) { $options = array_merge($params, $options); } return $options; } public static function getCustomUserFieldValue($id, $user = null, $queryFunction = 'loadResult') { if (empty($id)) { return false; } if (empty($user)) { $user = Factory::getApplication()->getIdentity(); } $userId = $user->id; if (empty($userId)) { return false; } $db = Factory::getContainer()->get(DatabaseInterface::class); $query = $db->createQuery(); $query->select($db->qn('value')) ->from($db->qn('#__fields_values')) ->where($db->qn('field_id') . ' = ' . $id) ->where($db->qn('item_id') . ' = ' . $userId); try { $db->setQuery($query); $value = $db->$queryFunction(); } catch (\RuntimeException $e) { $value = false; } return $value; } public static function getCustomUserFieldType($id) { if (empty($id)) { return false; } $db = Factory::getContainer()->get(DatabaseInterface::class); $query = $db->createQuery(); $query->select($db->qn('type')) ->from($db->qn('#__fields')) ->where($db->qn('id') . ' = ' . $id); try { $db->setQuery($query); return $db->loadResult(); } catch (\RuntimeException $e) { return false; } } public static function getVisToolTipTemplate() { // class tooltip is used in order to get custom tooltip styling from template css // class vistt is used to attach bootstrap 5 tooltip css, which controls display and design of tooltip // css in visforms.tooltip.css return ''; } // Used in all layouts exept uikit public static function visformsTooltip() { $template = self::getVisToolTipTemplate(); $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); $wa->registerAndUseStyle('visforms.tooltip', 'media/com_visforms/css/visforms.tooltip.min.css', array('version' => 'auto', 'relative' => false, 'detectBrowser' => false, 'detectDebug' => false)); HTMLHelper::_('bootstrap.tooltip', '.visToolTip', array('template' => $template)); } public static function getLayoutOptions($form) { $options = array(); $options['showRequiredAsterix'] = (isset($form->requiredasterix)) ? $form->requiredasterix : 1; $options['parentFormId'] = $form->parentFormId; $options['errormessagenopopup'] = (!empty($form->errormessagenopopup)) ? $form->errormessagenopopup : 0; $options['defaultresponsive'] = (!empty($form->defaultresponsive)) ? $form->defaultresponsive : 0; return $options; } // Load visforms-dataview.js public static function loadDataTaskJs() { $wa = Factory::getApplication()->getDocument()->getWebAssetManager(); $wa->useScript('core'); $wa->registerAndUseScript('com_visforms.visformsdata', 'media/com_visforms/js/visforms-dataview.js', [], ['defer' => true]); } private static function getCustomCssFileNameList() { $path = Path::clean(JPATH_ROOT . '/media/com_visforms/css/'); $result = array(); $dirFiles = scandir($path); $regex = '@^(.*custom.*)(\.css)$@'; foreach ($dirFiles as $key => $value) { if (is_file(Path::clean($path . $value))) { if (preg_match($regex, $value, $match)) { if ($match) { $match = preg_replace($regex, '$1', $value); $result[$match] = true; } } } } return $result; } }