diff --git a/config/default.toml b/config/default.toml
index b824ad53..9e8f065f 100644
--- a/config/default.toml
+++ b/config/default.toml
@@ -186,6 +186,23 @@ templates=[
["aves", "MJML Template"]
]
+[grapejs.mjml]
+# Editor main background color
+editorBackgroundColor = "#202835"
+# Editor canvas background (light, dark, bluish, custom css)
+canvasBackgroundStyle = "bluish"
+# Color for the head and attributes labels
+canvasLabelsColor = "#4b5666"
+
+[views.template]
+
+showeditor = false
+
+[views.lists]
+
+statuscolored = false
+
+
[reports]
# The whole reporting functionality can be disabled below if the they are not needed and the DB cannot be
# properly protected.
diff --git a/public/css/flags/flags.css b/public/css/flags/flags.css
new file mode 100644
index 00000000..2f31e07e
--- /dev/null
+++ b/public/css/flags/flags.css
@@ -0,0 +1,4 @@
+/*!
+ * Generated with CSS Flag Sprite generator (https://www.flag-sprites.com/)
+ */
+.flag{display:inline-block;position: relative;width:16px;height:11px;background:url('/css/flags/flags.png') no-repeat; background-position:-272px -176px;}.flag.flag-gu{background-position:-96px -55px}.flag.flag-mn{background-position:-208px -88px}.flag.flag-va{background-position:-48px -154px}.flag.flag-tibet{background-position:-32px -143px}.flag.flag-fo{background-position:-64px -44px}.flag.flag-th{background-position:-16px -143px}.flag.flag-tr{background-position:-144px -143px}.flag.flag-tl{background-position:-80px -143px}.flag.flag-kz{background-position:-144px -77px}.flag.flag-zm{background-position:-16px -165px}.flag.flag-uz{background-position:-32px -154px}.flag.flag-dk{background-position:-64px -33px}.flag.flag-scotland{background-position:-176px -121px}.flag.flag-gi{background-position:-224px -44px}.flag.flag-gy{background-position:-128px -55px}.flag.flag-bj{background-position:-112px -11px}.flag.flag-fr{background-position:-80px -44px}.flag.flag-mo{background-position:-224px -88px}.flag.flag-ir{background-position:-112px -66px}.flag.flag-io{background-position:-80px -66px}.flag.flag-tm{background-position:-96px -143px}.flag.flag-ch{background-position:-96px -22px}.flag.flag-mt{background-position:-32px -99px}.flag.flag-nl{background-position:-240px -99px}.flag.flag-gp{background-position:-16px -55px}.flag.flag-im{background-position:-48px -66px}.flag.flag-tv{background-position:-176px -143px}.flag.flag-mu{background-position:-48px -99px}.flag.flag-pe{background-position:-96px -110px}.flag.flag-vi{background-position:-112px -154px}.flag.flag-hn{background-position:-176px -55px}.flag.flag-ss{background-position:-128px -132px}.flag.flag-ae{background-position:-16px 0}.flag.flag-td{background-position:-240px -132px}.flag.flag-pw{background-position:0 -121px}.flag.flag-nu{background-position:-32px -110px}.flag.flag-bt{background-position:-208px -11px}.flag.flag-ms{background-position:-16px -99px}.flag.flag-cv{background-position:-240px -22px}.flag.flag-es{background-position:-224px -33px}.flag.flag-mh{background-position:-144px -88px}.flag.flag-la{background-position:-160px -77px}.flag.flag-vn{background-position:-128px -154px}.flag.flag-py{background-position:-16px -121px}.flag.flag-br{background-position:-176px -11px}.flag.flag-ye{background-position:-224px -154px}.flag.flag-ie{background-position:0 -66px}.flag.flag-gh{background-position:-208px -44px}.flag.flag-cg{background-position:-80px -22px}.flag.flag-cu{background-position:-224px -22px}.flag.flag-hu{background-position:-224px -55px}.flag.flag-sg{background-position:-224px -121px}.flag.flag-at{background-position:-176px 0}.flag.flag-lk{background-position:-224px -77px}.flag.flag-vu{background-position:-144px -154px}.flag.flag-bo{background-position:-160px -11px}.flag.flag-jo{background-position:-208px -66px}.flag.flag-er{background-position:-208px -33px}.flag.flag-za{background-position:-256px -154px}.flag.flag-rs{background-position:-80px -121px}.flag.flag-nr{background-position:-16px -110px}.flag.flag-ls{background-position:-256px -77px}.flag.flag-jm{background-position:-192px -66px}.flag.flag-tz{background-position:-208px -143px}.flag.flag-ki{background-position:-16px -77px}.flag.flag-sj{background-position:0 -132px}.flag.flag-cz{background-position:-16px -33px}.flag.flag-pg{background-position:-128px -110px}.flag.flag-lv{background-position:-32px -88px}.flag.flag-do{background-position:-96px -33px}.flag.flag-lu{background-position:-16px -88px}.flag.flag-no{background-position:-256px -99px}.flag.flag-kw{background-position:-112px -77px}.flag.flag-mx{background-position:-96px -99px}.flag.flag-yt{background-position:-240px -154px}.flag.flag-ly{background-position:-48px -88px}.flag.flag-cy{background-position:0 -33px}.flag.flag-ph{background-position:-144px -110px}.flag.flag-my{background-position:-112px -99px}.flag.flag-sm{background-position:-48px -132px}.flag.flag-et{background-position:-240px -33px}.flag.flag-ru{background-position:-96px -121px}.flag.flag-tj{background-position:-48px -143px}.flag.flag-ai{background-position:-64px 0}.flag.flag-pl{background-position:-176px -110px}.flag.flag-kp{background-position:-64px -77px}.flag.flag-uy{background-position:-16px -154px}.flag.flag-gb{background-position:-112px -44px}.flag.flag-gs{background-position:-64px -55px}.flag.flag-kurdistan{background-position:-96px -77px}.flag.flag-rw{background-position:-112px -121px}.flag.flag-ec{background-position:-128px -33px}.flag.flag-mm{background-position:-192px -88px}.flag.flag-pa{background-position:-80px -110px}.flag.flag-wales{background-position:-160px -154px}.flag.flag-kg{background-position:-256px -66px}.flag.flag-ve{background-position:-80px -154px}.flag.flag-tk{background-position:-64px -143px}.flag.flag-ca{background-position:-16px -22px}.flag.flag-is{background-position:-128px -66px}.flag.flag-ke{background-position:-240px -66px}.flag.flag-ro{background-position:-64px -121px}.flag.flag-gq{background-position:-32px -55px}.flag.flag-pt{background-position:-256px -110px}.flag.flag-tf{background-position:-256px -132px}.flag.flag-ad{background-position:0 0}.flag.flag-sk{background-position:-16px -132px}.flag.flag-pm{background-position:-192px -110px}.flag.flag-om{background-position:-64px -110px}.flag.flag-an{background-position:-112px 0}.flag.flag-ws{background-position:-192px -154px}.flag.flag-sh{background-position:-240px -121px}.flag.flag-mp{background-position:-240px -88px}.flag.flag-gt{background-position:-80px -55px}.flag.flag-cf{background-position:-64px -22px}.flag.flag-zanzibar{background-position:0 -165px}.flag.flag-mw{background-position:-80px -99px}.flag.flag-catalonia{background-position:-32px -22px}.flag.flag-ug{background-position:-240px -143px}.flag.flag-je{background-position:-176px -66px}.flag.flag-km{background-position:-32px -77px}.flag.flag-in{background-position:-64px -66px}.flag.flag-bf{background-position:-48px -11px}.flag.flag-mc{background-position:-80px -88px}.flag.flag-sy{background-position:-192px -132px}.flag.flag-sn{background-position:-64px -132px}.flag.flag-kr{background-position:-80px -77px}.flag.flag-eu{background-position:-256px -33px}.flag.flag-bn{background-position:-144px -11px}.flag.flag-st{background-position:-144px -132px}.flag.flag-england{background-position:-192px -33px}.flag.flag-lc{background-position:-192px -77px}.flag.flag-dm{background-position:-80px -33px}.flag.flag-be{background-position:-32px -11px}.flag.flag-ni{background-position:-224px -99px}.flag.flag-ua{background-position:-224px -143px}.flag.flag-mz{background-position:-128px -99px}.flag.flag-pf{background-position:-112px -110px}.flag.flag-tn{background-position:-112px -143px}.flag.flag-ee{background-position:-144px -33px}.flag.flag-xk{background-position:-208px -154px}.flag.flag-sx{background-position:-176px -132px}.flag.flag-sd{background-position:-192px -121px}.flag.flag-gd{background-position:-128px -44px}.flag.flag-ci{background-position:-112px -22px}.flag.flag-sz{background-position:-208px -132px}.flag.flag-cl{background-position:-144px -22px}.flag.flag-fi{background-position:0 -44px}.flag.flag-ga{background-position:-96px -44px}.flag.flag-jp{background-position:-224px -66px}.flag.flag-de{background-position:-32px -33px}.flag.flag-np{background-position:0 -110px}.flag.flag-re{background-position:-48px -121px}.flag.flag-bg{background-position:-64px -11px}.flag.flag-sc{background-position:-160px -121px}.flag.flag-ng{background-position:-208px -99px}.flag.flag-qa{background-position:-32px -121px}.flag.flag-mk{background-position:-160px -88px}.flag.flag-aw{background-position:-208px 0}.flag.flag-kn{background-position:-48px -77px}.flag.flag-al{background-position:-80px 0}.flag.flag-bw{background-position:-240px -11px}.flag.flag-um{background-position:-256px -143px}.flag.flag-ky{background-position:-128px -77px}.flag.flag-tt{background-position:-160px -143px}.flag.flag-so{background-position:-80px -132px}.flag.flag-lt{background-position:0 -88px}.flag.flag-by{background-position:-256px -11px}.flag.flag-bb{background-position:0 -11px}.flag.flag-us{background-position:0 -154px}.flag.flag-md{background-position:-96px -88px}.flag.flag-ag{background-position:-48px 0}.flag.flag-hm{background-position:-160px -55px}.flag.flag-as{background-position:-160px 0}.flag.flag-eg{background-position:-160px -33px}.flag.flag-sv{background-position:-160px -132px}.flag.flag-sl{background-position:-32px -132px}.flag.flag-fk{background-position:-32px -44px}.flag.flag-am{background-position:-96px 0}.flag.flag-ck{background-position:-128px -22px}.flag.flag-tw{background-position:-192px -143px}.flag.flag-kh{background-position:0 -77px}.flag.flag-to{background-position:-128px -143px}.flag.flag-se{background-position:-208px -121px}.flag.flag-cd{background-position:-48px -22px}.flag.flag-pn{background-position:-208px -110px}.flag.flag-gr{background-position:-48px -55px}.flag.flag-id{background-position:-256px -55px}.flag.flag-vc{background-position:-64px -154px}.flag.flag-somaliland{background-position:-96px -132px}.flag.flag-bi{background-position:-96px -11px}.flag.flag-pk{background-position:-160px -110px}.flag.flag-pr{background-position:-224px -110px}.flag.flag-bd{background-position:-16px -11px}.flag.flag-co{background-position:-192px -22px}.flag.flag-fm{background-position:-48px -44px}.flag.flag-bm{background-position:-128px -11px}.flag.flag-ar{background-position:-144px 0}.flag.flag-bv{background-position:-224px -11px}.flag.flag-sb{background-position:-144px -121px}.flag.flag-mq{background-position:-256px -88px}.flag.flag-eh{background-position:-176px -33px}.flag.flag-bh{background-position:-80px -11px}.flag.flag-it{background-position:-144px -66px}.flag.flag-hr{background-position:-192px -55px}.flag.flag-sa{background-position:-128px -121px}.flag.flag-mv{background-position:-64px -99px}.flag.flag-mg{background-position:-128px -88px}.flag.flag-dz{background-position:-112px -33px}.flag.flag-gg{background-position:-192px -44px}.flag.flag-gm{background-position:-256px -44px}.flag.flag-af{background-position:-32px 0}.flag.flag-li{background-position:-208px -77px}.flag.flag-sr{background-position:-112px -132px}.flag.flag-vg{background-position:-96px -154px}.flag.flag-cr{background-position:-208px -22px}.flag.flag-tc{background-position:-224px -132px}.flag.flag-ao{background-position:-128px 0}.flag.flag-ma{background-position:-64px -88px}.flag.flag-mr{background-position:0 -99px}.flag.flag-gn{background-position:0 -55px}.flag.flag-ne{background-position:-176px -99px}.flag.flag-nf{background-position:-192px -99px}.flag.flag-wf{background-position:-176px -154px}.flag.flag-hk{background-position:-144px -55px}.flag.flag-gf{background-position:-160px -44px}.flag.flag-ps{background-position:-240px -110px}.flag.flag-ic{background-position:-240px -55px}.flag.flag-cw{background-position:-256px -22px}.flag.flag-ml{background-position:-176px -88px}.flag.flag-ax{background-position:-224px 0}.flag.flag-gl{background-position:-240px -44px}.flag.flag-dj{background-position:-48px -33px}.flag.flag-cn{background-position:-176px -22px}.flag.flag-ht{background-position:-208px -55px}.flag.flag-lr{background-position:-240px -77px}.flag.flag-tg{background-position:0 -143px}.flag.flag-ba{background-position:-256px 0}.flag.flag-ge{background-position:-144px -44px}.flag.flag-bz{background-position:0 -22px}.flag.flag-au{background-position:-192px 0}.flag.flag-iq{background-position:-96px -66px}.flag.flag-cm{background-position:-160px -22px}.flag.flag-gw{background-position:-112px -55px}.flag.flag-az{background-position:-240px 0}.flag.flag-na{background-position:-144px -99px}.flag.flag-fj{background-position:-16px -44px}.flag.flag-zw{background-position:-32px -165px}.flag.flag-bs{background-position:-192px -11px}.flag.flag-il{background-position:-16px -66px}.flag.flag-nz{background-position:-48px -110px}.flag.flag-me{background-position:-112px -88px}.flag.flag-si{background-position:-256px -121px}.flag.flag-nc{background-position:-160px -99px}.flag.flag-lb{background-position:-176px -77px}
\ No newline at end of file
diff --git a/public/css/flags/flags.png b/public/css/flags/flags.png
new file mode 100644
index 00000000..0658bb8a
Binary files /dev/null and b/public/css/flags/flags.png differ
diff --git a/public/css/footer.css b/public/css/footer.css
index 01f241aa..0ef600d2 100644
--- a/public/css/footer.css
+++ b/public/css/footer.css
@@ -8,7 +8,7 @@ html {
body {
/* Margin bottom by footer height */
- margin-bottom: 60px;
+ margin-bottom: 70px;
}
.footer {
diff --git a/public/css/mailtrain.css b/public/css/mailtrain.css
index f4bf6f2f..1aac8abe 100644
--- a/public/css/mailtrain.css
+++ b/public/css/mailtrain.css
@@ -1,16 +1,28 @@
+@import "flags/flags.css";
+
.glyphicon.spinning {
animation: spin 1s infinite linear;
-webkit-animation: spin2 1s infinite linear;
}
@keyframes spin {
- from { transform: scale(1) rotate(0deg); }
- to { transform: scale(1) rotate(360deg); }
+ from {
+ transform: scale(1) rotate(0deg);
+ }
+
+ to {
+ transform: scale(1) rotate(360deg);
+ }
}
@-webkit-keyframes spin2 {
- from { -webkit-transform: rotate(0deg); }
- to { -webkit-transform: rotate(360deg); }
+ from {
+ -webkit-transform: rotate(0deg);
+ }
+
+ to {
+ -webkit-transform: rotate(360deg);
+ }
}
/* Supporting wider description lists */
@@ -23,11 +35,25 @@
.dl-horizontal dd {
margin-left: 220px;
}
+
}
+@media screen and (max-width: 767px) {
+ .text-xs-center {
+ text-align: center;
+ }
+
+ .form-group .col-xs-12 button {
+ margin-bottom: 20px;
+ }
+
+}
+
+
h2 .glyphicon {
font-size: .75em;
}
+
h3 .glyphicon {
font-size: .8em;
}
@@ -46,4 +72,78 @@ tbody>tr.selected {
.row-actions .row-action:last-child {
padding-right: 0px;
+}
+
+
+span.subscriber-status-1 {
+ /* subscribed */
+ color: #2b5718;
+}
+
+span.subscriber-status-0,
+span.subscriber-status-2 {
+ /* unknow / unsubscribed */
+ color: #b3aba0;
+}
+
+span.subscriber-status-3 {
+ /* bounced */
+ color: #aa3203;
+}
+
+span.subscriber-status-4 {
+ /* complained */
+ color: #7b0833;
+}
+
+/* subscriber line status */
+tr.subscriber-status-1 td:first-child {
+ border-right: solid 3px #87ad77;
+ text-align:center;
+ padding-right: 10px;
+}
+
+tr.subscriber-status-0 td:first-child,
+tr.subscriber-status-2 td:first-child {
+ border-right: solid 3px #c7bfb4;
+ text-align:center;
+ padding-right: 10px;
+}
+
+tr.subscriber-status-3 td:first-child {
+ border-right: solid 3px #df6b3d;
+ text-align:center;
+ padding-right: 10px;
+}
+
+tr.subscriber-status-4 td:first-child {
+ border-right: solid 3px #c94475;
+ text-align:center;
+ padding-right: 10px;
+}
+
+/* subscribers status icon */
+.status-icon {
+ display: inline-block;
+ width: 8px;
+ height: 8px;
+ border-radius: 4px;
+ vertical-align: middle;
+}
+
+.status-icon.subscriber-status-1 {
+ background-color: #2b5718;
+}
+
+.status-icon.subscriber-status-0,
+.status-icon.subscriber-status-2 {
+ background-color: #b3aba0;
+}
+
+.status-icon.subscriber-status-3 {
+ background-color: #aa3203;
+}
+
+.status-icon.subscriber-status-4 {
+ background-color: #7b0833;
}
\ No newline at end of file
diff --git a/routes/lists.js b/routes/lists.js
index 516c54d3..0318db12 100644
--- a/routes/lists.js
+++ b/routes/lists.js
@@ -12,6 +12,7 @@ let forms = require('../lib/models/forms');
let tools = require('../lib/tools');
let striptags = require('striptags');
let htmlescape = require('escape-html');
+let getName = require('country-list').getName;
let multer = require('multer');
let os = require('os');
let humanize = require('humanize');
@@ -167,7 +168,7 @@ router.post('/ajax', (req, res) => {
'' + row.cid + '
',
row.subscribers,
htmlescape(striptags(row.description) || ''),
- '' + _('Edit') + '' ]
+ ' ' + _('Edit') + '' ]
)
});
});
@@ -254,7 +255,7 @@ router.post('/ajax/:id', (req, res) => {
} else {
return htmlescape(cRow.value || '');
}
- })).concat(statuses[row.status]).concat(row.created && row.created.toISOString ? '' + row.created.toISOString() + '' : 'N/A').concat('' + _('Edit') + ''))
+ })).concat(config.views.lists.statuscolored ? '' + statuses[row.status] + '' : statuses[row.status]).concat(row.created && row.created.toISOString ? '' + row.created.toISOString() + '' : 'N/A').concat('' + _('Edit') + ''))
});
});
});
@@ -312,6 +313,7 @@ router.get('/view/:id', passport.csrfProtection, (req, res) => {
list.csrfToken = req.csrfToken();
list.customFields = fieldList.filter(field => field.visible);
list.customSort = list.customFields.length ? ',' + list.customFields.map(() => '0').join(',') : '';
+ list.statusColored = config.views.lists.statuscolored;
list.showSubscriptions = req.query.tab === 'subscriptions' || !req.query.tab;
list.showImports = req.query.tab === 'imports';
@@ -387,14 +389,27 @@ router.get('/subscription/:id/edit/:cid', passport.csrfProtection, (req, res) =>
fieldList = [];
}
+ let statuses = [_('Unknown'), _('Subscribed'), _('Unsubscribed'), _('Bounced'), _('Complained')];
+
subscription.list = list;
subscription.csrfToken = req.csrfToken();
subscription.customFields = fields.getRow(fieldList, subscription, false, true);
subscription.useEditor = true;
+ subscription.createdDate = moment(subscription.created).format('lll');
+ subscription.modifiedDate = moment(subscription.statusChange).format('lll');
+
+ subscription.statusTitle = statuses[subscription.status];
subscription.isSubscribed = subscription.status === 1;
subscription.isBounced = subscription.status === 3;
+ let country = {};
+ if (subscription.optInCountry) {
+ country.name = getName(subscription.optInCountry);
+ country.code = subscription.optInCountry.toLowerCase();
+ }
+ subscription.country = country;
+
let tzfound = false;
subscription.timezones = moment.tz.names().map(tz => {
let selected = false;
diff --git a/views/layout.hbs b/views/layout.hbs
index 73eff28a..8aad8a19 100644
--- a/views/layout.hbs
+++ b/views/layout.hbs
@@ -147,7 +147,7 @@
diff --git a/views/lists/subscription/edit.hbs b/views/lists/subscription/edit.hbs
index a1db3a24..1cb20de3 100644
--- a/views/lists/subscription/edit.hbs
+++ b/views/lists/subscription/edit.hbs
@@ -41,12 +41,28 @@