MailPoet Newsletters (New) - Version 3.0.0-rc.2.0.0

Version Description

  • 2017-08-29 =
  • Improved: MailPoet updates on high traffic sites now use less resources;
  • Improved: newsletter is saved when "next" button is pressed in newsletter editor;
  • Improved: allows editors to manage emails and adds hooks to extend plugin's roles/permissions;
  • Improved: we collect more informative data from those who share their data with us. You should too!
  • Fixed: subscription management form works again;
  • Fixed: MailPoet 3 no longer processes the "wysija_form" shortcode used by the old MailPoet 2 to allow both plugins to display forms. Please use the newer "mailpoet_form" shortcode instead. Thx Lynn!
  • Fixed: reactivated post notifications will be sent on next scheduled time. Thx Luc!
  • Fixed: updating subscription information of WP users no longer erases their first/last name;
  • Fixed: automated latest content in welcome emails always displays the latest posts. Kudos Ehi!
Download this release

Release Info

Developer wysija
Plugin Icon 128x128 MailPoet Newsletters (New)
Version 3.0.0-rc.2.0.0
Comparing to
See all releases

Code changes from version 3.0.0-rc.1.0.4 to 3.0.0-rc.2.0.0

Files changed (79) hide show
  1. assets/css/{admin.d5e07a36.css → admin.0df54f3d.css} +3 -2
  2. assets/css/manifest.json +1 -1
  3. assets/img/welcome_template/beacon.png +0 -0
  4. assets/js/{admin.d56f9a3d.js → admin.36b0c17d.js} +120 -92
  5. assets/js/{admin_vendor.aaf3acee.js → admin_vendor.71d84e79.js} +21 -21
  6. assets/js/{form_editor.4d117b35.js → form_editor.92c760ec.js} +1074 -1073
  7. assets/js/lib/mailpoet_shortcodes/plugin.js +2 -2
  8. assets/js/{mailpoet.28805a4f.js → mailpoet.a3939b7d.js} +13 -14
  9. assets/js/manifest.json +8 -8
  10. assets/js/{mp2migrator.d958f0f5.js → mp2migrator.f1fb2656.js} +4 -4
  11. assets/js/{newsletter_editor.a3d00b84.js → newsletter_editor.dabd6b50.js} +225 -229
  12. assets/js/{public.412ca9cc.js → public.15490850.js} +4 -4
  13. assets/js/{vendor.016cb65c.js → vendor.aecfe832.js} +7 -7
  14. lang/index.php +0 -3
  15. lang/mailpoet-da_DK.mo +0 -0
  16. lang/mailpoet-fr_FR.mo +0 -0
  17. lang/mailpoet-nl_NL.mo +0 -0
  18. lang/mailpoet-ru_RU.mo +0 -0
  19. lang/mailpoet-sv_SE.mo +0 -0
  20. lang/mailpoet-tr_TR.mo +0 -0
  21. lang/mailpoet.pot +141 -128
  22. lib/API/API.php +5 -2
  23. lib/API/JSON/API.php +13 -14
  24. lib/API/JSON/Access.php +0 -12
  25. lib/API/JSON/Endpoint.php +8 -3
  26. lib/API/JSON/v1/AutomatedLatestContent.php +6 -0
  27. lib/API/JSON/v1/CustomFields.php +7 -0
  28. lib/API/JSON/v1/Forms.php +10 -4
  29. lib/API/JSON/v1/ImportExport.php +8 -2
  30. lib/API/JSON/v1/MP2Migrator.php +14 -8
  31. lib/API/JSON/v1/Mailer.php +7 -0
  32. lib/API/JSON/v1/NewsletterTemplates.php +7 -1
  33. lib/API/JSON/v1/Newsletters.php +28 -10
  34. lib/API/JSON/v1/Segments.php +8 -2
  35. lib/API/JSON/v1/SendingQueue.php +8 -2
  36. lib/API/JSON/v1/Services.php +15 -8
  37. lib/API/JSON/v1/Settings.php +11 -4
  38. lib/API/JSON/v1/Setup.php +6 -0
  39. lib/API/JSON/v1/Subscribers.php +7 -6
  40. lib/Config/AccessControl.php +104 -0
  41. lib/Config/Activator.php +4 -3
  42. lib/Config/Changelog.php +2 -3
  43. lib/Config/Env.php +1 -1
  44. lib/Config/Initializer.php +11 -6
  45. lib/Config/MP2Migrator.php +3 -2
  46. lib/Config/Menu.php +221 -184
  47. lib/Config/ServicesChecker.php +19 -11
  48. lib/Config/Shortcodes.php +0 -1
  49. lib/Config/Widget.php +14 -2
  50. lib/Cron/Workers/SendingQueue/Tasks/Posts.php +5 -4
  51. lib/Form/Renderer.php +7 -5
  52. lib/Form/Widget.php +2 -2
  53. lib/Models/Subscriber.php +4 -1
  54. lib/Newsletter/Renderer/Blocks/Renderer.php +1 -4
  55. lib/Newsletter/Scheduler/Scheduler.php +12 -0
  56. lib/Router/Endpoints/CronDaemon.php +5 -0
  57. lib/Router/Endpoints/Subscription.php +5 -0
  58. lib/Router/Endpoints/Track.php +7 -2
  59. lib/Router/Endpoints/ViewInBrowser.php +9 -4
  60. lib/Router/Router.php +20 -6
  61. lib/Services/Bridge.php +23 -20
  62. lib/Services/Bridge/API.php +1 -5
  63. lib/Subscription/Form.php +3 -2
  64. lib/Subscription/Manage.php +6 -3
  65. lib/Subscription/Pages.php +2 -2
  66. mailpoet.php +2 -2
  67. readme.txt +13 -1
  68. vendor/autoload.php +1 -1
  69. vendor/composer/ClassLoader.php +38 -8
  70. vendor/composer/autoload_classmap.php +1 -1
  71. vendor/composer/autoload_real.php +8 -8
  72. vendor/composer/autoload_static.php +6 -6
  73. vendor/composer/installed.json +14 -14
  74. views/form/editor.html +17 -1
  75. views/form/templates/settings/field_form.hbs +5 -0
  76. views/forms.html +11 -1
  77. views/layout.html +1 -1
  78. views/premium.html +8 -0
  79. views/update.html +2 -2
assets/css/{admin.d5e07a36.css → admin.0df54f3d.css} RENAMED
@@ -1562,6 +1562,7 @@ body.mailpoet_modal_opened {
1562
  font-family: monospace;
1563
  height: 300px;
1564
  color: black;
 
1565
  }
1566
 
1567
  /* PADDING */
@@ -1876,8 +1877,8 @@ div.CodeMirror-dragcursors {
1876
  .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
1877
 
1878
  .cm-searching {
1879
- background: #ffa;
1880
- background: rgba(255, 255, 0, .4);
1881
  }
1882
 
1883
  /* Used to force a border model for a node */
1562
  font-family: monospace;
1563
  height: 300px;
1564
  color: black;
1565
+ direction: ltr;
1566
  }
1567
 
1568
  /* PADDING */
1877
  .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
1878
 
1879
  .cm-searching {
1880
+ background-color: #ffa;
1881
+ background-color: rgba(255, 255, 0, .4);
1882
  }
1883
 
1884
  /* Used to force a border model for a node */
assets/css/manifest.json CHANGED
@@ -1,5 +1,5 @@
1
  {
2
- "admin.css": "admin.d5e07a36.css",
3
  "importExport.css": "importExport.b3745466.css",
4
  "newsletter_editor.css": "newsletter_editor.effbdd78.css",
5
  "public.css": "public.cae357df.css",
1
  {
2
+ "admin.css": "admin.0df54f3d.css",
3
  "importExport.css": "importExport.b3745466.css",
4
  "newsletter_editor.css": "newsletter_editor.effbdd78.css",
5
  "public.css": "public.cae357df.css",
assets/img/welcome_template/beacon.png CHANGED
Binary file
assets/js/{admin.d56f9a3d.js → admin.36b0c17d.js} RENAMED
@@ -9171,10 +9171,10 @@ webpackJsonp([0],[
9171
  label: MailPoet.I18n.t('status'),
9172
  type: 'select',
9173
  values: {
9174
- 'subscribed': MailPoet.I18n.t('subscribed'),
9175
- 'unconfirmed': MailPoet.I18n.t('unconfirmed'),
9176
- 'unsubscribed': MailPoet.I18n.t('unsubscribed'),
9177
- 'bounced': MailPoet.I18n.t('bounced')
9178
  },
9179
  filter: function filter(subscriber, value) {
9180
  if (~ ~subscriber.wp_user_id > 0 && value === 'unconfirmed') {
@@ -9263,6 +9263,9 @@ webpackJsonp([0],[
9263
  },
9264
  onCreate: function onCreate() {
9265
  MailPoet.Notice.success(MailPoet.I18n.t('subscriberAdded'));
 
 
 
9266
  }
9267
  };
9268
 
@@ -9499,7 +9502,7 @@ webpackJsonp([0],[
9499
  });
9500
  }
9501
 
9502
- var formClasses = classNames('mailpoet_form', { 'mailpoet_form_loading': this.state.loading || this.props.loading });
9503
 
9504
  var beforeFormContent = false;
9505
  var afterFormContent = false;
@@ -10052,28 +10055,28 @@ webpackJsonp([0],[
10052
  switch (dateType) {
10053
  case 'year_month_day':
10054
  value = {
10055
- 'year': this.state.year,
10056
- 'month': this.state.month,
10057
- 'day': this.state.day
10058
  };
10059
  break;
10060
 
10061
  case 'year_month':
10062
  value = {
10063
- 'year': this.state.year,
10064
- 'month': this.state.month
10065
  };
10066
  break;
10067
 
10068
  case 'month':
10069
  value = {
10070
- 'month': this.state.month
10071
  };
10072
  break;
10073
 
10074
  case 'year':
10075
  value = {
10076
- 'year': this.state.year
10077
  };
10078
  break;
10079
  }
@@ -26130,10 +26133,10 @@ webpackJsonp([0],[
26130
  },
26131
  render: function render() {
26132
  var types = [{
26133
- 'id': 'standard',
26134
- 'title': MailPoet.I18n.t('regularNewsletterTypeTitle'),
26135
- 'description': MailPoet.I18n.t('regularNewsletterTypeDescription'),
26136
- 'action': (function () {
26137
  return React.createElement(
26138
  'a',
26139
  { className: 'button button-primary', onClick: this.createNewsletter.bind(null, 'standard') },
@@ -26141,10 +26144,10 @@ webpackJsonp([0],[
26141
  );
26142
  }).bind(this)()
26143
  }, {
26144
- 'id': 'welcome',
26145
- 'title': MailPoet.I18n.t('welcomeNewsletterTypeTitle'),
26146
- 'description': MailPoet.I18n.t('welcomeNewsletterTypeDescription'),
26147
- 'action': (function () {
26148
  return React.createElement(
26149
  'div',
26150
  null,
@@ -26156,10 +26159,10 @@ webpackJsonp([0],[
26156
  );
26157
  })()
26158
  }, {
26159
- 'id': 'notification',
26160
- 'title': MailPoet.I18n.t('postNotificationNewsletterTypeTitle'),
26161
- 'description': MailPoet.I18n.t('postNotificationNewsletterTypeDescription'),
26162
- 'action': (function () {
26163
  return React.createElement(
26164
  'a',
26165
  { className: 'button button-primary', onClick: this.setupNewsletter.bind(null, 'notification') },
@@ -26347,7 +26350,7 @@ webpackJsonp([0],[
26347
  response.data = [{
26348
  name: MailPoet.I18n.t('mailpoetGuideTemplateTitle'),
26349
  description: MailPoet.I18n.t('mailpoetGuideTemplateDescription'),
26350
- readonly: "1"
26351
  }];
26352
  }
26353
  _this2.setState({
@@ -26399,7 +26402,7 @@ webpackJsonp([0],[
26399
  var _this3 = this;
26400
 
26401
  this.setState({ loading: true });
26402
- if (window.confirm(MailPoet.I18n.t('confirmTemplateDeletion').replace("%$1s", template.name))) {
26403
  MailPoet.Ajax.post({
26404
  api_version: window.mailpoet_api_version,
26405
  endpoint: 'newsletterTemplates',
@@ -26500,11 +26503,11 @@ webpackJsonp([0],[
26500
  MailPoet.I18n.t('select')
26501
  )
26502
  ),
26503
- template.readonly === "1" ? false : deleteLink
26504
  );
26505
  });
26506
 
26507
- var boxClasses = classNames('mailpoet_boxes', 'clearfix', { 'mailpoet_boxes_loading': this.state.loading });
26508
 
26509
  return React.createElement(
26510
  'div',
@@ -26552,18 +26555,18 @@ webpackJsonp([0],[
26552
  var tooltipId = props.tooltipId;
26553
  var tooltip = props.tooltip;
26554
  // tooltip ID must be unique, defaults to tooltip text
26555
- if (!props.tooltipId && typeof props.tooltip === "string") {
26556
  tooltipId = props.tooltip;
26557
  }
26558
 
26559
- if (typeof props.tooltip === "string") {
26560
  tooltip = _react2['default'].createElement(
26561
  'span',
26562
  {
26563
  style: {
26564
- pointerEvents: "all",
26565
- maxWidth: "400",
26566
- display: "inline-block"
26567
  }
26568
  },
26569
  (0, _reactHtmlParser2['default'])(props.tooltip)
@@ -26575,7 +26578,7 @@ webpackJsonp([0],[
26575
  { className: props.className },
26576
  _react2['default'].createElement('span', {
26577
  style: {
26578
- cursor: "pointer"
26579
  },
26580
  className: 'tooltip dashicons dashicons-editor-help',
26581
  'data-event': 'click',
@@ -35363,13 +35366,13 @@ webpackJsonp([0],[
35363
  MailPoet.trackEvent('Emails > Welcome email activated', {
35364
  'MailPoet Free version': window.mailpoet_version,
35365
  'List type': opts.event,
35366
- 'Delay': opts.afterTimeNumber + ' ' + opts.afterTimeType
35367
  });
35368
  } else if (response.data.type === 'notification') {
35369
  MailPoet.Notice.success(MailPoet.I18n.t('postNotificationActivated'));
35370
  MailPoet.trackEvent('Emails > Post notifications activated', {
35371
  'MailPoet Free version': window.mailpoet_version,
35372
- 'Frequency': opts.intervalType
35373
  });
35374
  }
35375
  }).fail(_this2._showError);
@@ -35712,7 +35715,7 @@ webpackJsonp([0],[
35712
  var DateTime = React.createClass({
35713
  displayName: 'DateTime',
35714
 
35715
- _DATE_TIME_SEPARATOR: " ",
35716
  getInitialState: function getInitialState() {
35717
  return this._buildStateFromProps(this.props);
35718
  },
@@ -36849,7 +36852,7 @@ webpackJsonp([0],[
36849
  _mailpoet2['default'].Date.format(newsletter.queue.scheduled_at)
36850
  );
36851
  }
36852
- var progressClasses = (0, _classnames2['default'])('mailpoet_progress', { 'mailpoet_progress_complete': newsletter.queue.status === 'completed' });
36853
 
36854
  // calculate percentage done
36855
  var percentage = Math.round(newsletter.queue.count_processed * 100 / newsletter.queue.count_total);
@@ -36860,7 +36863,7 @@ webpackJsonp([0],[
36860
  label = _react2['default'].createElement(
36861
  'span',
36862
  null,
36863
- _mailpoet2['default'].I18n.t('newsletterQueueCompleted').replace("%$1d", newsletter.queue.count_processed).replace("%$2d", newsletter.queue.count_total)
36864
  );
36865
  } else {
36866
  label = _react2['default'].createElement(
@@ -36901,7 +36904,7 @@ webpackJsonp([0],[
36901
  percentage = _mailpoet2['default'].I18n.t('noSubscribers');
36902
  } else {
36903
  progress_bar_width = percentage;
36904
- percentage += "%";
36905
  }
36906
 
36907
  return _react2['default'].createElement(
@@ -36912,7 +36915,7 @@ webpackJsonp([0],[
36912
  { className: progressClasses },
36913
  _react2['default'].createElement('span', {
36914
  className: 'mailpoet_progress_bar',
36915
- style: { width: progress_bar_width + "%" }
36916
  }),
36917
  _react2['default'].createElement(
36918
  'span',
@@ -37048,7 +37051,7 @@ webpackJsonp([0],[
37048
  { className: 'mailpoet_stats_text' },
37049
  percentage_opened_display,
37050
  '%,',
37051
- " ",
37052
  percentage_clicked_display,
37053
  '%',
37054
  _react2['default'].createElement(
@@ -37132,7 +37135,7 @@ webpackJsonp([0],[
37132
  var mailer_check_settings_notice = (0, _reactStringReplace2['default'])(_mailpoet2['default'].I18n.t('mailerCheckSettingsNotice'), /\[link\](.*?)\[\/link\]/g, function (match) {
37133
  return _react2['default'].createElement(
37134
  'a',
37135
- { href: '?page=mailpoet-settings#mta' },
37136
  match
37137
  );
37138
  });
@@ -38453,6 +38456,9 @@ webpackJsonp([0],[
38453
  },
38454
  onCreate: function onCreate() {
38455
  MailPoet.Notice.success(MailPoet.I18n.t('segmentAdded'));
 
 
 
38456
  }
38457
  };
38458
 
@@ -41018,7 +41024,7 @@ webpackJsonp([0],[
41018
  };
41019
 
41020
  Tabs.propTypes = { tab: _react2['default'].PropTypes.string };
41021
- Tabs.defaultProps = { tab: "knowledgeBase" };
41022
 
41023
  module.exports = Tabs;
41024
 
@@ -41059,10 +41065,10 @@ webpackJsonp([0],[
41059
  return _react2['default'].createElement('textarea', {
41060
  readOnly: true,
41061
  onFocus: handleFocus,
41062
- value: printableData.join("\n"),
41063
  style: {
41064
- width: "100%",
41065
- height: "400px"
41066
  }
41067
  });
41068
  } else {
@@ -41082,7 +41088,7 @@ webpackJsonp([0],[
41082
  _react2['default'].createElement(_tabsJsx2['default'], { tab: 'systemInfo' }),
41083
  _react2['default'].createElement(
41084
  'div',
41085
- { className: 'mailpoet_notice notice inline notice-success', style: { marginTop: "1em" } },
41086
  _react2['default'].createElement(
41087
  'p',
41088
  null,
@@ -41114,9 +41120,9 @@ webpackJsonp([0],[
41114
 
41115
  MailPoet.Modal.loading(true);
41116
  MailPoet.Ajax.post({
41117
- 'api_version': window.mailpoet_api_version,
41118
- 'endpoint': 'setup',
41119
- 'action': 'reset'
41120
  }).always(function () {
41121
  MailPoet.Modal.loading(false);
41122
  }).done(function () {
@@ -41175,9 +41181,9 @@ webpackJsonp([0],[
41175
  router = new (Backbone.Router.extend({
41176
  routes: {
41177
  '': 'home',
41178
- 'step1': 'step1',
41179
- 'step2': 'step2',
41180
- 'step3': 'step3'
41181
  },
41182
  home: function () {
41183
  this.navigate('step1', {trigger: true});
@@ -41257,7 +41263,7 @@ webpackJsonp([0],[
41257
  * Paste
41258
  */
41259
  pasteInputElement
41260
- .attr('value', pasteInputPlaceholderElement).css('color', "#999")
41261
  .focus(function () {
41262
  if (jQuery(this).val() === pasteInputPlaceholderElement) {
41263
  jQuery(this).attr('value', '').css('color', '#222');
@@ -41265,7 +41271,7 @@ webpackJsonp([0],[
41265
  })
41266
  .blur(function () {
41267
  if (jQuery(this).val() === '') {
41268
- jQuery(this).attr('value', pasteInputPlaceholderElement).css('color', "#999");
41269
  }
41270
  })
41271
  .keyup(function () {
@@ -41286,7 +41292,7 @@ webpackJsonp([0],[
41286
  // delay loading indicator for 10ms or else it's just too fast :)
41287
  MailPoet.Modal.loading(true);
41288
  setTimeout(function () {
41289
- Papa.parse(pasteInputElement.val(), parseCSV());
41290
  }, 10);
41291
  });
41292
 
@@ -41313,7 +41319,7 @@ webpackJsonp([0],[
41313
  MailPoet.Modal.loading(true);
41314
  setTimeout(function () {
41315
  uploadElement.parse({
41316
- config: parseCSV()
41317
  })
41318
  }, 10);
41319
  }
@@ -41383,6 +41389,10 @@ webpackJsonp([0],[
41383
  MailPoet.Modal.loading(false);
41384
  }).done(function(response) {
41385
  importData.step1 = response.data;
 
 
 
 
41386
  router.navigate('step2', {trigger: true});
41387
  }).fail(function(response) {
41388
  if (response.errors.length > 0) {
@@ -41434,7 +41444,7 @@ webpackJsonp([0],[
41434
  element.closest('table a').addClass(disabled);
41435
  }
41436
 
41437
- function parseCSV() {
41438
  var processedSubscribers = [],
41439
  parsedEmails = [],
41440
  duplicateEmails = [],
@@ -41523,7 +41533,7 @@ webpackJsonp([0],[
41523
  processedSubscribers[0] = rowData;
41524
  }
41525
  }
41526
- else if (rowData[emailColumnPosition] !== "") {
41527
  var email = detectAndCleanupEmail(rowData[emailColumnPosition]);
41528
  if (_.has(parsedEmails, email)) {
41529
  duplicateEmails.push(email);
@@ -41552,14 +41562,18 @@ webpackJsonp([0],[
41552
  // since we assume that the header line is always present, we need
41553
  // to detect the header by checking if it contains a valid e-mail address
41554
  importData.step1 = {
41555
- 'header': (!emailRegex.test(
41556
  processedSubscribers[0][emailColumnPosition])
41557
  ) ? processedSubscribers.shift() : null,
41558
- 'subscribers': processedSubscribers,
41559
- 'subscribersCount': processedSubscribers.length,
41560
- 'duplicate': duplicateEmails,
41561
- 'invalid': invalidEmails
41562
  };
 
 
 
 
41563
  router.navigate('step2', {trigger: true});
41564
  }
41565
  else {
@@ -41657,7 +41671,7 @@ webpackJsonp([0],[
41657
  var details = jQuery('.mailpoet_subscribers_data_parse_results_details');
41658
  jQuery(details).toggle();
41659
  this.text =
41660
- (jQuery(details).is(":visible"))
41661
  ? MailPoet.I18n.t('hideDetails')
41662
  : MailPoet.I18n.t('showDetails');
41663
  });
@@ -41737,9 +41751,9 @@ webpackJsonp([0],[
41737
  }
41738
  }).done(function(response) {
41739
  mailpoetSegments.push({
41740
- 'id': response.data.id,
41741
- 'name': response.data.name,
41742
- 'subscriberCount': 0
41743
  });
41744
 
41745
  var selected_values = segmentSelectElement.val();
@@ -41771,7 +41785,7 @@ webpackJsonp([0],[
41771
 
41772
  // register partial template that will contain subscribers data
41773
  Handlebars.registerPartial(
41774
- "subscribers_data_template_partial",
41775
  subscribersDataTemplatePartial
41776
  );
41777
 
@@ -41815,7 +41829,7 @@ webpackJsonp([0],[
41815
  && displayedColumnsIds.indexOf(columnId) === -1)
41816
  ? columnId
41817
  : 'ignore';
41818
- displayedColumns[i] = {'column_id': columnId};
41819
  displayedColumnsIds.push(columnId);
41820
  }
41821
  return options.fn(displayedColumns);
@@ -41892,17 +41906,17 @@ webpackJsonp([0],[
41892
  data: data
41893
  }).done(function(response) {
41894
  var new_column_data = {
41895
- 'id': response.data.id,
41896
- 'name': response.data.name,
41897
- 'type': response.data.type,
41898
- 'params': response.data.params,
41899
- 'custom': true
41900
  };
41901
  // if this is the first custom column, create an "optgroup"
41902
  if (mailpoetColumnsSelect2.length === 2) {
41903
  mailpoetColumnsSelect2.push({
41904
- 'name': MailPoet.I18n.t('userColumns'),
41905
- 'children': []
41906
  });
41907
  }
41908
  mailpoetColumnsSelect2[2].children.push(new_column_data);
@@ -42119,10 +42133,10 @@ webpackJsonp([0],[
42119
  timestamp = Date.now() / 1000,
42120
  subscribers = [],
42121
  importResults = {
42122
- 'created': 0,
42123
- 'updated': 0,
42124
- 'errors': [],
42125
- 'segments': []
42126
  },
42127
  splitSubscribers = function (subscribers, size) {
42128
  return subscribers.reduce(function (res, item, index) {
@@ -42215,6 +42229,12 @@ webpackJsonp([0],[
42215
  MailPoet.Notice.error(_.flatten(importData.step2.errors));
42216
  }
42217
 
 
 
 
 
 
 
42218
  // display statistics
42219
  var subscribersDataImportResultsTemplate =
42220
  Handlebars
@@ -42265,6 +42285,7 @@ webpackJsonp([0],[
42265
  });
42266
  }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
42267
 
 
42268
  /***/ },
42269
  /* 543 */,
42270
  /* 544 */
@@ -42379,7 +42400,7 @@ webpackJsonp([0],[
42379
  Handlebars,
42380
  select2
42381
  ) {
42382
- if (!jQuery("#mailpoet_subscribers_export").length) {
42383
  return;
42384
  }
42385
  jQuery(document).ready(function () {
@@ -42393,11 +42414,11 @@ webpackJsonp([0],[
42393
  jQuery('#mailpoet_subscribers_export > div.inside').html(subscribers_export_template(exportData));
42394
 
42395
  // define reusable variables
42396
- var segmentsContainerElement = jQuery("#export_lists"),
42397
- subscriberFieldsContainerElement = jQuery("#export_columns"),
42398
  exportConfirmedOptionElement = jQuery(':radio[name="option_confirmed"]'),
42399
  groupBySegmentOptionElement = jQuery(':checkbox[name="option_group_by_list"]'),
42400
- nextStepButton = jQuery("a.mailpoet_export_process"),
42401
  renderSegmentsAndFields = function (container, data) {
42402
  if (container.data('select2')) {
42403
  container
@@ -42473,7 +42494,7 @@ webpackJsonp([0],[
42473
  'first_name',
42474
  'last_name',
42475
  'status'
42476
- ]).trigger("change");
42477
 
42478
  exportConfirmedOptionElement.change(function () {
42479
  var selectedSegments = segmentsContainerElement.val();
@@ -42503,16 +42524,17 @@ webpackJsonp([0],[
42503
  return;
42504
  }
42505
  MailPoet.Modal.loading(true);
 
42506
  MailPoet.Ajax.post({
42507
  api_version: window.mailpoet_api_version,
42508
  endpoint: 'ImportExport',
42509
  action: 'processExport',
42510
  data: JSON.stringify({
42511
- 'export_confirmed_option': exportData.exportConfirmedOption,
42512
- 'export_format_option': jQuery(':radio[name="option_format"]:checked').val(),
42513
- 'group_by_segment_option': (groupBySegmentOptionElement.is(":visible")) ? groupBySegmentOptionElement.prop('checked') : false,
42514
- 'segments': (exportData.segments) ? segmentsContainerElement.val() : false,
42515
- 'subscriber_fields': subscriberFieldsContainerElement.val()
42516
  })
42517
  }).always(function(response) {
42518
  MailPoet.Modal.loading(false);
@@ -42523,6 +42545,12 @@ webpackJsonp([0],[
42523
  .replace('[/link]', '</a>');
42524
  jQuery('#export_result_notice').html('<p>' + resultMessage + '</p>').show();
42525
  window.location.href = response.data.exportFileURL;
 
 
 
 
 
 
42526
  }).fail(function(response) {
42527
  if (response.errors.length > 0) {
42528
  MailPoet.Notice.error(
9171
  label: MailPoet.I18n.t('status'),
9172
  type: 'select',
9173
  values: {
9174
+ subscribed: MailPoet.I18n.t('subscribed'),
9175
+ unconfirmed: MailPoet.I18n.t('unconfirmed'),
9176
+ unsubscribed: MailPoet.I18n.t('unsubscribed'),
9177
+ bounced: MailPoet.I18n.t('bounced')
9178
  },
9179
  filter: function filter(subscriber, value) {
9180
  if (~ ~subscriber.wp_user_id > 0 && value === 'unconfirmed') {
9263
  },
9264
  onCreate: function onCreate() {
9265
  MailPoet.Notice.success(MailPoet.I18n.t('subscriberAdded'));
9266
+ MailPoet.trackEvent('Subscribers > Add new', {
9267
+ 'MailPoet Free version': window.mailpoet_version
9268
+ });
9269
  }
9270
  };
9271
 
9502
  });
9503
  }
9504
 
9505
+ var formClasses = classNames('mailpoet_form', { mailpoet_form_loading: this.state.loading || this.props.loading });
9506
 
9507
  var beforeFormContent = false;
9508
  var afterFormContent = false;
10055
  switch (dateType) {
10056
  case 'year_month_day':
10057
  value = {
10058
+ year: this.state.year,
10059
+ month: this.state.month,
10060
+ day: this.state.day
10061
  };
10062
  break;
10063
 
10064
  case 'year_month':
10065
  value = {
10066
+ year: this.state.year,
10067
+ month: this.state.month
10068
  };
10069
  break;
10070
 
10071
  case 'month':
10072
  value = {
10073
+ month: this.state.month
10074
  };
10075
  break;
10076
 
10077
  case 'year':
10078
  value = {
10079
+ year: this.state.year
10080
  };
10081
  break;
10082
  }
26133
  },
26134
  render: function render() {
26135
  var types = [{
26136
+ id: 'standard',
26137
+ title: MailPoet.I18n.t('regularNewsletterTypeTitle'),
26138
+ description: MailPoet.I18n.t('regularNewsletterTypeDescription'),
26139
+ action: (function () {
26140
  return React.createElement(
26141
  'a',
26142
  { className: 'button button-primary', onClick: this.createNewsletter.bind(null, 'standard') },
26144
  );
26145
  }).bind(this)()
26146
  }, {
26147
+ id: 'welcome',
26148
+ title: MailPoet.I18n.t('welcomeNewsletterTypeTitle'),
26149
+ description: MailPoet.I18n.t('welcomeNewsletterTypeDescription'),
26150
+ action: (function () {
26151
  return React.createElement(
26152
  'div',
26153
  null,
26159
  );
26160
  })()
26161
  }, {
26162
+ id: 'notification',
26163
+ title: MailPoet.I18n.t('postNotificationNewsletterTypeTitle'),
26164
+ description: MailPoet.I18n.t('postNotificationNewsletterTypeDescription'),
26165
+ action: (function () {
26166
  return React.createElement(
26167
  'a',
26168
  { className: 'button button-primary', onClick: this.setupNewsletter.bind(null, 'notification') },
26350
  response.data = [{
26351
  name: MailPoet.I18n.t('mailpoetGuideTemplateTitle'),
26352
  description: MailPoet.I18n.t('mailpoetGuideTemplateDescription'),
26353
+ readonly: '1'
26354
  }];
26355
  }
26356
  _this2.setState({
26402
  var _this3 = this;
26403
 
26404
  this.setState({ loading: true });
26405
+ if (window.confirm(MailPoet.I18n.t('confirmTemplateDeletion').replace('%$1s', template.name))) {
26406
  MailPoet.Ajax.post({
26407
  api_version: window.mailpoet_api_version,
26408
  endpoint: 'newsletterTemplates',
26503
  MailPoet.I18n.t('select')
26504
  )
26505
  ),
26506
+ template.readonly === '1' ? false : deleteLink
26507
  );
26508
  });
26509
 
26510
+ var boxClasses = classNames('mailpoet_boxes', 'clearfix', { mailpoet_boxes_loading: this.state.loading });
26511
 
26512
  return React.createElement(
26513
  'div',
26555
  var tooltipId = props.tooltipId;
26556
  var tooltip = props.tooltip;
26557
  // tooltip ID must be unique, defaults to tooltip text
26558
+ if (!props.tooltipId && typeof props.tooltip === 'string') {
26559
  tooltipId = props.tooltip;
26560
  }
26561
 
26562
+ if (typeof props.tooltip === 'string') {
26563
  tooltip = _react2['default'].createElement(
26564
  'span',
26565
  {
26566
  style: {
26567
+ pointerEvents: 'all',
26568
+ maxWidth: '400',
26569
+ display: 'inline-block'
26570
  }
26571
  },
26572
  (0, _reactHtmlParser2['default'])(props.tooltip)
26578
  { className: props.className },
26579
  _react2['default'].createElement('span', {
26580
  style: {
26581
+ cursor: 'pointer'
26582
  },
26583
  className: 'tooltip dashicons dashicons-editor-help',
26584
  'data-event': 'click',
35366
  MailPoet.trackEvent('Emails > Welcome email activated', {
35367
  'MailPoet Free version': window.mailpoet_version,
35368
  'List type': opts.event,
35369
+ Delay: opts.afterTimeNumber + ' ' + opts.afterTimeType
35370
  });
35371
  } else if (response.data.type === 'notification') {
35372
  MailPoet.Notice.success(MailPoet.I18n.t('postNotificationActivated'));
35373
  MailPoet.trackEvent('Emails > Post notifications activated', {
35374
  'MailPoet Free version': window.mailpoet_version,
35375
+ Frequency: opts.intervalType
35376
  });
35377
  }
35378
  }).fail(_this2._showError);
35715
  var DateTime = React.createClass({
35716
  displayName: 'DateTime',
35717
 
35718
+ _DATE_TIME_SEPARATOR: ' ',
35719
  getInitialState: function getInitialState() {
35720
  return this._buildStateFromProps(this.props);
35721
  },
36852
  _mailpoet2['default'].Date.format(newsletter.queue.scheduled_at)
36853
  );
36854
  }
36855
+ var progressClasses = (0, _classnames2['default'])('mailpoet_progress', { mailpoet_progress_complete: newsletter.queue.status === 'completed' });
36856
 
36857
  // calculate percentage done
36858
  var percentage = Math.round(newsletter.queue.count_processed * 100 / newsletter.queue.count_total);
36863
  label = _react2['default'].createElement(
36864
  'span',
36865
  null,
36866
+ _mailpoet2['default'].I18n.t('newsletterQueueCompleted').replace('%$1d', newsletter.queue.count_processed).replace('%$2d', newsletter.queue.count_total)
36867
  );
36868
  } else {
36869
  label = _react2['default'].createElement(
36904
  percentage = _mailpoet2['default'].I18n.t('noSubscribers');
36905
  } else {
36906
  progress_bar_width = percentage;
36907
+ percentage += '%';
36908
  }
36909
 
36910
  return _react2['default'].createElement(
36915
  { className: progressClasses },
36916
  _react2['default'].createElement('span', {
36917
  className: 'mailpoet_progress_bar',
36918
+ style: { width: progress_bar_width + '%' }
36919
  }),
36920
  _react2['default'].createElement(
36921
  'span',
37051
  { className: 'mailpoet_stats_text' },
37052
  percentage_opened_display,
37053
  '%,',
37054
+ ' ',
37055
  percentage_clicked_display,
37056
  '%',
37057
  _react2['default'].createElement(
37135
  var mailer_check_settings_notice = (0, _reactStringReplace2['default'])(_mailpoet2['default'].I18n.t('mailerCheckSettingsNotice'), /\[link\](.*?)\[\/link\]/g, function (match) {
37136
  return _react2['default'].createElement(
37137
  'a',
37138
+ { href: '?page=mailpoet-settings#mta', key: 'check-sending' },
37139
  match
37140
  );
37141
  });
38456
  },
38457
  onCreate: function onCreate() {
38458
  MailPoet.Notice.success(MailPoet.I18n.t('segmentAdded'));
38459
+ MailPoet.trackEvent('Lists > Add new', {
38460
+ 'MailPoet Free version': window.mailpoet_version
38461
+ });
38462
  }
38463
  };
38464
 
41024
  };
41025
 
41026
  Tabs.propTypes = { tab: _react2['default'].PropTypes.string };
41027
+ Tabs.defaultProps = { tab: 'knowledgeBase' };
41028
 
41029
  module.exports = Tabs;
41030
 
41065
  return _react2['default'].createElement('textarea', {
41066
  readOnly: true,
41067
  onFocus: handleFocus,
41068
+ value: printableData.join('\n'),
41069
  style: {
41070
+ width: '100%',
41071
+ height: '400px'
41072
  }
41073
  });
41074
  } else {
41088
  _react2['default'].createElement(_tabsJsx2['default'], { tab: 'systemInfo' }),
41089
  _react2['default'].createElement(
41090
  'div',
41091
+ { className: 'mailpoet_notice notice inline notice-success', style: { marginTop: '1em' } },
41092
  _react2['default'].createElement(
41093
  'p',
41094
  null,
41120
 
41121
  MailPoet.Modal.loading(true);
41122
  MailPoet.Ajax.post({
41123
+ api_version: window.mailpoet_api_version,
41124
+ endpoint: 'setup',
41125
+ action: 'reset'
41126
  }).always(function () {
41127
  MailPoet.Modal.loading(false);
41128
  }).done(function () {
41181
  router = new (Backbone.Router.extend({
41182
  routes: {
41183
  '': 'home',
41184
+ step1: 'step1',
41185
+ step2: 'step2',
41186
+ step3: 'step3'
41187
  },
41188
  home: function () {
41189
  this.navigate('step1', {trigger: true});
41263
  * Paste
41264
  */
41265
  pasteInputElement
41266
+ .attr('value', pasteInputPlaceholderElement).css('color', '#999')
41267
  .focus(function () {
41268
  if (jQuery(this).val() === pasteInputPlaceholderElement) {
41269
  jQuery(this).attr('value', '').css('color', '#222');
41271
  })
41272
  .blur(function () {
41273
  if (jQuery(this).val() === '') {
41274
+ jQuery(this).attr('value', pasteInputPlaceholderElement).css('color', '#999');
41275
  }
41276
  })
41277
  .keyup(function () {
41292
  // delay loading indicator for 10ms or else it's just too fast :)
41293
  MailPoet.Modal.loading(true);
41294
  setTimeout(function () {
41295
+ Papa.parse(pasteInputElement.val(), parseCSV(false));
41296
  }, 10);
41297
  });
41298
 
41319
  MailPoet.Modal.loading(true);
41320
  setTimeout(function () {
41321
  uploadElement.parse({
41322
+ config: parseCSV(true)
41323
  })
41324
  }, 10);
41325
  }
41389
  MailPoet.Modal.loading(false);
41390
  }).done(function(response) {
41391
  importData.step1 = response.data;
41392
+ MailPoet.trackEvent('Subscribers import started', {
41393
+ source: 'MailChimp',
41394
+ 'MailPoet Free version': window.mailpoet_version
41395
+ });
41396
  router.navigate('step2', {trigger: true});
41397
  }).fail(function(response) {
41398
  if (response.errors.length > 0) {
41444
  element.closest('table a').addClass(disabled);
41445
  }
41446
 
41447
+ function parseCSV(isFile) {
41448
  var processedSubscribers = [],
41449
  parsedEmails = [],
41450
  duplicateEmails = [],
41533
  processedSubscribers[0] = rowData;
41534
  }
41535
  }
41536
+ else if (rowData[emailColumnPosition] !== '') {
41537
  var email = detectAndCleanupEmail(rowData[emailColumnPosition]);
41538
  if (_.has(parsedEmails, email)) {
41539
  duplicateEmails.push(email);
41562
  // since we assume that the header line is always present, we need
41563
  // to detect the header by checking if it contains a valid e-mail address
41564
  importData.step1 = {
41565
+ header: (!emailRegex.test(
41566
  processedSubscribers[0][emailColumnPosition])
41567
  ) ? processedSubscribers.shift() : null,
41568
+ subscribers: processedSubscribers,
41569
+ subscribersCount: processedSubscribers.length,
41570
+ duplicate: duplicateEmails,
41571
+ invalid: invalidEmails
41572
  };
41573
+ MailPoet.trackEvent('Subscribers import started', {
41574
+ source: isFile ? 'file upload' : 'pasted data',
41575
+ 'MailPoet Free version': window.mailpoet_version
41576
+ });
41577
  router.navigate('step2', {trigger: true});
41578
  }
41579
  else {
41671
  var details = jQuery('.mailpoet_subscribers_data_parse_results_details');
41672
  jQuery(details).toggle();
41673
  this.text =
41674
+ (jQuery(details).is(':visible'))
41675
  ? MailPoet.I18n.t('hideDetails')
41676
  : MailPoet.I18n.t('showDetails');
41677
  });
41751
  }
41752
  }).done(function(response) {
41753
  mailpoetSegments.push({
41754
+ id: response.data.id,
41755
+ name: response.data.name,
41756
+ subscriberCount: 0
41757
  });
41758
 
41759
  var selected_values = segmentSelectElement.val();
41785
 
41786
  // register partial template that will contain subscribers data
41787
  Handlebars.registerPartial(
41788
+ 'subscribers_data_template_partial',
41789
  subscribersDataTemplatePartial
41790
  );
41791
 
41829
  && displayedColumnsIds.indexOf(columnId) === -1)
41830
  ? columnId
41831
  : 'ignore';
41832
+ displayedColumns[i] = {column_id: columnId};
41833
  displayedColumnsIds.push(columnId);
41834
  }
41835
  return options.fn(displayedColumns);
41906
  data: data
41907
  }).done(function(response) {
41908
  var new_column_data = {
41909
+ id: response.data.id,
41910
+ name: response.data.name,
41911
+ type: response.data.type,
41912
+ params: response.data.params,
41913
+ custom: true
41914
  };
41915
  // if this is the first custom column, create an "optgroup"
41916
  if (mailpoetColumnsSelect2.length === 2) {
41917
  mailpoetColumnsSelect2.push({
41918
+ name: MailPoet.I18n.t('userColumns'),
41919
+ children: []
41920
  });
41921
  }
41922
  mailpoetColumnsSelect2[2].children.push(new_column_data);
42133
  timestamp = Date.now() / 1000,
42134
  subscribers = [],
42135
  importResults = {
42136
+ created: 0,
42137
+ updated: 0,
42138
+ errors: [],
42139
+ segments: []
42140
  },
42141
  splitSubscribers = function (subscribers, size) {
42142
  return subscribers.reduce(function (res, item, index) {
42229
  MailPoet.Notice.error(_.flatten(importData.step2.errors));
42230
  }
42231
 
42232
+ MailPoet.trackEvent('Subscribers import finished', {
42233
+ 'Subscribers created': importData.step2.created,
42234
+ 'Subscribers updated': importData.step2.updated,
42235
+ 'MailPoet Free version': window.mailpoet_version
42236
+ });
42237
+
42238
  // display statistics
42239
  var subscribersDataImportResultsTemplate =
42240
  Handlebars
42285
  });
42286
  }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
42287
 
42288
+
42289
  /***/ },
42290
  /* 543 */,
42291
  /* 544 */
42400
  Handlebars,
42401
  select2
42402
  ) {
42403
+ if (!jQuery('#mailpoet_subscribers_export').length) {
42404
  return;
42405
  }
42406
  jQuery(document).ready(function () {
42414
  jQuery('#mailpoet_subscribers_export > div.inside').html(subscribers_export_template(exportData));
42415
 
42416
  // define reusable variables
42417
+ var segmentsContainerElement = jQuery('#export_lists'),
42418
+ subscriberFieldsContainerElement = jQuery('#export_columns'),
42419
  exportConfirmedOptionElement = jQuery(':radio[name="option_confirmed"]'),
42420
  groupBySegmentOptionElement = jQuery(':checkbox[name="option_group_by_list"]'),
42421
+ nextStepButton = jQuery('a.mailpoet_export_process'),
42422
  renderSegmentsAndFields = function (container, data) {
42423
  if (container.data('select2')) {
42424
  container
42494
  'first_name',
42495
  'last_name',
42496
  'status'
42497
+ ]).trigger('change');
42498
 
42499
  exportConfirmedOptionElement.change(function () {
42500
  var selectedSegments = segmentsContainerElement.val();
42524
  return;
42525
  }
42526
  MailPoet.Modal.loading(true);
42527
+ var exportFormat = jQuery(':radio[name="option_format"]:checked').val();
42528
  MailPoet.Ajax.post({
42529
  api_version: window.mailpoet_api_version,
42530
  endpoint: 'ImportExport',
42531
  action: 'processExport',
42532
  data: JSON.stringify({
42533
+ export_confirmed_option: exportData.exportConfirmedOption,
42534
+ export_format_option: exportFormat,
42535
+ group_by_segment_option: (groupBySegmentOptionElement.is(':visible')) ? groupBySegmentOptionElement.prop('checked') : false,
42536
+ segments: (exportData.segments) ? segmentsContainerElement.val() : false,
42537
+ subscriber_fields: subscriberFieldsContainerElement.val()
42538
  })
42539
  }).always(function(response) {
42540
  MailPoet.Modal.loading(false);
42545
  .replace('[/link]', '</a>');
42546
  jQuery('#export_result_notice').html('<p>' + resultMessage + '</p>').show();
42547
  window.location.href = response.data.exportFileURL;
42548
+ MailPoet.trackEvent('Subscribers export completed', {
42549
+ 'Total exported': response.data.totalExported,
42550
+ 'Only confirmed?': exportData.exportConfirmedOption,
42551
+ 'File Format': exportFormat,
42552
+ 'MailPoet Free version': window.mailpoet_version
42553
+ });
42554
  }).fail(function(response) {
42555
  if (response.errors.length > 0) {
42556
  MailPoet.Notice.error(
assets/js/{admin_vendor.aaf3acee.js → admin_vendor.71d84e79.js} RENAMED
@@ -28520,7 +28520,7 @@ webpackJsonp([1],[
28520
  )
28521
  );
28522
  } else {
28523
- var select_all_classes = (0, _classnames2['default'])('mailpoet_select_all', { 'mailpoet_hidden': this.props.selection === false || this.props.count <= this.props.limit
28524
  });
28525
 
28526
  return _react2['default'].createElement(
@@ -29066,7 +29066,7 @@ webpackJsonp([1],[
29066
  // item actions
29067
  var item_actions = this.props.item_actions || [];
29068
 
29069
- var table_classes = (0, _classnames2['default'])('mailpoet_listing_table', 'wp-list-table', 'widefat', 'fixed', 'striped', { 'mailpoet_listing_loading': this.state.loading });
29070
 
29071
  // search
29072
  var search = _react2['default'].createElement(_listingSearchJsx2['default'], {
@@ -30959,7 +30959,7 @@ webpackJsonp([1],[
30959
  this.props.onSort(sort_by, sort_order);
30960
  },
30961
  render: function render() {
30962
- var classes = (0, _classnames2['default'])('manage-column', { 'column-primary': this.props.column.is_primary }, { 'sortable': this.props.column.sortable }, this.props.column.sorted, { 'sorted': this.props.sort_by === this.props.column.name });
30963
  var label = undefined;
30964
 
30965
  if (this.props.column.sortable === true) {
@@ -31299,7 +31299,7 @@ webpackJsonp([1],[
31299
  return false;
31300
  }
31301
 
31302
- var classes = classNames({ 'current': group.name === _this.props.group });
31303
 
31304
  return React.createElement(
31305
  'li',
@@ -32586,7 +32586,7 @@ webpackJsonp([1],[
32586
  var _this = this;
32587
 
32588
  var steps = this.state.steps.map(function (step, index) {
32589
- var stepClasses = classNames({ 'mailpoet_current': _this.props.step === step.name });
32590
 
32591
  var label = step.label;
32592
 
@@ -34106,18 +34106,18 @@ webpackJsonp([1],[
34106
 
34107
  // welcome emails
34108
  var _timeDelayValues = {
34109
- 'immediate': _mailpoet2['default'].I18n.t('delayImmediately'),
34110
- 'hours': _mailpoet2['default'].I18n.t('delayHoursAfter'),
34111
- 'days': _mailpoet2['default'].I18n.t('delayDaysAfter'),
34112
- 'weeks': _mailpoet2['default'].I18n.t('delayWeeksAfter')
34113
  };
34114
 
34115
  var _intervalValues = {
34116
- 'daily': _mailpoet2['default'].I18n.t('daily'),
34117
- 'weekly': _mailpoet2['default'].I18n.t('weekly'),
34118
- 'monthly': _mailpoet2['default'].I18n.t('monthly'),
34119
- 'nthWeekDay': _mailpoet2['default'].I18n.t('monthlyEvery'),
34120
- 'immediately': _mailpoet2['default'].I18n.t('immediately')
34121
  };
34122
 
34123
  // notification emails
@@ -34157,16 +34157,16 @@ webpackJsonp([1],[
34157
  if (labels[day] !== undefined) {
34158
  label = labels[day];
34159
  } else {
34160
- label = _mailpoet2['default'].I18n.t('nth').replace("%$1d", day + 1);
34161
  }
34162
  return [day + 1, label];
34163
  }));
34164
 
34165
  var _nthWeekDayValues = {
34166
- '1': _mailpoet2['default'].I18n.t('first'),
34167
- '2': _mailpoet2['default'].I18n.t('second'),
34168
- '3': _mailpoet2['default'].I18n.t('third'),
34169
- 'L': _mailpoet2['default'].I18n.t('last')
34170
  };
34171
 
34172
  exports.timeDelayValues = _timeDelayValues;
@@ -34225,8 +34225,8 @@ webpackJsonp([1],[
34225
  var events = {
34226
  name: 'event',
34227
  values: {
34228
- 'segment': _mailpoet2['default'].I18n.t('onSubscriptionToList'),
34229
- 'user': _mailpoet2['default'].I18n.t('onWPUserRegistration')
34230
  }
34231
  };
34232
 
28520
  )
28521
  );
28522
  } else {
28523
+ var select_all_classes = (0, _classnames2['default'])('mailpoet_select_all', { mailpoet_hidden: this.props.selection === false || this.props.count <= this.props.limit
28524
  });
28525
 
28526
  return _react2['default'].createElement(
29066
  // item actions
29067
  var item_actions = this.props.item_actions || [];
29068
 
29069
+ var table_classes = (0, _classnames2['default'])('mailpoet_listing_table', 'wp-list-table', 'widefat', 'fixed', 'striped', { mailpoet_listing_loading: this.state.loading });
29070
 
29071
  // search
29072
  var search = _react2['default'].createElement(_listingSearchJsx2['default'], {
30959
  this.props.onSort(sort_by, sort_order);
30960
  },
30961
  render: function render() {
30962
+ var classes = (0, _classnames2['default'])('manage-column', { 'column-primary': this.props.column.is_primary }, { sortable: this.props.column.sortable }, this.props.column.sorted, { sorted: this.props.sort_by === this.props.column.name });
30963
  var label = undefined;
30964
 
30965
  if (this.props.column.sortable === true) {
31299
  return false;
31300
  }
31301
 
31302
+ var classes = classNames({ current: group.name === _this.props.group });
31303
 
31304
  return React.createElement(
31305
  'li',
32586
  var _this = this;
32587
 
32588
  var steps = this.state.steps.map(function (step, index) {
32589
+ var stepClasses = classNames({ mailpoet_current: _this.props.step === step.name });
32590
 
32591
  var label = step.label;
32592
 
34106
 
34107
  // welcome emails
34108
  var _timeDelayValues = {
34109
+ immediate: _mailpoet2['default'].I18n.t('delayImmediately'),
34110
+ hours: _mailpoet2['default'].I18n.t('delayHoursAfter'),
34111
+ days: _mailpoet2['default'].I18n.t('delayDaysAfter'),
34112
+ weeks: _mailpoet2['default'].I18n.t('delayWeeksAfter')
34113
  };
34114
 
34115
  var _intervalValues = {
34116
+ daily: _mailpoet2['default'].I18n.t('daily'),
34117
+ weekly: _mailpoet2['default'].I18n.t('weekly'),
34118
+ monthly: _mailpoet2['default'].I18n.t('monthly'),
34119
+ nthWeekDay: _mailpoet2['default'].I18n.t('monthlyEvery'),
34120
+ immediately: _mailpoet2['default'].I18n.t('immediately')
34121
  };
34122
 
34123
  // notification emails
34157
  if (labels[day] !== undefined) {
34158
  label = labels[day];
34159
  } else {
34160
+ label = _mailpoet2['default'].I18n.t('nth').replace('%$1d', day + 1);
34161
  }
34162
  return [day + 1, label];
34163
  }));
34164
 
34165
  var _nthWeekDayValues = {
34166
+ 1: _mailpoet2['default'].I18n.t('first'),
34167
+ 2: _mailpoet2['default'].I18n.t('second'),
34168
+ 3: _mailpoet2['default'].I18n.t('third'),
34169
+ L: _mailpoet2['default'].I18n.t('last')
34170
  };
34171
 
34172
  exports.timeDelayValues = _timeDelayValues;
34225
  var events = {
34226
  name: 'event',
34227
  values: {
34228
+ segment: _mailpoet2['default'].I18n.t('onSubscriptionToList'),
34229
+ user: _mailpoet2['default'].I18n.t('onWPUserRegistration')
34230
  }
34231
  };
34232
 
assets/js/{form_editor.4d117b35.js → form_editor.92c760ec.js} RENAMED
@@ -21,1075 +21,1075 @@ webpackJsonp([2],{
21
  /***/ 549:
22
  /***/ function(module, exports) {
23
 
24
- /*
25
- * name: MailPoet Form Editor
26
- * author: Jonathan Labreuille
27
- * company: Wysija
28
- * framework: prototype 1.7.2
29
- */
30
- 'use strict';
31
-
32
- Event.cacheDelegated = {};
33
- Object.extend(document, (function() {
34
- var cache = Event.cacheDelegated;
35
-
36
- function getCacheForSelector(selector) {
37
- cache[selector] = cache[selector] || {};
38
- return cache[selector];
39
- }
40
-
41
- function getWrappersForSelector(selector, eventName) {
42
- var c = getCacheForSelector(selector);
43
- c[eventName] = c[eventName] || [];
44
- return c[eventName];
45
- }
46
-
47
- function findWrapper(selector, eventName, handler) {
48
- var c = getWrappersForSelector(selector, eventName);
49
- return c.find(function(wrapper) {
50
- return wrapper.handler === handler
51
- });
52
- }
53
-
54
- function destroyWrapper(selector, eventName, handler) {
55
- var c = getCacheForSelector(selector);
56
- if(!c[eventName]) return false;
57
- var wrapper = findWrapper(selector, eventName, handler)
58
- c[eventName] = c[eventName].without(wrapper);
59
- return wrapper;
60
- }
61
-
62
- function createWrapper(selector, eventName, handler, context) {
63
- var wrapper, c = getWrappersForSelector(selector, eventName);
64
- if(c.pluck('handler').include(handler)) return false;
65
- wrapper = function(event) {
66
- var element = event.findElement(selector);
67
- if(element) handler.call(context || element, event, element);
68
- };
69
- wrapper.handler = handler;
70
- c.push(wrapper);
71
- return wrapper;
72
- }
73
- return {
74
- delegate: function(selector, eventName, handler, context) {
75
- var wrapper = createWrapper.apply(null, arguments);
76
- if(wrapper) document.observe(eventName, wrapper);
77
- return document;
78
- },
79
- stopDelegating: function(selector, eventName, handler) {
80
- var length = arguments.length;
81
- switch(length) {
82
- case 2:
83
- getWrappersForSelector(selector, eventName).each(function(wrapper) {
84
- document.stopDelegating(selector, eventName, wrapper.handler);
85
- });
86
- break;
87
- case 1:
88
- Object.keys(getCacheForSelector(selector)).each(function(eventName) {
89
- document.stopDelegating(selector, eventName);
90
- });
91
- break;
92
- case 0:
93
- Object.keys(cache).each(function(selector) {
94
- document.stopDelegating(selector);
95
- });
96
- break;
97
- default:
98
- var wrapper = destroyWrapper.apply(null, arguments);
99
- if(wrapper) document.stopObserving(eventName, wrapper);
100
- }
101
- return document;
102
- }
103
- }
104
- })());
105
-
106
- var Observable = (function() {
107
- function getEventName(nameA, namespace) {
108
- var name = nameA.substring(2);
109
- if(namespace) name = namespace + ':' + name;
110
- return name.underscore().split('_').join(':');
111
- }
112
-
113
- function getHandlers(klass) {
114
- var proto = klass.prototype,
115
- namespace = proto.namespace;
116
- return Object.keys(proto).grep(/^on/).inject($H(), function(handlers, name) {
117
- if(name === 'onDomLoaded') return handlers;
118
- handlers.set(getEventName(name, namespace), getWrapper(proto[name], klass));
119
- return handlers;
120
- });
121
- }
122
-
123
- function getWrapper(handler, klass) {
124
- return function(event) {
125
- return handler.call(new klass(this), event, event.memo);
126
- }
127
- }
128
-
129
- function onDomLoad(selector, klass) {
130
- $$(selector).each(function(element) {
131
- new klass(element).onDomLoaded();
132
- });
133
- }
134
- return {
135
- observe: function(selector) {
136
- if(!this.handlers) this.handlers = {};
137
- if(this.handlers[selector]) return;
138
- var klass = this;
139
- if(this.prototype.onDomLoaded) document.loaded ? onDomLoad(selector, klass) : document.observe('dom:loaded', onDomLoad.curry(selector, klass));
140
- this.handlers[selector] = getHandlers(klass).each(function(handler) {
141
- document.delegate(selector, handler.key, handler.value);
142
- });
143
- },
144
- stopObserving: function(selector) {
145
- if(!this.handlers || !this.handlers[selector]) return;
146
- this.handlers[selector].each(function(handler) {
147
- document.stopDelegating(selector, handler.key, handler.value);
148
- });
149
- delete this.handlers[selector];
150
- }
151
- }
152
- })();
153
-
154
- // override droppables
155
- Object.extend(Droppables, {
156
- deactivate: Droppables.deactivate.wrap(function(proceed, drop, draggable) {
157
- if(drop.onLeave) drop.onLeave(draggable, drop.element);
158
- return proceed(drop);
159
- }),
160
- activate: Droppables.activate.wrap(function(proceed, drop, draggable) {
161
- if(drop.onEnter) drop.onEnter(draggable, drop.element);
162
- return proceed(drop);
163
- }),
164
- show: function(point, element) {
165
- if(!this.drops.length) return;
166
- var drop, affected = [];
167
- this.drops.each(function(drop) {
168
- if(Droppables.isAffected(point, element, drop)) affected.push(drop);
169
- });
170
- if(affected.length > 0) drop = Droppables.findDeepestChild(affected);
171
- if(this.last_active && this.last_active !== drop) this.deactivate(this.last_active, element);
172
- if(drop) {
173
- Position.within(drop.element, point[0], point[1]);
174
- if(drop.onHover) drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
175
- if(drop !== this.last_active) Droppables.activate(drop, element);
176
- }
177
- },
178
- displayArea: function(draggable) {
179
- if(!this.drops.length) return;
180
-
181
- // hide controls when displaying drop areas.
182
- WysijaForm.hideBlockControls();
183
-
184
- this.drops.each(function(drop, iterator) {
185
- if(drop.element.hasClassName('block_placeholder')) {
186
- drop.element.addClassName('active');
187
- }
188
- });
189
- },
190
- hideArea: function() {
191
- if(!this.drops.length) return;
192
- this.drops.each(function(drop, iterator) {
193
- if(drop.element.hasClassName('block_placeholder')) {
194
- drop.element.removeClassName('active');
195
- } else if(drop.element.hasClassName('image_placeholder')) {
196
- drop.element.removeClassName('active');
197
- drop.element.up().removeClassName('active');
198
- } else if(drop.element.hasClassName('text_placeholder')) {
199
- drop.element.removeClassName('active');
200
- }
201
- });
202
- },
203
- reset: function(draggable) {
204
- if(this.last_active) this.deactivate(this.last_active, draggable);
205
- }
206
- });
207
-
208
- /*
209
- Wysija History handling
210
- POTENTIAL FEATURES:
211
- - set a maximum number of items to be stored
212
-
213
- */
214
- var WysijaHistory = {
215
- container: 'mailpoet_form_history',
216
- size: 30,
217
- enqueue: function(element) {
218
- // create deep clone (includes child elements) of passed element
219
- var clone = element.clone(true);
220
-
221
- // check if the field is unique
222
- if(parseInt(clone.readAttribute('wysija_unique'), 10) === 1) {
223
- // check if the field is already in the queue
224
- $(WysijaHistory.container).select('[wysija_name="' + clone.readAttribute('wysija_name') + '"]').invoke('remove');
225
- }
226
-
227
- // check history size
228
- if($(WysijaHistory.container).select('> div').length >= WysijaHistory.size) {
229
- // remove oldest element (last in the list)
230
- $(WysijaHistory.container).select('> div').last().remove();
231
- }
232
-
233
- // store block in history
234
- $(WysijaHistory.container).insert({
235
- top: clone
236
- });
237
- },
238
- dequeue: function() {
239
- // pop last block off the history
240
- var block = $(WysijaHistory.container).select('div').first();
241
-
242
- if(block !== undefined) {
243
- // insert block back into the editor
244
- $(WysijaForm.options.body).insert({
245
- top: block
246
- });
247
- }
248
- },
249
- clear: function() {
250
- $(WysijaHistory.container).innerHTML = '';
251
- },
252
- remove: function(field) {
253
- $(WysijaHistory.container).select('[wysija_name="' + field + '"]').invoke('remove');
254
- }
255
- };
256
-
257
- /* MailPoet Form */
258
- var WysijaForm = {
259
- version: '0.7',
260
- options: {
261
- container: 'mailpoet_form_container',
262
- editor: 'mailpoet_form_editor',
263
- body: 'mailpoet_form_body',
264
- toolbar: 'mailpoet_form_toolbar',
265
- templates: 'wysija_widget_templates',
266
- debug: false
267
- },
268
- toolbar: {
269
- effect: null,
270
- x: null,
271
- y: null,
272
- top: null,
273
- left: null
274
- },
275
- scroll: {
276
- top: 0,
277
- left: 0
278
- },
279
- flags: {
280
- doSave: false
281
- },
282
- locks: {
283
- dragging: false,
284
- selectingColor: false,
285
- showingTools: false
286
- },
287
- encodeHtmlValue: function(str) {
288
- return str.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;');
289
- // ": fix for FileMerge because the previous line fucks up its syntax coloring
290
- },
291
- decodeHtmlValue: function(str) {
292
- return str.replace(/&amp;/g, '&').replace(/&gt;/g, '>').replace(/&lt;/g, '<').replace(/&quot;/g, '"');
293
- // ": fix for FileMerge because the previous line fucks up its syntax coloring
294
- },
295
- loading: function(is_loading) {
296
- if(is_loading) {
297
- $(WysijaForm.options.editor).addClassName('loading');
298
- $(WysijaForm.options.toolbar).addClassName('loading');
299
- } else {
300
- $(WysijaForm.options.editor).removeClassName('loading');
301
- $(WysijaForm.options.toolbar).removeClassName('loading');
302
- }
303
- },
304
- loadStatic: function(blocks) {
305
- $A(blocks).each(function(block) {
306
- // create block
307
- WysijaForm.Block.create(block, $('block_placeholder'));
308
- });
309
- },
310
- load: function(data) {
311
- if(data === undefined) return;
312
-
313
- // load body
314
- if(data.body !== undefined) {
315
- $A(data.body).each(function(block) {
316
- // create block
317
- WysijaForm.Block.create(block, $('block_placeholder'));
318
- });
319
-
320
- // load settings
321
- var settings_elements = $('mailpoet_form_settings').getElements();
322
- settings_elements.each(function(setting) {
323
- // skip lists
324
- if(setting.name === 'segments') {
325
- return true;
326
- } else if(setting.name === 'on_success') {
327
- // if the input value is equal to the one stored in the settings
328
- if(setting.value === data.settings[setting.name]) {
329
- // check selected value
330
- $(setting).checked = true;
331
- }
332
- } else if(data.settings[setting.name] !== undefined) {
333
- if(typeof data.settings[setting.name] === 'string') {
334
- setting.setValue(WysijaForm.decodeHtmlValue(data.settings[setting.name]));
335
- } else {
336
- setting.setValue(data.settings[setting.name]);
337
- }
338
- }
339
- });
340
- }
341
- },
342
- save: function() {
343
- var position = 1,
344
- data = {
345
- 'name': $F('mailpoet_form_name'),
346
- 'settings': $('mailpoet_form_settings').serialize(true),
347
- 'body': [],
348
- 'styles': (MailPoet.CodeEditor !== undefined) ? MailPoet.CodeEditor.getValue() : null
349
- };
350
- // body
351
- WysijaForm.getBlocks().each(function(b) {
352
- var block_data = (typeof(b.block['save']) === 'function') ? b.block.save() : null;
353
-
354
- if(block_data !== null) {
355
- // set block position
356
- block_data['position'] = position;
357
-
358
- // increment position
359
- position++;
360
-
361
- // add block data to body
362
- data['body'].push(block_data);
363
- }
364
- });
365
-
366
- return data;
367
- },
368
- init: function() {
369
- // set document scroll
370
- info('init -> set scroll offsets');
371
- WysijaForm.setScrollOffsets();
372
-
373
- // position toolbar
374
- info('init -> set toolbar position');
375
- WysijaForm.setToolbarPosition();
376
-
377
- // enable droppable targets
378
- info('init -> make droppable');
379
- WysijaForm.makeDroppable();
380
-
381
- // enable sortable
382
- info('init -> make sortable');
383
- WysijaForm.makeSortable();
384
-
385
- // hide controls
386
- info('init -> hide controls');
387
- WysijaForm.hideControls();
388
-
389
- // hide settings
390
- info('init -> hide settings');
391
- WysijaForm.hideSettings();
392
-
393
- // set settings buttons position
394
- info('init -> init settings');
395
- WysijaForm.setSettingsPosition();
396
-
397
- // toggle widgets
398
- info('init -> toggle widgets');
399
- WysijaForm.toggleWidgets();
400
- },
401
- getFieldData: function(element) {
402
- // get basic field data
403
- var data = {
404
- type: element.readAttribute('wysija_type'),
405
- name: element.readAttribute('wysija_name'),
406
- id: element.readAttribute('wysija_id'),
407
- unique: parseInt(element.readAttribute('wysija_unique') || 0, 10),
408
- static: parseInt(element.readAttribute('wysija_static') || 0, 10),
409
- element: element,
410
- params: ''
411
- };
412
-
413
- // get params (may be empty)
414
- if(element.readAttribute('wysija_params') !== null && element.readAttribute('wysija_params').length > 0) {
415
- data.params = JSON.parse(element.readAttribute('wysija_params'));
416
- }
417
- return data;
418
- },
419
- toggleWidgets: function() {
420
- $$('a[wysija_unique="1"]').invoke('removeClassName', 'disabled');
421
-
422
- // loop through each unique field already inserted in the editor and disable its toolbar equivalent
423
- $$('#' + WysijaForm.options.editor + ' [wysija_unique="1"]').map(function(element) {
424
- var field = $$('#' + WysijaForm.options.toolbar + ' [wysija_id="' + element.readAttribute('wysija_id') + '"]');
425
- if(field.length > 0) {
426
- field.first().addClassName('disabled');
427
- }
428
- });
429
-
430
- var hasSegmentSelection = WysijaForm.hasSegmentSelection();
431
-
432
- if(hasSegmentSelection) {
433
- $('mailpoet_form_segments').writeAttribute('required', false).disable();
434
- $('mailpoet_settings_segment_selection').hide();
435
- } else {
436
- $('mailpoet_form_segments').writeAttribute('required', true).enable();
437
- $('mailpoet_settings_segment_selection').show();
438
- }
439
- },
440
- hasSegmentSelection: function() {
441
- return ($$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]').length > 0);
442
- },
443
- isSegmentSelectionValid: function() {
444
- var segment_selection = $$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]')[0];
445
- if(segment_selection !== undefined) {
446
- var block = WysijaForm.get(segment_selection).block.getData();
447
- return (
448
- (block.params.values !== undefined)
449
- &&
450
- (block.params.values.length > 0)
451
- );
452
- }
453
- return false;
454
- },
455
- setBlockPositions: function(event, target) {
456
- // release dragging lock
457
- WysijaForm.locks.dragging = false;
458
-
459
- var index = 1;
460
- WysijaForm.getBlocks().each(function(container) {
461
- container.setPosition(index++);
462
- // remove z-index value to avoid issues when resizing images
463
- if(container['block'] !== undefined) {
464
- container.block.element.setStyle({
465
- zIndex: ''
466
- });
467
- }
468
- });
469
-
470
- if(target !== undefined) {
471
- // get placeholders (previous placeholder matches the placeholder linked to the next block)
472
- var block_placeholder = $(target.element.readAttribute('wysija_placeholder')),
473
- previous_placeholder = target.element.previous('.block_placeholder');
474
-
475
- if(block_placeholder !== null) {
476
- // put block placeholder before the current block
477
- target.element.insert({
478
- before: block_placeholder
479
- });
480
-
481
- // if the next block is a wysija_block, insert previous placeholder
482
- if(target.element.next() !== undefined && target.element.next().hasClassName('mailpoet_form_block') && previous_placeholder !== undefined) {
483
- target.element.insert({
484
- after: previous_placeholder
485
- });
486
- }
487
- }
488
- }
489
- },
490
- setScrollOffsets: function() {
491
- WysijaForm.scroll = document.viewport.getScrollOffsets();
492
- },
493
- hideSettings: function() {
494
- $(WysijaForm.options.container).select('.wysija_settings').invoke('hide');
495
- },
496
- setSettingsPosition: function() {
497
- // get viewport offsets and dimensions
498
- var viewportHeight = document.viewport.getHeight(),
499
- blockPadding = 5;
500
-
501
- $(WysijaForm.options.container).select('.wysija_settings').each(function(element) {
502
- // get parent dimensions and position
503
- var parentDim = element.up('.mailpoet_form_block').getDimensions(),
504
- parentPos = element.up('.mailpoet_form_block').cumulativeOffset(),
505
- is_visible = (parentPos.top <= (WysijaForm.scroll.top + viewportHeight)) ? true : false,
506
- buttonMargin = 5,
507
- relativeTop = buttonMargin;
508
-
509
- if(is_visible) {
510
- // desired position is set to center of viewport
511
- var absoluteTop = parseInt(WysijaForm.scroll.top + ((viewportHeight / 2) - (element.getHeight() / 2)), 10),
512
- parentTop = parseInt(parentPos.top - blockPadding, 10),
513
- parentBottom = parseInt(parentPos.top + parentDim.height - blockPadding, 10);
514
-
515
- // always center
516
- relativeTop = parseInt((parentDim.height / 2) - (element.getHeight() / 2), 10);
517
- }
518
- // set position for button
519
- $(element).setStyle({
520
- left: parseInt((parentDim.width / 2) - (element.getWidth() / 2)) + 'px',
521
- top: relativeTop + 'px'
522
- });
523
- });
524
- },
525
- initToolbarPosition: function() {
526
- if(WysijaForm.toolbar.top === null) WysijaForm.toolbar.top = parseInt($(WysijaForm.options.container).positionedOffset().top);
527
- if(WysijaForm.toolbar.y === null) WysijaForm.toolbar.y = parseInt(WysijaForm.toolbar.top);
528
-
529
- if(isRtl) {
530
- if(WysijaForm.toolbar.left === null) WysijaForm.toolbar.left = 0;
531
- } else {
532
- if(WysijaForm.toolbar.left === null) WysijaForm.toolbar.left = parseInt($(WysijaForm.options.container).positionedOffset().left);
533
- }
534
- if(WysijaForm.toolbar.x === null) WysijaForm.toolbar.x = parseInt(WysijaForm.toolbar.left + $(WysijaForm.options.container).getDimensions().width + 15);
535
-
536
- },
537
- setToolbarPosition: function() {
538
- WysijaForm.initToolbarPosition();
539
-
540
- var position = {
541
- top: WysijaForm.toolbar.y + 'px',
542
- visibility: 'visible'
543
- };
544
-
545
- if(isRtl) {
546
- position.right = WysijaForm.toolbar.x + 'px';
547
- } else {
548
- position.left = WysijaForm.toolbar.x + 'px';
549
- }
550
-
551
- $(WysijaForm.options.toolbar).setStyle(position);
552
- },
553
- updateToolbarPosition: function() {
554
- // init toolbar position (updates scroll and toolbar y)
555
- WysijaForm.initToolbarPosition();
556
-
557
- // cancel previous effect
558
- if(WysijaForm.toolbar.effect !== null) WysijaForm.toolbar.effect.cancel();
559
-
560
- if(WysijaForm.scroll.top >= (WysijaForm.toolbar.top - 20)) {
561
- WysijaForm.toolbar.y = parseInt(20 + WysijaForm.scroll.top);
562
- // start effect
563
- WysijaForm.toolbar.effect = new Effect.Move(WysijaForm.options.toolbar, {
564
- x: WysijaForm.toolbar.x,
565
- y: WysijaForm.toolbar.y,
566
- mode: 'absolute',
567
- duration: 0.2
568
- });
569
- } else {
570
- $(WysijaForm.options.toolbar).setStyle({
571
- left: WysijaForm.toolbar.x + 'px',
572
- top: WysijaForm.toolbar.top + 'px'
573
- });
574
- }
575
- },
576
- blockDropOptions: {
577
- accept: $w('mailpoet_form_field'), // acceptable items (classes array)
578
- onEnter: function(draggable, droppable) {
579
- $(droppable).addClassName('hover');
580
- },
581
- onLeave: function(draggable, droppable) {
582
- $(droppable).removeClassName('hover');
583
- },
584
- onDrop: function(draggable, droppable) {
585
- // custom data for images
586
- droppable.fire('wjfe:item:drop', WysijaForm.getFieldData(draggable));
587
- $(droppable).removeClassName('hover');
588
- }
589
- },
590
- hideControls: function() {
591
- try {
592
- return WysijaForm.getBlocks().invoke('hideControls');
593
- } catch(e) {
594
- return;
595
- }
596
- },
597
- hideTools: function() {
598
- $$('.wysija_tools').invoke('hide');
599
- WysijaForm.locks.showingTools = false;
600
- },
601
- instances: {},
602
- get: function(element, typ) {
603
- var type = typ;
604
- if(type === undefined) type = 'block';
605
- // identify element
606
- var id = element.identify();
607
- var instance = WysijaForm.instances[id] || new WysijaForm[type.capitalize().camelize()](id);
608
-
609
- WysijaForm.instances[id] = instance;
610
- return instance;
611
- },
612
- makeDroppable: function() {
613
- Droppables.add('block_placeholder', WysijaForm.blockDropOptions);
614
- },
615
- makeSortable: function() {
616
- var body = $(WysijaForm.options.body);
617
- Sortable.create(body, {
618
- tag: 'div',
619
- only: 'mailpoet_form_block',
620
- scroll: window,
621
- handle: 'handle',
622
- constraint: 'vertical'
623
-
624
- });
625
- Draggables.removeObserver(body);
626
- Draggables.addObserver({
627
- element: body,
628
- onStart: WysijaForm.startBlockPositions,
629
- onEnd: WysijaForm.setBlockPositions
630
- });
631
- },
632
- hideBlockControls: function() {
633
- $$('.wysija_controls').invoke('hide');
634
- this.getBlockElements().invoke('removeClassName', 'hover');
635
- },
636
- getBlocks: function() {
637
- return WysijaForm.getBlockElements().map(function(element) {
638
- return WysijaForm.get(element);
639
- });
640
- },
641
- getBlockElements: function() {
642
- return $(WysijaForm.options.container).select('.mailpoet_form_block');
643
- },
644
- startBlockPositions: function(event, target) {
645
- if(target.element.hasClassName('mailpoet_form_block')) {
646
- // store block placeholder id for the block that is being repositionned
647
- if(target.element.previous('.block_placeholder') !== undefined) {
648
- target.element.writeAttribute('wysija_placeholder', target.element.previous('.block_placeholder').identify());
649
- }
650
- }
651
- WysijaForm.locks.dragging = true;
652
- },
653
- encodeURIComponent: function(str) {
654
- // check if it's a url and if so, prevent encoding of protocol
655
- var regexp = new RegExp(/^http[s]?:\/\//),
656
- protocol = regexp.exec(str);
657
-
658
- if(protocol === null) {
659
- // this is not a url so encode the whole thing
660
- return encodeURIComponent(str).replace(/[!'()*]/g, escape);
661
- } else if(protocol.length === 1) {
662
- // this is a url, so do not encode the protocol
663
- return encodeURI(str).replace(/[!'()*]/g, escape);
664
- }
665
- },
666
- updateBlock: function(field) {
667
- var hasUpdated = false;
668
- WysijaForm.getBlocks().each(function(b) {
669
- if(b.block.getData().id === field.id) {
670
- hasUpdated = true;
671
- b.block.redraw(field);
672
- }
673
- });
674
-
675
- return hasUpdated;
676
- },
677
- removeBlock: function(field, callback) {
678
- var hasRemoved = false;
679
- WysijaForm.getBlocks().each(function(b) {
680
- if(b.block.getData().id === field.id) {
681
- hasRemoved = true;
682
- b.block.removeBlock(callback);
683
- }
684
- });
685
-
686
- return hasRemoved;
687
- }
688
- };
689
-
690
- WysijaForm.DraggableItem = Class.create({
691
- initialize: function(element) {
692
- this.elementType = $(element).readAttribute('wysija_type');
693
- this.element = $(element).down() || $(element);
694
- this.clone = this.cloneElement();
695
- this.insert();
696
- },
697
- STYLES: new Template('position: absolute; top: #{top}px; left: #{left}px;'),
698
- cloneElement: function() {
699
- var clone = this.element.clone(),
700
- offset = this.element.cumulativeOffset(),
701
- list = this.getList(),
702
- styles = this.STYLES.evaluate({
703
- top: offset.top - list.scrollTop,
704
- left: offset.left - list.scrollLeft
705
- });
706
- clone.setStyle(styles);
707
-
708
- clone.addClassName('mailpoet_form_widget');
709
- clone.addClassName(this.elementType);
710
- clone.innerHTML = this.element.innerHTML;
711
- return clone;
712
- },
713
- getOffset: function() {
714
- return this.element.offsetTop - this.getList().scrollTop;
715
- },
716
- getList: function() {
717
- return this.element.up('ul');
718
- },
719
- insert: function() {
720
- $$("body")[0].insert(this.clone);
721
- },
722
- onMousedown: function(event) {
723
- var draggable = new Draggable(this.clone, {
724
- scroll: window,
725
- onStart: function() {
726
- Droppables.displayArea(draggable);
727
- },
728
- onEnd: function(drag) {
729
- drag.destroy();
730
- drag.element.remove();
731
- Droppables.hideArea();
732
- },
733
- starteffect: function(element) {
734
- new Effect.Opacity(element, {
735
- duration: 0.2,
736
- from: element.getOpacity(),
737
- to: 0.7
738
- });
739
- },
740
- endeffect: Prototype.emptyFunction
741
- });
742
- draggable.initDrag(event);
743
- draggable.startDrag(event);
744
- return draggable;
745
- }
746
- });
747
- Object.extend(WysijaForm.DraggableItem, Observable).observe('a[class="mailpoet_form_field"]');
748
-
749
-
750
- WysijaForm.Block = Class.create({
751
- /* Invoked on load */
752
- initialize: function(element) {
753
- info('block -> init');
754
-
755
- this.element = $(element);
756
- this.block = new WysijaForm.Widget(this.element);
757
-
758
- // enable block placeholder
759
- this.block.makeBlockDroppable();
760
-
761
- // setup events
762
- if(this.block['setup'] !== undefined) {
763
- this.block.setup();
764
- }
765
- return this;
766
- },
767
- setPosition: function(position) {
768
- this.element.writeAttribute('wysija_position', position);
769
- },
770
- hideControls: function() {
771
- if(this['getControls']) {
772
- this.element.removeClassName('hover');
773
- this.getControls().hide();
774
- }
775
- },
776
- showControls: function() {
777
- if(this['getControls']) {
778
- this.element.addClassName('hover');
779
- try {
780
- this.getControls().show();
781
- } catch(e) {;
782
- }
783
- }
784
- },
785
- makeBlockDroppable: function() {
786
- if(this.isBlockDroppableEnabled() === false) {
787
- var block_placeholder = this.getBlockDroppable();
788
- Droppables.add(block_placeholder.identify(), WysijaForm.blockDropOptions);
789
- block_placeholder.addClassName('enabled');
790
- }
791
- },
792
- removeBlockDroppable: function() {
793
- if(this.isBlockDroppableEnabled()) {
794
- var block_placeholder = this.getBlockDroppable();
795
- Droppables.remove(block_placeholder.identify());
796
- block_placeholder.removeClassName('enabled');
797
- }
798
- },
799
- isBlockDroppableEnabled: function() {
800
- // if the block_placeholder does not exist, create it
801
- var block_placeholder = this.getBlockDroppable();
802
- if(block_placeholder === null) {
803
- return this.createBlockDroppable().hasClassName('enabled');
804
- } else {
805
- return block_placeholder.hasClassName('enabled');
806
- }
807
- },
808
- createBlockDroppable: function() {
809
- info('block -> createBlockDroppable');
810
- this.element.insert({
811
- before: '<div class=\"block_placeholder\">' + $('block_placeholder').innerHTML + '</div>'
812
- });
813
- return this.element.previous('.block_placeholder');
814
- },
815
- getBlockDroppable: function() {
816
- if(this.element.previous() === undefined || this.element.previous().hasClassName('block_placeholder') === false) {
817
- return null;
818
- } else {
819
- return this.element.previous();
820
- }
821
- },
822
- getControls: function() {
823
- return this.element.down('.wysija_controls');
824
- },
825
- setupControls: function() {
826
- // enable controls
827
- this.controls = this.getControls();
828
-
829
- if(this.controls) {
830
- // setup events for block controls
831
- this.element.observe('mouseover', function() {
832
- // special cases where controls shouldn't be displayed
833
- if(WysijaForm.locks.dragging === true || WysijaForm.locks.selectingColor === true || WysijaForm.locks.showingTools === true) return;
834
-
835
- // set block flag
836
- this.element.addClassName('hover');
837
-
838
- // show controls
839
- this.showControls();
840
-
841
- // show settings if present
842
- if(this.element.down('.wysija_settings') !== undefined) {
843
- this.element.down('.wysija_settings').show();
844
- }
845
- }.bind(this));
846
-
847
- this.element.observe('mouseout', function() {
848
- // special cases where controls shouldn't hide
849
- if(WysijaForm.locks.dragging === true || WysijaForm.locks.selectingColor === true) return;
850
-
851
- // hide controls
852
- this.hideControls();
853
-
854
- // hide settings if present
855
- if(this.element.down('.wysija_settings') !== undefined) {
856
- this.element.down('.wysija_settings').hide();
857
- }
858
- }.bind(this));
859
-
860
-
861
- // setup click event for remove button
862
- this.removeButton = this.controls.down('.remove') || null;
863
- if(this.removeButton !== null) {
864
- this.removeButton.observe('click', function() {
865
- this.removeBlock();
866
- this.removeButton.stopObserving('click');
867
- }.bind(this));
868
- }
869
-
870
- // setup click event for settings button
871
- this.settingsButton = this.element.down('.settings') || null;
872
-
873
- if(this.settingsButton !== null) {
874
- this.settingsButton.observe('click', function(event) {
875
- // TODO: refactor
876
- var block = $(event.target).up('.mailpoet_form_block') || null;
877
- if(block !== null) {
878
- var field = WysijaForm.getFieldData(block);
879
- this.editSettings();
880
- }
881
- }.bind(this));
882
- }
883
- }
884
- return this;
885
- },
886
- removeBlock: function(callback) {
887
- info('block -> removeBlock');
888
-
889
- // save block in history
890
- WysijaHistory.enqueue(this.element);
891
-
892
- Effect.Fade(this.element.identify(), {
893
- duration: 0.2,
894
- afterFinish: function(effect) {
895
- // remove placeholder
896
- if(effect.element.previous('.block_placeholder') !== undefined) {
897
- effect.element.previous('.block_placeholder').remove();
898
- }
899
-
900
- // remove element from the DOM
901
- this.element.remove();
902
-
903
- // reset block positions
904
- WysijaForm.setBlockPositions();
905
-
906
- // toggle widgets
907
- WysijaForm.toggleWidgets();
908
-
909
- // optional callback execution after completely removing block
910
- if(callback !== undefined && typeof(callback) === 'function') {
911
- callback();
912
- }
913
-
914
- // remove block instance
915
- delete WysijaForm.instances[this.element.identify()];
916
- }.bind(this)
917
- });
918
- }
919
- });
920
-
921
- /* Invoked on item dropped */
922
- WysijaForm.Block.create = function(createBlock, target) {
923
- var block = createBlock;
924
- if($('form_template_' + block.type) === null) {
925
- return false;
926
- }
927
-
928
- var body = $(WysijaForm.options.body),
929
- block_template = Handlebars.compile($('form_template_block').innerHTML),
930
- template = Handlebars.compile($('form_template_' + block.type).innerHTML),
931
- output = '';
932
-
933
- if(block.type === 'segment') {
934
- if(block.params.values === undefined) {
935
- var settings_segments = jQuery('#mailpoet_form_segments').val();
936
- if(settings_segments !== null && settings_segments.length > 0){
937
- block.params.values = mailpoet_segments.filter(function(segment) {
938
- return (settings_segments.indexOf(segment.id) !== -1);
939
- });
940
- }
941
- }
942
- }
943
-
944
- // set block template (depending on the block type)
945
- block.template = template(block);
946
- output = block_template(block);
947
-
948
- // check if the new block is unique and if there's already an instance
949
- // of it in the history. If so, remove its former instance from the history
950
- if(block.unique === 1) {
951
- WysijaHistory.remove(block.field);
952
- }
953
-
954
- // if the drop target was the bottom placeholder
955
- var element = null;
956
- if(target.identify() === 'block_placeholder') {
957
- // insert block at the bottom
958
- element = body.insert(output);
959
- //block = body.childElements().last();
960
- } else {
961
- // insert block before the drop target
962
- element = target.insert({
963
- before: output
964
- });
965
- //block = target.previous('.mailpoet_form_block');
966
- }
967
- // refresh sortable items
968
- WysijaForm.makeSortable();
969
-
970
- // refresh block positions
971
- WysijaForm.setBlockPositions();
972
-
973
- // position settings
974
- WysijaForm.setSettingsPosition();
975
- };
976
-
977
- document.observe('wjfe:item:drop', function(event) {
978
- info('create block');
979
- WysijaForm.Block.create(event.memo, event.target);
980
-
981
- // hide block controls
982
- info('hide controls');
983
- WysijaForm.hideBlockControls();
984
-
985
- // toggle widgets
986
- setTimeout(function() {
987
- WysijaForm.toggleWidgets();
988
- }, 1);
989
- });
990
-
991
- /* Form Widget */
992
- WysijaForm.Widget = Class.create(WysijaForm.Block, {
993
- initialize: function(element) {
994
- info('widget -> init');
995
- this.element = $(element);
996
- return this;
997
- },
998
- setup: function() {
999
- info('widget -> setup');
1000
- this.setupControls();
1001
- },
1002
- save: function() {
1003
- info('widget -> save');
1004
- var data = this.getData();
1005
-
1006
- if(data.element !== undefined) {
1007
- delete data.element;
1008
- }
1009
-
1010
- return data;
1011
- },
1012
- setData: function(data) {
1013
- var current_data = this.getData(),
1014
- params = $H(current_data.params).merge(data.params).toObject();
1015
-
1016
- // update type if it changed
1017
- if(data.type !== undefined && data.type !== current_data.type) {
1018
- this.element.writeAttribute('wysija_type', data.type);
1019
- }
1020
-
1021
- // update params
1022
- this.element.writeAttribute('wysija_params', JSON.stringify(params));
1023
- },
1024
- getData: function() {
1025
- var data = WysijaForm.getFieldData(this.element);
1026
- // decode params
1027
- if(data.params.length > 0) {
1028
- data.params = JSON.parse(data.params);
1029
- }
1030
- return data;
1031
- },
1032
- getControls: function() {
1033
- return this.element.down('.wysija_controls');
1034
- },
1035
- remove: function() {
1036
- this.removeBlock();
1037
- },
1038
- redraw: function(data) {
1039
- // set parameters
1040
- this.setData(data);
1041
- var options = this.getData();
1042
- // redraw block
1043
- var block_template = Handlebars.compile($('form_template_block').innerHTML),
1044
- template = Handlebars.compile($('form_template_' + options.type).innerHTML),
1045
- data = $H(options).merge({
1046
- template: template(options)
1047
- }).toObject();
1048
- this.element.replace(block_template(data));
1049
-
1050
- WysijaForm.init();
1051
- },
1052
- editSettings: function() {
1053
- MailPoet.Modal.popup({
1054
- title: MailPoet.I18n.t('editFieldSettings'),
1055
- template: jQuery('#form_template_field_settings').html(),
1056
- data: this.getData(),
1057
- onSuccess: function() {
1058
- var data = jQuery('#form_field_settings').serializeObject();
1059
- this.redraw(data);
1060
- }.bind(this)
1061
- });
1062
- },
1063
- getSettings: function() {
1064
- return this.element.down('.wysija_settings');
1065
- }
1066
- });
1067
-
1068
- /* When dom is loaded, initialize WysijaForm */
1069
- document.observe('dom:loaded', WysijaForm.init);
1070
-
1071
- /* LOGGING */
1072
- function info(value) {
1073
- if(WysijaForm.options.debug === false) return;
1074
-
1075
- if(!(window.console && console.log)) {
1076
- (function() {
1077
- var noop = function() {};
1078
- var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
1079
- var length = methods.length;
1080
- window.console = {};
1081
- var console = {};
1082
- while(length--) {
1083
- console[methods[length]] = noop;
1084
- }
1085
- }());
1086
- }
1087
- try {
1088
- console.log('[DEBUG] ' + value);
1089
- } catch(e) {}
1090
- }
1091
-
1092
- module.exports = WysijaForm;
1093
 
1094
 
1095
  /***/ },
@@ -6283,7 +6283,7 @@ webpackJsonp([2],{
6283
  var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
6284
  if (split) {
6285
  for (var i = split.length - 1; i >= 0; --i)
6286
- { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}); }
6287
  } else {
6288
  makeChangeInner(doc, change);
6289
  }
@@ -10007,7 +10007,7 @@ webpackJsonp([2],{
10007
  var markerID = node.getAttribute("cm-marker"), range$$1;
10008
  if (markerID) {
10009
  var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
10010
- if (found.length && (range$$1 = found[0].find()))
10011
  { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); }
10012
  return
10013
  }
@@ -10591,7 +10591,7 @@ webpackJsonp([2],{
10591
 
10592
  addLegacyProps(CodeMirror$1);
10593
 
10594
- CodeMirror$1.version = "5.28.0";
10595
 
10596
  return CodeMirror$1;
10597
 
@@ -10988,7 +10988,8 @@ webpackJsonp([2],{
10988
  style = style[0];
10989
  }
10990
  override = style;
10991
- state.state = states[state.state](type, stream, state);
 
10992
  return override;
10993
  },
10994
 
21
  /***/ 549:
22
  /***/ function(module, exports) {
23
 
24
+ /*
25
+ * name: MailPoet Form Editor
26
+ * author: Jonathan Labreuille
27
+ * company: Wysija
28
+ * framework: prototype 1.7.2
29
+ */
30
+ 'use strict';
31
+
32
+ Event.cacheDelegated = {};
33
+ Object.extend(document, (function() {
34
+ var cache = Event.cacheDelegated;
35
+
36
+ function getCacheForSelector(selector) {
37
+ cache[selector] = cache[selector] || {};
38
+ return cache[selector];
39
+ }
40
+
41
+ function getWrappersForSelector(selector, eventName) {
42
+ var c = getCacheForSelector(selector);
43
+ c[eventName] = c[eventName] || [];
44
+ return c[eventName];
45
+ }
46
+
47
+ function findWrapper(selector, eventName, handler) {
48
+ var c = getWrappersForSelector(selector, eventName);
49
+ return c.find(function(wrapper) {
50
+ return wrapper.handler === handler
51
+ });
52
+ }
53
+
54
+ function destroyWrapper(selector, eventName, handler) {
55
+ var c = getCacheForSelector(selector);
56
+ if(!c[eventName]) return false;
57
+ var wrapper = findWrapper(selector, eventName, handler)
58
+ c[eventName] = c[eventName].without(wrapper);
59
+ return wrapper;
60
+ }
61
+
62
+ function createWrapper(selector, eventName, handler, context) {
63
+ var wrapper, c = getWrappersForSelector(selector, eventName);
64
+ if(c.pluck('handler').include(handler)) return false;
65
+ wrapper = function(event) {
66
+ var element = event.findElement(selector);
67
+ if(element) handler.call(context || element, event, element);
68
+ };
69
+ wrapper.handler = handler;
70
+ c.push(wrapper);
71
+ return wrapper;
72
+ }
73
+ return {
74
+ delegate: function(selector, eventName, handler, context) {
75
+ var wrapper = createWrapper.apply(null, arguments);
76
+ if(wrapper) document.observe(eventName, wrapper);
77
+ return document;
78
+ },
79
+ stopDelegating: function(selector, eventName, handler) {
80
+ var length = arguments.length;
81
+ switch(length) {
82
+ case 2:
83
+ getWrappersForSelector(selector, eventName).each(function(wrapper) {
84
+ document.stopDelegating(selector, eventName, wrapper.handler);
85
+ });
86
+ break;
87
+ case 1:
88
+ Object.keys(getCacheForSelector(selector)).each(function(eventName) {
89
+ document.stopDelegating(selector, eventName);
90
+ });
91
+ break;
92
+ case 0:
93
+ Object.keys(cache).each(function(selector) {
94
+ document.stopDelegating(selector);
95
+ });
96
+ break;
97
+ default:
98
+ var wrapper = destroyWrapper.apply(null, arguments);
99
+ if(wrapper) document.stopObserving(eventName, wrapper);
100
+ }
101
+ return document;
102
+ }
103
+ }
104
+ })());
105
+
106
+ var Observable = (function() {
107
+ function getEventName(nameA, namespace) {
108
+ var name = nameA.substring(2);
109
+ if(namespace) name = namespace + ':' + name;
110
+ return name.underscore().split('_').join(':');
111
+ }
112
+
113
+ function getHandlers(klass) {
114
+ var proto = klass.prototype,
115
+ namespace = proto.namespace;
116
+ return Object.keys(proto).grep(/^on/).inject($H(), function(handlers, name) {
117
+ if(name === 'onDomLoaded') return handlers;
118
+ handlers.set(getEventName(name, namespace), getWrapper(proto[name], klass));
119
+ return handlers;
120
+ });
121
+ }
122
+
123
+ function getWrapper(handler, klass) {
124
+ return function(event) {
125
+ return handler.call(new klass(this), event, event.memo);
126
+ }
127
+ }
128
+
129
+ function onDomLoad(selector, klass) {
130
+ $$(selector).each(function(element) {
131
+ new klass(element).onDomLoaded();
132
+ });
133
+ }
134
+ return {
135
+ observe: function(selector) {
136
+ if(!this.handlers) this.handlers = {};
137
+ if(this.handlers[selector]) return;
138
+ var klass = this;
139
+ if(this.prototype.onDomLoaded) document.loaded ? onDomLoad(selector, klass) : document.observe('dom:loaded', onDomLoad.curry(selector, klass));
140
+ this.handlers[selector] = getHandlers(klass).each(function(handler) {
141
+ document.delegate(selector, handler.key, handler.value);
142
+ });
143
+ },
144
+ stopObserving: function(selector) {
145
+ if(!this.handlers || !this.handlers[selector]) return;
146
+ this.handlers[selector].each(function(handler) {
147
+ document.stopDelegating(selector, handler.key, handler.value);
148
+ });
149
+ delete this.handlers[selector];
150
+ }
151
+ }
152
+ })();
153
+
154
+ // override droppables
155
+ Object.extend(Droppables, {
156
+ deactivate: Droppables.deactivate.wrap(function(proceed, drop, draggable) {
157
+ if(drop.onLeave) drop.onLeave(draggable, drop.element);
158
+ return proceed(drop);
159
+ }),
160
+ activate: Droppables.activate.wrap(function(proceed, drop, draggable) {
161
+ if(drop.onEnter) drop.onEnter(draggable, drop.element);
162
+ return proceed(drop);
163
+ }),
164
+ show: function(point, element) {
165
+ if(!this.drops.length) return;
166
+ var drop, affected = [];
167
+ this.drops.each(function(drop) {
168
+ if(Droppables.isAffected(point, element, drop)) affected.push(drop);
169
+ });
170
+ if(affected.length > 0) drop = Droppables.findDeepestChild(affected);
171
+ if(this.last_active && this.last_active !== drop) this.deactivate(this.last_active, element);
172
+ if(drop) {
173
+ Position.within(drop.element, point[0], point[1]);
174
+ if(drop.onHover) drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
175
+ if(drop !== this.last_active) Droppables.activate(drop, element);
176
+ }
177
+ },
178
+ displayArea: function(draggable) {
179
+ if(!this.drops.length) return;
180
+
181
+ // hide controls when displaying drop areas.
182
+ WysijaForm.hideBlockControls();
183
+
184
+ this.drops.each(function(drop, iterator) {
185
+ if(drop.element.hasClassName('block_placeholder')) {
186
+ drop.element.addClassName('active');
187
+ }
188
+ });
189
+ },
190
+ hideArea: function() {
191
+ if(!this.drops.length) return;
192
+ this.drops.each(function(drop, iterator) {
193
+ if(drop.element.hasClassName('block_placeholder')) {
194
+ drop.element.removeClassName('active');
195
+ } else if(drop.element.hasClassName('image_placeholder')) {
196
+ drop.element.removeClassName('active');
197
+ drop.element.up().removeClassName('active');
198
+ } else if(drop.element.hasClassName('text_placeholder')) {
199
+ drop.element.removeClassName('active');
200
+ }
201
+ });
202
+ },
203
+ reset: function(draggable) {
204
+ if(this.last_active) this.deactivate(this.last_active, draggable);
205
+ }
206
+ });
207
+
208
+ /*
209
+ Wysija History handling
210
+ POTENTIAL FEATURES:
211
+ - set a maximum number of items to be stored
212
+
213
+ */
214
+ var WysijaHistory = {
215
+ container: 'mailpoet_form_history',
216
+ size: 30,
217
+ enqueue: function(element) {
218
+ // create deep clone (includes child elements) of passed element
219
+ var clone = element.clone(true);
220
+
221
+ // check if the field is unique
222
+ if(parseInt(clone.readAttribute('wysija_unique'), 10) === 1) {
223
+ // check if the field is already in the queue
224
+ $(WysijaHistory.container).select('[wysija_name="' + clone.readAttribute('wysija_name') + '"]').invoke('remove');
225
+ }
226
+
227
+ // check history size
228
+ if($(WysijaHistory.container).select('> div').length >= WysijaHistory.size) {
229
+ // remove oldest element (last in the list)
230
+ $(WysijaHistory.container).select('> div').last().remove();
231
+ }
232
+
233
+ // store block in history
234
+ $(WysijaHistory.container).insert({
235
+ top: clone
236
+ });
237
+ },
238
+ dequeue: function() {
239
+ // pop last block off the history
240
+ var block = $(WysijaHistory.container).select('div').first();
241
+
242
+ if(block !== undefined) {
243
+ // insert block back into the editor
244
+ $(WysijaForm.options.body).insert({
245
+ top: block
246
+ });
247
+ }
248
+ },
249
+ clear: function() {
250
+ $(WysijaHistory.container).innerHTML = '';
251
+ },
252
+ remove: function(field) {
253
+ $(WysijaHistory.container).select('[wysija_name="' + field + '"]').invoke('remove');
254
+ }
255
+ };
256
+
257
+ /* MailPoet Form */
258
+ var WysijaForm = {
259
+ version: '0.7',
260
+ options: {
261
+ container: 'mailpoet_form_container',
262
+ editor: 'mailpoet_form_editor',
263
+ body: 'mailpoet_form_body',
264
+ toolbar: 'mailpoet_form_toolbar',
265
+ templates: 'wysija_widget_templates',
266
+ debug: false
267
+ },
268
+ toolbar: {
269
+ effect: null,
270
+ x: null,
271
+ y: null,
272
+ top: null,
273
+ left: null
274
+ },
275
+ scroll: {
276
+ top: 0,
277
+ left: 0
278
+ },
279
+ flags: {
280
+ doSave: false
281
+ },
282
+ locks: {
283
+ dragging: false,
284
+ selectingColor: false,
285
+ showingTools: false
286
+ },
287
+ encodeHtmlValue: function(str) {
288
+ return str.replace(/&/g, '&amp;').replace(/>/g, '&gt;').replace(/</g, '&lt;').replace(/"/g, '&quot;');
289
+ // ": fix for FileMerge because the previous line fucks up its syntax coloring
290
+ },
291
+ decodeHtmlValue: function(str) {
292
+ return str.replace(/&amp;/g, '&').replace(/&gt;/g, '>').replace(/&lt;/g, '<').replace(/&quot;/g, '"');
293
+ // ": fix for FileMerge because the previous line fucks up its syntax coloring
294
+ },
295
+ loading: function(is_loading) {
296
+ if(is_loading) {
297
+ $(WysijaForm.options.editor).addClassName('loading');
298
+ $(WysijaForm.options.toolbar).addClassName('loading');
299
+ } else {
300
+ $(WysijaForm.options.editor).removeClassName('loading');
301
+ $(WysijaForm.options.toolbar).removeClassName('loading');
302
+ }
303
+ },
304
+ loadStatic: function(blocks) {
305
+ $A(blocks).each(function(block) {
306
+ // create block
307
+ WysijaForm.Block.create(block, $('block_placeholder'));
308
+ });
309
+ },
310
+ load: function(data) {
311
+ if(data === undefined) return;
312
+
313
+ // load body
314
+ if(data.body !== undefined) {
315
+ $A(data.body).each(function(block) {
316
+ // create block
317
+ WysijaForm.Block.create(block, $('block_placeholder'));
318
+ });
319
+
320
+ // load settings
321
+ var settings_elements = $('mailpoet_form_settings').getElements();
322
+ settings_elements.each(function(setting) {
323
+ // skip lists
324
+ if(setting.name === 'segments') {
325
+ return true;
326
+ } else if(setting.name === 'on_success') {
327
+ // if the input value is equal to the one stored in the settings
328
+ if(setting.value === data.settings[setting.name]) {
329
+ // check selected value
330
+ $(setting).checked = true;
331
+ }
332
+ } else if(data.settings[setting.name] !== undefined) {
333
+ if(typeof data.settings[setting.name] === 'string') {
334
+ setting.setValue(WysijaForm.decodeHtmlValue(data.settings[setting.name]));
335
+ } else {
336
+ setting.setValue(data.settings[setting.name]);
337
+ }
338
+ }
339
+ });
340
+ }
341
+ },
342
+ save: function() {
343
+ var position = 1,
344
+ data = {
345
+ name: $F('mailpoet_form_name'),
346
+ settings: $('mailpoet_form_settings').serialize(true),
347
+ body: [],
348
+ styles: (MailPoet.CodeEditor !== undefined) ? MailPoet.CodeEditor.getValue() : null
349
+ };
350
+ // body
351
+ WysijaForm.getBlocks().each(function(b) {
352
+ var block_data = (typeof(b.block['save']) === 'function') ? b.block.save() : null;
353
+
354
+ if(block_data !== null) {
355
+ // set block position
356
+ block_data['position'] = position;
357
+
358
+ // increment position
359
+ position++;
360
+
361
+ // add block data to body
362
+ data['body'].push(block_data);
363
+ }
364
+ });
365
+
366
+ return data;
367
+ },
368
+ init: function() {
369
+ // set document scroll
370
+ info('init -> set scroll offsets');
371
+ WysijaForm.setScrollOffsets();
372
+
373
+ // position toolbar
374
+ info('init -> set toolbar position');
375
+ WysijaForm.setToolbarPosition();
376
+
377
+ // enable droppable targets
378
+ info('init -> make droppable');
379
+ WysijaForm.makeDroppable();
380
+
381
+ // enable sortable
382
+ info('init -> make sortable');
383
+ WysijaForm.makeSortable();
384
+
385
+ // hide controls
386
+ info('init -> hide controls');
387
+ WysijaForm.hideControls();
388
+
389
+ // hide settings
390
+ info('init -> hide settings');
391
+ WysijaForm.hideSettings();
392
+
393
+ // set settings buttons position
394
+ info('init -> init settings');
395
+ WysijaForm.setSettingsPosition();
396
+
397
+ // toggle widgets
398
+ info('init -> toggle widgets');
399
+ WysijaForm.toggleWidgets();
400
+ },
401
+ getFieldData: function(element) {
402
+ // get basic field data
403
+ var data = {
404
+ type: element.readAttribute('wysija_type'),
405
+ name: element.readAttribute('wysija_name'),
406
+ id: element.readAttribute('wysija_id'),
407
+ unique: parseInt(element.readAttribute('wysija_unique') || 0, 10),
408
+ static: parseInt(element.readAttribute('wysija_static') || 0, 10),
409
+ element: element,
410
+ params: ''
411
+ };
412
+
413
+ // get params (may be empty)
414
+ if(element.readAttribute('wysija_params') !== null && element.readAttribute('wysija_params').length > 0) {
415
+ data.params = JSON.parse(element.readAttribute('wysija_params'));
416
+ }
417
+ return data;
418
+ },
419
+ toggleWidgets: function() {
420
+ $$('a[wysija_unique="1"]').invoke('removeClassName', 'disabled');
421
+
422
+ // loop through each unique field already inserted in the editor and disable its toolbar equivalent
423
+ $$('#' + WysijaForm.options.editor + ' [wysija_unique="1"]').map(function(element) {
424
+ var field = $$('#' + WysijaForm.options.toolbar + ' [wysija_id="' + element.readAttribute('wysija_id') + '"]');
425
+ if(field.length > 0) {
426
+ field.first().addClassName('disabled');
427
+ }
428
+ });
429
+
430
+ var hasSegmentSelection = WysijaForm.hasSegmentSelection();
431
+
432
+ if(hasSegmentSelection) {
433
+ $('mailpoet_form_segments').writeAttribute('required', false).disable();
434
+ $('mailpoet_settings_segment_selection').hide();
435
+ } else {
436
+ $('mailpoet_form_segments').writeAttribute('required', true).enable();
437
+ $('mailpoet_settings_segment_selection').show();
438
+ }
439
+ },
440
+ hasSegmentSelection: function() {
441
+ return ($$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]').length > 0);
442
+ },
443
+ isSegmentSelectionValid: function() {
444
+ var segment_selection = $$('#' + WysijaForm.options.editor + ' [wysija_id="segments"]')[0];
445
+ if(segment_selection !== undefined) {
446
+ var block = WysijaForm.get(segment_selection).block.getData();
447
+ return (
448
+ (block.params.values !== undefined)
449
+ &&
450
+ (block.params.values.length > 0)
451
+ );
452
+ }
453
+ return false;
454
+ },
455
+ setBlockPositions: function(event, target) {
456
+ // release dragging lock
457
+ WysijaForm.locks.dragging = false;
458
+
459
+ var index = 1;
460
+ WysijaForm.getBlocks().each(function(container) {
461
+ container.setPosition(index++);
462
+ // remove z-index value to avoid issues when resizing images
463
+ if(container['block'] !== undefined) {
464
+ container.block.element.setStyle({
465
+ zIndex: ''
466
+ });
467
+ }
468
+ });
469
+
470
+ if(target !== undefined) {
471
+ // get placeholders (previous placeholder matches the placeholder linked to the next block)
472
+ var block_placeholder = $(target.element.readAttribute('wysija_placeholder')),
473
+ previous_placeholder = target.element.previous('.block_placeholder');
474
+
475
+ if(block_placeholder !== null) {
476
+ // put block placeholder before the current block
477
+ target.element.insert({
478
+ before: block_placeholder
479
+ });
480
+
481
+ // if the next block is a wysija_block, insert previous placeholder
482
+ if(target.element.next() !== undefined && target.element.next().hasClassName('mailpoet_form_block') && previous_placeholder !== undefined) {
483
+ target.element.insert({
484
+ after: previous_placeholder
485
+ });
486
+ }
487
+ }
488
+ }
489
+ },
490
+ setScrollOffsets: function() {
491
+ WysijaForm.scroll = document.viewport.getScrollOffsets();
492
+ },
493
+ hideSettings: function() {
494
+ $(WysijaForm.options.container).select('.wysija_settings').invoke('hide');
495
+ },
496
+ setSettingsPosition: function() {
497
+ // get viewport offsets and dimensions
498
+ var viewportHeight = document.viewport.getHeight(),
499
+ blockPadding = 5;
500
+
501
+ $(WysijaForm.options.container).select('.wysija_settings').each(function(element) {
502
+ // get parent dimensions and position
503
+ var parentDim = element.up('.mailpoet_form_block').getDimensions(),
504
+ parentPos = element.up('.mailpoet_form_block').cumulativeOffset(),
505
+ is_visible = (parentPos.top <= (WysijaForm.scroll.top + viewportHeight)) ? true : false,
506
+ buttonMargin = 5,
507
+ relativeTop = buttonMargin;
508
+
509
+ if(is_visible) {
510
+ // desired position is set to center of viewport
511
+ var absoluteTop = parseInt(WysijaForm.scroll.top + ((viewportHeight / 2) - (element.getHeight() / 2)), 10),
512
+ parentTop = parseInt(parentPos.top - blockPadding, 10),
513
+ parentBottom = parseInt(parentPos.top + parentDim.height - blockPadding, 10);
514
+
515
+ // always center
516
+ relativeTop = parseInt((parentDim.height / 2) - (element.getHeight() / 2), 10);
517
+ }
518
+ // set position for button
519
+ $(element).setStyle({
520
+ left: parseInt((parentDim.width / 2) - (element.getWidth() / 2)) + 'px',
521
+ top: relativeTop + 'px'
522
+ });
523
+ });
524
+ },
525
+ initToolbarPosition: function() {
526
+ if(WysijaForm.toolbar.top === null) WysijaForm.toolbar.top = parseInt($(WysijaForm.options.container).positionedOffset().top);
527
+ if(WysijaForm.toolbar.y === null) WysijaForm.toolbar.y = parseInt(WysijaForm.toolbar.top);
528
+
529
+ if(isRtl) {
530
+ if(WysijaForm.toolbar.left === null) WysijaForm.toolbar.left = 0;
531
+ } else {
532
+ if(WysijaForm.toolbar.left === null) WysijaForm.toolbar.left = parseInt($(WysijaForm.options.container).positionedOffset().left);
533
+ }
534
+ if(WysijaForm.toolbar.x === null) WysijaForm.toolbar.x = parseInt(WysijaForm.toolbar.left + $(WysijaForm.options.container).getDimensions().width + 15);
535
+
536
+ },
537
+ setToolbarPosition: function() {
538
+ WysijaForm.initToolbarPosition();
539
+
540
+ var position = {
541
+ top: WysijaForm.toolbar.y + 'px',
542
+ visibility: 'visible'
543
+ };
544
+
545
+ if(isRtl) {
546
+ position.right = WysijaForm.toolbar.x + 'px';
547
+ } else {
548
+ position.left = WysijaForm.toolbar.x + 'px';
549
+ }
550
+
551
+ $(WysijaForm.options.toolbar).setStyle(position);
552
+ },
553
+ updateToolbarPosition: function() {
554
+ // init toolbar position (updates scroll and toolbar y)
555
+ WysijaForm.initToolbarPosition();
556
+
557
+ // cancel previous effect
558
+ if(WysijaForm.toolbar.effect !== null) WysijaForm.toolbar.effect.cancel();
559
+
560
+ if(WysijaForm.scroll.top >= (WysijaForm.toolbar.top - 20)) {
561
+ WysijaForm.toolbar.y = parseInt(20 + WysijaForm.scroll.top);
562
+ // start effect
563
+ WysijaForm.toolbar.effect = new Effect.Move(WysijaForm.options.toolbar, {
564
+ x: WysijaForm.toolbar.x,
565
+ y: WysijaForm.toolbar.y,
566
+ mode: 'absolute',
567
+ duration: 0.2
568
+ });
569
+ } else {
570
+ $(WysijaForm.options.toolbar).setStyle({
571
+ left: WysijaForm.toolbar.x + 'px',
572
+ top: WysijaForm.toolbar.top + 'px'
573
+ });
574
+ }
575
+ },
576
+ blockDropOptions: {
577
+ accept: $w('mailpoet_form_field'), // acceptable items (classes array)
578
+ onEnter: function(draggable, droppable) {
579
+ $(droppable).addClassName('hover');
580
+ },
581
+ onLeave: function(draggable, droppable) {
582
+ $(droppable).removeClassName('hover');
583
+ },
584
+ onDrop: function(draggable, droppable) {
585
+ // custom data for images
586
+ droppable.fire('wjfe:item:drop', WysijaForm.getFieldData(draggable));
587
+ $(droppable).removeClassName('hover');
588
+ }
589
+ },
590
+ hideControls: function() {
591
+ try {
592
+ return WysijaForm.getBlocks().invoke('hideControls');
593
+ } catch(e) {
594
+ return;
595
+ }
596
+ },
597
+ hideTools: function() {
598
+ $$('.wysija_tools').invoke('hide');
599
+ WysijaForm.locks.showingTools = false;
600
+ },
601
+ instances: {},
602
+ get: function(element, typ) {
603
+ var type = typ;
604
+ if(type === undefined) type = 'block';
605
+ // identify element
606
+ var id = element.identify();
607
+ var instance = WysijaForm.instances[id] || new WysijaForm[type.capitalize().camelize()](id);
608
+
609
+ WysijaForm.instances[id] = instance;
610
+ return instance;
611
+ },
612
+ makeDroppable: function() {
613
+ Droppables.add('block_placeholder', WysijaForm.blockDropOptions);
614
+ },
615
+ makeSortable: function() {
616
+ var body = $(WysijaForm.options.body);
617
+ Sortable.create(body, {
618
+ tag: 'div',
619
+ only: 'mailpoet_form_block',
620
+ scroll: window,
621
+ handle: 'handle',
622
+ constraint: 'vertical'
623
+
624
+ });
625
+ Draggables.removeObserver(body);
626
+ Draggables.addObserver({
627
+ element: body,
628
+ onStart: WysijaForm.startBlockPositions,
629
+ onEnd: WysijaForm.setBlockPositions
630
+ });
631
+ },
632
+ hideBlockControls: function() {
633
+ $$('.wysija_controls').invoke('hide');
634
+ this.getBlockElements().invoke('removeClassName', 'hover');
635
+ },
636
+ getBlocks: function() {
637
+ return WysijaForm.getBlockElements().map(function(element) {
638
+ return WysijaForm.get(element);
639
+ });
640
+ },
641
+ getBlockElements: function() {
642
+ return $(WysijaForm.options.container).select('.mailpoet_form_block');
643
+ },
644
+ startBlockPositions: function(event, target) {
645
+ if(target.element.hasClassName('mailpoet_form_block')) {
646
+ // store block placeholder id for the block that is being repositionned
647
+ if(target.element.previous('.block_placeholder') !== undefined) {
648
+ target.element.writeAttribute('wysija_placeholder', target.element.previous('.block_placeholder').identify());
649
+ }
650
+ }
651
+ WysijaForm.locks.dragging = true;
652
+ },
653
+ encodeURIComponent: function(str) {
654
+ // check if it's a url and if so, prevent encoding of protocol
655
+ var regexp = new RegExp(/^http[s]?:\/\//),
656
+ protocol = regexp.exec(str);
657
+
658
+ if(protocol === null) {
659
+ // this is not a url so encode the whole thing
660
+ return encodeURIComponent(str).replace(/[!'()*]/g, escape);
661
+ } else if(protocol.length === 1) {
662
+ // this is a url, so do not encode the protocol
663
+ return encodeURI(str).replace(/[!'()*]/g, escape);
664
+ }
665
+ },
666
+ updateBlock: function(field) {
667
+ var hasUpdated = false;
668
+ WysijaForm.getBlocks().each(function(b) {
669
+ if(b.block.getData().id === field.id) {
670
+ hasUpdated = true;
671
+ b.block.redraw(field);
672
+ }
673
+ });
674
+
675
+ return hasUpdated;
676
+ },
677
+ removeBlock: function(field, callback) {
678
+ var hasRemoved = false;
679
+ WysijaForm.getBlocks().each(function(b) {
680
+ if(b.block.getData().id === field.id) {
681
+ hasRemoved = true;
682
+ b.block.removeBlock(callback);
683
+ }
684
+ });
685
+
686
+ return hasRemoved;
687
+ }
688
+ };
689
+
690
+ WysijaForm.DraggableItem = Class.create({
691
+ initialize: function(element) {
692
+ this.elementType = $(element).readAttribute('wysija_type');
693
+ this.element = $(element).down() || $(element);
694
+ this.clone = this.cloneElement();
695
+ this.insert();
696
+ },
697
+ STYLES: new Template('position: absolute; top: #{top}px; left: #{left}px;'),
698
+ cloneElement: function() {
699
+ var clone = this.element.clone(),
700
+ offset = this.element.cumulativeOffset(),
701
+ list = this.getList(),
702
+ styles = this.STYLES.evaluate({
703
+ top: offset.top - list.scrollTop,
704
+ left: offset.left - list.scrollLeft
705
+ });
706
+ clone.setStyle(styles);
707
+
708
+ clone.addClassName('mailpoet_form_widget');
709
+ clone.addClassName(this.elementType);
710
+ clone.innerHTML = this.element.innerHTML;
711
+ return clone;
712
+ },
713
+ getOffset: function() {
714
+ return this.element.offsetTop - this.getList().scrollTop;
715
+ },
716
+ getList: function() {
717
+ return this.element.up('ul');
718
+ },
719
+ insert: function() {
720
+ $$('body')[0].insert(this.clone);
721
+ },
722
+ onMousedown: function(event) {
723
+ var draggable = new Draggable(this.clone, {
724
+ scroll: window,
725
+ onStart: function() {
726
+ Droppables.displayArea(draggable);
727
+ },
728
+ onEnd: function(drag) {
729
+ drag.destroy();
730
+ drag.element.remove();
731
+ Droppables.hideArea();
732
+ },
733
+ starteffect: function(element) {
734
+ new Effect.Opacity(element, {
735
+ duration: 0.2,
736
+ from: element.getOpacity(),
737
+ to: 0.7
738
+ });
739
+ },
740
+ endeffect: Prototype.emptyFunction
741
+ });
742
+ draggable.initDrag(event);
743
+ draggable.startDrag(event);
744
+ return draggable;
745
+ }
746
+ });
747
+ Object.extend(WysijaForm.DraggableItem, Observable).observe('a[class="mailpoet_form_field"]');
748
+
749
+
750
+ WysijaForm.Block = Class.create({
751
+ /* Invoked on load */
752
+ initialize: function(element) {
753
+ info('block -> init');
754
+
755
+ this.element = $(element);
756
+ this.block = new WysijaForm.Widget(this.element);
757
+
758
+ // enable block placeholder
759
+ this.block.makeBlockDroppable();
760
+
761
+ // setup events
762
+ if(this.block['setup'] !== undefined) {
763
+ this.block.setup();
764
+ }
765
+ return this;
766
+ },
767
+ setPosition: function(position) {
768
+ this.element.writeAttribute('wysija_position', position);
769
+ },
770
+ hideControls: function() {
771
+ if(this['getControls']) {
772
+ this.element.removeClassName('hover');
773
+ this.getControls().hide();
774
+ }
775
+ },
776
+ showControls: function() {
777
+ if(this['getControls']) {
778
+ this.element.addClassName('hover');
779
+ try {
780
+ this.getControls().show();
781
+ } catch(e) {;
782
+ }
783
+ }
784
+ },
785
+ makeBlockDroppable: function() {
786
+ if(this.isBlockDroppableEnabled() === false) {
787
+ var block_placeholder = this.getBlockDroppable();
788
+ Droppables.add(block_placeholder.identify(), WysijaForm.blockDropOptions);
789
+ block_placeholder.addClassName('enabled');
790
+ }
791
+ },
792
+ removeBlockDroppable: function() {
793
+ if(this.isBlockDroppableEnabled()) {
794
+ var block_placeholder = this.getBlockDroppable();
795
+ Droppables.remove(block_placeholder.identify());
796
+ block_placeholder.removeClassName('enabled');
797
+ }
798
+ },
799
+ isBlockDroppableEnabled: function() {
800
+ // if the block_placeholder does not exist, create it
801
+ var block_placeholder = this.getBlockDroppable();
802
+ if(block_placeholder === null) {
803
+ return this.createBlockDroppable().hasClassName('enabled');
804
+ } else {
805
+ return block_placeholder.hasClassName('enabled');
806
+ }
807
+ },
808
+ createBlockDroppable: function() {
809
+ info('block -> createBlockDroppable');
810
+ this.element.insert({
811
+ before: '<div class=\"block_placeholder\">' + $('block_placeholder').innerHTML + '</div>'
812
+ });
813
+ return this.element.previous('.block_placeholder');
814
+ },
815
+ getBlockDroppable: function() {
816
+ if(this.element.previous() === undefined || this.element.previous().hasClassName('block_placeholder') === false) {
817
+ return null;
818
+ } else {
819
+ return this.element.previous();
820
+ }
821
+ },
822
+ getControls: function() {
823
+ return this.element.down('.wysija_controls');
824
+ },
825
+ setupControls: function() {
826
+ // enable controls
827
+ this.controls = this.getControls();
828
+
829
+ if(this.controls) {
830
+ // setup events for block controls
831
+ this.element.observe('mouseover', function() {
832
+ // special cases where controls shouldn't be displayed
833
+ if(WysijaForm.locks.dragging === true || WysijaForm.locks.selectingColor === true || WysijaForm.locks.showingTools === true) return;
834
+
835
+ // set block flag
836
+ this.element.addClassName('hover');
837
+
838
+ // show controls
839
+ this.showControls();
840
+
841
+ // show settings if present
842
+ if(this.element.down('.wysija_settings') !== undefined) {
843
+ this.element.down('.wysija_settings').show();
844
+ }
845
+ }.bind(this));
846
+
847
+ this.element.observe('mouseout', function() {
848
+ // special cases where controls shouldn't hide
849
+ if(WysijaForm.locks.dragging === true || WysijaForm.locks.selectingColor === true) return;
850
+
851
+ // hide controls
852
+ this.hideControls();
853
+
854
+ // hide settings if present
855
+ if(this.element.down('.wysija_settings') !== undefined) {
856
+ this.element.down('.wysija_settings').hide();
857
+ }
858
+ }.bind(this));
859
+
860
+
861
+ // setup click event for remove button
862
+ this.removeButton = this.controls.down('.remove') || null;
863
+ if(this.removeButton !== null) {
864
+ this.removeButton.observe('click', function() {
865
+ this.removeBlock();
866
+ this.removeButton.stopObserving('click');
867
+ }.bind(this));
868
+ }
869
+
870
+ // setup click event for settings button
871
+ this.settingsButton = this.element.down('.settings') || null;
872
+
873
+ if(this.settingsButton !== null) {
874
+ this.settingsButton.observe('click', function(event) {
875
+ // TODO: refactor
876
+ var block = $(event.target).up('.mailpoet_form_block') || null;
877
+ if(block !== null) {
878
+ var field = WysijaForm.getFieldData(block);
879
+ this.editSettings();
880
+ }
881
+ }.bind(this));
882
+ }
883
+ }
884
+ return this;
885
+ },
886
+ removeBlock: function(callback) {
887
+ info('block -> removeBlock');
888
+
889
+ // save block in history
890
+ WysijaHistory.enqueue(this.element);
891
+
892
+ Effect.Fade(this.element.identify(), {
893
+ duration: 0.2,
894
+ afterFinish: function(effect) {
895
+ // remove placeholder
896
+ if(effect.element.previous('.block_placeholder') !== undefined) {
897
+ effect.element.previous('.block_placeholder').remove();
898
+ }
899
+
900
+ // remove element from the DOM
901
+ this.element.remove();
902
+
903
+ // reset block positions
904
+ WysijaForm.setBlockPositions();
905
+
906
+ // toggle widgets
907
+ WysijaForm.toggleWidgets();
908
+
909
+ // optional callback execution after completely removing block
910
+ if(callback !== undefined && typeof(callback) === 'function') {
911
+ callback();
912
+ }
913
+
914
+ // remove block instance
915
+ delete WysijaForm.instances[this.element.identify()];
916
+ }.bind(this)
917
+ });
918
+ }
919
+ });
920
+
921
+ /* Invoked on item dropped */
922
+ WysijaForm.Block.create = function(createBlock, target) {
923
+ var block = createBlock;
924
+ if($('form_template_' + block.type) === null) {
925
+ return false;
926
+ }
927
+
928
+ var body = $(WysijaForm.options.body),
929
+ block_template = Handlebars.compile($('form_template_block').innerHTML),
930
+ template = Handlebars.compile($('form_template_' + block.type).innerHTML),
931
+ output = '';
932
+
933
+ if(block.type === 'segment') {
934
+ if(block.params.values === undefined) {
935
+ var settings_segments = jQuery('#mailpoet_form_segments').val();
936
+ if(settings_segments !== null && settings_segments.length > 0){
937
+ block.params.values = mailpoet_segments.filter(function(segment) {
938
+ return (settings_segments.indexOf(segment.id) !== -1);
939
+ });
940
+ }
941
+ }
942
+ }
943
+
944
+ // set block template (depending on the block type)
945
+ block.template = template(block);
946
+ output = block_template(block);
947
+
948
+ // check if the new block is unique and if there's already an instance
949
+ // of it in the history. If so, remove its former instance from the history
950
+ if(block.unique === 1) {
951
+ WysijaHistory.remove(block.field);
952
+ }
953
+
954
+ // if the drop target was the bottom placeholder
955
+ var element = null;
956
+ if(target.identify() === 'block_placeholder') {
957
+ // insert block at the bottom
958
+ element = body.insert(output);
959
+ //block = body.childElements().last();
960
+ } else {
961
+ // insert block before the drop target
962
+ element = target.insert({
963
+ before: output
964
+ });
965
+ //block = target.previous('.mailpoet_form_block');
966
+ }
967
+ // refresh sortable items
968
+ WysijaForm.makeSortable();
969
+
970
+ // refresh block positions
971
+ WysijaForm.setBlockPositions();
972
+
973
+ // position settings
974
+ WysijaForm.setSettingsPosition();
975
+ };
976
+
977
+ document.observe('wjfe:item:drop', function(event) {
978
+ info('create block');
979
+ WysijaForm.Block.create(event.memo, event.target);
980
+
981
+ // hide block controls
982
+ info('hide controls');
983
+ WysijaForm.hideBlockControls();
984
+
985
+ // toggle widgets
986
+ setTimeout(function() {
987
+ WysijaForm.toggleWidgets();
988
+ }, 1);
989
+ });
990
+
991
+ /* Form Widget */
992
+ WysijaForm.Widget = Class.create(WysijaForm.Block, {
993
+ initialize: function(element) {
994
+ info('widget -> init');
995
+ this.element = $(element);
996
+ return this;
997
+ },
998
+ setup: function() {
999
+ info('widget -> setup');
1000
+ this.setupControls();
1001
+ },
1002
+ save: function() {
1003
+ info('widget -> save');
1004
+ var data = this.getData();
1005
+
1006
+ if(data.element !== undefined) {
1007
+ delete data.element;
1008
+ }
1009
+
1010
+ return data;
1011
+ },
1012
+ setData: function(data) {
1013
+ var current_data = this.getData(),
1014
+ params = $H(current_data.params).merge(data.params).toObject();
1015
+
1016
+ // update type if it changed
1017
+ if(data.type !== undefined && data.type !== current_data.type) {
1018
+ this.element.writeAttribute('wysija_type', data.type);
1019
+ }
1020
+
1021
+ // update params
1022
+ this.element.writeAttribute('wysija_params', JSON.stringify(params));
1023
+ },
1024
+ getData: function() {
1025
+ var data = WysijaForm.getFieldData(this.element);
1026
+ // decode params
1027
+ if(data.params.length > 0) {
1028
+ data.params = JSON.parse(data.params);
1029
+ }
1030
+ return data;
1031
+ },
1032
+ getControls: function() {
1033
+ return this.element.down('.wysija_controls');
1034
+ },
1035
+ remove: function() {
1036
+ this.removeBlock();
1037
+ },
1038
+ redraw: function(data) {
1039
+ // set parameters
1040
+ this.setData(data);
1041
+ var options = this.getData();
1042
+ // redraw block
1043
+ var block_template = Handlebars.compile($('form_template_block').innerHTML),
1044
+ template = Handlebars.compile($('form_template_' + options.type).innerHTML),
1045
+ data = $H(options).merge({
1046
+ template: template(options)
1047
+ }).toObject();
1048
+ this.element.replace(block_template(data));
1049
+
1050
+ WysijaForm.init();
1051
+ },
1052
+ editSettings: function() {
1053
+ MailPoet.Modal.popup({
1054
+ title: MailPoet.I18n.t('editFieldSettings'),
1055
+ template: jQuery('#form_template_field_settings').html(),
1056
+ data: this.getData(),
1057
+ onSuccess: function() {
1058
+ var data = jQuery('#form_field_settings').serializeObject();
1059
+ this.redraw(data);
1060
+ }.bind(this)
1061
+ });
1062
+ },
1063
+ getSettings: function() {
1064
+ return this.element.down('.wysija_settings');
1065
+ }
1066
+ });
1067
+
1068
+ /* When dom is loaded, initialize WysijaForm */
1069
+ document.observe('dom:loaded', WysijaForm.init);
1070
+
1071
+ /* LOGGING */
1072
+ function info(value) {
1073
+ if(WysijaForm.options.debug === false) return;
1074
+
1075
+ if(!(window.console && console.log)) {
1076
+ (function() {
1077
+ var noop = function() {};
1078
+ var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
1079
+ var length = methods.length;
1080
+ window.console = {};
1081
+ var console = {};
1082
+ while(length--) {
1083
+ console[methods[length]] = noop;
1084
+ }
1085
+ }());
1086
+ }
1087
+ try {
1088
+ console.log('[DEBUG] ' + value);
1089
+ } catch(e) {}
1090
+ }
1091
+
1092
+ module.exports = WysijaForm;
1093
 
1094
 
1095
  /***/ },
6283
  var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
6284
  if (split) {
6285
  for (var i = split.length - 1; i >= 0; --i)
6286
+ { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}); }
6287
  } else {
6288
  makeChangeInner(doc, change);
6289
  }
10007
  var markerID = node.getAttribute("cm-marker"), range$$1;
10008
  if (markerID) {
10009
  var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
10010
+ if (found.length && (range$$1 = found[0].find(0)))
10011
  { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); }
10012
  return
10013
  }
10591
 
10592
  addLegacyProps(CodeMirror$1);
10593
 
10594
+ CodeMirror$1.version = "5.29.0";
10595
 
10596
  return CodeMirror$1;
10597
 
10988
  style = style[0];
10989
  }
10990
  override = style;
10991
+ if (type != "comment")
10992
+ state.state = states[state.state](type, stream, state);
10993
  return override;
10994
  },
10995
 
assets/js/lib/mailpoet_shortcodes/plugin.js CHANGED
@@ -46,8 +46,8 @@ tinymce.PluginManager.add('mailpoet_shortcodes', function(editor, url) {
46
 
47
  // Open window
48
  editor.windowManager.open({
49
- height: parseInt(editor.getParam("plugin_mailpoet_shortcodes_height", 400)),
50
- width: parseInt(editor.getParam("plugin_mailpoet_shortcodes_width", 450)),
51
  autoScroll: true,
52
  title: editor.settings.mailpoet_shortcodes_window_title,
53
  body: shortcodes,
46
 
47
  // Open window
48
  editor.windowManager.open({
49
+ height: parseInt(editor.getParam('plugin_mailpoet_shortcodes_height', 400)),
50
+ width: parseInt(editor.getParam('plugin_mailpoet_shortcodes_width', 450)),
51
  autoScroll: true,
52
  title: editor.settings.mailpoet_shortcodes_window_title,
53
  body: shortcodes,
assets/js/{mailpoet.28805a4f.js → mailpoet.a3939b7d.js} RENAMED
@@ -39765,18 +39765,18 @@ webpackJsonp([3],[
39765
  var tooltipId = props.tooltipId;
39766
  var tooltip = props.tooltip;
39767
  // tooltip ID must be unique, defaults to tooltip text
39768
- if (!props.tooltipId && typeof props.tooltip === "string") {
39769
  tooltipId = props.tooltip;
39770
  }
39771
 
39772
- if (typeof props.tooltip === "string") {
39773
  tooltip = _react2['default'].createElement(
39774
  'span',
39775
  {
39776
  style: {
39777
- pointerEvents: "all",
39778
- maxWidth: "400",
39779
- display: "inline-block"
39780
  }
39781
  },
39782
  (0, _reactHtmlParser2['default'])(props.tooltip)
@@ -39788,7 +39788,7 @@ webpackJsonp([3],[
39788
  { className: props.className },
39789
  _react2['default'].createElement('span', {
39790
  style: {
39791
- cursor: "pointer"
39792
  },
39793
  className: 'tooltip dashicons dashicons-editor-help',
39794
  'data-event': 'click',
@@ -49889,7 +49889,7 @@ webpackJsonp([3],[
49889
  if (xhr.responseJSON) {
49890
  return xhr.responseJSON;
49891
  }
49892
- var message = errorMessage.replace("%d", xhr.status);
49893
  return {
49894
  errors: [
49895
  {
@@ -50166,7 +50166,7 @@ webpackJsonp([3],[
50166
  translations[key] = value;
50167
  },
50168
  t: function(key) {
50169
- return translations[key] || 'TRANSLATION "%$1s" NOT FOUND'.replace("%$1s", key);
50170
  },
50171
  all: function() {
50172
  return translations;
@@ -50490,7 +50490,6 @@ webpackJsonp([3],[
50490
  setDimensions: function() {
50491
  switch(this.options.type) {
50492
  case 'popup':
50493
- console.log(this.options)
50494
  // set popup dimensions
50495
  jQuery('#mailpoet_popup').css({
50496
  width: this.options.width,
@@ -50830,7 +50829,7 @@ webpackJsonp([3],[
50830
  /***/ function(module, exports, __webpack_require__) {
50831
 
50832
  var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(274), __webpack_require__(273)], __WEBPACK_AMD_DEFINE_RESULT__ = function(mp, jQuery) {
50833
- "use strict";
50834
  /*==================================================================================================
50835
 
50836
  MailPoet Notice:
@@ -50955,7 +50954,7 @@ webpackJsonp([3],[
50955
  if (
50956
  this.options.id !== null
50957
  &&
50958
- jQuery('[data-id="'+this.options.id+'"').length > 0
50959
  ) {
50960
  this.updateNotice();
50961
  } else {
@@ -51102,7 +51101,7 @@ webpackJsonp([3],[
51102
  */
51103
  $.fn.serializeObject = function(coerce) {
51104
  var obj = {},
51105
- coerce_types = { 'true': !0, 'false': !1, 'null': null };
51106
 
51107
  // Iterate over all name=value pairs.
51108
  $.each( this.serializeArray(), function(j, v){
@@ -53677,7 +53676,7 @@ webpackJsonp([3],[
53677
  var eventsCache = [];
53678
 
53679
  function track(name, data){
53680
- if (typeof window.mixpanel.track !== "function") {
53681
  window.mixpanel.init(window.mixpanelTrackingId);
53682
  }
53683
  window.mixpanel.track(name, data);
@@ -53703,7 +53702,7 @@ webpackJsonp([3],[
53703
  }
53704
 
53705
  function initializeMixpanelWhenLoaded() {
53706
- if (typeof window.mixpanel === "object") {
53707
  exportMixpanel(MailPoet);
53708
  trackCachedEvents();
53709
  } else {
39765
  var tooltipId = props.tooltipId;
39766
  var tooltip = props.tooltip;
39767
  // tooltip ID must be unique, defaults to tooltip text
39768
+ if (!props.tooltipId && typeof props.tooltip === 'string') {
39769
  tooltipId = props.tooltip;
39770
  }
39771
 
39772
+ if (typeof props.tooltip === 'string') {
39773
  tooltip = _react2['default'].createElement(
39774
  'span',
39775
  {
39776
  style: {
39777
+ pointerEvents: 'all',
39778
+ maxWidth: '400',
39779
+ display: 'inline-block'
39780
  }
39781
  },
39782
  (0, _reactHtmlParser2['default'])(props.tooltip)
39788
  { className: props.className },
39789
  _react2['default'].createElement('span', {
39790
  style: {
39791
+ cursor: 'pointer'
39792
  },
39793
  className: 'tooltip dashicons dashicons-editor-help',
39794
  'data-event': 'click',
49889
  if (xhr.responseJSON) {
49890
  return xhr.responseJSON;
49891
  }
49892
+ var message = errorMessage.replace('%d', xhr.status);
49893
  return {
49894
  errors: [
49895
  {
50166
  translations[key] = value;
50167
  },
50168
  t: function(key) {
50169
+ return translations[key] || 'TRANSLATION "%$1s" NOT FOUND'.replace('%$1s', key);
50170
  },
50171
  all: function() {
50172
  return translations;
50490
  setDimensions: function() {
50491
  switch(this.options.type) {
50492
  case 'popup':
 
50493
  // set popup dimensions
50494
  jQuery('#mailpoet_popup').css({
50495
  width: this.options.width,
50829
  /***/ function(module, exports, __webpack_require__) {
50830
 
50831
  var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(274), __webpack_require__(273)], __WEBPACK_AMD_DEFINE_RESULT__ = function(mp, jQuery) {
50832
+ 'use strict';
50833
  /*==================================================================================================
50834
 
50835
  MailPoet Notice:
50954
  if (
50955
  this.options.id !== null
50956
  &&
50957
+ jQuery('[data-id="'+this.options.id+'"]').length > 0
50958
  ) {
50959
  this.updateNotice();
50960
  } else {
51101
  */
51102
  $.fn.serializeObject = function(coerce) {
51103
  var obj = {},
51104
+ coerce_types = { true: !0, false: !1, null: null };
51105
 
51106
  // Iterate over all name=value pairs.
51107
  $.each( this.serializeArray(), function(j, v){
53676
  var eventsCache = [];
53677
 
53678
  function track(name, data){
53679
+ if (typeof window.mixpanel.track !== 'function') {
53680
  window.mixpanel.init(window.mixpanelTrackingId);
53681
  }
53682
  window.mixpanel.track(name, data);
53702
  }
53703
 
53704
  function initializeMixpanelWhenLoaded() {
53705
+ if (typeof window.mixpanel === 'object') {
53706
  exportMixpanel(MailPoet);
53707
  trackCachedEvents();
53708
  } else {
assets/js/manifest.json CHANGED
@@ -1,10 +1,10 @@
1
  {
2
- "mp2migrator.js": "mp2migrator.d958f0f5.js",
3
- "public.js": "public.412ca9cc.js",
4
- "admin.js": "admin.d56f9a3d.js",
5
- "admin_vendor.js": "admin_vendor.aaf3acee.js",
6
- "form_editor.js": "form_editor.4d117b35.js",
7
- "mailpoet.js": "mailpoet.28805a4f.js",
8
- "newsletter_editor.js": "newsletter_editor.a3d00b84.js",
9
- "vendor.js": "vendor.016cb65c.js"
10
  }
1
  {
2
+ "mp2migrator.js": "mp2migrator.f1fb2656.js",
3
+ "public.js": "public.15490850.js",
4
+ "admin.js": "admin.36b0c17d.js",
5
+ "admin_vendor.js": "admin_vendor.71d84e79.js",
6
+ "form_editor.js": "form_editor.92c760ec.js",
7
+ "mailpoet.js": "mailpoet.a3939b7d.js",
8
+ "newsletter_editor.js": "newsletter_editor.dabd6b50.js",
9
+ "vendor.js": "vendor.aecfe832.js"
10
  }
assets/js/{mp2migrator.d958f0f5.js → mp2migrator.f1fb2656.js} RENAMED
@@ -81,8 +81,8 @@
81
  url: mailpoet_mp2_migrator.log_file_url,
82
  cache: false
83
  }).done(function (result) {
84
- jQuery("#logger").html('');
85
- result.split("\n").forEach(function (resultRow) {
86
  var row = resultRow;
87
  if(row.substr(0, 7) === '[ERROR]' || row.substr(0, 9) === '[WARNING]' || row === MailPoet.I18n.t('import_stopped_by_user')) {
88
  row = '<span class="error_msg">' + row + '</span>'; // Mark the errors in red
@@ -92,10 +92,10 @@
92
  jQuery('#import-actions').hide();
93
  jQuery('#upgrade-completed').show();
94
  }
95
- jQuery("#logger").append(row + "<br />\n");
96
 
97
  });
98
- jQuery("#logger").append('<span class="error_msg">' + MailPoet.MP2Migrator.fatal_error + '</span>' + "<br />\n");
99
  }).always(function () {
100
  if(MailPoet.MP2Migrator.is_logging) {
101
  MailPoet.MP2Migrator.displayLogs_timeout = setTimeout(MailPoet.MP2Migrator.displayLogs, 1000);
81
  url: mailpoet_mp2_migrator.log_file_url,
82
  cache: false
83
  }).done(function (result) {
84
+ jQuery('#logger').html('');
85
+ result.split('\n').forEach(function (resultRow) {
86
  var row = resultRow;
87
  if(row.substr(0, 7) === '[ERROR]' || row.substr(0, 9) === '[WARNING]' || row === MailPoet.I18n.t('import_stopped_by_user')) {
88
  row = '<span class="error_msg">' + row + '</span>'; // Mark the errors in red
92
  jQuery('#import-actions').hide();
93
  jQuery('#upgrade-completed').show();
94
  }
95
+ jQuery('#logger').append(row + '<br />\n');
96
 
97
  });
98
+ jQuery('#logger').append('<span class="error_msg">' + MailPoet.MP2Migrator.fatal_error + '</span>' + '<br />\n');
99
  }).always(function () {
100
  if(MailPoet.MP2Migrator.is_logging) {
101
  MailPoet.MP2Migrator.displayLogs_timeout = setTimeout(MailPoet.MP2Migrator.displayLogs, 1000);
assets/js/{newsletter_editor.a3d00b84.js → newsletter_editor.dabd6b50.js} RENAMED
@@ -9417,7 +9417,7 @@ webpackJsonp([4],{
9417
  if (xhr.responseJSON) {
9418
  return xhr.responseJSON;
9419
  }
9420
- var message = errorMessage.replace("%d", xhr.status);
9421
  return {
9422
  errors: [
9423
  {
@@ -9816,7 +9816,6 @@ webpackJsonp([4],{
9816
  setDimensions: function() {
9817
  switch(this.options.type) {
9818
  case 'popup':
9819
- console.log(this.options)
9820
  // set popup dimensions
9821
  jQuery('#mailpoet_popup').css({
9822
  width: this.options.width,
@@ -10157,7 +10156,7 @@ webpackJsonp([4],{
10157
  /***/ function(module, exports, __webpack_require__) {
10158
 
10159
  var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(274), __webpack_require__(273)], __WEBPACK_AMD_DEFINE_RESULT__ = function(mp, jQuery) {
10160
- "use strict";
10161
  /*==================================================================================================
10162
 
10163
  MailPoet Notice:
@@ -10282,7 +10281,7 @@ webpackJsonp([4],{
10282
  if (
10283
  this.options.id !== null
10284
  &&
10285
- jQuery('[data-id="'+this.options.id+'"').length > 0
10286
  ) {
10287
  this.updateNotice();
10288
  } else {
@@ -27705,7 +27704,7 @@ webpackJsonp([4],{
27705
  __webpack_require__(565)
27706
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, Marionette, SuperModel) {
27707
 
27708
- "use strict";
27709
 
27710
  var Module = {};
27711
 
@@ -27750,7 +27749,7 @@ webpackJsonp([4],{
27750
  Module.StylesView = Marionette.View.extend({
27751
  getTemplate: function() { return templates.styles; },
27752
  modelEvents: {
27753
- 'change': 'render'
27754
  },
27755
  serializeData: function() {
27756
  return this.model.toJSON();
@@ -27817,7 +27816,7 @@ webpackJsonp([4],{
27817
  StickyKit
27818
  ) {
27819
 
27820
- "use strict";
27821
 
27822
  var Module = {};
27823
 
@@ -27866,7 +27865,7 @@ webpackJsonp([4],{
27866
  'slideUp',
27867
  {
27868
  duration: 250,
27869
- easing: "easeOut",
27870
  complete: function() {
27871
  $openRegion.addClass('closed');
27872
  }.bind(this)
@@ -27878,7 +27877,7 @@ webpackJsonp([4],{
27878
  'slideDown',
27879
  {
27880
  duration: 250,
27881
- easing: "easeIn",
27882
  complete: function() {
27883
  $targetRegion.removeClass('closed');
27884
  }
@@ -27977,40 +27976,40 @@ webpackJsonp([4],{
27977
  },
27978
  events: function() {
27979
  return {
27980
- "change #mailpoet_text_font_color": _.partial(this.changeColorField, 'text.fontColor'),
27981
- "change #mailpoet_text_font_family": function(event) {
27982
  this.model.set('text.fontFamily', event.target.value);
27983
  },
27984
- "change #mailpoet_text_font_size": function(event) {
27985
  this.model.set('text.fontSize', event.target.value);
27986
  },
27987
- "change #mailpoet_h1_font_color": _.partial(this.changeColorField, 'h1.fontColor'),
27988
- "change #mailpoet_h1_font_family": function(event) {
27989
  this.model.set('h1.fontFamily', event.target.value);
27990
  },
27991
- "change #mailpoet_h1_font_size": function(event) {
27992
  this.model.set('h1.fontSize', event.target.value);
27993
  },
27994
- "change #mailpoet_h2_font_color": _.partial(this.changeColorField, 'h2.fontColor'),
27995
- "change #mailpoet_h2_font_family": function(event) {
27996
  this.model.set('h2.fontFamily', event.target.value);
27997
  },
27998
- "change #mailpoet_h2_font_size": function(event) {
27999
  this.model.set('h2.fontSize', event.target.value);
28000
  },
28001
- "change #mailpoet_h3_font_color": _.partial(this.changeColorField, 'h3.fontColor'),
28002
- "change #mailpoet_h3_font_family": function(event) {
28003
  this.model.set('h3.fontFamily', event.target.value);
28004
  },
28005
- "change #mailpoet_h3_font_size": function(event) {
28006
  this.model.set('h3.fontSize', event.target.value);
28007
  },
28008
- "change #mailpoet_a_font_color": _.partial(this.changeColorField, 'link.fontColor'),
28009
- "change #mailpoet_a_font_underline": function(event) {
28010
  this.model.set('link.textDecoration', (event.target.checked) ? event.target.value : 'none');
28011
  },
28012
- "change #mailpoet_newsletter_background_color": _.partial(this.changeColorField, 'wrapper.backgroundColor'),
28013
- "change #mailpoet_background_color": _.partial(this.changeColorField, 'body.backgroundColor')
28014
  };
28015
  },
28016
  templateContext: function() {
@@ -28118,10 +28117,7 @@ webpackJsonp([4],{
28118
  MailPoet.Modal.loading(true);
28119
 
28120
  // save before sending
28121
- var saveResult = {promise: null};
28122
- App.getChannel().trigger('save', saveResult);
28123
-
28124
- saveResult.promise.always(function() {
28125
  CommunicationComponent.previewNewsletter(data).always(function() {
28126
  MailPoet.Modal.loading(false);
28127
  }).done(function(response) {
@@ -28210,7 +28206,7 @@ webpackJsonp([4],{
28210
  __webpack_require__(278),
28211
  __webpack_require__(274)
28212
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, SuperModel, _, MailPoet) {
28213
- "use strict";
28214
 
28215
  var Module = {};
28216
 
@@ -28240,14 +28236,14 @@ webpackJsonp([4],{
28240
  if (type in Module._blockTypes) {
28241
  return Module._blockTypes[type].blockModel;
28242
  } else {
28243
- throw "Block type not supported: " + type;
28244
  }
28245
  };
28246
  Module.getBlockTypeView = function(type) {
28247
  if (type in Module._blockTypes) {
28248
  return Module._blockTypes[type].blockView;
28249
  } else {
28250
- throw "Block type not supported: " + type;
28251
  }
28252
  };
28253
 
@@ -28326,7 +28322,7 @@ webpackJsonp([4],{
28326
  __webpack_require__(273)
28327
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, Backbone, Marionette, _, jQuery) {
28328
 
28329
- "use strict";
28330
 
28331
  var Module = {};
28332
 
@@ -28339,8 +28335,8 @@ webpackJsonp([4],{
28339
  },
28340
  events: function() {
28341
  return {
28342
- 'keyup .mailpoet_input_title': _.partial(this.changeField, "subject"),
28343
- 'keyup .mailpoet_input_preheader': _.partial(this.changeField, "preheader")
28344
  };
28345
  },
28346
  changeField: function(field, event) {
@@ -28353,7 +28349,7 @@ webpackJsonp([4],{
28353
  MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-subject-line'), {
28354
  tooltipId: 'tooltip-designer-subject-line-ti',
28355
  tooltip: MailPoet.I18n.t('helpTooltipDesignerSubjectLine'),
28356
- place: "right"
28357
  });
28358
  MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-preheader'), {
28359
  tooltipId: 'tooltip-designer-preheader-ti',
@@ -28394,7 +28390,7 @@ webpackJsonp([4],{
28394
  html2canvas
28395
  ) {
28396
 
28397
- "use strict";
28398
 
28399
  var Module = {},
28400
  saveTimeout;
@@ -28437,15 +28433,6 @@ webpackJsonp([4],{
28437
  });
28438
  };
28439
 
28440
- // For getting a promise after triggering save event
28441
- Module.saveAndProvidePromise = function(saveResult) {
28442
- var result = saveResult;
28443
- var promise = Module.save();
28444
- if (saveResult !== undefined) {
28445
- result.promise = promise;
28446
- }
28447
- };
28448
-
28449
  Module.getThumbnail = function(element, options) {
28450
  var promise = html2canvas(element, options || {});
28451
 
@@ -28454,8 +28441,8 @@ webpackJsonp([4],{
28454
  // Removes 1px left transparent border from resulting canvas.
28455
 
28456
  var oldContext = oldCanvas.getContext('2d'),
28457
- newCanvas = document.createElement("canvas"),
28458
- newContext = newCanvas.getContext("2d"),
28459
  leftBorderWidth = 1;
28460
 
28461
  newCanvas.width = oldCanvas.width;
@@ -28541,7 +28528,7 @@ webpackJsonp([4],{
28541
  },
28542
  save: function() {
28543
  this.hideOptionContents();
28544
- App.getChannel().trigger('save');
28545
  },
28546
  beforeSave: function() {
28547
  // TODO: Add a loading animation instead
@@ -28661,7 +28648,10 @@ webpackJsonp([4],{
28661
  next: function() {
28662
  this.hideOptionContents();
28663
  if(!this.$('.mailpoet_save_next').hasClass('button-disabled')) {
28664
- window.location.href = App.getConfig().get('urls.send');
 
 
 
28665
  }
28666
  },
28667
  validateNewsletter: function(jsonObject) {
@@ -28672,8 +28662,8 @@ webpackJsonp([4],{
28672
 
28673
  var contents = JSON.stringify(jsonObject);
28674
  if (App.getConfig().get('validation.validateUnsubscribeLinkPresent') &&
28675
- contents.indexOf("[link:subscription_unsubscribe_url]") < 0 &&
28676
- contents.indexOf("[link:subscription_unsubscribe]") < 0) {
28677
  this.showValidationError(MailPoet.I18n.t('unsubscribeLinkMissing'));
28678
  return;
28679
  }
@@ -28698,15 +28688,21 @@ webpackJsonp([4],{
28698
  // may be requested
28699
  var AUTOSAVE_DELAY_DURATION = 1000;
28700
 
28701
- // Cancel save timer if another change happens before it completes
28702
- if (saveTimeout) clearTimeout(saveTimeout);
28703
  saveTimeout = setTimeout(function() {
28704
- App.getChannel().trigger('save');
28705
- clearTimeout(saveTimeout);
28706
- saveTimeout = undefined;
28707
  }, AUTOSAVE_DELAY_DURATION);
28708
  };
28709
 
 
 
 
 
 
 
 
28710
  Module.beforeExitWithUnsavedChanges = function(e) {
28711
  if (saveTimeout) {
28712
  var message = MailPoet.I18n.t('unsavedChangesWillBeLost');
@@ -28722,12 +28718,12 @@ webpackJsonp([4],{
28722
 
28723
  App.on('before:start', function(App, options) {
28724
  var Application = App;
28725
- Application.save = Module.saveAndProvidePromise;
28726
  Application.getChannel().on('autoSave', Module.autoSave);
28727
 
28728
  window.onbeforeunload = Module.beforeExitWithUnsavedChanges;
28729
 
28730
- Application.getChannel().on('save', function(saveResult) { Application.save(saveResult); });
28731
  });
28732
 
28733
  App.on('start', function(App, options) {
@@ -33338,7 +33334,7 @@ webpackJsonp([4],{
33338
  clickoutFiresChange: true,
33339
  showInput: true,
33340
  showInitial: true,
33341
- preferredFormat: "hex6",
33342
  allowEmpty: true,
33343
  chooseText: MailPoet.I18n.t('selectColor'),
33344
  cancelText: MailPoet.I18n.t('cancelColorSelection')
@@ -33965,8 +33961,8 @@ webpackJsonp([4],{
33965
 
33966
  BL.HighlightEditingBehavior = Marionette.Behavior.extend({
33967
  modelEvents: {
33968
- 'startEditing': 'enableHighlight',
33969
- 'stopEditing': 'disableHighlight'
33970
  },
33971
  enableHighlight: function() {
33972
  this.$el.addClass('mailpoet_highlight');
@@ -34004,8 +34000,8 @@ webpackJsonp([4],{
34004
  modelField: 'styles.block.height'
34005
  },
34006
  events: {
34007
- "mouseenter": 'showResizeHandle',
34008
- "mouseleave": 'hideResizeHandle'
34009
  },
34010
  onRender: function() {
34011
  this.attachResize();
@@ -34077,7 +34073,7 @@ webpackJsonp([4],{
34077
 
34078
  if (_.isFunction(this.$el.sortable)) {
34079
  this.$el.sortable({
34080
- cursor: "move",
34081
  start: function(event, ui) {
34082
  ui.item.data('previousIndex', ui.item.index());
34083
  },
@@ -34161,12 +34157,12 @@ webpackJsonp([4],{
34161
  BL.TextEditorBehavior = Marionette.Behavior.extend({
34162
  defaults: {
34163
  selector: '.mailpoet_content',
34164
- toolbar1: "bold italic link unlink forecolor mailpoet_shortcodes",
34165
- toolbar2: "",
34166
- validElements: "p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br",
34167
- invalidElements: "script",
34168
  blockFormats: 'Paragraph=p',
34169
- plugins: "link textcolor colorpicker mailpoet_shortcodes",
34170
  configurationFilter: function(originalConfig) { return originalConfig; }
34171
  },
34172
  onDomRefresh: function() {
@@ -34253,7 +34249,7 @@ webpackJsonp([4],{
34253
  __webpack_require__(556)
34254
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, Marionette, SuperModel, _, jQuery, MailPoet, Modal) {
34255
 
34256
- "use strict";
34257
 
34258
  var Module = {},
34259
  AugmentedView = Marionette.View.extend({});
@@ -34289,13 +34285,13 @@ webpackJsonp([4],{
34289
  toolsRegion: '> .mailpoet_tools'
34290
  },
34291
  modelEvents: {
34292
- 'change': 'render',
34293
- 'delete': 'deleteBlock',
34294
- 'duplicate': 'duplicateBlock'
34295
  },
34296
  events: {
34297
- "mouseenter": "showTools",
34298
- "mouseleave": "hideTools"
34299
  },
34300
  behaviors: {
34301
  DraggableBehavior: {
@@ -34419,11 +34415,11 @@ webpackJsonp([4],{
34419
  Module.BlockToolsView = AugmentedView.extend({
34420
  getTemplate: function() { return templates.genericBlockTools; },
34421
  events: {
34422
- "click .mailpoet_edit_block": "changeSettings",
34423
- "click .mailpoet_delete_block_activate": "showDeletionConfirmation",
34424
- "click .mailpoet_delete_block_cancel": "hideDeletionConfirmation",
34425
- "click .mailpoet_delete_block_confirm": "deleteBlock",
34426
- "click .mailpoet_duplicate_block": "duplicateBlock"
34427
  },
34428
  // Markers of whether these particular tools will be used for this instance
34429
  tools: {
@@ -34537,7 +34533,7 @@ webpackJsonp([4],{
34537
  behaviors: {
34538
  DraggableBehavior: {
34539
  drop: function() {
34540
- throw "Unsupported operation";
34541
  }
34542
  }
34543
  }
@@ -34566,7 +34562,7 @@ webpackJsonp([4],{
34566
  __webpack_require__(595)
34567
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(Backbone, Marionette, _, jQuery, App, BaseBlock) {
34568
 
34569
- "use strict";
34570
 
34571
  var Module = {},
34572
  base = BaseBlock,
@@ -34659,7 +34655,7 @@ webpackJsonp([4],{
34659
  className: 'mailpoet_block mailpoet_container_block mailpoet_droppable_block mailpoet_droppable_layout_block',
34660
  getTemplate: function() { return templates.containerBlock; },
34661
  events: _.extend({}, base.BlockView.prototype.events, {
34662
- "click .mailpoet_newsletter_layer_selector": "toggleEditingLayer"
34663
  }),
34664
  ui: {
34665
  tools: '> .mailpoet_tools'
@@ -34791,8 +34787,8 @@ webpackJsonp([4],{
34791
  getTemplate: function() { return templates.containerBlockSettings; },
34792
  events: function() {
34793
  return {
34794
- "change .mailpoet_field_container_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
34795
- "click .mailpoet_done_editing": "close"
34796
  };
34797
  },
34798
  regions: {
@@ -34934,7 +34930,7 @@ webpackJsonp([4],{
34934
  __webpack_require__(273)
34935
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, MailPoet, _, jQuery) {
34936
 
34937
- "use strict";
34938
 
34939
  var Module = {},
34940
  base = BaseBlock;
@@ -34966,7 +34962,7 @@ webpackJsonp([4],{
34966
  });
34967
 
34968
  Module.ButtonBlockView = base.BlockView.extend({
34969
- className: "mailpoet_block mailpoet_button_block mailpoet_droppable_block",
34970
  getTemplate: function() { return templates.buttonBlock; },
34971
  onDragSubstituteBy: function() { return Module.ButtonWidgetView; },
34972
  behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
@@ -34993,34 +34989,34 @@ webpackJsonp([4],{
34993
  getTemplate: function() { return templates.buttonBlockSettings; },
34994
  events: function() {
34995
  return {
34996
- "input .mailpoet_field_button_text": _.partial(this.changeField, "text"),
34997
- "input .mailpoet_field_button_url": _.partial(this.changeField, "url"),
34998
- "change .mailpoet_field_button_alignment": _.partial(this.changeField, "styles.block.textAlign"),
34999
- "change .mailpoet_field_button_font_color": _.partial(this.changeColorField, "styles.block.fontColor"),
35000
- "change .mailpoet_field_button_font_family": _.partial(this.changeField, "styles.block.fontFamily"),
35001
- "change .mailpoet_field_button_font_size": _.partial(this.changeField, "styles.block.fontSize"),
35002
- "change .mailpoet_field_button_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
35003
- "change .mailpoet_field_button_border_color": _.partial(this.changeColorField, "styles.block.borderColor"),
35004
- "change .mailpoet_field_button_font_weight": "changeFontWeight",
35005
-
35006
- "input .mailpoet_field_button_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
35007
- "change .mailpoet_field_button_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
35008
- "input .mailpoet_field_button_border_width_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
35009
-
35010
- "input .mailpoet_field_button_border_radius": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius_input', _.partial(this.changePixelField, "styles.block.borderRadius").bind(this)),
35011
- "change .mailpoet_field_button_border_radius": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius_input', _.partial(this.changePixelField, "styles.block.borderRadius").bind(this)),
35012
- "input .mailpoet_field_button_border_radius_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius', _.partial(this.changePixelField, "styles.block.borderRadius").bind(this)),
35013
-
35014
- "input .mailpoet_field_button_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_width_input', _.partial(this.changePixelField, "styles.block.width").bind(this)),
35015
- "change .mailpoet_field_button_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_width_input', _.partial(this.changePixelField, "styles.block.width").bind(this)),
35016
- "input .mailpoet_field_button_width_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_width', _.partial(this.changePixelField, "styles.block.width").bind(this)),
35017
-
35018
- "input .mailpoet_field_button_line_height": _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height_input', _.partial(this.changePixelField, "styles.block.lineHeight").bind(this)),
35019
- "change .mailpoet_field_button_line_height": _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height_input', _.partial(this.changePixelField, "styles.block.lineHeight").bind(this)),
35020
- "input .mailpoet_field_button_line_height_input": _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height', _.partial(this.changePixelField, "styles.block.lineHeight").bind(this)),
35021
-
35022
- "click .mailpoet_field_button_replace_all_styles": "applyToAll",
35023
- "click .mailpoet_done_editing": "close"
35024
  };
35025
  },
35026
  templateContext: function() {
@@ -35089,7 +35085,7 @@ webpackJsonp([4],{
35089
  __webpack_require__(274)
35090
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, _, MailPoet) {
35091
 
35092
- "use strict";
35093
 
35094
  var Module = {},
35095
  base = BaseBlock,
@@ -35115,7 +35111,7 @@ webpackJsonp([4],{
35115
  });
35116
 
35117
  Module.ImageBlockView = base.BlockView.extend({
35118
- className: "mailpoet_block mailpoet_image_block mailpoet_droppable_block",
35119
  getTemplate: function() { return templates.imageBlock; },
35120
  onDragSubstituteBy: function() { return Module.ImageWidgetView; },
35121
  templateContext: function() {
@@ -35156,13 +35152,13 @@ webpackJsonp([4],{
35156
  getTemplate: function() { return templates.imageBlockSettings; },
35157
  events: function() {
35158
  return {
35159
- "input .mailpoet_field_image_link": _.partial(this.changeField, "link"),
35160
- "input .mailpoet_field_image_address": 'changeAddress',
35161
- "input .mailpoet_field_image_alt_text": _.partial(this.changeField, "alt"),
35162
- "change .mailpoet_field_image_full_width": _.partial(this.changeBoolCheckboxField, "fullWidth"),
35163
- "change .mailpoet_field_image_alignment": _.partial(this.changeField, "styles.block.textAlign"),
35164
- "click .mailpoet_field_image_select_another_image": "showMediaManager",
35165
- "click .mailpoet_done_editing": "close"
35166
  };
35167
  },
35168
  initialize: function(options) {
@@ -35258,7 +35254,7 @@ webpackJsonp([4],{
35258
 
35259
  var handlers = {
35260
  content: {
35261
- 'embed': 'embedContent',
35262
  'edit-selection': 'editSelectionContent'
35263
  },
35264
  toolbar: {
@@ -35412,7 +35408,7 @@ webpackJsonp([4],{
35412
  height: mainSize.height + 'px',
35413
  width: mainSize.width + 'px',
35414
  src: mainSize.url,
35415
- alt: (attachment.get('alt') !== "" && attachment.get('alt') !== undefined) ? attachment.get('alt') : attachment.get('title')
35416
  });
35417
  // Rerender settings view due to changes from outside of settings view
35418
  that.render();
@@ -35492,7 +35488,7 @@ webpackJsonp([4],{
35492
  __webpack_require__(274)
35493
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, _, jQuery, MailPoet) {
35494
 
35495
- "use strict";
35496
 
35497
  var Module = {},
35498
  base = BaseBlock;
@@ -35515,7 +35511,7 @@ webpackJsonp([4],{
35515
  });
35516
 
35517
  Module.DividerBlockView = base.BlockView.extend({
35518
- className: "mailpoet_block mailpoet_divider_block mailpoet_droppable_block",
35519
  getTemplate: function() { return templates.dividerBlock; },
35520
  modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'),
35521
  behaviors: _.defaults({
@@ -35570,16 +35566,16 @@ webpackJsonp([4],{
35570
  getTemplate: function() { return templates.dividerBlockSettings; },
35571
  events: function() {
35572
  return {
35573
- "click .mailpoet_field_divider_style": 'changeStyle',
35574
 
35575
- "input .mailpoet_field_divider_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
35576
- "change .mailpoet_field_divider_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
35577
- "input .mailpoet_field_divider_border_width_input": _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
35578
 
35579
- "change .mailpoet_field_divider_border_color": _.partial(this.changeColorField, "styles.block.borderColor"),
35580
- "change .mailpoet_field_divider_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
35581
- "click .mailpoet_button_divider_apply_to_all": "applyToAll",
35582
- "click .mailpoet_done_editing": "close"
35583
  };
35584
  },
35585
  modelEvents: function() {
@@ -35653,7 +35649,7 @@ webpackJsonp([4],{
35653
  __webpack_require__(278)
35654
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, _) {
35655
 
35656
- "use strict";
35657
 
35658
  var Module = {},
35659
  base = BaseBlock;
@@ -35668,17 +35664,17 @@ webpackJsonp([4],{
35668
  });
35669
 
35670
  Module.TextBlockView = base.BlockView.extend({
35671
- className: "mailpoet_block mailpoet_text_block mailpoet_droppable_block",
35672
  getTemplate: function() { return templates.textBlock; },
35673
  modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'), // Prevent rerendering on model change due to text editor redrawing
35674
  behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
35675
  TextEditorBehavior: {
35676
- toolbar1: "formatselect bold italic forecolor | link unlink",
35677
- toolbar2: "alignleft aligncenter alignright alignjustify | bullist numlist blockquote | code mailpoet_shortcodes",
35678
- validElements: "p[class|style],span[class|style],a[href|class|title|target|style],h1[class|style],h2[class|style],h3[class|style],ol[class|style],ul[class|style],li[class|style],strong[class|style],em[class|style],strike,br,blockquote[class|style],table[class|style],tr[class|style],th[class|style],td[class|style]",
35679
- invalidElements: "script",
35680
  blockFormats: 'Heading 1=h1;Heading 2=h2;Heading 3=h3;Paragraph=p',
35681
- plugins: "link lists code textcolor colorpicker mailpoet_shortcodes paste",
35682
  configurationFilter: function(originalSettings) {
35683
  return _.extend({}, originalSettings, {
35684
  mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
@@ -35771,7 +35767,7 @@ webpackJsonp([4],{
35771
  __webpack_require__(278)
35772
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, _) {
35773
 
35774
- "use strict";
35775
 
35776
  var Module = {},
35777
  base = BaseBlock;
@@ -35791,7 +35787,7 @@ webpackJsonp([4],{
35791
  });
35792
 
35793
  Module.SpacerBlockView = base.BlockView.extend({
35794
- className: "mailpoet_block mailpoet_spacer_block mailpoet_droppable_block",
35795
  getTemplate: function() { return templates.spacerBlock; },
35796
  behaviors: _.defaults({
35797
  ResizableBehavior: {
@@ -35833,8 +35829,8 @@ webpackJsonp([4],{
35833
  getTemplate: function() { return templates.spacerBlockSettings; },
35834
  events: function() {
35835
  return {
35836
- "change .mailpoet_field_spacer_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
35837
- "click .mailpoet_done_editing": "close"
35838
  };
35839
  }
35840
  });
@@ -35882,7 +35878,7 @@ webpackJsonp([4],{
35882
  __webpack_require__(278)
35883
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, _) {
35884
 
35885
- "use strict";
35886
 
35887
  var Module = {},
35888
  base = BaseBlock;
@@ -35912,7 +35908,7 @@ webpackJsonp([4],{
35912
  });
35913
 
35914
  Module.FooterBlockView = base.BlockView.extend({
35915
- className: "mailpoet_block mailpoet_footer_block mailpoet_droppable_block",
35916
  getTemplate: function() { return templates.footerBlock; },
35917
  modelEvents: _.extend({
35918
  'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render'
@@ -35953,16 +35949,16 @@ webpackJsonp([4],{
35953
  getTemplate: function() { return templates.footerBlockSettings; },
35954
  events: function() {
35955
  return {
35956
- "change .mailpoet_field_footer_text_color": _.partial(this.changeColorField, "styles.text.fontColor"),
35957
- "change .mailpoet_field_footer_text_font_family": _.partial(this.changeField, "styles.text.fontFamily"),
35958
- "change .mailpoet_field_footer_text_size": _.partial(this.changeField, "styles.text.fontSize"),
35959
- "change #mailpoet_field_footer_link_color": _.partial(this.changeColorField, "styles.link.fontColor"),
35960
- "change #mailpoet_field_footer_link_underline": function(event) {
35961
  this.model.set('styles.link.textDecoration', (event.target.checked) ? event.target.value : 'none');
35962
  },
35963
- "change .mailpoet_field_footer_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
35964
- "change .mailpoet_field_footer_alignment": _.partial(this.changeField, "styles.text.textAlign"),
35965
- "click .mailpoet_done_editing": "close"
35966
  };
35967
  },
35968
  templateContext: function() {
@@ -36015,7 +36011,7 @@ webpackJsonp([4],{
36015
  __webpack_require__(278)
36016
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, _) {
36017
 
36018
- "use strict";
36019
 
36020
  var Module = {},
36021
  base = BaseBlock;
@@ -36045,7 +36041,7 @@ webpackJsonp([4],{
36045
  });
36046
 
36047
  Module.HeaderBlockView = base.BlockView.extend({
36048
- className: "mailpoet_block mailpoet_header_block mailpoet_droppable_block",
36049
  getTemplate: function() { return templates.headerBlock; },
36050
  modelEvents: _.extend({
36051
  'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render'
@@ -36086,16 +36082,16 @@ webpackJsonp([4],{
36086
  getTemplate: function() { return templates.headerBlockSettings; },
36087
  events: function() {
36088
  return {
36089
- "change .mailpoet_field_header_text_color": _.partial(this.changeColorField, "styles.text.fontColor"),
36090
- "change .mailpoet_field_header_text_font_family": _.partial(this.changeField, "styles.text.fontFamily"),
36091
- "change .mailpoet_field_header_text_size": _.partial(this.changeField, "styles.text.fontSize"),
36092
- "change #mailpoet_field_header_link_color": _.partial(this.changeColorField, "styles.link.fontColor"),
36093
- "change #mailpoet_field_header_link_underline": function(event) {
36094
  this.model.set('styles.link.textDecoration', (event.target.checked) ? event.target.value : 'none');
36095
  },
36096
- "change .mailpoet_field_header_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
36097
- "change .mailpoet_field_header_alignment": _.partial(this.changeField, "styles.text.textAlign"),
36098
- "click .mailpoet_done_editing": "close"
36099
  };
36100
  },
36101
  templateContext: function() {
@@ -36169,7 +36165,7 @@ webpackJsonp([4],{
36169
  jQuery
36170
  ) {
36171
 
36172
- "use strict";
36173
 
36174
  var Module = {},
36175
  base = BaseBlock;
@@ -36269,12 +36265,12 @@ webpackJsonp([4],{
36269
  });
36270
 
36271
  Module.AutomatedLatestContentBlockView = base.BlockView.extend({
36272
- className: "mailpoet_block mailpoet_automated_latest_content_block mailpoet_droppable_block",
36273
  initialize: function() {
36274
  function replaceButtonStylesHandler(data) {
36275
- this.model.set({"readMoreButton": data});
36276
  }
36277
- App.getChannel().on("replaceAllButtonStyles", replaceButtonStylesHandler.bind(this));
36278
  },
36279
  getTemplate: function() { return templates.automatedLatestContentBlock; },
36280
  regions: {
@@ -36284,7 +36280,7 @@ webpackJsonp([4],{
36284
  modelEvents: _.extend(
36285
  _.omit(base.BlockView.prototype.modelEvents, 'change'),
36286
  {
36287
- 'postsChanged': 'render'
36288
  }),
36289
  events: _.extend(base.BlockView.prototype.events, {
36290
  'click .mailpoet_automated_latest_content_block_overlay': 'showSettings'
@@ -36312,28 +36308,28 @@ webpackJsonp([4],{
36312
  getTemplate: function() { return templates.automatedLatestContentBlockSettings; },
36313
  events: function() {
36314
  return {
36315
- "click .mailpoet_automated_latest_content_hide_display_options": 'toggleDisplayOptions',
36316
- "click .mailpoet_automated_latest_content_show_display_options": 'toggleDisplayOptions',
36317
- "click .mailpoet_automated_latest_content_select_button": 'showButtonSettings',
36318
- "click .mailpoet_automated_latest_content_select_divider": 'showDividerSettings',
36319
- "change .mailpoet_automated_latest_content_read_more_type": 'changeReadMoreType',
36320
- "change .mailpoet_automated_latest_content_display_type": 'changeDisplayType',
36321
- "change .mailpoet_automated_latest_content_title_format": 'changeTitleFormat',
36322
- "change .mailpoet_automated_latest_content_title_as_links": _.partial(this.changeBoolField, 'titleIsLink'),
36323
- "change .mailpoet_automated_latest_content_show_divider": _.partial(this.changeBoolField, 'showDivider'),
36324
- "input .mailpoet_automated_latest_content_show_amount": _.partial(this.changeField, "amount"),
36325
- "change .mailpoet_automated_latest_content_content_type": _.partial(this.changeField, "contentType"),
36326
- "change .mailpoet_automated_latest_content_include_or_exclude": _.partial(this.changeField, "inclusionType"),
36327
- "change .mailpoet_automated_latest_content_title_alignment": _.partial(this.changeField, "titleAlignment"),
36328
- "change .mailpoet_automated_latest_content_image_full_width": _.partial(this.changeBoolField, "imageFullWidth"),
36329
- "change .mailpoet_automated_latest_content_featured_image_position": _.partial(this.changeField, "featuredImagePosition"),
36330
- "change .mailpoet_automated_latest_content_show_author": _.partial(this.changeField, "showAuthor"),
36331
- "input .mailpoet_automated_latest_content_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"),
36332
- "change .mailpoet_automated_latest_content_show_categories": _.partial(this.changeField, "showCategories"),
36333
- "input .mailpoet_automated_latest_content_categories": _.partial(this.changeField, "categoriesPrecededBy"),
36334
- "input .mailpoet_automated_latest_content_read_more_text": _.partial(this.changeField, "readMoreText"),
36335
- "change .mailpoet_automated_latest_content_sort_by": _.partial(this.changeField, "sortBy"),
36336
- "click .mailpoet_done_editing": "close"
36337
  };
36338
  },
36339
  onRender: function() {
@@ -36586,7 +36582,7 @@ webpackJsonp([4],{
36586
  DividerBlock
36587
  ) {
36588
 
36589
- "use strict";
36590
 
36591
  var Module = {},
36592
  base = BaseBlock;
@@ -36725,7 +36721,7 @@ webpackJsonp([4],{
36725
  });
36726
 
36727
  Module.PostsBlockView = base.BlockView.extend({
36728
- className: "mailpoet_block mailpoet_posts_block mailpoet_droppable_block",
36729
  getTemplate: function() { return templates.postsBlock; },
36730
  modelEvents: {}, // Forcefully disable all events
36731
  regions: _.extend({
@@ -36845,7 +36841,7 @@ webpackJsonp([4],{
36845
  this.blockModel = options.blockModel;
36846
  },
36847
  events: {
36848
- 'scroll': 'onPostsScroll'
36849
  },
36850
  onPostsScroll: function(event) {
36851
  var $postsBox = jQuery(event.target);
@@ -36875,10 +36871,10 @@ webpackJsonp([4],{
36875
  this.$('.mailpoet_post_scroll_container').scrollTop(0);
36876
  }
36877
  },
36878
- 'loadingMorePosts': function() {
36879
  this.$('.mailpoet_post_selection_loading').css('visibility', 'visible');
36880
  },
36881
- 'morePostsLoaded': function() {
36882
  this.$('.mailpoet_post_selection_loading').css('visibility', 'hidden');
36883
  }
36884
  },
@@ -37011,25 +37007,25 @@ webpackJsonp([4],{
37011
  getTemplate: function() { return templates.displayOptionsPostsBlockSettings; },
37012
  events: function() {
37013
  return {
37014
- "click .mailpoet_posts_select_button": 'showButtonSettings',
37015
- "click .mailpoet_posts_select_divider": 'showDividerSettings',
37016
- "change .mailpoet_posts_read_more_type": 'changeReadMoreType',
37017
- "change .mailpoet_posts_display_type": 'changeDisplayType',
37018
- "change .mailpoet_posts_title_format": 'changeTitleFormat',
37019
- "change .mailpoet_posts_title_as_links": _.partial(this.changeBoolField, 'titleIsLink'),
37020
- "change .mailpoet_posts_show_divider": _.partial(this.changeBoolField, 'showDivider'),
37021
- "input .mailpoet_posts_show_amount": _.partial(this.changeField, "amount"),
37022
- "change .mailpoet_posts_content_type": _.partial(this.changeField, "contentType"),
37023
- "change .mailpoet_posts_include_or_exclude": _.partial(this.changeField, "inclusionType"),
37024
- "change .mailpoet_posts_title_alignment": _.partial(this.changeField, "titleAlignment"),
37025
- "change .mailpoet_posts_image_full_width": _.partial(this.changeBoolField, "imageFullWidth"),
37026
- "change .mailpoet_posts_featured_image_position": _.partial(this.changeField, "featuredImagePosition"),
37027
- "change .mailpoet_posts_show_author": _.partial(this.changeField, "showAuthor"),
37028
- "input .mailpoet_posts_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"),
37029
- "change .mailpoet_posts_show_categories": _.partial(this.changeField, "showCategories"),
37030
- "input .mailpoet_posts_categories": _.partial(this.changeField, "categoriesPrecededBy"),
37031
- "input .mailpoet_posts_read_more_text": _.partial(this.changeField, "readMoreText"),
37032
- "change .mailpoet_posts_sort_by": _.partial(this.changeField, "sortBy")
37033
  };
37034
  },
37035
  templateContext: function() {
@@ -37159,7 +37155,7 @@ webpackJsonp([4],{
37159
  __webpack_require__(273)
37160
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, Backbone, Marionette, SuperModel, _, jQuery) {
37161
 
37162
- "use strict";
37163
 
37164
  var Module = {},
37165
  base = BaseBlock,
@@ -37235,7 +37231,7 @@ webpackJsonp([4],{
37235
  tagName: 'span',
37236
  getTemplate: function() { return templates.socialIconBlock; },
37237
  modelEvents: {
37238
- 'change': 'render'
37239
  },
37240
  templateContext: function() {
37241
  var allIconSets = App.getAvailableStyles().get('socialIconSets');
@@ -37286,7 +37282,7 @@ webpackJsonp([4],{
37286
  },
37287
  events: function() {
37288
  return {
37289
- "click .mailpoet_done_editing": "close"
37290
  };
37291
  },
37292
  initialize: function() {
@@ -37306,11 +37302,11 @@ webpackJsonp([4],{
37306
  getTemplate: function() { return templates.socialSettingsIcon; },
37307
  events: function() {
37308
  return {
37309
- "click .mailpoet_delete_block": "deleteIcon",
37310
- "change .mailpoet_social_icon_field_type": _.partial(this.changeField, "iconType"),
37311
- "input .mailpoet_social_icon_field_image": _.partial(this.changeField, "image"),
37312
- "input .mailpoet_social_icon_field_link": this.changeLink,
37313
- "input .mailpoet_social_icon_field_text": _.partial(this.changeField, "text")
37314
  };
37315
  },
37316
  modelEvents: {
@@ -37362,7 +37358,7 @@ webpackJsonp([4],{
37362
  SocialBlockSettingsIconSelectorView = Marionette.View.extend({
37363
  getTemplate: function() { return templates.socialSettingsIconSelector; },
37364
  regions: {
37365
- 'icons': '#mailpoet_social_icon_selector_contents'
37366
  },
37367
  events: {
37368
  'click .mailpoet_add_social_icon': 'addSocialIcon'
@@ -37385,7 +37381,7 @@ webpackJsonp([4],{
37385
  SocialBlockSettingsStylesView = Marionette.View.extend({
37386
  getTemplate: function() { return templates.socialSettingsStyles; },
37387
  modelEvents: {
37388
- 'change': 'render'
37389
  },
37390
  events: {
37391
  'click .mailpoet_social_icon_set': 'changeSocialIconSet'
9417
  if (xhr.responseJSON) {
9418
  return xhr.responseJSON;
9419
  }
9420
+ var message = errorMessage.replace('%d', xhr.status);
9421
  return {
9422
  errors: [
9423
  {
9816
  setDimensions: function() {
9817
  switch(this.options.type) {
9818
  case 'popup':
 
9819
  // set popup dimensions
9820
  jQuery('#mailpoet_popup').css({
9821
  width: this.options.width,
10156
  /***/ function(module, exports, __webpack_require__) {
10157
 
10158
  var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(274), __webpack_require__(273)], __WEBPACK_AMD_DEFINE_RESULT__ = function(mp, jQuery) {
10159
+ 'use strict';
10160
  /*==================================================================================================
10161
 
10162
  MailPoet Notice:
10281
  if (
10282
  this.options.id !== null
10283
  &&
10284
+ jQuery('[data-id="'+this.options.id+'"]').length > 0
10285
  ) {
10286
  this.updateNotice();
10287
  } else {
27704
  __webpack_require__(565)
27705
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, Marionette, SuperModel) {
27706
 
27707
+ 'use strict';
27708
 
27709
  var Module = {};
27710
 
27749
  Module.StylesView = Marionette.View.extend({
27750
  getTemplate: function() { return templates.styles; },
27751
  modelEvents: {
27752
+ change: 'render'
27753
  },
27754
  serializeData: function() {
27755
  return this.model.toJSON();
27816
  StickyKit
27817
  ) {
27818
 
27819
+ 'use strict';
27820
 
27821
  var Module = {};
27822
 
27865
  'slideUp',
27866
  {
27867
  duration: 250,
27868
+ easing: 'easeOut',
27869
  complete: function() {
27870
  $openRegion.addClass('closed');
27871
  }.bind(this)
27877
  'slideDown',
27878
  {
27879
  duration: 250,
27880
+ easing: 'easeIn',
27881
  complete: function() {
27882
  $targetRegion.removeClass('closed');
27883
  }
27976
  },
27977
  events: function() {
27978
  return {
27979
+ 'change #mailpoet_text_font_color': _.partial(this.changeColorField, 'text.fontColor'),
27980
+ 'change #mailpoet_text_font_family': function(event) {
27981
  this.model.set('text.fontFamily', event.target.value);
27982
  },
27983
+ 'change #mailpoet_text_font_size': function(event) {
27984
  this.model.set('text.fontSize', event.target.value);
27985
  },
27986
+ 'change #mailpoet_h1_font_color': _.partial(this.changeColorField, 'h1.fontColor'),
27987
+ 'change #mailpoet_h1_font_family': function(event) {
27988
  this.model.set('h1.fontFamily', event.target.value);
27989
  },
27990
+ 'change #mailpoet_h1_font_size': function(event) {
27991
  this.model.set('h1.fontSize', event.target.value);
27992
  },
27993
+ 'change #mailpoet_h2_font_color': _.partial(this.changeColorField, 'h2.fontColor'),
27994
+ 'change #mailpoet_h2_font_family': function(event) {
27995
  this.model.set('h2.fontFamily', event.target.value);
27996
  },
27997
+ 'change #mailpoet_h2_font_size': function(event) {
27998
  this.model.set('h2.fontSize', event.target.value);
27999
  },
28000
+ 'change #mailpoet_h3_font_color': _.partial(this.changeColorField, 'h3.fontColor'),
28001
+ 'change #mailpoet_h3_font_family': function(event) {
28002
  this.model.set('h3.fontFamily', event.target.value);
28003
  },
28004
+ 'change #mailpoet_h3_font_size': function(event) {
28005
  this.model.set('h3.fontSize', event.target.value);
28006
  },
28007
+ 'change #mailpoet_a_font_color': _.partial(this.changeColorField, 'link.fontColor'),
28008
+ 'change #mailpoet_a_font_underline': function(event) {
28009
  this.model.set('link.textDecoration', (event.target.checked) ? event.target.value : 'none');
28010
  },
28011
+ 'change #mailpoet_newsletter_background_color': _.partial(this.changeColorField, 'wrapper.backgroundColor'),
28012
+ 'change #mailpoet_background_color': _.partial(this.changeColorField, 'body.backgroundColor')
28013
  };
28014
  },
28015
  templateContext: function() {
28117
  MailPoet.Modal.loading(true);
28118
 
28119
  // save before sending
28120
+ App.getChannel().request('save').always(function() {
 
 
 
28121
  CommunicationComponent.previewNewsletter(data).always(function() {
28122
  MailPoet.Modal.loading(false);
28123
  }).done(function(response) {
28206
  __webpack_require__(278),
28207
  __webpack_require__(274)
28208
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, SuperModel, _, MailPoet) {
28209
+ 'use strict';
28210
 
28211
  var Module = {};
28212
 
28236
  if (type in Module._blockTypes) {
28237
  return Module._blockTypes[type].blockModel;
28238
  } else {
28239
+ throw 'Block type not supported: ' + type;
28240
  }
28241
  };
28242
  Module.getBlockTypeView = function(type) {
28243
  if (type in Module._blockTypes) {
28244
  return Module._blockTypes[type].blockView;
28245
  } else {
28246
+ throw 'Block type not supported: ' + type;
28247
  }
28248
  };
28249
 
28322
  __webpack_require__(273)
28323
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, Backbone, Marionette, _, jQuery) {
28324
 
28325
+ 'use strict';
28326
 
28327
  var Module = {};
28328
 
28335
  },
28336
  events: function() {
28337
  return {
28338
+ 'keyup .mailpoet_input_title': _.partial(this.changeField, 'subject'),
28339
+ 'keyup .mailpoet_input_preheader': _.partial(this.changeField, 'preheader')
28340
  };
28341
  },
28342
  changeField: function(field, event) {
28349
  MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-subject-line'), {
28350
  tooltipId: 'tooltip-designer-subject-line-ti',
28351
  tooltip: MailPoet.I18n.t('helpTooltipDesignerSubjectLine'),
28352
+ place: 'right'
28353
  });
28354
  MailPoet.helpTooltip.show(document.getElementById('tooltip-designer-preheader'), {
28355
  tooltipId: 'tooltip-designer-preheader-ti',
28390
  html2canvas
28391
  ) {
28392
 
28393
+ 'use strict';
28394
 
28395
  var Module = {},
28396
  saveTimeout;
28433
  });
28434
  };
28435
 
 
 
 
 
 
 
 
 
 
28436
  Module.getThumbnail = function(element, options) {
28437
  var promise = html2canvas(element, options || {});
28438
 
28441
  // Removes 1px left transparent border from resulting canvas.
28442
 
28443
  var oldContext = oldCanvas.getContext('2d'),
28444
+ newCanvas = document.createElement('canvas'),
28445
+ newContext = newCanvas.getContext('2d'),
28446
  leftBorderWidth = 1;
28447
 
28448
  newCanvas.width = oldCanvas.width;
28528
  },
28529
  save: function() {
28530
  this.hideOptionContents();
28531
+ App.getChannel().request('save');
28532
  },
28533
  beforeSave: function() {
28534
  // TODO: Add a loading animation instead
28648
  next: function() {
28649
  this.hideOptionContents();
28650
  if(!this.$('.mailpoet_save_next').hasClass('button-disabled')) {
28651
+ Module._cancelAutosave();
28652
+ Module.save().done(function(response) {
28653
+ window.location.href = App.getConfig().get('urls.send');
28654
+ });
28655
  }
28656
  },
28657
  validateNewsletter: function(jsonObject) {
28662
 
28663
  var contents = JSON.stringify(jsonObject);
28664
  if (App.getConfig().get('validation.validateUnsubscribeLinkPresent') &&
28665
+ contents.indexOf('[link:subscription_unsubscribe_url]') < 0 &&
28666
+ contents.indexOf('[link:subscription_unsubscribe]') < 0) {
28667
  this.showValidationError(MailPoet.I18n.t('unsubscribeLinkMissing'));
28668
  return;
28669
  }
28688
  // may be requested
28689
  var AUTOSAVE_DELAY_DURATION = 1000;
28690
 
28691
+ Module._cancelAutosave();
 
28692
  saveTimeout = setTimeout(function() {
28693
+ App.getChannel().request('save').always(function() {
28694
+ Module._cancelAutosave();
28695
+ });
28696
  }, AUTOSAVE_DELAY_DURATION);
28697
  };
28698
 
28699
+ Module._cancelAutosave = function() {
28700
+ if (!saveTimeout) return;
28701
+
28702
+ clearTimeout(saveTimeout);
28703
+ saveTimeout = undefined;
28704
+ };
28705
+
28706
  Module.beforeExitWithUnsavedChanges = function(e) {
28707
  if (saveTimeout) {
28708
  var message = MailPoet.I18n.t('unsavedChangesWillBeLost');
28718
 
28719
  App.on('before:start', function(App, options) {
28720
  var Application = App;
28721
+ Application.save = Module.save;
28722
  Application.getChannel().on('autoSave', Module.autoSave);
28723
 
28724
  window.onbeforeunload = Module.beforeExitWithUnsavedChanges;
28725
 
28726
+ Application.getChannel().reply('save', Application.save);
28727
  });
28728
 
28729
  App.on('start', function(App, options) {
33334
  clickoutFiresChange: true,
33335
  showInput: true,
33336
  showInitial: true,
33337
+ preferredFormat: 'hex6',
33338
  allowEmpty: true,
33339
  chooseText: MailPoet.I18n.t('selectColor'),
33340
  cancelText: MailPoet.I18n.t('cancelColorSelection')
33961
 
33962
  BL.HighlightEditingBehavior = Marionette.Behavior.extend({
33963
  modelEvents: {
33964
+ startEditing: 'enableHighlight',
33965
+ stopEditing: 'disableHighlight'
33966
  },
33967
  enableHighlight: function() {
33968
  this.$el.addClass('mailpoet_highlight');
34000
  modelField: 'styles.block.height'
34001
  },
34002
  events: {
34003
+ mouseenter: 'showResizeHandle',
34004
+ mouseleave: 'hideResizeHandle'
34005
  },
34006
  onRender: function() {
34007
  this.attachResize();
34073
 
34074
  if (_.isFunction(this.$el.sortable)) {
34075
  this.$el.sortable({
34076
+ cursor: 'move',
34077
  start: function(event, ui) {
34078
  ui.item.data('previousIndex', ui.item.index());
34079
  },
34157
  BL.TextEditorBehavior = Marionette.Behavior.extend({
34158
  defaults: {
34159
  selector: '.mailpoet_content',
34160
+ toolbar1: 'bold italic link unlink forecolor mailpoet_shortcodes',
34161
+ toolbar2: '',
34162
+ validElements: 'p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br',
34163
+ invalidElements: 'script',
34164
  blockFormats: 'Paragraph=p',
34165
+ plugins: 'link textcolor colorpicker mailpoet_shortcodes',
34166
  configurationFilter: function(originalConfig) { return originalConfig; }
34167
  },
34168
  onDomRefresh: function() {
34249
  __webpack_require__(556)
34250
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, Marionette, SuperModel, _, jQuery, MailPoet, Modal) {
34251
 
34252
+ 'use strict';
34253
 
34254
  var Module = {},
34255
  AugmentedView = Marionette.View.extend({});
34285
  toolsRegion: '> .mailpoet_tools'
34286
  },
34287
  modelEvents: {
34288
+ change: 'render',
34289
+ delete: 'deleteBlock',
34290
+ duplicate: 'duplicateBlock'
34291
  },
34292
  events: {
34293
+ mouseenter: 'showTools',
34294
+ mouseleave: 'hideTools'
34295
  },
34296
  behaviors: {
34297
  DraggableBehavior: {
34415
  Module.BlockToolsView = AugmentedView.extend({
34416
  getTemplate: function() { return templates.genericBlockTools; },
34417
  events: {
34418
+ 'click .mailpoet_edit_block': 'changeSettings',
34419
+ 'click .mailpoet_delete_block_activate': 'showDeletionConfirmation',
34420
+ 'click .mailpoet_delete_block_cancel': 'hideDeletionConfirmation',
34421
+ 'click .mailpoet_delete_block_confirm': 'deleteBlock',
34422
+ 'click .mailpoet_duplicate_block': 'duplicateBlock'
34423
  },
34424
  // Markers of whether these particular tools will be used for this instance
34425
  tools: {
34533
  behaviors: {
34534
  DraggableBehavior: {
34535
  drop: function() {
34536
+ throw 'Unsupported operation';
34537
  }
34538
  }
34539
  }
34562
  __webpack_require__(595)
34563
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(Backbone, Marionette, _, jQuery, App, BaseBlock) {
34564
 
34565
+ 'use strict';
34566
 
34567
  var Module = {},
34568
  base = BaseBlock,
34655
  className: 'mailpoet_block mailpoet_container_block mailpoet_droppable_block mailpoet_droppable_layout_block',
34656
  getTemplate: function() { return templates.containerBlock; },
34657
  events: _.extend({}, base.BlockView.prototype.events, {
34658
+ 'click .mailpoet_newsletter_layer_selector': 'toggleEditingLayer'
34659
  }),
34660
  ui: {
34661
  tools: '> .mailpoet_tools'
34787
  getTemplate: function() { return templates.containerBlockSettings; },
34788
  events: function() {
34789
  return {
34790
+ 'change .mailpoet_field_container_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
34791
+ 'click .mailpoet_done_editing': 'close'
34792
  };
34793
  },
34794
  regions: {
34930
  __webpack_require__(273)
34931
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, MailPoet, _, jQuery) {
34932
 
34933
+ 'use strict';
34934
 
34935
  var Module = {},
34936
  base = BaseBlock;
34962
  });
34963
 
34964
  Module.ButtonBlockView = base.BlockView.extend({
34965
+ className: 'mailpoet_block mailpoet_button_block mailpoet_droppable_block',
34966
  getTemplate: function() { return templates.buttonBlock; },
34967
  onDragSubstituteBy: function() { return Module.ButtonWidgetView; },
34968
  behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
34989
  getTemplate: function() { return templates.buttonBlockSettings; },
34990
  events: function() {
34991
  return {
34992
+ 'input .mailpoet_field_button_text': _.partial(this.changeField, 'text'),
34993
+ 'input .mailpoet_field_button_url': _.partial(this.changeField, 'url'),
34994
+ 'change .mailpoet_field_button_alignment': _.partial(this.changeField, 'styles.block.textAlign'),
34995
+ 'change .mailpoet_field_button_font_color': _.partial(this.changeColorField, 'styles.block.fontColor'),
34996
+ 'change .mailpoet_field_button_font_family': _.partial(this.changeField, 'styles.block.fontFamily'),
34997
+ 'change .mailpoet_field_button_font_size': _.partial(this.changeField, 'styles.block.fontSize'),
34998
+ 'change .mailpoet_field_button_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
34999
+ 'change .mailpoet_field_button_border_color': _.partial(this.changeColorField, 'styles.block.borderColor'),
35000
+ 'change .mailpoet_field_button_font_weight': 'changeFontWeight',
35001
+
35002
+ 'input .mailpoet_field_button_border_width': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
35003
+ 'change .mailpoet_field_button_border_width': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
35004
+ 'input .mailpoet_field_button_border_width_input': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
35005
+
35006
+ 'input .mailpoet_field_button_border_radius': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius_input', _.partial(this.changePixelField, 'styles.block.borderRadius').bind(this)),
35007
+ 'change .mailpoet_field_button_border_radius': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius_input', _.partial(this.changePixelField, 'styles.block.borderRadius').bind(this)),
35008
+ 'input .mailpoet_field_button_border_radius_input': _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_radius', _.partial(this.changePixelField, 'styles.block.borderRadius').bind(this)),
35009
+
35010
+ 'input .mailpoet_field_button_width': _.partial(this.updateValueAndCall, '.mailpoet_field_button_width_input', _.partial(this.changePixelField, 'styles.block.width').bind(this)),
35011
+ 'change .mailpoet_field_button_width': _.partial(this.updateValueAndCall, '.mailpoet_field_button_width_input', _.partial(this.changePixelField, 'styles.block.width').bind(this)),
35012
+ 'input .mailpoet_field_button_width_input': _.partial(this.updateValueAndCall, '.mailpoet_field_button_width', _.partial(this.changePixelField, 'styles.block.width').bind(this)),
35013
+
35014
+ 'input .mailpoet_field_button_line_height': _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height_input', _.partial(this.changePixelField, 'styles.block.lineHeight').bind(this)),
35015
+ 'change .mailpoet_field_button_line_height': _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height_input', _.partial(this.changePixelField, 'styles.block.lineHeight').bind(this)),
35016
+ 'input .mailpoet_field_button_line_height_input': _.partial(this.updateValueAndCall, '.mailpoet_field_button_line_height', _.partial(this.changePixelField, 'styles.block.lineHeight').bind(this)),
35017
+
35018
+ 'click .mailpoet_field_button_replace_all_styles': 'applyToAll',
35019
+ 'click .mailpoet_done_editing': 'close'
35020
  };
35021
  },
35022
  templateContext: function() {
35085
  __webpack_require__(274)
35086
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, _, MailPoet) {
35087
 
35088
+ 'use strict';
35089
 
35090
  var Module = {},
35091
  base = BaseBlock,
35111
  });
35112
 
35113
  Module.ImageBlockView = base.BlockView.extend({
35114
+ className: 'mailpoet_block mailpoet_image_block mailpoet_droppable_block',
35115
  getTemplate: function() { return templates.imageBlock; },
35116
  onDragSubstituteBy: function() { return Module.ImageWidgetView; },
35117
  templateContext: function() {
35152
  getTemplate: function() { return templates.imageBlockSettings; },
35153
  events: function() {
35154
  return {
35155
+ 'input .mailpoet_field_image_link': _.partial(this.changeField, 'link'),
35156
+ 'input .mailpoet_field_image_address': 'changeAddress',
35157
+ 'input .mailpoet_field_image_alt_text': _.partial(this.changeField, 'alt'),
35158
+ 'change .mailpoet_field_image_full_width': _.partial(this.changeBoolCheckboxField, 'fullWidth'),
35159
+ 'change .mailpoet_field_image_alignment': _.partial(this.changeField, 'styles.block.textAlign'),
35160
+ 'click .mailpoet_field_image_select_another_image': 'showMediaManager',
35161
+ 'click .mailpoet_done_editing': 'close'
35162
  };
35163
  },
35164
  initialize: function(options) {
35254
 
35255
  var handlers = {
35256
  content: {
35257
+ embed: 'embedContent',
35258
  'edit-selection': 'editSelectionContent'
35259
  },
35260
  toolbar: {
35408
  height: mainSize.height + 'px',
35409
  width: mainSize.width + 'px',
35410
  src: mainSize.url,
35411
+ alt: (attachment.get('alt') !== '' && attachment.get('alt') !== undefined) ? attachment.get('alt') : attachment.get('title')
35412
  });
35413
  // Rerender settings view due to changes from outside of settings view
35414
  that.render();
35488
  __webpack_require__(274)
35489
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, _, jQuery, MailPoet) {
35490
 
35491
+ 'use strict';
35492
 
35493
  var Module = {},
35494
  base = BaseBlock;
35511
  });
35512
 
35513
  Module.DividerBlockView = base.BlockView.extend({
35514
+ className: 'mailpoet_block mailpoet_divider_block mailpoet_droppable_block',
35515
  getTemplate: function() { return templates.dividerBlock; },
35516
  modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'),
35517
  behaviors: _.defaults({
35566
  getTemplate: function() { return templates.dividerBlockSettings; },
35567
  events: function() {
35568
  return {
35569
+ 'click .mailpoet_field_divider_style': 'changeStyle',
35570
 
35571
+ 'input .mailpoet_field_divider_border_width': _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width_input', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
35572
+ 'change .mailpoet_field_divider_border_width': _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width_input', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
35573
+ 'input .mailpoet_field_divider_border_width_input': _.partial(this.updateValueAndCall, '.mailpoet_field_divider_border_width', _.partial(this.changePixelField, 'styles.block.borderWidth').bind(this)),
35574
 
35575
+ 'change .mailpoet_field_divider_border_color': _.partial(this.changeColorField, 'styles.block.borderColor'),
35576
+ 'change .mailpoet_field_divider_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
35577
+ 'click .mailpoet_button_divider_apply_to_all': 'applyToAll',
35578
+ 'click .mailpoet_done_editing': 'close'
35579
  };
35580
  },
35581
  modelEvents: function() {
35649
  __webpack_require__(278)
35650
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, _) {
35651
 
35652
+ 'use strict';
35653
 
35654
  var Module = {},
35655
  base = BaseBlock;
35664
  });
35665
 
35666
  Module.TextBlockView = base.BlockView.extend({
35667
+ className: 'mailpoet_block mailpoet_text_block mailpoet_droppable_block',
35668
  getTemplate: function() { return templates.textBlock; },
35669
  modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'), // Prevent rerendering on model change due to text editor redrawing
35670
  behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
35671
  TextEditorBehavior: {
35672
+ toolbar1: 'formatselect bold italic forecolor | link unlink',
35673
+ toolbar2: 'alignleft aligncenter alignright alignjustify | bullist numlist blockquote | code mailpoet_shortcodes',
35674
+ validElements: 'p[class|style],span[class|style],a[href|class|title|target|style],h1[class|style],h2[class|style],h3[class|style],ol[class|style],ul[class|style],li[class|style],strong[class|style],em[class|style],strike,br,blockquote[class|style],table[class|style],tr[class|style],th[class|style],td[class|style]',
35675
+ invalidElements: 'script',
35676
  blockFormats: 'Heading 1=h1;Heading 2=h2;Heading 3=h3;Paragraph=p',
35677
+ plugins: 'link lists code textcolor colorpicker mailpoet_shortcodes paste',
35678
  configurationFilter: function(originalSettings) {
35679
  return _.extend({}, originalSettings, {
35680
  mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
35767
  __webpack_require__(278)
35768
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, _) {
35769
 
35770
+ 'use strict';
35771
 
35772
  var Module = {},
35773
  base = BaseBlock;
35787
  });
35788
 
35789
  Module.SpacerBlockView = base.BlockView.extend({
35790
+ className: 'mailpoet_block mailpoet_spacer_block mailpoet_droppable_block',
35791
  getTemplate: function() { return templates.spacerBlock; },
35792
  behaviors: _.defaults({
35793
  ResizableBehavior: {
35829
  getTemplate: function() { return templates.spacerBlockSettings; },
35830
  events: function() {
35831
  return {
35832
+ 'change .mailpoet_field_spacer_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
35833
+ 'click .mailpoet_done_editing': 'close'
35834
  };
35835
  }
35836
  });
35878
  __webpack_require__(278)
35879
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, _) {
35880
 
35881
+ 'use strict';
35882
 
35883
  var Module = {},
35884
  base = BaseBlock;
35908
  });
35909
 
35910
  Module.FooterBlockView = base.BlockView.extend({
35911
+ className: 'mailpoet_block mailpoet_footer_block mailpoet_droppable_block',
35912
  getTemplate: function() { return templates.footerBlock; },
35913
  modelEvents: _.extend({
35914
  'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render'
35949
  getTemplate: function() { return templates.footerBlockSettings; },
35950
  events: function() {
35951
  return {
35952
+ 'change .mailpoet_field_footer_text_color': _.partial(this.changeColorField, 'styles.text.fontColor'),
35953
+ 'change .mailpoet_field_footer_text_font_family': _.partial(this.changeField, 'styles.text.fontFamily'),
35954
+ 'change .mailpoet_field_footer_text_size': _.partial(this.changeField, 'styles.text.fontSize'),
35955
+ 'change #mailpoet_field_footer_link_color': _.partial(this.changeColorField, 'styles.link.fontColor'),
35956
+ 'change #mailpoet_field_footer_link_underline': function(event) {
35957
  this.model.set('styles.link.textDecoration', (event.target.checked) ? event.target.value : 'none');
35958
  },
35959
+ 'change .mailpoet_field_footer_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
35960
+ 'change .mailpoet_field_footer_alignment': _.partial(this.changeField, 'styles.text.textAlign'),
35961
+ 'click .mailpoet_done_editing': 'close'
35962
  };
35963
  },
35964
  templateContext: function() {
36011
  __webpack_require__(278)
36012
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, _) {
36013
 
36014
+ 'use strict';
36015
 
36016
  var Module = {},
36017
  base = BaseBlock;
36041
  });
36042
 
36043
  Module.HeaderBlockView = base.BlockView.extend({
36044
+ className: 'mailpoet_block mailpoet_header_block mailpoet_droppable_block',
36045
  getTemplate: function() { return templates.headerBlock; },
36046
  modelEvents: _.extend({
36047
  'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render'
36082
  getTemplate: function() { return templates.headerBlockSettings; },
36083
  events: function() {
36084
  return {
36085
+ 'change .mailpoet_field_header_text_color': _.partial(this.changeColorField, 'styles.text.fontColor'),
36086
+ 'change .mailpoet_field_header_text_font_family': _.partial(this.changeField, 'styles.text.fontFamily'),
36087
+ 'change .mailpoet_field_header_text_size': _.partial(this.changeField, 'styles.text.fontSize'),
36088
+ 'change #mailpoet_field_header_link_color': _.partial(this.changeColorField, 'styles.link.fontColor'),
36089
+ 'change #mailpoet_field_header_link_underline': function(event) {
36090
  this.model.set('styles.link.textDecoration', (event.target.checked) ? event.target.value : 'none');
36091
  },
36092
+ 'change .mailpoet_field_header_background_color': _.partial(this.changeColorField, 'styles.block.backgroundColor'),
36093
+ 'change .mailpoet_field_header_alignment': _.partial(this.changeField, 'styles.text.textAlign'),
36094
+ 'click .mailpoet_done_editing': 'close'
36095
  };
36096
  },
36097
  templateContext: function() {
36165
  jQuery
36166
  ) {
36167
 
36168
+ 'use strict';
36169
 
36170
  var Module = {},
36171
  base = BaseBlock;
36265
  });
36266
 
36267
  Module.AutomatedLatestContentBlockView = base.BlockView.extend({
36268
+ className: 'mailpoet_block mailpoet_automated_latest_content_block mailpoet_droppable_block',
36269
  initialize: function() {
36270
  function replaceButtonStylesHandler(data) {
36271
+ this.model.set({readMoreButton: data});
36272
  }
36273
+ App.getChannel().on('replaceAllButtonStyles', replaceButtonStylesHandler.bind(this));
36274
  },
36275
  getTemplate: function() { return templates.automatedLatestContentBlock; },
36276
  regions: {
36280
  modelEvents: _.extend(
36281
  _.omit(base.BlockView.prototype.modelEvents, 'change'),
36282
  {
36283
+ postsChanged: 'render'
36284
  }),
36285
  events: _.extend(base.BlockView.prototype.events, {
36286
  'click .mailpoet_automated_latest_content_block_overlay': 'showSettings'
36308
  getTemplate: function() { return templates.automatedLatestContentBlockSettings; },
36309
  events: function() {
36310
  return {
36311
+ 'click .mailpoet_automated_latest_content_hide_display_options': 'toggleDisplayOptions',
36312
+ 'click .mailpoet_automated_latest_content_show_display_options': 'toggleDisplayOptions',
36313
+ 'click .mailpoet_automated_latest_content_select_button': 'showButtonSettings',
36314
+ 'click .mailpoet_automated_latest_content_select_divider': 'showDividerSettings',
36315
+ 'change .mailpoet_automated_latest_content_read_more_type': 'changeReadMoreType',
36316
+ 'change .mailpoet_automated_latest_content_display_type': 'changeDisplayType',
36317
+ 'change .mailpoet_automated_latest_content_title_format': 'changeTitleFormat',
36318
+ 'change .mailpoet_automated_latest_content_title_as_links': _.partial(this.changeBoolField, 'titleIsLink'),
36319
+ 'change .mailpoet_automated_latest_content_show_divider': _.partial(this.changeBoolField, 'showDivider'),
36320
+ 'input .mailpoet_automated_latest_content_show_amount': _.partial(this.changeField, 'amount'),
36321
+ 'change .mailpoet_automated_latest_content_content_type': _.partial(this.changeField, 'contentType'),
36322
+ 'change .mailpoet_automated_latest_content_include_or_exclude': _.partial(this.changeField, 'inclusionType'),
36323
+ 'change .mailpoet_automated_latest_content_title_alignment': _.partial(this.changeField, 'titleAlignment'),
36324
+ 'change .mailpoet_automated_latest_content_image_full_width': _.partial(this.changeBoolField, 'imageFullWidth'),
36325
+ 'change .mailpoet_automated_latest_content_featured_image_position': _.partial(this.changeField, 'featuredImagePosition'),
36326
+ 'change .mailpoet_automated_latest_content_show_author': _.partial(this.changeField, 'showAuthor'),
36327
+ 'input .mailpoet_automated_latest_content_author_preceded_by': _.partial(this.changeField, 'authorPrecededBy'),
36328
+ 'change .mailpoet_automated_latest_content_show_categories': _.partial(this.changeField, 'showCategories'),
36329
+ 'input .mailpoet_automated_latest_content_categories': _.partial(this.changeField, 'categoriesPrecededBy'),
36330
+ 'input .mailpoet_automated_latest_content_read_more_text': _.partial(this.changeField, 'readMoreText'),
36331
+ 'change .mailpoet_automated_latest_content_sort_by': _.partial(this.changeField, 'sortBy'),
36332
+ 'click .mailpoet_done_editing': 'close'
36333
  };
36334
  },
36335
  onRender: function() {
36582
  DividerBlock
36583
  ) {
36584
 
36585
+ 'use strict';
36586
 
36587
  var Module = {},
36588
  base = BaseBlock;
36721
  });
36722
 
36723
  Module.PostsBlockView = base.BlockView.extend({
36724
+ className: 'mailpoet_block mailpoet_posts_block mailpoet_droppable_block',
36725
  getTemplate: function() { return templates.postsBlock; },
36726
  modelEvents: {}, // Forcefully disable all events
36727
  regions: _.extend({
36841
  this.blockModel = options.blockModel;
36842
  },
36843
  events: {
36844
+ scroll: 'onPostsScroll'
36845
  },
36846
  onPostsScroll: function(event) {
36847
  var $postsBox = jQuery(event.target);
36871
  this.$('.mailpoet_post_scroll_container').scrollTop(0);
36872
  }
36873
  },
36874
+ loadingMorePosts: function() {
36875
  this.$('.mailpoet_post_selection_loading').css('visibility', 'visible');
36876
  },
36877
+ morePostsLoaded: function() {
36878
  this.$('.mailpoet_post_selection_loading').css('visibility', 'hidden');
36879
  }
36880
  },
37007
  getTemplate: function() { return templates.displayOptionsPostsBlockSettings; },
37008
  events: function() {
37009
  return {
37010
+ 'click .mailpoet_posts_select_button': 'showButtonSettings',
37011
+ 'click .mailpoet_posts_select_divider': 'showDividerSettings',
37012
+ 'change .mailpoet_posts_read_more_type': 'changeReadMoreType',
37013
+ 'change .mailpoet_posts_display_type': 'changeDisplayType',
37014
+ 'change .mailpoet_posts_title_format': 'changeTitleFormat',
37015
+ 'change .mailpoet_posts_title_as_links': _.partial(this.changeBoolField, 'titleIsLink'),
37016
+ 'change .mailpoet_posts_show_divider': _.partial(this.changeBoolField, 'showDivider'),
37017
+ 'input .mailpoet_posts_show_amount': _.partial(this.changeField, 'amount'),
37018
+ 'change .mailpoet_posts_content_type': _.partial(this.changeField, 'contentType'),
37019
+ 'change .mailpoet_posts_include_or_exclude': _.partial(this.changeField, 'inclusionType'),
37020
+ 'change .mailpoet_posts_title_alignment': _.partial(this.changeField, 'titleAlignment'),
37021
+ 'change .mailpoet_posts_image_full_width': _.partial(this.changeBoolField, 'imageFullWidth'),
37022
+ 'change .mailpoet_posts_featured_image_position': _.partial(this.changeField, 'featuredImagePosition'),
37023
+ 'change .mailpoet_posts_show_author': _.partial(this.changeField, 'showAuthor'),
37024
+ 'input .mailpoet_posts_author_preceded_by': _.partial(this.changeField, 'authorPrecededBy'),
37025
+ 'change .mailpoet_posts_show_categories': _.partial(this.changeField, 'showCategories'),
37026
+ 'input .mailpoet_posts_categories': _.partial(this.changeField, 'categoriesPrecededBy'),
37027
+ 'input .mailpoet_posts_read_more_text': _.partial(this.changeField, 'readMoreText'),
37028
+ 'change .mailpoet_posts_sort_by': _.partial(this.changeField, 'sortBy')
37029
  };
37030
  },
37031
  templateContext: function() {
37155
  __webpack_require__(273)
37156
  ], __WEBPACK_AMD_DEFINE_RESULT__ = function(App, BaseBlock, Backbone, Marionette, SuperModel, _, jQuery) {
37157
 
37158
+ 'use strict';
37159
 
37160
  var Module = {},
37161
  base = BaseBlock,
37231
  tagName: 'span',
37232
  getTemplate: function() { return templates.socialIconBlock; },
37233
  modelEvents: {
37234
+ change: 'render'
37235
  },
37236
  templateContext: function() {
37237
  var allIconSets = App.getAvailableStyles().get('socialIconSets');
37282
  },
37283
  events: function() {
37284
  return {
37285
+ 'click .mailpoet_done_editing': 'close'
37286
  };
37287
  },
37288
  initialize: function() {
37302
  getTemplate: function() { return templates.socialSettingsIcon; },
37303
  events: function() {
37304
  return {
37305
+ 'click .mailpoet_delete_block': 'deleteIcon',
37306
+ 'change .mailpoet_social_icon_field_type': _.partial(this.changeField, 'iconType'),
37307
+ 'input .mailpoet_social_icon_field_image': _.partial(this.changeField, 'image'),
37308
+ 'input .mailpoet_social_icon_field_link': this.changeLink,
37309
+ 'input .mailpoet_social_icon_field_text': _.partial(this.changeField, 'text')
37310
  };
37311
  },
37312
  modelEvents: {
37358
  SocialBlockSettingsIconSelectorView = Marionette.View.extend({
37359
  getTemplate: function() { return templates.socialSettingsIconSelector; },
37360
  regions: {
37361
+ icons: '#mailpoet_social_icon_selector_contents'
37362
  },
37363
  events: {
37364
  'click .mailpoet_add_social_icon': 'addSocialIcon'
37381
  SocialBlockSettingsStylesView = Marionette.View.extend({
37382
  getTemplate: function() { return templates.socialSettingsStyles; },
37383
  modelEvents: {
37384
+ change: 'render'
37385
  },
37386
  events: {
37387
  'click .mailpoet_social_icon_set': 'changeSocialIconSet'
assets/js/{public.412ca9cc.js → public.15490850.js} RENAMED
@@ -86,7 +86,7 @@
86
  translations[key] = value;
87
  },
88
  t: function(key) {
89
- return translations[key] || 'TRANSLATION "%$1s" NOT FOUND'.replace("%$1s", key);
90
  },
91
  all: function() {
92
  return translations;
@@ -104,7 +104,7 @@
104
  if (xhr.responseJSON) {
105
  return xhr.responseJSON;
106
  }
107
- var message = errorMessage.replace("%d", xhr.status);
108
  return {
109
  errors: [
110
  {
@@ -1778,7 +1778,7 @@
1778
 
1779
  iframe.style.height = (
1780
  parseInt(i, 10) + this.marginY
1781
- ) + "px";
1782
  }
1783
  };
1784
 
@@ -1815,7 +1815,7 @@
1815
  */
1816
  $.fn.serializeObject = function(coerce) {
1817
  var obj = {},
1818
- coerce_types = { 'true': !0, 'false': !1, 'null': null };
1819
 
1820
  // Iterate over all name=value pairs.
1821
  $.each( this.serializeArray(), function(j, v){
86
  translations[key] = value;
87
  },
88
  t: function(key) {
89
+ return translations[key] || 'TRANSLATION "%$1s" NOT FOUND'.replace('%$1s', key);
90
  },
91
  all: function() {
92
  return translations;
104
  if (xhr.responseJSON) {
105
  return xhr.responseJSON;
106
  }
107
+ var message = errorMessage.replace('%d', xhr.status);
108
  return {
109
  errors: [
110
  {
1778
 
1779
  iframe.style.height = (
1780
  parseInt(i, 10) + this.marginY
1781
+ ) + 'px';
1782
  }
1783
  };
1784
 
1815
  */
1816
  $.fn.serializeObject = function(coerce) {
1817
  var obj = {},
1818
+ coerce_types = { true: !0, false: !1, null: null };
1819
 
1820
  // Iterate over all name=value pairs.
1821
  $.each( this.serializeArray(), function(j, v){
assets/js/{vendor.016cb65c.js → vendor.aecfe832.js} RENAMED
@@ -76,7 +76,7 @@
76
  /******/ script.charset = 'utf-8';
77
  /******/ script.async = true;
78
 
79
- /******/ script.src = __webpack_require__.p + "" + ({"0":"admin","1":"admin_vendor","2":"form_editor","3":"mailpoet","4":"newsletter_editor"}[chunkId]||chunkId) + "." + {"0":"d56f9a3d","1":"aaf3acee","2":"4d117b35","3":"28805a4f","4":"a3d00b84"}[chunkId] + ".chunk.js";
80
  /******/ head.appendChild(script);
81
  /******/ }
82
  /******/ };
@@ -130,7 +130,7 @@
130
  }
131
 
132
  // set date format
133
- var f = block.hash.format || "MMM Do, YYYY";
134
  // check if we passed a timestamp
135
  if(parseInt(timestamp, 10) == timestamp) {
136
  return moment.unix(timestamp).format(f);
@@ -178,7 +178,7 @@
178
  });
179
 
180
  Handlebars.registerHelper('nl2br', function(value, block) {
181
- return value.gsub("\n", "<br />");
182
  });
183
 
184
  Handlebars.registerHelper('json_encode', function(value, block) {
@@ -189,7 +189,7 @@
189
  return JSON.parse(value);
190
  });
191
  Handlebars.registerHelper('url', function(value, block) {
192
- var url = window.location.protocol + "//" + window.location.host + window.location.pathname;
193
 
194
  return url + value;
195
  });
@@ -210,7 +210,7 @@
210
  // extract all lines into an array
211
  if(value === undefined) return '';
212
 
213
- var lines = value.trim().split("\n");
214
 
215
  // remove header & footer
216
  lines.shift();
@@ -259,10 +259,10 @@
259
  case 'Courier New': return new Handlebars.SafeString("'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace");
260
  case 'Georgia': return new Handlebars.SafeString("Georgia, Times, 'Times New Roman', serif");
261
  case 'Lucida': return new Handlebars.SafeString("'Lucida Sans Unicode', 'Lucida Grande', sans-serif");
262
- case 'Tahoma': return new Handlebars.SafeString("Tahoma, Verdana, Segoe, sans-serif");
263
  case 'Times New Roman': return new Handlebars.SafeString("'Times New Roman', Times, Baskerville, Georgia, serif");
264
  case 'Trebuchet MS': return new Handlebars.SafeString("'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif");
265
- case 'Verdana': return new Handlebars.SafeString("Verdana, Geneva, sans-serif");
266
  default: return font;
267
  }
268
  });
76
  /******/ script.charset = 'utf-8';
77
  /******/ script.async = true;
78
 
79
+ /******/ script.src = __webpack_require__.p + "" + ({"0":"admin","1":"admin_vendor","2":"form_editor","3":"mailpoet","4":"newsletter_editor"}[chunkId]||chunkId) + "." + {"0":"36b0c17d","1":"71d84e79","2":"92c760ec","3":"a3939b7d","4":"dabd6b50"}[chunkId] + ".chunk.js";
80
  /******/ head.appendChild(script);
81
  /******/ }
82
  /******/ };
130
  }
131
 
132
  // set date format
133
+ var f = block.hash.format || 'MMM Do, YYYY';
134
  // check if we passed a timestamp
135
  if(parseInt(timestamp, 10) == timestamp) {
136
  return moment.unix(timestamp).format(f);
178
  });
179
 
180
  Handlebars.registerHelper('nl2br', function(value, block) {
181
+ return value.gsub('\n', '<br />');
182
  });
183
 
184
  Handlebars.registerHelper('json_encode', function(value, block) {
189
  return JSON.parse(value);
190
  });
191
  Handlebars.registerHelper('url', function(value, block) {
192
+ var url = window.location.protocol + '//' + window.location.host + window.location.pathname;
193
 
194
  return url + value;
195
  });
210
  // extract all lines into an array
211
  if(value === undefined) return '';
212
 
213
+ var lines = value.trim().split('\n');
214
 
215
  // remove header & footer
216
  lines.shift();
259
  case 'Courier New': return new Handlebars.SafeString("'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace");
260
  case 'Georgia': return new Handlebars.SafeString("Georgia, Times, 'Times New Roman', serif");
261
  case 'Lucida': return new Handlebars.SafeString("'Lucida Sans Unicode', 'Lucida Grande', sans-serif");
262
+ case 'Tahoma': return new Handlebars.SafeString('Tahoma, Verdana, Segoe, sans-serif');
263
  case 'Times New Roman': return new Handlebars.SafeString("'Times New Roman', Times, Baskerville, Georgia, serif");
264
  case 'Trebuchet MS': return new Handlebars.SafeString("'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif");
265
+ case 'Verdana': return new Handlebars.SafeString('Verdana, Geneva, sans-serif');
266
  default: return font;
267
  }
268
  });
lang/index.php CHANGED
@@ -1,3 +0,0 @@
1
- <?php
2
-
3
- // Silence is golden
 
 
 
lang/mailpoet-da_DK.mo CHANGED
Binary file
lang/mailpoet-fr_FR.mo CHANGED
Binary file
lang/mailpoet-nl_NL.mo CHANGED
Binary file
lang/mailpoet-ru_RU.mo CHANGED
Binary file
lang/mailpoet-sv_SE.mo CHANGED
Binary file
lang/mailpoet-tr_TR.mo CHANGED
Binary file
lang/mailpoet.pot CHANGED
@@ -4,7 +4,7 @@ msgid ""
4
  msgstr ""
5
  "Project-Id-Version: \n"
6
  "Report-Msgid-Bugs-To: http://support.mailpoet.com/\n"
7
- "POT-Creation-Date: 2017-08-22 12:52:21+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
@@ -26,185 +26,189 @@ msgstr ""
26
  "X-Poedit-Bookmarks: \n"
27
  "X-Textdomain-Support: yes\n"
28
 
29
- #: lib/API/API.php:16
30
  msgid "Invalid API version."
31
  msgstr ""
32
 
33
- #: lib/API/JSON/API.php:58 lib/API/JSON/API.php:85
34
  msgid "Invalid API request."
35
  msgstr ""
36
 
37
- #: lib/API/JSON/API.php:126
38
  msgid "Invalid API endpoint."
39
  msgstr ""
40
 
41
- #: lib/API/JSON/API.php:138
42
  msgid "You do not have the required permissions."
43
  msgstr ""
44
 
45
- #: lib/API/JSON/Endpoint.php:21
46
  msgid "An unknown error occurred."
47
  msgstr ""
48
 
49
- #: lib/API/JSON/Endpoint.php:30
50
  msgid "Invalid request parameters"
51
  msgstr ""
52
 
53
- #: lib/API/JSON/v1/CustomFields.php:24 lib/API/JSON/v1/CustomFields.php:51
54
  msgid "This custom field does not exist."
55
  msgstr ""
56
 
57
- #: lib/API/JSON/v1/Forms.php:20 lib/API/JSON/v1/Forms.php:127
58
- #: lib/API/JSON/v1/Forms.php:209 lib/API/JSON/v1/Forms.php:225
59
- #: lib/API/JSON/v1/Forms.php:241 lib/API/JSON/v1/Forms.php:255
60
  msgid "This form does not exist."
61
  msgstr ""
62
 
63
- #: lib/API/JSON/v1/Forms.php:60 lib/API/JSON/v1/Forms.php:139
64
  msgid "New form"
65
  msgstr ""
66
 
67
- #: lib/API/JSON/v1/Forms.php:64 lib/API/JSON/v1/Forms.php:68
68
  #: lib/API/MP/v1/API.php:17
69
  #: lib/Subscribers/ImportExport/ImportExportFactory.php:32
70
  #: views/newsletter/editor.html:938 views/newsletter/editor.html:939
71
  msgid "Email"
72
  msgstr ""
73
 
74
- #: lib/API/JSON/v1/Forms.php:74
75
  msgid "Submit"
76
  msgstr ""
77
 
78
- #: lib/API/JSON/v1/Forms.php:78
79
  msgid "Subscribe!"
80
  msgstr ""
81
 
82
- #: lib/API/JSON/v1/Forms.php:84
83
  msgid "Check your inbox or spam folder to confirm your subscription."
84
  msgstr ""
85
 
86
- #: lib/API/JSON/v1/Forms.php:259 lib/API/JSON/v1/Newsletters.php:212
87
- #: lib/API/JSON/v1/Segments.php:119
88
  msgid "Copy of %s"
89
  msgstr ""
90
 
91
- #: lib/API/JSON/v1/Mailer.php:29 lib/API/JSON/v1/Newsletters.php:314
92
  msgid "The email could not be sent: %s"
93
  msgstr ""
94
 
95
- #: lib/API/JSON/v1/NewsletterTemplates.php:16
96
- #: lib/API/JSON/v1/NewsletterTemplates.php:52
97
  msgid "This template does not exist."
98
  msgstr ""
99
 
100
- #: lib/API/JSON/v1/Newsletters.php:30 lib/API/JSON/v1/Newsletters.php:141
101
- #: lib/API/JSON/v1/Newsletters.php:162 lib/API/JSON/v1/Newsletters.php:178
102
- #: lib/API/JSON/v1/Newsletters.php:194 lib/API/JSON/v1/Newsletters.php:208
103
- #: lib/API/JSON/v1/Newsletters.php:241 lib/API/JSON/v1/Newsletters.php:272
104
- #: lib/API/JSON/v1/SendingQueue.php:28 lib/API/JSON/v1/SendingQueue.php:115
105
- #: lib/API/JSON/v1/SendingQueue.php:141
106
  msgid "This newsletter does not exist."
107
  msgstr ""
108
 
109
- #: lib/API/JSON/v1/Newsletters.php:132
110
  msgid "You need to specify a status."
111
  msgstr ""
112
 
113
- #: lib/API/JSON/v1/Newsletters.php:232
114
  msgid "Newsletter data is missing."
115
  msgstr ""
116
 
117
- #: lib/API/JSON/v1/Newsletters.php:263
118
  msgid "Please specify receiver information."
119
  msgstr ""
120
 
121
- #: lib/API/JSON/v1/Segments.php:18 lib/API/JSON/v1/Segments.php:69
122
- #: lib/API/JSON/v1/Segments.php:85 lib/API/JSON/v1/Segments.php:101
123
- #: lib/API/JSON/v1/Segments.php:115
124
  msgid "This list does not exist."
125
  msgstr ""
126
 
127
- #: lib/API/JSON/v1/SendingQueue.php:48
128
  msgid "This newsletter is already being sent."
129
  msgstr ""
130
 
131
- #: lib/API/JSON/v1/SendingQueue.php:79
132
  msgid "There are no subscribers in that list!"
133
  msgstr ""
134
 
135
- #: lib/API/JSON/v1/SendingQueue.php:122 lib/API/JSON/v1/SendingQueue.php:148
136
  msgid "This newsletter has not been sent yet."
137
  msgstr ""
138
 
139
- #: lib/API/JSON/v1/Services.php:27 lib/API/JSON/v1/Services.php:77
140
  msgid "Please specify a key."
141
  msgstr ""
142
 
143
- #: lib/API/JSON/v1/Services.php:44 views/settings/premium.html:40
144
  msgid "Your MailPoet Sending Service key has been successfully validated."
145
  msgstr ""
146
 
147
- #: lib/API/JSON/v1/Services.php:47
148
  msgid "Your MailPoet Sending Service key expires on %s!"
149
  msgstr ""
150
 
151
- #: lib/API/JSON/v1/Services.php:58 views/settings/premium.html:45
152
  msgid "Your MailPoet Sending Service key is invalid."
153
  msgstr ""
154
 
155
- #: lib/API/JSON/v1/Services.php:63
 
 
 
 
156
  msgid "Error validating MailPoet Sending Service key, please try again later (%s)"
157
  msgstr ""
158
 
159
- #: lib/API/JSON/v1/Services.php:94 views/settings/premium.html:30
160
  msgid "Your Premium key has been successfully validated."
161
  msgstr ""
162
 
163
- #: lib/API/JSON/v1/Services.php:97
164
  msgid "Your Premium key expires on %s."
165
  msgstr ""
166
 
167
- #: lib/API/JSON/v1/Services.php:111 views/settings/premium.html:35
168
  msgid "Your Premium key is invalid."
169
  msgstr ""
170
 
171
- #: lib/API/JSON/v1/Services.php:114
172
  msgid "Your Premium key is already used on another site."
173
  msgstr ""
174
 
175
- #: lib/API/JSON/v1/Services.php:119
176
  msgid "Error validating Premium key, please try again later (%s)"
177
  msgstr ""
178
 
179
- #: lib/API/JSON/v1/Services.php:131
180
  msgid "Service unavailable"
181
  msgstr ""
182
 
183
- #: lib/API/JSON/v1/Services.php:134
184
  msgid ""
185
  "Contact your hosting support to check the connection between your host and "
186
  "https://bridge.mailpoet.com"
187
  msgstr ""
188
 
189
- #: lib/API/JSON/v1/Settings.php:20
190
  msgid "You have not specified any settings to be saved."
191
  msgstr ""
192
 
193
- #: lib/API/JSON/v1/Subscribers.php:26 lib/API/JSON/v1/Subscribers.php:152
194
- #: lib/API/JSON/v1/Subscribers.php:168 lib/API/JSON/v1/Subscribers.php:184
195
  #: lib/API/MP/v1/API.php:48
196
  msgid "This subscriber does not exist."
197
  msgstr ""
198
 
199
- #: lib/API/JSON/v1/Subscribers.php:67
200
  msgid "Please specify a valid form ID."
201
  msgstr ""
202
 
203
- #: lib/API/JSON/v1/Subscribers.php:72
204
  msgid "Please leave the first field empty."
205
  msgstr ""
206
 
207
- #: lib/API/JSON/v1/Subscribers.php:87 views/form/editor.html:57
208
  msgid "Please select a list."
209
  msgstr ""
210
 
@@ -238,6 +242,10 @@ msgstr ""
238
  msgid "MailPoet Newsletter"
239
  msgstr ""
240
 
 
 
 
 
241
  #: lib/Config/MP2Migrator.php:151
242
  msgid "START IMPORT"
243
  msgstr ""
@@ -250,157 +258,157 @@ msgstr ""
250
  msgid "END IMPORT"
251
  msgstr ""
252
 
253
- #: lib/Config/MP2Migrator.php:195
254
  msgid "MailPoet data erased"
255
  msgstr ""
256
 
257
- #: lib/Config/MP2Migrator.php:225 views/mp2migration.html:69
258
  msgid "IMPORT STOPPED BY USER"
259
  msgstr ""
260
 
261
- #: lib/Config/MP2Migrator.php:257
262
  msgid "MailPoet 2 data found:"
263
  msgstr ""
264
 
265
- #: lib/Config/MP2Migrator.php:262
266
  msgid "%d subscribers list"
267
  msgid_plural "%d subscribers lists"
268
  msgstr[0] ""
269
  msgstr[1] ""
270
 
271
- #: lib/Config/MP2Migrator.php:267
272
  msgid "%d subscriber"
273
  msgid_plural "%d subscribers"
274
  msgstr[0] ""
275
  msgstr[1] ""
276
 
277
- #: lib/Config/MP2Migrator.php:272
278
  msgid "%d form"
279
  msgid_plural "%d forms"
280
  msgstr[0] ""
281
  msgstr[1] ""
282
 
283
- #: lib/Config/MP2Migrator.php:289
284
  msgid "Importing segments..."
285
  msgstr ""
286
 
287
- #: lib/Config/MP2Migrator.php:310
288
  msgid "%d segment imported"
289
  msgid_plural "%d segments imported"
290
  msgstr[0] ""
291
  msgstr[1] ""
292
 
293
- #: lib/Config/MP2Migrator.php:379
294
  msgid "Importing custom fields..."
295
  msgstr ""
296
 
297
- #: lib/Config/MP2Migrator.php:389
298
  msgid "%d custom field imported"
299
  msgid_plural "%d custom fields imported"
300
  msgstr[0] ""
301
  msgstr[1] ""
302
 
303
- #: lib/Config/MP2Migrator.php:527
304
  msgid "Importing subscribers..."
305
  msgstr ""
306
 
307
- #: lib/Config/MP2Migrator.php:549
308
  msgid "%d subscriber imported"
309
  msgid_plural "%d subscribers imported"
310
  msgstr[0] ""
311
  msgstr[1] ""
312
 
313
- #: lib/Config/MP2Migrator.php:775
314
  msgid "Importing forms..."
315
  msgstr ""
316
 
317
- #: lib/Config/MP2Migrator.php:794
318
  msgid "%d form imported"
319
  msgid_plural "%d forms imported"
320
  msgstr[0] ""
321
  msgstr[1] ""
322
 
323
- #: lib/Config/MP2Migrator.php:1058
324
  msgid "Settings imported"
325
  msgstr ""
326
 
327
- #: lib/Config/Menu.php:67 lib/Config/Menu.php:68 views/newsletters.html:23
328
  msgid "Emails"
329
  msgstr ""
330
 
331
- #: lib/Config/Menu.php:91 lib/Config/Menu.php:92 views/forms.html:25
332
- msgid "Forms"
333
- msgstr ""
334
-
335
- #: lib/Config/Menu.php:114 lib/Config/Menu.php:115
336
- #: views/subscribers/subscribers.html:18
337
- msgid "Subscribers"
338
  msgstr ""
339
 
340
- #: lib/Config/Menu.php:137 lib/Config/Menu.php:138 views/forms.html:53
341
- #: views/newsletters.html:64 views/newsletters.html:166 views/segments.html:13
342
- #: views/subscribers/subscribers.html:66
343
- msgid "Lists"
344
  msgstr ""
345
 
346
- #: lib/Config/Menu.php:161 lib/Config/Menu.php:162 views/form/editor.html:37
347
- #: views/newsletters.html:65 views/settings.html:6
348
- msgid "Settings"
349
  msgstr ""
350
 
351
- #: lib/Config/Menu.php:173 lib/Config/Menu.php:174 views/help.html:5
352
- msgid "Help"
353
  msgstr ""
354
 
355
- #: lib/Config/Menu.php:186 lib/Config/Menu.php:187 views/settings.html:22
356
- msgid "Premium"
 
357
  msgstr ""
358
 
359
- #: lib/Config/Menu.php:198 lib/Config/Menu.php:199
360
  #: views/subscribers/importExport/import.html:7
361
  #: views/subscribers/subscribers.html:94
362
  msgid "Import"
363
  msgstr ""
364
 
365
- #: lib/Config/Menu.php:210 lib/Config/Menu.php:211
366
  #: views/subscribers/importExport/export.html:6
367
  #: views/subscribers/importExport/export.html:96
368
  #: views/subscribers/subscribers.html:95
369
  msgid "Export"
370
  msgstr ""
371
 
372
- #: lib/Config/Menu.php:222 lib/Config/Menu.php:223 views/update.html:16
373
- #: views/welcome.html:16
374
- msgid "Welcome"
 
375
  msgstr ""
376
 
377
- #: lib/Config/Menu.php:234
378
- msgid "Migration"
 
379
  msgstr ""
380
 
381
- #: lib/Config/Menu.php:246 lib/Config/Menu.php:247 views/segments.html:43
382
- msgid "Update"
383
  msgstr ""
384
 
385
- #: lib/Config/Menu.php:258 lib/Config/Menu.php:259
386
- msgid "Form Editor"
387
  msgstr ""
388
 
389
- #: lib/Config/Menu.php:270 lib/Newsletter/Shortcodes/ShortcodesHelper.php:33
390
- #: views/newsletter/templates/components/sidebar/styles.hbs:75
391
- #: views/newsletters.html:121
392
- msgid "Newsletter"
393
  msgstr ""
394
 
395
- #: lib/Config/Menu.php:271 views/newsletter/editor.html:228
396
- msgid "Newsletter Editor"
397
  msgstr ""
398
 
399
- #: lib/Config/Menu.php:484
 
 
 
 
400
  msgid "In any WordPress role"
401
  msgstr ""
402
 
403
- #: lib/Config/Menu.php:560 views/premium.html:41
404
  msgid "MailPoet"
405
  msgstr ""
406
 
@@ -987,27 +995,28 @@ msgid ""
987
  "email plan[/link] by %s to keep sending them to your subscribers."
988
  msgstr ""
989
 
990
- #: lib/Config/ServicesChecker.php:74
991
  msgid ""
992
- "Warning! Your License Key is either invalid or expired. [link]Renew your "
993
- "License now[/link] to enjoy automatic updates and Premium support."
 
994
  msgstr ""
995
 
996
- #: lib/Config/ServicesChecker.php:88
997
  msgid ""
998
  "Your License Key is expiring! Don't forget to [link]renew your "
999
  "license[/link] by %s to keep enjoying automatic updates and Premium support."
1000
  msgstr ""
1001
 
1002
- #: lib/Config/Shortcodes.php:85
1003
  msgid "Oops! There are no newsletters to display."
1004
  msgstr ""
1005
 
1006
- #: lib/Config/Shortcodes.php:124
1007
  msgid "Preview in a new tab"
1008
  msgstr ""
1009
 
1010
- #: lib/Config/Widget.php:116
1011
  msgid "An error has happened while performing a request, please try again later."
1012
  msgstr ""
1013
 
@@ -1154,6 +1163,10 @@ msgstr ""
1154
  msgid "December"
1155
  msgstr ""
1156
 
 
 
 
 
1157
  #: lib/Form/Util/Export.php:55
1158
  msgid "BEGIN Scripts: you should place them in the header of your theme"
1159
  msgstr ""
@@ -1477,11 +1490,11 @@ msgstr ""
1477
  msgid "View in your browser"
1478
  msgstr ""
1479
 
1480
- #: lib/Router/Router.php:34
1481
  msgid "Invalid router endpoint"
1482
  msgstr ""
1483
 
1484
- #: lib/Router/Router.php:38
1485
  msgid "Invalid router endpoint action"
1486
  msgstr ""
1487
 
@@ -1797,23 +1810,23 @@ msgstr ""
1797
  msgid "Saved! Add this form to %1$sa widget%2$s."
1798
  msgstr ""
1799
 
1800
- #: views/form/editor.html:578 views/subscribers/importExport/import.html:50
1801
  msgid "Add new field"
1802
  msgstr ""
1803
 
1804
- #: views/form/editor.html:598 views/form/templates/toolbar/fields.hbs:14
1805
  msgid "Edit field"
1806
  msgstr ""
1807
 
1808
- #: views/form/editor.html:619
1809
  msgid "This field will be deleted for all your subscribers. Are you sure?"
1810
  msgstr ""
1811
 
1812
- #: views/form/editor.html:637
1813
  msgid "Removed custom field %$1s"
1814
  msgstr ""
1815
 
1816
- #: views/form/editor.html:717
1817
  msgid "Edit field settings"
1818
  msgstr ""
1819
 
@@ -1938,11 +1951,11 @@ msgstr ""
1938
  msgid "Done"
1939
  msgstr ""
1940
 
1941
- #: views/form/templates/settings/field_form.hbs:94
1942
  msgid "Updated custom field %$1s"
1943
  msgstr ""
1944
 
1945
- #: views/form/templates/settings/field_form.hbs:98
1946
  msgid "Added custom field %$1s"
1947
  msgstr ""
1948
 
@@ -5165,27 +5178,27 @@ msgid ""
5165
  "newsletter. Sign up below!"
5166
  msgstr ""
5167
 
5168
- #: lib/API/JSON/v1/Services.php:137
5169
  msgctxt "Error code (inside parentheses)"
5170
  msgid "code: %s"
5171
  msgstr ""
5172
 
5173
- #: lib/Config/Menu.php:80
5174
  msgctxt "newsletters per page (screen options)"
5175
  msgid "Number of newsletters per page"
5176
  msgstr ""
5177
 
5178
- #: lib/Config/Menu.php:103
5179
  msgctxt "forms per page (screen options)"
5180
  msgid "Number of forms per page"
5181
  msgstr ""
5182
 
5183
- #: lib/Config/Menu.php:126
5184
  msgctxt "subscribers per page (screen options)"
5185
  msgid "Number of subscribers per page"
5186
  msgstr ""
5187
 
5188
- #: lib/Config/Menu.php:150
5189
  msgctxt "segments per page (screen options)"
5190
  msgid "Number of segments per page"
5191
  msgstr ""
4
  msgstr ""
5
  "Project-Id-Version: \n"
6
  "Report-Msgid-Bugs-To: http://support.mailpoet.com/\n"
7
+ "POT-Creation-Date: 2017-08-29 13:18:15+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
26
  "X-Poedit-Bookmarks: \n"
27
  "X-Textdomain-Support: yes\n"
28
 
29
+ #: lib/API/API.php:19
30
  msgid "Invalid API version."
31
  msgstr ""
32
 
33
+ #: lib/API/JSON/API.php:60 lib/API/JSON/API.php:87
34
  msgid "Invalid API request."
35
  msgstr ""
36
 
37
+ #: lib/API/JSON/API.php:128
38
  msgid "Invalid API endpoint."
39
  msgstr ""
40
 
41
+ #: lib/API/JSON/API.php:136 lib/Router/Router.php:45
42
  msgid "You do not have the required permissions."
43
  msgstr ""
44
 
45
+ #: lib/API/JSON/Endpoint.php:26
46
  msgid "An unknown error occurred."
47
  msgstr ""
48
 
49
+ #: lib/API/JSON/Endpoint.php:35
50
  msgid "Invalid request parameters"
51
  msgstr ""
52
 
53
+ #: lib/API/JSON/v1/CustomFields.php:31 lib/API/JSON/v1/CustomFields.php:58
54
  msgid "This custom field does not exist."
55
  msgstr ""
56
 
57
+ #: lib/API/JSON/v1/Forms.php:26 lib/API/JSON/v1/Forms.php:133
58
+ #: lib/API/JSON/v1/Forms.php:215 lib/API/JSON/v1/Forms.php:231
59
+ #: lib/API/JSON/v1/Forms.php:247 lib/API/JSON/v1/Forms.php:261
60
  msgid "This form does not exist."
61
  msgstr ""
62
 
63
+ #: lib/API/JSON/v1/Forms.php:66 lib/API/JSON/v1/Forms.php:145
64
  msgid "New form"
65
  msgstr ""
66
 
67
+ #: lib/API/JSON/v1/Forms.php:70 lib/API/JSON/v1/Forms.php:74
68
  #: lib/API/MP/v1/API.php:17
69
  #: lib/Subscribers/ImportExport/ImportExportFactory.php:32
70
  #: views/newsletter/editor.html:938 views/newsletter/editor.html:939
71
  msgid "Email"
72
  msgstr ""
73
 
74
+ #: lib/API/JSON/v1/Forms.php:80
75
  msgid "Submit"
76
  msgstr ""
77
 
78
+ #: lib/API/JSON/v1/Forms.php:84
79
  msgid "Subscribe!"
80
  msgstr ""
81
 
82
+ #: lib/API/JSON/v1/Forms.php:90
83
  msgid "Check your inbox or spam folder to confirm your subscription."
84
  msgstr ""
85
 
86
+ #: lib/API/JSON/v1/Forms.php:265 lib/API/JSON/v1/Newsletters.php:230
87
+ #: lib/API/JSON/v1/Segments.php:125
88
  msgid "Copy of %s"
89
  msgstr ""
90
 
91
+ #: lib/API/JSON/v1/Mailer.php:36 lib/API/JSON/v1/Newsletters.php:332
92
  msgid "The email could not be sent: %s"
93
  msgstr ""
94
 
95
+ #: lib/API/JSON/v1/NewsletterTemplates.php:22
96
+ #: lib/API/JSON/v1/NewsletterTemplates.php:58
97
  msgid "This template does not exist."
98
  msgstr ""
99
 
100
+ #: lib/API/JSON/v1/Newsletters.php:37 lib/API/JSON/v1/Newsletters.php:148
101
+ #: lib/API/JSON/v1/Newsletters.php:180 lib/API/JSON/v1/Newsletters.php:196
102
+ #: lib/API/JSON/v1/Newsletters.php:212 lib/API/JSON/v1/Newsletters.php:226
103
+ #: lib/API/JSON/v1/Newsletters.php:259 lib/API/JSON/v1/Newsletters.php:290
104
+ #: lib/API/JSON/v1/SendingQueue.php:34 lib/API/JSON/v1/SendingQueue.php:121
105
+ #: lib/API/JSON/v1/SendingQueue.php:147
106
  msgid "This newsletter does not exist."
107
  msgstr ""
108
 
109
+ #: lib/API/JSON/v1/Newsletters.php:139
110
  msgid "You need to specify a status."
111
  msgstr ""
112
 
113
+ #: lib/API/JSON/v1/Newsletters.php:250
114
  msgid "Newsletter data is missing."
115
  msgstr ""
116
 
117
+ #: lib/API/JSON/v1/Newsletters.php:281
118
  msgid "Please specify receiver information."
119
  msgstr ""
120
 
121
+ #: lib/API/JSON/v1/Segments.php:24 lib/API/JSON/v1/Segments.php:75
122
+ #: lib/API/JSON/v1/Segments.php:91 lib/API/JSON/v1/Segments.php:107
123
+ #: lib/API/JSON/v1/Segments.php:121
124
  msgid "This list does not exist."
125
  msgstr ""
126
 
127
+ #: lib/API/JSON/v1/SendingQueue.php:54
128
  msgid "This newsletter is already being sent."
129
  msgstr ""
130
 
131
+ #: lib/API/JSON/v1/SendingQueue.php:85
132
  msgid "There are no subscribers in that list!"
133
  msgstr ""
134
 
135
+ #: lib/API/JSON/v1/SendingQueue.php:128 lib/API/JSON/v1/SendingQueue.php:154
136
  msgid "This newsletter has not been sent yet."
137
  msgstr ""
138
 
139
+ #: lib/API/JSON/v1/Services.php:31 lib/API/JSON/v1/Services.php:84
140
  msgid "Please specify a key."
141
  msgstr ""
142
 
143
+ #: lib/API/JSON/v1/Services.php:48 views/settings/premium.html:40
144
  msgid "Your MailPoet Sending Service key has been successfully validated."
145
  msgstr ""
146
 
147
+ #: lib/API/JSON/v1/Services.php:51
148
  msgid "Your MailPoet Sending Service key expires on %s!"
149
  msgstr ""
150
 
151
+ #: lib/API/JSON/v1/Services.php:62 views/settings/premium.html:45
152
  msgid "Your MailPoet Sending Service key is invalid."
153
  msgstr ""
154
 
155
+ #: lib/API/JSON/v1/Services.php:65
156
+ msgid "Your MailPoet Sending Service key is already used on another site."
157
+ msgstr ""
158
+
159
+ #: lib/API/JSON/v1/Services.php:70
160
  msgid "Error validating MailPoet Sending Service key, please try again later (%s)"
161
  msgstr ""
162
 
163
+ #: lib/API/JSON/v1/Services.php:101 views/settings/premium.html:30
164
  msgid "Your Premium key has been successfully validated."
165
  msgstr ""
166
 
167
+ #: lib/API/JSON/v1/Services.php:104
168
  msgid "Your Premium key expires on %s."
169
  msgstr ""
170
 
171
+ #: lib/API/JSON/v1/Services.php:118 views/settings/premium.html:35
172
  msgid "Your Premium key is invalid."
173
  msgstr ""
174
 
175
+ #: lib/API/JSON/v1/Services.php:121
176
  msgid "Your Premium key is already used on another site."
177
  msgstr ""
178
 
179
+ #: lib/API/JSON/v1/Services.php:126
180
  msgid "Error validating Premium key, please try again later (%s)"
181
  msgstr ""
182
 
183
+ #: lib/API/JSON/v1/Services.php:138
184
  msgid "Service unavailable"
185
  msgstr ""
186
 
187
+ #: lib/API/JSON/v1/Services.php:141
188
  msgid ""
189
  "Contact your hosting support to check the connection between your host and "
190
  "https://bridge.mailpoet.com"
191
  msgstr ""
192
 
193
+ #: lib/API/JSON/v1/Settings.php:27
194
  msgid "You have not specified any settings to be saved."
195
  msgstr ""
196
 
197
+ #: lib/API/JSON/v1/Subscribers.php:27 lib/API/JSON/v1/Subscribers.php:153
198
+ #: lib/API/JSON/v1/Subscribers.php:169 lib/API/JSON/v1/Subscribers.php:185
199
  #: lib/API/MP/v1/API.php:48
200
  msgid "This subscriber does not exist."
201
  msgstr ""
202
 
203
+ #: lib/API/JSON/v1/Subscribers.php:68
204
  msgid "Please specify a valid form ID."
205
  msgstr ""
206
 
207
+ #: lib/API/JSON/v1/Subscribers.php:73
208
  msgid "Please leave the first field empty."
209
  msgstr ""
210
 
211
+ #: lib/API/JSON/v1/Subscribers.php:88 views/form/editor.html:57
212
  msgid "Please select a list."
213
  msgstr ""
214
 
242
  msgid "MailPoet Newsletter"
243
  msgstr ""
244
 
245
+ #: lib/Config/Initializer.php:140
246
+ msgid "You do not have permission to activate/deactivate MailPoet plugin."
247
+ msgstr ""
248
+
249
  #: lib/Config/MP2Migrator.php:151
250
  msgid "START IMPORT"
251
  msgstr ""
258
  msgid "END IMPORT"
259
  msgstr ""
260
 
261
+ #: lib/Config/MP2Migrator.php:196
262
  msgid "MailPoet data erased"
263
  msgstr ""
264
 
265
+ #: lib/Config/MP2Migrator.php:226 views/mp2migration.html:69
266
  msgid "IMPORT STOPPED BY USER"
267
  msgstr ""
268
 
269
+ #: lib/Config/MP2Migrator.php:258
270
  msgid "MailPoet 2 data found:"
271
  msgstr ""
272
 
273
+ #: lib/Config/MP2Migrator.php:263
274
  msgid "%d subscribers list"
275
  msgid_plural "%d subscribers lists"
276
  msgstr[0] ""
277
  msgstr[1] ""
278
 
279
+ #: lib/Config/MP2Migrator.php:268
280
  msgid "%d subscriber"
281
  msgid_plural "%d subscribers"
282
  msgstr[0] ""
283
  msgstr[1] ""
284
 
285
+ #: lib/Config/MP2Migrator.php:273
286
  msgid "%d form"
287
  msgid_plural "%d forms"
288
  msgstr[0] ""
289
  msgstr[1] ""
290
 
291
+ #: lib/Config/MP2Migrator.php:290
292
  msgid "Importing segments..."
293
  msgstr ""
294
 
295
+ #: lib/Config/MP2Migrator.php:311
296
  msgid "%d segment imported"
297
  msgid_plural "%d segments imported"
298
  msgstr[0] ""
299
  msgstr[1] ""
300
 
301
+ #: lib/Config/MP2Migrator.php:380
302
  msgid "Importing custom fields..."
303
  msgstr ""
304
 
305
+ #: lib/Config/MP2Migrator.php:390
306
  msgid "%d custom field imported"
307
  msgid_plural "%d custom fields imported"
308
  msgstr[0] ""
309
  msgstr[1] ""
310
 
311
+ #: lib/Config/MP2Migrator.php:528
312
  msgid "Importing subscribers..."
313
  msgstr ""
314
 
315
+ #: lib/Config/MP2Migrator.php:550
316
  msgid "%d subscriber imported"
317
  msgid_plural "%d subscribers imported"
318
  msgstr[0] ""
319
  msgstr[1] ""
320
 
321
+ #: lib/Config/MP2Migrator.php:776
322
  msgid "Importing forms..."
323
  msgstr ""
324
 
325
+ #: lib/Config/MP2Migrator.php:795
326
  msgid "%d form imported"
327
  msgid_plural "%d forms imported"
328
  msgstr[0] ""
329
  msgstr[1] ""
330
 
331
+ #: lib/Config/MP2Migrator.php:1059
332
  msgid "Settings imported"
333
  msgstr ""
334
 
335
+ #: lib/Config/Menu.php:79 lib/Config/Menu.php:80 views/newsletters.html:23
336
  msgid "Emails"
337
  msgstr ""
338
 
339
+ #: lib/Config/Menu.php:104 lib/Newsletter/Shortcodes/ShortcodesHelper.php:33
340
+ #: views/newsletter/templates/components/sidebar/styles.hbs:75
341
+ #: views/newsletters.html:121
342
+ msgid "Newsletter"
 
 
 
343
  msgstr ""
344
 
345
+ #: lib/Config/Menu.php:105 views/newsletter/editor.html:228
346
+ msgid "Newsletter Editor"
 
 
347
  msgstr ""
348
 
349
+ #: lib/Config/Menu.php:119 lib/Config/Menu.php:120 views/forms.html:25
350
+ msgid "Forms"
 
351
  msgstr ""
352
 
353
+ #: lib/Config/Menu.php:144 lib/Config/Menu.php:145
354
+ msgid "Form Editor"
355
  msgstr ""
356
 
357
+ #: lib/Config/Menu.php:159 lib/Config/Menu.php:160
358
+ #: views/subscribers/subscribers.html:18
359
+ msgid "Subscribers"
360
  msgstr ""
361
 
362
+ #: lib/Config/Menu.php:184 lib/Config/Menu.php:185
363
  #: views/subscribers/importExport/import.html:7
364
  #: views/subscribers/subscribers.html:94
365
  msgid "Import"
366
  msgstr ""
367
 
368
+ #: lib/Config/Menu.php:197 lib/Config/Menu.php:198
369
  #: views/subscribers/importExport/export.html:6
370
  #: views/subscribers/importExport/export.html:96
371
  #: views/subscribers/subscribers.html:95
372
  msgid "Export"
373
  msgstr ""
374
 
375
+ #: lib/Config/Menu.php:212 lib/Config/Menu.php:213 views/forms.html:53
376
+ #: views/newsletters.html:64 views/newsletters.html:166 views/segments.html:13
377
+ #: views/subscribers/subscribers.html:66
378
+ msgid "Lists"
379
  msgstr ""
380
 
381
+ #: lib/Config/Menu.php:239 lib/Config/Menu.php:240 views/form/editor.html:37
382
+ #: views/newsletters.html:65 views/settings.html:6
383
+ msgid "Settings"
384
  msgstr ""
385
 
386
+ #: lib/Config/Menu.php:253 lib/Config/Menu.php:254 views/help.html:5
387
+ msgid "Help"
388
  msgstr ""
389
 
390
+ #: lib/Config/Menu.php:267 lib/Config/Menu.php:268 views/settings.html:22
391
+ msgid "Premium"
392
  msgstr ""
393
 
394
+ #: lib/Config/Menu.php:280 lib/Config/Menu.php:281 views/update.html:16
395
+ #: views/welcome.html:16
396
+ msgid "Welcome"
 
397
  msgstr ""
398
 
399
+ #: lib/Config/Menu.php:293 lib/Config/Menu.php:294 views/segments.html:43
400
+ msgid "Update"
401
  msgstr ""
402
 
403
+ #: lib/Config/Menu.php:306
404
+ msgid "Migration"
405
+ msgstr ""
406
+
407
+ #: lib/Config/Menu.php:520
408
  msgid "In any WordPress role"
409
  msgstr ""
410
 
411
+ #: lib/Config/Menu.php:596 views/premium.html:41
412
  msgid "MailPoet"
413
  msgstr ""
414
 
995
  "email plan[/link] by %s to keep sending them to your subscribers."
996
  msgstr ""
997
 
998
+ #: lib/Config/ServicesChecker.php:73
999
  msgid ""
1000
+ "[link1]Register[/link1] your copy of the MailPoet Premium plugin to receive "
1001
+ "access to automatic upgrades and support. Need a license key? "
1002
+ "[link2]Purchase one now.[/link2]"
1003
  msgstr ""
1004
 
1005
+ #: lib/Config/ServicesChecker.php:96
1006
  msgid ""
1007
  "Your License Key is expiring! Don't forget to [link]renew your "
1008
  "license[/link] by %s to keep enjoying automatic updates and Premium support."
1009
  msgstr ""
1010
 
1011
+ #: lib/Config/Shortcodes.php:84
1012
  msgid "Oops! There are no newsletters to display."
1013
  msgstr ""
1014
 
1015
+ #: lib/Config/Shortcodes.php:123
1016
  msgid "Preview in a new tab"
1017
  msgstr ""
1018
 
1019
+ #: lib/Config/Widget.php:118
1020
  msgid "An error has happened while performing a request, please try again later."
1021
  msgstr ""
1022
 
1163
  msgid "December"
1164
  msgstr ""
1165
 
1166
+ #: lib/Form/Renderer.php:44
1167
+ msgid "Please leave this field empty"
1168
+ msgstr ""
1169
+
1170
  #: lib/Form/Util/Export.php:55
1171
  msgid "BEGIN Scripts: you should place them in the header of your theme"
1172
  msgstr ""
1490
  msgid "View in your browser"
1491
  msgstr ""
1492
 
1493
+ #: lib/Router/Router.php:38
1494
  msgid "Invalid router endpoint"
1495
  msgstr ""
1496
 
1497
+ #: lib/Router/Router.php:42
1498
  msgid "Invalid router endpoint action"
1499
  msgstr ""
1500
 
1810
  msgid "Saved! Add this form to %1$sa widget%2$s."
1811
  msgstr ""
1812
 
1813
+ #: views/form/editor.html:587 views/subscribers/importExport/import.html:50
1814
  msgid "Add new field"
1815
  msgstr ""
1816
 
1817
+ #: views/form/editor.html:607 views/form/templates/toolbar/fields.hbs:14
1818
  msgid "Edit field"
1819
  msgstr ""
1820
 
1821
+ #: views/form/editor.html:629
1822
  msgid "This field will be deleted for all your subscribers. Are you sure?"
1823
  msgstr ""
1824
 
1825
+ #: views/form/editor.html:647
1826
  msgid "Removed custom field %$1s"
1827
  msgstr ""
1828
 
1829
+ #: views/form/editor.html:733
1830
  msgid "Edit field settings"
1831
  msgstr ""
1832
 
1951
  msgid "Done"
1952
  msgstr ""
1953
 
1954
+ #: views/form/templates/settings/field_form.hbs:99
1955
  msgid "Updated custom field %$1s"
1956
  msgstr ""
1957
 
1958
+ #: views/form/templates/settings/field_form.hbs:103
1959
  msgid "Added custom field %$1s"
1960
  msgstr ""
1961
 
5178
  "newsletter. Sign up below!"
5179
  msgstr ""
5180
 
5181
+ #: lib/API/JSON/v1/Services.php:144
5182
  msgctxt "Error code (inside parentheses)"
5183
  msgid "code: %s"
5184
  msgstr ""
5185
 
5186
+ #: lib/Config/Menu.php:92
5187
  msgctxt "newsletters per page (screen options)"
5188
  msgid "Number of newsletters per page"
5189
  msgstr ""
5190
 
5191
+ #: lib/Config/Menu.php:132
5192
  msgctxt "forms per page (screen options)"
5193
  msgid "Number of forms per page"
5194
  msgstr ""
5195
 
5196
+ #: lib/Config/Menu.php:172
5197
  msgctxt "subscribers per page (screen options)"
5198
  msgid "Number of subscribers per page"
5199
  msgstr ""
5200
 
5201
+ #: lib/Config/Menu.php:225
5202
  msgctxt "segments per page (screen options)"
5203
  msgid "Number of segments per page"
5204
  msgstr ""
lib/API/API.php CHANGED
@@ -1,11 +1,14 @@
1
  <?php
 
2
  namespace MailPoet\API;
3
 
 
 
4
  if(!defined('ABSPATH')) exit;
5
 
6
  class API {
7
- static function JSON() {
8
- return new \MailPoet\API\JSON\API();
9
  }
10
 
11
  static function MP($version) {
1
  <?php
2
+
3
  namespace MailPoet\API;
4
 
5
+ use MailPoet\Config\AccessControl;
6
+
7
  if(!defined('ABSPATH')) exit;
8
 
9
  class API {
10
+ static function JSON(AccessControl $access_control) {
11
+ return new \MailPoet\API\JSON\API($access_control);
12
  }
13
 
14
  static function MP($version) {
lib/API/JSON/API.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  namespace MailPoet\API\JSON;
3
 
4
- use MailPoet\Config\Env;
5
  use MailPoet\Util\Helpers;
6
  use MailPoet\Util\Security;
7
  use MailPoet\WP\Hooks;
@@ -19,9 +19,11 @@ class API {
19
  private $_available_api_versions = array(
20
  'v1'
21
  );
 
22
  const CURRENT_VERSION = 'v1';
23
 
24
- function __construct() {
 
25
  foreach($this->_available_api_versions as $available_api_version) {
26
  $this->addEndpointNamespace(
27
  sprintf('%s\%s', __NAMESPACE__, $available_api_version),
@@ -130,17 +132,11 @@ class API {
130
 
131
  // check the accessibility of the requested endpoint's action
132
  // by default, an endpoint's action is considered "private"
133
- $permissions = $endpoint->permissions;
134
- if(array_key_exists($this->_request_method, $permissions) === false ||
135
- $permissions[$this->_request_method] !== Access::ALL
136
- ) {
137
- if($this->checkPermissions() === false) {
138
- $error_message = __('You do not have the required permissions.', 'mailpoet');
139
- $error_response = $this->createErrorResponse(Error::FORBIDDEN, $error_message, Response::STATUS_FORBIDDEN);
140
- return $error_response;
141
- }
142
  }
143
-
144
  $response = $endpoint->{$this->_request_method}($this->_request_data);
145
  return $response;
146
  } catch(\Exception $e) {
@@ -150,8 +146,11 @@ class API {
150
  }
151
  }
152
 
153
- function checkPermissions() {
154
- return current_user_can(Env::$required_permission);
 
 
 
155
  }
156
 
157
  function checkToken() {
1
  <?php
2
  namespace MailPoet\API\JSON;
3
 
4
+ use MailPoet\Config\AccessControl;
5
  use MailPoet\Util\Helpers;
6
  use MailPoet\Util\Security;
7
  use MailPoet\WP\Hooks;
19
  private $_available_api_versions = array(
20
  'v1'
21
  );
22
+ private $access_control;
23
  const CURRENT_VERSION = 'v1';
24
 
25
+ function __construct(AccessControl $access_control) {
26
+ $this->access_control = $access_control;
27
  foreach($this->_available_api_versions as $available_api_version) {
28
  $this->addEndpointNamespace(
29
  sprintf('%s\%s', __NAMESPACE__, $available_api_version),
132
 
133
  // check the accessibility of the requested endpoint's action
134
  // by default, an endpoint's action is considered "private"
135
+ if(!$this->validatePermissions($this->_request_method, $endpoint->permissions)) {
136
+ $error_message = __('You do not have the required permissions.', 'mailpoet');
137
+ $error_response = $this->createErrorResponse(Error::FORBIDDEN, $error_message, Response::STATUS_FORBIDDEN);
138
+ return $error_response;
 
 
 
 
 
139
  }
 
140
  $response = $endpoint->{$this->_request_method}($this->_request_data);
141
  return $response;
142
  } catch(\Exception $e) {
146
  }
147
  }
148
 
149
+ function validatePermissions($request_method, $permissions) {
150
+ // validate method permission if defined, otherwise validate global permission
151
+ return(!empty($permissions['methods'][$request_method])) ?
152
+ $this->access_control->validatePermission($permissions['methods'][$request_method]) :
153
+ $this->access_control->validatePermission($permissions['global']);
154
  }
155
 
156
  function checkToken() {
lib/API/JSON/Access.php DELETED
@@ -1,12 +0,0 @@
1
- <?php
2
- namespace MailPoet\API\JSON;
3
-
4
- if(!defined('ABSPATH')) exit;
5
-
6
- final class Access {
7
- const ALL = 'all';
8
-
9
- private function __construct() {
10
-
11
- }
12
- }
 
 
 
 
 
 
 
 
 
 
 
 
lib/API/JSON/Endpoint.php CHANGED
@@ -1,11 +1,16 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON;
3
 
 
 
4
  if(!defined('ABSPATH')) exit;
5
 
6
  abstract class Endpoint {
7
-
8
- public $permissions = array();
 
 
9
 
10
  function successResponse(
11
  $data = array(), $meta = array(), $status = Response::STATUS_OK
@@ -18,7 +23,7 @@ abstract class Endpoint {
18
  ) {
19
  if(empty($errors)) {
20
  $errors = array(
21
- Error::UNKNOWN => __('An unknown error occurred.', 'mailpoet')
22
  );
23
  }
24
  return new ErrorResponse($errors, $meta, $status);
1
  <?php
2
+
3
  namespace MailPoet\API\JSON;
4
 
5
+ use MailPoet\Config\AccessControl;
6
+
7
  if(!defined('ABSPATH')) exit;
8
 
9
  abstract class Endpoint {
10
+ public $permissions = array(
11
+ 'global' => AccessControl::PERMISSION_MANAGE_SETTINGS,
12
+ 'methods' => array()
13
+ );
14
 
15
  function successResponse(
16
  $data = array(), $meta = array(), $status = Response::STATUS_OK
23
  ) {
24
  if(empty($errors)) {
25
  $errors = array(
26
+ Error::UNKNOWN => __('An unknown error occurred.', 'mailpoet')
27
  );
28
  }
29
  return new ErrorResponse($errors, $meta, $status);
lib/API/JSON/v1/AutomatedLatestContent.php CHANGED
@@ -1,12 +1,18 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
 
3
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
 
4
  use MailPoet\WP\Posts as WPPosts;
5
 
6
  if(!defined('ABSPATH')) exit;
7
 
8
  class AutomatedLatestContent extends APIEndpoint {
9
  public $ALC;
 
 
 
10
 
11
  function __construct() {
12
  $this->ALC = new \MailPoet\Newsletter\AutomatedLatestContent();
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
4
+
5
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
6
+ use MailPoet\Config\AccessControl;
7
  use MailPoet\WP\Posts as WPPosts;
8
 
9
  if(!defined('ABSPATH')) exit;
10
 
11
  class AutomatedLatestContent extends APIEndpoint {
12
  public $ALC;
13
+ public $permissions = array(
14
+ 'global' => AccessControl::PERMISSION_MANAGE_EMAILS
15
+ );
16
 
17
  function __construct() {
18
  $this->ALC = new \MailPoet\Newsletter\AutomatedLatestContent();
lib/API/JSON/v1/CustomFields.php CHANGED
@@ -1,12 +1,19 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
 
3
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
4
  use MailPoet\API\JSON\Error as APIError;
 
5
  use MailPoet\Models\CustomField;
6
 
7
  if(!defined('ABSPATH')) exit;
8
 
9
  class CustomFields extends APIEndpoint {
 
 
 
 
10
  function getAll() {
11
  $collection = CustomField::orderByAsc('created_at')->findMany();
12
  $custom_fields = array_map(function($custom_field) {
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
4
+
5
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
6
  use MailPoet\API\JSON\Error as APIError;
7
+ use MailPoet\Config\AccessControl;
8
  use MailPoet\Models\CustomField;
9
 
10
  if(!defined('ABSPATH')) exit;
11
 
12
  class CustomFields extends APIEndpoint {
13
+ public $permissions = array(
14
+ 'global' => AccessControl::PERMISSION_MANAGE_FORMS
15
+ );
16
+
17
  function getAll() {
18
  $collection = CustomField::orderByAsc('created_at')->findMany();
19
  $custom_fields = array_map(function($custom_field) {
lib/API/JSON/v1/Forms.php CHANGED
@@ -1,17 +1,23 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
 
3
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
4
  use MailPoet\API\JSON\Error as APIError;
5
-
6
- use MailPoet\Models\Form;
7
- use MailPoet\Models\StatisticsForms;
8
  use MailPoet\Form\Renderer as FormRenderer;
9
- use MailPoet\Listing;
10
  use MailPoet\Form\Util;
 
 
 
11
 
12
  if(!defined('ABSPATH')) exit;
13
 
14
  class Forms extends APIEndpoint {
 
 
 
 
15
  function get($data = array()) {
16
  $id = (isset($data['id']) ? (int)$data['id'] : false);
17
  $form = Form::findOne($id);
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
4
+
5
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
6
  use MailPoet\API\JSON\Error as APIError;
7
+ use MailPoet\Config\AccessControl;
 
 
8
  use MailPoet\Form\Renderer as FormRenderer;
 
9
  use MailPoet\Form\Util;
10
+ use MailPoet\Listing;
11
+ use MailPoet\Models\Form;
12
+ use MailPoet\Models\StatisticsForms;
13
 
14
  if(!defined('ABSPATH')) exit;
15
 
16
  class Forms extends APIEndpoint {
17
+ public $permissions = array(
18
+ 'global' => AccessControl::PERMISSION_MANAGE_FORMS
19
+ );
20
+
21
  function get($data = array()) {
22
  $id = (isset($data['id']) ? (int)$data['id'] : false);
23
  $form = Form::findOne($id);
lib/API/JSON/v1/ImportExport.php CHANGED
@@ -1,13 +1,19 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
3
- use MailPoet\API\JSON\Endpoint as APIEndpoint;
4
 
5
- use MailPoet\Subscribers\ImportExport\Import\MailChimp;
 
6
  use MailPoet\Models\Segment;
 
7
 
8
  if(!defined('ABSPATH')) exit;
9
 
10
  class ImportExport extends APIEndpoint {
 
 
 
 
11
  function getMailChimpLists($data) {
12
  try {
13
  $mailChimp = new MailChimp($data['api_key']);
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
 
4
 
5
+ use MailPoet\API\JSON\Endpoint as APIEndpoint;
6
+ use MailPoet\Config\AccessControl;
7
  use MailPoet\Models\Segment;
8
+ use MailPoet\Subscribers\ImportExport\Import\MailChimp;
9
 
10
  if(!defined('ABSPATH')) exit;
11
 
12
  class ImportExport extends APIEndpoint {
13
+ public $permissions = array(
14
+ 'global' => AccessControl::PERMISSION_MANAGE_SUBSCRIBERS
15
+ );
16
+
17
  function getMailChimpLists($data) {
18
  try {
19
  $mailChimp = new MailChimp($data['api_key']);
lib/API/JSON/v1/MP2Migrator.php CHANGED
@@ -1,18 +1,24 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
 
3
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
 
4
 
5
  if(!defined('ABSPATH')) exit;
6
 
7
  class MP2Migrator extends APIEndpoint {
8
-
 
 
 
9
  public function __construct() {
10
  $this->MP2Migrator = new \MailPoet\Config\MP2Migrator();
11
  }
12
-
13
  /**
14
  * Import end point
15
- *
16
  * @param object $data
17
  * @return object
18
  */
@@ -26,10 +32,10 @@ class MP2Migrator extends APIEndpoint {
26
  ));
27
  }
28
  }
29
-
30
  /**
31
  * Stop import end point
32
- *
33
  * @param object $data
34
  * @return object
35
  */
@@ -43,10 +49,10 @@ class MP2Migrator extends APIEndpoint {
43
  ));
44
  }
45
  }
46
-
47
  /**
48
  * Skip import end point
49
- *
50
  * @param object $data
51
  * @return object
52
  */
@@ -60,5 +66,5 @@ class MP2Migrator extends APIEndpoint {
60
  ));
61
  }
62
  }
63
-
64
  }
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
4
+
5
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
6
+ use MailPoet\Config\AccessControl;
7
 
8
  if(!defined('ABSPATH')) exit;
9
 
10
  class MP2Migrator extends APIEndpoint {
11
+ public $permissions = array(
12
+ 'global' => AccessControl::PERMISSION_MANAGE_SETTINGS
13
+ );
14
+
15
  public function __construct() {
16
  $this->MP2Migrator = new \MailPoet\Config\MP2Migrator();
17
  }
18
+
19
  /**
20
  * Import end point
21
+ *
22
  * @param object $data
23
  * @return object
24
  */
32
  ));
33
  }
34
  }
35
+
36
  /**
37
  * Stop import end point
38
+ *
39
  * @param object $data
40
  * @return object
41
  */
49
  ));
50
  }
51
  }
52
+
53
  /**
54
  * Skip import end point
55
+ *
56
  * @param object $data
57
  * @return object
58
  */
66
  ));
67
  }
68
  }
69
+
70
  }
lib/API/JSON/v1/Mailer.php CHANGED
@@ -1,12 +1,19 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
 
3
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
4
  use MailPoet\API\JSON\Error as APIError;
 
5
  use MailPoet\Mailer\MailerLog;
6
 
7
  if(!defined('ABSPATH')) exit;
8
 
9
  class Mailer extends APIEndpoint {
 
 
 
 
10
  function send($data = array()) {
11
  try {
12
  $mailer = new \MailPoet\Mailer\Mailer(
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
4
+
5
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
6
  use MailPoet\API\JSON\Error as APIError;
7
+ use MailPoet\Config\AccessControl;
8
  use MailPoet\Mailer\MailerLog;
9
 
10
  if(!defined('ABSPATH')) exit;
11
 
12
  class Mailer extends APIEndpoint {
13
+ public $permissions = array(
14
+ 'global' => AccessControl::PERMISSION_MANAGE_EMAILS
15
+ );
16
+
17
  function send($data = array()) {
18
  try {
19
  $mailer = new \MailPoet\Mailer\Mailer(
lib/API/JSON/v1/NewsletterTemplates.php CHANGED
@@ -1,13 +1,19 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
 
3
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
4
  use MailPoet\API\JSON\Error as APIError;
5
-
6
  use MailPoet\Models\NewsletterTemplate;
7
 
8
  if(!defined('ABSPATH')) exit;
9
 
10
  class NewsletterTemplates extends APIEndpoint {
 
 
 
 
11
  function get($data = array()) {
12
  $id = (isset($data['id']) ? (int)$data['id'] : false);
13
  $template = NewsletterTemplate::findOne($id);
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
4
+
5
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
6
  use MailPoet\API\JSON\Error as APIError;
7
+ use MailPoet\Config\AccessControl;
8
  use MailPoet\Models\NewsletterTemplate;
9
 
10
  if(!defined('ABSPATH')) exit;
11
 
12
  class NewsletterTemplates extends APIEndpoint {
13
+ public $permissions = array(
14
+ 'global' => AccessControl::PERMISSION_MANAGE_EMAILS
15
+ );
16
+
17
  function get($data = array()) {
18
  $id = (isset($data['id']) ? (int)$data['id'] : false);
19
  $template = NewsletterTemplate::findOne($id);
lib/API/JSON/v1/Newsletters.php CHANGED
@@ -1,16 +1,19 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
3
 
 
4
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
5
  use MailPoet\API\JSON\Error as APIError;
 
6
  use MailPoet\Listing;
7
- use MailPoet\Models\SendingQueue;
8
- use MailPoet\Models\Setting;
9
  use MailPoet\Models\Newsletter;
10
- use MailPoet\Models\NewsletterTemplate;
11
- use MailPoet\Models\NewsletterSegment;
12
- use MailPoet\Models\NewsletterOptionField;
13
  use MailPoet\Models\NewsletterOption;
 
 
 
 
 
14
  use MailPoet\Models\Subscriber;
15
  use MailPoet\Newsletter\Renderer\Renderer;
16
  use MailPoet\Newsletter\Scheduler\Scheduler;
@@ -22,6 +25,10 @@ if(!defined('ABSPATH')) exit;
22
  require_once(ABSPATH . 'wp-includes/pluggable.php');
23
 
24
  class Newsletters extends APIEndpoint {
 
 
 
 
25
  function get($data = array()) {
26
  $id = (isset($data['id']) ? (int)$data['id'] : false);
27
  $newsletter = Newsletter::findOne($id);
@@ -134,7 +141,7 @@ class Newsletters extends APIEndpoint {
134
  }
135
 
136
  $id = (isset($data['id'])) ? (int)$data['id'] : false;
137
- $newsletter = Newsletter::findOne($id);
138
 
139
  if($newsletter === false) {
140
  return $this->errorResponse(array(
@@ -147,11 +154,22 @@ class Newsletters extends APIEndpoint {
147
 
148
  if(!empty($errors)) {
149
  return $this->errorResponse($errors);
150
- } else {
151
- return $this->successResponse(
152
- Newsletter::findOne($newsletter->id)->asArray()
153
- );
154
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  }
156
 
157
  function restore($data = array()) {
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
4
 
5
+ use Carbon\Carbon;
6
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
7
  use MailPoet\API\JSON\Error as APIError;
8
+ use MailPoet\Config\AccessControl;
9
  use MailPoet\Listing;
 
 
10
  use MailPoet\Models\Newsletter;
 
 
 
11
  use MailPoet\Models\NewsletterOption;
12
+ use MailPoet\Models\NewsletterOptionField;
13
+ use MailPoet\Models\NewsletterSegment;
14
+ use MailPoet\Models\NewsletterTemplate;
15
+ use MailPoet\Models\SendingQueue;
16
+ use MailPoet\Models\Setting;
17
  use MailPoet\Models\Subscriber;
18
  use MailPoet\Newsletter\Renderer\Renderer;
19
  use MailPoet\Newsletter\Scheduler\Scheduler;
25
  require_once(ABSPATH . 'wp-includes/pluggable.php');
26
 
27
  class Newsletters extends APIEndpoint {
28
+ public $permissions = array(
29
+ 'global' => AccessControl::PERMISSION_MANAGE_EMAILS
30
+ );
31
+
32
  function get($data = array()) {
33
  $id = (isset($data['id']) ? (int)$data['id'] : false);
34
  $newsletter = Newsletter::findOne($id);
141
  }
142
 
143
  $id = (isset($data['id'])) ? (int)$data['id'] : false;
144
+ $newsletter = Newsletter::filter('filterWithOptions')->findOne($id);
145
 
146
  if($newsletter === false) {
147
  return $this->errorResponse(array(
154
 
155
  if(!empty($errors)) {
156
  return $this->errorResponse($errors);
 
 
 
 
157
  }
158
+
159
+ // if there are past due notifications, reschedule them for the next send date
160
+ if($newsletter->type === Newsletter::TYPE_NOTIFICATION && $status === Newsletter::STATUS_ACTIVE) {
161
+ $next_run_date = Scheduler::getNextRunDate($newsletter->schedule);
162
+ $newsletter->queue()
163
+ ->whereLte('scheduled_at', Carbon::createFromTimestamp(current_time('timestamp')))
164
+ ->where('status', SendingQueue::STATUS_SCHEDULED)
165
+ ->findResultSet()
166
+ ->set('scheduled_at', $next_run_date)
167
+ ->save();
168
+ }
169
+
170
+ return $this->successResponse(
171
+ Newsletter::findOne($newsletter->id)->asArray()
172
+ );
173
  }
174
 
175
  function restore($data = array()) {
lib/API/JSON/v1/Segments.php CHANGED
@@ -1,15 +1,21 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
 
3
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
4
  use MailPoet\API\JSON\Error as APIError;
5
-
6
- use MailPoet\Models\Segment;
7
  use MailPoet\Listing;
 
8
  use MailPoet\Segments\WP;
9
 
10
  if(!defined('ABSPATH')) exit;
11
 
12
  class Segments extends APIEndpoint {
 
 
 
 
13
  function get($data = array()) {
14
  $id = (isset($data['id']) ? (int)$data['id'] : false);
15
  $segment = Segment::findOne($id);
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
4
+
5
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
6
  use MailPoet\API\JSON\Error as APIError;
7
+ use MailPoet\Config\AccessControl;
 
8
  use MailPoet\Listing;
9
+ use MailPoet\Models\Segment;
10
  use MailPoet\Segments\WP;
11
 
12
  if(!defined('ABSPATH')) exit;
13
 
14
  class Segments extends APIEndpoint {
15
+ public $permissions = array(
16
+ 'global' => AccessControl::PERMISSION_MANAGE_SEGMENTS
17
+ );
18
+
19
  function get($data = array()) {
20
  $id = (isset($data['id']) ? (int)$data['id'] : false);
21
  $segment = Segment::findOne($id);
lib/API/JSON/v1/SendingQueue.php CHANGED
@@ -1,18 +1,24 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
 
3
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
4
  use MailPoet\API\JSON\Error as APIError;
5
-
6
  use MailPoet\Mailer\Mailer;
7
  use MailPoet\Models\Newsletter;
 
8
  use MailPoet\Models\Subscriber;
9
  use MailPoet\Newsletter\Scheduler\Scheduler;
10
- use MailPoet\Models\SendingQueue as SendingQueueModel;
11
  use MailPoet\Util\Helpers;
12
 
13
  if(!defined('ABSPATH')) exit;
14
 
15
  class SendingQueue extends APIEndpoint {
 
 
 
 
16
  function add($data = array()) {
17
  $newsletter_id = (isset($data['newsletter_id'])
18
  ? (int)$data['newsletter_id']
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
4
+
5
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
6
  use MailPoet\API\JSON\Error as APIError;
7
+ use MailPoet\Config\AccessControl;
8
  use MailPoet\Mailer\Mailer;
9
  use MailPoet\Models\Newsletter;
10
+ use MailPoet\Models\SendingQueue as SendingQueueModel;
11
  use MailPoet\Models\Subscriber;
12
  use MailPoet\Newsletter\Scheduler\Scheduler;
 
13
  use MailPoet\Util\Helpers;
14
 
15
  if(!defined('ABSPATH')) exit;
16
 
17
  class SendingQueue extends APIEndpoint {
18
+ public $permissions = array(
19
+ 'global' => AccessControl::PERMISSION_MANAGE_EMAILS
20
+ );
21
+
22
  function add($data = array()) {
23
  $newsletter_id = (isset($data['newsletter_id'])
24
  ? (int)$data['newsletter_id']
lib/API/JSON/v1/Services.php CHANGED
@@ -1,11 +1,12 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
3
 
4
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
5
  use MailPoet\API\JSON\Error as APIError;
 
6
  use MailPoet\Config\Installer;
7
  use MailPoet\Services\Bridge;
8
- use MailPoet\Util\License\License;
9
  use MailPoet\WP\DateTime;
10
 
11
  if(!defined('ABSPATH')) exit;
@@ -13,6 +14,9 @@ if(!defined('ABSPATH')) exit;
13
  class Services extends APIEndpoint {
14
  public $bridge;
15
  public $date_time;
 
 
 
16
 
17
  function __construct() {
18
  $this->bridge = new Bridge();
@@ -40,9 +44,9 @@ class Services extends APIEndpoint {
40
  $state = !empty($result['state']) ? $result['state'] : null;
41
 
42
  $success_message = null;
43
- if($state == Bridge::PREMIUM_KEY_VALID) {
44
  $success_message = __('Your MailPoet Sending Service key has been successfully validated.', 'mailpoet');
45
- } elseif($state == Bridge::PREMIUM_KEY_EXPIRING) {
46
  $success_message = sprintf(
47
  __('Your MailPoet Sending Service key expires on %s!', 'mailpoet'),
48
  $this->date_time->formatDate(strtotime($result['data']['expire_at']))
@@ -54,9 +58,12 @@ class Services extends APIEndpoint {
54
  }
55
 
56
  switch($state) {
57
- case Bridge::PREMIUM_KEY_INVALID:
58
  $error = __('Your MailPoet Sending Service key is invalid.', 'mailpoet');
59
  break;
 
 
 
60
  default:
61
  $code = !empty($result['code']) ? $result['code'] : Bridge::CHECK_ERROR_UNKNOWN;
62
  $error = sprintf(
@@ -90,9 +97,9 @@ class Services extends APIEndpoint {
90
  $state = !empty($result['state']) ? $result['state'] : null;
91
 
92
  $success_message = null;
93
- if($state == Bridge::PREMIUM_KEY_VALID) {
94
  $success_message = __('Your Premium key has been successfully validated.', 'mailpoet');
95
- } elseif($state == Bridge::PREMIUM_KEY_EXPIRING) {
96
  $success_message = sprintf(
97
  __('Your Premium key expires on %s.', 'mailpoet'),
98
  $this->date_time->formatDate(strtotime($result['data']['expire_at']))
@@ -107,10 +114,10 @@ class Services extends APIEndpoint {
107
  }
108
 
109
  switch($state) {
110
- case Bridge::PREMIUM_KEY_INVALID:
111
  $error = __('Your Premium key is invalid.', 'mailpoet');
112
  break;
113
- case Bridge::PREMIUM_KEY_ALREADY_USED:
114
  $error = __('Your Premium key is already used on another site.', 'mailpoet');
115
  break;
116
  default:
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
4
 
5
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
6
  use MailPoet\API\JSON\Error as APIError;
7
+ use MailPoet\Config\AccessControl;
8
  use MailPoet\Config\Installer;
9
  use MailPoet\Services\Bridge;
 
10
  use MailPoet\WP\DateTime;
11
 
12
  if(!defined('ABSPATH')) exit;
14
  class Services extends APIEndpoint {
15
  public $bridge;
16
  public $date_time;
17
+ public $permissions = array(
18
+ 'global' => AccessControl::PERMISSION_MANAGE_SETTINGS
19
+ );
20
 
21
  function __construct() {
22
  $this->bridge = new Bridge();
44
  $state = !empty($result['state']) ? $result['state'] : null;
45
 
46
  $success_message = null;
47
+ if($state == Bridge::KEY_VALID) {
48
  $success_message = __('Your MailPoet Sending Service key has been successfully validated.', 'mailpoet');
49
+ } elseif($state == Bridge::KEY_EXPIRING) {
50
  $success_message = sprintf(
51
  __('Your MailPoet Sending Service key expires on %s!', 'mailpoet'),
52
  $this->date_time->formatDate(strtotime($result['data']['expire_at']))
58
  }
59
 
60
  switch($state) {
61
+ case Bridge::KEY_INVALID:
62
  $error = __('Your MailPoet Sending Service key is invalid.', 'mailpoet');
63
  break;
64
+ case Bridge::KEY_ALREADY_USED:
65
+ $error = __('Your MailPoet Sending Service key is already used on another site.', 'mailpoet');
66
+ break;
67
  default:
68
  $code = !empty($result['code']) ? $result['code'] : Bridge::CHECK_ERROR_UNKNOWN;
69
  $error = sprintf(
97
  $state = !empty($result['state']) ? $result['state'] : null;
98
 
99
  $success_message = null;
100
+ if($state == Bridge::KEY_VALID) {
101
  $success_message = __('Your Premium key has been successfully validated.', 'mailpoet');
102
+ } elseif($state == Bridge::KEY_EXPIRING) {
103
  $success_message = sprintf(
104
  __('Your Premium key expires on %s.', 'mailpoet'),
105
  $this->date_time->formatDate(strtotime($result['data']['expire_at']))
114
  }
115
 
116
  switch($state) {
117
+ case Bridge::KEY_INVALID:
118
  $error = __('Your Premium key is invalid.', 'mailpoet');
119
  break;
120
+ case Bridge::KEY_ALREADY_USED:
121
  $error = __('Your Premium key is already used on another site.', 'mailpoet');
122
  break;
123
  default:
lib/API/JSON/v1/Settings.php CHANGED
@@ -1,24 +1,31 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
3
 
4
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
5
  use MailPoet\API\JSON\Error as APIError;
 
6
  use MailPoet\Models\Setting;
7
  use MailPoet\Services\Bridge;
8
 
9
  if(!defined('ABSPATH')) exit;
10
 
11
  class Settings extends APIEndpoint {
 
 
 
 
12
  function get() {
13
  return $this->successResponse(Setting::getAll());
14
  }
15
 
16
  function set($settings = array()) {
17
  if(empty($settings)) {
18
- return $this->badRequest(array(
19
- APIError::BAD_REQUEST =>
20
- __('You have not specified any settings to be saved.', 'mailpoet')
21
- ));
 
22
  } else {
23
  foreach($settings as $name => $value) {
24
  Setting::setValue($name, $value);
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
4
 
5
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
6
  use MailPoet\API\JSON\Error as APIError;
7
+ use MailPoet\Config\AccessControl;
8
  use MailPoet\Models\Setting;
9
  use MailPoet\Services\Bridge;
10
 
11
  if(!defined('ABSPATH')) exit;
12
 
13
  class Settings extends APIEndpoint {
14
+ public $permissions = array(
15
+ 'global' => AccessControl::PERMISSION_MANAGE_SETTINGS
16
+ );
17
+
18
  function get() {
19
  return $this->successResponse(Setting::getAll());
20
  }
21
 
22
  function set($settings = array()) {
23
  if(empty($settings)) {
24
+ return $this->badRequest(
25
+ array(
26
+ APIError::BAD_REQUEST =>
27
+ __('You have not specified any settings to be saved.', 'mailpoet')
28
+ ));
29
  } else {
30
  foreach($settings as $name => $value) {
31
  Setting::setValue($name, $value);
lib/API/JSON/v1/Setup.php CHANGED
@@ -1,13 +1,19 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
3
 
4
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
 
5
  use MailPoet\Config\Activator;
6
  use MailPoet\WP\Hooks;
7
 
8
  if(!defined('ABSPATH')) exit;
9
 
10
  class Setup extends APIEndpoint {
 
 
 
 
11
  function reset() {
12
  try {
13
  $activator = new Activator();
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
4
 
5
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
6
+ use MailPoet\Config\AccessControl;
7
  use MailPoet\Config\Activator;
8
  use MailPoet\WP\Hooks;
9
 
10
  if(!defined('ABSPATH')) exit;
11
 
12
  class Setup extends APIEndpoint {
13
+ public $permissions = array(
14
+ 'global' => AccessControl::PERMISSION_MANAGE_SETTINGS
15
+ );
16
+
17
  function reset() {
18
  try {
19
  $activator = new Activator();
lib/API/JSON/v1/Subscribers.php CHANGED
@@ -1,21 +1,22 @@
1
  <?php
 
2
  namespace MailPoet\API\JSON\v1;
 
3
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
4
  use MailPoet\API\JSON\Error as APIError;
5
- use MailPoet\API\JSON\Access as APIAccess;
6
-
7
- use MailPoet\Form\Util\FieldNameObfuscator;
8
  use MailPoet\Listing;
9
- use MailPoet\Models\Subscriber;
10
  use MailPoet\Models\Form;
11
  use MailPoet\Models\StatisticsForms;
 
12
 
13
  if(!defined('ABSPATH')) exit;
14
 
15
  class Subscribers extends APIEndpoint {
16
-
17
  public $permissions = array(
18
- 'subscribe' => APIAccess::ALL
 
19
  );
20
 
21
  function get($data = array()) {
1
  <?php
2
+
3
  namespace MailPoet\API\JSON\v1;
4
+
5
  use MailPoet\API\JSON\Endpoint as APIEndpoint;
6
  use MailPoet\API\JSON\Error as APIError;
7
+ use MailPoet\Config\AccessControl;
 
 
8
  use MailPoet\Listing;
9
+ use MailPoet\Form\Util\FieldNameObfuscator;
10
  use MailPoet\Models\Form;
11
  use MailPoet\Models\StatisticsForms;
12
+ use MailPoet\Models\Subscriber;
13
 
14
  if(!defined('ABSPATH')) exit;
15
 
16
  class Subscribers extends APIEndpoint {
 
17
  public $permissions = array(
18
+ 'global' => AccessControl::PERMISSION_MANAGE_SUBSCRIBERS,
19
+ 'methods' => array('subscribe' => AccessControl::NO_ACCESS_RESTRICTION)
20
  );
21
 
22
  function get($data = array()) {
lib/Config/AccessControl.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace MailPoet\Config;
4
+
5
+ use MailPoet\WP\Hooks as WPHooks;
6
+
7
+ if(!defined('ABSPATH')) exit;
8
+ require_once(ABSPATH . 'wp-includes/pluggable.php');
9
+
10
+ class AccessControl {
11
+ const PERMISSION_ACCESS_PLUGIN_ADMIN = 'access_plugin_admin';
12
+ const PERMISSION_MANAGE_SETTINGS = 'manage_settings';
13
+ const PERMISSION_MANAGE_EMAILS = 'manage_emails';
14
+ const PERMISSION_MANAGE_SUBSCRIBERS = 'manage_subscribers';
15
+ const PERMISSION_MANAGE_FORMS = 'manage_forms';
16
+ const PERMISSION_MANAGE_SEGMENTS = 'manage_segments';
17
+ const PERMISSION_UPDATE_PLUGIN = 'update_plugin';
18
+ const NO_ACCESS_RESTRICTION = 'no_access_restriction';
19
+
20
+ public $permissions;
21
+ public $current_user_roles;
22
+ public $user_capabilities;
23
+
24
+ function __construct() {
25
+ $this->permissions = $this->getDefaultPermissions();
26
+ $this->user_roles = $this->getUserRoles();
27
+ $this->user_capabilities = $this->getUserCapabilities();
28
+ }
29
+
30
+ private function getDefaultPermissions() {
31
+ return array(
32
+ self::PERMISSION_ACCESS_PLUGIN_ADMIN => WPHooks::applyFilters(
33
+ 'mailpoet_permission_access_plugin_admin',
34
+ array(
35
+ 'administrator',
36
+ 'editor'
37
+ )
38
+ ),
39
+ self::PERMISSION_MANAGE_SETTINGS => WPHooks::applyFilters(
40
+ 'mailpoet_permission_manage_settings',
41
+ array(
42
+ 'administrator'
43
+ )
44
+ ),
45
+ self::PERMISSION_MANAGE_EMAILS => WPHooks::applyFilters(
46
+ 'mailpoet_permission_manage_emails',
47
+ array(
48
+ 'administrator',
49
+ 'editor'
50
+ )
51
+ ),
52
+ self::PERMISSION_MANAGE_SUBSCRIBERS => WPHooks::applyFilters(
53
+ 'mailpoet_permission_manage_subscribers',
54
+ array(
55
+ 'administrator'
56
+ )
57
+ ),
58
+ self::PERMISSION_MANAGE_FORMS => WPHooks::applyFilters(
59
+ 'mailpoet_permission_manage_forms',
60
+ array(
61
+ 'administrator'
62
+ )
63
+ ),
64
+ self::PERMISSION_MANAGE_SEGMENTS => WPHooks::applyFilters(
65
+ 'mailpoet_permission_manage_segments',
66
+ array(
67
+ 'administrator'
68
+ )
69
+ ),
70
+ self::PERMISSION_UPDATE_PLUGIN => WPHooks::applyFilters(
71
+ 'mailpoet_permission_update_plugin',
72
+ array(
73
+ 'administrator'
74
+ )
75
+ ),
76
+ );
77
+ }
78
+
79
+ function getUserRoles() {
80
+ $user = wp_get_current_user();
81
+ return $user->roles;
82
+ }
83
+
84
+ function getUserCapabilities() {
85
+ $user = wp_get_current_user();
86
+ return array_keys($user->allcaps);
87
+ }
88
+
89
+ function getUserFirstCapability() {
90
+ return (!empty($this->user_capabilities)) ?
91
+ $this->user_capabilities[0] :
92
+ null;
93
+ }
94
+
95
+ function validatePermission($permission) {
96
+ if($permission === self::NO_ACCESS_RESTRICTION) return true;
97
+ if(empty($this->permissions[$permission])) return false;
98
+ $permitted_roles = array_intersect(
99
+ $this->user_roles,
100
+ $this->permissions[$permission]
101
+ );
102
+ return (!empty($permitted_roles));
103
+ }
104
+ }
lib/Config/Activator.php CHANGED
@@ -1,10 +1,11 @@
1
  <?php
 
2
  namespace MailPoet\Config;
3
 
4
  if(!defined('ABSPATH')) exit;
5
 
6
  class Activator {
7
- static function activate() {
8
  $migrator = new Migrator();
9
  $migrator->up();
10
 
@@ -14,8 +15,8 @@ class Activator {
14
  update_option('mailpoet_db_version', Env::$version);
15
  }
16
 
17
- static function deactivate() {
18
  $migrator = new Migrator();
19
  $migrator->down();
20
  }
21
- }
1
  <?php
2
+
3
  namespace MailPoet\Config;
4
 
5
  if(!defined('ABSPATH')) exit;
6
 
7
  class Activator {
8
+ function activate() {
9
  $migrator = new Migrator();
10
  $migrator->up();
11
 
15
  update_option('mailpoet_db_version', Env::$version);
16
  }
17
 
18
+ function deactivate() {
19
  $migrator = new Migrator();
20
  $migrator->down();
21
  }
22
+ }
lib/Config/Changelog.php CHANGED
@@ -1,12 +1,11 @@
1
  <?php
 
2
  namespace MailPoet\Config;
 
3
  use MailPoet\Models\Setting;
4
  use MailPoet\Util\Url;
5
 
6
  class Changelog {
7
- function __construct() {
8
- }
9
-
10
  function init() {
11
  $doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX);
12
 
1
  <?php
2
+
3
  namespace MailPoet\Config;
4
+
5
  use MailPoet\Models\Setting;
6
  use MailPoet\Util\Url;
7
 
8
  class Changelog {
 
 
 
9
  function init() {
10
  $doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX);
11
 
lib/Config/Env.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  namespace MailPoet\Config;
3
 
4
  if(!defined('ABSPATH')) exit;
@@ -31,7 +32,6 @@ class Env {
31
  static $db_collation;
32
  static $db_charset_collate;
33
  static $db_timezone_offset;
34
- static $required_permission = 'manage_options';
35
 
36
  static function init($file, $version) {
37
  global $wpdb;
1
  <?php
2
+
3
  namespace MailPoet\Config;
4
 
5
  if(!defined('ABSPATH')) exit;
32
  static $db_collation;
33
  static $db_charset_collate;
34
  static $db_timezone_offset;
 
35
 
36
  static function init($file, $version) {
37
  global $wpdb;
lib/Config/Initializer.php CHANGED
@@ -13,17 +13,18 @@ if(!defined('ABSPATH')) exit;
13
  require_once(ABSPATH . 'wp-admin/includes/plugin.php');
14
 
15
  class Initializer {
16
-
17
  const UNABLE_TO_CONNECT = 'Unable to connect to the database (the database is unable to open a file or folder), the connection is likely not configured correctly. Please read our [link] Knowledge Base article [/link] for steps how to resolve it.';
18
  const SOLVE_DB_ISSUE_URL = 'http://beta.docs.mailpoet.com/article/200-solving-database-connection-issues';
19
 
20
  protected $plugin_initialized = false;
 
21
 
22
  function __construct($params = array(
23
  'file' => '',
24
  'version' => '1.0.0'
25
  )) {
26
  Env::init($params['file'], $params['version']);
 
27
  }
28
 
29
  function init() {
@@ -135,7 +136,11 @@ class Initializer {
135
 
136
  // if current db version and plugin version differ
137
  if(version_compare($current_db_version, Env::$version) !== 0) {
138
- Activator::activate();
 
 
 
 
139
  }
140
  }
141
 
@@ -185,7 +190,7 @@ class Initializer {
185
  }
186
 
187
  function setupMenu() {
188
- $menu = new Menu($this->renderer, Env::$assets_url);
189
  $menu->init();
190
  }
191
 
@@ -218,11 +223,11 @@ class Initializer {
218
  }
219
 
220
  function setupJSONAPI() {
221
- API\API::JSON()->init();
222
  }
223
 
224
  function setupRouter() {
225
- $router = new Router\Router();
226
  $router->init();
227
  }
228
 
@@ -246,7 +251,7 @@ class Initializer {
246
  function handleFailedInitialization($exception) {
247
  // Check if we are able to add pages at this point
248
  if(function_exists('wp_get_current_user')) {
249
- Menu::addErrorPage();
250
  }
251
  return WPNotice::displayError($exception);
252
  }
13
  require_once(ABSPATH . 'wp-admin/includes/plugin.php');
14
 
15
  class Initializer {
 
16
  const UNABLE_TO_CONNECT = 'Unable to connect to the database (the database is unable to open a file or folder), the connection is likely not configured correctly. Please read our [link] Knowledge Base article [/link] for steps how to resolve it.';
17
  const SOLVE_DB_ISSUE_URL = 'http://beta.docs.mailpoet.com/article/200-solving-database-connection-issues';
18
 
19
  protected $plugin_initialized = false;
20
+ private $access_control;
21
 
22
  function __construct($params = array(
23
  'file' => '',
24
  'version' => '1.0.0'
25
  )) {
26
  Env::init($params['file'], $params['version']);
27
+ $this->access_control = new AccessControl();
28
  }
29
 
30
  function init() {
136
 
137
  // if current db version and plugin version differ
138
  if(version_compare($current_db_version, Env::$version) !== 0) {
139
+ if(!$this->access_control->validatePermission(AccessControl::PERMISSION_UPDATE_PLUGIN)) {
140
+ throw new \Exception(__('You do not have permission to activate/deactivate MailPoet plugin.', 'mailpoet'));
141
+ }
142
+ $activator = new Activator();
143
+ $activator->activate();
144
  }
145
  }
146
 
190
  }
191
 
192
  function setupMenu() {
193
+ $menu = new Menu($this->renderer, Env::$assets_url, $this->access_control);
194
  $menu->init();
195
  }
196
 
223
  }
224
 
225
  function setupJSONAPI() {
226
+ API\API::JSON($this->access_control)->init();
227
  }
228
 
229
  function setupRouter() {
230
+ $router = new Router\Router($this->access_control);
231
  $router->init();
232
  }
233
 
251
  function handleFailedInitialization($exception) {
252
  // Check if we are able to add pages at this point
253
  if(function_exists('wp_get_current_user')) {
254
+ Menu::addErrorPage($this->access_control);
255
  }
256
  return WPNotice::displayError($exception);
257
  }
lib/Config/MP2Migrator.php CHANGED
@@ -187,8 +187,9 @@ class MP2Migrator {
187
  *
188
  */
189
  private function eraseMP3Data() {
190
- Activator::deactivate();
191
- Activator::activate();
 
192
 
193
  $this->deleteSegments();
194
  $this->resetMigrationCounters();
187
  *
188
  */
189
  private function eraseMP3Data() {
190
+ $activator = new Activator();
191
+ $activator->deactivate();
192
+ $activator->activate();
193
 
194
  $this->deleteSegments();
195
  $this->resetMigrationCounters();
lib/Config/Menu.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  namespace MailPoet\Config;
3
 
4
  use MailPoet\Cron\CronTrigger;
@@ -25,9 +26,18 @@ use MailPoet\WP\Readme;
25
  if(!defined('ABSPATH')) exit;
26
 
27
  class Menu {
28
- function __construct($renderer, $assets_url) {
 
 
 
 
 
 
 
29
  $this->renderer = $renderer;
30
  $this->assets_url = $assets_url;
 
 
31
  $subscribers_feature = new SubscribersFeature();
32
  $this->subscribers_over_limit = $subscribers_feature->check();
33
  $this->checkMailPoetAPIKey();
@@ -45,134 +55,204 @@ class Menu {
45
  }
46
 
47
  function setup() {
 
48
  if(self::isOnMailPoetAdminPage()) {
49
  do_action('mailpoet_conflict_resolver_styles');
50
  do_action('mailpoet_conflict_resolver_scripts');
51
  }
52
 
53
- $main_page_slug = 'mailpoet-newsletters';
54
-
55
  add_menu_page(
56
  'MailPoet',
57
  'MailPoet',
58
- Env::$required_permission,
59
- $main_page_slug,
60
  null,
61
  $this->assets_url . '/img/menu_icon.png',
62
  30
63
  );
64
 
65
- $newsletters_page = add_submenu_page(
66
- $main_page_slug,
67
- $this->setPageTitle(__('Emails', 'mailpoet')),
68
- __('Emails', 'mailpoet'),
69
- Env::$required_permission,
70
- $main_page_slug,
71
- array(
72
- $this,
73
- 'newsletters'
74
- )
75
- );
 
 
76
 
77
- // add limit per page to screen options
78
- add_action('load-' . $newsletters_page, function() {
79
- add_screen_option('per_page', array(
80
- 'label' => _x(
81
- 'Number of newsletters per page',
82
- 'newsletters per page (screen options)',
83
- 'mailpoet'
84
- ),
85
- 'option' => 'mailpoet_newsletters_per_page'
86
- ));
87
- });
88
-
89
- $forms_page = add_submenu_page(
90
- $main_page_slug,
91
- $this->setPageTitle(__('Forms', 'mailpoet')),
92
- __('Forms', 'mailpoet'),
93
- Env::$required_permission,
94
- 'mailpoet-forms',
95
- array(
96
- $this,
97
- 'forms'
98
- )
99
- );
100
- // add limit per page to screen options
101
- add_action('load-' . $forms_page, function() {
102
- add_screen_option('per_page', array(
103
- 'label' => _x(
104
- 'Number of forms per page',
105
- 'forms per page (screen options)',
106
- 'mailpoet'
107
- ),
108
- 'option' => 'mailpoet_forms_per_page'
109
- ));
110
- });
111
-
112
- $subscribers_page = add_submenu_page(
113
- $main_page_slug,
114
- $this->setPageTitle(__('Subscribers', 'mailpoet')),
115
- __('Subscribers', 'mailpoet'),
116
- Env::$required_permission,
117
- 'mailpoet-subscribers',
118
- array(
119
- $this,
120
- 'subscribers'
121
- )
122
- );
123
- // add limit per page to screen options
124
- add_action('load-' . $subscribers_page, function() {
125
- add_screen_option('per_page', array(
126
- 'label' => _x(
127
- 'Number of subscribers per page',
128
- 'subscribers per page (screen options)',
129
- 'mailpoet'
130
- ),
131
- 'option' => 'mailpoet_subscribers_per_page'
132
- ));
133
- });
134
-
135
- $segments_page = add_submenu_page(
136
- $main_page_slug,
137
- $this->setPageTitle(__('Lists', 'mailpoet')),
138
- __('Lists', 'mailpoet'),
139
- Env::$required_permission,
140
- 'mailpoet-segments',
141
- array(
142
- $this,
143
- 'segments'
144
- )
145
- );
146
 
147
- // add limit per page to screen options
148
- add_action('load-' . $segments_page, function() {
149
- add_screen_option('per_page', array(
150
- 'label' => _x(
151
- 'Number of segments per page',
152
- 'segments per page (screen options)',
153
- 'mailpoet'
154
- ),
155
- 'option' => 'mailpoet_segments_per_page'
156
- ));
157
- });
 
 
158
 
159
- add_submenu_page(
160
- $main_page_slug,
161
- $this->setPageTitle(__('Settings', 'mailpoet')),
162
- __('Settings', 'mailpoet'),
163
- Env::$required_permission,
164
- 'mailpoet-settings',
165
- array(
166
- $this,
167
- 'settings'
168
- )
169
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
 
171
  add_submenu_page(
172
- $main_page_slug,
173
  $this->setPageTitle(__('Help', 'mailpoet')),
174
  __('Help', 'mailpoet'),
175
- Env::$required_permission,
176
  'mailpoet-help',
177
  array(
178
  $this,
@@ -180,12 +260,13 @@ class Menu {
180
  )
181
  );
182
 
 
183
  // Only show this page in menu if the Premium plugin is not activated
184
  add_submenu_page(
185
- License::getLicense() ? true : $main_page_slug,
186
  $this->setPageTitle(__('Premium', 'mailpoet')),
187
  __('Premium', 'mailpoet'),
188
- Env::$required_permission,
189
  'mailpoet-premium',
190
  array(
191
  $this,
@@ -193,35 +274,12 @@ class Menu {
193
  )
194
  );
195
 
196
- add_submenu_page(
197
- 'admin.php?page=mailpoet-subscribers',
198
- $this->setPageTitle(__('Import', 'mailpoet')),
199
- __('Import', 'mailpoet'),
200
- Env::$required_permission,
201
- 'mailpoet-import',
202
- array(
203
- $this,
204
- 'import'
205
- )
206
- );
207
-
208
- add_submenu_page(
209
- true,
210
- $this->setPageTitle(__('Export', 'mailpoet')),
211
- __('Export', 'mailpoet'),
212
- Env::$required_permission,
213
- 'mailpoet-export',
214
- array(
215
- $this,
216
- 'export'
217
- )
218
- );
219
-
220
  add_submenu_page(
221
  true,
222
  $this->setPageTitle(__('Welcome', 'mailpoet')),
223
  __('Welcome', 'mailpoet'),
224
- Env::$required_permission,
225
  'mailpoet-welcome',
226
  array(
227
  $this,
@@ -229,23 +287,12 @@ class Menu {
229
  )
230
  );
231
 
232
- add_submenu_page(
233
- true,
234
- $this->setPageTitle(__('Migration', 'mailpoet')),
235
- '',
236
- Env::$required_permission,
237
- 'mailpoet-migration',
238
- array(
239
- $this,
240
- 'migration'
241
- )
242
- );
243
-
244
  add_submenu_page(
245
  true,
246
  $this->setPageTitle(__('Update', 'mailpoet')),
247
  __('Update', 'mailpoet'),
248
- Env::$required_permission,
249
  'mailpoet-update',
250
  array(
251
  $this,
@@ -253,27 +300,16 @@ class Menu {
253
  )
254
  );
255
 
 
256
  add_submenu_page(
257
  true,
258
- $this->setPageTitle(__('Form Editor', 'mailpoet')),
259
- __('Form Editor', 'mailpoet'),
260
- Env::$required_permission,
261
- 'mailpoet-form-editor',
262
- array(
263
- $this,
264
- 'formEditor'
265
- )
266
- );
267
-
268
- add_submenu_page(
269
- true,
270
- $this->setPageTitle(__('Newsletter', 'mailpoet')),
271
- __('Newsletter Editor', 'mailpoet'),
272
- Env::$required_permission,
273
- 'mailpoet-newsletter-editor',
274
  array(
275
  $this,
276
- 'newletterEditor'
277
  )
278
  );
279
  }
@@ -293,20 +329,20 @@ class Menu {
293
  or
294
  strpos($redirect_url, 'mailpoet') === false
295
  ) {
296
- $redirect_url = admin_url('admin.php?page=mailpoet-newsletters');
297
  }
298
 
299
  $data = array(
300
  'settings' => Setting::getAll(),
301
  'current_user' => wp_get_current_user(),
302
  'redirect_url' => $redirect_url,
303
- 'sub_menu' => 'mailpoet-newsletters'
304
  );
305
  $this->displayPage('welcome.html', $data);
306
  }
307
 
308
  function migration() {
309
- $mp2_migrator = new MP2Migrator();
310
  $mp2_migrator->init();
311
  $data = array(
312
  'log_file_url' => $mp2_migrator->log_file_url,
@@ -328,14 +364,14 @@ class Menu {
328
  or
329
  strpos($redirect_url, 'mailpoet') === false
330
  ) {
331
- $redirect_url = admin_url('admin.php?page=mailpoet-newsletters');
332
  }
333
 
334
  $data = array(
335
  'settings' => Setting::getAll(),
336
  'current_user' => wp_get_current_user(),
337
  'redirect_url' => $redirect_url,
338
- 'sub_menu' => 'mailpoet-newsletters'
339
  );
340
 
341
  $readme_file = Env::$path . '/readme.txt';
@@ -352,7 +388,7 @@ class Menu {
352
  function premium() {
353
  $data = array(
354
  'subscriber_count' => Subscriber::getTotalSubscribers(),
355
- 'sub_menu' => 'mailpoet-newsletters'
356
  );
357
 
358
  $this->displayPage('premium.html', $data);
@@ -505,7 +541,7 @@ class Menu {
505
  'shortcodes' => ShortcodesHelper::getShortcodes(),
506
  'settings' => Setting::getAll(),
507
  'current_wp_user' => Subscriber::getCurrentWPUser(),
508
- 'sub_menu' => 'mailpoet-newsletters'
509
  );
510
  wp_enqueue_media();
511
  wp_enqueue_script('tinymce-wplink', includes_url('js/tinymce/plugins/wplink/plugin.js'));
@@ -597,13 +633,13 @@ class Menu {
597
  * This error page is used when the initialization is failed
598
  * to display admin notices only
599
  */
600
- static function addErrorPage() {
601
  if(!self::isOnMailPoetAdminPage()) {
602
  return false;
603
  }
604
  // Check if page already exists
605
  if(get_plugin_page_hook($_REQUEST['page'], '')
606
- || get_plugin_page_hook($_REQUEST['page'], 'mailpoet-newsletters')
607
  ) {
608
  return false;
609
  }
@@ -611,9 +647,12 @@ class Menu {
611
  true,
612
  'MailPoet',
613
  'MailPoet',
614
- Env::$required_permission,
615
  $_REQUEST['page'],
616
- array(__CLASS__, 'errorPageCallback')
 
 
 
617
  );
618
  }
619
 
@@ -624,19 +663,17 @@ class Menu {
624
  function checkMailPoetAPIKey(ServicesChecker $checker = null) {
625
  if(self::isOnMailPoetAdminPage()) {
626
  $show_notices = isset($_REQUEST['page'])
627
- && stripos($_REQUEST['page'], 'mailpoet-newsletters') === false;
628
  $checker = $checker ?: new ServicesChecker();
629
  $this->mp_api_key_valid = $checker->isMailPoetAPIKeyValid($show_notices);
630
  }
631
  }
632
 
633
  function checkPremiumKey(ServicesChecker $checker = null) {
634
- if(self::isOnMailPoetAdminPage()) {
635
- $show_notices = isset($_REQUEST['page'])
636
- && stripos($_REQUEST['page'], 'mailpoet-newsletters') === false;
637
- $checker = $checker ?: new ServicesChecker();
638
- $this->premium_key_valid = $checker->isPremiumKeyValid($show_notices);
639
- }
640
  }
641
 
642
  private function getLimitPerPage($model = null) {
1
  <?php
2
+
3
  namespace MailPoet\Config;
4
 
5
  use MailPoet\Cron\CronTrigger;
26
  if(!defined('ABSPATH')) exit;
27
 
28
  class Menu {
29
+ const MAIN_PAGE_SLUG = 'mailpoet-newsletters';
30
+
31
+ public $renderer;
32
+ public $assets_url;
33
+ private $access_control;
34
+ private $subscribers_over_limit;
35
+
36
+ function __construct($renderer, $assets_url, AccessControl $access_control) {
37
  $this->renderer = $renderer;
38
  $this->assets_url = $assets_url;
39
+ $this->access_control = $access_control;
40
+ $this->user_capability = $this->access_control->getUserFirstCapability();
41
  $subscribers_feature = new SubscribersFeature();
42
  $this->subscribers_over_limit = $subscribers_feature->check();
43
  $this->checkMailPoetAPIKey();
55
  }
56
 
57
  function setup() {
58
+ if(!$this->access_control->validatePermission(AccessControl::PERMISSION_ACCESS_PLUGIN_ADMIN)) return;
59
  if(self::isOnMailPoetAdminPage()) {
60
  do_action('mailpoet_conflict_resolver_styles');
61
  do_action('mailpoet_conflict_resolver_scripts');
62
  }
63
 
64
+ // Main page
 
65
  add_menu_page(
66
  'MailPoet',
67
  'MailPoet',
68
+ $this->user_capability,
69
+ self::MAIN_PAGE_SLUG,
70
  null,
71
  $this->assets_url . '/img/menu_icon.png',
72
  30
73
  );
74
 
75
+ // Emails page
76
+ if($this->access_control->validatePermission(AccessControl::PERMISSION_MANAGE_EMAILS)) {
77
+ $newsletters_page = add_submenu_page(
78
+ self::MAIN_PAGE_SLUG,
79
+ $this->setPageTitle(__('Emails', 'mailpoet')),
80
+ __('Emails', 'mailpoet'),
81
+ $this->user_capability,
82
+ self::MAIN_PAGE_SLUG,
83
+ array(
84
+ $this,
85
+ 'newsletters'
86
+ )
87
+ );
88
 
89
+ // add limit per page to screen options
90
+ add_action('load-' . $newsletters_page, function() {
91
+ add_screen_option('per_page', array(
92
+ 'label' => _x(
93
+ 'Number of newsletters per page',
94
+ 'newsletters per page (screen options)',
95
+ 'mailpoet'
96
+ ),
97
+ 'option' => 'mailpoet_newsletters_per_page'
98
+ ));
99
+ });
100
+
101
+ // newsletter editor
102
+ add_submenu_page(
103
+ true,
104
+ $this->setPageTitle(__('Newsletter', 'mailpoet')),
105
+ __('Newsletter Editor', 'mailpoet'),
106
+ $this->user_capability,
107
+ 'mailpoet-newsletter-editor',
108
+ array(
109
+ $this,
110
+ 'newletterEditor'
111
+ )
112
+ );
113
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
+ // Forms page
116
+ if($this->access_control->validatePermission(AccessControl::PERMISSION_MANAGE_FORMS)) {
117
+ $forms_page = add_submenu_page(
118
+ self::MAIN_PAGE_SLUG,
119
+ $this->setPageTitle(__('Forms', 'mailpoet')),
120
+ __('Forms', 'mailpoet'),
121
+ $this->user_capability,
122
+ 'mailpoet-forms',
123
+ array(
124
+ $this,
125
+ 'forms'
126
+ )
127
+ );
128
 
129
+ // add limit per page to screen options
130
+ add_action('load-' . $forms_page, function() {
131
+ add_screen_option('per_page', array(
132
+ 'label' => _x(
133
+ 'Number of forms per page',
134
+ 'forms per page (screen options)',
135
+ 'mailpoet'
136
+ ),
137
+ 'option' => 'mailpoet_forms_per_page'
138
+ ));
139
+ });
140
+
141
+ // form editor
142
+ add_submenu_page(
143
+ true,
144
+ $this->setPageTitle(__('Form Editor', 'mailpoet')),
145
+ __('Form Editor', 'mailpoet'),
146
+ $this->user_capability,
147
+ 'mailpoet-form-editor',
148
+ array(
149
+ $this,
150
+ 'formEditor'
151
+ )
152
+ );
153
+ }
154
+
155
+ // Subscribers page
156
+ if($this->access_control->validatePermission(AccessControl::PERMISSION_MANAGE_SUBSCRIBERS)) {
157
+ $subscribers_page = add_submenu_page(
158
+ self::MAIN_PAGE_SLUG,
159
+ $this->setPageTitle(__('Subscribers', 'mailpoet')),
160
+ __('Subscribers', 'mailpoet'),
161
+ $this->user_capability,
162
+ 'mailpoet-subscribers',
163
+ array(
164
+ $this,
165
+ 'subscribers'
166
+ )
167
+ );
168
+
169
+ // add limit per page to screen options
170
+ add_action('load-' . $subscribers_page, function() {
171
+ add_screen_option('per_page', array(
172
+ 'label' => _x(
173
+ 'Number of subscribers per page',
174
+ 'subscribers per page (screen options)',
175
+ 'mailpoet'
176
+ ),
177
+ 'option' => 'mailpoet_subscribers_per_page'
178
+ ));
179
+ });
180
+
181
+ // import
182
+ add_submenu_page(
183
+ 'admin.php?page=mailpoet-subscribers',
184
+ $this->setPageTitle(__('Import', 'mailpoet')),
185
+ __('Import', 'mailpoet'),
186
+ $this->user_capability,
187
+ 'mailpoet-import',
188
+ array(
189
+ $this,
190
+ 'import'
191
+ )
192
+ );
193
+
194
+ // export
195
+ add_submenu_page(
196
+ true,
197
+ $this->setPageTitle(__('Export', 'mailpoet')),
198
+ __('Export', 'mailpoet'),
199
+ $this->user_capability,
200
+ 'mailpoet-export',
201
+ array(
202
+ $this,
203
+ 'export'
204
+ )
205
+ );
206
+ }
207
+
208
+ // Segments page
209
+ if($this->access_control->validatePermission(AccessControl::PERMISSION_MANAGE_SEGMENTS)) {
210
+ $segments_page = add_submenu_page(
211
+ self::MAIN_PAGE_SLUG,
212
+ $this->setPageTitle(__('Lists', 'mailpoet')),
213
+ __('Lists', 'mailpoet'),
214
+ $this->user_capability,
215
+ 'mailpoet-segments',
216
+ array(
217
+ $this,
218
+ 'segments'
219
+ )
220
+ );
221
+
222
+ // add limit per page to screen options
223
+ add_action('load-' . $segments_page, function() {
224
+ add_screen_option('per_page', array(
225
+ 'label' => _x(
226
+ 'Number of segments per page',
227
+ 'segments per page (screen options)',
228
+ 'mailpoet'
229
+ ),
230
+ 'option' => 'mailpoet_segments_per_page'
231
+ ));
232
+ });
233
+ }
234
+
235
+ // Settings page
236
+ if($this->access_control->validatePermission(AccessControl::PERMISSION_MANAGE_SETTINGS)) {
237
+ add_submenu_page(
238
+ self::MAIN_PAGE_SLUG,
239
+ $this->setPageTitle(__('Settings', 'mailpoet')),
240
+ __('Settings', 'mailpoet'),
241
+ $this->user_capability,
242
+ 'mailpoet-settings',
243
+ array(
244
+ $this,
245
+ 'settings'
246
+ )
247
+ );
248
+ }
249
 
250
+ // Help page
251
  add_submenu_page(
252
+ self::MAIN_PAGE_SLUG,
253
  $this->setPageTitle(__('Help', 'mailpoet')),
254
  __('Help', 'mailpoet'),
255
+ $this->user_capability,
256
  'mailpoet-help',
257
  array(
258
  $this,
260
  )
261
  );
262
 
263
+ // Premium page
264
  // Only show this page in menu if the Premium plugin is not activated
265
  add_submenu_page(
266
+ License::getLicense() ? true : self::MAIN_PAGE_SLUG,
267
  $this->setPageTitle(__('Premium', 'mailpoet')),
268
  __('Premium', 'mailpoet'),
269
+ $this->user_capability,
270
  'mailpoet-premium',
271
  array(
272
  $this,
274
  )
275
  );
276
 
277
+ // Welcome page
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  add_submenu_page(
279
  true,
280
  $this->setPageTitle(__('Welcome', 'mailpoet')),
281
  __('Welcome', 'mailpoet'),
282
+ $this->user_capability,
283
  'mailpoet-welcome',
284
  array(
285
  $this,
287
  )
288
  );
289
 
290
+ // Update page
 
 
 
 
 
 
 
 
 
 
 
291
  add_submenu_page(
292
  true,
293
  $this->setPageTitle(__('Update', 'mailpoet')),
294
  __('Update', 'mailpoet'),
295
+ $this->user_capability,
296
  'mailpoet-update',
297
  array(
298
  $this,
300
  )
301
  );
302
 
303
+ // Migration page
304
  add_submenu_page(
305
  true,
306
+ $this->setPageTitle(__('Migration', 'mailpoet')),
307
+ '',
308
+ $this->user_capability,
309
+ 'mailpoet-migration',
 
 
 
 
 
 
 
 
 
 
 
 
310
  array(
311
  $this,
312
+ 'migration'
313
  )
314
  );
315
  }
329
  or
330
  strpos($redirect_url, 'mailpoet') === false
331
  ) {
332
+ $redirect_url = admin_url('admin.php?page=' . self::MAIN_PAGE_SLUG);
333
  }
334
 
335
  $data = array(
336
  'settings' => Setting::getAll(),
337
  'current_user' => wp_get_current_user(),
338
  'redirect_url' => $redirect_url,
339
+ 'sub_menu' => self::MAIN_PAGE_SLUG
340
  );
341
  $this->displayPage('welcome.html', $data);
342
  }
343
 
344
  function migration() {
345
+ $mp2_migrator = new MP2Migrator($this->access_control);
346
  $mp2_migrator->init();
347
  $data = array(
348
  'log_file_url' => $mp2_migrator->log_file_url,
364
  or
365
  strpos($redirect_url, 'mailpoet') === false
366
  ) {
367
+ $redirect_url = admin_url('admin.php?page=' . self::MAIN_PAGE_SLUG);
368
  }
369
 
370
  $data = array(
371
  'settings' => Setting::getAll(),
372
  'current_user' => wp_get_current_user(),
373
  'redirect_url' => $redirect_url,
374
+ 'sub_menu' => self::MAIN_PAGE_SLUG
375
  );
376
 
377
  $readme_file = Env::$path . '/readme.txt';
388
  function premium() {
389
  $data = array(
390
  'subscriber_count' => Subscriber::getTotalSubscribers(),
391
+ 'sub_menu' => self::MAIN_PAGE_SLUG
392
  );
393
 
394
  $this->displayPage('premium.html', $data);
541
  'shortcodes' => ShortcodesHelper::getShortcodes(),
542
  'settings' => Setting::getAll(),
543
  'current_wp_user' => Subscriber::getCurrentWPUser(),
544
+ 'sub_menu' => self::MAIN_PAGE_SLUG
545
  );
546
  wp_enqueue_media();
547
  wp_enqueue_script('tinymce-wplink', includes_url('js/tinymce/plugins/wplink/plugin.js'));
633
  * This error page is used when the initialization is failed
634
  * to display admin notices only
635
  */
636
+ static function addErrorPage(AccessControl $access_control) {
637
  if(!self::isOnMailPoetAdminPage()) {
638
  return false;
639
  }
640
  // Check if page already exists
641
  if(get_plugin_page_hook($_REQUEST['page'], '')
642
+ || get_plugin_page_hook($_REQUEST['page'], self::MAIN_PAGE_SLUG)
643
  ) {
644
  return false;
645
  }
647
  true,
648
  'MailPoet',
649
  'MailPoet',
650
+ $access_control->getUserFirstCapability(),
651
  $_REQUEST['page'],
652
+ array(
653
+ __CLASS__,
654
+ 'errorPageCallback'
655
+ )
656
  );
657
  }
658
 
663
  function checkMailPoetAPIKey(ServicesChecker $checker = null) {
664
  if(self::isOnMailPoetAdminPage()) {
665
  $show_notices = isset($_REQUEST['page'])
666
+ && stripos($_REQUEST['page'], self::MAIN_PAGE_SLUG) === false;
667
  $checker = $checker ?: new ServicesChecker();
668
  $this->mp_api_key_valid = $checker->isMailPoetAPIKeyValid($show_notices);
669
  }
670
  }
671
 
672
  function checkPremiumKey(ServicesChecker $checker = null) {
673
+ $show_notices = isset($_SERVER['SCRIPT_NAME'])
674
+ && stripos($_SERVER['SCRIPT_NAME'], 'plugins.php') !== false;
675
+ $checker = $checker ?: new ServicesChecker();
676
+ $this->premium_key_valid = $checker->isPremiumKeyValid($show_notices);
 
 
677
  }
678
 
679
  private function getLimitPerPage($model = null) {
lib/Config/ServicesChecker.php CHANGED
@@ -22,7 +22,7 @@ class ServicesChecker {
22
 
23
  if(!$mss_key_specified
24
  || empty($mss_key['state'])
25
- || $mss_key['state'] == Bridge::PREMIUM_KEY_INVALID
26
  ) {
27
  if($display_error_notice) {
28
  $error = Helpers::replaceLinkTags(
@@ -33,7 +33,7 @@ class ServicesChecker {
33
  WPNotice::displayError($error);
34
  }
35
  return false;
36
- } elseif($mss_key['state'] == Bridge::PREMIUM_KEY_EXPIRING
37
  && !empty($mss_key['data']['expire_at'])
38
  ) {
39
  if($display_error_notice) {
@@ -48,7 +48,7 @@ class ServicesChecker {
48
  WPNotice::displayWarning($error);
49
  }
50
  return true;
51
- } elseif($mss_key['state'] == Bridge::PREMIUM_KEY_VALID) {
52
  return true;
53
  }
54
 
@@ -66,19 +66,27 @@ class ServicesChecker {
66
 
67
  if(!$premium_key_specified
68
  || empty($premium_key['state'])
69
- || $premium_key['state'] === Bridge::PREMIUM_KEY_INVALID
70
- || $premium_key['state'] === Bridge::PREMIUM_KEY_ALREADY_USED
71
  ) {
72
  if($display_error_notice) {
 
73
  $error = Helpers::replaceLinkTags(
74
- __('Warning! Your License Key is either invalid or expired. [link]Renew your License now[/link] to enjoy automatic updates and Premium support.', 'mailpoet'),
75
- 'https://account.mailpoet.com',
76
- array('target' => '_blank')
 
77
  );
78
- WPNotice::displayError($error);
 
 
 
 
 
 
79
  }
80
  return false;
81
- } elseif($premium_key['state'] === Bridge::PREMIUM_KEY_EXPIRING
82
  && !empty($premium_key['data']['expire_at'])
83
  ) {
84
  if($display_error_notice) {
@@ -93,7 +101,7 @@ class ServicesChecker {
93
  WPNotice::displayWarning($error);
94
  }
95
  return true;
96
- } elseif($premium_key['state'] === Bridge::PREMIUM_KEY_VALID) {
97
  return true;
98
  }
99
 
22
 
23
  if(!$mss_key_specified
24
  || empty($mss_key['state'])
25
+ || $mss_key['state'] == Bridge::KEY_INVALID
26
  ) {
27
  if($display_error_notice) {
28
  $error = Helpers::replaceLinkTags(
33
  WPNotice::displayError($error);
34
  }
35
  return false;
36
+ } elseif($mss_key['state'] == Bridge::KEY_EXPIRING
37
  && !empty($mss_key['data']['expire_at'])
38
  ) {
39
  if($display_error_notice) {
48
  WPNotice::displayWarning($error);
49
  }
50
  return true;
51
+ } elseif($mss_key['state'] == Bridge::KEY_VALID) {
52
  return true;
53
  }
54
 
66
 
67
  if(!$premium_key_specified
68
  || empty($premium_key['state'])
69
+ || $premium_key['state'] === Bridge::KEY_INVALID
70
+ || $premium_key['state'] === Bridge::KEY_ALREADY_USED
71
  ) {
72
  if($display_error_notice) {
73
+ $error_string = __('[link1]Register[/link1] your copy of the MailPoet Premium plugin to receive access to automatic upgrades and support. Need a license key? [link2]Purchase one now.[/link2]', 'mailpoet');
74
  $error = Helpers::replaceLinkTags(
75
+ $error_string,
76
+ 'admin.php?page=mailpoet-settings#premium',
77
+ array(),
78
+ 'link1'
79
  );
80
+ $error = Helpers::replaceLinkTags(
81
+ $error,
82
+ 'admin.php?page=mailpoet-premium',
83
+ array(),
84
+ 'link2'
85
+ );
86
+ WPNotice::displayWarning($error);
87
  }
88
  return false;
89
+ } elseif($premium_key['state'] === Bridge::KEY_EXPIRING
90
  && !empty($premium_key['data']['expire_at'])
91
  ) {
92
  if($display_error_notice) {
101
  WPNotice::displayWarning($error);
102
  }
103
  return true;
104
+ } elseif($premium_key['state'] === Bridge::KEY_VALID) {
105
  return true;
106
  }
107
 
lib/Config/Shortcodes.php CHANGED
@@ -12,7 +12,6 @@ class Shortcodes {
12
  function init() {
13
  // form widget shortcode
14
  add_shortcode('mailpoet_form', array($this, 'formWidget'));
15
- add_shortcode('wysija_form', array($this, 'formWidget'));
16
 
17
  // subscribers count shortcode
18
  add_shortcode('mailpoet_subscribers_count', array(
12
  function init() {
13
  // form widget shortcode
14
  add_shortcode('mailpoet_form', array($this, 'formWidget'));
 
15
 
16
  // subscribers count shortcode
17
  add_shortcode('mailpoet_subscribers_count', array(
lib/Config/Widget.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
 
2
  namespace MailPoet\Config;
 
3
  use MailPoet\Models\Form;
4
 
5
  if(!defined('ABSPATH')) exit;
@@ -113,10 +115,20 @@ class Widget {
113
  'is_rtl' => (function_exists('is_rtl') ? (bool)is_rtl() : false)
114
  ));
115
 
116
- $ajaxFailedErrorMessage = __('An error has happened while performing a request, please try again later.');
 
 
 
 
 
 
 
 
 
 
117
  wp_add_inline_script(
118
  'mailpoet_public',
119
- sprintf('MailPoet.I18n.add("ajaxFailedErrorMessage", "%s")', $ajaxFailedErrorMessage),
120
  'after'
121
  );
122
  }
1
  <?php
2
+
3
  namespace MailPoet\Config;
4
+
5
  use MailPoet\Models\Form;
6
 
7
  if(!defined('ABSPATH')) exit;
115
  'is_rtl' => (function_exists('is_rtl') ? (bool)is_rtl() : false)
116
  ));
117
 
118
+ $ajax_failed_error_message = __('An error has happened while performing a request, please try again later.');
119
+ $inline_script = <<<EOL
120
+ function initMailpoetTranslation() {
121
+ if(typeof MailPoet !== 'undefined') {
122
+ MailPoet.I18n.add('ajaxFailedErrorMessage', '%s')
123
+ } else {
124
+ setTimeout(initMailpoetTranslation, 250);
125
+ }
126
+ }
127
+ setTimeout(initMailpoetTranslation, 250);
128
+ EOL;
129
  wp_add_inline_script(
130
  'mailpoet_public',
131
+ sprintf($inline_script, $ajax_failed_error_message),
132
  'after'
133
  );
134
  }
lib/Cron/Workers/SendingQueue/Tasks/Posts.php CHANGED
@@ -8,6 +8,9 @@ if(!defined('ABSPATH')) exit;
8
 
9
  class Posts {
10
  static function extractAndSave($rendered_newsletter, $newsletter) {
 
 
 
11
  preg_match_all(
12
  '/data-post-id="(\d+)"/ism',
13
  $rendered_newsletter['html'],
@@ -16,9 +19,7 @@ class Posts {
16
  if(!count($matched_posts_ids)) {
17
  return false;
18
  }
19
- $newsletter_id = ($newsletter->type === NewsletterModel::TYPE_NOTIFICATION_HISTORY) ?
20
- $newsletter->parent_id :
21
- $newsletter->id;
22
  foreach($matched_posts_ids as $post_id) {
23
  $newsletter_post = NewsletterPost::create();
24
  $newsletter_post->newsletter_id = $newsletter_id;
@@ -27,4 +28,4 @@ class Posts {
27
  }
28
  return true;
29
  }
30
- }
8
 
9
  class Posts {
10
  static function extractAndSave($rendered_newsletter, $newsletter) {
11
+ if($newsletter->type !== NewsletterModel::TYPE_NOTIFICATION_HISTORY) {
12
+ return false;
13
+ }
14
  preg_match_all(
15
  '/data-post-id="(\d+)"/ism',
16
  $rendered_newsletter['html'],
19
  if(!count($matched_posts_ids)) {
20
  return false;
21
  }
22
+ $newsletter_id = $newsletter->parent_id; // parent post notification
 
 
23
  foreach($matched_posts_ids as $post_id) {
24
  $newsletter_post = NewsletterPost::create();
25
  $newsletter_post->newsletter_id = $newsletter_id;
28
  }
29
  return true;
30
  }
31
+ }
lib/Form/Renderer.php CHANGED
@@ -15,7 +15,7 @@ class Renderer {
15
  $styles = new Util\Styles(static::getStyles($form));
16
 
17
  $html = '<style type="text/css">';
18
- $html .= '.mailpoet_hp_email_label{position: absolute;left: -999em;}';// move honeypot field out of the sight
19
  $html .= $styles->render($prefix);
20
  $html .= '</style>';
21
 
@@ -38,11 +38,13 @@ class Renderer {
38
  }
39
  }
40
 
41
- static function renderBlocks($blocks = array()) {
42
- // this is a honeypot for spambots
43
- $html = '<label class="mailpoet_hp_email_label">Please leave this field empty<input type="email" name="data[email]"></label>';
 
 
44
  foreach($blocks as $key => $block) {
45
- $html .= static::renderBlock($block)."\n";
46
  }
47
 
48
  return $html;
15
  $styles = new Util\Styles(static::getStyles($form));
16
 
17
  $html = '<style type="text/css">';
18
+ $html .= '.mailpoet_hp_email_label{position: absolute;left: -999em;}'; // move honeypot field out of sight
19
  $html .= $styles->render($prefix);
20
  $html .= '</style>';
21
 
38
  }
39
  }
40
 
41
+ static function renderBlocks($blocks = array(), $honeypot_enabled = true) {
42
+ // add honeypot for spambots
43
+ $html = ($honeypot_enabled) ?
44
+ '<label class="mailpoet_hp_email_label">' . __('Please leave this field empty', 'mailpoet') . '<input type="email" name="data[email]"></label>' :
45
+ '';
46
  foreach($blocks as $key => $block) {
47
+ $html .= static::renderBlock($block) . PHP_EOL;
48
  }
49
 
50
  return $html;
lib/Form/Widget.php CHANGED
@@ -3,7 +3,7 @@
3
  namespace MailPoet\Form;
4
 
5
  use MailPoet\API\JSON\API;
6
- use MailPoet\Config\Renderer;
7
  use MailPoet\Form\Renderer as FormRenderer;
8
  use MailPoet\Models\Form;
9
  use MailPoet\Util\Security;
@@ -174,7 +174,7 @@ class Widget extends \WP_Widget {
174
  $data['api_version'] = API::CURRENT_VERSION;
175
 
176
  // render form
177
- $renderer = new Renderer();
178
  try {
179
  $output = $renderer->render('form/widget.html', $data);
180
  $output = do_shortcode($output);
3
  namespace MailPoet\Form;
4
 
5
  use MailPoet\API\JSON\API;
6
+ use MailPoet\Config\Renderer as ConfigRenderer;
7
  use MailPoet\Form\Renderer as FormRenderer;
8
  use MailPoet\Models\Form;
9
  use MailPoet\Util\Security;
174
  $data['api_version'] = API::CURRENT_VERSION;
175
 
176
  // render form
177
+ $renderer = new ConfigRenderer();
178
  try {
179
  $output = $renderer->render('form/widget.html', $data);
180
  $output = do_shortcode($output);
lib/Models/Subscriber.php CHANGED
@@ -488,7 +488,10 @@ class Subscriber extends Model {
488
  unset($data['segments']);
489
  }
490
 
491
- $data = self::setRequiredFieldsDefaultValues($data);
 
 
 
492
 
493
  // get custom fields
494
  list($data, $custom_fields) = self::extractCustomFieldsFromFromObject($data);
488
  unset($data['segments']);
489
  }
490
 
491
+ // if new subscriber, make sure that required fields are set
492
+ if(!$subscriber) {
493
+ $data = self::setRequiredFieldsDefaultValues($data);
494
+ }
495
 
496
  // get custom fields
497
  list($data, $custom_fields) = self::extractCustomFieldsFromFromObject($data);
lib/Newsletter/Renderer/Blocks/Renderer.php CHANGED
@@ -23,11 +23,8 @@ class Renderer {
23
  $parent = Newsletter::findOne($newsletter_id);
24
  $newer_than_timestamp = $parent->created_at;
25
  }
26
- } else if($preview) {
27
- $newsletter_id = false;
28
- $newer_than_timestamp = false;
29
  } else {
30
- $newsletter_id = $newsletter['id'];
31
  $newer_than_timestamp = false;
32
  }
33
  $this->ALC = new \MailPoet\Newsletter\AutomatedLatestContent(
23
  $parent = Newsletter::findOne($newsletter_id);
24
  $newer_than_timestamp = $parent->created_at;
25
  }
 
 
 
26
  } else {
27
+ $newsletter_id = false;
28
  $newer_than_timestamp = false;
29
  }
30
  $this->ALC = new \MailPoet\Newsletter\AutomatedLatestContent(
lib/Newsletter/Scheduler/Scheduler.php CHANGED
@@ -176,6 +176,18 @@ class Scheduler {
176
  return $next_run_date;
177
  }
178
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  static function getNewsletters($type) {
180
  return Newsletter::getPublished()
181
  ->filter('filterType', $type)
176
  return $next_run_date;
177
  }
178
 
179
+ static function getPreviousRunDate($schedule, $from_timestamp = false) {
180
+ $from_timestamp = ($from_timestamp) ? $from_timestamp : current_time('timestamp');
181
+ try {
182
+ $schedule = \Cron\CronExpression::factory($schedule);
183
+ $previous_run_date = $schedule->getPreviousRunDate(Carbon::createFromTimestamp($from_timestamp))
184
+ ->format('Y-m-d H:i:s');
185
+ } catch(\Exception $e) {
186
+ $previous_run_date = false;
187
+ }
188
+ return $previous_run_date;
189
+ }
190
+
191
  static function getNewsletters($type) {
192
  return Newsletter::getPublished()
193
  ->filter('filterType', $type)
lib/Router/Endpoints/CronDaemon.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
 
2
  namespace MailPoet\Router\Endpoints;
3
 
 
4
  use MailPoet\Cron\CronHelper;
5
  use MailPoet\Cron\Daemon;
6
 
@@ -17,6 +19,9 @@ class CronDaemon {
17
  self::ACTION_PING_RESPONSE
18
  );
19
  public $data;
 
 
 
20
 
21
  function __construct($data) {
22
  $this->data = $data;
1
  <?php
2
+
3
  namespace MailPoet\Router\Endpoints;
4
 
5
+ use MailPoet\Config\AccessControl;
6
  use MailPoet\Cron\CronHelper;
7
  use MailPoet\Cron\Daemon;
8
 
19
  self::ACTION_PING_RESPONSE
20
  );
21
  public $data;
22
+ public $permissions = array(
23
+ 'global' => AccessControl::NO_ACCESS_RESTRICTION
24
+ );
25
 
26
  function __construct($data) {
27
  $this->data = $data;
lib/Router/Endpoints/Subscription.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
 
2
  namespace MailPoet\Router\Endpoints;
3
 
 
4
  use MailPoet\Subscription as UserSubscription;
5
 
6
  if(!defined('ABSPATH')) exit;
@@ -16,6 +18,9 @@ class Subscription {
16
  self::ACTION_UNSUBSCRIBE
17
  );
18
  public $data;
 
 
 
19
 
20
  function __construct($data) {
21
  $this->data = $data;
1
  <?php
2
+
3
  namespace MailPoet\Router\Endpoints;
4
 
5
+ use MailPoet\Config\AccessControl;
6
  use MailPoet\Subscription as UserSubscription;
7
 
8
  if(!defined('ABSPATH')) exit;
18
  self::ACTION_UNSUBSCRIBE
19
  );
20
  public $data;
21
+ public $permissions = array(
22
+ 'global' => AccessControl::NO_ACCESS_RESTRICTION
23
+ );
24
 
25
  function __construct($data) {
26
  $this->data = $data;
lib/Router/Endpoints/Track.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
 
2
  namespace MailPoet\Router\Endpoints;
3
 
 
4
  use MailPoet\Models\Newsletter;
5
  use MailPoet\Models\NewsletterLink;
6
  use MailPoet\Models\SendingQueue;
@@ -20,6 +22,9 @@ class Track {
20
  self::ACTION_OPEN
21
  );
22
  public $data;
 
 
 
23
 
24
  function __construct($data) {
25
  $this->data = $this->_processTrackData($data);
@@ -38,8 +43,8 @@ class Track {
38
  function _processTrackData($data) {
39
  $data = (object)Links::transformUrlDataObject($data);
40
  if(empty($data->queue_id) ||
41
- empty($data->subscriber_id) ||
42
- empty($data->subscriber_token)
43
  ) {
44
  return false;
45
  }
1
  <?php
2
+
3
  namespace MailPoet\Router\Endpoints;
4
 
5
+ use MailPoet\Config\AccessControl;
6
  use MailPoet\Models\Newsletter;
7
  use MailPoet\Models\NewsletterLink;
8
  use MailPoet\Models\SendingQueue;
22
  self::ACTION_OPEN
23
  );
24
  public $data;
25
+ public $permissions = array(
26
+ 'global' => AccessControl::NO_ACCESS_RESTRICTION
27
+ );
28
 
29
  function __construct($data) {
30
  $this->data = $this->_processTrackData($data);
43
  function _processTrackData($data) {
44
  $data = (object)Links::transformUrlDataObject($data);
45
  if(empty($data->queue_id) ||
46
+ empty($data->subscriber_id) ||
47
+ empty($data->subscriber_token)
48
  ) {
49
  return false;
50
  }
lib/Router/Endpoints/ViewInBrowser.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
 
2
  namespace MailPoet\Router\Endpoints;
3
 
4
- use MailPoet\Config\Env;
5
  use MailPoet\Models\Newsletter;
6
  use MailPoet\Models\SendingQueue;
7
  use MailPoet\Models\Subscriber;
@@ -17,8 +18,12 @@ class ViewInBrowser {
17
  const ACTION_VIEW = 'view';
18
  public $allowed_actions = array(self::ACTION_VIEW);
19
  public $data;
 
 
 
20
 
21
- function __construct($data) {
 
22
  $this->data = $this->_processBrowserPreviewData($data);
23
  }
24
 
@@ -69,8 +74,8 @@ class ViewInBrowser {
69
  $data->queue = false;
70
  }
71
 
72
- // allow users with 'manage_options' permission to preview any newsletter
73
- if(!empty($data->preview) && current_user_can(Env::$required_permission)
74
  ) return $data;
75
 
76
  // allow others to preview newsletters only when newsletter hash is defined
1
  <?php
2
+
3
  namespace MailPoet\Router\Endpoints;
4
 
5
+ use MailPoet\Config\AccessControl;
6
  use MailPoet\Models\Newsletter;
7
  use MailPoet\Models\SendingQueue;
8
  use MailPoet\Models\Subscriber;
18
  const ACTION_VIEW = 'view';
19
  public $allowed_actions = array(self::ACTION_VIEW);
20
  public $data;
21
+ public $permissions = array(
22
+ 'global' => AccessControl::NO_ACCESS_RESTRICTION
23
+ );
24
 
25
+ function __construct($data, AccessControl $access_control) {
26
+ $this->access_control = $access_control;
27
  $this->data = $this->_processBrowserPreviewData($data);
28
  }
29
 
74
  $data->queue = false;
75
  }
76
 
77
+ // allow users with permission to manage emails to preview any newsletter
78
+ if(!empty($data->preview) && $this->access_control->validatePermission(AccessControl::PERMISSION_MANAGE_EMAILS)
79
  ) return $data;
80
 
81
  // allow others to preview newsletters only when newsletter hash is defined
lib/Router/Router.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
 
2
  namespace MailPoet\Router;
3
 
 
4
  use MailPoet\Util\Helpers;
5
 
6
  if(!defined('ABSPATH')) exit;
@@ -12,19 +14,21 @@ class Router {
12
  public $data;
13
  const NAME = 'mailpoet_router';
14
  const RESPONSE_ERROR = 404;
 
15
 
16
- function __construct($api_data = false) {
17
  $api_data = ($api_data) ? $api_data : $_GET;
18
  $this->api_request = isset($api_data[self::NAME]);
19
  $this->endpoint = isset($api_data['endpoint']) ?
20
  Helpers::underscoreToCamelCase($api_data['endpoint']) :
21
  false;
22
- $this->action = isset($api_data['action']) ?
23
  Helpers::underscoreToCamelCase($api_data['action']) :
24
  false;
25
  $this->data = isset($api_data['data']) ?
26
  self::decodeRequestData($api_data['data']) :
27
  false;
 
28
  }
29
 
30
  function init() {
@@ -33,15 +37,18 @@ class Router {
33
  if(!$this->endpoint || !class_exists($endpoint_class)) {
34
  return $this->terminateRequest(self::RESPONSE_ERROR, __('Invalid router endpoint', 'mailpoet'));
35
  }
36
- $endpoint = new $endpoint_class($this->data);
37
- if(!method_exists($endpoint, $this->action) || !in_array($this->action, $endpoint->allowed_actions)) {
38
  return $this->terminateRequest(self::RESPONSE_ERROR, __('Invalid router endpoint action', 'mailpoet'));
39
  }
 
 
 
40
  do_action('mailpoet_conflict_resolver_router_url_query_parameters');
41
  return call_user_func(
42
  array(
43
  $endpoint,
44
- $this->action
45
  )
46
  );
47
  }
@@ -74,4 +81,11 @@ class Router {
74
  status_header($code, $message);
75
  exit;
76
  }
77
- }
 
 
 
 
 
 
 
1
  <?php
2
+
3
  namespace MailPoet\Router;
4
 
5
+ use MailPoet\Config\AccessControl;
6
  use MailPoet\Util\Helpers;
7
 
8
  if(!defined('ABSPATH')) exit;
14
  public $data;
15
  const NAME = 'mailpoet_router';
16
  const RESPONSE_ERROR = 404;
17
+ const RESPONE_FORBIDDEN = 403;
18
 
19
+ function __construct(AccessControl $access_control, $api_data = false) {
20
  $api_data = ($api_data) ? $api_data : $_GET;
21
  $this->api_request = isset($api_data[self::NAME]);
22
  $this->endpoint = isset($api_data['endpoint']) ?
23
  Helpers::underscoreToCamelCase($api_data['endpoint']) :
24
  false;
25
+ $this->endpoint_action = isset($api_data['action']) ?
26
  Helpers::underscoreToCamelCase($api_data['action']) :
27
  false;
28
  $this->data = isset($api_data['data']) ?
29
  self::decodeRequestData($api_data['data']) :
30
  false;
31
+ $this->access_control = $access_control;
32
  }
33
 
34
  function init() {
37
  if(!$this->endpoint || !class_exists($endpoint_class)) {
38
  return $this->terminateRequest(self::RESPONSE_ERROR, __('Invalid router endpoint', 'mailpoet'));
39
  }
40
+ $endpoint = new $endpoint_class($this->data, $this->access_control);
41
+ if(!method_exists($endpoint, $this->endpoint_action) || !in_array($this->endpoint_action, $endpoint->allowed_actions)) {
42
  return $this->terminateRequest(self::RESPONSE_ERROR, __('Invalid router endpoint action', 'mailpoet'));
43
  }
44
+ if(!$this->validatePermissions($this->endpoint_action, $endpoint->permissions)) {
45
+ return $this->terminateRequest(self::RESPONE_FORBIDDEN, __('You do not have the required permissions.', 'mailpoet'));
46
+ }
47
  do_action('mailpoet_conflict_resolver_router_url_query_parameters');
48
  return call_user_func(
49
  array(
50
  $endpoint,
51
+ $this->endpoint_action
52
  )
53
  );
54
  }
81
  status_header($code, $message);
82
  exit;
83
  }
84
+
85
+ function validatePermissions($endpoint_action, $permissions) {
86
+ // validate action permission if defined, otherwise validate global permission
87
+ return(!empty($permissions['actions'][$endpoint_action])) ?
88
+ $this->access_control->validatePermission($permissions['actions'][$endpoint_action]) :
89
+ $this->access_control->validatePermission($permissions['global']);
90
+ }
91
+ }
lib/Services/Bridge.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  namespace MailPoet\Services;
3
 
4
  use MailPoet\Mailer\Mailer;
@@ -14,12 +15,13 @@ class Bridge {
14
  const PREMIUM_KEY_SETTING_NAME = 'premium.premium_key';
15
  const PREMIUM_KEY_STATE_SETTING_NAME = 'premium.premium_key_state';
16
 
17
- const PREMIUM_KEY_VALID = 'valid';
18
- const PREMIUM_KEY_INVALID = 'invalid';
19
- const PREMIUM_KEY_EXPIRING = 'expiring';
20
- const PREMIUM_KEY_ALREADY_USED = 'already_used';
 
21
 
22
- const PREMIUM_KEY_CHECK_ERROR = 'check_error';
23
 
24
  const CHECK_ERROR_UNAVAILABLE = 503;
25
  const CHECK_ERROR_UNKNOWN = 'unknown';
@@ -31,7 +33,7 @@ class Bridge {
31
  $mailer_config = Mailer::getMailerConfig();
32
  return !empty($mailer_config['method'])
33
  && $mailer_config['method'] === Mailer::METHOD_MAILPOET;
34
- } catch (\Exception $e) {
35
  return false;
36
  }
37
  }
@@ -57,12 +59,12 @@ class Bridge {
57
  function checkMSSKey($api_key) {
58
  $this->initApi($api_key);
59
  $result = $this->api->checkMSSKey();
60
- return $this->processPremiumKeyCheckResult($result);
61
  }
62
 
63
  function storeMSSKeyAndState($key, $state) {
64
  if(empty($state['state'])
65
- || $state['state'] === self::PREMIUM_KEY_CHECK_ERROR
66
  ) {
67
  return false;
68
  }
@@ -83,26 +85,27 @@ class Bridge {
83
  function checkPremiumKey($key) {
84
  $this->initApi($key);
85
  $result = $this->api->checkPremiumKey();
86
- return $this->processPremiumKeyCheckResult($result);
87
  }
88
 
89
- private function processPremiumKeyCheckResult(array $result) {
90
  $state_map = array(
91
- 200 => self::PREMIUM_KEY_VALID,
92
- 401 => self::PREMIUM_KEY_INVALID,
93
- 402 => self::PREMIUM_KEY_ALREADY_USED
 
94
  );
95
 
96
  if(!empty($result['code']) && isset($state_map[$result['code']])) {
97
- if($state_map[$result['code']] == self::PREMIUM_KEY_VALID
98
  && !empty($result['data']['expire_at'])
99
  ) {
100
- $key_state = self::PREMIUM_KEY_EXPIRING;
101
  } else {
102
  $key_state = $state_map[$result['code']];
103
  }
104
  } else {
105
- $key_state = self::PREMIUM_KEY_CHECK_ERROR;
106
  }
107
 
108
  return $this->buildKeyState(
@@ -113,7 +116,7 @@ class Bridge {
113
 
114
  function storePremiumKeyAndState($key, $state) {
115
  if(empty($state['state'])
116
- || $state['state'] === self::PREMIUM_KEY_CHECK_ERROR
117
  ) {
118
  return false;
119
  }
@@ -143,8 +146,8 @@ class Bridge {
143
 
144
  function updateSubscriberCount($result) {
145
  if(!empty($result['state'])
146
- && ($result['state'] === self::PREMIUM_KEY_VALID
147
- || $result['state'] === self::PREMIUM_KEY_EXPIRING)
148
  ) {
149
  return $this->api->updateSubscriberCount(Subscriber::getTotalSubscribers());
150
  }
@@ -154,7 +157,7 @@ class Bridge {
154
  static function invalidateKey() {
155
  Setting::setValue(
156
  self::API_KEY_STATE_SETTING_NAME,
157
- array('state' => self::PREMIUM_KEY_INVALID)
158
  );
159
  }
160
 
1
  <?php
2
+
3
  namespace MailPoet\Services;
4
 
5
  use MailPoet\Mailer\Mailer;
15
  const PREMIUM_KEY_SETTING_NAME = 'premium.premium_key';
16
  const PREMIUM_KEY_STATE_SETTING_NAME = 'premium.premium_key_state';
17
 
18
+ const PREMIUM_KEY_VALID = 'valid'; // for backwards compatibility until version 3.0.0
19
+ const KEY_VALID = 'valid';
20
+ const KEY_INVALID = 'invalid';
21
+ const KEY_EXPIRING = 'expiring';
22
+ const KEY_ALREADY_USED = 'already_used';
23
 
24
+ const KEY_CHECK_ERROR = 'check_error';
25
 
26
  const CHECK_ERROR_UNAVAILABLE = 503;
27
  const CHECK_ERROR_UNKNOWN = 'unknown';
33
  $mailer_config = Mailer::getMailerConfig();
34
  return !empty($mailer_config['method'])
35
  && $mailer_config['method'] === Mailer::METHOD_MAILPOET;
36
+ } catch(\Exception $e) {
37
  return false;
38
  }
39
  }
59
  function checkMSSKey($api_key) {
60
  $this->initApi($api_key);
61
  $result = $this->api->checkMSSKey();
62
+ return $this->processKeyCheckResult($result);
63
  }
64
 
65
  function storeMSSKeyAndState($key, $state) {
66
  if(empty($state['state'])
67
+ || $state['state'] === self::KEY_CHECK_ERROR
68
  ) {
69
  return false;
70
  }
85
  function checkPremiumKey($key) {
86
  $this->initApi($key);
87
  $result = $this->api->checkPremiumKey();
88
+ return $this->processKeyCheckResult($result);
89
  }
90
 
91
+ private function processKeyCheckResult(array $result) {
92
  $state_map = array(
93
+ 200 => self::KEY_VALID,
94
+ 401 => self::KEY_INVALID,
95
+ 402 => self::KEY_ALREADY_USED,
96
+ 403 => self::KEY_INVALID
97
  );
98
 
99
  if(!empty($result['code']) && isset($state_map[$result['code']])) {
100
+ if($state_map[$result['code']] == self::KEY_VALID
101
  && !empty($result['data']['expire_at'])
102
  ) {
103
+ $key_state = self::KEY_EXPIRING;
104
  } else {
105
  $key_state = $state_map[$result['code']];
106
  }
107
  } else {
108
+ $key_state = self::KEY_CHECK_ERROR;
109
  }
110
 
111
  return $this->buildKeyState(
116
 
117
  function storePremiumKeyAndState($key, $state) {
118
  if(empty($state['state'])
119
+ || $state['state'] === self::KEY_CHECK_ERROR
120
  ) {
121
  return false;
122
  }
146
 
147
  function updateSubscriberCount($result) {
148
  if(!empty($result['state'])
149
+ && ($result['state'] === self::KEY_VALID
150
+ || $result['state'] === self::KEY_EXPIRING)
151
  ) {
152
  return $this->api->updateSubscriberCount(Subscriber::getTotalSubscribers());
153
  }
157
  static function invalidateKey() {
158
  Setting::setValue(
159
  self::API_KEY_STATE_SETTING_NAME,
160
+ array('state' => self::KEY_INVALID)
161
  );
162
  }
163
 
lib/Services/Bridge/API.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  namespace MailPoet\Services\Bridge;
3
 
4
  if(!defined('ABSPATH')) exit;
@@ -9,7 +10,6 @@ class API {
9
  const SENDING_STATUS_SEND_ERROR = 'send_error';
10
 
11
  const RESPONSE_CODE_KEY_INVALID = 401;
12
-
13
  const RESPONSE_CODE_STATS_SAVED = 204;
14
 
15
  private $api_key;
@@ -33,12 +33,8 @@ class API {
33
  $code = wp_remote_retrieve_response_code($result);
34
  switch($code) {
35
  case 200:
36
- case 402:
37
  $body = json_decode(wp_remote_retrieve_body($result), true);
38
  break;
39
- case 401:
40
- $body = wp_remote_retrieve_body($result);
41
- break;
42
  default:
43
  $body = null;
44
  break;
1
  <?php
2
+
3
  namespace MailPoet\Services\Bridge;
4
 
5
  if(!defined('ABSPATH')) exit;
10
  const SENDING_STATUS_SEND_ERROR = 'send_error';
11
 
12
  const RESPONSE_CODE_KEY_INVALID = 401;
 
13
  const RESPONSE_CODE_STATS_SAVED = 204;
14
 
15
  private $api_key;
33
  $code = wp_remote_retrieve_response_code($result);
34
  switch($code) {
35
  case 200:
 
36
  $body = json_decode(wp_remote_retrieve_body($result), true);
37
  break;
 
 
 
38
  default:
39
  $body = null;
40
  break;
lib/Subscription/Form.php CHANGED
@@ -2,14 +2,15 @@
2
 
3
  namespace MailPoet\Subscription;
4
 
5
- use MailPoet\API\JSON\API;
6
  use MailPoet\API\JSON\Response as APIResponse;
 
7
  use MailPoet\Util\Url as UrlHelper;
8
 
9
  class Form {
10
  static function onSubmit($request_data = false) {
11
  $request_data = ($request_data) ? $request_data : $_REQUEST;
12
- $api = new API();
13
  $api->setRequestData($request_data);
14
  $form_id = (!empty($request_data['data']['form_id'])) ? (int)$request_data['data']['form_id'] : false;
15
  $response = $api->processRoute();
2
 
3
  namespace MailPoet\Subscription;
4
 
5
+ use MailPoet\API\API as API;
6
  use MailPoet\API\JSON\Response as APIResponse;
7
+ use MailPoet\Config\AccessControl;
8
  use MailPoet\Util\Url as UrlHelper;
9
 
10
  class Form {
11
  static function onSubmit($request_data = false) {
12
  $request_data = ($request_data) ? $request_data : $_REQUEST;
13
+ $api = API::JSON(new AccessControl());
14
  $api->setRequestData($request_data);
15
  $form_id = (!empty($request_data['data']['form_id'])) ? (int)$request_data['data']['form_id'] : false;
16
  $response = $api->processRoute();
lib/Subscription/Manage.php CHANGED
@@ -1,5 +1,8 @@
1
  <?php
 
2
  namespace MailPoet\Subscription;
 
 
3
  use MailPoet\Models\Subscriber;
4
  use MailPoet\Util\Url;
5
 
@@ -13,10 +16,10 @@ class Manage {
13
  Url::redirectBack();
14
  }
15
  $subscriber_data = $_POST['data'];
 
 
16
 
17
- if(!empty($subscriber_data['email']) &&
18
- Subscriber::verifyToken($subscriber_data['email'], $token)
19
- ) {
20
  if($subscriber_data['email'] !== Pages::DEMO_EMAIL) {
21
  $subscriber = Subscriber::createOrUpdate($subscriber_data);
22
  $errors = $subscriber->getErrors();
1
  <?php
2
+
3
  namespace MailPoet\Subscription;
4
+
5
+ use MailPoet\Form\Util\FieldNameObfuscator;
6
  use MailPoet\Models\Subscriber;
7
  use MailPoet\Util\Url;
8
 
16
  Url::redirectBack();
17
  }
18
  $subscriber_data = $_POST['data'];
19
+ $obfuscator = new FieldNameObfuscator();
20
+ $subscriber_data = $obfuscator->deobfuscateFormPayload($subscriber_data);
21
 
22
+ if(!empty($subscriber_data['email']) && Subscriber::verifyToken($subscriber_data['email'], $token)) {
 
 
23
  if($subscriber_data['email'] !== Pages::DEMO_EMAIL) {
24
  $subscriber = Subscriber::createOrUpdate($subscriber_data);
25
  $errors = $subscriber->getErrors();
lib/Subscription/Pages.php CHANGED
@@ -95,7 +95,7 @@ class Pages {
95
  }
96
  }
97
  }
98
-
99
  function setPageTitle($page_title = '') {
100
  global $post;
101
 
@@ -393,7 +393,7 @@ class Pages {
393
  $form_html .= '</p>';
394
 
395
  // subscription form
396
- $form_html .= FormRenderer::renderBlocks($form);
397
  $form_html .= '</form>';
398
  return $form_html;
399
  }
95
  }
96
  }
97
  }
98
+
99
  function setPageTitle($page_title = '') {
100
  global $post;
101
 
393
  $form_html .= '</p>';
394
 
395
  // subscription form
396
+ $form_html .= FormRenderer::renderBlocks($form, $honeypot = false);
397
  $form_html .= '</form>';
398
  return $form_html;
399
  }
mailpoet.php CHANGED
@@ -4,7 +4,7 @@ if(!defined('ABSPATH')) exit;
4
 
5
  /*
6
  * Plugin Name: MailPoet 3 (new)
7
- * Version: 3.0.0-rc.1.0.4
8
  * Plugin URI: http://www.mailpoet.com
9
  * Description: Create and send newsletters, post notifications and welcome emails from your WordPress.
10
  * Author: MailPoet
@@ -21,7 +21,7 @@ if(!defined('ABSPATH')) exit;
21
  */
22
 
23
  $mailpoet_plugin = array(
24
- 'version' => '3.0.0-rc.1.0.4',
25
  'filename' => __FILE__,
26
  'path' => dirname(__FILE__),
27
  'autoloader' => dirname(__FILE__) . '/vendor/autoload.php',
4
 
5
  /*
6
  * Plugin Name: MailPoet 3 (new)
7
+ * Version: 3.0.0-rc.2.0.0
8
  * Plugin URI: http://www.mailpoet.com
9
  * Description: Create and send newsletters, post notifications and welcome emails from your WordPress.
10
  * Author: MailPoet
21
  */
22
 
23
  $mailpoet_plugin = array(
24
+ 'version' => '3.0.0-rc.2.0.0',
25
  'filename' => __FILE__,
26
  'path' => dirname(__FILE__),
27
  'autoloader' => dirname(__FILE__) . '/vendor/autoload.php',
readme.txt CHANGED
@@ -3,7 +3,8 @@ Contributors: mailpoet, wysija
3
  Tags: newsletter, email, welcome email, post notification, autoresponder, signup, subscription, SMTP
4
  Requires at least: 4.6
5
  Tested up to: 4.8
6
- Stable tag: 3.0.0-rc.1.0.4
 
7
  Create and send beautiful emails and newsletters from WordPress.
8
 
9
  == Description ==
@@ -93,6 +94,17 @@ Our [support site](https://beta.docs.mailpoet.com) has plenty of articles. You c
93
 
94
  == Changelog ==
95
 
 
 
 
 
 
 
 
 
 
 
 
96
  = 3.0.0-rc.1.0.4 - 2017-08-22 =
97
  * Added: newsletters can now be paused and edited while sending;
98
  * Added: tooltips across the UI to quickly answer questions we often get on support;
3
  Tags: newsletter, email, welcome email, post notification, autoresponder, signup, subscription, SMTP
4
  Requires at least: 4.6
5
  Tested up to: 4.8
6
+ Requires PHP: 5.3
7
+ Stable tag: 3.0.0-rc.2.0.0
8
  Create and send beautiful emails and newsletters from WordPress.
9
 
10
  == Description ==
94
 
95
  == Changelog ==
96
 
97
+ = 3.0.0-rc.2.0.0 - 2017-08-29 =
98
+ * Improved: MailPoet updates on high traffic sites now use less resources;
99
+ * Improved: newsletter is saved when "next" button is pressed in newsletter editor;
100
+ * Improved: allows editors to manage emails and adds hooks to extend plugin's roles/permissions;
101
+ * Improved: we collect more informative data from those who share their data with us. You should too!
102
+ * Fixed: subscription management form works again;
103
+ * Fixed: MailPoet 3 no longer processes the "wysija_form" shortcode used by the old MailPoet 2 to allow both plugins to display forms. Please use the newer "mailpoet_form" shortcode instead. Thx Lynn!
104
+ * Fixed: reactivated post notifications will be sent on next scheduled time. Thx Luc!
105
+ * Fixed: updating subscription information of WP users no longer erases their first/last name;
106
+ * Fixed: automated latest content in welcome emails always displays the latest posts. Kudos Ehi!
107
+
108
  = 3.0.0-rc.1.0.4 - 2017-08-22 =
109
  * Added: newsletters can now be paused and edited while sending;
110
  * Added: tooltips across the UI to quickly answer questions we often get on support;
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit10b5d37ffba46ca8f302144725b97f38::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit4e7b78adf8569cf01525fd80978c5d4c::getLoader();
vendor/composer/ClassLoader.php CHANGED
@@ -55,6 +55,7 @@ class ClassLoader
55
  private $classMap = array();
56
  private $classMapAuthoritative = false;
57
  private $missingClasses = array();
 
58
 
59
  public function getPrefixes()
60
  {
@@ -271,6 +272,26 @@ class ClassLoader
271
  return $this->classMapAuthoritative;
272
  }
273
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  /**
275
  * Registers this instance as an autoloader.
276
  *
@@ -313,11 +334,6 @@ class ClassLoader
313
  */
314
  public function findFile($class)
315
  {
316
- // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
317
- if ('\\' == $class[0]) {
318
- $class = substr($class, 1);
319
- }
320
-
321
  // class map lookup
322
  if (isset($this->classMap[$class])) {
323
  return $this->classMap[$class];
@@ -325,6 +341,12 @@ class ClassLoader
325
  if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
326
  return false;
327
  }
 
 
 
 
 
 
328
 
329
  $file = $this->findFileWithExtension($class, '.php');
330
 
@@ -333,6 +355,10 @@ class ClassLoader
333
  $file = $this->findFileWithExtension($class, '.hh');
334
  }
335
 
 
 
 
 
336
  if (false === $file) {
337
  // Remember that this class does not exist.
338
  $this->missingClasses[$class] = true;
@@ -348,9 +374,13 @@ class ClassLoader
348
 
349
  $first = $class[0];
350
  if (isset($this->prefixLengthsPsr4[$first])) {
351
- foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
352
- if (0 === strpos($class, $prefix)) {
353
- foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
 
 
 
 
354
  if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
355
  return $file;
356
  }
55
  private $classMap = array();
56
  private $classMapAuthoritative = false;
57
  private $missingClasses = array();
58
+ private $apcuPrefix;
59
 
60
  public function getPrefixes()
61
  {
272
  return $this->classMapAuthoritative;
273
  }
274
 
275
+ /**
276
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
277
+ *
278
+ * @param string|null $apcuPrefix
279
+ */
280
+ public function setApcuPrefix($apcuPrefix)
281
+ {
282
+ $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
283
+ }
284
+
285
+ /**
286
+ * The APCu prefix in use, or null if APCu caching is not enabled.
287
+ *
288
+ * @return string|null
289
+ */
290
+ public function getApcuPrefix()
291
+ {
292
+ return $this->apcuPrefix;
293
+ }
294
+
295
  /**
296
  * Registers this instance as an autoloader.
297
  *
334
  */
335
  public function findFile($class)
336
  {
 
 
 
 
 
337
  // class map lookup
338
  if (isset($this->classMap[$class])) {
339
  return $this->classMap[$class];
341
  if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
342
  return false;
343
  }
344
+ if (null !== $this->apcuPrefix) {
345
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
346
+ if ($hit) {
347
+ return $file;
348
+ }
349
+ }
350
 
351
  $file = $this->findFileWithExtension($class, '.php');
352
 
355
  $file = $this->findFileWithExtension($class, '.hh');
356
  }
357
 
358
+ if (null !== $this->apcuPrefix) {
359
+ apcu_add($this->apcuPrefix.$class, $file);
360
+ }
361
+
362
  if (false === $file) {
363
  // Remember that this class does not exist.
364
  $this->missingClasses[$class] = true;
374
 
375
  $first = $class[0];
376
  if (isset($this->prefixLengthsPsr4[$first])) {
377
+ $subPath = $class;
378
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
379
+ $subPath = substr($subPath, 0, $lastPos);
380
+ $search = $subPath.'\\';
381
+ if (isset($this->prefixDirsPsr4[$search])) {
382
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
383
+ $length = $this->prefixLengthsPsr4[$first][$search];
384
  if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
385
  return $file;
386
  }
vendor/composer/autoload_classmap.php CHANGED
@@ -27,7 +27,6 @@ return array(
27
  'IdiormStringException' => $vendorDir . '/j4mie/idiorm/idiorm.php',
28
  'MailPoet\\API\\API' => $baseDir . '/lib/API/API.php',
29
  'MailPoet\\API\\JSON\\API' => $baseDir . '/lib/API/JSON/API.php',
30
- 'MailPoet\\API\\JSON\\Access' => $baseDir . '/lib/API/JSON/Access.php',
31
  'MailPoet\\API\\JSON\\Endpoint' => $baseDir . '/lib/API/JSON/Endpoint.php',
32
  'MailPoet\\API\\JSON\\Error' => $baseDir . '/lib/API/JSON/Error.php',
33
  'MailPoet\\API\\JSON\\ErrorResponse' => $baseDir . '/lib/API/JSON/ErrorResponse.php',
@@ -50,6 +49,7 @@ return array(
50
  'MailPoet\\API\\MP\\v1\\API' => $baseDir . '/lib/API/MP/v1/API.php',
51
  'MailPoet\\Analytics\\Analytics' => $baseDir . '/lib/Analytics/Analytics.php',
52
  'MailPoet\\Analytics\\Reporter' => $baseDir . '/lib/Analytics/Reporter.php',
 
53
  'MailPoet\\Config\\Activator' => $baseDir . '/lib/Config/Activator.php',
54
  'MailPoet\\Config\\Changelog' => $baseDir . '/lib/Config/Changelog.php',
55
  'MailPoet\\Config\\Database' => $baseDir . '/lib/Config/Database.php',
27
  'IdiormStringException' => $vendorDir . '/j4mie/idiorm/idiorm.php',
28
  'MailPoet\\API\\API' => $baseDir . '/lib/API/API.php',
29
  'MailPoet\\API\\JSON\\API' => $baseDir . '/lib/API/JSON/API.php',
 
30
  'MailPoet\\API\\JSON\\Endpoint' => $baseDir . '/lib/API/JSON/Endpoint.php',
31
  'MailPoet\\API\\JSON\\Error' => $baseDir . '/lib/API/JSON/Error.php',
32
  'MailPoet\\API\\JSON\\ErrorResponse' => $baseDir . '/lib/API/JSON/ErrorResponse.php',
49
  'MailPoet\\API\\MP\\v1\\API' => $baseDir . '/lib/API/MP/v1/API.php',
50
  'MailPoet\\Analytics\\Analytics' => $baseDir . '/lib/Analytics/Analytics.php',
51
  'MailPoet\\Analytics\\Reporter' => $baseDir . '/lib/Analytics/Reporter.php',
52
+ 'MailPoet\\Config\\AccessControl' => $baseDir . '/lib/Config/AccessControl.php',
53
  'MailPoet\\Config\\Activator' => $baseDir . '/lib/Config/Activator.php',
54
  'MailPoet\\Config\\Changelog' => $baseDir . '/lib/Config/Changelog.php',
55
  'MailPoet\\Config\\Database' => $baseDir . '/lib/Config/Database.php',
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit10b5d37ffba46ca8f302144725b97f38
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInit10b5d37ffba46ca8f302144725b97f38
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit10b5d37ffba46ca8f302144725b97f38', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit10b5d37ffba46ca8f302144725b97f38', 'loadClassLoader'));
25
 
26
- $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInit10b5d37ffba46ca8f302144725b97f38::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
@@ -48,19 +48,19 @@ class ComposerAutoloaderInit10b5d37ffba46ca8f302144725b97f38
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
- $includeFiles = Composer\Autoload\ComposerStaticInit10b5d37ffba46ca8f302144725b97f38::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
- composerRequire10b5d37ffba46ca8f302144725b97f38($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
- function composerRequire10b5d37ffba46ca8f302144725b97f38($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit4e7b78adf8569cf01525fd80978c5d4c
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit4e7b78adf8569cf01525fd80978c5d4c', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit4e7b78adf8569cf01525fd80978c5d4c', 'loadClassLoader'));
25
 
26
+ $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInit4e7b78adf8569cf01525fd80978c5d4c::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
+ $includeFiles = Composer\Autoload\ComposerStaticInit4e7b78adf8569cf01525fd80978c5d4c::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
+ composerRequire4e7b78adf8569cf01525fd80978c5d4c($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
+ function composerRequire4e7b78adf8569cf01525fd80978c5d4c($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit10b5d37ffba46ca8f302144725b97f38
8
  {
9
  public static $files = array (
10
  '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
@@ -117,7 +117,6 @@ class ComposerStaticInit10b5d37ffba46ca8f302144725b97f38
117
  'IdiormStringException' => __DIR__ . '/..' . '/j4mie/idiorm/idiorm.php',
118
  'MailPoet\\API\\API' => __DIR__ . '/../..' . '/lib/API/API.php',
119
  'MailPoet\\API\\JSON\\API' => __DIR__ . '/../..' . '/lib/API/JSON/API.php',
120
- 'MailPoet\\API\\JSON\\Access' => __DIR__ . '/../..' . '/lib/API/JSON/Access.php',
121
  'MailPoet\\API\\JSON\\Endpoint' => __DIR__ . '/../..' . '/lib/API/JSON/Endpoint.php',
122
  'MailPoet\\API\\JSON\\Error' => __DIR__ . '/../..' . '/lib/API/JSON/Error.php',
123
  'MailPoet\\API\\JSON\\ErrorResponse' => __DIR__ . '/../..' . '/lib/API/JSON/ErrorResponse.php',
@@ -140,6 +139,7 @@ class ComposerStaticInit10b5d37ffba46ca8f302144725b97f38
140
  'MailPoet\\API\\MP\\v1\\API' => __DIR__ . '/../..' . '/lib/API/MP/v1/API.php',
141
  'MailPoet\\Analytics\\Analytics' => __DIR__ . '/../..' . '/lib/Analytics/Analytics.php',
142
  'MailPoet\\Analytics\\Reporter' => __DIR__ . '/../..' . '/lib/Analytics/Reporter.php',
 
143
  'MailPoet\\Config\\Activator' => __DIR__ . '/../..' . '/lib/Config/Activator.php',
144
  'MailPoet\\Config\\Changelog' => __DIR__ . '/../..' . '/lib/Config/Changelog.php',
145
  'MailPoet\\Config\\Database' => __DIR__ . '/../..' . '/lib/Config/Database.php',
@@ -834,10 +834,10 @@ class ComposerStaticInit10b5d37ffba46ca8f302144725b97f38
834
  public static function getInitializer(ClassLoader $loader)
835
  {
836
  return \Closure::bind(function () use ($loader) {
837
- $loader->prefixLengthsPsr4 = ComposerStaticInit10b5d37ffba46ca8f302144725b97f38::$prefixLengthsPsr4;
838
- $loader->prefixDirsPsr4 = ComposerStaticInit10b5d37ffba46ca8f302144725b97f38::$prefixDirsPsr4;
839
- $loader->prefixesPsr0 = ComposerStaticInit10b5d37ffba46ca8f302144725b97f38::$prefixesPsr0;
840
- $loader->classMap = ComposerStaticInit10b5d37ffba46ca8f302144725b97f38::$classMap;
841
 
842
  }, null, ClassLoader::class);
843
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit4e7b78adf8569cf01525fd80978c5d4c
8
  {
9
  public static $files = array (
10
  '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
117
  'IdiormStringException' => __DIR__ . '/..' . '/j4mie/idiorm/idiorm.php',
118
  'MailPoet\\API\\API' => __DIR__ . '/../..' . '/lib/API/API.php',
119
  'MailPoet\\API\\JSON\\API' => __DIR__ . '/../..' . '/lib/API/JSON/API.php',
 
120
  'MailPoet\\API\\JSON\\Endpoint' => __DIR__ . '/../..' . '/lib/API/JSON/Endpoint.php',
121
  'MailPoet\\API\\JSON\\Error' => __DIR__ . '/../..' . '/lib/API/JSON/Error.php',
122
  'MailPoet\\API\\JSON\\ErrorResponse' => __DIR__ . '/../..' . '/lib/API/JSON/ErrorResponse.php',
139
  'MailPoet\\API\\MP\\v1\\API' => __DIR__ . '/../..' . '/lib/API/MP/v1/API.php',
140
  'MailPoet\\Analytics\\Analytics' => __DIR__ . '/../..' . '/lib/Analytics/Analytics.php',
141
  'MailPoet\\Analytics\\Reporter' => __DIR__ . '/../..' . '/lib/Analytics/Reporter.php',
142
+ 'MailPoet\\Config\\AccessControl' => __DIR__ . '/../..' . '/lib/Config/AccessControl.php',
143
  'MailPoet\\Config\\Activator' => __DIR__ . '/../..' . '/lib/Config/Activator.php',
144
  'MailPoet\\Config\\Changelog' => __DIR__ . '/../..' . '/lib/Config/Changelog.php',
145
  'MailPoet\\Config\\Database' => __DIR__ . '/../..' . '/lib/Config/Database.php',
834
  public static function getInitializer(ClassLoader $loader)
835
  {
836
  return \Closure::bind(function () use ($loader) {
837
+ $loader->prefixLengthsPsr4 = ComposerStaticInit4e7b78adf8569cf01525fd80978c5d4c::$prefixLengthsPsr4;
838
+ $loader->prefixDirsPsr4 = ComposerStaticInit4e7b78adf8569cf01525fd80978c5d4c::$prefixDirsPsr4;
839
+ $loader->prefixesPsr0 = ComposerStaticInit4e7b78adf8569cf01525fd80978c5d4c::$prefixesPsr0;
840
+ $loader->classMap = ComposerStaticInit4e7b78adf8569cf01525fd80978c5d4c::$classMap;
841
 
842
  }, null, ClassLoader::class);
843
  }
vendor/composer/installed.json CHANGED
@@ -14,7 +14,7 @@
14
  "reference": "b0c1bda3be5a35da44ba1ac28cc61c67d2ada465",
15
  "shasum": ""
16
  },
17
- "time": "2015-11-28 21:47:43",
18
  "type": "library",
19
  "installation-source": "dist",
20
  "autoload": {
@@ -55,7 +55,7 @@
55
  "require-dev": {
56
  "phpunit/phpunit": "^4.8"
57
  },
58
- "time": "2017-03-21 01:31:25",
59
  "type": "library",
60
  "installation-source": "dist",
61
  "autoload": {
@@ -116,7 +116,7 @@
116
  "j4mie/idiorm": "1.5.*",
117
  "php": ">=5.2.0"
118
  },
119
- "time": "2014-09-23 10:49:36",
120
  "type": "library",
121
  "installation-source": "dist",
122
  "autoload": {
@@ -180,7 +180,7 @@
180
  "require-dev": {
181
  "phpunit/phpunit": "~4.0|~5.0"
182
  },
183
- "time": "2017-01-23 04:29:33",
184
  "type": "library",
185
  "installation-source": "dist",
186
  "autoload": {
@@ -226,7 +226,7 @@
226
  "suggest": {
227
  "ext-mbstring": "For best performance"
228
  },
229
- "time": "2017-06-14 15:44:48",
230
  "type": "library",
231
  "extra": {
232
  "branch-alias": {
@@ -299,7 +299,7 @@
299
  "symfony/config": "",
300
  "symfony/yaml": ""
301
  },
302
- "time": "2017-06-24 16:44:49",
303
  "type": "library",
304
  "extra": {
305
  "branch-alias": {
@@ -355,7 +355,7 @@
355
  "friendsofphp/php-cs-fixer": "~2",
356
  "phpunit/phpunit": "~4.0 || ~5.0"
357
  },
358
- "time": "2017-01-16 07:55:07",
359
  "type": "library",
360
  "extra": {
361
  "branch-alias": {
@@ -408,7 +408,7 @@
408
  "require-dev": {
409
  "phpunit/phpunit": "*"
410
  },
411
- "time": "2016-07-19 19:14:21",
412
  "type": "library",
413
  "installation-source": "dist",
414
  "autoload": {
@@ -457,7 +457,7 @@
457
  "phpunit/phpunit": ">=4.0",
458
  "soundasleep/component-tests": "dev-master"
459
  },
460
- "time": "2016-06-09 04:56:16",
461
  "type": "library",
462
  "installation-source": "dist",
463
  "autoload": {
@@ -510,7 +510,7 @@
510
  "mockery/mockery": "~0.9.1",
511
  "symfony/phpunit-bridge": "~3.2"
512
  },
513
- "time": "2017-05-01 15:54:03",
514
  "type": "library",
515
  "extra": {
516
  "branch-alias": {
@@ -562,7 +562,7 @@
562
  "require": {
563
  "php": ">=5.3.3"
564
  },
565
- "time": "2017-07-11 13:25:55",
566
  "type": "library",
567
  "extra": {
568
  "branch-alias": {
@@ -620,7 +620,7 @@
620
  "php": ">=5.3.3",
621
  "symfony/polyfill-php72": "~1.4"
622
  },
623
- "time": "2017-06-14 15:44:48",
624
  "type": "metapackage",
625
  "extra": {
626
  "branch-alias": {
@@ -671,7 +671,7 @@
671
  "require-dev": {
672
  "htmlawed/htmlawed": "dev-master"
673
  },
674
- "time": "2016-01-14 20:55:00",
675
  "type": "library",
676
  "installation-source": "dist",
677
  "autoload": {
@@ -727,7 +727,7 @@
727
  "symfony/debug": "~2.7",
728
  "symfony/phpunit-bridge": "~3.3@dev"
729
  },
730
- "time": "2017-07-04 13:19:31",
731
  "type": "library",
732
  "extra": {
733
  "branch-alias": {
14
  "reference": "b0c1bda3be5a35da44ba1ac28cc61c67d2ada465",
15
  "shasum": ""
16
  },
17
+ "time": "2015-11-28T21:47:43+00:00",
18
  "type": "library",
19
  "installation-source": "dist",
20
  "autoload": {
55
  "require-dev": {
56
  "phpunit/phpunit": "^4.8"
57
  },
58
+ "time": "2017-03-21T01:31:25+00:00",
59
  "type": "library",
60
  "installation-source": "dist",
61
  "autoload": {
116
  "j4mie/idiorm": "1.5.*",
117
  "php": ">=5.2.0"
118
  },
119
+ "time": "2014-09-23T10:49:36+00:00",
120
  "type": "library",
121
  "installation-source": "dist",
122
  "autoload": {
180
  "require-dev": {
181
  "phpunit/phpunit": "~4.0|~5.0"
182
  },
183
+ "time": "2017-01-23T04:29:33+00:00",
184
  "type": "library",
185
  "installation-source": "dist",
186
  "autoload": {
226
  "suggest": {
227
  "ext-mbstring": "For best performance"
228
  },
229
+ "time": "2017-06-14T15:44:48+00:00",
230
  "type": "library",
231
  "extra": {
232
  "branch-alias": {
299
  "symfony/config": "",
300
  "symfony/yaml": ""
301
  },
302
+ "time": "2017-06-24T16:44:49+00:00",
303
  "type": "library",
304
  "extra": {
305
  "branch-alias": {
355
  "friendsofphp/php-cs-fixer": "~2",
356
  "phpunit/phpunit": "~4.0 || ~5.0"
357
  },
358
+ "time": "2017-01-16T07:55:07+00:00",
359
  "type": "library",
360
  "extra": {
361
  "branch-alias": {
408
  "require-dev": {
409
  "phpunit/phpunit": "*"
410
  },
411
+ "time": "2016-07-19T19:14:21+00:00",
412
  "type": "library",
413
  "installation-source": "dist",
414
  "autoload": {
457
  "phpunit/phpunit": ">=4.0",
458
  "soundasleep/component-tests": "dev-master"
459
  },
460
+ "time": "2016-06-09T04:56:16+00:00",
461
  "type": "library",
462
  "installation-source": "dist",
463
  "autoload": {
510
  "mockery/mockery": "~0.9.1",
511
  "symfony/phpunit-bridge": "~3.2"
512
  },
513
+ "time": "2017-05-01T15:54:03+00:00",
514
  "type": "library",
515
  "extra": {
516
  "branch-alias": {
562
  "require": {
563
  "php": ">=5.3.3"
564
  },
565
+ "time": "2017-07-11T13:25:55+00:00",
566
  "type": "library",
567
  "extra": {
568
  "branch-alias": {
620
  "php": ">=5.3.3",
621
  "symfony/polyfill-php72": "~1.4"
622
  },
623
+ "time": "2017-06-14T15:44:48+00:00",
624
  "type": "metapackage",
625
  "extra": {
626
  "branch-alias": {
671
  "require-dev": {
672
  "htmlawed/htmlawed": "dev-master"
673
  },
674
+ "time": "2016-01-14T20:55:00+00:00",
675
  "type": "library",
676
  "installation-source": "dist",
677
  "autoload": {
727
  "symfony/debug": "~2.7",
728
  "symfony/phpunit-bridge": "~3.3@dev"
729
  },
730
+ "time": "2017-07-04T13:19:31+00:00",
731
  "type": "library",
732
  "extra": {
733
  "branch-alias": {
views/form/editor.html CHANGED
@@ -513,6 +513,10 @@
513
  });
514
  }
515
 
 
 
 
 
516
  // if there is a callback, call it!
517
  if(callback !== undefined) {
518
  callback();
@@ -566,8 +570,13 @@
566
  mailpoet_form_export();
567
 
568
  $(document).on('click', '.mailpoet_form_export_toggle', function() {
 
569
  $('.mailpoet_form_export_output').hide();
570
- $('#mailpoet_form_export_'+$(this).data('type')).show();
 
 
 
 
571
  return false;
572
  });
573
 
@@ -614,6 +623,7 @@
614
  var id = $(this).data('id');
615
  var item = $(this).parent();
616
  var name = $(this).siblings('.mailpoet_form_field').attr('wysija_name');
 
617
 
618
  if(window.confirm(
619
  "<%= __('This field will be deleted for all your subscribers. Are you sure?') %>"
@@ -636,6 +646,12 @@
636
  MailPoet.Notice.success(
637
  "<%= __('Removed custom field %$1s') | escape('js') %>".replace('%$1s', '"' + name + '"')
638
  );
 
 
 
 
 
 
639
  });
640
  }
641
  });
513
  });
514
  }
515
 
516
+ MailPoet.trackEvent('Forms > Add New', {
517
+ 'MailPoet Free version': window.mailpoet_version
518
+ });
519
+
520
  // if there is a callback, call it!
521
  if(callback !== undefined) {
522
  callback();
570
  mailpoet_form_export();
571
 
572
  $(document).on('click', '.mailpoet_form_export_toggle', function() {
573
+ var type = $(this).data('type');
574
  $('.mailpoet_form_export_output').hide();
575
+ $('#mailpoet_form_export_' + type).show();
576
+ MailPoet.trackEvent('Forms > Embed', {
577
+ 'Embed type': type,
578
+ 'MailPoet Free version': window.mailpoet_version
579
+ });
580
  return false;
581
  });
582
 
623
  var id = $(this).data('id');
624
  var item = $(this).parent();
625
  var name = $(this).siblings('.mailpoet_form_field').attr('wysija_name');
626
+ var type = $(this).siblings('.mailpoet_form_field').attr('wysija_type');
627
 
628
  if(window.confirm(
629
  "<%= __('This field will be deleted for all your subscribers. Are you sure?') %>"
646
  MailPoet.Notice.success(
647
  "<%= __('Removed custom field %$1s') | escape('js') %>".replace('%$1s', '"' + name + '"')
648
  );
649
+
650
+ MailPoet.trackEvent('Forms > Delete custom field', {
651
+ 'Field type': type,
652
+ 'MailPoet Free version': window.mailpoet_version
653
+ });
654
+
655
  });
656
  }
657
  });
views/form/templates/settings/field_form.hbs CHANGED
@@ -82,6 +82,11 @@
82
  // close popup
83
  MailPoet.Modal.close();
84
 
 
 
 
 
 
85
  if(WysijaForm.updateBlock(response.data) === true) {
86
  // trigger save, if a block has been updated
87
  mailpoet_form_save(false);
82
  // close popup
83
  MailPoet.Modal.close();
84
 
85
+ MailPoet.trackEvent('Forms > Add new custom field', {
86
+ 'Field type': data.type,
87
+ 'MailPoet Free version': window.mailpoet_version
88
+ });
89
+
90
  if(WysijaForm.updateBlock(response.data) === true) {
91
  // trigger save, if a block has been updated
92
  mailpoet_form_save(false);
views/forms.html CHANGED
@@ -6,7 +6,7 @@
6
  <div>
7
  <p class="mailpoet_sending_methods_help help">
8
  <%= __('<strong>Tip:</strong> we have a [link]list of plugins[/link] that work with MailPoet if you need fancier forms.')
9
- |replaceLinkTags('http://beta.docs.mailpoet.com/article/198-list-of-forms-plugins-that-work-with-mailpoet?utm_source=plugin&utm_medium=settings&utm_campaign=helpdocs', {'target' : '_blank'})
10
  |raw
11
  %>
12
  </p>
@@ -68,3 +68,13 @@
68
  'new': __('Add New'),
69
  }) %>
70
  <% endblock %>
 
 
 
 
 
 
 
 
 
 
6
  <div>
7
  <p class="mailpoet_sending_methods_help help">
8
  <%= __('<strong>Tip:</strong> we have a [link]list of plugins[/link] that work with MailPoet if you need fancier forms.')
9
+ |replaceLinkTags('http://beta.docs.mailpoet.com/article/198-list-of-forms-plugins-that-work-with-mailpoet?utm_source=plugin&utm_medium=settings&utm_campaign=helpdocs', {'target' : '_blank', id: 'mailpoet_helper_link'})
10
  |raw
11
  %>
12
  </p>
68
  'new': __('Add New'),
69
  }) %>
70
  <% endblock %>
71
+
72
+ <% block after_javascript %>
73
+ <script type="text/javascript">
74
+ jQuery('#mailpoet_helper_link').on('click', function() {
75
+ MailPoet.trackEvent('Forms page > link to doc page', {
76
+ 'MailPoet Free version': window.mailpoet_version
77
+ });
78
+ });
79
+ </script>
80
+ <% endblock %>
views/layout.html CHANGED
@@ -79,7 +79,7 @@ jQuery('.toplevel_page_mailpoet-newsletters.menu-top-last')
79
  if(window['HS'] !== undefined) {
80
  // HelpScout Beacon: Configuration
81
  HS.beacon.config({
82
- icon: 'message',
83
  zIndex: 50000,
84
  instructions: "<%= __('Want to give feedback to the MailPoet team? Contact us here. Please provide as much information as possible!') %>",
85
  showContactFields: true
79
  if(window['HS'] !== undefined) {
80
  // HelpScout Beacon: Configuration
81
  HS.beacon.config({
82
+ icon: 'question',
83
  zIndex: 50000,
84
  instructions: "<%= __('Want to give feedback to the MailPoet team? Contact us here. Please provide as much information as possible!') %>",
85
  showContactFields: true
views/premium.html CHANGED
@@ -148,3 +148,11 @@
148
  </div>
149
 
150
  <% endblock %>
 
 
 
 
 
 
 
 
148
  </div>
149
 
150
  <% endblock %>
151
+
152
+ <% block after_javascript %>
153
+ <script type="text/javascript">
154
+ MailPoet.trackEvent('Premium page viewed', {
155
+ 'MailPoet Free version': window.mailpoet_version
156
+ });
157
+ </script>
158
+ <% endblock %>
views/update.html CHANGED
@@ -60,8 +60,8 @@
60
  <div class="feature-section one-col mailpoet_centered">
61
  <h2><%= __('Care to Give Your Opinion?') %></h2>
62
 
63
- <script type="text/javascript" charset="utf-8" src="//secure.polldaddy.com/p/9801037.js"></script>
64
- <noscript><a href="//polldaddy.com/poll/9801037/">Did you install MailPoet yourself?</a></noscript>
65
  </div>
66
 
67
  <hr>
60
  <div class="feature-section one-col mailpoet_centered">
61
  <h2><%= __('Care to Give Your Opinion?') %></h2>
62
 
63
+ <script type="text/javascript" charset="utf-8" src="//secure.polldaddy.com/p/9801032.js"></script>
64
+ <noscript><a href="//polldaddy.com/poll/9801032/">To which gender identity to you identify?</a></noscript>
65
  </div>
66
 
67
  <hr>