diff --git a/.gitignore b/.gitignore index 60c42ce6e..e964b1f31 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ msi.iws .idea/ nbproject/ -Resources/Private/node_modules/ +node_modules .DS_Store .DS_Store? ._* diff --git a/Classes/Eid/GetLocationEid.php b/Classes/Eid/GetLocationEid.php index 5142e7295..14d2209e2 100644 --- a/Classes/Eid/GetLocationEid.php +++ b/Classes/Eid/GetLocationEid.php @@ -2,8 +2,10 @@ declare(strict_types = 1); namespace In2code\Powermail\Eid; +use InvalidArgumentException; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Throwable; use TYPO3\CMS\Core\Exception; use TYPO3\CMS\Core\Http\Response; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -59,7 +61,7 @@ public function main(ServerRequestInterface $request): ResponseInterface $response = new Response(); $response->getBody()->write($this->content); return $response; - } catch (\InvalidArgumentException $e) { + } catch (InvalidArgumentException $e) { // add a 410 "gone" if invalid parameters given return (new Response())->withStatus(410); } catch (Exception $e) { @@ -104,9 +106,8 @@ protected function getAddressFromGeo(float $lat, float $lng): array ]; } } - } catch (\Exception $e) { + } catch (Throwable $e) { } - return $result; } } diff --git a/Classes/Hook/CreateMarker.php b/Classes/Hook/CreateMarker.php index 15dcf9978..783a1836d 100644 --- a/Classes/Hook/CreateMarker.php +++ b/Classes/Hook/CreateMarker.php @@ -371,6 +371,7 @@ protected function shouldProcessField(): bool */ protected function shouldRenameMarker(array $markers): bool { - return !empty($markers[$this->uid]) && $markers[$this->uid] !== $this->properties['marker']; + return !empty($markers[$this->uid]) && !empty($this->properties['marker']) + && $markers[$this->uid] !== $this->properties['marker']; } } diff --git a/Classes/ViewHelpers/Validation/AbstractValidationViewHelper.php b/Classes/ViewHelpers/Validation/AbstractValidationViewHelper.php index 9d1285005..0ca613acb 100644 --- a/Classes/ViewHelpers/Validation/AbstractValidationViewHelper.php +++ b/Classes/ViewHelpers/Validation/AbstractValidationViewHelper.php @@ -72,19 +72,18 @@ protected function addMandatoryAttributes(array $additionalAttributes, ?Field $f $additionalAttributes['required'] = 'required'; } else { if ($this->isClientValidationEnabled()) { - $additionalAttributes['data-parsley-required'] = 'true'; + $additionalAttributes['data-powermail-required'] = 'true'; } } $additionalAttributes['aria-required'] = 'true'; if ($this->isClientValidationEnabled()) { - $additionalAttributes['data-parsley-required-message'] = + $additionalAttributes['data-powermail-required-message'] = LocalizationUtility::translate('validationerror_mandatory'); - $additionalAttributes['data-parsley-trigger'] = 'change'; /** * Special case multiselect: - * Parsley sets the error messages after the wrapping div (but only for multiselect) + * JS sets the error messages after the wrapping div (but only for multiselect) * So we define for this case where the errors should be included */ if ($field->getType() === 'select' && $field->isMultiselect()) { @@ -105,7 +104,7 @@ protected function addMandatoryAttributes(array $additionalAttributes, ?Field $f */ protected function addErrorContainer(array $additionalAttributes, Field $field): array { - $additionalAttributes['data-parsley-errors-container'] = + $additionalAttributes['data-powermail-errors-container'] = '.powermail_field_error_container_' . $field->getMarker(); return $additionalAttributes; } @@ -120,8 +119,8 @@ protected function addErrorContainer(array $additionalAttributes, Field $field): */ protected function addClassHandler(array $additionalAttributes, Field $field): array { - $additionalAttributes['data-parsley-class-handler'] = - '.powermail_fieldwrap_' . $field->getMarker() . ' div:first > div'; + $additionalAttributes['data-powermail-class-handler'] = + '.powermail_fieldwrap_' . $field->getMarker() . ' > div > div'; return $additionalAttributes; } diff --git a/Classes/ViewHelpers/Validation/CaptchaDataAttributeViewHelper.php b/Classes/ViewHelpers/Validation/CaptchaDataAttributeViewHelper.php index 81f1ae714..d8fe5d453 100644 --- a/Classes/ViewHelpers/Validation/CaptchaDataAttributeViewHelper.php +++ b/Classes/ViewHelpers/Validation/CaptchaDataAttributeViewHelper.php @@ -11,9 +11,8 @@ */ class CaptchaDataAttributeViewHelper extends ValidationDataAttributeViewHelper { - /** - * Returns Data Attribute Array for JS validation with parsley.js + * Returns Data Attribute Array for JS validation * * @return array for data attributes * @throws Exception @@ -30,12 +29,12 @@ public function render(): array if ($this->isNativeValidationEnabled()) { $dataArray['required'] = 'required'; } elseif ($this->isClientValidationEnabled()) { - $dataArray['data-parsley-required'] = 'true'; + $dataArray['data-powermail-required'] = 'true'; } if ($this->isClientValidationEnabled()) { - $dataArray['data-parsley-errors-container'] = '.powermail_field_error_container_' . $field->getMarker(); - $dataArray['data-parsley-class-handler'] = '#powermail_field_' . $field->getMarker(); - $dataArray['data-parsley-required-message'] = LocalizationUtility::translate('validationerror_mandatory'); + $dataArray['data-powermail-errors-container'] = '.powermail_field_error_container_' . $field->getMarker(); + $dataArray['data-powermail-class-handler'] = '#powermail_field_' . $field->getMarker(); + $dataArray['data-powermail-required-message'] = LocalizationUtility::translate('validationerror_mandatory'); } return $dataArray; diff --git a/Classes/ViewHelpers/Validation/DatepickerDataAttributeViewHelper.php b/Classes/ViewHelpers/Validation/DatepickerDataAttributeViewHelper.php index be5e06c48..f3c03c594 100644 --- a/Classes/ViewHelpers/Validation/DatepickerDataAttributeViewHelper.php +++ b/Classes/ViewHelpers/Validation/DatepickerDataAttributeViewHelper.php @@ -36,11 +36,6 @@ public function render(): array $additionalAttributes = $this->arguments['additionalAttributes']; $value = $this->arguments['value']; - $additionalAttributes['data-datepicker-force'] = - $this->settings['misc']['datepicker']['forceJavaScriptDatePicker'] ?? 0; - $additionalAttributes['data-datepicker-settings'] = $this->getDatepickerSettings($field); - $additionalAttributes['data-datepicker-months'] = $this->getMonthNames(); - $additionalAttributes['data-datepicker-days'] = $this->getDayNames(); $additionalAttributes['data-datepicker-format'] = $this->getFormat($field); if ($value) { $additionalAttributes['data-date-value'] = $value; @@ -54,7 +49,7 @@ public function render(): array /** * Get Datepicker Settings * - * @param Field $field + * @param Field|null $field * @return string */ protected function getDatepickerSettings(Field $field = null): string @@ -66,64 +61,39 @@ protected function getDatepickerSettings(Field $field = null): string } /** - * Get timeformat out of datepicker type - * - * @param Field $field + * @param Field|null $field * @return string */ protected function getFormat(Field $field = null): string { - return LocalizationUtility::translate('datepicker_format_' . $this->getDatepickerSettings($field)); - } - - /** - * Generate Monthnames from locallang - * - * @return string - */ - protected function getDayNames(): string - { - $days = [ - 'so', - 'mo', - 'tu', - 'we', - 'th', - 'fr', - 'sa', - ]; - $dayArray = []; - foreach ($days as $day) { - $dayArray[] = LocalizationUtility::translate('datepicker_day_' . $day); - } - return implode(',', $dayArray); + $format = LocalizationUtility::translate('datepicker_format_' . $this->getDatepickerSettings($field)); + return $this->convertFormatForMomentJs($format); } /** - * Generate Monthnames from locallang - * + * Because moment.js needs a different format writings, we need to convert this + * "Y-m-d H:i" => "YYYY-MM-DD HH:mm" + * @param string $format * @return string */ - protected function getMonthNames(): string + protected function convertFormatForMomentJs(string $format): string { - $months = [ - 'jan', - 'feb', - 'mar', - 'apr', - 'may', - 'jun', - 'jul', - 'aug', - 'sep', - 'oct', - 'nov', - 'dec', + $replace = [ + [ + 'Y', + 'm', + 'd', + 'H', + 'i', + ], + [ + 'YYYY', + 'MM', + 'DD', + 'HH', + 'mm', + ] ]; - $monthArray = []; - foreach ($months as $month) { - $monthArray[] = LocalizationUtility::translate('datepicker_month_' . $month); - } - return implode(',', $monthArray); + return str_replace($replace[0], $replace[1], $format); } } diff --git a/Classes/ViewHelpers/Validation/EnableParsleyAndAjaxViewHelper.php b/Classes/ViewHelpers/Validation/EnableJavascriptValidationAndAjaxViewHelper.php similarity index 87% rename from Classes/ViewHelpers/Validation/EnableParsleyAndAjaxViewHelper.php rename to Classes/ViewHelpers/Validation/EnableJavascriptValidationAndAjaxViewHelper.php index 9c4986eb6..ce470deaf 100644 --- a/Classes/ViewHelpers/Validation/EnableParsleyAndAjaxViewHelper.php +++ b/Classes/ViewHelpers/Validation/EnableJavascriptValidationAndAjaxViewHelper.php @@ -8,11 +8,10 @@ use TYPO3\CMS\Extbase\Object\Exception; /** - * Class EnableParsleyAndAjaxViewHelper + * Class EnableJavascriptValidationAndAjaxViewHelper */ -class EnableParsleyAndAjaxViewHelper extends AbstractValidationViewHelper +class EnableJavascriptValidationAndAjaxViewHelper extends AbstractValidationViewHelper { - /** * Could be disabled for testing * @@ -31,7 +30,7 @@ public function initializeArguments() } /** - * Returns Data Attribute Array to enable parsley + * Returns Data Attribute Array to enable validation * * @return array for data attributes * @throws Exception @@ -42,7 +41,7 @@ public function render(): array $form = $this->arguments['form']; $additionalAttributes = $this->arguments['additionalAttributes']; if ($this->isClientValidationEnabled()) { - $additionalAttributes['data-parsley-validate'] = 'data-parsley-validate'; + $additionalAttributes['data-powermail-validate'] = 'data-powermail-validate'; } if ($this->isNativeValidationEnabled()) { diff --git a/Classes/ViewHelpers/Validation/PasswordValidationDataAttributeViewHelper.php b/Classes/ViewHelpers/Validation/PasswordValidationDataAttributeViewHelper.php index 803c1a6ab..7fe5b2e61 100644 --- a/Classes/ViewHelpers/Validation/PasswordValidationDataAttributeViewHelper.php +++ b/Classes/ViewHelpers/Validation/PasswordValidationDataAttributeViewHelper.php @@ -11,9 +11,8 @@ */ class PasswordValidationDataAttributeViewHelper extends ValidationDataAttributeViewHelper { - /** - * Returns Data Attribute Array for JS validation with parsley.js + * Returns Data Attribute Array for JS validation * * @return array for data attributes * @throws Exception @@ -25,8 +24,8 @@ public function render(): array if ($this->isClientValidationEnabled()) { /** @var Field $field */ $field = $this->arguments['field']; - $additionalAttributes['data-parsley-equalto'] = '#powermail_field_' . $field->getMarker(); - $additionalAttributes['data-parsley-equalto-message'] = + $additionalAttributes['data-powermail-equalto'] = '#powermail_field_' . $field->getMarker(); + $additionalAttributes['data-powermail-equalto-message'] = LocalizationUtility::translate('validationerror_password'); } diff --git a/Classes/ViewHelpers/Validation/UploadAttributesViewHelper.php b/Classes/ViewHelpers/Validation/UploadAttributesViewHelper.php index df7c102f3..cd89f2fe2 100644 --- a/Classes/ViewHelpers/Validation/UploadAttributesViewHelper.php +++ b/Classes/ViewHelpers/Validation/UploadAttributesViewHelper.php @@ -45,14 +45,14 @@ public function render(): array } if ($this->isClientValidationEnabled()) { if (!empty($this->settings['misc']['file']['size'])) { - $additionalAttributes['data-parsley-powermailfilesize'] = + $additionalAttributes['data-powermail-powermailfilesize'] = (int)$this->settings['misc']['file']['size'] . ',' . $field->getMarker(); - $additionalAttributes['data-parsley-powermailfilesize-message'] = + $additionalAttributes['data-powermail-powermailfilesize-message'] = LocalizationUtility::translate('validationerror_upload_size'); } if (!empty($this->settings['misc']['file']['extension'])) { - $additionalAttributes['data-parsley-powermailfileextensions'] = $field->getMarker(); - $additionalAttributes['data-parsley-powermailfileextensions-message'] = + $additionalAttributes['data-powermail-powermailfileextensions'] = $field->getMarker(); + $additionalAttributes['data-powermail-powermailfileextensions-message'] = LocalizationUtility::translate('validationerror_upload_extension'); } } diff --git a/Classes/ViewHelpers/Validation/ValidationDataAttributeViewHelper.php b/Classes/ViewHelpers/Validation/ValidationDataAttributeViewHelper.php index 13885a880..9fcd3e7a5 100644 --- a/Classes/ViewHelpers/Validation/ValidationDataAttributeViewHelper.php +++ b/Classes/ViewHelpers/Validation/ValidationDataAttributeViewHelper.php @@ -29,7 +29,7 @@ public function initializeArguments() } /** - * Returns Data Attribute Array for JS validation with parsley.js + * Returns Data Attribute Array for JS validation with internal framework * * @return array for data attributes * @throws Exception @@ -88,18 +88,18 @@ protected function addMandatoryAttributesForMultipleFields( } } else { if ($this->isClientValidationEnabled()) { - $additionalAttributes['data-parsley-required'] = 'true'; + $additionalAttributes['data-powermail-required'] = 'true'; $additionalAttributes['aria-required'] = 'true'; } } if ($this->isClientValidationEnabled()) { - $additionalAttributes['data-parsley-required-message'] = + $additionalAttributes['data-powermail-required-message'] = LocalizationUtility::translate('validationerror_mandatory'); if ($iteration['total'] > 1) { - $additionalAttributes['data-parsley-required-message'] = + $additionalAttributes['data-powermail-required-message'] = LocalizationUtility::translate('validationerror_mandatory_multi'); if ($field->getType() === 'check') { - $additionalAttributes['data-parsley-required'] = 'true'; + $additionalAttributes['data-powermail-required'] = 'true'; $additionalAttributes['aria-required'] = 'true'; } } @@ -143,11 +143,11 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f * EMAIL (+html5) * * html5 example: - * javascript example: + * javascript example: */ case 1: if ($this->isClientValidationEnabled() && !$this->isNativeValidationEnabled()) { - $additionalAttributes['data-parsley-type'] = 'email'; + $additionalAttributes['data-powermail-type'] = 'email'; } break; @@ -155,11 +155,11 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f * URL (+html5) * * html5 example: - * javascript example: + * javascript example: */ case 2: if ($this->isClientValidationEnabled() && !$this->isNativeValidationEnabled()) { - $additionalAttributes['data-parsley-type'] = 'url'; + $additionalAttributes['data-powermail-type'] = 'url'; } break; @@ -181,7 +181,7 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f * * javascript example: - * */ case 3: @@ -190,7 +190,7 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f $additionalAttributes['pattern'] = $pattern; } else { if ($this->isClientValidationEnabled()) { - $additionalAttributes['data-parsley-pattern'] = $pattern; + $additionalAttributes['data-powermail-pattern'] = $pattern; } } break; @@ -199,11 +199,11 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f * NUMBER/INTEGER (+html5) * * html5 example: - * javascript example: + * javascript example: */ case 4: if ($this->isClientValidationEnabled() && !$this->isNativeValidationEnabled()) { - $additionalAttributes['data-parsley-type'] = 'integer'; + $additionalAttributes['data-powermail-type'] = 'integer'; } break; @@ -211,14 +211,14 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f * LETTERS (+html5) * * html5 example: - * javascript example: + * javascript example: */ case 5: if ($this->isNativeValidationEnabled()) { $additionalAttributes['pattern'] = '[A-Za-z]+'; } else { if ($this->isClientValidationEnabled()) { - $additionalAttributes['data-parsley-pattern'] = '[a-zA-Z]+'; + $additionalAttributes['data-powermail-pattern'] = '[a-zA-Z]+'; } } break; @@ -228,14 +228,14 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f * * Note: Field validation_configuration for editors viewable * html5 example: - * javascript example: + * javascript example: */ case 6: if ($this->isNativeValidationEnabled()) { $additionalAttributes['min'] = $field->getValidationConfiguration(); } else { if ($this->isClientValidationEnabled()) { - $additionalAttributes['data-parsley-min'] = $field->getValidationConfiguration(); + $additionalAttributes['data-powermail-min'] = $field->getValidationConfiguration(); } } break; @@ -245,14 +245,14 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f * * Note: Field validation_configuration for editors viewable * html5 example: - * javascript example: + * javascript example: */ case 7: if ($this->isNativeValidationEnabled()) { $additionalAttributes['max'] = $field->getValidationConfiguration(); } else { if ($this->isClientValidationEnabled()) { - $additionalAttributes['data-parsley-max'] = $field->getValidationConfiguration(); + $additionalAttributes['data-powermail-max'] = $field->getValidationConfiguration(); } } break; @@ -263,7 +263,7 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f * Note: Field validation_configuration for editors viewable * html5 example: * javascript example: - * + * */ case 8: $values = GeneralUtility::trimExplode(',', $field->getValidationConfiguration(), true); @@ -279,8 +279,8 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f $additionalAttributes['max'] = (int)$values[1]; } else { if ($this->isClientValidationEnabled()) { - $additionalAttributes['data-parsley-min'] = (int)$values[0]; - $additionalAttributes['data-parsley-max'] = (int)$values[1]; + $additionalAttributes['data-powermail-min'] = (int)$values[0]; + $additionalAttributes['data-powermail-max'] = (int)$values[1]; } } break; @@ -290,7 +290,7 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f * * Note: Field validation_configuration for editors viewable * javascript example: - * + * */ case 9: $values = GeneralUtility::trimExplode(',', $field->getValidationConfiguration(), true); @@ -302,7 +302,7 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f $values[0] = 1; } if ($this->isClientValidationEnabled()) { - $additionalAttributes['data-parsley-length'] = '[' . implode(', ', $values) . ']'; + $additionalAttributes['data-powermail-length'] = '[' . implode(', ', $values) . ']'; } break; @@ -312,14 +312,14 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f * Note: Field validation_configuration for editors viewable * html5 example: * javascript example: - * + * */ case 10: if ($this->isNativeValidationEnabled()) { $additionalAttributes['pattern'] = $field->getValidationConfiguration(); } else { if ($this->isClientValidationEnabled()) { - $additionalAttributes['data-parsley-pattern'] = $field->getValidationConfiguration(); + $additionalAttributes['data-powermail-pattern'] = $field->getValidationConfiguration(); } } break; @@ -330,7 +330,7 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f * If CustomValidation was added via Page TSConfig * tx_powermail.flexForm.validation.addFieldOptions.100 = New Validation * - * + * */ default: if ($field->getValidation() && $this->isClientValidationEnabled()) { @@ -338,13 +338,13 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f if ($field->getValidationConfiguration()) { $value = $field->getValidationConfiguration(); } - $additionalAttributes['data-parsley-custom' . $field->getValidation()] = $value; + $additionalAttributes['data-powermail-custom' . $field->getValidation()] = $value; } } // set errormessage if javascript validation active if ($field->getValidation() && $this->isClientValidationEnabled()) { - $additionalAttributes['data-parsley-error-message'] = + $additionalAttributes['data-powermail-error-message'] = LocalizationUtility::translate('validationerror_validation.' . $field->getValidation()); } @@ -352,7 +352,7 @@ protected function addValidationAttributes(array $additionalAttributes, Field $f } /** - * Add multiple attribute to bundle checkboxes for parsley + * Add multiple attribute to bundle checkboxes for JS validation framework * * @param array $additionalAttributes * @param Field $field @@ -370,7 +370,7 @@ protected function addMultipleDataAttributeForCheckboxes( $field->getType() === 'check' && $iteration['total'] > 1 ) { - $additionalAttributes['data-parsley-multiple'] = $field->getMarker(); + $additionalAttributes['data-powermail-multiple'] = $field->getMarker(); } return $additionalAttributes; } diff --git a/Configuration/TCA/tx_powermail_domain_model_field.php b/Configuration/TCA/tx_powermail_domain_model_field.php index 783f92b1f..737994daa 100644 --- a/Configuration/TCA/tx_powermail_domain_model_field.php +++ b/Configuration/TCA/tx_powermail_domain_model_field.php @@ -629,7 +629,7 @@ * EMAIL (+html5) * * html5 example: - * javascript example: + * javascript example: */ [ 'LLL:EXT:powermail/Resources/Private/Language/locallang_db.xlf:' . @@ -640,7 +640,7 @@ * URL (+html5) * * html5 example: - * javascript example: + * javascript example: */ [ 'LLL:EXT:powermail/Resources/Private/Language/locallang_db.xlf:' . @@ -653,7 +653,7 @@ * html5 example: * * javascript example: - * + * */ [ 'LLL:EXT:powermail/Resources/Private/Language/locallang_db.xlf:' . @@ -664,7 +664,7 @@ * NUMBER/INTEGER (+html5) * * html5 example: - * javascript example: + * javascript example: */ [ 'LLL:EXT:powermail/Resources/Private/Language/locallang_db.xlf:' . @@ -675,7 +675,7 @@ * LETTERS (+html5) * * html5 example: - * javascript example: + * javascript example: */ [ 'LLL:EXT:powermail/Resources/Private/Language/locallang_db.xlf:' . @@ -695,7 +695,7 @@ * * Note: Field validation_configuration for editors viewable * html5 example: - * javascript example: + * javascript example: */ [ 'LLL:EXT:powermail/Resources/Private/Language/locallang_db.xlf:' . @@ -707,7 +707,7 @@ * * Note: Field validation_configuration for editors viewable * html5 example: - * javascript example: + * javascript example: */ [ 'LLL:EXT:powermail/Resources/Private/Language/locallang_db.xlf:' . @@ -720,7 +720,7 @@ * Note: Field validation_configuration for editors viewable * html5 example: * javascript example: - * + * */ [ 'LLL:EXT:powermail/Resources/Private/Language/locallang_db.xlf:' . @@ -732,7 +732,7 @@ * * Note: Field validation_configuration for editors viewable * javascript example: - * + * */ [ 'LLL:EXT:powermail/Resources/Private/Language/locallang_db.xlf:' . @@ -745,7 +745,7 @@ * Note: Field validation_configuration for editors viewable * html5 example: * javascript example: - * + * */ [ 'LLL:EXT:powermail/Resources/Private/Language/locallang_db.xlf:' . diff --git a/Configuration/TypoScript/Main/Configuration/01_Extension.typoscript b/Configuration/TypoScript/Main/Configuration/01_Extension.typoscript new file mode 100644 index 000000000..fb6e8b961 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/01_Extension.typoscript @@ -0,0 +1,31 @@ +################## +# Basic plugin configuration of the extension +################## +plugin.tx_powermail { + view { + templateRootPaths { + 0 = EXT:powermail/Resources/Private/Templates/ + 1 = {$plugin.tx_powermail.view.templateRootPath} + } + + partialRootPaths { + 0 = EXT:powermail/Resources/Private/Partials/ + 1 = {$plugin.tx_powermail.view.partialRootPath} + } + + layoutRootPaths { + 0 = EXT:powermail/Resources/Private/Layouts/ + 1 = {$plugin.tx_powermail.view.layoutRootPath} + } + } + + # EXAMPLE: Modify localization of labels + # _LOCAL_LANG { + # default { + # confirmation_message = Are these values correct? + # } + # de { + # confirmation_message = Sind diese Eingaben korrekt? + # } + # } +} diff --git a/Configuration/TypoScript/Main/Configuration/02_Settings.typoscript b/Configuration/TypoScript/Main/Configuration/02_Settings.typoscript new file mode 100644 index 000000000..4a8f9b2d5 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/02_Settings.typoscript @@ -0,0 +1,48 @@ +################## +# Various settings +################## +plugin.tx_powermail.settings.setup { + main { + pid = {$plugin.tx_powermail.settings.main.pid} + form = {$plugin.tx_powermail.settings.main.form} + confirmation = {$plugin.tx_powermail.settings.main.confirmation} + optin = {$plugin.tx_powermail.settings.main.optin} + moresteps = {$plugin.tx_powermail.settings.main.moresteps} + } + + misc { + # HTML Output for type HMTL fields + htmlForHtmlFields = {$plugin.tx_powermail.settings.misc.htmlForHtmlFields} + + # HTML for labels + htmlForLabels = {$plugin.tx_powermail.settings.misc.htmlForLabels} + + # Show only values if they are filled (for all views and for mails) + showOnlyFilledValues = {$plugin.tx_powermail.settings.misc.showOnlyFilledValues} + + # Submit Powermail Forms with AJAX (browser will not reload complete page) + ajaxSubmit = {$plugin.tx_powermail.settings.misc.ajaxSubmit} + + # Keep third-party GET/POST variables on submit with addQueryString="1" in form + addQueryString = {$plugin.tx_powermail.settings.misc.addQueryString} + + # File upload settings + file { + folder = {$plugin.tx_powermail.settings.misc.uploadFolder} + size = {$plugin.tx_powermail.settings.misc.uploadSize} + extension = {$plugin.tx_powermail.settings.misc.uploadFileExtensions} + randomizeFileName = {$plugin.tx_powermail.settings.misc.randomizeFileName} + randomizePrependOriginalFileName = {$plugin.tx_powermail.settings.misc.randomizePrependOriginalFileName} + } + } + + # Don't touch this (this is just to let the extension know, that there is TypoScript included) + staticTemplate = 1 +} + +# ParseFunc Configuration for using FAL links in receiver and sender mail +lib.parseFunc_powermail < lib.parseFunc_RTE +lib.parseFunc_powermail.tags { + link.typolink.forceAbsoluteUrl = 1 + a.typolink.forceAbsoluteUrl = 1 +} diff --git a/Configuration/TypoScript/Main/Configuration/03_MailReceiver.typoscript b/Configuration/TypoScript/Main/Configuration/03_MailReceiver.typoscript new file mode 100644 index 000000000..af00ab370 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/03_MailReceiver.typoscript @@ -0,0 +1,106 @@ +################## +# All settings for mail to receiver +################## +plugin.tx_powermail.settings.setup { + receiver { + enable = {$plugin.tx_powermail.settings.receiver.enable} + + # Following settings are normally set via Flexform + email = + subject = + body = + + # add file attachments from upload fields + attachment = {$plugin.tx_powermail.settings.receiver.attachment} + + # html, plain, both + mailformat = {$plugin.tx_powermail.settings.receiver.mailformat} + + default { + senderName = TEXT + senderName.value = {$plugin.tx_powermail.settings.receiver.default.senderName} + + senderEmail = TEXT + senderEmail.value = {$plugin.tx_powermail.settings.receiver.default.senderEmail} + } + + # EXAMPLE: Predefine some receivers - selection in backend could be done via page TSConfig: + # tx_powermail.flexForm.predefinedReceivers.addFieldOptions.receivers1 = receiver list #1 + # or with a locallang variable: + # tx_powermail.flexForm.predefinedReceivers.addFieldOptions.receivers1 = LLL:fileadmin/locallang.xlf:key + predefinedReceiver { + # EXAMPLE: for hard coded receivers + # receivers1 { + # email = TEXT + # email.value = email1@domain.org, email2@domain.org + # } + + # EXAMPLE: for dynamic receiver - depending on value in field {receiver} + # receivers2 { + # email = CASE + # email { + # key.data = GP:tx_powermail_pi1|field|receiver + + # 1 = TEXT + # 1.value = email1@domain.org + + # 2 = TEXT + # 2.value = email2@domain.org + # } + # } + } + + # Normally you do not need to overwrite a flexform setting, but this allows you to use cObject functions + overwrite { + email = TEXT + email.value = {$plugin.tx_powermail.settings.receiver.overwrite.email} + + name = TEXT + name.value = {$plugin.tx_powermail.settings.receiver.overwrite.name} + + senderName = TEXT + senderName.value = {$plugin.tx_powermail.settings.receiver.overwrite.senderName} + + senderEmail = TEXT + senderEmail.value = {$plugin.tx_powermail.settings.receiver.overwrite.senderEmail} + + subject = TEXT + subject.value = {$plugin.tx_powermail.settings.receiver.overwrite.subject} + + # Add further CC Receivers (split them via comma) + cc = TEXT + cc.value = {$plugin.tx_powermail.settings.receiver.overwrite.cc} + + # Add further BCC Receivers (split them via comma) + bcc = TEXT + bcc.value = {$plugin.tx_powermail.settings.receiver.overwrite.bcc} + + # Add return path + returnPath = TEXT + returnPath.value = {$plugin.tx_powermail.settings.receiver.overwrite.returnPath} + + # Reply address (both required) + replyToEmail = TEXT + replyToEmail.value = {$plugin.tx_powermail.settings.receiver.overwrite.replyToEmail} + replyToName = TEXT + replyToName.value = {$plugin.tx_powermail.settings.receiver.overwrite.replyToName} + + # Set mail priority from 1 to 5 + priority = {$plugin.tx_powermail.settings.receiver.overwrite.priority} + } + + # EXAMPLE: Add additional attachments to the mail (separate each with comma) + # addAttachment = TEXT + # addAttachment.value = fileadmin/file.jpg + # addAttachment.wrap = |, + + # Mail Header "Sender:" see RFC 2822 - 3.6.2 Originator fields f.e. webserver@example.com, leave empty if you do not want to set a Sender-Header + senderHeader { + email = TEXT + email.value = {$plugin.tx_powermail.settings.receiver.senderHeader.email} + # optional: f.e. Webserver + name = TEXT + name.value = {$plugin.tx_powermail.settings.receiver.senderHeader.name} + } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/04_MailSender.typoscript b/Configuration/TypoScript/Main/Configuration/04_MailSender.typoscript new file mode 100644 index 000000000..f5b7a86f3 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/04_MailSender.typoscript @@ -0,0 +1,83 @@ +################## +# All settings for mail to user +################## +plugin.tx_powermail.settings.setup { + sender { + enable = {$plugin.tx_powermail.settings.sender.enable} + + # Following settings are normally set via Flexform + name = + email = + subject = + body = + + # add file attachments from upload fields + attachment = {$plugin.tx_powermail.settings.sender.attachment} + + # html, plain, both + mailformat = {$plugin.tx_powermail.settings.sender.mailformat} + + addDisclaimerLink = {$plugin.tx_powermail.settings.sender.addDisclaimerLink} + + default { + senderEmail = TEXT + senderEmail.value = {$plugin.tx_powermail.settings.sender.default.senderEmail} + + senderName = TEXT + senderName.value = {$plugin.tx_powermail.settings.sender.default.senderName} + } + + # Normally you do not need to overwrite a flexform settings, but this allows you to use cObject functions + overwrite { + email = TEXT + email.value = {$plugin.tx_powermail.settings.sender.overwrite.email} + + name = TEXT + name.value = {$plugin.tx_powermail.settings.sender.overwrite.name} + + senderName = TEXT + senderName.value = {$plugin.tx_powermail.settings.sender.overwrite.senderName} + + senderEmail = TEXT + senderEmail.value = {$plugin.tx_powermail.settings.sender.overwrite.senderEmail} + + subject = TEXT + subject.value = {$plugin.tx_powermail.settings.sender.overwrite.subject} + + # Add further CC Receivers (split them via comma) + cc = TEXT + cc.value = {$plugin.tx_powermail.settings.sender.overwrite.cc} + + # Add further BCC Receivers (split them via comma) + bcc = TEXT + bcc.value = {$plugin.tx_powermail.settings.sender.overwrite.bcc} + + # Add return path + returnPath = TEXT + returnPath.value = {$plugin.tx_powermail.settings.sender.overwrite.returnPath} + + # Reply address (both required) + replyToEmail = TEXT + replyToEmail.value = {$plugin.tx_powermail.settings.sender.overwrite.replyToEmail} + replyToName = TEXT + replyToName.value = {$plugin.tx_powermail.settings.sender.overwrite.replyToName} + + # Set mail priority from 1 to 5 + priority = {$plugin.tx_powermail.settings.sender.overwrite.priority} + } + + # EXAMPLE: Add additional attachments to the mail (separate each with comma) + # addAttachment = TEXT + # addAttachment.value = fileadmin/file.jpg + # addAttachment.wrap = |, + + # Mail Header "Sender:" see RFC 2822 - 3.6.2 Originator fields f.e. webserver@example.com, leave empty if you do not want to set a Sender-Header + senderHeader { + email = TEXT + email.value = {$plugin.tx_powermail.settings.sender.senderHeader.email} + # optional: f.e. Webserver + name = TEXT + name.value = {$plugin.tx_powermail.settings.sender.senderHeader.name} + } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/05_ThxPage.typoscript b/Configuration/TypoScript/Main/Configuration/05_ThxPage.typoscript new file mode 100644 index 000000000..8a4a2f742 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/05_ThxPage.typoscript @@ -0,0 +1,26 @@ +################## +# All settings for thx page +################## +plugin.tx_powermail.settings.setup { + thx { + # Following settings are normally set via Flexform + body = + redirect = + + overwrite { + # EXAMPLE: Overwrite redirect with TypoScript cObject + # Return a Number: Typolink to the pid + # Return a URL: Link to an intern or extern URL + # Return a File: Link to a file (within fileadmin folder) + # redirect = COA + # redirect { + # 10 = TEXT + # 10 { + # typolink.parameter = 2 + # typolink.returnLast = url + # typolink.additionalParams = &x=y + # } + # } + } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/06_Database.typoscript b/Configuration/TypoScript/Main/Configuration/06_Database.typoscript new file mode 100644 index 000000000..536d09772 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/06_Database.typoscript @@ -0,0 +1,12 @@ +################## +# All settings for database storage +################## +plugin.tx_powermail.settings.setup { + db { + # Enable mail storage + enable = {$plugin.tx_powermail.settings.db.enable} + + # Add new mails with hidden=1 + hidden = {$plugin.tx_powermail.settings.db.hidden} + } +} diff --git a/Configuration/TypoScript/Main/Configuration/07_DoubleOptin.typoscript b/Configuration/TypoScript/Main/Configuration/07_DoubleOptin.typoscript new file mode 100644 index 000000000..be5fdef42 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/07_DoubleOptin.typoscript @@ -0,0 +1,24 @@ +################## +# All settings for double optin mails +################## +plugin.tx_powermail.settings.setup { + optin { + subject = TEXT + subject.data = LLL:EXT:powermail/Resources/Private/Language/locallang.xlf:optin_subject + + overwrite { + # EXAMPLE: + # email = TEXT + # email.value = alexander.kellner@in2code.de + + # name = TEXT + # name.value = Receivers Name + + # senderName = TEXT + # senderName.value = Sender Name + + # senderEmail = TEXT + # senderEmail.value = sender@mail.com + } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/08_Disclaimer.typoscript b/Configuration/TypoScript/Main/Configuration/08_Disclaimer.typoscript new file mode 100644 index 000000000..fd9dfdc5b --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/08_Disclaimer.typoscript @@ -0,0 +1,9 @@ +################## +# All settings for disclaimer notification +################## +plugin.tx_powermail.settings.setup { + disclaimer { + subject = TEXT + subject.data = LLL:EXT:powermail/Resources/Private/Language/locallang.xlf:disclaimed_subject + } +} diff --git a/Configuration/TypoScript/Main/Configuration/09_Styles.typoscript b/Configuration/TypoScript/Main/Configuration/09_Styles.typoscript new file mode 100644 index 000000000..c03f6aa3f --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/09_Styles.typoscript @@ -0,0 +1,22 @@ +################## +# CSS classes for frameworks (add only if bootstrapClassesAndLayout is not added before) +################## +plugin.tx_powermail.settings.setup { + styles { + numberOfColumns = {$plugin.tx_powermail.settings.styles.framework.numberOfColumns} + + framework { + rowClasses = {$plugin.tx_powermail.settings.styles.framework.rowClasses} + formClasses = {$plugin.tx_powermail.settings.styles.framework.formClasses} + fieldAndLabelWrappingClasses = {$plugin.tx_powermail.settings.styles.framework.fieldAndLabelWrappingClasses} + fieldWrappingClasses = {$plugin.tx_powermail.settings.styles.framework.fieldWrappingClasses} + labelClasses = {$plugin.tx_powermail.settings.styles.framework.labelClasses} + fieldClasses = {$plugin.tx_powermail.settings.styles.framework.fieldClasses} + offsetClasses = {$plugin.tx_powermail.settings.styles.framework.offsetClasses} + radioClasses = {$plugin.tx_powermail.settings.styles.framework.radioClasses} + checkClasses = {$plugin.tx_powermail.settings.styles.framework.checkClasses} + submitClasses = {$plugin.tx_powermail.settings.styles.framework.submitClasses} + createClasses = {$plugin.tx_powermail.settings.styles.framework.createClasses} + } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/10_Validation.typoscript b/Configuration/TypoScript/Main/Configuration/10_Validation.typoscript new file mode 100644 index 000000000..c15c6a146 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/10_Validation.typoscript @@ -0,0 +1,60 @@ +plugin.tx_powermail.settings.setup { + validation { + # enable native HTML5 validation + native = {$plugin.tx_powermail.settings.validation.native} + + # enable clientside validation + client = {$plugin.tx_powermail.settings.validation.client} + + # enable serverside validation + server = {$plugin.tx_powermail.settings.validation.server} + + unique { + # EXAMPLE: Enable unique check for {email} + #email = 1 + + # EXAMPLE: Enable a max limit of 3 times for the same entry for {event} + #event = 3 + } + + ########################################################## + # EXAMPLE: CUSTOMVALIDATION + # + # E.g. Validation was extended with Page TSconfig + # tx_powermail.flexForm.validation.addFieldOptions.100 = New Validation + # + # Register your Class and Method with TypoScript Setup + # plugin.tx_powermail.settings.setup.validation.customValidation.100 = + # In2code\Powermailextended\Domain\Validator\ZipValidator + # + # Add method to your class + # validate100($value, $validationConfiguration) + # + # Define your Errormessage with TypoScript Setup + # plugin.tx_powermail._LOCAL_LANG.default.validationerror_validation.100 = Error happens! + # + # ########################################################## + customValidation { + # 100 = In2code\Powermailextended\Domain\Validator\ZipValidator + } + } + + # EXAMPLE: Add own validator classes that will be called before create action (if you want to validate user input with own PHP classes) + validators { + # 1 { + # Classname that should be called with method *Validator() + # class = Vendor\Ext\Domain\Model\DoSomethingValidator + + # optional: Add configuration for your PHP + # config { + # foo = bar + + # fooCObject = TEXT + # fooCObject.value = do something with this text + # } + + # optional: If file will not be loaded from autoloader, add path and it will be called with require_once + # require = fileadmin/powermail/validator/DoSomethingValidator.php + # } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/11_Captcha.typoscript b/Configuration/TypoScript/Main/Configuration/11_Captcha.typoscript new file mode 100644 index 000000000..5366d8211 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/11_Captcha.typoscript @@ -0,0 +1,22 @@ +################## +# Captcha Settings +################## +plugin.tx_powermail.settings.setup { + captcha { + # Select "default" (on board calculating captcha) or "captcha" (needs extension captcha) + use = default + + default { + image = {$plugin.tx_powermail.settings.captcha.image} + font = {$plugin.tx_powermail.settings.captcha.font} + textColor = {$plugin.tx_powermail.settings.captcha.textColor} + textSize = {$plugin.tx_powermail.settings.captcha.textSize} + textAngle = {$plugin.tx_powermail.settings.captcha.textAngle} + distanceHor = {$plugin.tx_powermail.settings.captcha.distanceHor} + distanceVer = {$plugin.tx_powermail.settings.captcha.distanceVer} + + # EXAMPLE: You can force a fix captcha - operator must be "+" (for testing only with calculating captcha) + # forceValue = 1+1 + } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/12_Spamshield.typoscript b/Configuration/TypoScript/Main/Configuration/12_Spamshield.typoscript new file mode 100644 index 000000000..8afaf0e14 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/12_Spamshield.typoscript @@ -0,0 +1,190 @@ +################## +# Spam Settings +################## +plugin.tx_powermail.settings.setup { + spamshield { + # enable or disable spam check + _enable = {$plugin.tx_powermail.settings.spamshield.enable} + + # EXAMPLE: disable complete spam check on individual conditions (overrules ._enable=1) + # _disable { + # 1 { + # Disable spamcheck if visitor is in IP-Range + # class = In2code\Powermail\Domain\Validator\SpamShield\Breaker\IpBreaker + # configuration { + # // Commaseparated list of IPs. Use * for wildcards in the IP-address + # ipWhitelist = 127.0.0.1,192.168.0.* + # } + # } + + # 2 { + # Disable spamcheck if any field contains a given value - like "powermailTestCase" + # class = In2code\Powermail\Domain\Validator\SpamShield\Breaker\ValueBreaker + # configuration { + # value = powermailTestCase + # } + # } + # } + + # Spam Factor Limit in % + factor = {$plugin.tx_powermail.settings.spamshield.factor} + + # Notification Email to Admin if spam recognized (empty disables email to admin) + email = {$plugin.tx_powermail.settings.spamshield.email} + + # Email address sending out spam mail. Set this if your mail transport limits allowed sender addresses + senderEmail = {$plugin.tx_powermail.settings.spamshield.senderEmail} + + # Subject for notification Email to Admin + emailSubject = {$plugin.tx_powermail.settings.spamshield.emailSubject} + + # Template for notification Email to Admin + emailTemplate = {$plugin.tx_powermail.settings.spamshield.emailTemplate} + + # Path to logfile + logfileLocation = {$plugin.tx_powermail.settings.spamshield.logfileLocation} + + # Template for logging entry + logTemplate = {$plugin.tx_powermail.settings.spamshield.logTemplate} + + methods { + # Honeypot check + 1 { + _enable = 1 + + # Spamcheck name + name = Honey Pot + + # Class + class = In2code\Powermail\Domain\Validator\SpamShield\HoneyPodMethod + + # if this check failes - add this indication value to indicator (0 disables this check completely) + indication = 5 + + # method configuration + configuration { + + } + } + + # Link check + 2 { + _enable = 1 + + # Spamcheck name + name = Link check + + # Class + class = In2code\Powermail\Domain\Validator\SpamShield\LinkMethod + + # if this check failes - add this indication value to indicator (0 disables this check completely) + indication = 3 + + # method configuration + configuration { + # number of allowed links + linkLimit = 2 + } + } + + # Name check + 3 { + _enable = 1 + + # Spamcheck name + name = Name check + + # Class + class = In2code\Powermail\Domain\Validator\SpamShield\NameMethod + + # if this check failes - add this indication value to indicator (0 disables this check completely) + indication = 3 + + # method configuration + configuration { + + } + } + + # Session check: Enabling session check means to store a cookie on form load. If forms are submitted powermail checks for that cookie again. If this check is disabled, powermail will not set a cookie by default. + 4 { + _enable = 0 + + # Spamcheck name + name = Session check + + # Class + class = In2code\Powermail\Domain\Validator\SpamShield\SessionMethod + + # if this check failes - add this indication value to indicator (0 disables this check completely) + indication = 5 + + # method configuration + configuration { + + } + } + + # Unique check + 5 { + _enable = 1 + + # Spamcheck name + name = Unique check + + # Class + class = In2code\Powermail\Domain\Validator\SpamShield\UniqueMethod + + # if this check failes - add this indication value to indicator (0 disables this check completely) + indication = 2 + + # method configuration + configuration { + + } + } + + # Value blacklist check + 6 { + _enable = 1 + + # Spamcheck name + name = Value blacklist check + + # Class + class = In2code\Powermail\Domain\Validator\SpamShield\ValueBlacklistMethod + + # if this check failes - add this indication value to indicator (0 disables this check completely) + indication = 7 + + # method configuration + configuration { + # Blacklisted values (could also get read from a file - simply with FLUIDTEMPLATE) + values = TEXT + values.value = viagra,sex,porn,p0rn + } + } + + # IP blacklist check + 7 { + _enable = 1 + + # Spamcheck name + name = IP blacklist check + + # Class + class = In2code\Powermail\Domain\Validator\SpamShield\IpBlacklistMethod + + # if this check failes - add this indication value to indicator (0 disables this check completely) + indication = 7 + + # method configuration + configuration { + # Blacklisted values (could also get read from a file - simply with FLUIDTEMPLATE) + values = TEXT + values.value = 123.132.125.123,123.132.125.124 + } + } + } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/20_Prefill.typoscript b/Configuration/TypoScript/Main/Configuration/20_Prefill.typoscript new file mode 100644 index 000000000..d25671ef5 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/20_Prefill.typoscript @@ -0,0 +1,25 @@ +################## +# Prefill fields with their marker - e.g. {firstname} (Fields available for prefill: input, textarea, select, select multi, radio, checkbox) +################## +plugin.tx_powermail.settings.setup { + prefill { + # example: fill with string + # firstname = Alex + + # example: fill with TypoScript + # email = TEXT + # email.value = alex@in2code.de + # email.wrap = | + + # example: fill checkboxes or multiselect with more values + # category.0 = TEXT + # category.0.value = IT + # category.1 = TEXT + # category.1.value = Real Estate + + # example: fill with value from Field Record + # available: uid, title, type, settings, css, feuserValue, mandatory, marker, pid, prefillValue, senderEmail, senderName, sorting, validation + # comment = TEXT + # comment.field = type + } +} diff --git a/Configuration/TypoScript/Main/Configuration/21_ExcludeFromPowermailAllMarker.typoscript b/Configuration/TypoScript/Main/Configuration/21_ExcludeFromPowermailAllMarker.typoscript new file mode 100644 index 000000000..f6691264d --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/21_ExcludeFromPowermailAllMarker.typoscript @@ -0,0 +1,51 @@ +################## +# Exclude values from {powermail_all} by markername or fieldtype +################## +plugin.tx_powermail.settings.setup { + excludeFromPowermailAllMarker { + # On Confirmation Page (if activated) + confirmationPage { + # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) + excludeFromMarkerNames = + + # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) + excludeFromFieldTypes = + } + + # On Submitpage + submitPage { + # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) + excludeFromMarkerNames = + + # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) + excludeFromFieldTypes = + } + + # In Mail to receiver + receiverMail { + # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) + excludeFromMarkerNames = + + # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) + excludeFromFieldTypes = + } + + # In Mail to sender (if activated) + senderMail { + # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) + excludeFromMarkerNames = + + # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) + excludeFromFieldTypes = + } + + # In double-opt-in Mail to sender (if activated) + optinMail { + # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) + excludeFromMarkerNames = + + # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) + excludeFromFieldTypes = + } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/22_ManipulateVariablesInPowermailAllMarker.typoscript b/Configuration/TypoScript/Main/Configuration/22_ManipulateVariablesInPowermailAllMarker.typoscript new file mode 100644 index 000000000..b92559778 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/22_ManipulateVariablesInPowermailAllMarker.typoscript @@ -0,0 +1,81 @@ +################## +# Manipulate values from {powermail_all} by markername +################## +plugin.tx_powermail.settings.setup { + manipulateVariablesInPowermailAllMarker { + # On Confirmation Page (if activated) + confirmationPage { + # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid + # markerName = CASE + # markerName { + # key.field = value + # + # 1 = TEXT + # 1.value = red + # + # default = TEXT + # default.value = blue + # } + } + + # On Submitpage + submitPage { + # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid + # markerName = CASE + # markerName { + # key.field = value + # + # 1 = TEXT + # 1.value = red + # + # default = TEXT + # default.value = blue + # } + } + + # In Mail to receiver + receiverMail { + # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid + # markerName = CASE + # markerName { + # key.field = value + # + # 1 = TEXT + # 1.value = red + # + # default = TEXT + # default.value = blue + # } + } + + # In Mail to sender (if activated) + senderMail { + # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid + # markerName = CASE + # markerName { + # key.field = value + # + # 1 = TEXT + # 1.value = red + # + # default = TEXT + # default.value = blue + # } + } + + # In double-opt-in Mail to sender (if activated) + optinMail { + # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid + # markerName = CASE + # markerName { + # key.field = value + # + # 1 = TEXT + # 1.value = red + # + # default = TEXT + # default.value = blue + # } + } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/23_SaveSession.typoscript b/Configuration/TypoScript/Main/Configuration/23_SaveSession.typoscript new file mode 100644 index 000000000..06dc0900a --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/23_SaveSession.typoscript @@ -0,0 +1,15 @@ +################## +# Save submitted values in a session to prefill forms for further visits. Define each markername for all forms. +################## +plugin.tx_powermail.settings.setup { + saveSession { + # EXAMPLE: Method "temporary" means as long as the browser is open. "permanently" could be used together with a frontend-user session. If method is empty, saveSession is deactivated. + # _method = temporary + # + # firstname = TEXT + # firstname.field = firstname + # + # lastname = TEXT + # lastname.field = lastname + } +} diff --git a/Configuration/TypoScript/Main/Configuration/24_Marketing.typoscript b/Configuration/TypoScript/Main/Configuration/24_Marketing.typoscript new file mode 100644 index 000000000..519f201e1 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/24_Marketing.typoscript @@ -0,0 +1,58 @@ +################## +# All marketing related settings +################## +plugin.tx_powermail.settings.setup { + marketing { + + # Use Google Adwords Conversion JavaScript on form submit + googleAdwords { + _enable = {$plugin.tx_powermail.settings.marketing.enable} + google_conversion_id = {$plugin.tx_powermail.settings.marketing.google_conversion_id} + google_conversion_label = {$plugin.tx_powermail.settings.marketing.google_conversion_label} + google_conversion_language = {$plugin.tx_powermail.settings.marketing.google_conversion_language} + google_conversion_format = 3 + } + + # Send Form values to a third party software (like a CRM - e.g. salesforce or eloqua) + sendPost { + # Activate sendPost (0/1) + _enable = TEXT + _enable.value = 0 + + # Target URL for POST values (like http://www.target.com/target.php) + targetUrl = http://eloqua.com/e/f.aspx + + # Basic Auth Protection - leave empty if Target is not protected + username = + password = + + # build your post values like ¶m1=value1¶m2=value2 + values = COA + values { + 10 = TEXT + 10 { + # value from field {firstname} + field = vorname + wrap = &firstname=| + } + + 20 = TEXT + 20 { + # value from field {e_mail} + field = e_mail + wrap = &email=| + } + + 30 = TEXT + 30 { + # value from field {comment} + field = comment + wrap = &text=| + } + } + + # activate debug - log all configuration from curl settings + debug = 0 + } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/30_Finisher.typoscript b/Configuration/TypoScript/Main/Configuration/30_Finisher.typoscript new file mode 100644 index 000000000..3884bff4c --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/30_Finisher.typoscript @@ -0,0 +1,28 @@ +################## +# Finisher classes that will be called after submit +################## +plugin.tx_powermail.settings.setup { + finishers { + # Powermail finishers + 10.class = In2code\Powermail\Finisher\SaveToAnyTableFinisher + 20.class = In2code\Powermail\Finisher\SendParametersFinisher + 100.class = In2code\Powermail\Finisher\RedirectFinisher + + # EXAMPLE: Add your own finishers classes (e.g. if you want to do something with form values by your own: Save into tables, call an API, make your own redirect etc...) + # 1 { + # Classname that should be called with method *Finisher() + # class = Vendor\Ext\Finisher\DoSomethingFinisher + + # optional: Add configuration for your PHP + # config { + # foo = bar + + # fooCObject = TEXT + # fooCObject.value = do something with this text + # } + + # optional: If file will not be loaded from autoloader, add path and it will be called with require_once + # require = fileadmin/powermail/finisher/DoSomethingFinisher.php + # } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/31_DataProcessors.typoscript b/Configuration/TypoScript/Main/Configuration/31_DataProcessors.typoscript new file mode 100644 index 000000000..16f8a7a19 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/31_DataProcessors.typoscript @@ -0,0 +1,27 @@ +################## +# DataProcessor classes that will be called before the mail object will be persisted and used in mails +################## +plugin.tx_powermail.settings.setup { + dataProcessors { + # Powermail data processors + 10.class = In2code\Powermail\DataProcessor\UploadDataProcessor + 20.class = In2code\Powermail\DataProcessor\SessionDataProcessor + + # EXAMPLE Add your own data processor classes (e.g. if you want to do something with form values by your own before they are used in powermail to persist or in mails) + # 1 { + # Classname that should be called with method *Finisher() + # class = Vendor\Ext\Finisher\DoSomethingFinisher + + # optional: Add configuration for your PHP + # config { + # foo = bar + + # fooCObject = TEXT + # fooCObject.value = do something with this text + # } + + # optional: If file will not be loaded from autoloader, add path and it will be called with require_once + # require = fileadmin/powermail/finisher/DoSomethingFinisher.php + # } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/32_DatabaseEntry.typoscript b/Configuration/TypoScript/Main/Configuration/32_DatabaseEntry.typoscript new file mode 100644 index 000000000..ff26211b5 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/32_DatabaseEntry.typoscript @@ -0,0 +1,84 @@ +################## +# EXAMPLE for adding values to any table (e.g. tt_address) +################## +plugin.tx_powermail.settings.setup { + # Save values to any table (see following example) + dbEntry { + 1 { + # EXAMPLE: Enable or disable db entry for table tt_address + # _enable = TEXT + # _enable.value = 1 + + # Set tableName to "tt_address" + # _table = TEXT + # _table.value = tt_address + + # Write only if any field is not yet filled with current value (e.g. test if an email is already in database) + # default: always add new records (don't care about existing values) + # update: update record if there is an existing entry (e.g. if email is already there) + # none: no entry if field is filled (do nothing if record already exists) + # _ifUnique.email = update + + # optional: add additional where clause (only in mode "update") for search if a record still exists. You could use a plain string (see example below) or a cObject if needed + # _ifUniqueWhereClause = AND pid = 123 + + # Fill tt_address.email with a static value => mail@mail.com + # email = TEXT + # email.value = mail@mail.com + + # Fill tt_address.pid with the current pid (e.g. 12) + # pid = TEXT + # pid.data = TSFE:id + + # Fill tt_address.tstamp with the current time as timestamp (like 123456789) + # tstamp = TEXT + # tstamp.data = date:U + + # Fill tt_address.address with the current formatted time (like "Date: 20.01.2013") + # address = TEXT + # address.data = date:U + # address.strftime = Date: %d.%m.%Y + + # Fill tt_address.name with the value from powermail {firstname} + # name = TEXT + # name.field = firstname + + # Fill tt_address.last_name with the value from powermail {lastname} + # last_name = TEXT + # last_name.field = lastname + + # Fill tt_address.company with the value from powermail {company} + # company = TEXT + # company.field = company + + # Fill tt_address.position with the uid of the mail record + # position = TEXT + # position.field = uid + } + + + ############################################################## + ### EXAMPLE for building a relation to tt_address_group ### + ### over the MM table tt_address_group_mm ### + ### Add relation to an existing address group with uid 123 ### + ############################################################## + + 2 { + # EXAMPLE: Enable or disable db entry for table tt_address_group_mm + # _enable = TEXT + # _enable.value = 1 + + # Set tableName to "tt_address_group_mm" + # _table = TEXT + # _table.value = tt_address_group_mm + + # Fill tt_address_group_mm.uid_local with uid of tt_address record from above configuration 1. (usage .field=uid_[key]) + # uid_local = TEXT + # uid_local.field = uid_1 + + # Fill new record of table "tt_address_group_mm" with field "uid_foreign" with uid 123 + # uid_foreign = TEXT + # uid_foreign.value = 123 + } + } +} diff --git a/Configuration/TypoScript/Main/Configuration/33_Debug.typoscript b/Configuration/TypoScript/Main/Configuration/33_Debug.typoscript new file mode 100644 index 000000000..a7918ba24 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/33_Debug.typoscript @@ -0,0 +1,21 @@ +################## +# Switch on or off Debug mode +################## +plugin.tx_powermail.settings.setup { + debug { + # All views: Show Settings from TypoScript, Flexform and Extension Manager + settings = {$plugin.tx_powermail.settings.misc.debugSettings} + + # Create view: Show submitted variables + variables = {$plugin.tx_powermail.settings.misc.debugVariables} + + # Create view: Show complete mail settings + mail = {$plugin.tx_powermail.settings.misc.debugMail} + + # Create view: Show saveToTable array + saveToTable = {$plugin.tx_powermail.settings.misc.debugSaveToTable} + + # Create view: Show spamtest results + spamshield = {$plugin.tx_powermail.settings.misc.debugSpamshield} + } +} diff --git a/Configuration/TypoScript/Main/Configuration/40_Includes.typoscript b/Configuration/TypoScript/Main/Configuration/40_Includes.typoscript new file mode 100644 index 000000000..f5eb90e67 --- /dev/null +++ b/Configuration/TypoScript/Main/Configuration/40_Includes.typoscript @@ -0,0 +1,6 @@ +page { + includeJSFooter { + powermailForm = EXT:powermail/Resources/Public/JavaScript/Powermail/Form.min.js + powermailForm.defer = 1 + } +} diff --git a/Configuration/TypoScript/Main/constants.typoscript b/Configuration/TypoScript/Main/constants.typoscript index a468aa196..da3636dfb 100644 --- a/Configuration/TypoScript/Main/constants.typoscript +++ b/Configuration/TypoScript/Main/constants.typoscript @@ -1,6 +1,5 @@ plugin.tx_powermail { - view { # cat=powermail_main/file; type=string; label= Path to template root (FE) templateRootPath = EXT:powermail/Resources/Private/Templates/ @@ -14,7 +13,6 @@ plugin.tx_powermail { settings { - main { # cat=powermail_additional//0010; type=int+; label= Storage PID: Save mails in a defined Page (normally set via Flexform) pid = @@ -223,9 +221,6 @@ plugin.tx_powermail { # cat=powermail_additional//0840; type=boolean; label= Prepend original file name: Prepend original file name to randomized file name if randomizeFileName is enabled randomizePrependOriginalFileName = 0 - # cat=powermail_additional//0845; type=boolean; label= Force JavaScript Datepicker: Per default html5 Date or Datetime format is used. If you don't want to use it and want to have the same datepicker all over all browsers, you can enable this feature - forceJavaScriptDatePicker = 0 - # cat=powermail_additional//0850; type=boolean; label= Debug Settings: Show all Settings from TypoScript, Flexform and Global Config in Devlog debugSettings = 0 @@ -291,17 +286,6 @@ plugin.tx_powermail { distanceVer = 30,45 } - javascript { - # cat=powermail_main//1000; type=boolean; label= Include jQuery From Google: Add jQuery JavaScript (will be loaded from ajax.googleapis.com) - addJQueryFromGoogle = 0 - - # cat=powermail_additional//1010; type=boolean; label= Include additional JavaScript: Add additional JavaScript and CSS Files (form validation, datepicker, etc...) - addAdditionalJavaScript = 1 - - # cat=powermail_additional//1020; type=text; label= jQuery Source: Change jQuery Source - per default it will be loaded from googleapis.com - powermailJQuery = //ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js - } - # CSS classes for frameworks (add only if bootstrapClassesAndLayout is not added before) styles { framework { diff --git a/Configuration/TypoScript/Main/setup.typoscript b/Configuration/TypoScript/Main/setup.typoscript index bd231f273..3d2fd1386 100644 --- a/Configuration/TypoScript/Main/setup.typoscript +++ b/Configuration/TypoScript/Main/setup.typoscript @@ -1,1009 +1 @@ -################## -# Frontend Plugin -################## -plugin.tx_powermail { - view { - templateRootPaths { - 0 = EXT:powermail/Resources/Private/Templates/ - 1 = {$plugin.tx_powermail.view.templateRootPath} - } - - partialRootPaths { - 0 = EXT:powermail/Resources/Private/Partials/ - 1 = {$plugin.tx_powermail.view.partialRootPath} - } - - layoutRootPaths { - 0 = EXT:powermail/Resources/Private/Layouts/ - 1 = {$plugin.tx_powermail.view.layoutRootPath} - } - } - - # Modify localization of labels - # _LOCAL_LANG { - # default { - # confirmation_message = Are these values correct? - # } - # de { - # confirmation_message = Sind diese Eingaben korrekt? - # } - # } - - # Main settings - settings { - setup { - - main { - pid = {$plugin.tx_powermail.settings.main.pid} - form = {$plugin.tx_powermail.settings.main.form} - confirmation = {$plugin.tx_powermail.settings.main.confirmation} - optin = {$plugin.tx_powermail.settings.main.optin} - moresteps = {$plugin.tx_powermail.settings.main.moresteps} - } - - validation { - # enable native HTML5 validation - native = {$plugin.tx_powermail.settings.validation.native} - - # enable clientside validation - client = {$plugin.tx_powermail.settings.validation.client} - - # enable serverside validation - server = {$plugin.tx_powermail.settings.validation.server} - - unique { - # Enable unique check for {email} - #email = 1 - - # Enable a max limit of 3 times for the same entry for {event} - #event = 3 - } - - ########################################################## - # CUSTOMVALIDATION EXAMPLE - # - # E.g. Validation was extended with Page TSconfig - # tx_powermail.flexForm.validation.addFieldOptions.100 = New Validation - # - # Register your Class and Method with TypoScript Setup - # plugin.tx_powermail.settings.setup.validation.customValidation.100 = - # In2code\Powermailextended\Domain\Validator\ZipValidator - # - # Add method to your class - # validate100($value, $validationConfiguration) - # - # Define your Errormessage with TypoScript Setup - # plugin.tx_powermail._LOCAL_LANG.default.validationerror_validation.100 = Error happens! - # - # ########################################################## - customValidation { - # 100 = In2code\Powermailextended\Domain\Validator\ZipValidator - } - } - - # All settings for mail to receiver - receiver { - enable = {$plugin.tx_powermail.settings.receiver.enable} - - # Following settings are normally set via Flexform - email = - subject = - body = - - # add file attachments from upload fields - attachment = {$plugin.tx_powermail.settings.receiver.attachment} - - # html, plain, both - mailformat = {$plugin.tx_powermail.settings.receiver.mailformat} - - default { - senderName = TEXT - senderName.value = {$plugin.tx_powermail.settings.receiver.default.senderName} - - senderEmail = TEXT - senderEmail.value = {$plugin.tx_powermail.settings.receiver.default.senderEmail} - } - - # Predefine some receivers - selection in backend could be done via page TSConfig: - # tx_powermail.flexForm.predefinedReceivers.addFieldOptions.receivers1 = receiver list #1 - # or with a locallang variable: - # tx_powermail.flexForm.predefinedReceivers.addFieldOptions.receivers1 = LLL:fileadmin/locallang.xlf:key - predefinedReceiver { - # example for hard coded receivers - # receivers1 { - # email = TEXT - # email.value = email1@domain.org, email2@domain.org - # } - - # example for dynamic receiver - depending on value in field {receiver} - # receivers2 { - # email = CASE - # email { - # key.data = GP:tx_powermail_pi1|field|receiver - - # 1 = TEXT - # 1.value = email1@domain.org - - # 2 = TEXT - # 2.value = email2@domain.org - # } - # } - } - - # Normally you do not need to overwrite a flexform setting, but this allows you to use cObject functions - overwrite { - email = TEXT - email.value = {$plugin.tx_powermail.settings.receiver.overwrite.email} - - name = TEXT - name.value = {$plugin.tx_powermail.settings.receiver.overwrite.name} - - senderName = TEXT - senderName.value = {$plugin.tx_powermail.settings.receiver.overwrite.senderName} - - senderEmail = TEXT - senderEmail.value = {$plugin.tx_powermail.settings.receiver.overwrite.senderEmail} - - subject = TEXT - subject.value = {$plugin.tx_powermail.settings.receiver.overwrite.subject} - - # Add further CC Receivers (split them via comma) - cc = TEXT - cc.value = {$plugin.tx_powermail.settings.receiver.overwrite.cc} - - # Add further BCC Receivers (split them via comma) - bcc = TEXT - bcc.value = {$plugin.tx_powermail.settings.receiver.overwrite.bcc} - - # Add return path - returnPath = TEXT - returnPath.value = {$plugin.tx_powermail.settings.receiver.overwrite.returnPath} - - # Reply address (both required) - replyToEmail = TEXT - replyToEmail.value = {$plugin.tx_powermail.settings.receiver.overwrite.replyToEmail} - replyToName = TEXT - replyToName.value = {$plugin.tx_powermail.settings.receiver.overwrite.replyToName} - - # Set mail priority from 1 to 5 - priority = {$plugin.tx_powermail.settings.receiver.overwrite.priority} - } - - # Add additional attachments to the mail (separate each with comma) - # addAttachment = TEXT - # addAttachment.value = fileadmin/file.jpg - # addAttachment.wrap = |, - - # Mail Header "Sender:" see RFC 2822 - 3.6.2 Originator fields f.e. webserver@example.com, leave empty if you do not want to set a Sender-Header - senderHeader { - email = TEXT - email.value = {$plugin.tx_powermail.settings.receiver.senderHeader.email} - # optional: f.e. Webserver - name = TEXT - name.value = {$plugin.tx_powermail.settings.receiver.senderHeader.name} - } - } - - # All settings for mail to user - sender { - enable = {$plugin.tx_powermail.settings.sender.enable} - - # Following settings are normally set via Flexform - name = - email = - subject = - body = - - # add file attachments from upload fields - attachment = {$plugin.tx_powermail.settings.sender.attachment} - - # html, plain, both - mailformat = {$plugin.tx_powermail.settings.sender.mailformat} - - addDisclaimerLink = {$plugin.tx_powermail.settings.sender.addDisclaimerLink} - - default { - senderEmail = TEXT - senderEmail.value = {$plugin.tx_powermail.settings.sender.default.senderEmail} - - senderName = TEXT - senderName.value = {$plugin.tx_powermail.settings.sender.default.senderName} - } - - # Normally you do not need to overwrite a flexform settings, but this allows you to use cObject functions - overwrite { - email = TEXT - email.value = {$plugin.tx_powermail.settings.sender.overwrite.email} - - name = TEXT - name.value = {$plugin.tx_powermail.settings.sender.overwrite.name} - - senderName = TEXT - senderName.value = {$plugin.tx_powermail.settings.sender.overwrite.senderName} - - senderEmail = TEXT - senderEmail.value = {$plugin.tx_powermail.settings.sender.overwrite.senderEmail} - - subject = TEXT - subject.value = {$plugin.tx_powermail.settings.sender.overwrite.subject} - - # Add further CC Receivers (split them via comma) - cc = TEXT - cc.value = {$plugin.tx_powermail.settings.sender.overwrite.cc} - - # Add further BCC Receivers (split them via comma) - bcc = TEXT - bcc.value = {$plugin.tx_powermail.settings.sender.overwrite.bcc} - - # Add return path - returnPath = TEXT - returnPath.value = {$plugin.tx_powermail.settings.sender.overwrite.returnPath} - - # Reply address (both required) - replyToEmail = TEXT - replyToEmail.value = {$plugin.tx_powermail.settings.sender.overwrite.replyToEmail} - replyToName = TEXT - replyToName.value = {$plugin.tx_powermail.settings.sender.overwrite.replyToName} - - # Set mail priority from 1 to 5 - priority = {$plugin.tx_powermail.settings.sender.overwrite.priority} - } - - # Add additional attachments to the mail (separate each with comma) - # addAttachment = TEXT - # addAttachment.value = fileadmin/file.jpg - # addAttachment.wrap = |, - - # Mail Header "Sender:" see RFC 2822 - 3.6.2 Originator fields f.e. webserver@example.com, leave empty if you do not want to set a Sender-Header - senderHeader { - email = TEXT - email.value = {$plugin.tx_powermail.settings.sender.senderHeader.email} - # optional: f.e. Webserver - name = TEXT - name.value = {$plugin.tx_powermail.settings.sender.senderHeader.name} - } - } - - thx { - # Following settings are normally set via Flexform - body = - redirect = - - overwrite { - # Overwrite redirect with TypoScript cObject - # Return a Number: Typolink to the pid - # Return a URL: Link to an intern or extern URL - # Return a File: Link to a file (within fileadmin folder) - # redirect = COA - # redirect { - # 10 = TEXT - # 10 { - # typolink.parameter = 2 - # typolink.returnLast = url - # typolink.additionalParams = &x=y - # } - # } - } - } - - db { - # Enable mail storage - enable = {$plugin.tx_powermail.settings.db.enable} - - # Add new mails with hidden=1 - hidden = {$plugin.tx_powermail.settings.db.hidden} - } - - optin { - subject = TEXT - subject.data = LLL:EXT:powermail/Resources/Private/Language/locallang.xlf:optin_subject - - overwrite { - # email = TEXT - # email.value = alexander.kellner@in2code.de - - # name = TEXT - # name.value = Receivers Name - - # senderName = TEXT - # senderName.value = Sender Name - - # senderEmail = TEXT - # senderEmail.value = sender@mail.com - } - } - - disclaimer { - subject = TEXT - subject.data = LLL:EXT:powermail/Resources/Private/Language/locallang.xlf:disclaimed_subject - } - - - # Captcha Settings - captcha { - # Select "default" (on board calculating captcha) or "captcha" (needs extension captcha) - use = default - - default { - image = {$plugin.tx_powermail.settings.captcha.image} - font = {$plugin.tx_powermail.settings.captcha.font} - textColor = {$plugin.tx_powermail.settings.captcha.textColor} - textSize = {$plugin.tx_powermail.settings.captcha.textSize} - textAngle = {$plugin.tx_powermail.settings.captcha.textAngle} - distanceHor = {$plugin.tx_powermail.settings.captcha.distanceHor} - distanceVer = {$plugin.tx_powermail.settings.captcha.distanceVer} - - # You can force a fix captcha - operator must be "+" (for testing only with calculating captcha) - # forceValue = 1+1 - } - } - - - # Spam Settings - spamshield { - # enable or disable spam check - _enable = {$plugin.tx_powermail.settings.spamshield.enable} - - # disable complete spam check on individual conditions (overrules ._enable=1) - # _disable { - # 1 { - # Disable spamcheck if visitor is in IP-Range - # class = In2code\Powermail\Domain\Validator\SpamShield\Breaker\IpBreaker - # configuration { - # // Commaseparated list of IPs. Use * for wildcards in the IP-address - # ipWhitelist = 127.0.0.1,192.168.0.* - # } - # } - - # 2 { - # Disable spamcheck if any field contains a given value - like "powermailTestCase" - # class = In2code\Powermail\Domain\Validator\SpamShield\Breaker\ValueBreaker - # configuration { - # value = powermailTestCase - # } - # } - # } - - # Spam Factor Limit in % - factor = {$plugin.tx_powermail.settings.spamshield.factor} - - # Notification Email to Admin if spam recognized (empty disables email to admin) - email = {$plugin.tx_powermail.settings.spamshield.email} - - # Email address sending out spam mail. Set this if your mail transport limits allowed sender addresses - senderEmail = {$plugin.tx_powermail.settings.spamshield.senderEmail} - - # Subject for notification Email to Admin - emailSubject = {$plugin.tx_powermail.settings.spamshield.emailSubject} - - # Template for notification Email to Admin - emailTemplate = {$plugin.tx_powermail.settings.spamshield.emailTemplate} - - # Path to logfile - logfileLocation = {$plugin.tx_powermail.settings.spamshield.logfileLocation} - - # Template for logging entry - logTemplate = {$plugin.tx_powermail.settings.spamshield.logTemplate} - - methods { - # Honeypot check - 1 { - _enable = 1 - - # Spamcheck name - name = Honey Pot - - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\HoneyPodMethod - - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 5 - - # method configuration - configuration { - - } - } - - # Link check - 2 { - _enable = 1 - - # Spamcheck name - name = Link check - - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\LinkMethod - - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 3 - - # method configuration - configuration { - # number of allowed links - linkLimit = 2 - } - } - - # Name check - 3 { - _enable = 1 - - # Spamcheck name - name = Name check - - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\NameMethod - - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 3 - - # method configuration - configuration { - - } - } - - # Session check: Enabling session check means to store a cookie on form load. If forms are submitted powermail checks for that cookie again. If this check is disabled, powermail will not set a cookie by default. - 4 { - _enable = 0 - - # Spamcheck name - name = Session check - - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\SessionMethod - - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 5 - - # method configuration - configuration { - - } - } - - # Unique check - 5 { - _enable = 1 - - # Spamcheck name - name = Unique check - - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\UniqueMethod - - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 2 - - # method configuration - configuration { - - } - } - - # Value blacklist check - 6 { - _enable = 1 - - # Spamcheck name - name = Value blacklist check - - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\ValueBlacklistMethod - - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 7 - - # method configuration - configuration { - # Blacklisted values (could also get read from a file - simply with FLUIDTEMPLATE) - values = TEXT - values.value = viagra,sex,porn,p0rn - } - } - - # IP blacklist check - 7 { - _enable = 1 - - # Spamcheck name - name = IP blacklist check - - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\IpBlacklistMethod - - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 7 - - # method configuration - configuration { - # Blacklisted values (could also get read from a file - simply with FLUIDTEMPLATE) - values = TEXT - values.value = 123.132.125.123,123.132.125.124 - } - } - } - } - - - # Misc Settings - misc { - # HTML Output for type HMTL fields - htmlForHtmlFields = {$plugin.tx_powermail.settings.misc.htmlForHtmlFields} - - # HTML for labels - htmlForLabels = {$plugin.tx_powermail.settings.misc.htmlForLabels} - - # Show only values if they are filled (for all views and for mails) - showOnlyFilledValues = {$plugin.tx_powermail.settings.misc.showOnlyFilledValues} - - # Submit Powermail Forms with AJAX (browser will not reload complete page) - ajaxSubmit = {$plugin.tx_powermail.settings.misc.ajaxSubmit} - - # Keep third-party GET/POST variables on submit with addQueryString="1" in form - addQueryString = {$plugin.tx_powermail.settings.misc.addQueryString} - - # File upload settings - file { - folder = {$plugin.tx_powermail.settings.misc.uploadFolder} - size = {$plugin.tx_powermail.settings.misc.uploadSize} - extension = {$plugin.tx_powermail.settings.misc.uploadFileExtensions} - randomizeFileName = {$plugin.tx_powermail.settings.misc.randomizeFileName} - randomizePrependOriginalFileName = {$plugin.tx_powermail.settings.misc.randomizePrependOriginalFileName} - } - - datepicker { - # Per default html5 Date or Datetime format is used. If you don't want to use it and want to have the same datepicker all over all browsers, you can enable this feature - forceJavaScriptDatePicker = {$plugin.tx_powermail.settings.misc.forceJavaScriptDatePicker} - } - } - - - # Prefill fields with their marker - e.g. {firstname} (Fields available for prefill: input, textarea, select, select multi, radio, checkbox) - prefill { - # example: fill with string - # firstname = Alex - - # example: fill with TypoScript - # email = TEXT - # email.value = alex@in2code.de - # email.wrap = | - - # example: fill checkboxes or multiselect with more values - # category.0 = TEXT - # category.0.value = IT - # category.1 = TEXT - # category.1.value = Real Estate - - # example: fill with value from Field Record - # available: uid, title, type, settings, css, feuserValue, mandatory, marker, pid, prefillValue, senderEmail, senderName, sorting, validation - # comment = TEXT - # comment.field = type - } - - - # Exclude values from {powermail_all} by markername or fieldtype - excludeFromPowermailAllMarker { - # On Confirmation Page (if activated) - confirmationPage { - # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) - excludeFromMarkerNames = - - # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) - excludeFromFieldTypes = - } - - # On Submitpage - submitPage { - # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) - excludeFromMarkerNames = - - # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) - excludeFromFieldTypes = - } - - # In Mail to receiver - receiverMail { - # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) - excludeFromMarkerNames = - - # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) - excludeFromFieldTypes = - } - - # In Mail to sender (if activated) - senderMail { - # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) - excludeFromMarkerNames = - - # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) - excludeFromFieldTypes = - } - - # In double-opt-in Mail to sender (if activated) - optinMail { - # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) - excludeFromMarkerNames = - - # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) - excludeFromFieldTypes = - } - } - - - # Manipulate values from {powermail_all} by markername - manipulateVariablesInPowermailAllMarker { - # On Confirmation Page (if activated) - confirmationPage { - # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid - # markerName = CASE - # markerName { - # key.field = value - # - # 1 = TEXT - # 1.value = red - # - # default = TEXT - # default.value = blue - # } - } - - # On Submitpage - submitPage { - # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid - # markerName = CASE - # markerName { - # key.field = value - # - # 1 = TEXT - # 1.value = red - # - # default = TEXT - # default.value = blue - # } - } - - # In Mail to receiver - receiverMail { - # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid - # markerName = CASE - # markerName { - # key.field = value - # - # 1 = TEXT - # 1.value = red - # - # default = TEXT - # default.value = blue - # } - } - - # In Mail to sender (if activated) - senderMail { - # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid - # markerName = CASE - # markerName { - # key.field = value - # - # 1 = TEXT - # 1.value = red - # - # default = TEXT - # default.value = blue - # } - } - - # In double-opt-in Mail to sender (if activated) - optinMail { - # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid - # markerName = CASE - # markerName { - # key.field = value - # - # 1 = TEXT - # 1.value = red - # - # default = TEXT - # default.value = blue - # } - } - } - - - # Save submitted values in a session to prefill forms for further visits. Define each markername for all forms. - saveSession { - # Method "temporary" means as long as the browser is open. "permanently" could be used together with a frontend-user session. If method is empty, saveSession is deactivated. - # _method = temporary - # - # firstname = TEXT - # firstname.field = firstname - # - # lastname = TEXT - # lastname.field = lastname - } - - - marketing { - - # Use Google Adwords Conversion JavaScript on form submit - googleAdwords { - _enable = {$plugin.tx_powermail.settings.marketing.enable} - google_conversion_id = {$plugin.tx_powermail.settings.marketing.google_conversion_id} - google_conversion_label = {$plugin.tx_powermail.settings.marketing.google_conversion_label} - google_conversion_language = {$plugin.tx_powermail.settings.marketing.google_conversion_language} - google_conversion_format = 3 - } - - # Send Form values to a third party software (like a CRM - e.g. salesforce or eloqua) - sendPost { - # Activate sendPost (0/1) - _enable = TEXT - _enable.value = 0 - - # Target URL for POST values (like http://www.target.com/target.php) - targetUrl = http://eloqua.com/e/f.aspx - - # Basic Auth Protection - leave empty if Target is not protected - username = - password = - - # build your post values like ¶m1=value1¶m2=value2 - values = COA - values { - 10 = TEXT - 10 { - # value from field {firstname} - field = vorname - wrap = &firstname=| - } - - 20 = TEXT - 20 { - # value from field {e_mail} - field = e_mail - wrap = &email=| - } - - 30 = TEXT - 30 { - # value from field {comment} - field = comment - wrap = &text=| - } - } - - # activate debug - log all configuration from curl settings to devlog (use extension devlog to view this values) - debug = 0 - } - } - - - # Save values to any table (see following example) - dbEntry { - - ##################################################### - ### EXAMPLE for adding values to table tt_address ### - ##################################################### - - 1 { - # Enable or disable db entry for table tt_address - # _enable = TEXT - # _enable.value = 1 - - # Set tableName to "tt_address" - # _table = TEXT - # _table.value = tt_address - - # Write only if any field is not yet filled with current value (e.g. test if an email is already in database) - # default: always add new records (don't care about existing values) - # update: update record if there is an existing entry (e.g. if email is already there) - # none: no entry if field is filled (do nothing if record already exists) - # _ifUnique.email = update - - # optional: add additional where clause (only in mode "update") for search if a record still exists. You could use a plain string (see example below) or a cObject if needed - # _ifUniqueWhereClause = AND pid = 123 - - # Fill tt_address.email with a static value => mail@mail.com - # email = TEXT - # email.value = mail@mail.com - - # Fill tt_address.pid with the current pid (e.g. 12) - # pid = TEXT - # pid.data = TSFE:id - - # Fill tt_address.tstamp with the current time as timestamp (like 123456789) - # tstamp = TEXT - # tstamp.data = date:U - - # Fill tt_address.address with the current formatted time (like "Date: 20.01.2013") - # address = TEXT - # address.data = date:U - # address.strftime = Date: %d.%m.%Y - - # Fill tt_address.name with the value from powermail {firstname} - # name = TEXT - # name.field = firstname - - # Fill tt_address.last_name with the value from powermail {lastname} - # last_name = TEXT - # last_name.field = lastname - - # Fill tt_address.company with the value from powermail {company} - # company = TEXT - # company.field = company - - # Fill tt_address.position with the uid of the mail record - # position = TEXT - # position.field = uid - } - - - ############################################################## - ### EXAMPLE for building a relation to tt_address_group ### - ### over the MM table tt_address_group_mm ### - ### Add relation to an existing address group with uid 123 ### - ############################################################## - - 2 { - # Enable or disable db entry for table tt_address_group_mm - # _enable = TEXT - # _enable.value = 1 - - # Set tableName to "tt_address_group_mm" - # _table = TEXT - # _table.value = tt_address_group_mm - - # Fill tt_address_group_mm.uid_local with uid of tt_address record from above configuration 1. (usage .field=uid_[key]) - # uid_local = TEXT - # uid_local.field = uid_1 - - # Fill new record of table "tt_address_group_mm" with field "uid_foreign" with uid 123 - # uid_foreign = TEXT - # uid_foreign.value = 123 - } - } - - - # Add own validator classes that will be called before create action (if you want to validate user input with own PHP classes) - validators { - # 1 { - # Classname that should be called with method *Validator() - # class = Vendor\Ext\Domain\Model\DoSomethingValidator - - # optional: Add configuration for your PHP - # config { - # foo = bar - - # fooCObject = TEXT - # fooCObject.value = do something with this text - # } - - # optional: If file will not be loaded from autoloader, add path and it will be called with require_once - # require = fileadmin/powermail/validator/DoSomethingValidator.php - # } - } - - - # dataProcessor classes that will be called before the mail object will be persisted and used in mails - dataProcessors { - # Powermail data processors - 10.class = In2code\Powermail\DataProcessor\UploadDataProcessor - 20.class = In2code\Powermail\DataProcessor\SessionDataProcessor - - # Add your own data processor classes (e.g. if you want to do something with form values by your own before they are used in powermail to persist or in mails) - # 1 { - # Classname that should be called with method *Finisher() - # class = Vendor\Ext\Finisher\DoSomethingFinisher - - # optional: Add configuration for your PHP - # config { - # foo = bar - - # fooCObject = TEXT - # fooCObject.value = do something with this text - # } - - # optional: If file will not be loaded from autoloader, add path and it will be called with require_once - # require = fileadmin/powermail/finisher/DoSomethingFinisher.php - # } - } - - - # Finisher classes that will be called after submit - finishers { - # Powermail finishers - 10.class = In2code\Powermail\Finisher\SaveToAnyTableFinisher - 20.class = In2code\Powermail\Finisher\SendParametersFinisher - 100.class = In2code\Powermail\Finisher\RedirectFinisher - - # Add your own finishers classes (e.g. if you want to do something with form values by your own: Save into tables, call an API, make your own redirect etc...) - # 1 { - # Classname that should be called with method *Finisher() - # class = Vendor\Ext\Finisher\DoSomethingFinisher - - # optional: Add configuration for your PHP - # config { - # foo = bar - - # fooCObject = TEXT - # fooCObject.value = do something with this text - # } - - # optional: If file will not be loaded from autoloader, add path and it will be called with require_once - # require = fileadmin/powermail/finisher/DoSomethingFinisher.php - # } - } - - - # Switch on or off Debug mode (use extension devlog to view this values) - debug { - # All views: Show Settings from TypoScript, Flexform and Extension Manager - settings = {$plugin.tx_powermail.settings.misc.debugSettings} - - # Create view: Show submitted variables - variables = {$plugin.tx_powermail.settings.misc.debugVariables} - - # Create view: Show complete mail settings - mail = {$plugin.tx_powermail.settings.misc.debugMail} - - # Create view: Show saveToTable array - saveToTable = {$plugin.tx_powermail.settings.misc.debugSaveToTable} - - # Create view: Show spamtest results - spamshield = {$plugin.tx_powermail.settings.misc.debugSpamshield} - } - - - # Don't touch this (this is just to let the extension know, that there is TypoScript included) - staticTemplate = 1 - - # CSS classes for frameworks (add only if bootstrapClassesAndLayout is not added before) - styles { - numberOfColumns = {$plugin.tx_powermail.settings.styles.framework.numberOfColumns} - - framework { - rowClasses = {$plugin.tx_powermail.settings.styles.framework.rowClasses} - formClasses = {$plugin.tx_powermail.settings.styles.framework.formClasses} - fieldAndLabelWrappingClasses = {$plugin.tx_powermail.settings.styles.framework.fieldAndLabelWrappingClasses} - fieldWrappingClasses = {$plugin.tx_powermail.settings.styles.framework.fieldWrappingClasses} - labelClasses = {$plugin.tx_powermail.settings.styles.framework.labelClasses} - fieldClasses = {$plugin.tx_powermail.settings.styles.framework.fieldClasses} - offsetClasses = {$plugin.tx_powermail.settings.styles.framework.offsetClasses} - radioClasses = {$plugin.tx_powermail.settings.styles.framework.radioClasses} - checkClasses = {$plugin.tx_powermail.settings.styles.framework.checkClasses} - submitClasses = {$plugin.tx_powermail.settings.styles.framework.submitClasses} - createClasses = {$plugin.tx_powermail.settings.styles.framework.createClasses} - } - } - } - } -} - -# ParseFunc Configuration for using FAL links in receiver and sender mail -lib.parseFunc_powermail < lib.parseFunc_RTE -lib.parseFunc_powermail.tags { - link.typolink.forceAbsoluteUrl = 1 - a.typolink.forceAbsoluteUrl = 1 -} - -# add jQuery if it was turned on in the constants -[{$plugin.tx_powermail.settings.javascript.addJQueryFromGoogle} == 1] -page.includeJSFooterlibs { - powermailJQuery = {$plugin.tx_powermail.settings.javascript.powermailJQuery} - powermailJQuery.external = 1 -} -[end] - -# add additional javascript libs, if it was turned on in the constants -[{$plugin.tx_powermail.settings.javascript.addAdditionalJavaScript} == 1] -page { - # Include JavaScript files - includeJSFooter { - powermailJQueryDatepicker = EXT:powermail/Resources/Public/JavaScript/Libraries/jquery.datetimepicker.min.js - powermailJQueryFormValidation = EXT:powermail/Resources/Public/JavaScript/Libraries/parsley.min.js - powermailJQueryTabs = EXT:powermail/Resources/Public/JavaScript/Powermail/Tabs.min.js - powermailForm = EXT:powermail/Resources/Public/JavaScript/Powermail/Form.min.js - } -} -[end] +@import 'EXT:powermail/Configuration/TypoScript/Main/Configuration/*.typoscript' diff --git a/Configuration/TypoScript/Marketing/setup.typoscript b/Configuration/TypoScript/Marketing/setup.typoscript index 0cc9b3b9d..69790d3b5 100644 --- a/Configuration/TypoScript/Marketing/setup.typoscript +++ b/Configuration/TypoScript/Marketing/setup.typoscript @@ -38,11 +38,23 @@ page { data = TSFE:sys_language_uid intval = 1 } + + 30 = TEXT + 30 { + noTrimWrap = | data-url="|"| + typolink { + parameter.data = TSFE:id + additionalParams = &type=1540053358 + returnLast = url + forceAbsoluteUrl = 1 + } + } } # Add JavaScript includeJSFooter { powermailMarketing = EXT:powermail/Resources/Public/JavaScript/Powermail/Marketing.min.js + powermailMarketing.defer = 1 } } diff --git a/Configuration/TypoScript/Powermail_Frontend/setup.typoscript b/Configuration/TypoScript/Powermail_Frontend/setup.typoscript index 13157d942..5a89df1f9 100644 --- a/Configuration/TypoScript/Powermail_Frontend/setup.typoscript +++ b/Configuration/TypoScript/Powermail_Frontend/setup.typoscript @@ -123,17 +123,6 @@ tt_content.stdWrap.innerWrap > # JavaScript and CSS section ############################ -# add jQuery if it was turned on in the constants -[{$plugin.tx_powermail.settings.javascript.addJQueryFromGoogle} == 1] -page { - # Inlude JavaScript files - includeJSFooterlibs { - powermailJQuery = {$plugin.tx_powermail.settings.javascript.powermailJQuery} - powermailJQuery.external = 1 - } -} -[end] - # Overwrite classes if bootrap classes given [{$plugin.tx_powermail.settings.styles.bootstrap.important} == 1] plugin.tx_powermail { diff --git a/Documentation/Changelog/Readme.md b/Documentation/Changelog/Readme.md index 1f7da7185..fc02d32d6 100644 --- a/Documentation/Changelog/Readme.md +++ b/Documentation/Changelog/Readme.md @@ -4,7 +4,8 @@ | Version | Release Date | Description | |---------------------------------------------------|--------------|--------------------------------------------------------------------------------------------------------------------| -| [9.0.0](/Documentation/Changelog/RUpgradeInstructions.md) | 2022-11-11 | Feature: Add Support TYPO3 11, drop support for TYPO3 10 | +| [10.0.0](/Documentation/Changelog/UpgradeInstructions.md) | 2022-04-10 | Remove jQuery, parsley.js and other old JS frameworks and replace it | +| [9.0.0](/Documentation/Changelog/UpgradeInstructions.md) | 2022-11-11 | Feature: Add Support TYPO3 11, drop support for TYPO3 10 | | 8.4.1 | 2021-08-11 | Task: Also Sanitize CSV and XLS export in Pi2 (not only the export in the backend module) | | 8.4.0 | 2021-08-11 | Task: Sanitize CSV and XLS export against excel hacks (see https://typo3.org/security/advisory/typo3-psa-2021-002) | | | | Task: Add automatic test via github actions | diff --git a/Documentation/Changelog/UpgradeInstructions.md b/Documentation/Changelog/UpgradeInstructions.md index fc23d5c20..3773a5d10 100644 --- a/Documentation/Changelog/UpgradeInstructions.md +++ b/Documentation/Changelog/UpgradeInstructions.md @@ -1,7 +1,23 @@ -# Upgrade Instructions +# Upgrade Instructions and breaking changes -## Version 9.0 +## Version 10.0 + +In version 10 we completely removed jQuery, jQuery UI, Datetimepicker, Parsley.js and other old JS stuff from frontend +rendering. We now use an own form framework, that runs with vanilla JS and can be included via async or defer and does +not need any old jQuery version. +To make the switch as smooth as possible for you, the validation output is nearly the same as with parsley.js. +As a new feature we now validate while the input is done from the user. +Nevertheless, some HTML templates have changed: +* Morestep validation is build in the HTML template: + * EXT:powermail/Resources/Private/Partials/Form/Page.html +* ViewHelper name changed from {vh:validation.enableParsleyAndAjax(form:form)} to {vh:validation.enableJavascriptValidationAndAjax(form:form)}: + * EXT:powermail/Resources/Private/Templates/Form/Form.html + * EXT:powermail/Resources/Private/Templates/Output/Edit.html + * EXT:powermail/Resources/Private/Templates/Form/Confirmation.html +* If you have added jQuery manually, you can remove the implementation (if it was only for powermail) + +## Version 9.0 | Version | Description | |---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| diff --git a/Documentation/FAQ/Readme.md b/Documentation/FAQ/Readme.md index afe319e10..e643b94cb 100644 --- a/Documentation/FAQ/Readme.md +++ b/Documentation/FAQ/Readme.md @@ -173,7 +173,7 @@ And adds the class “formgrey”, "form2cols" or “default” to all forms, pa ### Hiding fields in tables form, page or field -For editors (not administrators) fields can be disabled in the right management of TYPO3 +For editors (not administrators) fields can be disabled in the rights management of TYPO3 (see TYPO3 documentation how to show or hide fields for editors). Another way is to hide fields for editors (and administrators) via Page TSConfig: @@ -235,41 +235,6 @@ you can do this with a simple line of Page TSConfig: `TCEFORM.tx_powermail_domain_model_field.type.removeItems = captcha,location,typoscript` -## JavaScript validation does not work – what's wrong? - -Powermail loads jQuery (if you activated it with TypoScript) from googleapis.com. -You can change that behaviour with constants or typoscript. - -It's importand to have the correct ordering of the JavaScript files. -First you need the libraries (jQuery, Datepicker, Parsley) and after that your JavaScript. - -Check the correct including of your JavaScript in the HTML source – -example Footer could be: - -``` - - - - - - -``` - -## The datetimepicker is not working – what's wrong? - -First of all, check if there are all JavaScript loaded correctly (see :ref:`javascriptvalidationdoesnotwork`). -In addition the datetimepicker needs some CSS to get shown in frontend. You can try to add the demo.css in Static TypoScript Template section. - -If you want to get more information to the used datetimepicker (JavaScript, CSS, examples, etc...) see: - -* http://xdsoft.net/jqplugins/datetimepicker -* https://github.com/xdan/datetimepicker - -*Note:* There is a check, if the browser supports fields like `input[type="date"]` (e.g. Chrome). -Per default the datetimepicker is disabled in this case. -If you want to enforce datetimepicker for all browsers, you can enable this via TypoScript Constants. - - # I want to use additionalAttributes in a field partial, but it's already in use All Field partials are original stored under EXT:powermail/Resources/Private/Partials/Form/Field/* @@ -290,17 +255,6 @@ In some case you need to set your own additionalAttributes - see following code ... /> ``` -## How can I add a callback function on ajax submit? - -See this example JavaScript how to add an own callback function in JavaScript when an ajaxsubmit is done -(e.g. to close a lightbox or something else). - -``` -// Note: this event fires on the .tx-powermail element, since its inner html is replaced -$('.tx-powermail').on('submitted.powermail.form', function(){ - console.log('ajax form was submitted'); -}) -``` ## I want to use powermail on a news-detail-page, but the error **Reason: No news entry found.** comes up diff --git a/Documentation/ForAdministrators/BestPractice/MainTypoScript.md b/Documentation/ForAdministrators/BestPractice/MainTypoScript.md index eea68f076..98ed48b4d 100644 --- a/Documentation/ForAdministrators/BestPractice/MainTypoScript.md +++ b/Documentation/ForAdministrators/BestPractice/MainTypoScript.md @@ -3,1020 +3,346 @@ Constants are fix variables for your TYPO3 instance, that are often modified for an initial configuration. While TypoScript setup include the complete frontend configuration for powermail where constants are included. -Setup and constants are located in powermail at EXT:powermail/Configuration/TypoScript/Main/* +Setup and constants are located in powermail at EXT:powermail/Configuration/TypoScript/Main/* (+ subfolders) Some additional and optional TypoScript is stored in sibling folders. ## TypoScript Constants ``` -################## -# Frontend Plugin -################## plugin.tx_powermail { + view { - templateRootPaths { - 0 = EXT:powermail/Resources/Private/Templates/ - 1 = {$plugin.tx_powermail.view.templateRootPath} - } + # cat=powermail_main/file; type=string; label= Path to template root (FE) + templateRootPath = EXT:powermail/Resources/Private/Templates/ - partialRootPaths { - 0 = EXT:powermail/Resources/Private/Partials/ - 1 = {$plugin.tx_powermail.view.partialRootPath} - } + # cat=powermail_main/file; type=string; label= Path to template partials (FE) + partialRootPath = EXT:powermail/Resources/Private/Partials/ - layoutRootPaths { - 0 = EXT:powermail/Resources/Private/Layouts/ - 1 = {$plugin.tx_powermail.view.layoutRootPath} - } + # cat=powermail_main/file; type=string; label= Path to template layouts (FE) + layoutRootPath = EXT:powermail/Resources/Private/Layouts/ } - # Modify localization of labels - # _LOCAL_LANG { - # default { - # confirmation_message = Are these values correct? - # } - # de { - # confirmation_message = Sind diese Eingaben korrekt? - # } - # } - - # Main settings settings { - setup { - - main { - pid = {$plugin.tx_powermail.settings.main.pid} - form = {$plugin.tx_powermail.settings.main.form} - confirmation = {$plugin.tx_powermail.settings.main.confirmation} - optin = {$plugin.tx_powermail.settings.main.optin} - moresteps = {$plugin.tx_powermail.settings.main.moresteps} - } - - validation { - # enable native HTML5 validation - native = {$plugin.tx_powermail.settings.validation.native} - - # enable clientside validation - client = {$plugin.tx_powermail.settings.validation.client} - - # enable serverside validation - server = {$plugin.tx_powermail.settings.validation.server} - - unique { - # Enable unique check for {email} - #email = 1 - - # Enable a max limit of 3 times for the same entry for {event} - #event = 3 - } - - ########################################################## - # CUSTOMVALIDATION EXAMPLE - # - # E.g. Validation was extended with Page TSconfig - # tx_powermail.flexForm.validation.addFieldOptions.100 = New Validation - # - # Register your Class and Method with TypoScript Setup - # plugin.tx_powermail.settings.setup.validation.customValidation.100 = - # In2code\Powermailextended\Domain\Validator\ZipValidator - # - # Add method to your class - # validate100($value, $validationConfiguration) - # - # Define your Errormessage with TypoScript Setup - # plugin.tx_powermail._LOCAL_LANG.default.validationerror_validation.100 = Error happens! - # - # ########################################################## - customValidation { - # 100 = In2code\Powermailextended\Domain\Validator\ZipValidator - } - } - # All settings for mail to receiver - receiver { - enable = {$plugin.tx_powermail.settings.receiver.enable} + main { + # cat=powermail_additional//0010; type=int+; label= Storage PID: Save mails in a defined Page (normally set via Flexform) + pid = - # Following settings are normally set via Flexform - email = - subject = - body = - - # add file attachments from upload fields - attachment = {$plugin.tx_powermail.settings.receiver.attachment} - - # html, plain, both - mailformat = {$plugin.tx_powermail.settings.receiver.mailformat} - - default { - senderName = TEXT - senderName.value = {$plugin.tx_powermail.settings.receiver.default.senderName} - - senderEmail = TEXT - senderEmail.value = {$plugin.tx_powermail.settings.receiver.default.senderEmail} - } - - # Predefine some receivers - selection in backend could be done via page TSConfig: - # tx_powermail.flexForm.predefinedReceivers.addFieldOptions.receivers1 = receiver list #1 - # or with a locallang variable: - # tx_powermail.flexForm.predefinedReceivers.addFieldOptions.receivers1 = LLL:fileadmin/locallang.xlf:key - predefinedReceiver { - # example for hard coded receivers - # receivers1 { - # email = TEXT - # email.value = email1@domain.org, email2@domain.org - # } - - # example for dynamic receiver - depending on value in field {receiver} - # receivers2 { - # email = CASE - # email { - # key.data = GP:tx_powermail_pi1|field|receiver - - # 1 = TEXT - # 1.value = email1@domain.org - - # 2 = TEXT - # 2.value = email2@domain.org - # } - # } - } - - # Normally you do not need to overwrite a flexform setting, but this allows you to use cObject functions - overwrite { - email = TEXT - email.value = {$plugin.tx_powermail.settings.receiver.overwrite.email} - - name = TEXT - name.value = {$plugin.tx_powermail.settings.receiver.overwrite.name} - - senderName = TEXT - senderName.value = {$plugin.tx_powermail.settings.receiver.overwrite.senderName} - - senderEmail = TEXT - senderEmail.value = {$plugin.tx_powermail.settings.receiver.overwrite.senderEmail} - - subject = TEXT - subject.value = {$plugin.tx_powermail.settings.receiver.overwrite.subject} - - # Add further CC Receivers (split them via comma) - cc = TEXT - cc.value = {$plugin.tx_powermail.settings.receiver.overwrite.cc} - - # Add further BCC Receivers (split them via comma) - bcc = TEXT - bcc.value = {$plugin.tx_powermail.settings.receiver.overwrite.bcc} - - # Add return path - returnPath = TEXT - returnPath.value = {$plugin.tx_powermail.settings.receiver.overwrite.returnPath} - - # Reply address (both required) - replyToEmail = TEXT - replyToEmail.value = {$plugin.tx_powermail.settings.receiver.overwrite.replyToEmail} - replyToName = TEXT - replyToName.value = {$plugin.tx_powermail.settings.receiver.overwrite.replyToName} - - # Set mail priority from 1 to 5 - priority = {$plugin.tx_powermail.settings.receiver.overwrite.priority} - } - - # Add additional attachments to the mail (separate each with comma) - # addAttachment = TEXT - # addAttachment.value = fileadmin/file.jpg - # addAttachment.wrap = |, - - # Mail Header "Sender:" see RFC 2822 - 3.6.2 Originator fields f.e. webserver@example.com, leave empty if you do not want to set a Sender-Header - senderHeader { - email = TEXT - email.value = {$plugin.tx_powermail.settings.receiver.senderHeader.email} - # optional: f.e. Webserver - name = TEXT - name.value = {$plugin.tx_powermail.settings.receiver.senderHeader.name} - } - } - - # All settings for mail to user - sender { - enable = {$plugin.tx_powermail.settings.sender.enable} + # cat=powermail_additional//0020; type=text; label= Form Uid: Commaseparated list of forms to show (normally set via Flexform) + form = - # Following settings are normally set via Flexform - name = - email = - subject = - body = + # cat=powermail_additional//0030; type=boolean; label= Confirmation Page Active: Activate Confirmation Page (normally set via Flexform) + confirmation = - # add file attachments from upload fields - attachment = {$plugin.tx_powermail.settings.sender.attachment} + # cat=powermail_additional//0040; type=boolean; label= Double Optin Active: Activate Double Optin for Mail sender (normally set via Flexform) + optin = - # html, plain, both - mailformat = {$plugin.tx_powermail.settings.sender.mailformat} - - addDisclaimerLink = {$plugin.tx_powermail.settings.sender.addDisclaimerLink} - - default { - senderEmail = TEXT - senderEmail.value = {$plugin.tx_powermail.settings.sender.default.senderEmail} - - senderName = TEXT - senderName.value = {$plugin.tx_powermail.settings.sender.default.senderName} - } - - # Normally you do not need to overwrite a flexform settings, but this allows you to use cObject functions - overwrite { - email = TEXT - email.value = {$plugin.tx_powermail.settings.sender.overwrite.email} - - name = TEXT - name.value = {$plugin.tx_powermail.settings.sender.overwrite.name} - - senderName = TEXT - senderName.value = {$plugin.tx_powermail.settings.sender.overwrite.senderName} - - senderEmail = TEXT - senderEmail.value = {$plugin.tx_powermail.settings.sender.overwrite.senderEmail} - - subject = TEXT - subject.value = {$plugin.tx_powermail.settings.sender.overwrite.subject} + # cat=powermail_additional//0050; type=boolean; label= Morestep Active: Activate Morestep Forms (normally set via Flexform) + moresteps = + } - # Add further CC Receivers (split them via comma) - cc = TEXT - cc.value = {$plugin.tx_powermail.settings.sender.overwrite.cc} + validation { + # cat=powermail_additional//0100; type=boolean; label= Native Browser Validation: Validate User Input with HTML5 native browser validation on clientside + native = 1 - # Add further BCC Receivers (split them via comma) - bcc = TEXT - bcc.value = {$plugin.tx_powermail.settings.sender.overwrite.bcc} + # cat=powermail_additional//0110; type=boolean; label= JavaScript Browser Validation: Validate User Input with JavaScript on clientside + client = 1 - # Add return path - returnPath = TEXT - returnPath.value = {$plugin.tx_powermail.settings.sender.overwrite.returnPath} + # cat=powermail_additional//0120; type=boolean; label= PHP Server Validation: Validate User Input with PHP on serverside + server = 1 + } - # Reply address (both required) - replyToEmail = TEXT - replyToEmail.value = {$plugin.tx_powermail.settings.sender.overwrite.replyToEmail} - replyToName = TEXT - replyToName.value = {$plugin.tx_powermail.settings.sender.overwrite.replyToName} + receiver { + # cat=powermail_main/enable/0200; type=boolean; label= Receiver Mail: Enable Email to Receiver + enable = 1 - # Set mail priority from 1 to 5 - priority = {$plugin.tx_powermail.settings.sender.overwrite.priority} - } + # cat=powermail_main//0210; type=boolean; label= Receiver Attachments: Add uploaded files to emails + attachment = 1 - # Add additional attachments to the mail (separate each with comma) - # addAttachment = TEXT - # addAttachment.value = fileadmin/file.jpg - # addAttachment.wrap = |, + # cat=powermail_main//0220; type=options[both,html,plain]; label= Receiver Mail Format: Change mail format + mailformat = both - # Mail Header "Sender:" see RFC 2822 - 3.6.2 Originator fields f.e. webserver@example.com, leave empty if you do not want to set a Sender-Header - senderHeader { - email = TEXT - email.value = {$plugin.tx_powermail.settings.sender.senderHeader.email} - # optional: f.e. Webserver - name = TEXT - name.value = {$plugin.tx_powermail.settings.sender.senderHeader.name} - } - } + default { + # cat=powermail_additional//0230; type=text; label= Default Sender Name: Sendername if no sender name given + senderName = - thx { - # Following settings are normally set via Flexform - body = - redirect = - - overwrite { - # Overwrite redirect with TypoScript cObject - # Return a Number: Typolink to the pid - # Return a URL: Link to an intern or extern URL - # Return a File: Link to a file (within fileadmin folder) - # redirect = COA - # redirect { - # 10 = TEXT - # 10 { - # typolink.parameter = 2 - # typolink.returnLast = url - # typolink.additionalParams = &x=y - # } - # } - } + # cat=powermail_additional//0240; type=text; label= Default Sender Email: Sender-email if no sender email given + senderEmail = } - db { - # Enable mail storage - enable = {$plugin.tx_powermail.settings.db.enable} - - # Add new mails with hidden=1 - hidden = {$plugin.tx_powermail.settings.db.hidden} - } + overwrite { + # cat=powermail_additional//0250; type=text; label= Receiver overwrite Email: Commaseparated list of mail receivers overwrites flexform settings (e.g. receiver1@mail.com, receiver1@mail.com) + email = - optin { - subject = TEXT - subject.data = LLL:EXT:powermail/Resources/Private/Language/locallang.xlf:optin_subject + # cat=powermail_additional//0252; type=text; label= Receiver overwrite Name: Receiver Name overwrites flexform settings (e.g. Receiver Name) + name = - overwrite { - # email = TEXT - # email.value = alexander.kellner@in2code.de + # cat=powermail_additional//0254; type=text; label= Receiver overwrite SenderName: Sender Name for mail to receiver overwrites flexform settings (e.g. Sender Name) + senderName = - # name = TEXT - # name.value = Receivers Name + # cat=powermail_additional//0256; type=text; label= Receiver overwrite SenderEmail: Sender Email for mail to receiver overwrites flexform settings (e.g. sender@mail.com) + senderEmail = - # senderName = TEXT - # senderName.value = Sender Name + # cat=powermail_additional//0258; type=text; label= Receiver overwrite Mail Subject: Subject for mail to receiver overwrites flexform settings (e.g. New Mail from website) + subject = - # senderEmail = TEXT - # senderEmail.value = sender@mail.com - } - } + # cat=powermail_additional//0260; type=text; label= Receiver CC Email Addresses: Commaseparated list of cc mail receivers (e.g. rec2@mail.com, rec3@mail.com) + cc = - disclaimer { - subject = TEXT - subject.data = LLL:EXT:powermail/Resources/Private/Language/locallang.xlf:disclaimed_subject - } + # cat=powermail_additional//0262; type=text; label= Receiver BCC Email Addresses: Commaseparated list of bcc mail receivers (e.g. rec2@mail.com, rec3@mail.com) + bcc = + # cat=powermail_additional//0264; type=text; label= Receiver Mail Return Path: Return Path for emails to receiver (e.g. return@mail.com) + returnPath = - # Captcha Settings - captcha { - # Select "default" (on board calculating captcha) or "captcha" (needs extension captcha) - use = default + # cat=powermail_additional//0266; type=text; label= Receiver Mail Reply Mail: Reply Email address for mail to receiver (e.g. reply@mail.com) + replyToEmail = - default { - image = {$plugin.tx_powermail.settings.captcha.image} - font = {$plugin.tx_powermail.settings.captcha.font} - textColor = {$plugin.tx_powermail.settings.captcha.textColor} - textSize = {$plugin.tx_powermail.settings.captcha.textSize} - textAngle = {$plugin.tx_powermail.settings.captcha.textAngle} - distanceHor = {$plugin.tx_powermail.settings.captcha.distanceHor} - distanceVer = {$plugin.tx_powermail.settings.captcha.distanceVer} + # cat=powermail_additional//0268; type=text; label= Receiver Mail Reply Name: Reply Name for mail to receiver (e.g. Mr. Reply) + replyToName = - # You can force a fix captcha - operator must be "+" (for testing only with calculating captcha) - # forceValue = 1+1 - } + # cat=powermail_additional//0270; type=options[1,2,3,4,5]; label= Receiver Mail Priority: Set mail priority for mail to receiver (e.g. 3) + priority = 3 } + senderHeader { + # cat=powermail_additional//0060; type=text; label= Server-Mail: If set, the Mail-Header Sender is set (RFC 2822 - 3.6.2 Originator fields) + email = - # Spam Settings - spamshield { - # enable or disable spam check - _enable = {$plugin.tx_powermail.settings.spamshield.enable} - - # disable complete spam check on individual conditions (overrules ._enable=1) - # _disable { - # 1 { - # Disable spamcheck if visitor is in IP-Range - # class = In2code\Powermail\Domain\Validator\SpamShield\Breaker\IpBreaker - # configuration { - # // Commaseparated list of IPs. Use * for wildcards in the IP-address - # ipWhitelist = 127.0.0.1,192.168.0.* - # } - # } - - # 2 { - # Disable spamcheck if any field contains a given value - like "powermailTestCase" - # class = In2code\Powermail\Domain\Validator\SpamShield\Breaker\ValueBreaker - # configuration { - # value = powermailTestCase - # } - # } - # } - - # Spam Factor Limit in % - factor = {$plugin.tx_powermail.settings.spamshield.factor} - - # Notification Email to Admin if spam recognized (empty disables email to admin) - email = {$plugin.tx_powermail.settings.spamshield.email} - - # Email address sending out spam mail. Set this if your mail transport limits allowed sender addresses - senderEmail = {$plugin.tx_powermail.settings.spamshield.senderEmail} - - # Subject for notification Email to Admin - emailSubject = {$plugin.tx_powermail.settings.spamshield.emailSubject} - - # Template for notification Email to Admin - emailTemplate = {$plugin.tx_powermail.settings.spamshield.emailTemplate} - - # Path to logfile - logfileLocation = {$plugin.tx_powermail.settings.spamshield.logfileLocation} - - # Template for logging entry - logTemplate = {$plugin.tx_powermail.settings.spamshield.logTemplate} - - methods { - # Honeypot check - 1 { - _enable = 1 - - # Spamcheck name - name = Honey Pot - - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\HoneyPodMethod - - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 5 - - # method configuration - configuration { - - } - } - - # Link check - 2 { - _enable = 1 - - # Spamcheck name - name = Link check - - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\LinkMethod - - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 3 - - # method configuration - configuration { - # number of allowed links - linkLimit = 2 - } - } - - # Name check - 3 { - _enable = 1 - - # Spamcheck name - name = Name check - - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\NameMethod - - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 3 - - # method configuration - configuration { - - } - } - - # Session check: Enabling session check means to store a cookie on form load. If forms are submitted powermail checks for that cookie again. If this check is disabled, powermail will not set a cookie by default. - 4 { - _enable = 0 - - # Spamcheck name - name = Session check - - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\SessionMethod - - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 5 - - # method configuration - configuration { - - } - } - - # Unique check - 5 { - _enable = 1 - - # Spamcheck name - name = Unique check - - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\UniqueMethod - - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 2 - - # method configuration - configuration { - - } - } - - # Value blacklist check - 6 { - _enable = 1 - - # Spamcheck name - name = Value blacklist check - - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\ValueBlacklistMethod - - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 7 + # cat=powermail_additional//0070; type=text; label= Server-Name: you can define a name along with the mail address (optional) + name = + } + } - # method configuration - configuration { - # Blacklisted values (could also get read from a file - simply with FLUIDTEMPLATE) - values = TEXT - values.value = viagra,sex,porn,p0rn - } - } + sender { + # cat=powermail_main/enable/0400; type=boolean; label= Sender Mail: Enable Email to Sender + enable = 1 - # IP blacklist check - 7 { - _enable = 1 + # cat=powermail_main//0410; type=boolean; label= Sender Attachments: Add uploaded files to emails + attachment = 0 - # Spamcheck name - name = IP blacklist check + # cat=powermail_main//0420; type=options[both,html,plain]; label= Sender Mail Format: Change mail format + mailformat = both - # Class - class = In2code\Powermail\Domain\Validator\SpamShield\IpBlacklistMethod + # cat=powermail_main//0425; type=boolean; label= Add disclaimer link: Add disclaimer link to the sender email (also in optin mail) + addDisclaimerLink = 1 - # if this check failes - add this indication value to indicator (0 disables this check completely) - indication = 7 + default { + # cat=powermail_additional//0430; type=text; label= Sender Mail - Default Sender Name: Sendername if no sender name given + senderName = - # method configuration - configuration { - # Blacklisted values (could also get read from a file - simply with FLUIDTEMPLATE) - values = TEXT - values.value = 123.132.125.123,123.132.125.124 - } - } - } + # cat=powermail_additional//0432; type=text; label= Sender Mail - Default Sender Email: Sender email address if no sender email given + senderEmail = } + overwrite { + # cat=powermail_additional//0450; type=text; label= Sender overwrite Email: Comma-separated list of mail receivers overwrites flexform settings (e.g. receiver1@mail.com, receiver1@mail.com) + email = - # Misc Settings - misc { - # HTML Output for type HMTL fields - htmlForHtmlFields = {$plugin.tx_powermail.settings.misc.htmlForHtmlFields} - - # HTML for labels - htmlForLabels = {$plugin.tx_powermail.settings.misc.htmlForLabels} - - # Show only values if they are filled (for all views and for mails) - showOnlyFilledValues = {$plugin.tx_powermail.settings.misc.showOnlyFilledValues} - - # Submit Powermail Forms with AJAX (browser will not reload complete page) - ajaxSubmit = {$plugin.tx_powermail.settings.misc.ajaxSubmit} - - # Keep third-party GET/POST variables on submit with addQueryString="1" in form - addQueryString = {$plugin.tx_powermail.settings.misc.addQueryString} + # cat=powermail_additional//0452; type=text; label= Sender overwrite Name: Receiver Name overwrites flexform settings (e.g. Receiver Name) + name = - # File upload settings - file { - folder = {$plugin.tx_powermail.settings.misc.uploadFolder} - size = {$plugin.tx_powermail.settings.misc.uploadSize} - extension = {$plugin.tx_powermail.settings.misc.uploadFileExtensions} - randomizeFileName = {$plugin.tx_powermail.settings.misc.randomizeFileName} - randomizePrependOriginalFileName = {$plugin.tx_powermail.settings.misc.randomizePrependOriginalFileName} - } + # cat=powermail_additional//0454; type=text; label= Sender overwrite SenderName: Sender Name for mail to sender overwrites flexform settings (e.g. Sender Name) + senderName = - datepicker { - # Per default html5 Date or Datetime format is used. If you don't want to use it and want to have the same datepicker all over all browsers, you can enable this feature - forceJavaScriptDatePicker = {$plugin.tx_powermail.settings.misc.forceJavaScriptDatePicker} - } - } + # cat=powermail_additional//0456; type=text; label= Sender overwrite SenderEmail: Sender Email for mail to sender overwrites flexform settings (e.g. sender@mail.com) + senderEmail = + # cat=powermail_additional//0458; type=text; label= Sender overwrite Mail Subject: Subject for mail to sender overwrites flexform settings (e.g. Thx for your mail) + subject = - # Prefill fields with their marker - e.g. {firstname} (Fields available for prefill: input, textarea, select, select multi, radio, checkbox) - prefill { - # example: fill with string - # firstname = Alex + # cat=powermail_additional//0460; type=text; label= Sender CC Email Addresses: Comma-separated list of cc mail receivers (e.g. rec2@mail.com, rec3@mail.com) + cc = - # example: fill with TypoScript - # email = TEXT - # email.value = alex@in2code.de - # email.wrap = | + # cat=powermail_additional//0462; type=text; label= Sender BCC Email Addresses: Comma-separated list of bcc mail receivers (e.g. rec2@mail.com, rec3@mail.com) + bcc = - # example: fill checkboxes or multiselect with more values - # category.0 = TEXT - # category.0.value = IT - # category.1 = TEXT - # category.1.value = Real Estate + # cat=powermail_additional//0464; type=text; label= Sender Mail Return Path: Return Path for emails to sender (e.g. return@mail.com) + returnPath = - # example: fill with value from Field Record - # available: uid, title, type, settings, css, feuserValue, mandatory, marker, pid, prefillValue, senderEmail, senderName, sorting, validation - # comment = TEXT - # comment.field = type - } + # cat=powermail_additional//0466; type=text; label= Sender Mail Reply Mail: Reply Email address for mail to sender (e.g. reply@mail.com) + replyToEmail = + # cat=powermail_additional//0468; type=text; label= Sender Mail Reply Name: Reply Name for mail to sender (e.g. Mr. Reply) + replyToName = - # Exclude values from {powermail_all} by markername or fieldtype - excludeFromPowermailAllMarker { - # On Confirmation Page (if activated) - confirmationPage { - # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) - excludeFromMarkerNames = - - # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) - excludeFromFieldTypes = - } - - # On Submitpage - submitPage { - # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) - excludeFromMarkerNames = - - # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) - excludeFromFieldTypes = - } - - # In Mail to receiver - receiverMail { - # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) - excludeFromMarkerNames = - - # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) - excludeFromFieldTypes = - } - - # In Mail to sender (if activated) - senderMail { - # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) - excludeFromMarkerNames = - - # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) - excludeFromFieldTypes = - } - - # In double-opt-in Mail to sender (if activated) - optinMail { - # add some markernames (commaseparated) which should be excluded (e.g. firstname, email, referrer) - excludeFromMarkerNames = - - # add some fieldtypes (commaseparated) which should be excluded (e.g. hidden, captcha) - excludeFromFieldTypes = - } + # cat=powermail_additional//0470; type=options[1,2,3,4,5]; label= Sender Mail Priority: Set mail priority for mail to sender (e.g. 3) + priority = 3 } + senderHeader { + # cat=powermail_additional//0060; type=text; label= Server-Mail: If set, the Mail-Header Sender is set (RFC 2822 - 3.6.2 Originator fields) + email = - # Manipulate values from {powermail_all} by markername - manipulateVariablesInPowermailAllMarker { - # On Confirmation Page (if activated) - confirmationPage { - # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid - # markerName = CASE - # markerName { - # key.field = value - # - # 1 = TEXT - # 1.value = red - # - # default = TEXT - # default.value = blue - # } - } - - # On Submitpage - submitPage { - # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid - # markerName = CASE - # markerName { - # key.field = value - # - # 1 = TEXT - # 1.value = red - # - # default = TEXT - # default.value = blue - # } - } - - # In Mail to receiver - receiverMail { - # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid - # markerName = CASE - # markerName { - # key.field = value - # - # 1 = TEXT - # 1.value = red - # - # default = TEXT - # default.value = blue - # } - } - - # In Mail to sender (if activated) - senderMail { - # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid - # markerName = CASE - # markerName { - # key.field = value - # - # 1 = TEXT - # 1.value = red - # - # default = TEXT - # default.value = blue - # } - } - - # In double-opt-in Mail to sender (if activated) - optinMail { - # manipulate values by given marker (e.g. firstname, email, referrer) with TypoScript - available fieldnames (access with .field=): value, valueType, uid, pid - # markerName = CASE - # markerName { - # key.field = value - # - # 1 = TEXT - # 1.value = red - # - # default = TEXT - # default.value = blue - # } - } + # cat=powermail_additional//0070; type=text; label= Server-Name: you can define a name along with the mail address (optional) + name = } + } + db { + # cat=powermail_main/enable/0600; type=boolean; label= Mail Storage enabled: Store Mails in database + enable = 1 - # Save submitted values in a session to prefill forms for further visits. Define each markername for all forms. - saveSession { - # Method "temporary" means as long as the browser is open. "permanently" could be used together with a frontend-user session. If method is empty, saveSession is deactivated. - # _method = temporary - # - # firstname = TEXT - # firstname.field = firstname - # - # lastname = TEXT - # lastname.field = lastname - } + # cat=powermail_additional//0610; type=boolean; label= Hidden Mails in Storage: Add mails with hidden flag (e.g. 1) + hidden = 0 + } + marketing { + # cat=powermail_additional//0700; type=boolean; label= Enable Google Conversion: Enable JavaScript for google conversion - This is interesting if you want to track every submit in your Google Adwords account for a complete conversion. + enable = 0 - marketing { - - # Use Google Adwords Conversion JavaScript on form submit - googleAdwords { - _enable = {$plugin.tx_powermail.settings.marketing.enable} - google_conversion_id = {$plugin.tx_powermail.settings.marketing.google_conversion_id} - google_conversion_label = {$plugin.tx_powermail.settings.marketing.google_conversion_label} - google_conversion_language = {$plugin.tx_powermail.settings.marketing.google_conversion_language} - google_conversion_format = 3 - } - - # Send Form values to a third party software (like a CRM - e.g. salesforce or eloqua) - sendPost { - # Activate sendPost (0/1) - _enable = TEXT - _enable.value = 0 - - # Target URL for POST values (like http://www.target.com/target.php) - targetUrl = http://eloqua.com/e/f.aspx - - # Basic Auth Protection - leave empty if Target is not protected - username = - password = - - # build your post values like ¶m1=value1¶m2=value2 - values = COA - values { - 10 = TEXT - 10 { - # value from field {firstname} - field = vorname - wrap = &firstname=| - } - - 20 = TEXT - 20 { - # value from field {e_mail} - field = e_mail - wrap = &email=| - } - - 30 = TEXT - 30 { - # value from field {comment} - field = comment - wrap = &text=| - } - } - - # activate debug - log all configuration from curl settings to devlog (use extension devlog to view this values) - debug = 0 - } - } + # cat=powermail_additional//0710; type=int+; label= Google Conversion Id: Add your google conversion id (see www.google.com/adwords for details) + google_conversion_id = 1234567890 + # cat=powermail_additional//0720; type=text; label= Google Conversion Label: Add your google conversion label (see www.google.com/adwords for details) + google_conversion_label = abcdefghijklmnopqrs - # Save values to any table (see following example) - dbEntry { + # cat=powermail_additional//0730; type=text; label= Google Conversion Language: Add your google conversion language (see www.google.com/adwords for details) + google_conversion_language = en + } - ##################################################### - ### EXAMPLE for adding values to table tt_address ### - ##################################################### + misc { + # cat=powermail_additional//0800; type=boolean; label= Allow html in html fields: Per default output of fields of type HTML is parsed through a htmlspecialchars() function to avoid Cross-Site-Scripting for security reasons. If you are aware of possible XSS-problems, caused by editors, you can enable it and your original HTML is shown in the Frontend. + htmlForHtmlFields = 0 - 1 { - # Enable or disable db entry for table tt_address - # _enable = TEXT - # _enable.value = 1 + # cat=powermail_additional//0802; type=boolean; label= Allow html in field labels: Per default labels are generated with htmlspecialchars() to prevent xss. This also disables links in labels. If you aware of possible XSS-problems, caused by editors, you can enable it. + htmlForLabels = 0 - # Set tableName to "tt_address" - # _table = TEXT - # _table.value = tt_address + # cat=powermail_additional//0803; type=boolean; label= Show only filled values: If the user submits a form, even not filled values are viewable. If you only want to show labels with filled values, use this setting + showOnlyFilledValues = 1 - # Write only if any field is not yet filled with current value (e.g. test if an email is already in database) - # default: always add new records (don't care about existing values) - # update: update record if there is an existing entry (e.g. if email is already there) - # none: no entry if field is filled (do nothing if record already exists) - # _ifUnique.email = update + # cat=powermail_additional//0805; type=boolean; label= AJAX Submit Form: Submit Powermail Forms with AJAX (browser will not reload complete page) + ajaxSubmit = 0 - # optional: add additional where clause (only in mode "update") for search if a record still exists. You could use a plain string (see example below) or a cObject if needed - # _ifUniqueWhereClause = AND pid = 123 + # cat=powermail_additional//0808; type=boolean; label= Enable AddQueryString: Keep GET-params in form Action (e.g. to use powermail on a tx_news detail page) + addQueryString = 0 - # Fill tt_address.email with a static value => mail@mail.com - # email = TEXT - # email.value = mail@mail.com + # cat=powermail_additional//0810; type=text; label= Misc Upload Folder: Define the folder where files should be uploaded with upload fields (e.g. fileadmin/uploads/) + uploadFolder = uploads/tx_powermail/ - # Fill tt_address.pid with the current pid (e.g. 12) - # pid = TEXT - # pid.data = TSFE:id + # cat=powermail_additional//0820; type=int+; label= Misc Upload Filesize: Define the maximum filesize of file uploads in bytes (10485760 Byte -> 10 MB) + uploadSize = 10485760 - # Fill tt_address.tstamp with the current time as timestamp (like 123456789) - # tstamp = TEXT - # tstamp.data = date:U + # cat=powermail_additional//0830; type=text; label= Misc Upload Fileextensions: Define the allowed filetypes with their extensions for fileuploads and separate them with commas (e.g. jpg,jpeg,gif) + uploadFileExtensions = jpg,jpeg,gif,png,tif,txt,doc,docx,xls,xlsx,ppt,pptx,pdf,mpg,mpeg,avi,mp3,zip,rar,ace,csv,svg - # Fill tt_address.address with the current formatted time (like "Date: 20.01.2013") - # address = TEXT - # address.data = date:U - # address.strftime = Date: %d.%m.%Y + # cat=powermail_additional//0840; type=boolean; label= Randomized Filenames: Uploaded filenames can be randomized to respect data privacy + randomizeFileName = 1 - # Fill tt_address.name with the value from powermail {firstname} - # name = TEXT - # name.field = firstname + # cat=powermail_additional//0840; type=boolean; label= Prepend original file name: Prepend original file name to randomized file name if randomizeFileName is enabled + randomizePrependOriginalFileName = 0 - # Fill tt_address.last_name with the value from powermail {lastname} - # last_name = TEXT - # last_name.field = lastname + # cat=powermail_additional//0850; type=boolean; label= Debug Settings: Show all Settings from TypoScript, Flexform and Global Config in Devlog + debugSettings = 0 - # Fill tt_address.company with the value from powermail {company} - # company = TEXT - # company.field = company + # cat=powermail_additional//0860; type=boolean; label= Debug Variables: Show all given Plugin variables from GET or POST in Devlog + debugVariables = 0 - # Fill tt_address.position with the uid of the mail record - # position = TEXT - # position.field = uid - } + # cat=powermail_additional//0870; type=boolean; label= Debug Mails: Show all mail values in Devlog + debugMail = 0 + # cat=powermail_additional//0880; type=boolean; label= Debug Save to Table: Show all values if you want to save powermail variables to another table in Devlog + debugSaveToTable = 0 - ############################################################## - ### EXAMPLE for building a relation to tt_address_group ### - ### over the MM table tt_address_group_mm ### - ### Add relation to an existing address group with uid 123 ### - ############################################################## + # cat=powermail_additional//0890; type=boolean; label= Debug Spamshield: Show Spamshield Functions in Devlog + debugSpamshield = 0 + } - 2 { - # Enable or disable db entry for table tt_address_group_mm - # _enable = TEXT - # _enable.value = 1 + spamshield { + # cat=powermail_spam//0900; type=boolean; label= SpamShield Active: En- or disable Spamshield for Powermail + enable = 1 - # Set tableName to "tt_address_group_mm" - # _table = TEXT - # _table.value = tt_address_group_mm + # cat=powermail_spam//0910; type=int+; label= Spamshield Spamfactor in %: Set limit for spamfactor in powermail forms in % (e.g. 85) + factor = 75 - # Fill tt_address_group_mm.uid_local with uid of tt_address record from above configuration 1. (usage .field=uid_[key]) - # uid_local = TEXT - # uid_local.field = uid_1 + # cat=powermail_spam//0920; type=text; label= Spamshield Notifymail: Admin can get an email if he/she wants to get informed if a mail failed. Let this field empty and no mail will be sent (e.g. admin@mail.com) + email = - # Fill new record of table "tt_address_group_mm" with field "uid_foreign" with uid 123 - # uid_foreign = TEXT - # uid_foreign.value = 123 - } - } + # cat=powermail_spam//0925; type=text; label= Spamshield Notifymail sendermail: Define sender email address for mails + senderEmail = + # cat=powermail_spam//0930; type=text; label= Spamshield Notifymail Subject: Subject for notification Email to Admin + emailSubject = Spam in powermail form recognized - # Add own validator classes that will be called before create action (if you want to validate user input with own PHP classes) - validators { - # 1 { - # Classname that should be called with method *Validator() - # class = Vendor\Ext\Domain\Model\DoSomethingValidator + # cat=powermail_spam//0940; type=text; label= Spamshield Notifymail Template: Template for notification Email to Admin + emailTemplate = EXT:powermail/Resources/Private/Templates/Mail/SpamNotification.html - # optional: Add configuration for your PHP - # config { - # foo = bar + # cat=powermail_spam//0950; type=text; label= Spamshield Log Template Location: Path of log file, ie. typo3temp/logs/powermail_spam.log, if empty, logging is deactivated + logfileLocation = - # fooCObject = TEXT - # fooCObject.value = do something with this text - # } + # cat=powermail_spam//0960; type=text; label= Spamshield Log Template: Template for entries written to log file + logTemplate = EXT:powermail/Resources/Private/Templates/Log/SpamNotification.html + } - # optional: If file will not be loaded from autoloader, add path and it will be called with require_once - # require = fileadmin/powermail/validator/DoSomethingValidator.php - # } - } + captcha { + # cat=powermail_spam//0930; type=text; label= Captcha Background: Set own captcha background image (e.g. fileadmin/bg.png) + image = EXT:powermail/Resources/Private/Image/captcha_bg.png + # cat=powermail_spam//0940; type=text; label= Captcha Font: Set TTF-Font for captcha image (e.g. fileadmin/font.ttf) + font = EXT:powermail/Resources/Private/Fonts/Segment16cBold.ttf - # dataProcessor classes that will be called before the mail object will be persisted and used in mails - dataProcessors { - # Powermail data processors - 10.class = In2code\Powermail\DataProcessor\UploadDataProcessor - 20.class = In2code\Powermail\DataProcessor\SessionDataProcessor + # cat=powermail_spam//0950; type=text; label= Captcha Text Color: Define your text color in hex code - must start with # (e.g. #ff0000) + textColor = #111111 - # Add your own data processor classes (e.g. if you want to do something with form values by your own before they are used in powermail to persist or in mails) - # 1 { - # Classname that should be called with method *Finisher() - # class = Vendor\Ext\Finisher\DoSomethingFinisher + # cat=powermail_spam//0960; type=int+; label= Captcha Text Size: Define your text size in px (e.g. 24) + textSize = 32 - # optional: Add configuration for your PHP - # config { - # foo = bar + # cat=powermail_spam//0970; type=text; label= Captcha Text Angle: Define two different values (start and stop) for your text random angle and separate it with a comma (e.g. -10,10) + textAngle = -5,5 - # fooCObject = TEXT - # fooCObject.value = do something with this text - # } + # cat=powermail_spam//0980; type=text; label= Captcha Text Distance Hor: Define two different values (start and stop) for your text horizontal random distance and separate it with a comma (e.g. 20,80) + distanceHor = 20,100 - # optional: If file will not be loaded from autoloader, add path and it will be called with require_once - # require = fileadmin/powermail/finisher/DoSomethingFinisher.php - # } - } + # cat=powermail_spam//0990; type=text; label= Captcha Text Distance Ver: Define two different values (start and stop) for your text vertical random distance and separate it with a comma (e.g. 30,60) + distanceVer = 30,45 + } + # CSS classes for frameworks (add only if bootstrapClassesAndLayout is not added before) + styles { + framework { + # cat=powermail_styles//0020; type=int+; label= Number of columns + numberOfColumns = 0 - # Finisher classes that will be called after submit - finishers { - # Powermail finishers - 10.class = In2code\Powermail\Finisher\SaveToAnyTableFinisher - 20.class = In2code\Powermail\Finisher\SendParametersFinisher - 100.class = In2code\Powermail\Finisher\RedirectFinisher + # cat=powermail_styles//0100; type=text; label= Framework classname(s) for containers to build rows + rowClasses = row - # Add your own finishers classes (e.g. if you want to do something with form values by your own: Save into tables, call an API, make your own redirect etc...) - # 1 { - # Classname that should be called with method *Finisher() - # class = Vendor\Ext\Finisher\DoSomethingFinisher + # cat=powermail_styles//0105; type=text; label= Framework classname(s) for form "form-horizontal" + formClasses = - # optional: Add configuration for your PHP - # config { - # foo = bar + # cat=powermail_styles//0110; type=text; label= Framework classname(s) for overall wrapping container of a field/label pair e.g. "row form-group" + fieldAndLabelWrappingClasses = - # fooCObject = TEXT - # fooCObject.value = do something with this text - # } + # cat=powermail_styles//0120; type=text; label= Framework classname(s) for wrapping container of a field e.g. "row form-group" + fieldWrappingClasses = powermail_field - # optional: If file will not be loaded from autoloader, add path and it will be called with require_once - # require = fileadmin/powermail/finisher/DoSomethingFinisher.php - # } - } + # cat=powermail_styles//0130; type=text; label= Framework classname(s) for fieldlabels e.g. "col-md-2 col-md-3" + labelClasses = powermail_label + # cat=powermail_styles//0140; type=text; label= Framework classname(s) for fields e.g. "form-control" + fieldClasses = - # Switch on or off Debug mode (use extension devlog to view this values) - debug { - # All views: Show Settings from TypoScript, Flexform and Extension Manager - settings = {$plugin.tx_powermail.settings.misc.debugSettings} + # cat=powermail_styles//0150; type=text; label= Framework classname(s) for fields with an offset e.g. "col-sm-offset-2" + offsetClasses = - # Create view: Show submitted variables - variables = {$plugin.tx_powermail.settings.misc.debugVariables} + # cat=powermail_styles//0160; type=text; label= Framework classname(s) especially for radiobuttons e.g. "radio" + radioClasses = radio - # Create view: Show complete mail settings - mail = {$plugin.tx_powermail.settings.misc.debugMail} + # cat=powermail_styles//0170; type=text; label= Framework classname(s) especially for checkboxes e.g. "check" + checkClasses = checkbox - # Create view: Show saveToTable array - saveToTable = {$plugin.tx_powermail.settings.misc.debugSaveToTable} + # cat=powermail_styles//0180; type=text; label= Framework classname(s) for the submit button e.g. "btn btn-primary" + submitClasses = powermail_submit - # Create view: Show spamtest results - spamshield = {$plugin.tx_powermail.settings.misc.debugSpamshield} + # cat=powermail_styles//0190; type=text; label= Framework classname(s) for "create" message after submit + createClasses = powermail_create } - - # Don't touch this (this is just to let the extension know, that there is TypoScript included) - staticTemplate = 1 - - # CSS classes for frameworks (add only if bootstrapClassesAndLayout is not added before) - styles { - numberOfColumns = {$plugin.tx_powermail.settings.styles.framework.numberOfColumns} - - framework { - rowClasses = {$plugin.tx_powermail.settings.styles.framework.rowClasses} - formClasses = {$plugin.tx_powermail.settings.styles.framework.formClasses} - fieldAndLabelWrappingClasses = {$plugin.tx_powermail.settings.styles.framework.fieldAndLabelWrappingClasses} - fieldWrappingClasses = {$plugin.tx_powermail.settings.styles.framework.fieldWrappingClasses} - labelClasses = {$plugin.tx_powermail.settings.styles.framework.labelClasses} - fieldClasses = {$plugin.tx_powermail.settings.styles.framework.fieldClasses} - offsetClasses = {$plugin.tx_powermail.settings.styles.framework.offsetClasses} - radioClasses = {$plugin.tx_powermail.settings.styles.framework.radioClasses} - checkClasses = {$plugin.tx_powermail.settings.styles.framework.checkClasses} - submitClasses = {$plugin.tx_powermail.settings.styles.framework.submitClasses} - createClasses = {$plugin.tx_powermail.settings.styles.framework.createClasses} - } + bootstrap { + # cat=powermail_styles//0200; type=boolean; label= Activate bootstrap classes (constants in {$plugin.tx_powermail.settings.styles.bootstrap.*} override {$plugin.tx_powermail.settings.styles.framework.*}) + important = 0 } } } } - -# ParseFunc Configuration for using FAL links in receiver and sender mail -lib.parseFunc_powermail < lib.parseFunc_RTE -lib.parseFunc_powermail.tags { - link.typolink.forceAbsoluteUrl = 1 - a.typolink.forceAbsoluteUrl = 1 -} - -# add jQuery if it was turned on in the constants -[{$plugin.tx_powermail.settings.javascript.addJQueryFromGoogle} == 1] -page.includeJSFooterlibs { - powermailJQuery = {$plugin.tx_powermail.settings.javascript.powermailJQuery} - powermailJQuery.external = 1 -} -[end] - -# add additional javascript libs, if it was turned on in the constants -[{$plugin.tx_powermail.settings.javascript.addAdditionalJavaScript} == 1] -page { - # Include JavaScript files - includeJSFooter { - powermailJQueryDatepicker = EXT:powermail/Resources/Public/JavaScript/Libraries/jquery.datetimepicker.min.js - powermailJQueryFormValidation = EXT:powermail/Resources/Public/JavaScript/Libraries/parsley.min.js - powermailJQueryTabs = EXT:powermail/Resources/Public/JavaScript/Powermail/Tabs.min.js - powermailForm = EXT:powermail/Resources/Public/JavaScript/Powermail/Form.min.js - } -} -[end] ``` diff --git a/Documentation/ForDevelopers/WriteOwnValidators.md b/Documentation/ForDevelopers/WriteOwnValidators.md index 5bfc3c4bc..4961d99ea 100644 --- a/Documentation/ForDevelopers/WriteOwnValidators.md +++ b/Documentation/ForDevelopers/WriteOwnValidators.md @@ -2,13 +2,13 @@ ## Introduction -Since powermail 2.1 a combination of different validation types is possible: +In powermail a combination of different validation types is possible: - Serverside Validation (PHP) - Clientside Validation (JavaScript) - Clientside Validation (Native with HTML5) -You can enable or disable or combine some of the validation via TypoScript +You can enable or disable or combine some of the validation methods via TypoScript ``` plugin.tx_powermail.settings.setup { @@ -21,8 +21,7 @@ plugin.tx_powermail.settings.setup { ``` -Parsley.js allows us to have a robust solution for JavaScript and Native HTML5 -Validation +Meanwhile we added an own robust JavaScript validation which also supports native HTML5 validation  @@ -33,8 +32,6 @@ Serverside Validation Example Clientside Validation Example -Want to learn more about Parsley.js? Look at https://parsleyjs.org/ - ## 1. Add a new validation type @@ -61,23 +58,36 @@ This leads to a new validation option for the editors: You will see a HTML-Code like this for this field -`` +`` Add a new Extension or simply a JavaScript File with this content. Please pay attention to the ordering. -This code must be included after all JavaScript of powermail. +This code must be included after all JavaScripts of powermail. ``` -window.ParsleyValidator -.addValidator('custom100', function (value, requirement) { -if (value >= 80000) { - return true; -} -return false; -}, 32) -.addMessage('en', 'custom100', 'Error'); +page.includeJSFooter.powermailextended = EXT:powermailextended/Resources/Public/JavaScripts/ZipValidation.js +page.includeJSFooter.powermailextended.defer = 1 +``` + +``` +/** + * Add a ZIP validation to all powermail forms on the current page and listen to those fields: + * + */ +const forms = document.querySelectorAll('.powermail_form'); +forms.forEach(function(form) { + let formValidation = form.powermailFormValidation; + + formValidation.addValidator('custom100', function(field) { + if (field.hasAttribute('data-powermail-custom100')) { + // return true means validation has failed + return field.value < parseInt(field.getAttribute('data-powermail-custom100')); + } + return false; + }); +}); ``` -See Extension powermailextended.zip in your powermail folder powermail/Resources/Private/Software/ +See Extension powermailextended https://github.com/einpraegsam/powermailextended for details ### Add new PHP Validation @@ -359,13 +369,13 @@ This extension allows you to: A global validator is something that could normally not be selected by an editor. -### Parsley Introduction +### Javascript validation introduction -Example form, validated with parsley.js, with a required and an email field. -In addition to HTML5, this input fields are validated with parsley: +Example form, validated with form validation framework, with a required and an email field. +In addition to HTML5, this input fields are validated now: ``` -
``` -### Own Parsley Validator +### Own JavaScript validator #### Quick example @@ -382,14 +392,17 @@ See how you can relate a JavaScript validator to a field with a data-attribute. message also via data-attribute: ``` - + [...] ``` @@ -416,7 +429,7 @@ The example fluid template (partial): id="powermail_field_{field.marker}" property="{field.marker}" value="" - additionalAttributes="{data-parsley-emailverification-message:'{f:translate(key:\'powermail.validation.emailverification\',extensionName:\'In2template\')}',data-parsley-emailverification:'{field.marker}_mirror'}" + additionalAttributes="{data-powermail-emailverification-message:'{f:translate(key:\'powermail.validation.emailverification\',extensionName:\'In2template\')}',data-powermail-emailverification:'{field.marker}_mirror'}" class="powermail_emailverification {settings.styles.framework.fieldClasses} {vh:Validation.ErrorClass(field:field, class:'powermail_field_error')}" /> @@ -432,7 +445,7 @@ The example fluid template (partial): id="powermail_field_{field.marker}_mirror" property="{field.marker}_mirror" value="" - additionalAttributes="{data-parsley-emailverification-message:'{f:translate(key:\'powermail.validation.emailverification\',extensionName:\'In2template\')}',data-parsley-emailverification:'{field.marker}'}" + additionalAttributes="{data-powermail-emailverification-message:'{f:translate(key:\'powermail.validation.emailverification\',extensionName:\'In2template\')}',data-powermail-emailverification:'{field.marker}'}" class="powermail_emailverification {settings.styles.framework.fieldClasses} {vh:Validation.ErrorClass(field:field, class:'powermail_field_error')}" /> @@ -443,34 +456,22 @@ The example fluid template (partial): The example JavaScript: ``` -/** - * @returns {void} - */ -var addEmailVerificationValidation = function() { - window.Parsley.addValidator('emailverification', { - validateString: function(value, markerMirror) { - return value === getMirrorValue(markerMirror); - }, - requirementType: 'string' - }); -}; - -/** - * @param {string} marker - * @returns {string} - */ -var getMirrorValue = function(marker) { - var elements = document.querySelectorAll('input[name="tx_powermail_pi1[field][' + marker + ']"]'); - return elements[0].value; -}; + ``` -### Documentation - -Look at http://parsleyjs.org/doc/examples/customvalidator.html for more examples of individual parsley.js validation - - ### Example Code Look at https://github.com/einpraegsam/powermailextended for an example extension. diff --git a/Documentation/ForEditors/FieldDate.md b/Documentation/ForEditors/FieldDate.md index 8c7c1b543..6a813ee1f 100644 --- a/Documentation/ForEditors/FieldDate.md +++ b/Documentation/ForEditors/FieldDate.md @@ -2,7 +2,7 @@ ## What does it do? -- **General:** Do you want to render a datepicker for date (or datetime or time), you can use this field type. Per default html5 date fields are used with a JavaScript fallback. If you want to force the JavaScript Datepicker, you can use TypoScript. Dateformat will change by the frontend language. You can use TypoScript to use any dateformat (locallang.xlf). +- **General:** Do you want to render a datepicker for date (or datetime or time), you can use this field type. Per default html5 date fields are used in modern browsers. ## Frontend Output Example @@ -33,16 +33,7 @@ ## Date Formats -If you use a browser, that support modern date fields (e.g. Chrome), -JavaScript Datepicker will not be loaded by default. -In this case the Browser takes the configured language of the OS to set the date-format automaticly. -There is no change to define another dateformat. - -But it's possible to enforce the JavaScript Datepicker even in Chrome with a line of TypoScript Constants: - -`plugin.tx_powermail.settings.misc.forceJavaScriptDatePicker = 1` - -Beside that, you can define the dateformat for the JavaScript Datepicker. +You can define the dateformat for the JavaScript Datepicker. Depending on the datepicker settings (date, datetime, time), there are different entries in the locallang files. You can overwrite that via TypoScript: diff --git a/Documentation/ForEditors/FieldInput.md b/Documentation/ForEditors/FieldInput.md index c1958441c..fb085c1a9 100644 --- a/Documentation/ForEditors/FieldInput.md +++ b/Documentation/ForEditors/FieldInput.md @@ -44,7 +44,7 @@ Administrator can enable or disable the validation in general with TypoScript (see TypoScript part in manual). - HTML5 Validation -- Clientside Validation with JavaScript (see parsleyjs.org) +- Clientside Validation with own JavaScript framework - Serverside Validation with PHP | Validation Type | Description | Examples | Note | diff --git a/Readme.md b/Readme.md index 898f9c847..30c07aaf9 100644 --- a/Readme.md +++ b/Readme.md @@ -60,15 +60,16 @@ Quick guide: | Powermail | TYPO3 | PHP | Support/Development | | ------------------- | ---------- | ----------|------------------------------------------------ | -| 9.x | 11.x | 7.4 | Features, Bugfixes, Security Updates | +| 10.x | 11.x | >= 7.4 | Features, Bugfixes, Security Updates | +| 9.x | 11.x | >= 7.4 | Support dropped | | 8.x | 10.x | >= 7.2 | Security Updates (paid backports are possible) | | 7.x | 8.7 - 9.x | 7.0 - 7.x | Security Updates (paid backports are possible) | | 6.x | 8.7 - 9.x | 7.0 - 7.x | Support dropped | | 5.x | 8.7 - 9.x | 7.0 - 7.x | Support dropped | | 4.x | 7.6 - 8.7 | 5.5 - 7.2 | Security Updates (paid backports are possible) | -| 3.x | 7.6 - 8.7 | 5.5 - 7.2 | Support dropped | -| 2.18 - 2.25 | 6.2 - 7.6 | 5.5 - 7.0 | Support dropped | -| 2.2 - 2.17 | 6.2 - 7.6 | 5.3 - 7.0 | Support dropped | +| 3.x | 7.6 - 8.7 | 5.5 - 7.2 | Support dropped | +| 2.18 - 2.25 | 6.2 - 7.6 | 5.5 - 7.0 | Support dropped | +| 2.2 - 2.17 | 6.2 - 7.6 | 5.3 - 7.0 | Support dropped | Do you need free support? There is a kind TYPO3 community that could help you. You can ask questions at https://stackoverflow.com and tag your question with `TYPO3` and `Powermail`. diff --git a/Resources/Private/Build/.babelrc b/Resources/Private/Build/.babelrc new file mode 100644 index 000000000..bbc5723e4 --- /dev/null +++ b/Resources/Private/Build/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [["@babel/preset-env", { + "modules": false + }]] +} diff --git a/Resources/Private/Build/.nvmrc b/Resources/Private/Build/.nvmrc new file mode 100644 index 000000000..8351c1939 --- /dev/null +++ b/Resources/Private/Build/.nvmrc @@ -0,0 +1 @@ +14 diff --git a/Resources/Private/JavaScript/Powermail/Backend.js b/Resources/Private/Build/JavaScript/Backend.js similarity index 93% rename from Resources/Private/JavaScript/Powermail/Backend.js rename to Resources/Private/Build/JavaScript/Backend.js index f687558ca..f47042152 100644 --- a/Resources/Private/JavaScript/Powermail/Backend.js +++ b/Resources/Private/Build/JavaScript/Backend.js @@ -23,7 +23,6 @@ function PowermailBackend($) { addDeleteLinesListener(); addToggleLinesVisibilityListener(); addExtendedSearchListener(); - addDatePickerListener(); addExportListener(); addConverterDetailsOpenListener(); hidePasswords(); @@ -226,42 +225,6 @@ function PowermailBackend($) { }); }; - /** - * Add datepicker to date fields - * - * @returns {void} - * @private - */ - var addDatePickerListener = function() { - if ($.fn.datetimepicker) { - $('input[data-datepicker="true"]').each(function () { - var $this = $(this); - var datepickerStatus = true; - var timepickerStatus = true; - if ($this.data('datepicker-settings') === 'date') { - timepickerStatus = false; - } else if ($this.data('datepicker-settings') === 'time') { - datepickerStatus = false; - } - $this.datetimepicker({ - format: $this.data('datepicker-format'), - timepicker: timepickerStatus, - datepicker: datepickerStatus, - lang: 'en', - i18n: { - en: { - months: $this.data('datepicker-months').split(','), - dayOfWeek: $this.data('datepicker-days').split(',') - } - } - }); - }); - $('*[data-datepicker-opener="true"]').click(function () { - $(this).prev().datetimepicker('show'); - }); - } - }; - /** * Add export functions * @@ -671,7 +634,6 @@ define( [ 'jquery', 'TYPO3/CMS/Powermail/Libraries/jquery-ui.min', - 'TYPO3/CMS/Powermail/Libraries/jquery.datetimepicker.min', 'TYPO3/CMS/Powermail/Libraries/jquery.flot.min', 'TYPO3/CMS/Powermail/Libraries/jquery.flot.pie.min', 'TYPO3/CMS/Powermail/Libraries/bootstrap.min', diff --git a/Resources/Private/Build/JavaScript/Form.js b/Resources/Private/Build/JavaScript/Form.js new file mode 100644 index 000000000..0c5f60ce1 --- /dev/null +++ b/Resources/Private/Build/JavaScript/Form.js @@ -0,0 +1,210 @@ +import Utility from './Utility'; +import MoreStepForm from './MoreStepForm'; +import FormValidation from './FormValidation'; +import moment from 'moment'; + +class PowermailForm { + 'use strict'; + + initialize = function () { + const that = this; + that.#formValidationListener(); + that.#moreStepFormListener(); + that.#ajaxSubmitListener(); + that.#locationFieldListener(); + that.#hidePasswordsListener(); + that.#deleteAllFilesListener(); + that.#prefillDateFieldsListener(); + }; + + #formValidationListener() { + let formValidation = new FormValidation(); + formValidation.validate(); + }; + + #moreStepFormListener() { + let moreStepForm = new MoreStepForm(); + moreStepForm.initialize(); + }; + + #ajaxSubmitListener() { + const that = this; + const forms = document.querySelectorAll('form[data-powermail-ajax]'); + forms.forEach(function(form) { + form.addEventListener('submit', function(event) { + event.preventDefault(); + if (form.classList.contains('powermail_form_error') === false) { + const url = form.getAttribute('action'); + const formUid = form.getAttribute('data-powermail-form'); + const redirectUri = form.getAttribute('data-powermail-ajax-uri'); + that.#addProgressbar(form); + + fetch(url, {body: new FormData(form), method: 'post'}) + .then((resp) => resp.text()) + .then(function(data) { + const parser = new DOMParser(); + const htmlDocument = parser.parseFromString(data, 'text/html'); + const section = htmlDocument.documentElement.querySelector('[data-powermail-form="' + formUid + '"]'); + if (section !== null) { + const container = document.querySelector('[data-powermail-form="' + formUid + '"]') + .closest('.tx-powermail'); + container.innerHTML = ''; + container.appendChild(section); + } else { + // no form markup found try to redirect via javascript + if (redirectUri !== null) { + Utility.redirectToUri(redirectUri); + } else { + // fallback if no location found (but will effect 2x submit) + form.submit(); + } + } + + // Fire existing listener again + that.#ajaxSubmitListener(); + that.#formValidationListener(); + that.#moreStepFormListener(); + that.#reloadCaptchaImages(); + }) + .catch(function(error) { + console.log(error); + }); + } + }); + }); + }; + + #locationFieldListener() { + if (document.querySelector('[data-powermail-location="prefill"]') !== null) { + navigator.geolocation.getCurrentPosition(function(position) { + let lat = position.coords.latitude; + let lng = position.coords.longitude; + let base = document.querySelector('[data-powermail-eidurl]').getAttribute('data-powermail-eidurl'); + let url = base + '?eID=' + 'powermailEidGetLocation&lat=' + lat + '&lng=' + lng; + + fetch(url) + .then((resp) => resp.text()) + .then(function(data) { + let elements = document.querySelectorAll('[data-powermail-location="prefill"]'); + for (let i = 0; i < elements.length; i++) { + elements[i].value = data; + } + }) + .catch(function(error) { + console.log(error); + }); + }); + } + }; + + #addProgressbar(form) { + this.#removeProgressbar(form); + const submit = form.querySelector('.powermail_submit'); + if (submit !== null) { + submit.parentNode.appendChild(this.#getProgressbar()); + } else { + const powermailContainer = form.closest('.tx-powermail'); + if (powermailContainer !== null) { + powermailContainer.appendChild(this.#getProgressbar()); + } + } + }; + + #removeProgressbar(form) { + const powermailContainer = form.closest('.tx-powermail'); + if (powermailContainer !== null) { + const progressbar = powermailContainer.querySelector('.powermail_progressbar'); + if (progressbar !== null) { + progressbar.remove(); + } + } + }; + + #getProgressbar() { + const outer = document.createElement('div'); + outer.classList.add('powermail_progressbar'); + const center = document.createElement('div'); + center.classList.add('powermail_progress'); + const inner = document.createElement('div'); + inner.classList.add('powermail_progress_inner'); + outer.appendChild(center); + center.appendChild(inner); + return outer; + }; + + #hidePasswordsListener() { + let elements = document.querySelectorAll('.powermail_all_type_password.powermail_all_value'); + for (let i = 0; i < elements.length; i++) { + elements[i].innerText = '********'; + } + }; + + #reloadCaptchaImages() { + const images = document.querySelectorAll('img.powermail_captchaimage'); + images.forEach(function(image) { + let source = Utility.getUriWithoutGetParam(image.getAttribute('src')); + image.setAttribute('src', source + '?hash=' + Utility.getRandomString(5)); + }); + }; + + #deleteAllFilesListener() { + const that = this; + const deleteAllFiles = document.querySelectorAll('.deleteAllFiles'); + deleteAllFiles.forEach(function(file) { + let fileWrapper = file.closest('.powermail_fieldwrap_file'); + if (fileWrapper !== null) { + let element = fileWrapper.querySelector('input[type="file"]'); + that.#disableUploadField(element); + } + + file.addEventListener('click', function() { + let fileWrapper = file.closest('.powermail_fieldwrap_file'); + if (fileWrapper !== null) { + let element = fileWrapper.querySelector('input[type="hidden"]'); + that.#enableUploadField(element); + } + let ul = file.closest('ul'); + if (ul !== null) { + ul.remove(); + } + }); + }); + }; + + #prefillDateFieldsListener() { + const forms = document.querySelectorAll('form.powermail_form'); + forms.forEach(function(form) { + let fields = form.querySelectorAll('input'); + fields.forEach(function(field) { + const type = field.getAttribute('type'); + if (type === 'date' || type === 'datetime-local' || type === 'time') { + let formatOutput = 'YYYY-MM-DD'; + if (type === 'datetime-local') { + formatOutput = 'YYYY-MM-DD\THH:mm'; + } else if (type === 'time') { + formatOutput = 'HH:mm'; + } + let value = field.getAttribute('data-date-value'); + if (value !== null) { + let formatInput = field.getAttribute('data-datepicker-format'); + let momentDate = moment(value, formatInput); + if (momentDate.isValid) { + field.value = momentDate.format(formatOutput); + } + } + } + }); + }); + }; + + #disableUploadField($element) { + $element.prop('disabled', 'disabled').addClass('hide').prop('type', 'hidden'); + }; + + #enableUploadField($element) { + $element.prop('disabled', false).removeClass('hide').prop('type', 'file'); + }; +} + +let powermailForm = new PowermailForm(); +powermailForm.initialize(); diff --git a/Resources/Private/Build/JavaScript/FormValidation.js b/Resources/Private/Build/JavaScript/FormValidation.js new file mode 100644 index 000000000..147652b50 --- /dev/null +++ b/Resources/Private/Build/JavaScript/FormValidation.js @@ -0,0 +1,473 @@ +import Utility from './Utility'; + +export default class FormValidation { + #formValidationSelector = '[data-powermail-validate]'; + + validate() { + const forms = document.querySelectorAll(this.#formValidationSelector); + forms.forEach(function(form) { + form = new Form(form); + form.validate(); + }); + }; +} + + +class Form { + 'use strict'; + + /** + * Form element (filled via constructor) + */ + #form; + + /** + * Has form any errors? + * + * @type {boolean} + */ + #error = false; + + /** + * List all fieldnames and errors + * @type {{}} + */ + #errorFields = {}; + + #formErrorClass = 'powermail_form_error'; + #fieldsetErrorClass = 'powermail_fieldset_error'; + #fieldErrorClass = 'powermail_field_error'; + #errorContainerClass = 'data-powermail-class-handler'; + #errorMessageContainerClass = 'powermail-errors-list'; + + constructor(form) { + this.#form = form; + this.#form.powermailFormValidation = this; + } + + validate() { + this.#validateFormSubmit(); + this.#validateFieldListener(); + } + + /** + * Add possibility to add own validators from outside like: + * + * const forms = document.querySelectorAll('.powermail_form'); + * forms.forEach(function(form) { + * let formValidation = form.powermailFormValidation; + * + * formValidation.addValidator('custom100', function(field) { + * if (field.hasAttribute('data-powermail-custom100')) { + * // return true means validation has failed + * return field.value < parseInt(field.getAttribute('data-powermail-custom100')); + * } + * return false; + * }); + * }); + * + * @param name + * @param validator + */ + addValidator(name, validator) { + this.#validators[name] = validator; + } + + #validateFormSubmit() { + const that = this; + this.#form.setAttribute('novalidate', 'novalidate') + this.#form.addEventListener('submit', function(event) { + that.#validateForm(); + if (that.#hasFormErrors() === true) { + event.preventDefault(); + } + }) + }; + + #validateFieldListener() { + const fields = this.#getFieldsFromForm(); + fields.forEach((field) => { + field.addEventListener('input', () => { + // When user types something in a field + this.#validateField(field); + }); + field.addEventListener('blur', () => { + // When field focus gets lost + this.#validateField(field); + }); + field.addEventListener('change', () => { + // When a checkbox, radiobutton or option in a select was chosen + this.#validateField(field); + }); + }); + }; + + #validateForm() { + let fields = this.#getFieldsFromForm(); + for (let i = 0; i < fields.length; i++) { + this.#validateField(fields[i]); + } + }; + + /** + * Validator configuration + * + * @type {{name: function(*=, *): boolean}} + */ + #validators = { + 'required': (field) => { + return this.#isRequiredField(field) && this.#isValidationRequiredConfirmed(field) === false; + }, + 'email': (field) => { + return this.#isEmailField(field) && this.#isValidationEmailConfirmed(field) === false; + }, + 'url': (field) => { + return this.#isUrlField(field) && this.#isValidationUrlConfirmed(field) === false; + }, + 'pattern': (field) => { + return this.#isPatternField(field) && this.#isValidationPatternConfirmed(field) === false; + }, + 'number': (field) => { + return this.#isNumberField(field) && this.#isValidationNumberConfirmed(field) === false; + }, + 'minimum': (field) => { + return this.#isMinimumField(field) && this.#isValidationMinimumConfirmed(field) === false; + }, + 'maximum': (field) => { + return this.#isMaximumField(field) && this.#isValidationMaximumConfirmed(field) === false; + }, + 'length': (field) => { + return this.#isLengthField(field) && this.#isValidationLengthConfirmed(field) === false; + }, + 'equalto': (field) => { + return this.#isEqualtoField(field) && this.#isValidationEqualtoConfirmed(field) === false; + }, + 'powermailfilesize': (field) => { + return this.#isUploadField(field) && this.#isValidationUploadFieldSizeConfirmed(field) === false; + }, + 'powermailfileextensions': (field) => { + return this.#isUploadField(field) && this.#isValidationUploadFieldExtensionConfirmed(field) === false; + }, + }; + + #validateField(field) { + let error = false; + field = this.#getValidationField(field); + + for (let validator in this.#validators) { + if (this.#validators.hasOwnProperty(validator) === false) { + continue; + } + error = this.#runValidator(validator, this.#validators[validator], field, error); + } + + this.#addFieldErrorStatus(field, error); + this.#calculateError(); + this.#updateErrorClassesForFormAndFieldsets(field); + }; + + #runValidator(name, validator, field, error) { + if (error === true) { + return error; + } + error = validator(field); + error ? this.#setError(name, field) : this.#removeError(name, field); + return error; + } + + /* + * Check for validations + */ + + #isRequiredField(field) { + return field.hasAttribute('required') || field.getAttribute('data-powermail-required') === 'true'; + }; + + #isEmailField(field) { + return field.getAttribute('type') === 'email' || field.getAttribute('data-powermail-type') === 'email'; + }; + + #isUrlField(field) { + return field.getAttribute('type') === 'url' || field.getAttribute('data-powermail-type') === 'url'; + }; + + #isPatternField(field) { + return field.hasAttribute('pattern') || field.hasAttribute('data-powermail-pattern'); + }; + + #isNumberField(field) { + return field.getAttribute('type') === 'number' || field.getAttribute('data-powermail-type') === 'integer'; + }; + + #isMinimumField(field) { + return field.hasAttribute('min') || field.hasAttribute('data-powermail-min'); + }; + + #isMaximumField(field) { + return field.hasAttribute('max') || field.hasAttribute('data-powermail-max'); + }; + + #isLengthField(field) { + return field.hasAttribute('data-powermail-length'); + }; + + #isEqualtoField(field) { + return field.hasAttribute('data-powermail-equalto'); + }; + + #isUploadField(field) { + return field.getAttribute('type') === 'file'; + }; + + /* + * Single validators + */ + + #isValidationRequiredConfirmed(field) { + return this.#getFieldValue(field) !== ''; + }; + + #isValidationEmailConfirmed(field) { + if (field.value === '') { + return true; + } + let pattern = /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; + let constraint = new RegExp(pattern, ''); + return constraint.test(this.#getFieldValue(field)); + }; + + #isValidationUrlConfirmed(field) { + if (field.value === '') { + return true; + } + let pattern = '^(https?:\\/\\/)?'+ // protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name + '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path + '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string + '(\\#[-a-z\\d_]*)?$' + let constraint = new RegExp(pattern, ''); + return constraint.test(this.#getFieldValue(field)); + }; + + #isValidationPatternConfirmed(field) { + if (field.value === '') { + return true; + } + let pattern = field.getAttribute('data-powermail-pattern') || field.getAttribute('pattern'); + let constraint = new RegExp(pattern, ''); + return constraint.test(this.#getFieldValue(field)); + }; + + #isValidationNumberConfirmed(field) { + if (field.value === '') { + return true; + } + return isNaN(field.value) === false; + }; + + #isValidationMinimumConfirmed(field) { + if (field.value === '') { + return true; + } + let minimum = field.getAttribute('min') || field.getAttribute('data-powermail-min'); + return parseInt(field.value) >= parseInt(minimum); + }; + + #isValidationMaximumConfirmed(field) { + if (field.value === '') { + return true; + } + let maximum = field.getAttribute('max') || field.getAttribute('data-powermail-max'); + return parseInt(field.value) <= parseInt(maximum); + }; + + #isValidationLengthConfirmed(field) { + if (field.value === '') { + return true; + } + let lengthConfiguration = field.getAttribute('data-powermail-length'); + let length = lengthConfiguration.replace('[', '').replace(']', '').split(','); + let minimum = length[0].trim(); + let maximum = length[1].trim(); + return parseInt(field.value.length) >= parseInt(minimum) && parseInt(field.value.length) <= parseInt(maximum); + }; + + #isValidationEqualtoConfirmed(field) { + const comparisonSelector = field.getAttribute('data-powermail-equalto'); + const comparisonField = this.#form.querySelector(comparisonSelector); + if (comparisonField !== null) { + return comparisonField.value === field.value; + } + return false; + }; + + #isValidationUploadFieldSizeConfirmed(field) { + if (field.value === '') { + return true; + } + let size = Utility.getLargestFileSize(field); + let sizeConfiguration = field.getAttribute('data-powermail-powermailfilesize').split(','); + return size <= parseInt(sizeConfiguration[0]); + }; + + #isValidationUploadFieldExtensionConfirmed(field) { + if (field.value === '') { + return true; + } + return Utility.isFileExtensionInList(Utility.getExtensionFromFileName(field.value), field.getAttribute('accept')); + }; + + /** + * @param type like "required" or "pattern" + * @param field + */ + #setError(type, field) { + this.#removeError(type, field); + this.#addErrorClass(field); + let message = field.getAttribute('data-powermail-' + type + '-message') || + field.getAttribute('data-powermail-error-message') || 'Validation error'; + this.#addErrorMessage(message, field); + }; + + /** + * @param type like "required" or "pattern" + * @param field + */ + #removeError(type, field) { + this.#removeErrorClass(field); + this.#removeErrorMessages(field); + }; + + #addErrorClass(field) { + if (field.getAttribute(this.#errorContainerClass)) { + let elements = document.querySelectorAll(field.getAttribute(this.#errorContainerClass)); + for (let i = 0; i < elements.length; i++) { + elements[i].classList.add(this.#fieldErrorClass); + } + } else { + field.classList.add(this.#fieldErrorClass); + } + }; + + #removeErrorClass(field) { + if (field.getAttribute(this.#errorContainerClass)) { + let elements = document.querySelectorAll(field.getAttribute(this.#errorContainerClass)); + for (let i = 0; i < elements.length; i++) { + elements[i].classList.remove(this.#fieldErrorClass); + } + } else { + field.classList.remove(this.#fieldErrorClass); + } + }; + + #addErrorMessage(message, field) { + let errorContainer = document.createElement('ul'); + errorContainer.classList.add(this.#errorMessageContainerClass); + errorContainer.classList.add('filled'); + errorContainer.setAttribute('data-powermail-error', this.#getFieldIdentifier(field)); + let errorElement = document.createElement('li'); + errorContainer.appendChild(errorElement); + let textNode = document.createTextNode(message); + errorElement.appendChild(textNode); + + if (field.getAttribute('data-powermail-errors-container') !== null) { + let parentContainer = document.querySelector(field.getAttribute('data-powermail-errors-container')); + if (parentContainer !== null) { + parentContainer.appendChild(errorContainer); + } + } else { + field.parentNode.appendChild(errorContainer); + } + }; + + #removeErrorMessages(field) { + let errorMessageContainer = document.querySelector( + '[data-powermail-error="' + this.#getFieldIdentifier(field) + '"]' + ); + if (errorMessageContainer !== null) { + errorMessageContainer.remove(); + } + }; + + #getFieldValue(field) { + let value = field.value; + + // Special case radiobuttons & checkboxes: take value from selected field + if (field.getAttribute('type') === 'radio' || field.getAttribute('type') === 'checkbox') { + value = ''; + let name = field.getAttribute('name'); + let form = field.closest('form'); + let selectedField = form.querySelector('input[name="' + name + '"]:checked'); + if (selectedField !== null) { + value = selectedField.value; + } + } + return value; + }; + + #getFieldIdentifier(field) { + let name = field.getAttribute('name'); + return name.replace(/[^\w\s]/gi, ''); + }; + + #getFieldsFromForm() { + return this.#form.querySelectorAll( + 'input:not([data-powermail-validation="disabled"]):not([type="hidden"]):not([type="submit"])' + + ', textarea:not([data-powermail-validation="disabled"])' + + ', select:not([data-powermail-validation="disabled"])' + ); + }; + + /** + * Special case for radiobuttons & checkboxes: take first field + * + * @param field + * @returns {*} + */ + #getValidationField(field) { + if (field.getAttribute('type') === 'radio' || field.getAttribute('type') === 'checkbox') { + let name = field.getAttribute('name'); + let form = field.closest('form'); + let fields = form.querySelectorAll('[name="' + name + '"]'); + field = fields[0]; + } + return field; + }; + + #hasFormErrors() { + return this.#error; + } + + #addFieldErrorStatus(field, error) { + this.#errorFields[field.getAttribute('name')] = error; + } + + #calculateError() { + let error = false; + for (let property in this.#errorFields) { + if (this.#errorFields.hasOwnProperty(property) === false) { + continue; + } + if (this.#errorFields[property] === true) { + error = true; + } + } + this.#error = error; + } + + #updateErrorClassesForFormAndFieldsets(field) { + const fieldset = field.closest('fieldset.powermail_fieldset'); + if (this.#hasFormErrors()) { + this.#form.classList.add(this.#formErrorClass); + if (fieldset !== null) { + fieldset.classList.add(this.#fieldsetErrorClass); + } + } else { + this.#form.classList.remove(this.#formErrorClass); + if (fieldset !== null) { + fieldset.classList.remove(this.#fieldsetErrorClass); + } + } + } +} diff --git a/Resources/Private/Build/JavaScript/Marketing.js b/Resources/Private/Build/JavaScript/Marketing.js new file mode 100644 index 000000000..30fd772a5 --- /dev/null +++ b/Resources/Private/Build/JavaScript/Marketing.js @@ -0,0 +1,34 @@ +class Marketing { + 'use strict'; + + initialize = function () { + const that = this; + that.#sendMarketingInformation(); + }; + + #sendMarketingInformation() { + const marketingInformation = document.querySelector('#powermail_marketing_information'); + const url = marketingInformation.getAttribute('data-url'); + let data = ''; + data += 'tx_powermail_pi1[language]=' + marketingInformation.getAttribute('data-language'); + data += '&id=' + marketingInformation.getAttribute('data-pid'); + data += '&tx_powermail_pi1[pid]=' + marketingInformation.getAttribute('data-pid'); + data += '&tx_powermail_pi1[mobileDevice]=' + (this.#isMobile() ? 1 : 0); + data += '&tx_powermail_pi1[referer]=' + encodeURIComponent(document.referrer); + + fetch(url, {method: 'POST', body: data, cache: 'no-cache'}); + }; + + #isMobile() { + var ua = navigator.userAgent; + var checker = { + iphone:ua.match(/(iPhone|iPod|iPad)/), + blackberry:ua.match(/BlackBerry/), + android:ua.match(/Android/) + }; + return (checker.iphone || checker.blackberry || checker.android); + }; +} + +let marketing = new Marketing(); +marketing.initialize(); diff --git a/Resources/Private/Build/JavaScript/MoreStepForm.js b/Resources/Private/Build/JavaScript/MoreStepForm.js new file mode 100644 index 000000000..27e6dd0d1 --- /dev/null +++ b/Resources/Private/Build/JavaScript/MoreStepForm.js @@ -0,0 +1,88 @@ +export default function MoreStepForm() { + 'use strict'; + + let formClass = 'powermail_morestep'; + + let fieldsetClass = 'powermail_fieldset'; + + let buttonActiveClass = 'btn-primary'; + + this.initialize = function() { + showListener(); + initializeForms(); + }; + + let initializeForms = function() { + let moreStepForms = document.querySelectorAll('form.' + formClass); + for (let i = 0; i < moreStepForms.length; i++) { + initializeForm(moreStepForms[i]); + } + }; + + let initializeForm = function(form) { + showFieldset(0, form); + }; + + let showListener = function() { + let moreButtons = document.querySelectorAll('[data-powermail-morestep-show]'); + for (let i = 0; i < moreButtons.length; i++) { + moreButtons[i].addEventListener('click', function(event) { + let targetFieldset = event.target.getAttribute('data-powermail-morestep-show'); + let form = event.target.closest('form'); + showFieldset(targetFieldset, form); + }); + } + } + + let showFieldset = function(index, form) { + hideAllFieldsets(form); + let fieldsets = getAllFieldsetsOfForm(form); + showElement(fieldsets[index]); + updateButtonStatus(form); + }; + + let hideAllFieldsets = function(form) { + let fieldsets = getAllFieldsetsOfForm(form); + for (let i = 0; i < fieldsets.length; i++) { + hideElement(fieldsets[i]); + } + }; + + let updateButtonStatus = function(form) { + let buttons = form.querySelectorAll('[data-powermail-morestep-current]'); + let activePageIndex = getActivePageIndex(form); + for (let i = 0; i < buttons.length; i++) { + buttons[i].classList.remove(buttonActiveClass); + if (i === activePageIndex) { + buttons[i].classList.add(buttonActiveClass); + } + } + }; + + /** + * Get index of current visible fieldset + * + * @param form + * @returns {number} + */ + let getActivePageIndex = function(form) { + let fieldsets = getAllFieldsetsOfForm(form); + for (let i = 0; i < fieldsets.length; i++) { + if (fieldsets[i].style.display !== 'none') { + return i; + } + } + } + + let getAllFieldsetsOfForm = function(form) { + return form.querySelectorAll('.' + fieldsetClass); + }; + + let hideElement = function(element) { + element.style.display = 'none'; + }; + + let showElement = function(element) { + element.style.display = 'block'; + }; +} diff --git a/Resources/Private/Build/JavaScript/Utility.js b/Resources/Private/Build/JavaScript/Utility.js new file mode 100644 index 000000000..51eeb92ab --- /dev/null +++ b/Resources/Private/Build/JavaScript/Utility.js @@ -0,0 +1,95 @@ +export default class Utility { + + /** + * Get largest filesize (if more then only one is selected) + * + * @param field + * @returns {number} + */ + static getLargestFileSize(field) { + let size = 0; + for (let i = 0; i < field.files.length; i++) { + let file = field.files[i]; + if (file.size > size) { + size = file.size; + } + } + return size; + } + + /** + * Check if fileextension is allowed in dotted list + * "jpg" in ".jpg,.jpeg" => true + * "jpg" in ".gif,.png" => false + * + * @param {string} extension + * @param {string} list + * @returns {boolean} + */ + static isFileExtensionInList(extension, list) { + return list.indexOf('.' + extension) !== -1; + }; + + /** + * Get extension from filename in lowercase + * image.jpg => jpg + * image.JPG => jpg + * + * @param {string} fileName + * @returns {string} + */ + static getExtensionFromFileName(fileName) { + return fileName.split('.').pop().toLowerCase(); + }; + + /** + * Get uri without get params + * + * @param {string} uri + * @returns {string} + */ + static getUriWithoutGetParam(uri) { + const parts = uri.split('?'); + return parts[0]; + }; + + /** + * Get random string + * + * @param {int} length + * @returns {string} + */ + static getRandomString(length) { + let text = ''; + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for (let i = 0; i < length; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; + }; + + /** + * Redirect to an external or internal target + * + * @param {string} redirectUri + */ + static redirectToUri(redirectUri) { + if (redirectUri.indexOf('http') !== -1) { + window.location = redirectUri; + } else { + window.location.pathname = redirectUri; + } + }; + + static hideElement(element) { + if (element !== null) { + element.style.display = 'none'; + } + } + + static showElement(element) { + if (element !== null) { + element.style.display = 'block'; + } + } +} diff --git a/Resources/Private/Build/gulpfile.js b/Resources/Private/Build/gulpfile.js new file mode 100644 index 000000000..870c9a330 --- /dev/null +++ b/Resources/Private/Build/gulpfile.js @@ -0,0 +1,73 @@ +/* jshint node: true */ +'use strict'; + +const { src, dest, watch, series, parallel } = require('gulp'); +const sass = require('gulp-sass')(require('node-sass')); +const rollup = require('rollup').rollup; +const rollupConfig = require('./rollup.config'); +const uglify = require('gulp-uglify'); +const plumber = require('gulp-plumber'); +const rename = require('gulp-rename'); + +const project = { + base: __dirname + '/../../Public', + css: __dirname + '/../../Public/Css', + js: __dirname + '/../../Public/JavaScript/Powermail', + images: __dirname + '/../../Public/Images' +}; + +// SCSS zu css +function css() { + const config = {}; + config.outputStyle = 'compressed'; + + return src(__dirname + '/../Sass/*.scss') + .pipe(plumber()) + .pipe(sass(config)) + .pipe(dest(project.css)); +}; + +function jsForm(done) { + rollup(rollupConfig).then(bundle => { + rollupConfig.output.plugins = rollupConfig + bundle.write(rollupConfig.output).then(() => done()); + }); +}; + +function jsMarketing() { + return src([__dirname + '/JavaScript/Marketing.js']) + .pipe(plumber()) + .pipe(uglify()) + .pipe(rename({ + suffix: '.min' + })) + .pipe(dest(project.js)); +}; + +function jsBackend() { + return src([__dirname + '/JavaScript/Backend.js']) + .pipe(plumber()) + .pipe(uglify()) + .pipe(rename({ + suffix: '.min' + })) + .pipe(dest(project.js)); +}; + +// "npm run build" +const build = series(jsForm, jsMarketing, jsBackend, css); + +// "npm run watch" +const def = parallel( + function watchSCSS() { return watch(__dirname + '/../Sass/**/*.scss', series(css)) }, + function watchJS() { return watch(__dirname + '/JavaScript/*.js', series(jsForm, jsMarketing)) } +); + +module.exports = { + default: def, + build, + css, + jsForm, + jsMarketing, + jsBackend, +}; diff --git a/Resources/Private/Build/package.json b/Resources/Private/Build/package.json new file mode 100644 index 000000000..8a0d27d3d --- /dev/null +++ b/Resources/Private/Build/package.json @@ -0,0 +1,28 @@ +{ + "name": "powermail", + "description": "Powermail is a well-known, editor-friendly, powerful and easy to use mailform extension for TYPO3 with a lots of features", + "author": "in2code", + "private": true, + "devDependencies": { + "@babel/core": "^7.16.0", + "@babel/preset-env": "^7.16.4", + "@rollup/plugin-babel": "^5.3.0", + "@rollup/plugin-commonjs": "^21.0.1", + "@rollup/plugin-node-resolve": "^13.0.6", + "gulp": "^4.0.2", + "gulp-plumber": "^1.2.1", + "gulp-rename": "^2.0.0", + "gulp-sass": "^5.0.0", + "gulp-uglify": "^3.0.2", + "node-sass": "^4.14.1", + "rollup": "^2.61.1", + "rollup-plugin-terser": "^7.0.2" + }, + "scripts": { + "build": "./node_modules/gulp/bin/gulp.js build", + "watch": "./node_modules/gulp/bin/gulp.js default" + }, + "dependencies": { + "moment": "^2.29.2" + } +} diff --git a/Resources/Private/Build/readme.md b/Resources/Private/Build/readme.md new file mode 100644 index 000000000..fcbf7cb5d --- /dev/null +++ b/Resources/Private/Build/readme.md @@ -0,0 +1,8 @@ +# How to start frontend toolchain + +## Small guide + +* Go to Recources/Private/Build +* `nvm use` will change to needed npm version +* `npm i` will install the node modules (if not yet installed) +* Then start with `npm run build` or the watch task with `npm run watch` diff --git a/Resources/Private/Build/rollup.config.js b/Resources/Private/Build/rollup.config.js new file mode 100644 index 000000000..90bdcb4e6 --- /dev/null +++ b/Resources/Private/Build/rollup.config.js @@ -0,0 +1,25 @@ +const babel = require('@rollup/plugin-babel').babel; +const resolve = require('@rollup/plugin-node-resolve').default; +const commonjs = require('@rollup/plugin-commonjs'); +const { terser } = require('rollup-plugin-terser'); + +module.exports = { + input: './JavaScript/Form.js', + plugins: [ + resolve({ + browser: true + }), + commonjs({ + sourceMap: false + }), + babel({ + exclude: './node_modules/**', + babelHelpers: 'bundled' + }), + terser() + ], + output: { + file: '../../Public/JavaScript/Powermail/Form.min.js', + format: 'iife' + }, +}; diff --git a/Resources/Private/JavaScript/Libraries/bootstrap.js b/Resources/Private/JavaScript/Libraries/bootstrap.js deleted file mode 100644 index 8a2e99a53..000000000 --- a/Resources/Private/JavaScript/Libraries/bootstrap.js +++ /dev/null @@ -1,2377 +0,0 @@ -/*! - * Bootstrap v3.3.7 (http://getbootstrap.com) - * Copyright 2011-2016 Twitter, Inc. - * Licensed under the MIT license - */ - -if (typeof jQuery === 'undefined') { - throw new Error('Bootstrap\'s JavaScript requires jQuery') -} - -+function ($) { - 'use strict'; - var version = $.fn.jquery.split(' ')[0].split('.') - if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) { - throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4') - } -}(jQuery); - -/* ======================================================================== - * Bootstrap: transition.js v3.3.7 - * http://getbootstrap.com/javascript/#transitions - * ======================================================================== - * Copyright 2011-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) - // ============================================================ - - function transitionEnd() { - var el = document.createElement('bootstrap') - - var transEndEventNames = { - WebkitTransition : 'webkitTransitionEnd', - MozTransition : 'transitionend', - OTransition : 'oTransitionEnd otransitionend', - transition : 'transitionend' - } - - for (var name in transEndEventNames) { - if (el.style[name] !== undefined) { - return { end: transEndEventNames[name] } - } - } - - return false // explicit for ie8 ( ._.) - } - - // http://blog.alexmaccaw.com/css-transitions - $.fn.emulateTransitionEnd = function (duration) { - var called = false - var $el = this - $(this).one('bsTransitionEnd', function () { called = true }) - var callback = function () { if (!called) $($el).trigger($.support.transition.end) } - setTimeout(callback, duration) - return this - } - - $(function () { - $.support.transition = transitionEnd() - - if (!$.support.transition) return - - $.event.special.bsTransitionEnd = { - bindType: $.support.transition.end, - delegateType: $.support.transition.end, - handle: function (e) { - if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) - } - } - }) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: alert.js v3.3.7 - * http://getbootstrap.com/javascript/#alerts - * ======================================================================== - * Copyright 2011-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // ALERT CLASS DEFINITION - // ====================== - - var dismiss = '[data-dismiss="alert"]' - var Alert = function (el) { - $(el).on('click', dismiss, this.close) - } - - Alert.VERSION = '3.3.7' - - Alert.TRANSITION_DURATION = 150 - - Alert.prototype.close = function (e) { - var $this = $(this) - var selector = $this.attr('data-target') - - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 - } - - var $parent = $(selector === '#' ? [] : selector) - - if (e) e.preventDefault() - - if (!$parent.length) { - $parent = $this.closest('.alert') - } - - $parent.trigger(e = $.Event('close.bs.alert')) - - if (e.isDefaultPrevented()) return - - $parent.removeClass('in') - - function removeElement() { - // detach from parent, fire event then clean up data - $parent.detach().trigger('closed.bs.alert').remove() - } - - $.support.transition && $parent.hasClass('fade') ? - $parent - .one('bsTransitionEnd', removeElement) - .emulateTransitionEnd(Alert.TRANSITION_DURATION) : - removeElement() - } - - - // ALERT PLUGIN DEFINITION - // ======================= - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.alert') - - if (!data) $this.data('bs.alert', (data = new Alert(this))) - if (typeof option == 'string') data[option].call($this) - }) - } - - var old = $.fn.alert - - $.fn.alert = Plugin - $.fn.alert.Constructor = Alert - - - // ALERT NO CONFLICT - // ================= - - $.fn.alert.noConflict = function () { - $.fn.alert = old - return this - } - - - // ALERT DATA-API - // ============== - - $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: button.js v3.3.7 - * http://getbootstrap.com/javascript/#buttons - * ======================================================================== - * Copyright 2011-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // BUTTON PUBLIC CLASS DEFINITION - // ============================== - - var Button = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, Button.DEFAULTS, options) - this.isLoading = false - } - - Button.VERSION = '3.3.7' - - Button.DEFAULTS = { - loadingText: 'loading...' - } - - Button.prototype.setState = function (state) { - var d = 'disabled' - var $el = this.$element - var val = $el.is('input') ? 'val' : 'html' - var data = $el.data() - - state += 'Text' - - if (data.resetText == null) $el.data('resetText', $el[val]()) - - // push to event loop to allow forms to submit - setTimeout($.proxy(function () { - $el[val](data[state] == null ? this.options[state] : data[state]) - - if (state == 'loadingText') { - this.isLoading = true - $el.addClass(d).attr(d, d).prop(d, true) - } else if (this.isLoading) { - this.isLoading = false - $el.removeClass(d).removeAttr(d).prop(d, false) - } - }, this), 0) - } - - Button.prototype.toggle = function () { - var changed = true - var $parent = this.$element.closest('[data-toggle="buttons"]') - - if ($parent.length) { - var $input = this.$element.find('input') - if ($input.prop('type') == 'radio') { - if ($input.prop('checked')) changed = false - $parent.find('.active').removeClass('active') - this.$element.addClass('active') - } else if ($input.prop('type') == 'checkbox') { - if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false - this.$element.toggleClass('active') - } - $input.prop('checked', this.$element.hasClass('active')) - if (changed) $input.trigger('change') - } else { - this.$element.attr('aria-pressed', !this.$element.hasClass('active')) - this.$element.toggleClass('active') - } - } - - - // BUTTON PLUGIN DEFINITION - // ======================== - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.button') - var options = typeof option == 'object' && option - - if (!data) $this.data('bs.button', (data = new Button(this, options))) - - if (option == 'toggle') data.toggle() - else if (option) data.setState(option) - }) - } - - var old = $.fn.button - - $.fn.button = Plugin - $.fn.button.Constructor = Button - - - // BUTTON NO CONFLICT - // ================== - - $.fn.button.noConflict = function () { - $.fn.button = old - return this - } - - - // BUTTON DATA-API - // =============== - - $(document) - .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { - var $btn = $(e.target).closest('.btn') - Plugin.call($btn, 'toggle') - if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) { - // Prevent double click on radios, and the double selections (so cancellation) on checkboxes - e.preventDefault() - // The target component still receive the focus - if ($btn.is('input,button')) $btn.trigger('focus') - else $btn.find('input:visible,button:visible').first().trigger('focus') - } - }) - .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { - $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) - }) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: carousel.js v3.3.7 - * http://getbootstrap.com/javascript/#carousel - * ======================================================================== - * Copyright 2011-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // CAROUSEL CLASS DEFINITION - // ========================= - - var Carousel = function (element, options) { - this.$element = $(element) - this.$indicators = this.$element.find('.carousel-indicators') - this.options = options - this.paused = null - this.sliding = null - this.interval = null - this.$active = null - this.$items = null - - this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) - - this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element - .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) - .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) - } - - Carousel.VERSION = '3.3.7' - - Carousel.TRANSITION_DURATION = 600 - - Carousel.DEFAULTS = { - interval: 5000, - pause: 'hover', - wrap: true, - keyboard: true - } - - Carousel.prototype.keydown = function (e) { - if (/input|textarea/i.test(e.target.tagName)) return - switch (e.which) { - case 37: this.prev(); break - case 39: this.next(); break - default: return - } - - e.preventDefault() - } - - Carousel.prototype.cycle = function (e) { - e || (this.paused = false) - - this.interval && clearInterval(this.interval) - - this.options.interval - && !this.paused - && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) - - return this - } - - Carousel.prototype.getItemIndex = function (item) { - this.$items = item.parent().children('.item') - return this.$items.index(item || this.$active) - } - - Carousel.prototype.getItemForDirection = function (direction, active) { - var activeIndex = this.getItemIndex(active) - var willWrap = (direction == 'prev' && activeIndex === 0) - || (direction == 'next' && activeIndex == (this.$items.length - 1)) - if (willWrap && !this.options.wrap) return active - var delta = direction == 'prev' ? -1 : 1 - var itemIndex = (activeIndex + delta) % this.$items.length - return this.$items.eq(itemIndex) - } - - Carousel.prototype.to = function (pos) { - var that = this - var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) - - if (pos > (this.$items.length - 1) || pos < 0) return - - if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" - if (activeIndex == pos) return this.pause().cycle() - - return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) - } - - Carousel.prototype.pause = function (e) { - e || (this.paused = true) - - if (this.$element.find('.next, .prev').length && $.support.transition) { - this.$element.trigger($.support.transition.end) - this.cycle(true) - } - - this.interval = clearInterval(this.interval) - - return this - } - - Carousel.prototype.next = function () { - if (this.sliding) return - return this.slide('next') - } - - Carousel.prototype.prev = function () { - if (this.sliding) return - return this.slide('prev') - } - - Carousel.prototype.slide = function (type, next) { - var $active = this.$element.find('.item.active') - var $next = next || this.getItemForDirection(type, $active) - var isCycling = this.interval - var direction = type == 'next' ? 'left' : 'right' - var that = this - - if ($next.hasClass('active')) return (this.sliding = false) - - var relatedTarget = $next[0] - var slideEvent = $.Event('slide.bs.carousel', { - relatedTarget: relatedTarget, - direction: direction - }) - this.$element.trigger(slideEvent) - if (slideEvent.isDefaultPrevented()) return - - this.sliding = true - - isCycling && this.pause() - - if (this.$indicators.length) { - this.$indicators.find('.active').removeClass('active') - var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) - $nextIndicator && $nextIndicator.addClass('active') - } - - var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" - if ($.support.transition && this.$element.hasClass('slide')) { - $next.addClass(type) - $next[0].offsetWidth // force reflow - $active.addClass(direction) - $next.addClass(direction) - $active - .one('bsTransitionEnd', function () { - $next.removeClass([type, direction].join(' ')).addClass('active') - $active.removeClass(['active', direction].join(' ')) - that.sliding = false - setTimeout(function () { - that.$element.trigger(slidEvent) - }, 0) - }) - .emulateTransitionEnd(Carousel.TRANSITION_DURATION) - } else { - $active.removeClass('active') - $next.addClass('active') - this.sliding = false - this.$element.trigger(slidEvent) - } - - isCycling && this.cycle() - - return this - } - - - // CAROUSEL PLUGIN DEFINITION - // ========================== - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.carousel') - var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) - var action = typeof option == 'string' ? option : options.slide - - if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) - if (typeof option == 'number') data.to(option) - else if (action) data[action]() - else if (options.interval) data.pause().cycle() - }) - } - - var old = $.fn.carousel - - $.fn.carousel = Plugin - $.fn.carousel.Constructor = Carousel - - - // CAROUSEL NO CONFLICT - // ==================== - - $.fn.carousel.noConflict = function () { - $.fn.carousel = old - return this - } - - - // CAROUSEL DATA-API - // ================= - - var clickHandler = function (e) { - var href - var $this = $(this) - var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 - if (!$target.hasClass('carousel')) return - var options = $.extend({}, $target.data(), $this.data()) - var slideIndex = $this.attr('data-slide-to') - if (slideIndex) options.interval = false - - Plugin.call($target, options) - - if (slideIndex) { - $target.data('bs.carousel').to(slideIndex) - } - - e.preventDefault() - } - - $(document) - .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) - .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) - - $(window).on('load', function () { - $('[data-ride="carousel"]').each(function () { - var $carousel = $(this) - Plugin.call($carousel, $carousel.data()) - }) - }) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: collapse.js v3.3.7 - * http://getbootstrap.com/javascript/#collapse - * ======================================================================== - * Copyright 2011-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - -/* jshint latedef: false */ - -+function ($) { - 'use strict'; - - // COLLAPSE PUBLIC CLASS DEFINITION - // ================================ - - var Collapse = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, Collapse.DEFAULTS, options) - this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' + - '[data-toggle="collapse"][data-target="#' + element.id + '"]') - this.transitioning = null - - if (this.options.parent) { - this.$parent = this.getParent() - } else { - this.addAriaAndCollapsedClass(this.$element, this.$trigger) - } - - if (this.options.toggle) this.toggle() - } - - Collapse.VERSION = '3.3.7' - - Collapse.TRANSITION_DURATION = 350 - - Collapse.DEFAULTS = { - toggle: true - } - - Collapse.prototype.dimension = function () { - var hasWidth = this.$element.hasClass('width') - return hasWidth ? 'width' : 'height' - } - - Collapse.prototype.show = function () { - if (this.transitioning || this.$element.hasClass('in')) return - - var activesData - var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing') - - if (actives && actives.length) { - activesData = actives.data('bs.collapse') - if (activesData && activesData.transitioning) return - } - - var startEvent = $.Event('show.bs.collapse') - this.$element.trigger(startEvent) - if (startEvent.isDefaultPrevented()) return - - if (actives && actives.length) { - Plugin.call(actives, 'hide') - activesData || actives.data('bs.collapse', null) - } - - var dimension = this.dimension() - - this.$element - .removeClass('collapse') - .addClass('collapsing')[dimension](0) - .attr('aria-expanded', true) - - this.$trigger - .removeClass('collapsed') - .attr('aria-expanded', true) - - this.transitioning = 1 - - var complete = function () { - this.$element - .removeClass('collapsing') - .addClass('collapse in')[dimension]('') - this.transitioning = 0 - this.$element - .trigger('shown.bs.collapse') - } - - if (!$.support.transition) return complete.call(this) - - var scrollSize = $.camelCase(['scroll', dimension].join('-')) - - this.$element - .one('bsTransitionEnd', $.proxy(complete, this)) - .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) - } - - Collapse.prototype.hide = function () { - if (this.transitioning || !this.$element.hasClass('in')) return - - var startEvent = $.Event('hide.bs.collapse') - this.$element.trigger(startEvent) - if (startEvent.isDefaultPrevented()) return - - var dimension = this.dimension() - - this.$element[dimension](this.$element[dimension]())[0].offsetHeight - - this.$element - .addClass('collapsing') - .removeClass('collapse in') - .attr('aria-expanded', false) - - this.$trigger - .addClass('collapsed') - .attr('aria-expanded', false) - - this.transitioning = 1 - - var complete = function () { - this.transitioning = 0 - this.$element - .removeClass('collapsing') - .addClass('collapse') - .trigger('hidden.bs.collapse') - } - - if (!$.support.transition) return complete.call(this) - - this.$element - [dimension](0) - .one('bsTransitionEnd', $.proxy(complete, this)) - .emulateTransitionEnd(Collapse.TRANSITION_DURATION) - } - - Collapse.prototype.toggle = function () { - this[this.$element.hasClass('in') ? 'hide' : 'show']() - } - - Collapse.prototype.getParent = function () { - return $(this.options.parent) - .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') - .each($.proxy(function (i, element) { - var $element = $(element) - this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) - }, this)) - .end() - } - - Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { - var isOpen = $element.hasClass('in') - - $element.attr('aria-expanded', isOpen) - $trigger - .toggleClass('collapsed', !isOpen) - .attr('aria-expanded', isOpen) - } - - function getTargetFromTrigger($trigger) { - var href - var target = $trigger.attr('data-target') - || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 - - return $(target) - } - - - // COLLAPSE PLUGIN DEFINITION - // ========================== - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.collapse') - var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) - - if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false - if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - var old = $.fn.collapse - - $.fn.collapse = Plugin - $.fn.collapse.Constructor = Collapse - - - // COLLAPSE NO CONFLICT - // ==================== - - $.fn.collapse.noConflict = function () { - $.fn.collapse = old - return this - } - - - // COLLAPSE DATA-API - // ================= - - $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { - var $this = $(this) - - if (!$this.attr('data-target')) e.preventDefault() - - var $target = getTargetFromTrigger($this) - var data = $target.data('bs.collapse') - var option = data ? 'toggle' : $this.data() - - Plugin.call($target, option) - }) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: dropdown.js v3.3.7 - * http://getbootstrap.com/javascript/#dropdowns - * ======================================================================== - * Copyright 2011-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // DROPDOWN CLASS DEFINITION - // ========================= - - var backdrop = '.dropdown-backdrop' - var toggle = '[data-toggle="dropdown"]' - var Dropdown = function (element) { - $(element).on('click.bs.dropdown', this.toggle) - } - - Dropdown.VERSION = '3.3.7' - - function getParent($this) { - var selector = $this.attr('data-target') - - if (!selector) { - selector = $this.attr('href') - selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 - } - - var $parent = selector && $(selector) - - return $parent && $parent.length ? $parent : $this.parent() - } - - function clearMenus(e) { - if (e && e.which === 3) return - $(backdrop).remove() - $(toggle).each(function () { - var $this = $(this) - var $parent = getParent($this) - var relatedTarget = { relatedTarget: this } - - if (!$parent.hasClass('open')) return - - if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return - - $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget)) - - if (e.isDefaultPrevented()) return - - $this.attr('aria-expanded', 'false') - $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget)) - }) - } - - Dropdown.prototype.toggle = function (e) { - var $this = $(this) - - if ($this.is('.disabled, :disabled')) return - - var $parent = getParent($this) - var isActive = $parent.hasClass('open') - - clearMenus() - - if (!isActive) { - if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { - // if mobile we use a backdrop because click events don't delegate - $(document.createElement('div')) - .addClass('dropdown-backdrop') - .insertAfter($(this)) - .on('click', clearMenus) - } - - var relatedTarget = { relatedTarget: this } - $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget)) - - if (e.isDefaultPrevented()) return - - $this - .trigger('focus') - .attr('aria-expanded', 'true') - - $parent - .toggleClass('open') - .trigger($.Event('shown.bs.dropdown', relatedTarget)) - } - - return false - } - - Dropdown.prototype.keydown = function (e) { - if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return - - var $this = $(this) - - e.preventDefault() - e.stopPropagation() - - if ($this.is('.disabled, :disabled')) return - - var $parent = getParent($this) - var isActive = $parent.hasClass('open') - - if (!isActive && e.which != 27 || isActive && e.which == 27) { - if (e.which == 27) $parent.find(toggle).trigger('focus') - return $this.trigger('click') - } - - var desc = ' li:not(.disabled):visible a' - var $items = $parent.find('.dropdown-menu' + desc) - - if (!$items.length) return - - var index = $items.index(e.target) - - if (e.which == 38 && index > 0) index-- // up - if (e.which == 40 && index < $items.length - 1) index++ // down - if (!~index) index = 0 - - $items.eq(index).trigger('focus') - } - - - // DROPDOWN PLUGIN DEFINITION - // ========================== - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.dropdown') - - if (!data) $this.data('bs.dropdown', (data = new Dropdown(this))) - if (typeof option == 'string') data[option].call($this) - }) - } - - var old = $.fn.dropdown - - $.fn.dropdown = Plugin - $.fn.dropdown.Constructor = Dropdown - - - // DROPDOWN NO CONFLICT - // ==================== - - $.fn.dropdown.noConflict = function () { - $.fn.dropdown = old - return this - } - - - // APPLY TO STANDARD DROPDOWN ELEMENTS - // =================================== - - $(document) - .on('click.bs.dropdown.data-api', clearMenus) - .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) - .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle) - .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown) - .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: modal.js v3.3.7 - * http://getbootstrap.com/javascript/#modals - * ======================================================================== - * Copyright 2011-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // MODAL CLASS DEFINITION - // ====================== - - var Modal = function (element, options) { - this.options = options - this.$body = $(document.body) - this.$element = $(element) - this.$dialog = this.$element.find('.modal-dialog') - this.$backdrop = null - this.isShown = null - this.originalBodyPad = null - this.scrollbarWidth = 0 - this.ignoreBackdropClick = false - - if (this.options.remote) { - this.$element - .find('.modal-content') - .load(this.options.remote, $.proxy(function () { - this.$element.trigger('loaded.bs.modal') - }, this)) - } - } - - Modal.VERSION = '3.3.7' - - Modal.TRANSITION_DURATION = 300 - Modal.BACKDROP_TRANSITION_DURATION = 150 - - Modal.DEFAULTS = { - backdrop: true, - keyboard: true, - show: true - } - - Modal.prototype.toggle = function (_relatedTarget) { - return this.isShown ? this.hide() : this.show(_relatedTarget) - } - - Modal.prototype.show = function (_relatedTarget) { - var that = this - var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) - - this.$element.trigger(e) - - if (this.isShown || e.isDefaultPrevented()) return - - this.isShown = true - - this.checkScrollbar() - this.setScrollbar() - this.$body.addClass('modal-open') - - this.escape() - this.resize() - - this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) - - this.$dialog.on('mousedown.dismiss.bs.modal', function () { - that.$element.one('mouseup.dismiss.bs.modal', function (e) { - if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true - }) - }) - - this.backdrop(function () { - var transition = $.support.transition && that.$element.hasClass('fade') - - if (!that.$element.parent().length) { - that.$element.appendTo(that.$body) // don't move modals dom position - } - - that.$element - .show() - .scrollTop(0) - - that.adjustDialog() - - if (transition) { - that.$element[0].offsetWidth // force reflow - } - - that.$element.addClass('in') - - that.enforceFocus() - - var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) - - transition ? - that.$dialog // wait for modal to slide in - .one('bsTransitionEnd', function () { - that.$element.trigger('focus').trigger(e) - }) - .emulateTransitionEnd(Modal.TRANSITION_DURATION) : - that.$element.trigger('focus').trigger(e) - }) - } - - Modal.prototype.hide = function (e) { - if (e) e.preventDefault() - - e = $.Event('hide.bs.modal') - - this.$element.trigger(e) - - if (!this.isShown || e.isDefaultPrevented()) return - - this.isShown = false - - this.escape() - this.resize() - - $(document).off('focusin.bs.modal') - - this.$element - .removeClass('in') - .off('click.dismiss.bs.modal') - .off('mouseup.dismiss.bs.modal') - - this.$dialog.off('mousedown.dismiss.bs.modal') - - $.support.transition && this.$element.hasClass('fade') ? - this.$element - .one('bsTransitionEnd', $.proxy(this.hideModal, this)) - .emulateTransitionEnd(Modal.TRANSITION_DURATION) : - this.hideModal() - } - - Modal.prototype.enforceFocus = function () { - $(document) - .off('focusin.bs.modal') // guard against infinite focus loop - .on('focusin.bs.modal', $.proxy(function (e) { - if (document !== e.target && - this.$element[0] !== e.target && - !this.$element.has(e.target).length) { - this.$element.trigger('focus') - } - }, this)) - } - - Modal.prototype.escape = function () { - if (this.isShown && this.options.keyboard) { - this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) { - e.which == 27 && this.hide() - }, this)) - } else if (!this.isShown) { - this.$element.off('keydown.dismiss.bs.modal') - } - } - - Modal.prototype.resize = function () { - if (this.isShown) { - $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this)) - } else { - $(window).off('resize.bs.modal') - } - } - - Modal.prototype.hideModal = function () { - var that = this - this.$element.hide() - this.backdrop(function () { - that.$body.removeClass('modal-open') - that.resetAdjustments() - that.resetScrollbar() - that.$element.trigger('hidden.bs.modal') - }) - } - - Modal.prototype.removeBackdrop = function () { - this.$backdrop && this.$backdrop.remove() - this.$backdrop = null - } - - Modal.prototype.backdrop = function (callback) { - var that = this - var animate = this.$element.hasClass('fade') ? 'fade' : '' - - if (this.isShown && this.options.backdrop) { - var doAnimate = $.support.transition && animate - - this.$backdrop = $(document.createElement('div')) - .addClass('modal-backdrop ' + animate) - .appendTo(this.$body) - - this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { - if (this.ignoreBackdropClick) { - this.ignoreBackdropClick = false - return - } - if (e.target !== e.currentTarget) return - this.options.backdrop == 'static' - ? this.$element[0].focus() - : this.hide() - }, this)) - - if (doAnimate) this.$backdrop[0].offsetWidth // force reflow - - this.$backdrop.addClass('in') - - if (!callback) return - - doAnimate ? - this.$backdrop - .one('bsTransitionEnd', callback) - .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : - callback() - - } else if (!this.isShown && this.$backdrop) { - this.$backdrop.removeClass('in') - - var callbackRemove = function () { - that.removeBackdrop() - callback && callback() - } - $.support.transition && this.$element.hasClass('fade') ? - this.$backdrop - .one('bsTransitionEnd', callbackRemove) - .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : - callbackRemove() - - } else if (callback) { - callback() - } - } - - // these following methods are used to handle overflowing modals - - Modal.prototype.handleUpdate = function () { - this.adjustDialog() - } - - Modal.prototype.adjustDialog = function () { - var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight - - this.$element.css({ - paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '', - paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : '' - }) - } - - Modal.prototype.resetAdjustments = function () { - this.$element.css({ - paddingLeft: '', - paddingRight: '' - }) - } - - Modal.prototype.checkScrollbar = function () { - var fullWindowWidth = window.innerWidth - if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8 - var documentElementRect = document.documentElement.getBoundingClientRect() - fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left) - } - this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth - this.scrollbarWidth = this.measureScrollbar() - } - - Modal.prototype.setScrollbar = function () { - var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) - this.originalBodyPad = document.body.style.paddingRight || '' - if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) - } - - Modal.prototype.resetScrollbar = function () { - this.$body.css('padding-right', this.originalBodyPad) - } - - Modal.prototype.measureScrollbar = function () { // thx walsh - var scrollDiv = document.createElement('div') - scrollDiv.className = 'modal-scrollbar-measure' - this.$body.append(scrollDiv) - var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth - this.$body[0].removeChild(scrollDiv) - return scrollbarWidth - } - - - // MODAL PLUGIN DEFINITION - // ======================= - - function Plugin(option, _relatedTarget) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.modal') - var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) - - if (!data) $this.data('bs.modal', (data = new Modal(this, options))) - if (typeof option == 'string') data[option](_relatedTarget) - else if (options.show) data.show(_relatedTarget) - }) - } - - var old = $.fn.modal - - $.fn.modal = Plugin - $.fn.modal.Constructor = Modal - - - // MODAL NO CONFLICT - // ================= - - $.fn.modal.noConflict = function () { - $.fn.modal = old - return this - } - - - // MODAL DATA-API - // ============== - - $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { - var $this = $(this) - var href = $this.attr('href') - var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7 - var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) - - if ($this.is('a')) e.preventDefault() - - $target.one('show.bs.modal', function (showEvent) { - if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown - $target.one('hidden.bs.modal', function () { - $this.is(':visible') && $this.trigger('focus') - }) - }) - Plugin.call($target, option, this) - }) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: tooltip.js v3.3.7 - * http://getbootstrap.com/javascript/#tooltip - * Inspired by the original jQuery.tipsy by Jason Frame - * ======================================================================== - * Copyright 2011-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // TOOLTIP PUBLIC CLASS DEFINITION - // =============================== - - var Tooltip = function (element, options) { - this.type = null - this.options = null - this.enabled = null - this.timeout = null - this.hoverState = null - this.$element = null - this.inState = null - - this.init('tooltip', element, options) - } - - Tooltip.VERSION = '3.3.7' - - Tooltip.TRANSITION_DURATION = 150 - - Tooltip.DEFAULTS = { - animation: true, - placement: 'top', - selector: false, - template: ''+options.i18n[options.lang].dayOfWeek[(j+options.dayOfWeekStart)>6?0:j+options.dayOfWeekStart]+' | '; - } - - table+='
---|
'+
- ' '+d+' '+
- ' | ';
-
- if( start.getDay()==options.dayOfWeekStartPrev ) {
- table+='