Included MJML4

This commit is contained in:
Tomas Bures 2018-11-10 02:05:26 +01:00
parent e2093e22fe
commit 9f467762c0
18 changed files with 15949 additions and 3889 deletions

1
client/mjml/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/dist

1
client/mjml/mjml-git Submodule

@ -0,0 +1 @@
Subproject commit 3ff2c60ae31a561a2fb7695bcf4eb012f6d43ede

9
client/mjml/mocks/fs.js Normal file
View file

@ -0,0 +1,9 @@
export default {
readFileSync: (filename) => {
if (filename === '/.mjmlconfig') {
return '{ "packages": [] }';
} else {
console.log('readFileSync - unknown file name "' + filename + '"');
}
}
};

View file

@ -0,0 +1 @@
export default {};

8300
client/mjml/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

32
client/mjml/package.json Normal file
View file

@ -0,0 +1,32 @@
{
"name": "mjml",
"description": "mjml",
"version": "4.2.0",
"license": "MIT",
"dependencies": {
"html-minifier": "^3.5.3",
"js-beautify": "^1.6.14",
"juice": "^4.1.0",
"lodash": "^4.17.2",
"htmlparser2": "^3.9.2"
},
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-loader": "^7.1.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-function-bind": "^6.22.0",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-1": "^6.24.1",
"css-loader": "^0.28.4",
"file-loader": "^2.0.0",
"i18next-conv": "^3.0.3",
"node-sass": "^4.5.3",
"postcss-loader": "^3.0.0",
"raw-loader": "^0.5.1",
"sass-loader": "^6.0.6",
"style-loader": "^0.18.2",
"url-loader": "^0.5.9",
"webpack": "^2.6.1"
}
}

View file

@ -0,0 +1,135 @@
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: {
"mjml": ['./mjml-git/packages/mjml/src/index'],
},
output: {
library: 'mjml',
filename: '[name].js',
path: path.resolve(__dirname, './dist'),
libraryTarget: 'umd',
umdNamedDefine: true
},
resolve: {
alias: {
'mjml-core/lib': path.resolve(__dirname, './mjml-git/packages/mjml-core/src'),
'mjml-accordion': path.resolve(__dirname, './mjml-git/packages/mjml-accordion/src'),
'mjml-body': path.resolve(__dirname, './mjml-git/packages/mjml-body/src'),
'mjml-button': path.resolve(__dirname, './mjml-git/packages/mjml-button/src'),
'mjml-carousel': path.resolve(__dirname, './mjml-git/packages/mjml-carousel/src'),
'mjml-cli': path.resolve(__dirname, './mjml-git/packages/mjml-cli/src'),
'mjml-column': path.resolve(__dirname, './mjml-git/packages/mjml-column/src'),
'mjml-core': path.resolve(__dirname, './mjml-git/packages/mjml-core/src'),
'mjml-divider': path.resolve(__dirname, './mjml-git/packages/mjml-divider/src'),
'mjml-group': path.resolve(__dirname, './mjml-git/packages/mjml-group/src'),
'mjml-head': path.resolve(__dirname, './mjml-git/packages/mjml-head/src'),
'mjml-head-attributes': path.resolve(__dirname, './mjml-git/packages/mjml-head-attributes/src'),
'mjml-head-breakpoint': path.resolve(__dirname, './mjml-git/packages/mjml-head-breakpoint/src'),
'mjml-head-font': path.resolve(__dirname, './mjml-git/packages/mjml-head-font/src'),
'mjml-head-preview': path.resolve(__dirname, './mjml-git/packages/mjml-head-preview/src'),
'mjml-head-style': path.resolve(__dirname, './mjml-git/packages/mjml-head-style/src'),
'mjml-head-title': path.resolve(__dirname, './mjml-git/packages/mjml-head-title/src'),
'mjml-hero': path.resolve(__dirname, './mjml-git/packages/mjml-hero/src'),
'mjml-image': path.resolve(__dirname, './mjml-git/packages/mjml-image/src'),
'mjml-migrate': path.resolve(__dirname, './mjml-git/packages/mjml-migrate/src/migrate.js'),
'mjml-navbar': path.resolve(__dirname, './mjml-git/packages/mjml-navbar/src'),
'mjml-raw': path.resolve(__dirname, './mjml-git/packages/mjml-raw/src'),
'mjml-section': path.resolve(__dirname, './mjml-git/packages/mjml-section/src'),
'mjml-social': path.resolve(__dirname, './mjml-git/packages/mjml-social/src'),
'mjml-spacer': path.resolve(__dirname, './mjml-git/packages/mjml-spacer/src'),
'mjml-table': path.resolve(__dirname, './mjml-git/packages/mjml-table/src'),
'mjml-text': path.resolve(__dirname, './mjml-git/packages/mjml-text/src'),
'mjml-validator': path.resolve(__dirname, './mjml-git/packages/mjml-validator/src'),
'mjml-wrapper': path.resolve(__dirname, './mjml-git/packages/mjml-wrapper/src'),
'mjml-parser-xml': path.resolve(__dirname, './mjml-git/packages/mjml-parser-xml/src'),
'fs': path.resolve(__dirname, 'mocks/fs'),
'uglify-js': path.resolve(__dirname, 'mocks/uglify-js'),
}
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: path.join(__dirname, 'node_modules'),
use: [
{
loader: 'babel-loader',
options: {
presets: [
['env', {
targets: {
"chrome": "58",
"edge": "15",
"firefox": "55",
"ios": "10"
}
}],
'stage-1'
],
plugins: ['add-module-exports', 'transform-react-jsx', 'transform-decorators-legacy', 'transform-function-bind'],
babelrc: false
}
}
]
},
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
}
]
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192 // inline base64 URLs for <=8k images, direct URLs for the rest
}
}
]
},
{
test: /\.scss$/,
exclude: path.join(__dirname, 'node_modules'),
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]'
}
},
'sass-loader'
]
},
{
test: /\.(svg|otf|woff2|woff|ttf|eot)$/,
use: [
'url-loader'
]
}
]
},
externals: {
jquery: 'jQuery',
csfrToken: 'csfrToken',
mailtrainConfig: 'mailtrainConfig'
},
plugins: [
// new webpack.optimize.UglifyJsPlugin(),
],
watchOptions: {
ignored: 'node_modules/',
poll: 2000
}
};

