Compare commits
42 Commits
Author | SHA1 | Date | |
---|---|---|---|
56782e2f10 | |||
698c523d25 | |||
dc280fd38c | |||
e951591d6f | |||
34409432e8 | |||
0ceac8921f | |||
20909f0912 | |||
a669beed07 | |||
9de1481efe | |||
33948892fa | |||
83f3729e37 | |||
25aec60bc9 | |||
cbe2fc64bb | |||
9547839aa9 | |||
f5fc03ee1d | |||
61251f6e34 | |||
ec8adcae73 | |||
691a8a45f3 | |||
ce127eadc1 | |||
b49ce7d4e4 | |||
d83975dc64 | |||
57b0747b6e | |||
24c87ad19e | |||
2c7b8a7d25 | |||
07bbdc59f6 | |||
3f74b74ff0 | |||
713908b6c3 | |||
fbc650e331 | |||
eef74fa2cc | |||
317bed32b1 | |||
8fa61ca883 | |||
a1df6acdcc | |||
ac557d692e | |||
7b2eef18ad | |||
c9c1b1fa92 | |||
927d9cf87e | |||
daefe143a0 | |||
21926ea3e0 | |||
9e5acecbc0 | |||
c921bc6f71 | |||
2f2a00cbbe | |||
493d6caffc |
2
.babelrc
2
.babelrc
@ -1,9 +1,11 @@
|
||||
{
|
||||
"presets": [
|
||||
"@babel/preset-typescript",
|
||||
"@babel/preset-react",
|
||||
"@babel/preset-env"
|
||||
],
|
||||
"plugins": [
|
||||
"babel-plugin-typescript-to-proptypes",
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
[
|
||||
"@babel/plugin-transform-runtime", {
|
||||
|
137
.eslintrc.ts.json
Normal file
137
.eslintrc.ts.json
Normal file
@ -0,0 +1,137 @@
|
||||
{
|
||||
"extends": [
|
||||
"airbnb",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:@typescript-eslint/recommended-requiring-type-checking"
|
||||
],
|
||||
"env": {
|
||||
"amd": true,
|
||||
"browser": true,
|
||||
"mocha": true
|
||||
},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"tsconfigRootDir": ".",
|
||||
"project": ["./tsconfig.json"],
|
||||
"ecmaVersion": 6,
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"plugins": [
|
||||
"react-hooks",
|
||||
"no-only-tests",
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"settings": {
|
||||
"import/resolver": "webpack"
|
||||
},
|
||||
"rules": {
|
||||
// Typrescript Rules
|
||||
"@typescript-eslint/adjacent-overload-signatures": "off",
|
||||
"@typescript-eslint/array-type": "off",
|
||||
"@typescript-eslint/await-thenable": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"@typescript-eslint/consistent-type-assertions": "off",
|
||||
"@typescript-eslint/consistent-type-definitions": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/explicit-member-accessibility": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/member-delimiter-style": "off",
|
||||
"@typescript-eslint/member-ordering": "off",
|
||||
"@typescript-eslint/naming-convention": "off",
|
||||
"@typescript-eslint/no-dynamic-delete": "off",
|
||||
"@typescript-eslint/no-empty-interface": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-extra-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-extraneous-class": "off",
|
||||
"@typescript-eslint/no-floating-promises": "off",
|
||||
"@typescript-eslint/no-for-in-array": "off",
|
||||
"@typescript-eslint/no-implied-eval": "off",
|
||||
"@typescript-eslint/no-inferrable-types": "off",
|
||||
"@typescript-eslint/no-misused-new": "off",
|
||||
"@typescript-eslint/no-misused-promises": "off",
|
||||
"@typescript-eslint/no-namespace": "off",
|
||||
"@typescript-eslint/no-non-null-asserted-optional-chain": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-parameter-properties": "off",
|
||||
"@typescript-eslint/no-require-imports": "off",
|
||||
"@typescript-eslint/no-this-alias": "off",
|
||||
"@typescript-eslint/no-throw-literal": "off",
|
||||
"@typescript-eslint/no-type-alias": "off",
|
||||
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "off",
|
||||
"@typescript-eslint/no-unnecessary-condition": "off",
|
||||
"@typescript-eslint/no-unnecessary-qualifier": "off",
|
||||
"@typescript-eslint/no-unnecessary-type-arguments": "off",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "off",
|
||||
"@typescript-eslint/no-unused-vars-experimental": "off",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"@typescript-eslint/prefer-as-const": "off",
|
||||
"@typescript-eslint/prefer-for-of": "off",
|
||||
"@typescript-eslint/prefer-function-type": "off",
|
||||
"@typescript-eslint/prefer-includes": "off",
|
||||
"@typescript-eslint/prefer-namespace-keyword": "off",
|
||||
"@typescript-eslint/prefer-nullish-coalescing": "off",
|
||||
"@typescript-eslint/prefer-optional-chain": "off",
|
||||
"@typescript-eslint/prefer-readonly": "off",
|
||||
"@typescript-eslint/prefer-regexp-exec": "off",
|
||||
"@typescript-eslint/prefer-string-starts-ends-with": "off",
|
||||
"@typescript-eslint/promise-function-async": "off",
|
||||
"@typescript-eslint/require-array-sort-compare": "off",
|
||||
"@typescript-eslint/restrict-plus-operands": "off",
|
||||
"@typescript-eslint/restrict-template-expressions": "off",
|
||||
"@typescript-eslint/strict-boolean-expressions": "off",
|
||||
"@typescript-eslint/switch-exhaustiveness-check": "off",
|
||||
"@typescript-eslint/triple-slash-reference": "off",
|
||||
"@typescript-eslint/type-annotation-spacing": "off",
|
||||
"@typescript-eslint/typedef": "off",
|
||||
"@typescript-eslint/unbound-method": "off",
|
||||
"@typescript-eslint/unified-signatures": "off",
|
||||
// ESlint recommended rules adjusted for Typescript
|
||||
"@typescript-eslint/brace-style": "off",
|
||||
"@typescript-eslint/comma-spacing": "off",
|
||||
"@typescript-eslint/default-param-last": "off",
|
||||
"@typescript-eslint/func-call-spacing": "off",
|
||||
"@typescript-eslint/indent": "off",
|
||||
"@typescript-eslint/no-array-constructor": "off",
|
||||
"@typescript-eslint/no-dupe-class-members": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"@typescript-eslint/no-extra-parens": "off",
|
||||
"@typescript-eslint/no-extra-semi": "off",
|
||||
"@typescript-eslint/no-magic-numbers": "off",
|
||||
"@typescript-eslint/no-unused-expressions": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"@typescript-eslint/no-use-before-define": "off",
|
||||
"@typescript-eslint/no-useless-constructor": "off",
|
||||
"@typescript-eslint/quotes": "off",
|
||||
"@typescript-eslint/require-await": "off",
|
||||
"@typescript-eslint/return-await": "off",
|
||||
"@typescript-eslint/semi": "off",
|
||||
"@typescript-eslint/space-before-function-paren": "off",
|
||||
"@typescript-eslint/camelcase": "off",
|
||||
// PropTypes
|
||||
"react/prop-types": 0,
|
||||
// Hooks
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
"react-hooks/exhaustive-deps": "warn",
|
||||
// Exceptions
|
||||
"react/jsx-filename-extension": 0,
|
||||
"arrow-parens": ["error", "always"],
|
||||
"comma-dangle": ["error", "always-multiline"],
|
||||
"no-only-tests/no-only-tests": 2,
|
||||
"no-script-url": 0,
|
||||
"import/extensions": 0, // we wouldn't be able to import jQuery without this line
|
||||
"react/destructuring-assignment": 0, // that would be too many changes to fix this one
|
||||
"prefer-destructuring": 0, // that would be too many changes to fix this one
|
||||
"jsx-a11y/label-has-for": [2, {
|
||||
"required": {"some": ["nesting", "id"]} // some of our labels are hidden and we cannot nest those
|
||||
}],
|
||||
"jsx-a11y/anchor-is-valid": 0, // cannot fix this one, it would break wprdpress themes
|
||||
"jsx-a11y/label-has-associated-control": [ 2, {
|
||||
"either": "either" // control has to be either nested or associated via htmlFor
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
15
RoboFile.php
15
RoboFile.php
@ -363,7 +363,7 @@ class RoboFile extends \Robo\Tasks {
|
||||
}
|
||||
|
||||
public function qaLintJavascript() {
|
||||
return $this->_exec('npm run lint');
|
||||
return $this->_exec('npm run check-types && npm run lint');
|
||||
}
|
||||
|
||||
public function qaLintCss() {
|
||||
@ -445,11 +445,22 @@ class RoboFile extends \Robo\Tasks {
|
||||
)
|
||||
->run();
|
||||
}
|
||||
if (substr($filePath, -4) === '.tsx' || substr($filePath, -3) === '.ts') {
|
||||
// fix ESLint using TS rules
|
||||
return $this->collectionBuilder()
|
||||
->taskExec(
|
||||
'npx eslint -c .eslintrc.ts.json ' .
|
||||
'--max-warnings 0 ' .
|
||||
'--fix ' .
|
||||
$filePath
|
||||
)
|
||||
->run();
|
||||
}
|
||||
if (substr($filePath, -8) === '.spec.js') {
|
||||
// fix ESLint using tests rules
|
||||
return $this->collectionBuilder()
|
||||
->taskExec(
|
||||
'npx eslint -c .eslintrc.tests.json ' .
|
||||
'npx eslint -c .eslintrc.tests_newsletter_editor.json ' .
|
||||
'--max-warnings 0 ' .
|
||||
'--fix ' .
|
||||
$filePath
|
||||
|
@ -86,6 +86,20 @@ $gutenberg-control-border-color-focus: #007cba;
|
||||
}
|
||||
}
|
||||
|
||||
.mailpoet-styles-settings {
|
||||
display: grid;
|
||||
grid-auto-flow: row;
|
||||
grid-row-gap: 30px;
|
||||
}
|
||||
|
||||
.mailpoet-styles-settings-heading {
|
||||
font-size: 15px;
|
||||
|
||||
.component-color-indicator {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
|
@ -174,6 +174,24 @@ $column-icon-size-with-padding: 27px;
|
||||
|
||||
@include animation-fade-in-and-scale-horizontally();
|
||||
}
|
||||
|
||||
.mailpoet_delete_block_confirm {
|
||||
color: $warning-text-color;
|
||||
|
||||
&:hover {
|
||||
color: $warning-text-color;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.mailpoet_delete_block_cancel {
|
||||
color: $warning-alternate-text-color;
|
||||
|
||||
&:hover {
|
||||
color: $warning-alternate-text-color;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mailpoet_delete_block_activated {
|
||||
@ -199,21 +217,3 @@ $column-icon-size-with-padding: 27px;
|
||||
margin-left: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.mailpoet_delete_block_confirm {
|
||||
color: $warning-text-color;
|
||||
|
||||
&:hover {
|
||||
color: $warning-text-color;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.mailpoet_delete_block_cancel {
|
||||
color: $warning-alternate-text-color;
|
||||
|
||||
&:hover {
|
||||
color: $warning-alternate-text-color;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ export const fromUrl = (url) => new Promise((resolve, reject) => {
|
||||
const iframe = document.createElement('iframe');
|
||||
const protocol = document.location.href.startsWith('https://') ? 'https:' : 'http:';
|
||||
iframe.src = protocol + url.replace(/^https?:/, '');
|
||||
iframe.style.opacity = 0;
|
||||
iframe.style.opacity = '0';
|
||||
iframe.scrolling = 'no';
|
||||
iframe.onload = async () => {
|
||||
const container = iframe.contentDocument.documentElement;
|
||||
@ -44,7 +44,7 @@ export const fromUrl = (url) => new Promise((resolve, reject) => {
|
||||
reject(MailPoet.I18n.t('errorWhileTakingScreenshot'));
|
||||
};
|
||||
iframe.onerror = onError;
|
||||
iframe.onError = onError;
|
||||
(iframe as any).onError = onError;
|
||||
iframe.className = 'mailpoet_template_iframe';
|
||||
try {
|
||||
document.body.appendChild(iframe);
|
||||
@ -65,7 +65,7 @@ export const fromNewsletter = (data) => new Promise((resolve, reject) => {
|
||||
json.body = JSON.stringify(json.body);
|
||||
}
|
||||
MailPoet.Ajax.post({
|
||||
api_version: window.mailpoet_api_version,
|
||||
api_version: (window as any).mailpoet_api_version,
|
||||
endpoint: 'newsletters',
|
||||
action: 'showPreview',
|
||||
data: json,
|
@ -1,5 +0,0 @@
|
||||
export default function getFeaturesContext(data) {
|
||||
const flags = data.mailpoet_feature_flags;
|
||||
const isSupported = (feature) => flags[feature] || false;
|
||||
return { isSupported };
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
export default function getSegmentsContext(data) {
|
||||
return {
|
||||
all: data.mailpoetSegments,
|
||||
};
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
export default function getUsersContext(data) {
|
||||
return {
|
||||
isNewUser: data.mailpoet_is_new_user,
|
||||
};
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import getFeaturesContext from './getFeaturesContext.jsx';
|
||||
import getSegmentsContext from './getSegmentsContext.jsx';
|
||||
import getUsersContext from './getUsersContext.jsx';
|
||||
import useFeaturesContext from './useFeaturesContext.jsx';
|
||||
import useSegmentsContext from './useSegmentsContext.jsx';
|
||||
import useUsersContext from './useUsersContext.jsx';
|
||||
import useNotices from './useNotices.jsx';
|
||||
|
||||
/**
|
||||
@ -10,9 +10,9 @@ import useNotices from './useNotices.jsx';
|
||||
* some React hooks to build some parts of the context.
|
||||
*/
|
||||
export function useGlobalContextValue(data) {
|
||||
const features = getFeaturesContext(data);
|
||||
const segments = getSegmentsContext(data);
|
||||
const users = getUsersContext(data);
|
||||
const features = useFeaturesContext(data);
|
||||
const segments = useSegmentsContext(data);
|
||||
const users = useUsersContext(data);
|
||||
const notices = useNotices();
|
||||
return {
|
||||
features, segments, users, notices,
|
||||
|
9
assets/js/src/context/useFeaturesContext.jsx
Normal file
9
assets/js/src/context/useFeaturesContext.jsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
export default function useFeaturesContext(data) {
|
||||
return React.useMemo(() => {
|
||||
const flags = data.mailpoet_feature_flags;
|
||||
const isSupported = (feature) => flags[feature] || false;
|
||||
return { isSupported };
|
||||
}, [data]);
|
||||
}
|
@ -1,28 +1,43 @@
|
||||
import React from 'react';
|
||||
|
||||
export default () => {
|
||||
const [items, setItems] = React.useState([]);
|
||||
const [nextId, setNextId] = React.useState(1);
|
||||
const [state, setState] = React.useState({
|
||||
items: [],
|
||||
nextId: 1,
|
||||
});
|
||||
|
||||
const getNextId = () => {
|
||||
setNextId((x) => x + 1);
|
||||
return nextId;
|
||||
};
|
||||
const add = React.useCallback((item) => {
|
||||
setState(({ items, nextId }) => ({
|
||||
items: [...items, { ...item, id: item.id || nextId }],
|
||||
nextId: item.id ? nextId : nextId + 1,
|
||||
}));
|
||||
}, [setState]);
|
||||
|
||||
const add = (item) => {
|
||||
setItems((xs) => [...xs, { ...item, id: item.id || getNextId() }]);
|
||||
};
|
||||
const remove = React.useCallback((id) => {
|
||||
setState(({ items, nextId }) => ({
|
||||
items: items.filter((x) => x.id !== id),
|
||||
nextId,
|
||||
}));
|
||||
}, [setState]);
|
||||
|
||||
const remove = (id) => {
|
||||
setItems((xs) => xs.filter((x) => x.id !== id));
|
||||
};
|
||||
|
||||
const success = (content, props = {}) => add({ ...props, type: 'success', children: content });
|
||||
const info = (content, props = {}) => add({ ...props, type: 'info', children: content });
|
||||
const warning = (content, props = {}) => add({ ...props, type: 'warning', children: content });
|
||||
const error = (content, props = {}) => add({ ...props, type: 'error', children: content });
|
||||
const success = React.useCallback(
|
||||
(content, props = {}) => add({ ...props, type: 'success', children: content }),
|
||||
[add]
|
||||
);
|
||||
const info = React.useCallback(
|
||||
(content, props = {}) => add({ ...props, type: 'info', children: content }),
|
||||
[add]
|
||||
);
|
||||
const warning = React.useCallback(
|
||||
(content, props = {}) => add({ ...props, type: 'warning', children: content }),
|
||||
[add]
|
||||
);
|
||||
const error = React.useCallback(
|
||||
(content, props = {}) => add({ ...props, type: 'error', children: content }),
|
||||
[add]
|
||||
);
|
||||
|
||||
return {
|
||||
items, success, info, warning, error, remove,
|
||||
items: state.items, success, info, warning, error, remove,
|
||||
};
|
||||
};
|
||||
|
7
assets/js/src/context/useSegmentsContext.jsx
Normal file
7
assets/js/src/context/useSegmentsContext.jsx
Normal file
@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
export default function useSegmentsContext(data) {
|
||||
return React.useMemo(() => ({
|
||||
all: data.mailpoetSegments,
|
||||
}), [data]);
|
||||
}
|
7
assets/js/src/context/useUsersContext.jsx
Normal file
7
assets/js/src/context/useUsersContext.jsx
Normal file
@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
export default function useUsersContext(data) {
|
||||
return React.useMemo(() => ({
|
||||
isNewUser: data.mailpoet_is_new_user,
|
||||
}), [data]);
|
||||
}
|
@ -7,6 +7,7 @@ import Notices from 'notices/notices.jsx';
|
||||
const ExperimentalFeatures = () => {
|
||||
const [flags, setFlags] = useState(null);
|
||||
const contextValue = useGlobalContextValue(window);
|
||||
const showError = contextValue.notices.error;
|
||||
|
||||
useEffect(() => {
|
||||
MailPoet.Ajax.post({
|
||||
@ -18,13 +19,13 @@ const ExperimentalFeatures = () => {
|
||||
setFlags(flagsMap);
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
showError(
|
||||
<>{response.errors.map((error) => <p>{error.message}</p>)}</>,
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
}, [showError]);
|
||||
|
||||
function handleChange(event) {
|
||||
const name = event.target.name;
|
||||
@ -41,11 +42,12 @@ const ExperimentalFeatures = () => {
|
||||
const flag = flags[name];
|
||||
flag.value = value;
|
||||
setFlags({ ...flags, [name]: flag });
|
||||
MailPoet.Notice.success(`Feature '${name}' was ${value ? 'enabled' : 'disabled'}.`);
|
||||
const message = `Feature '${name}' was ${value ? 'enabled' : 'disabled'}.`;
|
||||
contextValue.notices.success(<p>{message}</p>);
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
showError(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import moment from 'moment';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
|
||||
function FormFieldDateYear(props) {
|
||||
const yearsRange = 100;
|
||||
@ -28,6 +29,7 @@ function FormFieldDateYear(props) {
|
||||
name={`${props.name}[year]`}
|
||||
value={props.year}
|
||||
onChange={props.onValueChange}
|
||||
className={classnames({ mailpoet_date_year: props.addDefaultClasses })}
|
||||
>
|
||||
{ years }
|
||||
</select>
|
||||
@ -42,6 +44,7 @@ FormFieldDateYear.propTypes = {
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
]).isRequired,
|
||||
addDefaultClasses: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
function FormFieldDateMonth(props) {
|
||||
@ -68,6 +71,7 @@ function FormFieldDateMonth(props) {
|
||||
name={`${props.name}[month]`}
|
||||
value={props.month}
|
||||
onChange={props.onValueChange}
|
||||
className={classnames({ mailpoet_date_month: props.addDefaultClasses })}
|
||||
>
|
||||
{ months }
|
||||
</select>
|
||||
@ -83,6 +87,7 @@ FormFieldDateMonth.propTypes = {
|
||||
PropTypes.number,
|
||||
]).isRequired,
|
||||
monthNames: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
addDefaultClasses: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
function FormFieldDateDay(props) {
|
||||
@ -110,6 +115,7 @@ function FormFieldDateDay(props) {
|
||||
name={`${props.name}[day]`}
|
||||
value={props.day}
|
||||
onChange={props.onValueChange}
|
||||
className={classnames({ mailpoet_date_day: props.addDefaultClasses })}
|
||||
>
|
||||
{ days }
|
||||
</select>
|
||||
@ -124,6 +130,7 @@ FormFieldDateDay.propTypes = {
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
]).isRequired,
|
||||
addDefaultClasses: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
class FormFieldDate extends React.Component {
|
||||
@ -253,6 +260,7 @@ class FormFieldDate extends React.Component {
|
||||
onValueChange={this.onValueChange}
|
||||
key="year"
|
||||
name={this.props.field.name}
|
||||
addDefaultClasses={this.props.addDefaultClasses}
|
||||
year={this.state.year}
|
||||
placeholder={this.props.field.year_placeholder}
|
||||
/>
|
||||
@ -264,6 +272,7 @@ class FormFieldDate extends React.Component {
|
||||
onValueChange={this.onValueChange}
|
||||
key="month"
|
||||
name={this.props.field.name}
|
||||
addDefaultClasses={this.props.addDefaultClasses}
|
||||
month={this.state.month}
|
||||
monthNames={monthNames}
|
||||
placeholder={this.props.field.month_placeholder}
|
||||
@ -276,6 +285,7 @@ class FormFieldDate extends React.Component {
|
||||
onValueChange={this.onValueChange}
|
||||
key="day"
|
||||
name={this.props.field.name}
|
||||
addDefaultClasses={this.props.addDefaultClasses}
|
||||
day={this.state.day}
|
||||
placeholder={this.props.field.day_placeholder}
|
||||
/>
|
||||
@ -304,6 +314,11 @@ FormFieldDate.propTypes = {
|
||||
params: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
}).isRequired,
|
||||
onValueChange: PropTypes.func.isRequired,
|
||||
addDefaultClasses: PropTypes.bool,
|
||||
};
|
||||
|
||||
FormFieldDate.defaultProps = {
|
||||
addDefaultClasses: false,
|
||||
};
|
||||
|
||||
export default FormFieldDate;
|
||||
|
@ -10,6 +10,7 @@ import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
|
||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||
import CustomFieldSettings from './custom_field_settings.jsx';
|
||||
import mapCustomFieldFormData from '../map_custom_field_form_data.jsx';
|
||||
|
||||
@ -109,7 +110,7 @@ const CustomCheckboxEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
checkboxLabel += ' *';
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<ParagraphEdit>
|
||||
{inspectorControls}
|
||||
<span className="mailpoet_checkbox_label">{getLabel()}</span>
|
||||
<div>
|
||||
@ -118,11 +119,12 @@ const CustomCheckboxEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
type="checkbox"
|
||||
disabled
|
||||
checked={isChecked()}
|
||||
className="mailpoet_checkbox"
|
||||
/>
|
||||
{checkboxLabel}
|
||||
</label>
|
||||
</div>
|
||||
</>
|
||||
</ParagraphEdit>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,7 @@ import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
|
||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||
import CustomFieldSettings from './custom_field_settings.jsx';
|
||||
import FormFieldDate from '../../../form/fields/date.jsx';
|
||||
import formatLabel from '../label_formatter.jsx';
|
||||
@ -80,28 +81,31 @@ const CustomDateEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="mailpoet_custom_date">
|
||||
{inspectorControls}
|
||||
<label className="mailpoet_date_label" data-automation-id="editor_custom_date_label" htmlFor={clientId}>
|
||||
{formatLabel(attributes)}
|
||||
</label>
|
||||
<FormFieldDate
|
||||
field={{
|
||||
name: clientId,
|
||||
day_placeholder: MailPoet.I18n.t('customFieldDay'),
|
||||
month_placeholder: MailPoet.I18n.t('customFieldMonth'),
|
||||
year_placeholder: MailPoet.I18n.t('customFieldYear'),
|
||||
params: {
|
||||
date_type: attributes.dateType,
|
||||
date_format: attributes.dateFormat,
|
||||
},
|
||||
}}
|
||||
item={{
|
||||
[clientId]: attributes.defaultToday ? moment().format('YYYY-MM-DD') : '',
|
||||
}}
|
||||
onValueChange={() => {}}
|
||||
/>
|
||||
</div>
|
||||
<ParagraphEdit>
|
||||
<div className="mailpoet_custom_date">
|
||||
{inspectorControls}
|
||||
<label className="mailpoet_date_label" data-automation-id="editor_custom_date_label" htmlFor={clientId}>
|
||||
{formatLabel(attributes)}
|
||||
</label>
|
||||
<FormFieldDate
|
||||
field={{
|
||||
name: clientId,
|
||||
day_placeholder: MailPoet.I18n.t('customFieldDay'),
|
||||
month_placeholder: MailPoet.I18n.t('customFieldMonth'),
|
||||
year_placeholder: MailPoet.I18n.t('customFieldYear'),
|
||||
params: {
|
||||
date_type: attributes.dateType,
|
||||
date_format: attributes.dateFormat,
|
||||
},
|
||||
}}
|
||||
item={{
|
||||
[clientId]: attributes.defaultToday ? moment().format('YYYY-MM-DD') : '',
|
||||
}}
|
||||
addDefaultClasses
|
||||
onValueChange={() => {}}
|
||||
/>
|
||||
</div>
|
||||
</ParagraphEdit>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,7 @@ import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
|
||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||
import CustomFieldSettings from './custom_field_settings.jsx';
|
||||
import formatLabel from '../label_formatter.jsx';
|
||||
import mapCustomFieldFormData from '../map_custom_field_form_data.jsx';
|
||||
@ -80,7 +81,7 @@ const CustomRadioEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ParagraphEdit>
|
||||
{inspectorControls}
|
||||
<span className="mailpoet_radio_label">{getLabel()}</span>
|
||||
{Array.isArray(attributes.values) && attributes.values.map((value) => (
|
||||
@ -90,12 +91,13 @@ const CustomRadioEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
type="radio"
|
||||
disabled
|
||||
checked={value.isChecked || false}
|
||||
className="mailpoet_radio"
|
||||
/>
|
||||
{value.name}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
</ParagraphEdit>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -9,8 +9,9 @@ import { InspectorControls } from '@wordpress/block-editor';
|
||||
import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
import formatLabel from '../label_formatter.jsx';
|
||||
|
||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||
import formatLabel from '../label_formatter.jsx';
|
||||
import CustomFieldSettings from '../custom_radio/custom_field_settings.jsx';
|
||||
import mapCustomFieldFormData from '../map_custom_field_form_data.jsx';
|
||||
|
||||
@ -105,7 +106,7 @@ const CustomSelectEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ParagraphEdit>
|
||||
{inspectorControls}
|
||||
<div className="mailpoet_custom_select" data-automation-id="custom_select_block">
|
||||
{!attributes.labelWithinInput ? (
|
||||
@ -115,7 +116,7 @@ const CustomSelectEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
) : null}
|
||||
{getInput()}
|
||||
</div>
|
||||
</>
|
||||
</ParagraphEdit>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,7 @@ import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
|
||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||
import CustomFieldSettings from './custom_field_settings.jsx';
|
||||
import formatLabel from '../label_formatter.jsx';
|
||||
import mapCustomFieldFormData from '../map_custom_field_form_data.jsx';
|
||||
@ -92,7 +93,7 @@ const CustomTextEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ParagraphEdit>
|
||||
{inspectorControls}
|
||||
{!attributes.labelWithinInput ? (
|
||||
<label className="mailpoet_text_label" data-automation-id="editor_custom_text_label" htmlFor={clientId}>
|
||||
@ -100,7 +101,7 @@ const CustomTextEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
</label>
|
||||
) : null}
|
||||
{getTextInput(attributes.labelWithinInput ? formatLabel(attributes) : '')}
|
||||
</>
|
||||
</ParagraphEdit>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,7 @@ import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
|
||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||
import CustomFieldSettings from '../custom_text/custom_field_settings.jsx';
|
||||
import formatLabel from '../label_formatter.jsx';
|
||||
import mapCustomFieldFormData from '../map_custom_field_form_data.jsx';
|
||||
@ -104,7 +105,7 @@ const CustomTextAreaEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
const getTextArea = (placeholder) => (
|
||||
<textarea
|
||||
id="custom_text"
|
||||
className="mailpoet_text"
|
||||
className="mailpoet_textarea"
|
||||
name="custom_text"
|
||||
disabled
|
||||
data-automation-id="editor_custom_text_input"
|
||||
@ -114,7 +115,7 @@ const CustomTextAreaEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ParagraphEdit>
|
||||
{inspectorControls}
|
||||
{attributes.labelWithinInput ? (getTextArea(formatLabel(attributes))
|
||||
) : (
|
||||
@ -125,7 +126,7 @@ const CustomTextAreaEdit = ({ attributes, setAttributes, clientId }) => {
|
||||
{getTextArea('')}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</ParagraphEdit>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -3,5 +3,11 @@ import {
|
||||
HorizontalRule,
|
||||
} from '@wordpress/components';
|
||||
|
||||
const DividerEdit = () => (<HorizontalRule />);
|
||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||
|
||||
const DividerEdit = () => (
|
||||
<ParagraphEdit>
|
||||
<HorizontalRule className="mailpoet_divider" />
|
||||
</ParagraphEdit>
|
||||
);
|
||||
export default DividerEdit;
|
||||
|
@ -9,6 +9,8 @@ import { InspectorControls } from '@wordpress/block-editor';
|
||||
import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
|
||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||
|
||||
const EmailEdit = ({ attributes, setAttributes }) => {
|
||||
const inspectorControls = (
|
||||
<InspectorControls>
|
||||
@ -44,7 +46,7 @@ const EmailEdit = ({ attributes, setAttributes }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ParagraphEdit>
|
||||
{inspectorControls}
|
||||
{!attributes.labelWithinInput ? (
|
||||
<label className="mailpoet_text_label" data-automation-id="editor_email_label" htmlFor="email">
|
||||
@ -52,7 +54,7 @@ const EmailEdit = ({ attributes, setAttributes }) => {
|
||||
</label>
|
||||
) : null}
|
||||
{getTextInput(attributes.labelWithinInput ? `${attributes.label} *` : '')}
|
||||
</>
|
||||
</ParagraphEdit>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -9,6 +9,7 @@ import { InspectorControls } from '@wordpress/block-editor';
|
||||
import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
|
||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||
import formatLabel from '../label_formatter.jsx';
|
||||
|
||||
const FirstNameEdit = ({ attributes, setAttributes }) => {
|
||||
@ -51,7 +52,7 @@ const FirstNameEdit = ({ attributes, setAttributes }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ParagraphEdit>
|
||||
{inspectorControls}
|
||||
{!attributes.labelWithinInput ? (
|
||||
<label className="mailpoet_text_label" data-automation-id="editor_first_name_label" htmlFor="first_name">
|
||||
@ -59,7 +60,7 @@ const FirstNameEdit = ({ attributes, setAttributes }) => {
|
||||
</label>
|
||||
) : null}
|
||||
{getTextInput(attributes.labelWithinInput ? formatLabel(attributes) : '')}
|
||||
</>
|
||||
</ParagraphEdit>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -10,8 +10,22 @@ import { InspectorControls } from '@wordpress/block-editor';
|
||||
import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
import { debounce } from 'lodash';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
|
||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||
|
||||
const CustomHtmlEdit = ({ attributes, setAttributes }) => {
|
||||
const { fontColor, fontSize } = useSelect(
|
||||
(select) => {
|
||||
const settings = select('mailpoet-form-editor').getFormSettings();
|
||||
return {
|
||||
backgroundColor: settings.backgroundColor,
|
||||
fontColor: settings.fontColor,
|
||||
fontSize: settings.fontSize,
|
||||
};
|
||||
},
|
||||
[]
|
||||
);
|
||||
const [renderedContent, setRenderedContent] = useState(attributes.content);
|
||||
const setRenderedContentDebounced = useCallback(debounce((content) => {
|
||||
setRenderedContent(content);
|
||||
@ -44,14 +58,16 @@ const CustomHtmlEdit = ({ attributes, setAttributes }) => {
|
||||
</InspectorControls>
|
||||
);
|
||||
const styles = attributes.nl2br ? ['body { white-space: pre-line; }'] : [];
|
||||
if (fontColor) styles.push(` body {color: ${fontColor};}`);
|
||||
if (fontSize) styles.push(` body {font-size: ${fontSize}px }`);
|
||||
const key = `${renderedContent}_${styles}`;
|
||||
return (
|
||||
<>
|
||||
<ParagraphEdit>
|
||||
{inspectorControls}
|
||||
<div>
|
||||
<SandBox html={renderedContent} styles={styles} key={key} />
|
||||
</div>
|
||||
</>
|
||||
</ParagraphEdit>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -9,6 +9,7 @@ import { InspectorControls } from '@wordpress/block-editor';
|
||||
import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
|
||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||
import formatLabel from '../label_formatter.jsx';
|
||||
|
||||
const LastNameEdit = ({ attributes, setAttributes }) => {
|
||||
@ -51,7 +52,7 @@ const LastNameEdit = ({ attributes, setAttributes }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ParagraphEdit>
|
||||
{inspectorControls}
|
||||
{!attributes.labelWithinInput ? (
|
||||
<label className="mailpoet_text_label" data-automation-id="editor_last_name_label" htmlFor="last_name">
|
||||
@ -59,7 +60,7 @@ const LastNameEdit = ({ attributes, setAttributes }) => {
|
||||
</label>
|
||||
) : null}
|
||||
{getTextInput(attributes.labelWithinInput ? formatLabel(attributes) : '')}
|
||||
</>
|
||||
</ParagraphEdit>
|
||||
);
|
||||
};
|
||||
|
||||
|
14
assets/js/src/form_editor/blocks/paragraph_edit.jsx
Normal file
14
assets/js/src/form_editor/blocks/paragraph_edit.jsx
Normal file
@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const ParagraphEdit = ({ children }) => (
|
||||
<div className="mailpoet_paragraph">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
ParagraphEdit.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export default ParagraphEdit;
|
@ -1,9 +1,8 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
CheckboxControl,
|
||||
} from '@wordpress/components';
|
||||
import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
|
||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||
import Settings from './settings.jsx';
|
||||
|
||||
const SegmentSelectEdit = ({ attributes, setAttributes }) => {
|
||||
@ -12,17 +11,21 @@ const SegmentSelectEdit = ({ attributes, setAttributes }) => {
|
||||
return (<p className="mailpoet_error">{MailPoet.I18n.t('blockSegmentSelectNoLists')}</p>);
|
||||
}
|
||||
return attributes.values.map((value) => (
|
||||
<CheckboxControl
|
||||
label={value.name}
|
||||
checked={!!value.isChecked}
|
||||
disabled
|
||||
key={value.id}
|
||||
/>
|
||||
<label key={value.id} className="mailpoet_checkbox_label">
|
||||
<input
|
||||
type="checkbox"
|
||||
disabled
|
||||
key={value.id}
|
||||
checked={!!value.isChecked}
|
||||
className="mailpoet_checkbox"
|
||||
/>
|
||||
{value.name}
|
||||
</label>
|
||||
));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ParagraphEdit>
|
||||
<Settings
|
||||
label={attributes.label}
|
||||
onLabelChanged={(label) => (setAttributes({ label }))}
|
||||
@ -39,7 +42,7 @@ const SegmentSelectEdit = ({ attributes, setAttributes }) => {
|
||||
{attributes.label}
|
||||
</span>
|
||||
{renderValues()}
|
||||
</>
|
||||
</ParagraphEdit>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -8,6 +8,8 @@ import { InspectorControls } from '@wordpress/block-editor';
|
||||
import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
|
||||
import ParagraphEdit from '../paragraph_edit.jsx';
|
||||
|
||||
const SubmitEdit = ({ attributes, setAttributes }) => {
|
||||
const inspectorControls = (
|
||||
<InspectorControls>
|
||||
@ -26,17 +28,15 @@ const SubmitEdit = ({ attributes, setAttributes }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ParagraphEdit>
|
||||
{ inspectorControls }
|
||||
<div className="mailpoet_submit">
|
||||
<input
|
||||
className="button"
|
||||
type="submit"
|
||||
value={attributes.label}
|
||||
data-automation-id="editor_submit_input"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
<input
|
||||
className="button mailpoet_submit"
|
||||
type="submit"
|
||||
value={attributes.label}
|
||||
data-automation-id="editor_submit_input"
|
||||
/>
|
||||
</ParagraphEdit>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -17,6 +17,7 @@ import Notices from './notices.jsx';
|
||||
import UnsavedChangesNotice from './unsaved_changes_notice.jsx';
|
||||
import FormStyles from './form_styles.jsx';
|
||||
import Preview from './preview.jsx';
|
||||
import FormStylingBackground from './form_styling_background.jsx';
|
||||
|
||||
// Editor settings - see @wordpress/block-editor/src/store/defaults.js
|
||||
const editorSettings = {
|
||||
@ -67,12 +68,16 @@ export default () => {
|
||||
<BlockSelectionClearer className="edit-post-visual-editor editor-styles-wrapper">
|
||||
<BlockEditorKeyboardShortcuts />
|
||||
<BlockEditorKeyboardShortcuts.Register />
|
||||
<WritingFlow>
|
||||
<ObserveTyping>
|
||||
<FormTitle />
|
||||
<BlockList />
|
||||
</ObserveTyping>
|
||||
</WritingFlow>
|
||||
<div className="mailpoet_form">
|
||||
<FormStylingBackground>
|
||||
<WritingFlow>
|
||||
<ObserveTyping>
|
||||
<FormTitle />
|
||||
<BlockList />
|
||||
</ObserveTyping>
|
||||
</WritingFlow>
|
||||
</FormStylingBackground>
|
||||
</div>
|
||||
</BlockSelectionClearer>
|
||||
</div>
|
||||
<div className="block-editor-editor-skeleton__sidebar">
|
||||
|
@ -3,6 +3,7 @@ import React from 'react';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
import { partial } from 'lodash';
|
||||
import BasicSettingsPanel from './basic_settings_panel.jsx';
|
||||
import StylesSettingsPanel from './styles_settings_panel.jsx';
|
||||
import FormPlacementPanel from './form_placement_panel.jsx';
|
||||
import CustomCssPanel from './custom_css_panel.jsx';
|
||||
|
||||
@ -19,6 +20,10 @@ export default () => {
|
||||
isOpened={openedPanels.includes('basic-settings')}
|
||||
onToggle={partial(toggleSidebarPanel, 'basic-settings')}
|
||||
/>
|
||||
<StylesSettingsPanel
|
||||
isOpened={openedPanels.includes('styles-settings')}
|
||||
onToggle={partial(toggleSidebarPanel, 'styles-settings')}
|
||||
/>
|
||||
<FormPlacementPanel
|
||||
isOpened={openedPanels.includes('form-placement')}
|
||||
onToggle={partial(toggleSidebarPanel, 'form-placement')}
|
||||
|
@ -0,0 +1,114 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
ColorIndicator,
|
||||
ColorPalette,
|
||||
FontSizePicker,
|
||||
Panel,
|
||||
PanelBody,
|
||||
} from '@wordpress/components';
|
||||
import MailPoet from 'mailpoet';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelect, useDispatch } from '@wordpress/data';
|
||||
|
||||
const BasicSettingsPanel = ({ onToggle, isOpened }) => {
|
||||
const { changeFormSettings } = useDispatch('mailpoet-form-editor');
|
||||
const settings = useSelect(
|
||||
(select) => select('mailpoet-form-editor').getFormSettings(),
|
||||
[]
|
||||
);
|
||||
const setBackgroundColor = (color) => {
|
||||
changeFormSettings({
|
||||
...settings,
|
||||
backgroundColor: color,
|
||||
});
|
||||
};
|
||||
const setFontColor = (color) => {
|
||||
changeFormSettings({
|
||||
...settings,
|
||||
fontColor: color,
|
||||
});
|
||||
};
|
||||
const setFontSize = (size) => {
|
||||
changeFormSettings({
|
||||
...settings,
|
||||
fontSize: size,
|
||||
});
|
||||
};
|
||||
const { settingsColors, fontSizes } = useSelect(
|
||||
(select) => {
|
||||
const { getSettings } = select('core/block-editor');
|
||||
return {
|
||||
settingsColors: getSettings().colors,
|
||||
fontSizes: getSettings().fontSizes,
|
||||
};
|
||||
},
|
||||
[]
|
||||
);
|
||||
return (
|
||||
<Panel>
|
||||
<PanelBody
|
||||
title={MailPoet.I18n.t('formSettingsStyles')}
|
||||
opened={isOpened}
|
||||
onToggle={onToggle}
|
||||
>
|
||||
<div className="mailpoet-styles-settings">
|
||||
<div>
|
||||
<h3 className="mailpoet-styles-settings-heading">
|
||||
{MailPoet.I18n.t('formSettingsStylesBackgroundColor')}
|
||||
{
|
||||
settings.backgroundColor !== undefined
|
||||
&& (
|
||||
<ColorIndicator
|
||||
colorValue={settings.backgroundColor}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</h3>
|
||||
<ColorPalette
|
||||
value={settings.backgroundColor}
|
||||
onChange={setBackgroundColor}
|
||||
colors={settingsColors}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="mailpoet-styles-settings-heading">
|
||||
{MailPoet.I18n.t('formSettingsStylesFontColor')}
|
||||
{
|
||||
settings.fontColor !== undefined
|
||||
&& (
|
||||
<ColorIndicator
|
||||
colorValue={settings.fontColor}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</h3>
|
||||
<ColorPalette
|
||||
value={settings.fontColor}
|
||||
onChange={setFontColor}
|
||||
colors={settingsColors}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="mailpoet-styles-settings-heading">
|
||||
{MailPoet.I18n.t('formSettingsStylesFontSize')}
|
||||
</h3>
|
||||
<FontSizePicker
|
||||
value={settings.fontSize}
|
||||
onChange={setFontSize}
|
||||
fontSizes={fontSizes}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</PanelBody>
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
||||
BasicSettingsPanel.propTypes = {
|
||||
onToggle: PropTypes.func.isRequired,
|
||||
isOpened: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default BasicSettingsPanel;
|
@ -0,0 +1,38 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
|
||||
const FormStylingBackground = ({ children }) => {
|
||||
const { fontColor, backgroundColor, fontSize } = useSelect(
|
||||
(select) => {
|
||||
const settings = select('mailpoet-form-editor').getFormSettings();
|
||||
return {
|
||||
backgroundColor: settings.backgroundColor,
|
||||
fontColor: settings.fontColor,
|
||||
fontSize: settings.fontSize,
|
||||
};
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
let font;
|
||||
if (fontSize) font = Number(fontSize);
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
backgroundColor,
|
||||
color: fontColor,
|
||||
fontSize: font,
|
||||
lineHeight: 1.2,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
FormStylingBackground.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export default FormStylingBackground;
|
@ -1,4 +1,10 @@
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import React, {
|
||||
useEffect,
|
||||
useState,
|
||||
useCallback,
|
||||
useRef,
|
||||
useLayoutEffect,
|
||||
} from 'react';
|
||||
import MailPoet from 'mailpoet';
|
||||
import { Spinner } from '@wordpress/components';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
@ -8,6 +14,7 @@ import Modal from '../../common/modal/modal.jsx';
|
||||
import blocksToFormBody from '../store/blocks_to_form_body.jsx';
|
||||
|
||||
const FormPreview = () => {
|
||||
const formEl = useRef(null);
|
||||
const [form, setForm] = useState(null);
|
||||
|
||||
const formBlocks = useSelect(
|
||||
@ -18,6 +25,10 @@ const FormPreview = () => {
|
||||
(select) => select('mailpoet-form-editor').getAllAvailableCustomFields(),
|
||||
[]
|
||||
);
|
||||
const settings = useSelect(
|
||||
(select) => select('mailpoet-form-editor').getFormSettings(),
|
||||
[]
|
||||
);
|
||||
|
||||
const { hidePreview } = useDispatch('mailpoet-form-editor');
|
||||
const isPreview = useSelect(
|
||||
@ -32,11 +43,12 @@ const FormPreview = () => {
|
||||
action: 'previewEditor',
|
||||
data: {
|
||||
body: blocksToFormBody(formBlocks, customFields),
|
||||
settings,
|
||||
},
|
||||
}).done((response) => {
|
||||
setForm(response.data);
|
||||
});
|
||||
}, [formBlocks, customFields]);
|
||||
}, [formBlocks, customFields, settings]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isPreview) {
|
||||
@ -44,6 +56,13 @@ const FormPreview = () => {
|
||||
}
|
||||
}, [isPreview, loadFormPreviewFromServer]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
// eslint-disable-next-line camelcase
|
||||
if (formEl.current && form?.form_element_styles) {
|
||||
formEl.current.setAttribute('style', form.form_element_styles);
|
||||
}
|
||||
}, [formEl, form]);
|
||||
|
||||
if (!isPreview) return null;
|
||||
|
||||
function onClose() {
|
||||
@ -69,12 +88,20 @@ const FormPreview = () => {
|
||||
{'.mailpoet_hp_email_label { display: none }' }
|
||||
{form.css}
|
||||
</style>
|
||||
{/* eslint-disable-next-line react/no-danger */}
|
||||
<div dangerouslySetInnerHTML={{ __html: form.html }} />
|
||||
<div className="mailpoet_message">
|
||||
<p className="mailpoet_validate_success">{MailPoet.I18n.t('successMessage')}</p>
|
||||
<p className="mailpoet_validate_error">{MailPoet.I18n.t('errorMessage')}</p>
|
||||
</div>
|
||||
<form
|
||||
target="_self"
|
||||
method="post"
|
||||
className="mailpoet_form "
|
||||
noValidate
|
||||
ref={formEl}
|
||||
>
|
||||
{/* eslint-disable-next-line react/no-danger */}
|
||||
<div dangerouslySetInnerHTML={{ __html: form.html }} />
|
||||
<div className="mailpoet_message">
|
||||
<p className="mailpoet_validate_success">{MailPoet.I18n.t('successMessage')}</p>
|
||||
<p className="mailpoet_validate_error">{MailPoet.I18n.t('errorMessage')}</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Preview>
|
||||
)}
|
||||
|
@ -13,6 +13,7 @@ import ListingFilters from 'listing/filters.jsx';
|
||||
import ListingItems from 'listing/listing_items.jsx';
|
||||
import MailerError from 'listing/notices.jsx';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { GlobalContext } from 'context/index.jsx';
|
||||
|
||||
class Listing extends React.Component {
|
||||
constructor(props) {
|
||||
@ -190,8 +191,8 @@ class Listing extends React.Component {
|
||||
});
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
@ -266,8 +267,8 @@ class Listing extends React.Component {
|
||||
}
|
||||
this.getItems();
|
||||
}).fail((response) => {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
});
|
||||
@ -295,8 +296,8 @@ class Listing extends React.Component {
|
||||
}
|
||||
this.getItems();
|
||||
}).fail((response) => {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
});
|
||||
@ -324,8 +325,8 @@ class Listing extends React.Component {
|
||||
}
|
||||
this.getItems();
|
||||
}).fail((response) => {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
});
|
||||
@ -344,8 +345,8 @@ class Listing extends React.Component {
|
||||
// redirect to default group
|
||||
this.handleGroup('all');
|
||||
}).fail((response) => {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
});
|
||||
@ -383,8 +384,8 @@ class Listing extends React.Component {
|
||||
this.getItems();
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
@ -685,6 +686,8 @@ class Listing extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
Listing.contextType = GlobalContext;
|
||||
|
||||
/* eslint-disable react/require-default-props */
|
||||
Listing.propTypes = {
|
||||
limit: PropTypes.number,
|
||||
|
@ -6,7 +6,7 @@ import Marionette from 'backbone.marionette';
|
||||
import $ from 'jquery';
|
||||
import Blob from 'blob';
|
||||
import FileSaver from 'file-saver';
|
||||
import * as Thumbnail from 'common/thumbnail.jsx';
|
||||
import * as Thumbnail from 'common/thumbnail.ts';
|
||||
import _ from 'underscore';
|
||||
|
||||
var Module = {};
|
||||
|
@ -6,6 +6,7 @@ import EventOptions from 'newsletters/automatic_emails/events/event_options.jsx'
|
||||
import MailPoet from 'mailpoet';
|
||||
import _ from 'underscore';
|
||||
import PropTypes from 'prop-types';
|
||||
import { GlobalContext } from 'context/index.jsx';
|
||||
|
||||
const defaultAfterTimeType = 'immediate';
|
||||
const defaultAfterTimeNumber = 1;
|
||||
@ -205,8 +206,8 @@ class EventsConditions extends React.Component {
|
||||
history.push(`/template/${response.data.id}`);
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
@ -245,6 +246,8 @@ class EventsConditions extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
EventsConditions.contextType = GlobalContext;
|
||||
|
||||
EventsConditions.propTypes = {
|
||||
history: PropTypes.shape({
|
||||
push: PropTypes.func.isRequired,
|
||||
|
@ -3,7 +3,7 @@ import MailPoet from 'mailpoet';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
import APIErrorsNotice from 'notices/api_errors_notice.jsx';
|
||||
import APIErrorsNotice from 'notices/api_errors_notice.tsx';
|
||||
|
||||
const QueuePropType = PropTypes.shape({
|
||||
status: PropTypes.string,
|
||||
|
@ -8,13 +8,14 @@ import NotificationNewsletterFields from 'newsletters/send/notification.jsx';
|
||||
import WelcomeNewsletterFields from 'newsletters/send/welcome.jsx';
|
||||
import HelpTooltip from 'help-tooltip.jsx';
|
||||
import jQuery from 'jquery';
|
||||
import { fromUrl } from 'common/thumbnail.jsx';
|
||||
import { fromUrl } from 'common/thumbnail.ts';
|
||||
import Hooks from 'wp-js-hooks';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import ReactStringReplace from 'react-string-replace';
|
||||
import SubscribersLimitNotice from 'notices/subscribers_limit_notice.jsx';
|
||||
import slugify from 'slugify';
|
||||
import { GlobalContext } from 'context/index.jsx';
|
||||
|
||||
const generateGaTrackingCampaignName = (id, subject) => {
|
||||
const name = slugify(subject, { lower: true })
|
||||
@ -242,16 +243,16 @@ class NewsletterSend extends React.Component {
|
||||
if (_.isFunction(customResponse)) {
|
||||
customResponse();
|
||||
} else if (response.data.status === 'scheduled') {
|
||||
MailPoet.Notice.success(
|
||||
MailPoet.I18n.t('newsletterHasBeenScheduled')
|
||||
this.context.notices.success(
|
||||
<p>{MailPoet.I18n.t('newsletterHasBeenScheduled')}</p>
|
||||
);
|
||||
MailPoet.trackEvent('Emails > Newsletter sent', {
|
||||
scheduled: true,
|
||||
'MailPoet Free version': window.mailpoet_version,
|
||||
});
|
||||
} else {
|
||||
MailPoet.Notice.success(
|
||||
MailPoet.I18n.t('newsletterBeingSent'),
|
||||
this.context.notices.success(
|
||||
<p>{MailPoet.I18n.t('newsletterBeingSent')}</p>,
|
||||
{ id: 'mailpoet_notice_being_sent' }
|
||||
);
|
||||
MailPoet.trackEvent('Emails > Newsletter sent', {
|
||||
@ -288,8 +289,8 @@ class NewsletterSend extends React.Component {
|
||||
const opts = this.state.item.options;
|
||||
// display success message depending on newsletter type
|
||||
if (response.data.type === 'welcome') {
|
||||
MailPoet.Notice.success(
|
||||
MailPoet.I18n.t('welcomeEmailActivated')
|
||||
this.context.notices.success(
|
||||
<p>{MailPoet.I18n.t('welcomeEmailActivated')}</p>
|
||||
);
|
||||
MailPoet.trackEvent('Emails > Welcome email activated', {
|
||||
'MailPoet Free version': window.mailpoet_version,
|
||||
@ -297,8 +298,8 @@ class NewsletterSend extends React.Component {
|
||||
Delay: `${opts.afterTimeNumber} ${opts.afterTimeType}`,
|
||||
});
|
||||
} else if (response.data.type === 'notification') {
|
||||
MailPoet.Notice.success(
|
||||
MailPoet.I18n.t('postNotificationActivated')
|
||||
this.context.notices.success(
|
||||
<p>{MailPoet.I18n.t('postNotificationActivated')}</p>
|
||||
);
|
||||
MailPoet.trackEvent('Emails > Post notifications activated', {
|
||||
'MailPoet Free version': window.mailpoet_version,
|
||||
@ -330,16 +331,11 @@ class NewsletterSend extends React.Component {
|
||||
},
|
||||
}).done(() => {
|
||||
this.props.history.push(`/${this.state.item.type || ''}`);
|
||||
MailPoet.Notice.success(
|
||||
MailPoet.I18n.t('newsletterSendingHasBeenResumed')
|
||||
this.context.notices.success(
|
||||
<p>{MailPoet.I18n.t('newsletterSendingHasBeenResumed')}</p>
|
||||
);
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
this.showError(response);
|
||||
});
|
||||
})
|
||||
.fail((err) => {
|
||||
@ -356,8 +352,8 @@ class NewsletterSend extends React.Component {
|
||||
e.preventDefault();
|
||||
|
||||
this.saveNewsletter(e).done(() => {
|
||||
MailPoet.Notice.success(
|
||||
MailPoet.I18n.t('newsletterUpdated')
|
||||
this.context.notices.success(
|
||||
<p>{MailPoet.I18n.t('newsletterUpdated')}</p>
|
||||
);
|
||||
}).done(() => {
|
||||
const path = this.state.item.type === 'automatic' ? this.state.item.options.group : this.state.item.type;
|
||||
@ -372,8 +368,8 @@ class NewsletterSend extends React.Component {
|
||||
const redirectTo = e.target.href;
|
||||
|
||||
this.saveNewsletter(e).done(() => {
|
||||
MailPoet.Notice.success(
|
||||
MailPoet.I18n.t('newsletterUpdated')
|
||||
this.context.notices.success(
|
||||
<p>{MailPoet.I18n.t('newsletterUpdated')}</p>
|
||||
);
|
||||
}).done(() => {
|
||||
window.location = redirectTo;
|
||||
@ -407,8 +403,8 @@ class NewsletterSend extends React.Component {
|
||||
|
||||
showError = (response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
@ -528,6 +524,8 @@ class NewsletterSend extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
NewsletterSend.contextType = GlobalContext;
|
||||
|
||||
NewsletterSend.propTypes = {
|
||||
match: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
|
@ -8,6 +8,7 @@ import ImportTemplate from 'newsletters/templates/import_template.jsx';
|
||||
import Hooks from 'wp-js-hooks';
|
||||
import _ from 'underscore';
|
||||
import PropTypes from 'prop-types';
|
||||
import { GlobalContext } from 'context/index.jsx';
|
||||
|
||||
const getEditorUrl = (id) => `admin.php?page=mailpoet-newsletter-editor&id=${id}`;
|
||||
|
||||
@ -87,8 +88,8 @@ class NewsletterTemplates extends React.Component {
|
||||
this.sortTemplates();
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
@ -158,8 +159,8 @@ class NewsletterTemplates extends React.Component {
|
||||
}
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
@ -277,6 +278,8 @@ class NewsletterTemplates extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
NewsletterTemplates.contextType = GlobalContext;
|
||||
|
||||
NewsletterTemplates.propTypes = {
|
||||
match: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
|
@ -3,6 +3,7 @@ import _ from 'underscore';
|
||||
import MailPoet from 'mailpoet';
|
||||
import HelpTooltip from 'help-tooltip.jsx';
|
||||
import PropTypes from 'prop-types';
|
||||
import { GlobalContext } from 'context/index.jsx';
|
||||
|
||||
class ImportTemplate extends React.Component {
|
||||
constructor(props) {
|
||||
@ -51,8 +52,8 @@ class ImportTemplate extends React.Component {
|
||||
afterImport(true, response.data);
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
@ -77,7 +78,7 @@ class ImportTemplate extends React.Component {
|
||||
'MailPoet Free version': window.mailpoet_version,
|
||||
});
|
||||
} catch (err) {
|
||||
MailPoet.Notice.error(MailPoet.I18n.t('templateFileMalformedError'));
|
||||
this.context.notices.error(<p>{MailPoet.I18n.t('templateFileMalformedError')}</p>);
|
||||
}
|
||||
};
|
||||
|
||||
@ -115,6 +116,8 @@ class ImportTemplate extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
ImportTemplate.contextType = GlobalContext;
|
||||
|
||||
ImportTemplate.propTypes = {
|
||||
beforeImport: PropTypes.func.isRequired,
|
||||
afterImport: PropTypes.func.isRequired,
|
||||
|
@ -3,6 +3,7 @@ import MailPoet from 'mailpoet';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import confirmAlert from 'common/confirm_alert.jsx';
|
||||
import { GlobalContext } from 'context/index.jsx';
|
||||
|
||||
/**
|
||||
* props = {
|
||||
@ -35,8 +36,8 @@ class TemplateBox extends React.Component {
|
||||
afterDelete(true, id);
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
@ -81,8 +82,8 @@ class TemplateBox extends React.Component {
|
||||
afterSelect(true, response.data.id);
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
@ -158,6 +159,8 @@ class TemplateBox extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
TemplateBox.contextType = GlobalContext;
|
||||
|
||||
TemplateBox.propTypes = {
|
||||
index: PropTypes.number.isRequired,
|
||||
id: PropTypes.string.isRequired,
|
||||
|
@ -5,6 +5,7 @@ import Breadcrumb from 'newsletters/breadcrumb.jsx';
|
||||
import Hooks from 'wp-js-hooks';
|
||||
import _ from 'underscore';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { GlobalContext } from 'context/index.jsx';
|
||||
|
||||
class NewsletterTypes extends React.Component {
|
||||
constructor(props) {
|
||||
@ -108,7 +109,12 @@ class NewsletterTypes extends React.Component {
|
||||
'MailPoet Free version': window.mailpoet_version,
|
||||
});
|
||||
} catch (response) {
|
||||
MailPoet.Notice.showApiErrorNotice(response, { scroll: true });
|
||||
if (response.errors.length > 0) {
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -134,8 +140,8 @@ class NewsletterTypes extends React.Component {
|
||||
}).fail((response) => {
|
||||
this.setState({ isCreating: false });
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
@ -289,6 +295,8 @@ class NewsletterTypes extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
NewsletterTypes.contextType = GlobalContext;
|
||||
|
||||
NewsletterTypes.propTypes = {
|
||||
filter: PropTypes.func,
|
||||
history: PropTypes.shape({
|
||||
|
@ -5,6 +5,7 @@ import Breadcrumb from 'newsletters/breadcrumb.jsx';
|
||||
import _ from 'underscore';
|
||||
import Scheduling from 'newsletters/types/notification/scheduling.jsx';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { GlobalContext } from 'context/index.jsx';
|
||||
|
||||
const field = {
|
||||
name: 'options',
|
||||
@ -45,8 +46,8 @@ class NewsletterNotification extends React.Component {
|
||||
this.showTemplateSelection(response.data.id);
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
@ -84,6 +85,8 @@ class NewsletterNotification extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
NewsletterNotification.contextType = GlobalContext;
|
||||
|
||||
NewsletterNotification.propTypes = {
|
||||
history: PropTypes.shape({
|
||||
push: PropTypes.func.isRequired,
|
||||
|
@ -3,6 +3,7 @@ import React from 'react';
|
||||
import MailPoet from 'mailpoet';
|
||||
import Breadcrumb from 'newsletters/breadcrumb.jsx';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { GlobalContext } from 'context/index.jsx';
|
||||
|
||||
class NewsletterStandard extends React.Component {
|
||||
componentDidMount() {
|
||||
@ -18,8 +19,8 @@ class NewsletterStandard extends React.Component {
|
||||
this.showTemplateSelection(response.data.id);
|
||||
}).fail((response) => {
|
||||
if (response.errors.length > 0) {
|
||||
MailPoet.Notice.error(
|
||||
response.errors.map((error) => error.message),
|
||||
this.context.notices.error(
|
||||
response.errors.map((error) => <p key={error.message}>{error.message}</p>),
|
||||
{ scroll: true }
|
||||
);
|
||||
}
|
||||
@ -40,6 +41,8 @@ class NewsletterStandard extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
NewsletterStandard.contextType = GlobalContext;
|
||||
|
||||
NewsletterStandard.propTypes = {
|
||||
history: PropTypes.shape({
|
||||
push: PropTypes.func.isRequired,
|
||||
|
@ -1,15 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Notice from 'notices/notice.jsx';
|
||||
|
||||
const APIErrorsNotice = ({ errors }) => {
|
||||
if (errors.length < 1) return null;
|
||||
return <Notice type="error" closable={false}>{errors.map((err) => <p key={err.message}>{err.message}</p>)}</Notice>;
|
||||
};
|
||||
APIErrorsNotice.propTypes = {
|
||||
errors: PropTypes.arrayOf(PropTypes.shape({
|
||||
message: PropTypes.string.isRequired,
|
||||
})).isRequired,
|
||||
};
|
||||
|
||||
export default APIErrorsNotice;
|
13
assets/js/src/notices/api_errors_notice.tsx
Normal file
13
assets/js/src/notices/api_errors_notice.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import Notice from 'notices/notice';
|
||||
|
||||
type Props = {
|
||||
errors: Array<{ message: string }>
|
||||
}
|
||||
|
||||
const APIErrorsNotice = ({ errors }: Props) => {
|
||||
if (errors.length < 1) return null;
|
||||
return <Notice type="error" closable={false}>{errors.map((err) => <p key={err.message}>{err.message}</p>)}</Notice>;
|
||||
};
|
||||
|
||||
export default APIErrorsNotice;
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Notice from 'notices/notice.jsx';
|
||||
import Notice from 'notices/notice.tsx';
|
||||
|
||||
const MailerStatusNotice = ({ error }) => {
|
||||
if (!error || error.operation !== 'authorization') return null;
|
||||
|
@ -1,8 +1,18 @@
|
||||
import React from 'react';
|
||||
import React, { ReactNode } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import MailPoet from 'mailpoet';
|
||||
|
||||
type Props = {
|
||||
type: 'success' | 'info' | 'warning' | 'error';
|
||||
children: ReactNode;
|
||||
scroll?: boolean;
|
||||
closable?: boolean;
|
||||
renderInPlace?: boolean;
|
||||
onDisplay?: () => void;
|
||||
onClose?: () => void;
|
||||
timeout?: number | false;
|
||||
};
|
||||
|
||||
const Notice = ({
|
||||
onClose,
|
||||
onDisplay,
|
||||
@ -12,7 +22,7 @@ const Notice = ({
|
||||
children,
|
||||
closable,
|
||||
type,
|
||||
}) => {
|
||||
}: Props) => {
|
||||
const [hidden, setHidden] = React.useState(false);
|
||||
const elementRef = React.useRef(null);
|
||||
const timeoutRef = React.useRef(null);
|
||||
@ -24,7 +34,7 @@ const Notice = ({
|
||||
|
||||
React.useEffect(() => {
|
||||
if (timeout) {
|
||||
timeoutRef.current = setTimeout(close, timeout);
|
||||
timeoutRef.current = setTimeout(close, timeout as number);
|
||||
}
|
||||
return () => (timeoutRef.current ? clearTimeout(timeoutRef.current) : null);
|
||||
}, [close, timeout]);
|
||||
@ -61,20 +71,6 @@ const Notice = ({
|
||||
document.getElementById('mailpoet_notices')
|
||||
);
|
||||
};
|
||||
Notice.propTypes = {
|
||||
type: PropTypes.oneOf(['success', 'info', 'warning', 'error']).isRequired,
|
||||
scroll: PropTypes.bool,
|
||||
closable: PropTypes.bool,
|
||||
renderInPlace: PropTypes.bool,
|
||||
onDisplay: PropTypes.func,
|
||||
onClose: PropTypes.func,
|
||||
timeout: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf([false])]),
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.element,
|
||||
PropTypes.arrayOf(PropTypes.element),
|
||||
]).isRequired,
|
||||
};
|
||||
Notice.defaultProps = {
|
||||
timeout: 10000,
|
||||
scroll: false,
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { GlobalContext } from 'context/index.jsx';
|
||||
import Notice from './notice.jsx';
|
||||
import Notice from './notice.tsx';
|
||||
|
||||
export default () => {
|
||||
const { notices } = React.useContext(GlobalContext);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import MailPoet from 'mailpoet';
|
||||
import Notice from 'notices/notice.jsx';
|
||||
import Notice from 'notices/notice.tsx';
|
||||
|
||||
const SubscribersLimitNotice = () => {
|
||||
if (!window.mailpoet_subscribers_limit_reached) return null;
|
||||
|
@ -119,6 +119,7 @@ class Forms extends APIEndpoint {
|
||||
return $this->successResponse([
|
||||
'html' => $html,
|
||||
'css' => $css,
|
||||
'form_element_styles' => $this->formRenderer->renderFormElementStyles($data),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,7 @@ class BlockRendererHelper {
|
||||
return join(' ', $validation);
|
||||
}
|
||||
|
||||
public function renderLabel(array $block): string {
|
||||
public function renderLabel(array $block, array $formSettings): string {
|
||||
$html = '';
|
||||
if (
|
||||
isset($block['params']['hide_label'])
|
||||
@ -98,7 +98,10 @@ class BlockRendererHelper {
|
||||
}
|
||||
if (isset($block['params']['label'])
|
||||
&& strlen(trim($block['params']['label'])) > 0) {
|
||||
$html .= '<label class="mailpoet_' . $block['type'] . '_label">';
|
||||
$html .= '<label '
|
||||
. 'class="mailpoet_' . $block['type'] . '_label" '
|
||||
. $this->renderFontStyle($formSettings)
|
||||
. '>';
|
||||
$html .= htmlspecialchars($block['params']['label']);
|
||||
|
||||
if (isset($block['params']['required']) && $block['params']['required']) {
|
||||
@ -110,6 +113,15 @@ class BlockRendererHelper {
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function renderFontStyle(array $formSettings) {
|
||||
if (isset($formSettings['fontSize'])) {
|
||||
return 'style="'
|
||||
. 'font-size: ' . trim($formSettings['fontSize']) . 'px;'
|
||||
. 'line-height: ' . trim($formSettings['fontSize']) * 1.2 . 'px";';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public function renderInputPlaceholder(array $block): string {
|
||||
$html = '';
|
||||
// if the label is displayed as a placeholder,
|
||||
|
@ -17,7 +17,7 @@ class Checkbox {
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function render(array $block): string {
|
||||
public function render(array $block, array $formSettings): string {
|
||||
$html = '';
|
||||
|
||||
$fieldName = 'data[' . $this->rendererHelper->getFieldName($block) . ']';
|
||||
@ -25,7 +25,7 @@ class Checkbox {
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= $this->rendererHelper->renderLabel($block);
|
||||
$html .= $this->rendererHelper->renderLabel($block, $formSettings);
|
||||
|
||||
$options = (!empty($block['params']['values'])
|
||||
? $block['params']['values']
|
||||
@ -35,7 +35,8 @@ class Checkbox {
|
||||
$selectedValue = $this->rendererHelper->getFieldValue($block);
|
||||
|
||||
foreach ($options as $option) {
|
||||
$html .= '<label class="mailpoet_checkbox_label">';
|
||||
$html .= '<label class="mailpoet_checkbox_label" '
|
||||
. $this->rendererHelper->renderFontStyle($formSettings) . '>';
|
||||
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
|
||||
|
||||
$html .= 'name="' . $fieldName . '" ';
|
||||
|
@ -11,10 +11,10 @@ class Date {
|
||||
$this->rendererHelper = $rendererHelper;
|
||||
}
|
||||
|
||||
public function render(array $block): string {
|
||||
public function render(array $block, array $formSettings): string {
|
||||
$html = '';
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
$html .= $this->rendererHelper->renderLabel($block);
|
||||
$html .= $this->rendererHelper->renderLabel($block, $formSettings);
|
||||
$html .= $this->renderDateSelect($block);
|
||||
$html .= '</p>';
|
||||
|
||||
|
@ -3,7 +3,14 @@
|
||||
namespace MailPoet\Form\Block;
|
||||
|
||||
class Html {
|
||||
public function render(array $block): string {
|
||||
/** @var BlockRendererHelper */
|
||||
private $rendererHelper;
|
||||
|
||||
public function __construct(BlockRendererHelper $rendererHelper) {
|
||||
$this->rendererHelper = $rendererHelper;
|
||||
}
|
||||
|
||||
public function render(array $block, array $formSettings): string {
|
||||
$html = '';
|
||||
$text = '';
|
||||
|
||||
@ -15,7 +22,7 @@ class Html {
|
||||
$text = nl2br($text);
|
||||
}
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
$html .= '<p class="mailpoet_paragraph" ' . $this->rendererHelper->renderFontStyle($formSettings) . '>';
|
||||
$html .= $text;
|
||||
$html .= '</p>';
|
||||
|
||||
|
@ -17,7 +17,7 @@ class Radio {
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function render(array $block): string {
|
||||
public function render(array $block, array $formSettings): string {
|
||||
$html = '';
|
||||
|
||||
$fieldName = 'data[' . $this->rendererHelper->getFieldName($block) . ']';
|
||||
@ -25,7 +25,7 @@ class Radio {
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= $this->rendererHelper->renderLabel($block);
|
||||
$html .= $this->rendererHelper->renderLabel($block, $formSettings);
|
||||
|
||||
$options = (!empty($block['params']['values'])
|
||||
? $block['params']['values']
|
||||
@ -35,7 +35,9 @@ class Radio {
|
||||
$selectedValue = $this->rendererHelper->getFieldValue($block);
|
||||
|
||||
foreach ($options as $option) {
|
||||
$html .= '<label class="mailpoet_radio_label">';
|
||||
$html .= '<label class="mailpoet_radio_label" '
|
||||
. $this->rendererHelper->renderFontStyle($formSettings)
|
||||
. '>';
|
||||
|
||||
$html .= '<input type="radio" class="mailpoet_radio" ';
|
||||
|
||||
|
@ -17,7 +17,7 @@ class Segment {
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function render(array $block): string {
|
||||
public function render(array $block, array $formSettings): string {
|
||||
$html = '';
|
||||
|
||||
$fieldName = 'data[' . $this->rendererHelper->getFieldName($block) . ']';
|
||||
@ -25,7 +25,7 @@ class Segment {
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= $this->rendererHelper->renderLabel($block);
|
||||
$html .= $this->rendererHelper->renderLabel($block, $formSettings);
|
||||
|
||||
$options = (!empty($block['params']['values'])
|
||||
? $block['params']['values']
|
||||
@ -37,7 +37,9 @@ class Segment {
|
||||
|
||||
$isChecked = (isset($option['is_checked']) && $option['is_checked']) ? 'checked="checked"' : '';
|
||||
|
||||
$html .= '<label class="mailpoet_checkbox_label">';
|
||||
$html .= '<label class="mailpoet_checkbox_label" '
|
||||
. $this->rendererHelper->renderFontStyle($formSettings)
|
||||
. '>';
|
||||
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
|
||||
$html .= 'name="' . $fieldName . '[]" ';
|
||||
$html .= 'value="' . $option['id'] . '" ' . $isChecked . ' ';
|
||||
|
@ -17,13 +17,13 @@ class Select {
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function render(array $block): string {
|
||||
public function render(array $block, array $formSettings): string {
|
||||
$html = '';
|
||||
|
||||
$fieldName = 'data[' . $this->rendererHelper->getFieldName($block) . ']';
|
||||
$automationId = ($block['id'] == 'status') ? 'data-automation-id="form_status"' : '';
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
$html .= $this->rendererHelper->renderLabel($block);
|
||||
$html .= $this->rendererHelper->renderLabel($block, $formSettings);
|
||||
$html .= '<select class="mailpoet_select" name="' . $fieldName . '" ' . $automationId . '>';
|
||||
|
||||
if (isset($block['params']['label_within']) && $block['params']['label_within']) {
|
||||
|
@ -11,7 +11,7 @@ class Text {
|
||||
$this->rendererHelper = $rendererHelper;
|
||||
}
|
||||
|
||||
public function render(array $block): string {
|
||||
public function render(array $block, array $formSettings): string {
|
||||
$type = 'text';
|
||||
$automationId = ' ';
|
||||
if ($block['id'] === 'email') {
|
||||
@ -21,7 +21,7 @@ class Text {
|
||||
|
||||
$html = '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= $this->rendererHelper->renderLabel($block);
|
||||
$html .= $this->rendererHelper->renderLabel($block, $formSettings);
|
||||
|
||||
$html .= '<input type="' . $type . '" class="mailpoet_text" ';
|
||||
|
||||
|
@ -10,12 +10,12 @@ class Textarea {
|
||||
$this->rendererHelper = $rendererHelper;
|
||||
}
|
||||
|
||||
public function render(array $block): string {
|
||||
public function render(array $block, array $formSettings): string {
|
||||
$html = '';
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= $this->rendererHelper->renderLabel($block);
|
||||
$html .= $this->rendererHelper->renderLabel($block, $formSettings);
|
||||
|
||||
$lines = (isset($block['params']['lines']) ? (int)$block['params']['lines'] : 1);
|
||||
|
||||
|
@ -68,11 +68,11 @@ class BlocksRenderer {
|
||||
$this->textarea = $textarea;
|
||||
}
|
||||
|
||||
public function renderBlock(array $block = []): string {
|
||||
public function renderBlock(array $block = [], array $formSettings): string {
|
||||
$html = '';
|
||||
switch ($block['type']) {
|
||||
case 'html':
|
||||
$html .= $this->html->render($block);
|
||||
$html .= $this->html->render($block, $formSettings);
|
||||
break;
|
||||
|
||||
case 'divider':
|
||||
@ -80,31 +80,31 @@ class BlocksRenderer {
|
||||
break;
|
||||
|
||||
case 'checkbox':
|
||||
$html .= $this->checkbox->render($block);
|
||||
$html .= $this->checkbox->render($block, $formSettings);
|
||||
break;
|
||||
|
||||
case 'radio':
|
||||
$html .= $this->radio->render($block);
|
||||
$html .= $this->radio->render($block, $formSettings);
|
||||
break;
|
||||
|
||||
case 'segment':
|
||||
$html .= $this->segment->render($block);
|
||||
$html .= $this->segment->render($block, $formSettings);
|
||||
break;
|
||||
|
||||
case 'date':
|
||||
$html .= $this->date->render($block);
|
||||
$html .= $this->date->render($block, $formSettings);
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
$html .= $this->select->render($block);
|
||||
$html .= $this->select->render($block, $formSettings);
|
||||
break;
|
||||
|
||||
case 'text':
|
||||
$html .= $this->text->render($block);
|
||||
$html .= $this->text->render($block, $formSettings);
|
||||
break;
|
||||
|
||||
case 'textarea':
|
||||
$html .= $this->textarea->render($block);
|
||||
$html .= $this->textarea->render($block, $formSettings);
|
||||
break;
|
||||
|
||||
case 'submit':
|
||||
|
@ -94,15 +94,18 @@ class DisplayFormInWPContent {
|
||||
$formData = [
|
||||
'body' => $form->getBody(),
|
||||
'styles' => $form->getStyles(),
|
||||
'settings' => $form->getSettings(),
|
||||
];
|
||||
$formSettings = $form->getSettings();
|
||||
$htmlId = 'mp_form_below_' . $form->getId();
|
||||
$templateData = [
|
||||
'form_html_id' => 'mp_form_below_' . $form->getId(),
|
||||
'form_html_id' => $htmlId,
|
||||
'form_id' => $form->getId(),
|
||||
'form_success_message' => $formSettings['success_message'] ?? null,
|
||||
'form_type' => 'below_post',
|
||||
'styles' => $this->formRenderer->renderStyles($formData, '#' . $form->getId()),
|
||||
'styles' => $this->formRenderer->renderStyles($formData, '#' . $htmlId),
|
||||
'html' => $this->formRenderer->renderHTML($formData),
|
||||
'form_element_styles' => $this->formRenderer->renderFormElementStyles($formData),
|
||||
];
|
||||
|
||||
// (POST) non ajax success/error variables
|
||||
|
@ -37,7 +37,7 @@ class Renderer {
|
||||
|
||||
public function renderHTML(array $form = []): string {
|
||||
if (isset($form['body']) && !empty($form['body'])) {
|
||||
return $this->renderBlocks($form['body']);
|
||||
return $this->renderBlocks($form['body'], $form['settings'] ?? []);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
@ -51,14 +51,14 @@ class Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
public function renderBlocks(array $blocks = [], bool $honeypotEnabled = true): string {
|
||||
public function renderBlocks(array $blocks = [], array $formSettings = [], bool $honeypotEnabled = true): string {
|
||||
// add honeypot for spambots
|
||||
$html = ($honeypotEnabled) ? $this->renderHoneypot() : '';
|
||||
foreach ($blocks as $key => $block) {
|
||||
if ($block['type'] == 'submit' && $this->settings->get('captcha.type') === Captcha::TYPE_RECAPTCHA) {
|
||||
$html .= $this->renderReCaptcha();
|
||||
}
|
||||
$html .= $this->blocksRenderer->renderBlock($block) . PHP_EOL;
|
||||
$html .= $this->blocksRenderer->renderBlock($block, $formSettings) . PHP_EOL;
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
@ -88,4 +88,20 @@ class Renderer {
|
||||
<input class="mailpoet_recaptcha_field" type="hidden" name="recaptcha">
|
||||
</div>';
|
||||
}
|
||||
|
||||
public function renderFormElementStyles(array $form): string {
|
||||
if (!isset($form['settings'])) return '';
|
||||
$formSettings = $form['settings'];
|
||||
$styles = [];
|
||||
|
||||
if (isset($formSettings['backgroundColor'])) {
|
||||
$styles[] = 'background-color: ' . trim($formSettings['backgroundColor']);
|
||||
}
|
||||
|
||||
if (isset($formSettings['fontColor'])) {
|
||||
$styles[] = 'color: ' . trim($formSettings['fontColor']);
|
||||
}
|
||||
|
||||
return join(';', $styles);
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ class Styles {
|
||||
private $defaultStyles = <<<EOL
|
||||
/* form */
|
||||
.mailpoet_form {
|
||||
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* paragraphs (label + input) */
|
||||
@ -48,7 +48,7 @@ class Styles {
|
||||
.mailpoet_checkbox {
|
||||
}
|
||||
|
||||
.mailpoet_submit input {
|
||||
.mailpoet_submit {
|
||||
}
|
||||
|
||||
.mailpoet_divider {
|
||||
|
@ -226,6 +226,7 @@ class Widget extends \WP_Widget {
|
||||
'after_widget' => $afterWidget,
|
||||
'before_title' => $beforeTitle,
|
||||
'after_title' => $afterTitle,
|
||||
'form_element_styles' => $this->formRenderer->renderFormElementStyles($form),
|
||||
];
|
||||
|
||||
// (POST) non ajax success/error variables
|
||||
|
@ -115,7 +115,7 @@ class CaptchaRenderer {
|
||||
$formHtml .= '</p>';
|
||||
|
||||
// subscription form
|
||||
$formHtml .= $this->formRenderer->renderBlocks($form, $honeypot = false);
|
||||
$formHtml .= $this->formRenderer->renderBlocks($form, [], $honeypot = false);
|
||||
$formHtml .= '</div>';
|
||||
$formHtml .= $this->renderFormMessages($formModel, $showSuccessMessage, $showErrorMessage);
|
||||
$formHtml .= '</form>';
|
||||
|
@ -497,7 +497,7 @@ class Pages {
|
||||
$formHtml .= '</p>';
|
||||
|
||||
// subscription form
|
||||
$formHtml .= $this->formRenderer->renderBlocks($form, $honeypot = false);
|
||||
$formHtml .= $this->formRenderer->renderBlocks($form, [], $honeypot = false);
|
||||
$formHtml .= '</form>';
|
||||
return $formHtml;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
/*
|
||||
* Plugin Name: MailPoet 3 (New)
|
||||
* Version: 3.46.0
|
||||
* Version: 3.46.2
|
||||
* Plugin URI: http://www.mailpoet.com
|
||||
* Description: Create and send newsletters, post notifications and welcome emails from your WordPress.
|
||||
* Author: MailPoet
|
||||
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
$mailpoetPlugin = [
|
||||
'version' => '3.46.0',
|
||||
'version' => '3.46.2',
|
||||
'filename' => __FILE__,
|
||||
'path' => dirname(__FILE__),
|
||||
'autoloader' => dirname(__FILE__) . '/vendor/autoload.php',
|
||||
|
343
package-lock.json
generated
343
package-lock.json
generated
@ -2408,6 +2408,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/plugin-syntax-typescript": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.8.3.tgz",
|
||||
"integrity": "sha512-GO1MQ/SGGGoiEXY0e0bSpHimJvxqB7lktLLIq2pv8xG7WZ8IMEle74jIe1FhprHBWjwjZtXHkycDLZXIWM5Wfg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-plugin-utils": "^7.8.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
|
||||
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/plugin-transform-arrow-functions": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz",
|
||||
@ -3283,6 +3300,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/plugin-transform-typescript": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.8.3.tgz",
|
||||
"integrity": "sha512-Ebj230AxcrKGZPKIp4g4TdQLrqX95TobLUWKd/CwG7X1XHUH1ZpkpFvXuXqWbtGRWb7uuEWNlrl681wsOArAdQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.8.3",
|
||||
"@babel/helper-plugin-utils": "^7.8.3",
|
||||
"@babel/plugin-syntax-typescript": "^7.8.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
|
||||
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/plugin-transform-unicode-regex": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz",
|
||||
@ -3449,6 +3485,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/preset-typescript": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.8.3.tgz",
|
||||
"integrity": "sha512-qee5LgPGui9zQ0jR1TeU5/fP9L+ovoArklEqY12ek8P/wV5ZeM/VYSQYwICeoT6FfpJTekG9Ilay5PhwsOpMHA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-plugin-utils": "^7.8.3",
|
||||
"@babel/plugin-transform-typescript": "^7.8.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
|
||||
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/register": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/register/-/register-7.8.3.tgz",
|
||||
@ -3812,9 +3866,9 @@
|
||||
}
|
||||
},
|
||||
"@popperjs/core": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.0.5.tgz",
|
||||
"integrity": "sha512-YOV1TitTNzJDXe/14sDJO/M/aL12Jhind0EkQRnqTX2167fqJsAICJfi0vsDdapPI1WaYsheyYYgy6PO02Nqqg=="
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.0.6.tgz",
|
||||
"integrity": "sha512-zj7Gw8QC4jmR92eKUvtrZUEpl2ypRbq+qlE4pwf9n2hnUO9BOAcWUs4/Ht+gNIbFt98xtqhLvccdCfD469MzpQ=="
|
||||
},
|
||||
"@sinonjs/commons": {
|
||||
"version": "1.7.0",
|
||||
@ -3885,6 +3939,12 @@
|
||||
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/eslint-visitor-keys": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
|
||||
"integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/events": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
|
||||
@ -3902,6 +3962,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz",
|
||||
"integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/minimatch": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
||||
@ -3931,6 +3997,22 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
|
||||
},
|
||||
"@types/prop-types": {
|
||||
"version": "15.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
|
||||
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/react": {
|
||||
"version": "16.9.22",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.22.tgz",
|
||||
"integrity": "sha512-7OSt4EGiLvy0h5R7X+r0c7S739TCU/LvWbkNOrm10lUwNHe7XPz5OLhLOSZeCkqO9JSCly1NkYJ7ODTUqVnHJQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@types/unist": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
|
||||
@ -3957,6 +4039,137 @@
|
||||
"vfile-message": "*"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "2.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.21.0.tgz",
|
||||
"integrity": "sha512-b5jjjDMxzcjh/Sbjuo7WyhrQmVJg0WipTHQgXh5Xwx10uYm6nPWqN1WGOsaNq4HR3Zh4wUx4IRQdDkCHwyewyw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/experimental-utils": "2.21.0",
|
||||
"eslint-utils": "^1.4.3",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"regexpp": "^3.0.0",
|
||||
"tsutils": "^3.17.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"regexpp": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz",
|
||||
"integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/experimental-utils": {
|
||||
"version": "2.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.21.0.tgz",
|
||||
"integrity": "sha512-olKw9JP/XUkav4lq0I7S1mhGgONJF9rHNhKFn9wJlpfRVjNo3PPjSvybxEldvCXnvD+WAshSzqH5cEjPp9CsBA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.3",
|
||||
"@typescript-eslint/typescript-estree": "2.21.0",
|
||||
"eslint-scope": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-scope": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
|
||||
"integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esrecurse": "^4.1.0",
|
||||
"estraverse": "^4.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "2.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.21.0.tgz",
|
||||
"integrity": "sha512-VrmbdrrrvvI6cPPOG7uOgGUFXNYTiSbnRq8ZMyuGa4+qmXJXVLEEz78hKuqupvkpwJQNk1Ucz1TenrRP90gmBg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/eslint-visitor-keys": "^1.0.0",
|
||||
"@typescript-eslint/experimental-utils": "2.21.0",
|
||||
"@typescript-eslint/typescript-estree": "2.21.0",
|
||||
"eslint-visitor-keys": "^1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-visitor-keys": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz",
|
||||
"integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "2.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.21.0.tgz",
|
||||
"integrity": "sha512-NC/nogZNb9IK2MEFQqyDBAciOT8Lp8O3KgAfvHx2Skx6WBo+KmDqlU3R9KxHONaijfTIKtojRe3SZQyMjr3wBw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^4.1.1",
|
||||
"eslint-visitor-keys": "^1.1.0",
|
||||
"glob": "^7.1.6",
|
||||
"is-glob": "^4.0.1",
|
||||
"lodash": "^4.17.15",
|
||||
"semver": "^6.3.0",
|
||||
"tsutils": "^3.17.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"eslint-visitor-keys": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz",
|
||||
"integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==",
|
||||
"dev": true
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-glob": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
|
||||
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz",
|
||||
@ -4169,14 +4382,14 @@
|
||||
}
|
||||
},
|
||||
"@wordpress/block-directory": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/block-directory/-/block-directory-1.5.0.tgz",
|
||||
"integrity": "sha512-LxVOYsWFNhVIIFgVLChBWWo+g/tUT4UKBvN4IF9afoOmF6SYp9VDHuEfQzUO/FeWlyuYK2gvcqYOdhzLnw7BuA==",
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/block-directory/-/block-directory-1.5.1.tgz",
|
||||
"integrity": "sha512-YdlatnSHjw0dKxr4mqKT10awrVYC//kHrwtRrfg2z98+O+4uVsWN9E0mtHzFmYQHRFK3Ep/+GqIgp2RyH8TMgQ==",
|
||||
"requires": {
|
||||
"@wordpress/api-fetch": "^3.11.0",
|
||||
"@wordpress/block-editor": "^3.7.0",
|
||||
"@wordpress/block-editor": "^3.7.1",
|
||||
"@wordpress/blocks": "^6.12.0",
|
||||
"@wordpress/components": "^9.2.0",
|
||||
"@wordpress/components": "^9.2.1",
|
||||
"@wordpress/compose": "^3.11.0",
|
||||
"@wordpress/data": "^4.14.0",
|
||||
"@wordpress/element": "^2.11.0",
|
||||
@ -4187,15 +4400,15 @@
|
||||
}
|
||||
},
|
||||
"@wordpress/block-editor": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/block-editor/-/block-editor-3.7.0.tgz",
|
||||
"integrity": "sha512-8qKVQUeXbRctCnBVmcg+G/uc8+LGaGOT++iD0FRGK3C3HjMQ1qWiwhUFvXZukMUWQaiw5tJWGMOxmVb3TI4Z5A==",
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/block-editor/-/block-editor-3.7.1.tgz",
|
||||
"integrity": "sha512-joZBiYY4iqSpyFJBsPvEJQjILxdywESTu4ACAKb8SGQ19DIa3vkuS6FTEsmdy+YfkRiohhPAsd17mLZAv0tb1g==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@wordpress/a11y": "^2.7.0",
|
||||
"@wordpress/blob": "^2.7.0",
|
||||
"@wordpress/blocks": "^6.12.0",
|
||||
"@wordpress/components": "^9.2.0",
|
||||
"@wordpress/components": "^9.2.1",
|
||||
"@wordpress/compose": "^3.11.0",
|
||||
"@wordpress/data": "^4.14.0",
|
||||
"@wordpress/deprecated": "^2.7.0",
|
||||
@ -4241,25 +4454,25 @@
|
||||
}
|
||||
},
|
||||
"@wordpress/block-library": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/block-library/-/block-library-2.14.0.tgz",
|
||||
"integrity": "sha512-LAKUGnlrV5bdTRX/QnTItKMlhBIEsMgW3E9PWxYBUhrFIhrcrAu007jW8Q6oqsMNyDeakNPpd2MderTGAAzJpw==",
|
||||
"version": "2.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/block-library/-/block-library-2.14.1.tgz",
|
||||
"integrity": "sha512-gq+PKbnnQr/kFm29Cqh5n9EABL1V/Ey79eItfNhzCle92r79kgUwfDjRvoVbzikNU5F1j392ojpZK8EQCn+T8w==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@wordpress/a11y": "^2.7.0",
|
||||
"@wordpress/api-fetch": "^3.11.0",
|
||||
"@wordpress/autop": "^2.6.0",
|
||||
"@wordpress/blob": "^2.7.0",
|
||||
"@wordpress/block-editor": "^3.7.0",
|
||||
"@wordpress/block-editor": "^3.7.1",
|
||||
"@wordpress/blocks": "^6.12.0",
|
||||
"@wordpress/components": "^9.2.0",
|
||||
"@wordpress/components": "^9.2.1",
|
||||
"@wordpress/compose": "^3.11.0",
|
||||
"@wordpress/core-data": "^2.12.0",
|
||||
"@wordpress/data": "^4.14.0",
|
||||
"@wordpress/date": "^3.8.0",
|
||||
"@wordpress/deprecated": "^2.7.0",
|
||||
"@wordpress/dom": "^2.8.0",
|
||||
"@wordpress/editor": "^9.12.0",
|
||||
"@wordpress/editor": "^9.12.1",
|
||||
"@wordpress/element": "^2.11.0",
|
||||
"@wordpress/escape-html": "^1.7.0",
|
||||
"@wordpress/i18n": "^3.9.0",
|
||||
@ -4268,7 +4481,7 @@
|
||||
"@wordpress/keycodes": "^2.9.0",
|
||||
"@wordpress/primitives": "^1.1.0",
|
||||
"@wordpress/rich-text": "^3.12.0",
|
||||
"@wordpress/server-side-render": "^1.8.0",
|
||||
"@wordpress/server-side-render": "^1.8.1",
|
||||
"@wordpress/url": "^2.11.0",
|
||||
"@wordpress/viewport": "^2.13.0",
|
||||
"classnames": "^2.2.5",
|
||||
@ -4316,9 +4529,9 @@
|
||||
}
|
||||
},
|
||||
"@wordpress/components": {
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/components/-/components-9.2.0.tgz",
|
||||
"integrity": "sha512-8KETp5Dafq1uYaQc3D9EWqPG/pM8ffGyqwCGr7n+Gc9v86v7ctIWNz2iJvjY1Pw7Sr/AlezhstOVE5z8sHMZag==",
|
||||
"version": "9.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/components/-/components-9.2.1.tgz",
|
||||
"integrity": "sha512-OAfibZccphrOmQyc8PF4Y5b5iAGCrzrySh9tgCP1tgYkzY9RwULmYnAFDtrYjfCF9najPTI6Snvea5z7huwlJg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@emotion/core": "^10.0.22",
|
||||
@ -4453,28 +4666,28 @@
|
||||
}
|
||||
},
|
||||
"@wordpress/edit-post": {
|
||||
"version": "3.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/edit-post/-/edit-post-3.13.0.tgz",
|
||||
"integrity": "sha512-VNZi8QryeoUwN1shjB1G0DSEoFICVkAUsj/gCtC3iG5NVlT2UTRUwrNa45IFZ9uMNSOdDVL5ydAoSOIauqpJ3Q==",
|
||||
"version": "3.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/edit-post/-/edit-post-3.13.1.tgz",
|
||||
"integrity": "sha512-ypHBgc+tO7N2Syyqxe/aHh2AlJ1qXNQ01IIeeESATpwlrLpAap+QrSbdALri3p9L1mHVWPRVbwdB42usfzshRw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@wordpress/a11y": "^2.7.0",
|
||||
"@wordpress/api-fetch": "^3.11.0",
|
||||
"@wordpress/block-editor": "^3.7.0",
|
||||
"@wordpress/block-library": "^2.14.0",
|
||||
"@wordpress/block-editor": "^3.7.1",
|
||||
"@wordpress/block-library": "^2.14.1",
|
||||
"@wordpress/blocks": "^6.12.0",
|
||||
"@wordpress/components": "^9.2.0",
|
||||
"@wordpress/components": "^9.2.1",
|
||||
"@wordpress/compose": "^3.11.0",
|
||||
"@wordpress/core-data": "^2.12.0",
|
||||
"@wordpress/data": "^4.14.0",
|
||||
"@wordpress/editor": "^9.12.0",
|
||||
"@wordpress/editor": "^9.12.1",
|
||||
"@wordpress/element": "^2.11.0",
|
||||
"@wordpress/hooks": "^2.7.0",
|
||||
"@wordpress/i18n": "^3.9.0",
|
||||
"@wordpress/icons": "^1.1.0",
|
||||
"@wordpress/keyboard-shortcuts": "^1.1.0",
|
||||
"@wordpress/keycodes": "^2.9.0",
|
||||
"@wordpress/media-utils": "^1.7.0",
|
||||
"@wordpress/media-utils": "^1.7.1",
|
||||
"@wordpress/notices": "^2.0.0",
|
||||
"@wordpress/plugins": "^2.12.0",
|
||||
"@wordpress/url": "^2.11.0",
|
||||
@ -4487,18 +4700,18 @@
|
||||
}
|
||||
},
|
||||
"@wordpress/editor": {
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/editor/-/editor-9.12.0.tgz",
|
||||
"integrity": "sha512-4Ub/ksSsMX347kA+dO3lgPqEF7XKgUTuqsuegXiXVqotxczU0FWPumvWtCkcBr5lodBs1OtDgJzQYujQ/Sk3ww==",
|
||||
"version": "9.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/editor/-/editor-9.12.1.tgz",
|
||||
"integrity": "sha512-WjwQV+vESD63HBgi7ueBXzPt0enEZBi2SGzrfj/zPI1mLskNZTC0Ep6iKhU+PCLBJC6W/OoYct5PeMd2BjbuVA==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@wordpress/api-fetch": "^3.11.0",
|
||||
"@wordpress/autop": "^2.6.0",
|
||||
"@wordpress/blob": "^2.7.0",
|
||||
"@wordpress/block-directory": "^1.5.0",
|
||||
"@wordpress/block-editor": "^3.7.0",
|
||||
"@wordpress/block-directory": "^1.5.1",
|
||||
"@wordpress/block-editor": "^3.7.1",
|
||||
"@wordpress/blocks": "^6.12.0",
|
||||
"@wordpress/components": "^9.2.0",
|
||||
"@wordpress/components": "^9.2.1",
|
||||
"@wordpress/compose": "^3.11.0",
|
||||
"@wordpress/core-data": "^2.12.0",
|
||||
"@wordpress/data": "^4.14.0",
|
||||
@ -4513,10 +4726,10 @@
|
||||
"@wordpress/is-shallow-equal": "^1.8.0",
|
||||
"@wordpress/keyboard-shortcuts": "^1.1.0",
|
||||
"@wordpress/keycodes": "^2.9.0",
|
||||
"@wordpress/media-utils": "^1.7.0",
|
||||
"@wordpress/media-utils": "^1.7.1",
|
||||
"@wordpress/notices": "^2.0.0",
|
||||
"@wordpress/rich-text": "^3.12.0",
|
||||
"@wordpress/server-side-render": "^1.8.0",
|
||||
"@wordpress/server-side-render": "^1.8.1",
|
||||
"@wordpress/url": "^2.11.0",
|
||||
"@wordpress/viewport": "^2.13.0",
|
||||
"@wordpress/wordcount": "^2.7.0",
|
||||
@ -4641,9 +4854,9 @@
|
||||
}
|
||||
},
|
||||
"@wordpress/media-utils": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/media-utils/-/media-utils-1.7.0.tgz",
|
||||
"integrity": "sha512-SPfCB1BKC6PZ3BArYXjAf2aQXKeYGVKLL0sVt/k81bNngkfBUE8/cJ/vnNhrIzYPr/ZJX72IgDzOvWzS6fpm2w==",
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/media-utils/-/media-utils-1.7.1.tgz",
|
||||
"integrity": "sha512-cfcCAvhrCUMjYjBhbtKO1Y5GqFvxFqosYykkbDifbwj8DA+P8+Fh2Q9aWKieVh8d7RAES3DqFVY7qvINkKiYMw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@wordpress/api-fetch": "^3.11.0",
|
||||
@ -4725,13 +4938,13 @@
|
||||
}
|
||||
},
|
||||
"@wordpress/server-side-render": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/server-side-render/-/server-side-render-1.8.0.tgz",
|
||||
"integrity": "sha512-u8aGO5ygmb8fiskev0mXvjNSl1oxHe7czbBZ2MSYWnbdu0VpJdPDkj7eWNSxbpQKCDj1gjNgVPAcarWrK9fdKA==",
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@wordpress/server-side-render/-/server-side-render-1.8.1.tgz",
|
||||
"integrity": "sha512-JLLwyY6W/KxALMc72R1KgrtTaiHoyNzCjNI8bVD192z+gFTFdBg8d7F3CUMwaCzkfKxf09Y0zn7955c0S6k3Ew==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.8.3",
|
||||
"@wordpress/api-fetch": "^3.11.0",
|
||||
"@wordpress/components": "^9.2.0",
|
||||
"@wordpress/components": "^9.2.1",
|
||||
"@wordpress/data": "^4.14.0",
|
||||
"@wordpress/deprecated": "^2.7.0",
|
||||
"@wordpress/element": "^2.11.0",
|
||||
@ -5793,6 +6006,25 @@
|
||||
"@babel/helper-plugin-utils": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-typescript-to-proptypes": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-typescript-to-proptypes/-/babel-plugin-typescript-to-proptypes-1.2.1.tgz",
|
||||
"integrity": "sha512-D44MNR2bEORkudJdntPoi13EaKfzXlDSCg8XZ6YMBrKxSAFFPTcOrYiPizKU+tdkojdM7bbgL6QAghsyO9R3Xg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-module-imports": "^7.8.3",
|
||||
"@babel/helper-plugin-utils": "^7.8.3",
|
||||
"@babel/plugin-syntax-typescript": "^7.8.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
|
||||
"integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-register": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
|
||||
@ -7316,9 +7548,9 @@
|
||||
}
|
||||
},
|
||||
"csstype": {
|
||||
"version": "2.6.8",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.8.tgz",
|
||||
"integrity": "sha512-msVS9qTuMT5zwAGCVm4mxfrZ18BNc6Csd0oJAtiFMZ1FAx1CCvy2+5MDmYoix63LM/6NDbNtodCiGYGmFgO0dA=="
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.9.tgz",
|
||||
"integrity": "sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q=="
|
||||
},
|
||||
"currently-unhandled": {
|
||||
"version": "0.4.1",
|
||||
@ -16996,6 +17228,15 @@
|
||||
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
|
||||
"dev": true
|
||||
},
|
||||
"tsutils": {
|
||||
"version": "3.17.1",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz",
|
||||
"integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.8.1"
|
||||
}
|
||||
},
|
||||
"tty-browserify": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
||||
@ -17059,6 +17300,12 @@
|
||||
"is-typedarray": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.8.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.2.tgz",
|
||||
"integrity": "sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"version": "0.7.21",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz",
|
||||
|
21
package.json
21
package.json
@ -10,24 +10,27 @@
|
||||
"not dead"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "npm run lint6 && npm run lint5 && npm run lint-tests",
|
||||
"lint": "npm run lint6 && npm run lint-ts && npm run lint5 && npm run lint-tests",
|
||||
"lint6": "eslint -c .eslintrc.es6.json --max-warnings 0 'assets/js/src/**/*.jsx' 'tests/javascript/**/*.js'",
|
||||
"lint-ts": "eslint -c .eslintrc.ts.json --max-warnings 0 'assets/js/src/**/*.tsx' 'assets/js/src/**/*.ts'",
|
||||
"lint5": "eslint -c .eslintrc.es5.json --ignore-pattern helpscout.js --max-warnings 0 'assets/js/src/**/*.js'",
|
||||
"lint-tests": "eslint -c .eslintrc.tests_newsletter_editor.json --max-warnings 0 'tests/javascript_newsletter_editor'",
|
||||
"autoprefixer": "postcss assets/dist/css/*.css --use autoprefixer --no-map --replace",
|
||||
"scss": "node-sass assets/css/src/ --output assets/dist/css/ --output-style compact",
|
||||
"stylelint": "stylelint --fix",
|
||||
"test": "mocha --require @babel/register tests/javascript/**/*.spec.js"
|
||||
"test": "mocha --require @babel/register tests/javascript/**/*.spec.js",
|
||||
"check-types": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.4",
|
||||
"@babel/runtime-corejs3": "^7.8.4",
|
||||
"@wordpress/block-editor": "^3.7.0",
|
||||
"@wordpress/block-editor": "^3.7.1",
|
||||
"@wordpress/block-library": "^2.14.1",
|
||||
"@wordpress/blocks": "^6.12.0",
|
||||
"@wordpress/components": "^9.2.0",
|
||||
"@wordpress/components": "^9.2.1",
|
||||
"@wordpress/data": "^4.14.0",
|
||||
"@wordpress/edit-post": "^3.13.0",
|
||||
"@wordpress/editor": "^9.12.0",
|
||||
"@wordpress/edit-post": "^3.13.1",
|
||||
"@wordpress/editor": "^9.12.1",
|
||||
"@wordpress/element": "^2.11.0",
|
||||
"@wordpress/hooks": "^2.7.0",
|
||||
"@wordpress/i18n": "^3.9.0",
|
||||
@ -81,11 +84,16 @@
|
||||
"@babel/plugin-transform-runtime": "^7.8.3",
|
||||
"@babel/preset-env": "^7.8.4",
|
||||
"@babel/preset-react": "^7.8.3",
|
||||
"@babel/preset-typescript": "^7.8.3",
|
||||
"@babel/register": "^7.8.3",
|
||||
"@types/react": "^16.9.22",
|
||||
"@typescript-eslint/eslint-plugin": "^2.21.0",
|
||||
"@typescript-eslint/parser": "^2.21.0",
|
||||
"autoprefixer": "^9.7.4",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-loader": "^8.0.4",
|
||||
"babel-plugin-transform-commonjs": "^1.1.4",
|
||||
"babel-plugin-typescript-to-proptypes": "^1.2.1",
|
||||
"chai": "^4.2.0",
|
||||
"chai-jq": "0.0.9",
|
||||
"clean-webpack-plugin": "^1.0.0",
|
||||
@ -118,6 +126,7 @@
|
||||
"stylelint-order": "^4.0.0",
|
||||
"stylelint-scss": "^3.14.0",
|
||||
"terser-webpack-plugin": "^1.4.3",
|
||||
"typescript": "^3.8.2",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-cli": "^3.2.1",
|
||||
"webpack-manifest-plugin": "^2.0.4"
|
||||
|
@ -3,7 +3,7 @@ Contributors: mailpoet, wysija
|
||||
Tags: email, email marketing, post notification, woocommerce emails, email automation, newsletter, newsletter builder, newsletter subscribers
|
||||
Requires at least: 4.7
|
||||
Tested up to: 5.3
|
||||
Stable tag: 3.46.0
|
||||
Stable tag: 3.46.2
|
||||
Requires PHP: 5.6
|
||||
License: GPLv3
|
||||
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
||||
@ -184,6 +184,12 @@ Check our [Knowledge Base](https://kb.mailpoet.com) or contact us through our [s
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 3.46.2 - 2020-03-03 =
|
||||
* Editor: delete block confirmation links are white again.
|
||||
|
||||
= 3.46.1 - 2020-02-25 =
|
||||
* Improved: minor changes and fixes.
|
||||
|
||||
= 3.46.0 - 2020-02-17 =
|
||||
* Added: MailPoet now has a Gutenberg block for subscription forms;
|
||||
* Improved: preview links now works publicly;
|
||||
|
@ -48,7 +48,7 @@ class ThrottlingTest extends \MailPoetTest {
|
||||
|
||||
$ip2 = SubscriberIP::create();
|
||||
$ip2->ip = '127.0.0.1';
|
||||
$ip2->createdAt = Carbon::now()->subMonths(1)->subSeconds(1);
|
||||
$ip2->createdAt = Carbon::now()->subDays(30)->subSeconds(1);
|
||||
$ip2->save();
|
||||
|
||||
expect(SubscriberIP::count())->equals(2);
|
||||
|
@ -224,7 +224,7 @@ describe('Save', function () {
|
||||
trackEvent: function () {},
|
||||
},
|
||||
'newsletter_editor/App': EditorApplication,
|
||||
'common/thumbnail.jsx': {
|
||||
'common/thumbnail.ts': {
|
||||
fromNewsletter: function () {
|
||||
return promiseMock;
|
||||
},
|
||||
|
@ -42,15 +42,15 @@ class BlockRendererHelperTest extends \MailPoetUnitTest {
|
||||
|
||||
public function testItShouldRenderLabel() {
|
||||
$block = $this->block;
|
||||
$label = $this->rendererHelper->renderLabel($block);
|
||||
expect($label)->equals('<label class="mailpoet_text_label">Input label</label>');
|
||||
$label = $this->rendererHelper->renderLabel($block, []);
|
||||
expect($label)->regExp('#<label.*class="mailpoet_text_label".*>Input label</label>#m');
|
||||
|
||||
$block['params']['required'] = '1';
|
||||
$label = $this->rendererHelper->renderLabel($block);
|
||||
expect($label)->equals('<label class="mailpoet_text_label">Input label <span class="mailpoet_required">*</span></label>');
|
||||
$label = $this->rendererHelper->renderLabel($block, []);
|
||||
expect($label)->equals('<label class="mailpoet_text_label" >Input label <span class="mailpoet_required">*</span></label>');
|
||||
|
||||
$block['params']['hide_label'] = '1';
|
||||
$label = $this->rendererHelper->renderLabel($block);
|
||||
$label = $this->rendererHelper->renderLabel($block, []);
|
||||
expect($label)->equals('');
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ class CheckboxTest extends \MailPoetUnitTest {
|
||||
$this->rendererHelperMock->expects($this->once())->method('getFieldName')->willReturn('Field name');
|
||||
$this->rendererHelperMock->expects($this->once())->method('getInputValidation')->willReturn('validation="1"');
|
||||
$this->rendererHelperMock->expects($this->once())->method('getFieldValue')->willReturn('1');
|
||||
$html = $this->checkbox->render($this->block);
|
||||
$html = $this->checkbox->render($this->block, []);
|
||||
$checkboxLabel = $this->htmlParser->getElementByXpath($html, "//label[@class='mailpoet_checkbox_label']");
|
||||
expect($checkboxLabel->nodeValue)->equals(' Checkbox label');
|
||||
$checkbox = $this->htmlParser->getChildElement($checkboxLabel, 'input');
|
||||
|
@ -48,7 +48,7 @@ class DateTest extends \MailPoetUnitTest {
|
||||
$this->baseMock->expects($this->once())->method('getFieldName')->willReturn('Field name');
|
||||
$this->baseMock->expects($this->any())->method('getInputValidation')->willReturn(' validation="1" ');
|
||||
|
||||
$html = $this->date->render($this->block);
|
||||
$html = $this->date->render($this->block, []);
|
||||
$mothsSelect = $this->htmlParser->getElementByXpath($html, "//select", 0);
|
||||
$yearsSelect = $this->htmlParser->getElementByXpath($html, "//select", 1);
|
||||
expect($mothsSelect->childNodes->length)->equals(13); // Months + placeholder
|
||||
@ -73,7 +73,7 @@ class DateTest extends \MailPoetUnitTest {
|
||||
$block['params']['date_type'] = 'year_month_day';
|
||||
$block['params']['date_format'] = 'MM/DD/YYYY';
|
||||
|
||||
$html = $this->date->render($block);
|
||||
$html = $this->date->render($block, []);
|
||||
$mothsSelect = $this->htmlParser->getElementByXpath($html, "//select", 0);
|
||||
$daysSelect = $this->htmlParser->getElementByXpath($html, "//select", 1);
|
||||
$yearsSelect = $this->htmlParser->getElementByXpath($html, "//select", 2);
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace MailPoet\Test\Form\Block;
|
||||
|
||||
use MailPoet\Form\Block\BlockRendererHelper;
|
||||
use MailPoet\Form\Block\Html;
|
||||
|
||||
class HtmlTest extends \MailPoetUnitTest {
|
||||
@ -23,25 +24,25 @@ class HtmlTest extends \MailPoetUnitTest {
|
||||
|
||||
public function _before() {
|
||||
parent::_before();
|
||||
$this->html = new Html();
|
||||
$this->html = new Html($this->createMock(BlockRendererHelper::class));
|
||||
}
|
||||
|
||||
public function testItShouldRenderCustomHtml() {
|
||||
$html = $this->html->render($this->block);
|
||||
expect($html)->equals("<p class=\"mailpoet_paragraph\">line1<br />\nline2</p>");
|
||||
$html = $this->html->render($this->block, []);
|
||||
expect($html)->equals("<p class=\"mailpoet_paragraph\" >line1<br />\nline2</p>");
|
||||
}
|
||||
|
||||
public function testItShouldRenderCustomHtmlWithoutAutomaticBrs() {
|
||||
$block = $this->block;
|
||||
$block['params']['nl2br'] = '';
|
||||
$html = $this->html->render($block);
|
||||
expect($html)->equals("<p class=\"mailpoet_paragraph\">line1\nline2</p>");
|
||||
$html = $this->html->render($block, []);
|
||||
expect($html)->equals("<p class=\"mailpoet_paragraph\" >line1\nline2</p>");
|
||||
}
|
||||
|
||||
public function testItShouldNotEscapeHtml() {
|
||||
$block = $this->block;
|
||||
$block['params']['text'] = '<p class="my-p">Hello</p>';
|
||||
$html = $this->html->render($block);
|
||||
expect($html)->equals("<p class=\"mailpoet_paragraph\"><p class=\"my-p\">Hello</p></p>");
|
||||
$html = $this->html->render($block, []);
|
||||
expect($html)->equals("<p class=\"mailpoet_paragraph\" ><p class=\"my-p\">Hello</p></p>");
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ class RadioTest extends \MailPoetUnitTest {
|
||||
$this->baseMock->expects($this->once())->method('getInputValidation')->willReturn(' validation="1" ');
|
||||
$this->baseMock->expects($this->once())->method('getFieldValue')->willReturn('Radio 2');
|
||||
|
||||
$html = $this->radio->render($this->block);
|
||||
$html = $this->radio->render($this->block, []);
|
||||
|
||||
$radio1 = $this->htmlParser->getElementByXpath($html, "//label[@class='mailpoet_radio_label']", 0);
|
||||
$radio2 = $this->htmlParser->getElementByXpath($html, "//label[@class='mailpoet_radio_label']", 1);
|
||||
|
@ -57,7 +57,7 @@ class SegmentTest extends \MailPoetUnitTest {
|
||||
$this->rendererHelperMock->expects($this->once())->method('getInputValidation')->willReturn('validation="1"');
|
||||
$this->rendererHelperMock->expects($this->once())->method('getFieldName')->willReturn('Segments');
|
||||
|
||||
$html = $this->segment->render($this->block);
|
||||
$html = $this->segment->render($this->block, []);
|
||||
|
||||
$checkbox1 = $this->htmlParser->getElementByXpath($html, "//label[@class='mailpoet_checkbox_label']", 0);
|
||||
$checkbox2 = $this->htmlParser->getElementByXpath($html, "//label[@class='mailpoet_checkbox_label']", 1);
|
||||
|
@ -56,7 +56,7 @@ class SelectTest extends \MailPoetUnitTest {
|
||||
],
|
||||
'is_checked' => false,
|
||||
'is_disabled' => false,
|
||||
'is_hidden' => false,
|
||||
|
||||
],
|
||||
],
|
||||
],
|
||||
@ -64,7 +64,7 @@ class SelectTest extends \MailPoetUnitTest {
|
||||
}
|
||||
|
||||
public function testItRendersSelectBlock() {
|
||||
$rendered = $this->selectBlock->render($this->block);
|
||||
$rendered = $this->selectBlock->render($this->block, []);
|
||||
expect($rendered)->contains(Subscriber::STATUS_SUBSCRIBED);
|
||||
expect($rendered)->contains(Subscriber::STATUS_UNSUBSCRIBED);
|
||||
expect($rendered)->contains(Subscriber::STATUS_BOUNCED);
|
||||
@ -72,19 +72,19 @@ class SelectTest extends \MailPoetUnitTest {
|
||||
|
||||
public function testItRendersSelectedOption() {
|
||||
$this->block['params']['values'][0]['is_checked'] = true;
|
||||
$rendered = $this->selectBlock->render($this->block);
|
||||
$rendered = $this->selectBlock->render($this->block, []);
|
||||
expect($rendered)->contains('selected="selected"');
|
||||
}
|
||||
|
||||
public function testItRendersDisabledOptions() {
|
||||
$this->block['params']['values'][2]['is_disabled'] = true;
|
||||
$rendered = $this->selectBlock->render($this->block);
|
||||
$rendered = $this->selectBlock->render($this->block, []);
|
||||
expect($rendered)->contains('disabled="disabled"');
|
||||
}
|
||||
|
||||
public function testItDoesNotRenderHiddenOptions() {
|
||||
$this->block['params']['values'][2]['is_hidden'] = true;
|
||||
$rendered = $this->selectBlock->render($this->block);
|
||||
$rendered = $this->selectBlock->render($this->block, []);
|
||||
expect($rendered)->notContains(Subscriber::STATUS_BOUNCED);
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ class TextTest extends \MailPoetUnitTest {
|
||||
$this->rendererHelperMock->expects($this->once())->method('renderInputPlaceholder')->willReturn('');
|
||||
$this->rendererHelperMock->expects($this->once())->method('getInputModifiers')->willReturn(' modifiers="mod" ');
|
||||
|
||||
$html = $this->text->render($this->block);
|
||||
$html = $this->text->render($this->block, []);
|
||||
$input = $this->htmlParser->getElementByXpath($html, '//input');
|
||||
$name = $this->htmlParser->getAttribute($input, 'name');
|
||||
$type = $this->htmlParser->getAttribute($input, 'type');
|
||||
|
@ -49,7 +49,7 @@ class TextareaTest extends \MailPoetUnitTest {
|
||||
$this->rendererHelperMock->expects($this->once())->method('getInputModifiers')->willReturn(' modifiers="mod" ');
|
||||
$this->rendererHelperMock->expects($this->once())->method('getFieldValue')->willReturn('val');
|
||||
|
||||
$html = $this->textarea->render($this->block);
|
||||
$html = $this->textarea->render($this->block, []);
|
||||
$textarea = $this->htmlParser->getElementByXpath($html, '//textarea');
|
||||
$name = $this->htmlParser->getAttribute($textarea, 'name');
|
||||
$validation = $this->htmlParser->getAttribute($textarea, 'validation');
|
||||
|
@ -38,6 +38,7 @@ class DisplayFormInWPContentTest extends \MailPoetUnitTest {
|
||||
$this->renderer = $this->createMock(Renderer::class);
|
||||
$this->renderer->expects($this->any())->method('renderStyles')->willReturn('<style></style>');
|
||||
$this->renderer->expects($this->any())->method('renderHTML')->willReturn('<form></form>');
|
||||
$this->renderer->expects($this->any())->method('renderFormElementStyles')->willReturn('');
|
||||
$this->hook = new DisplayFormInWPContent($this->wp, $this->repository, $this->renderer, $this->assetsController, $this->templateRenderer);
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ class RendererTest extends \MailPoetUnitTest {
|
||||
->method('get')
|
||||
->with('captcha.type')
|
||||
->willReturn(Captcha::TYPE_DISABLED);
|
||||
$html = $this->renderer->renderBlocks(Fixtures::get('simple_form_body'), false);
|
||||
$html = $this->renderer->renderBlocks(Fixtures::get('simple_form_body'), [], false);
|
||||
$hpLabel = $this->htmlParser->findByXpath($html, "//label[@class='mailpoet_hp_email_label']");
|
||||
expect($hpLabel->length)->equals(0);
|
||||
$recaptcha = $this->htmlParser->findByXpath($html, "//div[@class='mailpoet_recaptcha']");
|
||||
|
67
tsconfig.json
Normal file
67
tsconfig.json
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"include": [
|
||||
"assets/js/src/**/*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
"strict": false, /* Enable all strict type-checking options. */
|
||||
"jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
"baseUrl": "./assets/js/src", /* Base directory to resolve non-absolute module names. */
|
||||
"rootDir": "./assets/js/src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
"allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
|
||||
/* Strict Type-Checking Options */
|
||||
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
"strictNullChecks": false, /* Enable strict null checks. */
|
||||
"strictFunctionTypes": false, /* Enable strict checking of function types. */
|
||||
"strictBindCallApply": false, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
"strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */
|
||||
"noImplicitThis": false, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
"alwaysStrict": false, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
"allowJs": true, /* Allow javascript files to be compiled. */
|
||||
"checkJs": false, /* Report errors in .js files. */
|
||||
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
/* Advanced Options */
|
||||
}
|
||||
}
|
@ -34,6 +34,11 @@
|
||||
'changesNotSaved': __('Your changes you made may not be saved'),
|
||||
'form': __('Form'),
|
||||
'formSettings': _x('Settings', 'A settings section heading'),
|
||||
'formSettingsStyles': __('Styles'),
|
||||
'formSettingsStylesBackgroundColor': __('Background Color'),
|
||||
'formSettingsStylesFontSize': __('Font Size'),
|
||||
'formSettingsStylesFontColor': __('Font Color'),
|
||||
'formSettingsStylesFontColorInherit': __('Inherit from theme'),
|
||||
'customFieldSettings': _x('Custom field settings', 'A settings section heading'),
|
||||
'customFieldsFormSettings': _x('Form settings', 'A settings section heading'),
|
||||
'formPlacement': _x('Form Placement', 'A settings section heading'),
|
||||
|
@ -15,6 +15,7 @@
|
||||
action="<%= admin_url('admin-post.php?action=mailpoet_subscription_form') | raw %>"
|
||||
class="mailpoet_form mailpoet_form_<%= form_type %>"
|
||||
novalidate
|
||||
style="<%= form_element_styles %>"/* paragraphs (label + input)
|
||||
>
|
||||
<input type="hidden" name="data[form_id]" value="<%= form_id %>" />
|
||||
<input type="hidden" name="token" value="<%= token %>" />
|
||||
|
@ -40,6 +40,7 @@ const baseConfig = {
|
||||
'node_modules',
|
||||
'assets/js/src',
|
||||
],
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
alias: {
|
||||
'handlebars': 'handlebars/dist/handlebars.js',
|
||||
'backbone.marionette': 'backbone.marionette/lib/backbone.marionette',
|
||||
@ -65,7 +66,7 @@ const baseConfig = {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
test: /\.(j|t)sx?$/,
|
||||
exclude: /(node_modules|src\/vendor)/,
|
||||
loader: 'babel-loader',
|
||||
},
|
||||
|
Reference in New Issue
Block a user