Merge pull request #142 from witzig/master
Support for custom HTML editors
This commit is contained in:
commit
811d7b51b9
22 changed files with 256 additions and 133 deletions
2
app.js
2
app.js
|
@ -47,6 +47,8 @@ if (config.www.proxy) {
|
|||
// Do not expose software used
|
||||
app.disable('x-powered-by');
|
||||
|
||||
hbs.registerPartials(__dirname + '/views/partials');
|
||||
|
||||
/**
|
||||
* We need this helper to make sure that we consume flash messages only
|
||||
* when we are able to actually display these. Otherwise we might end up
|
||||
|
|
|
@ -21,6 +21,12 @@
|
|||
# Process title visible in monitoring logs and process listing
|
||||
title="mailtrain"
|
||||
|
||||
# Enabled HTML editors
|
||||
editors=[
|
||||
["summernote", "Summernote"],
|
||||
["codeeditor", "Code Editor"]
|
||||
]
|
||||
|
||||
# If you start out as a root user (eg. if you want to use ports lower than 1000)
|
||||
# then you can downgrade the user once all services are up and running
|
||||
#user="nobody"
|
||||
|
|
|
@ -13,7 +13,7 @@ let log = require('npmlog');
|
|||
let mailer = require('../mailer');
|
||||
let humanize = require('humanize');
|
||||
|
||||
let allowedKeys = ['description', 'from', 'address', 'reply_to', 'subject', 'template', 'source_url', 'list', 'segment', 'html', 'text', 'tracking_disabled'];
|
||||
let allowedKeys = ['description', 'from', 'address', 'reply_to', 'subject', 'editor_name', 'editor_data', 'template', 'source_url', 'list', 'segment', 'html', 'text', 'tracking_disabled'];
|
||||
|
||||
module.exports.list = (start, limit, callback) => {
|
||||
db.getConnection((err, connection) => {
|
||||
|
@ -729,6 +729,8 @@ module.exports.create = (campaign, opts, callback) => {
|
|||
return callback(new Error('Selected template not found'));
|
||||
}
|
||||
|
||||
campaign.editorName = template.editorName;
|
||||
campaign.editorData = template.editorData;
|
||||
campaign.html = template.html;
|
||||
campaign.text = template.text;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
let db = require('../db');
|
||||
let tools = require('../tools');
|
||||
|
||||
let allowedKeys = ['description', 'html', 'text'];
|
||||
let allowedKeys = ['description', 'editor_name', 'editor_data', 'html', 'text'];
|
||||
|
||||
module.exports.list = (start, limit, callback) => {
|
||||
db.getConnection((err, connection) => {
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"schemaVersion": 20
|
||||
"schemaVersion": 21
|
||||
}
|
||||
|
|
|
@ -62,8 +62,13 @@ router.get('/:campaign/:list/:subscription', passport.csrfProtection, (req, res,
|
|||
}
|
||||
|
||||
let renderHtml = (html, renderTags) => {
|
||||
res.render('archive/view', {
|
||||
layout: 'archive/layout',
|
||||
campaign.editorName = campaign.editorName || 'summernote';
|
||||
let sfx = '';
|
||||
if (campaign.editorName !== 'summernote' && campaign.editorName !== 'codeeditor') {
|
||||
sfx = '-raw';
|
||||
}
|
||||
res.render('archive/view' + sfx, {
|
||||
layout: 'archive/layout' + sfx,
|
||||
message: renderTags ? tools.formatMessage(serviceUrl, campaign, list, subscription, html) : html,
|
||||
campaign,
|
||||
list,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
let config = require('config');
|
||||
let express = require('express');
|
||||
let router = new express.Router();
|
||||
let lists = require('../lib/models/lists');
|
||||
|
@ -115,7 +116,10 @@ router.post('/create', passport.parseForm, passport.csrfProtection, (req, res) =
|
|||
return res.redirect('/campaigns/create?' + tools.queryParams(req.body));
|
||||
}
|
||||
req.flash('success', 'Campaign “' + req.body.name + '” created');
|
||||
res.redirect('/campaigns/view/' + id);
|
||||
res.redirect((req.body.type === 'rss')
|
||||
? '/campaigns/edit/' + id
|
||||
: '/campaigns/edit/' + id + '?tab=template'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -159,6 +163,8 @@ router.get('/edit/:id', passport.csrfProtection, (req, res, next) => {
|
|||
campaign.csrfToken = req.csrfToken();
|
||||
campaign.listItems = listItems;
|
||||
campaign.useEditor = true;
|
||||
campaign.editorName = campaign.editorName || 'summernote';
|
||||
campaign.editorConfig = config[campaign.editorName];
|
||||
|
||||
campaign.disableWysiwyg = configItems.disableWysiwyg;
|
||||
campaign.showGeneral = req.query.tab === 'general' || !req.query.tab;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
let config = require('config');
|
||||
let express = require('express');
|
||||
let router = new express.Router();
|
||||
let templates = require('../lib/models/templates');
|
||||
|
@ -66,6 +67,23 @@ router.get('/create', passport.csrfProtection, (req, res, next) => {
|
|||
data.text = data.text || rendererText(configItems);
|
||||
data.disableWysiwyg = configItems.disableWysiwyg;
|
||||
|
||||
data.editors = config.editors || [['summernote', 'Summernote']];
|
||||
data.editors = data.editors.map(ed => {
|
||||
let editor = {
|
||||
name: ed[0],
|
||||
label: ed[1],
|
||||
};
|
||||
if (config[editor.name] && config[editor.name].templates) {
|
||||
editor.templates = config[editor.name].templates.map(tmpl => {
|
||||
return {
|
||||
name: tmpl[0],
|
||||
label: tmpl[1],
|
||||
}
|
||||
});
|
||||
}
|
||||
return editor;
|
||||
});
|
||||
|
||||
res.render('templates/create', data);
|
||||
});
|
||||
});
|
||||
|
@ -79,7 +97,7 @@ router.post('/create', passport.parseForm, passport.csrfProtection, (req, res) =
|
|||
return res.redirect('/templates/create?' + tools.queryParams(req.body));
|
||||
}
|
||||
req.flash('success', 'Template created');
|
||||
res.redirect('/templates');
|
||||
res.redirect('/templates/edit/' + id);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -95,6 +113,8 @@ router.get('/edit/:id', passport.csrfProtection, (req, res, next) => {
|
|||
}
|
||||
template.csrfToken = req.csrfToken();
|
||||
template.useEditor = true;
|
||||
template.editorName = template.editorName || 'summernote';
|
||||
template.editorConfig = config[template.editorName];
|
||||
template.disableWysiwyg = configItems.disableWysiwyg;
|
||||
res.render('templates/edit', template);
|
||||
});
|
||||
|
|
16
setup/sql/upgrade-00021.sql
Normal file
16
setup/sql/upgrade-00021.sql
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Header section
|
||||
# Define incrementing schema version number
|
||||
SET @schema_version = '21';
|
||||
|
||||
# Add fields editor_name, editor_data to templates
|
||||
ALTER TABLE `templates` ADD COLUMN `editor_name` varchar(50) DEFAULT '' AFTER `description`;
|
||||
ALTER TABLE `templates` ADD COLUMN `editor_data` longtext DEFAULT '' AFTER `editor_name`;
|
||||
|
||||
# Add fields editor_name, editor_data to campaigns
|
||||
ALTER TABLE `campaigns` ADD COLUMN `editor_name` varchar(50) DEFAULT '' AFTER `source_url`;
|
||||
ALTER TABLE `campaigns` ADD COLUMN `editor_data` longtext DEFAULT '' AFTER `editor_name`;
|
||||
|
||||
# Footer section
|
||||
LOCK TABLES `settings` WRITE;
|
||||
INSERT INTO `settings` (`key`, `value`) VALUES('db_schema_version', @schema_version) ON DUPLICATE KEY UPDATE `value`=@schema_version;
|
||||
UNLOCK TABLES;
|
1
views/archive/layout-raw.hbs
Normal file
1
views/archive/layout-raw.hbs
Normal file
|
@ -0,0 +1 @@
|
|||
{{{body}}}
|
1
views/archive/view-raw.hbs
Normal file
1
views/archive/view-raw.hbs
Normal file
|
@ -0,0 +1 @@
|
|||
{{{message}}}
|
|
@ -58,7 +58,7 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="template" class="col-sm-2 control-label">RSS Feed Url</label>
|
||||
<label for="source-url" class="col-sm-2 control-label">RSS Feed Url</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="url" class="form-control" name="source-url" id="source-url" value="{{sourceUrl}}" placeholder="http://example.com/rss.php" required>
|
||||
<span class="help-block">New entries from this RSS URL are sent out to list subscribers as email messages</span>
|
||||
|
|
|
@ -125,17 +125,15 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="template-html" class="col-sm-2 control-label">Template content (HTML)</label>
|
||||
<div class="col-sm-10">
|
||||
{{#if disableWysiwyg}}
|
||||
<div class="code-editor" id="template-html">{{html}}</div>
|
||||
<input type="hidden" name="html">
|
||||
{{else}}
|
||||
<textarea class="form-control summernote" id="template-html" name="html" rows="8">{{html}}</textarea>
|
||||
{{/if}}
|
||||
<span class="help-block">Use special merge tag <code>[RSS_ENTRY]</code> to mark the position for the RSS post content. Additionally you can use any valid merge tag as well.</span>
|
||||
{{#if disableWysiwyg}}
|
||||
{{> codeeditor}}
|
||||
{{else}}
|
||||
{{> summernote}}
|
||||
{{/if}}
|
||||
|
||||
<div class="form-group" style="margin-top: -15px;">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<span class="help-block">Use special merge tag <code>[RSS_ENTRY]</code> to mark the position for the RSS post content. Additionally you can use any valid merge tag as well.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -167,24 +167,13 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="template-html" class="col-sm-2 control-label">Template content (HTML)</label>
|
||||
<div class="col-sm-10">
|
||||
{{#if disableWysiwyg}}
|
||||
<div class="code-editor" id="template-html">{{html}}</div>
|
||||
<input type="hidden" name="html">
|
||||
{{else}}
|
||||
<textarea class="form-control summernote" id="template-html" name="html" rows="8">{{html}}</textarea>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{> plaintext}}
|
||||
|
||||
<div class="form-group">
|
||||
<label for="template-text" class="col-sm-2 control-label">Template content (plaintext)</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control" id="template-text" name="text" rows="10">{{text}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
{{#if disableWysiwyg}}
|
||||
{{> codeeditor}}
|
||||
{{else}}
|
||||
{{> (lookup . 'editorName') }}
|
||||
{{/if}}
|
||||
|
||||
{{/if}}
|
||||
</fieldset>
|
||||
|
|
|
@ -183,24 +183,13 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="template-html" class="col-sm-2 control-label">Template content (HTML)</label>
|
||||
<div class="col-sm-10">
|
||||
{{#if disableWysiwyg}}
|
||||
<div class="code-editor" id="template-html">{{html}}</div>
|
||||
<input type="hidden" name="html">
|
||||
{{else}}
|
||||
<textarea class="form-control summernote" id="template-html" name="html" rows="8">{{html}}</textarea>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{> plaintext}}
|
||||
|
||||
<div class="form-group">
|
||||
<label for="template-text" class="col-sm-2 control-label">Template content (plaintext)</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control" id="template-text" name="text" rows="10">{{text}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
{{#if disableWysiwyg}}
|
||||
{{> codeeditor}}
|
||||
{{else}}
|
||||
{{> (lookup . 'editorName') }}
|
||||
{{/if}}
|
||||
|
||||
{{/if}}
|
||||
</fieldset>
|
||||
|
|
7
views/partials/codeeditor.hbs
Normal file
7
views/partials/codeeditor.hbs
Normal file
|
@ -0,0 +1,7 @@
|
|||
<div class="form-group">
|
||||
<label for="template-html" class="col-sm-2 control-label">Template content (HTML)</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="code-editor" id="template-html">{{html}}</div>
|
||||
<input type="hidden" name="html">
|
||||
</div>
|
||||
</div>
|
80
views/partials/editor-bridge.hbs
Normal file
80
views/partials/editor-bridge.hbs
Normal file
|
@ -0,0 +1,80 @@
|
|||
<style>
|
||||
body.noscroll {
|
||||
overflow: hidden;
|
||||
}
|
||||
#editor-frame,
|
||||
#editor-frame-spinner {
|
||||
border: none;
|
||||
position: fixed;
|
||||
z-index: 10000;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
#editor-frame-spinner {
|
||||
z-index: 10001;
|
||||
background: white;
|
||||
}
|
||||
#editor-frame-spinner div {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
margin-top: -60px;
|
||||
margin-left: -60px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
#editor-frame-spinner span:before {
|
||||
font-size: 120px;
|
||||
color: #efefef;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="editor-frame-spinner" style="display: none;">
|
||||
<div><span class="glyphicon glyphicon-refresh spinning"></span></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// campaign or template
|
||||
var type = window.location.pathname.split('/')[1].slice(0, -1);
|
||||
|
||||
var editorWindow;
|
||||
|
||||
var $editorFrame = $('<iframe id="editor-frame"/>')
|
||||
.attr('src', '/{{editorName}}/editor?id={{id}}&type=' + type)
|
||||
.on('load', function() {
|
||||
editorWindow = $editorFrame[0].contentWindow;
|
||||
editorWindow.bridge = editorWindow.bridge || {};
|
||||
editorWindow.bridge.exit = function() {
|
||||
closeEditor();
|
||||
}
|
||||
setTimeout(function() {
|
||||
$('#editor-frame-spinner').hide();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
var openEditor = function() {
|
||||
$('body').addClass('noscroll');
|
||||
$('#editor-frame-spinner').show();
|
||||
$editorFrame.appendTo($('body'));
|
||||
}
|
||||
|
||||
var closeEditor = function() {
|
||||
$('body').removeClass('noscroll');
|
||||
$editorFrame = $editorFrame.detach();
|
||||
if (editorWindow.bridge.lastSavedHtml) {
|
||||
$('#template-html').val(editorWindow.bridge.lastSavedHtml);
|
||||
$('#html-preview-frame').attr('srcdoc', editorWindow.bridge.lastSavedHtml);
|
||||
$('#html-preview').show(); // it's hidden when there's no html
|
||||
}
|
||||
// Reload to discard unsaved changes
|
||||
$editorFrame.attr('src', '/{{editorName}}/editor?id={{id}}&type=' + type + '&cb=' + Math.random());
|
||||
}
|
||||
|
||||
$('#btn-open-{{editorName}}').on('click', function() {
|
||||
openEditor();
|
||||
});
|
||||
});
|
||||
</script>
|
14
views/partials/html-preview.hbs
Normal file
14
views/partials/html-preview.hbs
Normal file
|
@ -0,0 +1,14 @@
|
|||
<div class="form-group" id="html-preview" {{#unless html}}style="display: none;"{{/unless}}>
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<a role="button" data-toggle="collapse" href="#html-preview-toggle" aria-expanded="false" aria-controls="html-preview-toggle">Toggle HTML preview</a>
|
||||
<div class="collapse" id="html-preview-toggle">
|
||||
<h6 class="small text-muted">320x480px</h6>
|
||||
<iframe
|
||||
id="html-preview-frame"
|
||||
srcdoc="{{#if preparedHtml}}{{preparedHtml}}{{else}}{{html}}{{/if}}"
|
||||
width="320" height="480"
|
||||
style="border: 1px solid #ccc;">
|
||||
</iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
6
views/partials/plaintext.hbs
Normal file
6
views/partials/plaintext.hbs
Normal file
|
@ -0,0 +1,6 @@
|
|||
<div class="form-group">
|
||||
<label for="template-text" class="col-sm-2 control-label">Template content (plaintext)</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control" id="template-text" name="text" rows="10">{{text}}</textarea>
|
||||
</div>
|
||||
</div>
|
6
views/partials/summernote.hbs
Normal file
6
views/partials/summernote.hbs
Normal file
|
@ -0,0 +1,6 @@
|
|||
<div class="form-group">
|
||||
<label for="template-html" class="col-sm-2 control-label">Template content (HTML)</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control summernote" id="template-html" name="html" rows="8">{{html}}</textarea>
|
||||
</div>
|
||||
</div>
|
|
@ -19,72 +19,21 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<a class="btn btn-default" role="button" data-toggle="collapse" href="#mergeReference" aria-expanded="false" aria-controls="mergeReference">Merge tag reference</a>
|
||||
<div class="collapse" id="mergeReference">
|
||||
|
||||
<p>
|
||||
Merge tags are tags that are replaced before sending out the message. The format of the merge tag is the following: <code>[TAG_NAME]</code> or <code>[TAG_NAME/fallback]</code> where <code>fallback</code> is an optional text value used
|
||||
when <code>TAG_NAME</code> is empty.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<code>[EMAIL]</code> – email address of the subscriber
|
||||
</li>
|
||||
<li>
|
||||
<code>[FIRST_NAME]</code> – first name of the subscriber
|
||||
</li>
|
||||
<li>
|
||||
<code>[LAST_NAME]</code> – last name of the subscriber
|
||||
</li>
|
||||
<li>
|
||||
<code>[FULL_NAME]</code> – first and last names of the subscriber joined
|
||||
</li>
|
||||
<li>
|
||||
<code>[LINK_UNSUBSCRIBE]</code> – URL that points to the preferences page of the subscriber
|
||||
</li>
|
||||
<li>
|
||||
<code>[LINK_PREFERENCES]</code> – URL that points to the unsubscribe page
|
||||
</li>
|
||||
<li>
|
||||
<code>[LINK_BROWSER]</code> – URL to preview the message in a browser
|
||||
</li>
|
||||
<li>
|
||||
<code>[SUBSCRIPTION_ID]</code> – Unique ID that identifies the recipient
|
||||
</li>
|
||||
<li>
|
||||
<code>[LIST_ID]</code> – Unique ID that identifies the list used for this campaign
|
||||
</li>
|
||||
<li>
|
||||
<code>[CAMPAIGN_ID]</code> – Unique ID that identifies current campaign
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
In addition to that any custom field can have its own merge tag.
|
||||
</p>
|
||||
</div>
|
||||
<label for="editor_name" class="col-sm-2 control-label">HTML Editor</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control" id="editor_name" name="editor_name">
|
||||
<option value=""> –– Select –– </option>
|
||||
{{#each editors}}
|
||||
<option value="{{name}}">{{label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="template-html" class="col-sm-2 control-label">Template content (HTML)</label>
|
||||
<div class="col-sm-10">
|
||||
|
||||
{{#if disableWysiwyg}}
|
||||
<div class="code-editor" id="template-html">{{html}}</div>
|
||||
<input type="hidden" name="html">
|
||||
{{else}}
|
||||
<textarea class="form-control summernote" id="template-html" name="html" rows="8">{{html}}</textarea>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="template-text" class="col-sm-2 control-label">Template content (plaintext)</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control" id="template-text" name="text" rows="10">{{text}}</textarea>
|
||||
<div id="editor-template">
|
||||
<div>
|
||||
<input type="hidden" name="text" value="{{text}}">
|
||||
<input type="hidden" name="html" value="{{html}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -102,5 +51,42 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
<div style="display: none">
|
||||
{{#each editors}}
|
||||
{{#if templates}}
|
||||
<div class="form-group" id="{{name}}-template">
|
||||
<label for="editor_data_{{name}}" class="col-sm-2 control-label">{{label}} Template</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control" id="editor_data_{{name}}" name="editor_data">
|
||||
{{#each templates}}
|
||||
<option value='{"template":"{{name}}"}'>{{label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
|
||||
<div id="summernote-template">
|
||||
<input type="hidden" name="text" value="{{text}}">
|
||||
<input type="hidden" name="html" value="{{html}}">
|
||||
</div>
|
||||
|
||||
<div id="codeeditor-template">
|
||||
<input type="hidden" name="text" value="{{text}}">
|
||||
<input type="hidden" name="html" value="{{html}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$('select#editor_name').on('change', function() {
|
||||
var editor = this.value || 'summernote';
|
||||
$('#editor-template').children().first().replaceWith(
|
||||
$('#' + editor + '-template').clone()
|
||||
);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -72,24 +72,13 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="template-html" class="col-sm-2 control-label">Template content (HTML)</label>
|
||||
<div class="col-sm-10">
|
||||
{{#if disableWysiwyg}}
|
||||
<div class="code-editor" id="template-html">{{html}}</div>
|
||||
<input type="hidden" name="html">
|
||||
{{else}}
|
||||
<textarea class="form-control summernote" id="template-html" name="html" rows="8">{{html}}</textarea>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{> plaintext}}
|
||||
|
||||
<div class="form-group">
|
||||
<label for="template-text" class="col-sm-2 control-label">Template content (plaintext)</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control" id="template-text" name="text" rows="10">{{text}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
{{#if disableWysiwyg}}
|
||||
{{> codeeditor}}
|
||||
{{else}}
|
||||
{{> (lookup . 'editorName') }}
|
||||
{{/if}}
|
||||
|
||||
<div class="form-group">
|
||||
<label for="template-description" class="col-sm-2 control-label">Description</label>
|
||||
|
|
Loading…
Reference in a new issue