2395
client/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -65,6 +65,7 @@
"@ckeditor/ckeditor5-dev-webpack-plugin": "^7.0.1",
"babel-cli": "^6.24.1",
"babel-loader": "^7.1.1",
"babel-plugin-add-module-exports": "^1.0.0",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-function-bind": "^6.22.0",
"babel-preset-env": "^1.7.0",

View file

@ -67,7 +67,6 @@ class Breadcrumb extends Component {
class SecondaryNavBar extends Component {
static propTypes = {
route: PropTypes.object.isRequired,
params: PropTypes.object.isRequired,
resolved: PropTypes.object.isRequired,
className: PropTypes.string

View file

@ -20,12 +20,15 @@ import PropTypes
import {
getPublicUrl,
getSandboxUrl,
getTrustedUrl
getTrustedUrl,
getUrl
} from "./urls";
import {
base,
unbase
} from "../../../shared/templates";
import mjml2html from "../../mjml/dist/mjml";
console.log(mjml2html);
import 'grapesjs/dist/css/grapes.min.css';
import grapesjs from 'grapesjs';
@ -51,56 +54,72 @@ export class GrapesJSSandbox extends Component {
static propTypes = {
entityTypeId: PropTypes.string,
entityId: PropTypes.number,
initialModel: PropTypes.object
initialSource: PropTypes.string,
initialStyle: PropTypes.string
}
async exportState(method, params) {
const editor = this.editor;
// If exportState comes during text editing (via RichTextEditor), we need to cancel the editing, so that the
// text being edited is stored in the model
const sel = editor.getSelected();
if (sel) {
sel.view.disableEditing();
}
editor.select(null);
const trustedUrlBase = getTrustedUrl();
const sandboxUrlBase = getSandboxUrl();
const publicUrlBase = getPublicUrl();
const source = unbase(editor.getHtml(), trustedUrlBase, sandboxUrlBase, publicUrlBase, true);
const style = unbase(editor.getCss(), trustedUrlBase, sandboxUrlBase, publicUrlBase, true);
let html;
html = unbase(editor.getHtml(), trustedUrlBase, sandboxUrlBase, publicUrlBase, true);
const model = {
css: editor.getCss(),
source: editor.getHtml(),
};
const preMjml = '<mjml><mj-head></mj-head><mj-body>';
const postMjml = '</mj-body></mjml>';
const mjml = preMjml + source + postMjml;
console.log(mjml);
console.log(model.css);
console.log(model.source);
const mjmlRes = mjml2html(mjml);
console.log(mjmlRes);
console.log(mjmlRes.html);
console.log(mjmlRes.errors);
console.log(mjmlRes.errors[0]);
return {
html,
model
style: style,
source: source
};
}
componentDidMount() {
const props = this.props;
parentRPC.setMethodHandler('exportState', ::this.exportState);
const trustedUrlBase = getTrustedUrl();
const sandboxUrlBase = getSandboxUrl();
const publicUrlBase = getPublicUrl();
const model = this.props.initialModel || {}
const source = props.initialSource ?
base(props.initialSource, trustedUrlBase, sandboxUrlBase, publicUrlBase) :
' <mj-container>\n' +
' <mj-section>\n' +
' <mj-column>\n' +
' <mj-text>My Company</mj-text>\n' +
' </mj-column>\n' +
' </mj-section>\n' +
' </mj-container>';
const source = model.source && base(model.source, trustedUrlBase, sandboxUrlBase, publicUrlBase);
const css = model.css && base(model.css, trustedUrlBase, sandboxUrlBase, publicUrlBase);
/*
' <mj-container>\n' +
' <mj-section>\n' +
' <mj-column>\n' +
' <mj-text>My Company</mj-text>\n' +
' </mj-column>\n' +
' </mj-section>\n' +
' <mj-container>',
*/
const css = props.initialStyle && base(props.initialStyle, trustedUrlBase, sandboxUrlBase, publicUrlBase);
this.editor = grapesjs.init({
noticeOnUnload: false,
container: this.canvasNode,
height: '100%',
width: '100%',
@ -126,10 +145,12 @@ export class GrapesJSSandbox extends Component {
'gjs-mjml'
],
pluginsOpts: {
'gjs-mjml': {}
'gjs-mjml': {
preMjml: '<mjml><mj-head></mj-head><mj-body>',
postMjml: '</mj-body></mjml>'
}
}
});
}
render() {

View file

@ -24,7 +24,8 @@ export class GrapesJSHost extends Component {
static propTypes = {
entityTypeId: PropTypes.string,
entity: PropTypes.object,
initialModel: PropTypes.object,
initialSource: PropTypes.string,
initialStyle: PropTypes.string,
title: PropTypes.string,
onFullscreenAsync: PropTypes.func
}
@ -47,7 +48,8 @@ export class GrapesJSHost extends Component {
const editorData = {
entityTypeId: this.props.entityTypeId,
entityId: this.props.entity.id,
initialModel: this.props.initialModel
initialSource: this.props.initialSource,
initialStyle: this.props.initialStyle
};
const tokenData = {

View file

@ -183,28 +183,40 @@ export function getTemplateTypes(t, prefix = '', entityTypeId = ResourceType.TEM
<GrapesJSHost
ref={node => owner.editorNode = node}
entity={owner.props.entity}
initialModel={owner.getFormValue(prefix + 'grapesJSData')}
entityTypeId={entityTypeId}
initialSource={owner.getFormValue(prefix + 'grapesJSData').source}
initialStyle={owner.getFormValue(prefix + 'grapesJSData').style}
title={t('GrapesJS Template Designer')}
onFullscreenAsync={::owner.setElementInFullscreen}
/>
</AlignedRow>,
exportHTMLEditorData: async owner => {
const {html, model} = await owner.editorNode.exportState();
const {html, source, style} = await owner.editorNode.exportState();
owner.updateFormValue(prefix + 'html', html);
owner.updateFormValue(prefix + 'grapesJSData', model);
owner.updateFormValue(prefix + 'grapesJSData', {
source,
style
});
},
initData: () => ({
[prefix + 'grapesJSData']: {}
}),
afterLoad: data => {
data[prefix + 'grapesJSData'] = data[prefix + 'data'];
data[prefix + 'grapesJSData'] = {
source: data[prefix + 'data'].source,
style: data[prefix + 'data'].style
};
},
beforeSave: data => {
data[prefix + 'data'] = data[prefix + 'grapesJSData'];
data[prefix + 'data'] = {
source: data[prefix + 'grapesJSData'].source,
style: data[prefix + 'grapesJSData'].style
};
clearBeforeSave(data);
},
afterTypeChange: mutState => {},
afterTypeChange: mutState => {
initFieldsIfMissing(mutState, 'grapesjs');
},
validate: state => {}
};