diff --git a/assets/js/src/date.js b/assets/js/src/date.js index ae6debd5b8..36b3ab4468 100644 --- a/assets/js/src/date.js +++ b/assets/js/src/date.js @@ -41,9 +41,7 @@ define('date', }, format: function(date, options) { this.init(options); - return Moment.utc(date) - .local() - .format(this.convertFormat(this.options.format)); + return Moment(date).format(this.convertFormat(this.options.format)); }, short: function(date) { return this.format(date, { diff --git a/assets/js/src/form/fields/text.jsx b/assets/js/src/form/fields/text.jsx index 2e472c7b54..7f30e09038 100644 --- a/assets/js/src/form/fields/text.jsx +++ b/assets/js/src/form/fields/text.jsx @@ -7,7 +7,10 @@ function( var FormFieldText = React.createClass({ render: function() { var value = this.props.item[this.props.field.name]; - if(!value) { value = null; } + if(value === undefined) { + value = this.props.field.defaultValue || ''; + } + return ( diff --git a/assets/js/src/form/form.jsx b/assets/js/src/form/form.jsx index 6dfc827b82..aebf441d28 100644 --- a/assets/js/src/form/form.jsx +++ b/assets/js/src/form/form.jsx @@ -13,10 +13,11 @@ define( Router, FormField ) { + var Form = React.createClass({ - mixins: [ - Router.History - ], + contextTypes: { + router: React.PropTypes.object.isRequired + }, getDefaultProps: function() { return { params: {}, @@ -68,7 +69,7 @@ define( loading: false, item: {} }, function() { - this.history.pushState(null, '/new'); + this.context.router.push('/new'); }.bind(this)); } else { this.setState({ @@ -118,7 +119,16 @@ define( if(this.props.onSuccess !== undefined) { this.props.onSuccess(); } else { - this.history.pushState(null, '/') + var isChrome = (/Chrome/.test(navigator.userAgent)) + && (/Google Inc/.test(navigator.vendor)); + if( + (isChrome && history.length > 2) + || (!isChrome && history.length > 1) + ) { + this.context.router.goBack(); + } else { + this.context.router.push('/'); + } } if(this.props.params.id !== undefined) { diff --git a/assets/js/src/forms/forms.jsx b/assets/js/src/forms/forms.jsx index 5099d122bd..8f13a478a7 100644 --- a/assets/js/src/forms/forms.jsx +++ b/assets/js/src/forms/forms.jsx @@ -1,10 +1,10 @@ import React from 'react' import ReactDOM from 'react-dom' -import { Router, Route, IndexRoute } from 'react-router' +import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router' +import { createHashHistory } from 'history' import FormList from 'forms/list.jsx' -import createHashHistory from 'history/lib/createHashHistory' -let history = createHashHistory({ queryKey: false }) +const history = useRouterHistory(createHashHistory)({ queryKey: false }); const App = React.createClass({ render() { @@ -12,7 +12,7 @@ const App = React.createClass({ } }); -let container = document.getElementById('forms_container'); +const container = document.getElementById('forms_container'); if(container) { ReactDOM.render(( diff --git a/assets/js/src/listing/listing.jsx b/assets/js/src/listing/listing.jsx index ab3e005f4b..4eb4ffa424 100644 --- a/assets/js/src/listing/listing.jsx +++ b/assets/js/src/listing/listing.jsx @@ -295,9 +295,9 @@ define( }); var Listing = React.createClass({ - mixins: [ - Router.History - ], + contextTypes: { + router: React.PropTypes.object.isRequired + }, getInitialState: function() { return { loading: false, @@ -359,9 +359,12 @@ define( } }) } + + // default overrides if(this.props.limit !== undefined) { state.limit = Math.abs(~~this.props.limit); } + this.setState(state, function() { this.getItems(); }.bind(this)); @@ -398,7 +401,7 @@ define( if(this.props.location) { if(this.props.location.pathname !== params) { - this.history.pushState(null, `${params}`) + this.context.router.push(`${params}`); } } }, @@ -753,8 +756,8 @@ define( onSort={ this.handleSort } onSelectItems={ this.handleSelectItems } selection={ this.state.selection } - sort_by={ this.state.sort_by } - sort_order={ this.state.sort_order } + sort_by={ sort_by } + sort_order={ sort_order } columns={ this.props.columns } is_selectable={ bulk_actions.length > 0 } /> @@ -783,8 +786,8 @@ define( onSort={ this.handleSort } onSelectItems={ this.handleSelectItems } selection={ this.state.selection } - sort_by={ this.state.sort_by } - sort_order={ this.state.sort_order } + sort_by={ sort_by } + sort_order={ sort_order } columns={ this.props.columns } is_selectable={ bulk_actions.length > 0 } /> diff --git a/assets/js/src/newsletters/breadcrumb.jsx b/assets/js/src/newsletters/breadcrumb.jsx index 60515a6d18..a508a1bcc5 100644 --- a/assets/js/src/newsletters/breadcrumb.jsx +++ b/assets/js/src/newsletters/breadcrumb.jsx @@ -14,9 +14,6 @@ define( var Link = Router.Link; var Breadcrumb = React.createClass({ - mixins: [ - Router.History - ], getInitialState: function() { return { step: null, diff --git a/assets/js/src/newsletters/newsletters.jsx b/assets/js/src/newsletters/newsletters.jsx index 435546c51b..9f5ffa15a1 100644 --- a/assets/js/src/newsletters/newsletters.jsx +++ b/assets/js/src/newsletters/newsletters.jsx @@ -1,6 +1,7 @@ import React from 'react' import ReactDOM from 'react-dom' -import { Router, Route, IndexRoute, Link } from 'react-router' +import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router' +import { createHashHistory } from 'history' import NewsletterList from 'newsletters/list.jsx' import NewsletterTypes from 'newsletters/types.jsx' import NewsletterTemplates from 'newsletters/templates.jsx' @@ -8,9 +9,8 @@ import NewsletterSend from 'newsletters/send.jsx' import NewsletterStandard from 'newsletters/types/standard.jsx' import NewsletterWelcome from 'newsletters/types/welcome/welcome.jsx' import NewsletterNotification from 'newsletters/types/notification/notification.jsx' -import createHashHistory from 'history/lib/createHashHistory' -let history = createHashHistory({ queryKey: false }) +const history = useRouterHistory(createHashHistory)({ queryKey: false }); const App = React.createClass({ render() { @@ -18,7 +18,7 @@ const App = React.createClass({ } }); -let container = document.getElementById('newsletters_container'); +const container = document.getElementById('newsletters_container'); if(container) { ReactDOM.render(( diff --git a/assets/js/src/newsletters/send.jsx b/assets/js/src/newsletters/send.jsx index e15943d02d..b1b7e8b2c1 100644 --- a/assets/js/src/newsletters/send.jsx +++ b/assets/js/src/newsletters/send.jsx @@ -23,9 +23,9 @@ define( ) { var NewsletterSend = React.createClass({ - mixins: [ - Router.History - ], + contextTypes: { + router: React.PropTypes.object.isRequired + }, getInitialState: function() { return { fields: [], @@ -68,7 +68,7 @@ define( loading: false, item: {}, }, function() { - this.history.pushState(null, '/new'); + this.context.router.push('/new'); }.bind(this)); } else { this.setState({ @@ -106,8 +106,10 @@ define( }).done((response) => { this.setState({ loading: false }); if(response.result === true) { - this.history.pushState(null, '/'); - MailPoet.Notice.success(response.data.message); + this.context.router.push('/'); + MailPoet.Notice.success( + MailPoet.Notice.success(response.data.message); + ); } else { if(response.errors) { MailPoet.Notice.error(response.errors); @@ -133,7 +135,7 @@ define( this.setState({ loading: false }); if(response.result === true) { - this.history.pushState(null, '/'); + this.context.router.push('/'); MailPoet.Notice.success( MailPoet.I18n.t('newsletterUpdated') ); diff --git a/assets/js/src/newsletters/send/notification.jsx b/assets/js/src/newsletters/send/notification.jsx index ac682d520d..0f1d801e6e 100644 --- a/assets/js/src/newsletters/send/notification.jsx +++ b/assets/js/src/newsletters/send/notification.jsx @@ -60,7 +60,6 @@ define( name: 'sender_name', type: 'text', placeholder: MailPoet.I18n.t('senderNamePlaceholder'), - defaultValue: (settings.sender !== undefined) ? settings.sender.name : '', validation: { 'data-parsley-required': true } @@ -69,7 +68,6 @@ define( name: 'sender_address', type: 'text', placeholder: MailPoet.I18n.t('senderAddressPlaceholder'), - defaultValue: (settings.sender !== undefined) ? settings.sender.address : '', validation: { 'data-parsley-required': true, 'data-parsley-type': 'email' @@ -86,15 +84,13 @@ define( { name: 'reply_to_name', type: 'text', - placeholder: MailPoet.I18n.t('replyToNamePlaceholder'), - defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.name : '', + placeholder: MailPoet.I18n.t('replyToNamePlaceholder') }, { name: 'reply_to_address', type: 'text', - placeholder: MailPoet.I18n.t('replyToAddressPlaceholder'), - defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.address : '' - }, + placeholder: MailPoet.I18n.t('replyToAddressPlaceholder') + } ] } ]; diff --git a/assets/js/src/newsletters/send/standard.jsx b/assets/js/src/newsletters/send/standard.jsx index 8350394bb3..63ad067b35 100644 --- a/assets/js/src/newsletters/send/standard.jsx +++ b/assets/js/src/newsletters/send/standard.jsx @@ -52,7 +52,6 @@ define( name: 'sender_name', type: 'text', placeholder: MailPoet.I18n.t('senderNamePlaceholder'), - defaultValue: (settings.sender !== undefined) ? settings.sender.name : '', validation: { 'data-parsley-required': true } @@ -61,7 +60,6 @@ define( name: 'sender_address', type: 'text', placeholder: MailPoet.I18n.t('senderAddressPlaceholder'), - defaultValue: (settings.sender !== undefined) ? settings.sender.address : '', validation: { 'data-parsley-required': true, 'data-parsley-type': 'email' @@ -78,15 +76,13 @@ define( { name: 'reply_to_name', type: 'text', - placeholder: MailPoet.I18n.t('replyToNamePlaceholder'), - defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.name : '', + placeholder: MailPoet.I18n.t('replyToNamePlaceholder') }, { name: 'reply_to_address', type: 'text', - placeholder: MailPoet.I18n.t('replyToAddressPlaceholder'), - defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.address : '' - }, + placeholder: MailPoet.I18n.t('replyToAddressPlaceholder') + } ] } ]; diff --git a/assets/js/src/newsletters/send/welcome.jsx b/assets/js/src/newsletters/send/welcome.jsx index b6fae0edbd..cb8940ceb8 100644 --- a/assets/js/src/newsletters/send/welcome.jsx +++ b/assets/js/src/newsletters/send/welcome.jsx @@ -36,7 +36,6 @@ define( name: 'sender_name', type: 'text', placeholder: MailPoet.I18n.t('senderNamePlaceholder'), - defaultValue: (settings.sender !== undefined) ? settings.sender.name : '', validation: { 'data-parsley-required': true } @@ -45,7 +44,6 @@ define( name: 'sender_address', type: 'text', placeholder: MailPoet.I18n.t('senderAddressPlaceholder'), - defaultValue: (settings.sender !== undefined) ? settings.sender.address : '', validation: { 'data-parsley-required': true, 'data-parsley-type': 'email' @@ -62,15 +60,13 @@ define( { name: 'reply_to_name', type: 'text', - placeholder: MailPoet.I18n.t('replyToNamePlaceholder'), - defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.name : '', + placeholder: MailPoet.I18n.t('replyToNamePlaceholder') }, { name: 'reply_to_address', type: 'text', - placeholder: MailPoet.I18n.t('replyToAddressPlaceholder'), - defaultValue: (settings.reply_to !== undefined) ? settings.reply_to.address : '' - }, + placeholder: MailPoet.I18n.t('replyToAddressPlaceholder') + } ] } ]; diff --git a/assets/js/src/newsletters/templates.jsx b/assets/js/src/newsletters/templates.jsx index cfe7a67be5..87c50c0fe1 100644 --- a/assets/js/src/newsletters/templates.jsx +++ b/assets/js/src/newsletters/templates.jsx @@ -80,9 +80,6 @@ define( }); var NewsletterTemplates = React.createClass({ - mixins: [ - Router.History - ], getInitialState: function() { return { loading: false, diff --git a/assets/js/src/newsletters/types.jsx b/assets/js/src/newsletters/types.jsx index b4f5deb5f6..a59ab353da 100644 --- a/assets/js/src/newsletters/types.jsx +++ b/assets/js/src/newsletters/types.jsx @@ -12,12 +12,12 @@ define( Breadcrumb ) { var NewsletterTypes = React.createClass({ - mixins: [ - Router.History - ], + contextTypes: { + router: React.PropTypes.object.isRequired + }, setupNewsletter: function(type) { if(type !== undefined) { - this.history.pushState(null, `/new/${type}`); + this.context.router.push(`/new/${type}`); } }, createNewsletter: function(type) { @@ -30,7 +30,7 @@ define( } }).done(function(response) { if(response.result && response.newsletter.id) { - this.history.pushState(null, `/template/${response.newsletter.id}`); + this.context.router.push(`/template/${response.newsletter.id}`); } else { if(response.errors.length > 0) { response.errors.map(function(error) { diff --git a/assets/js/src/newsletters/types/notification/notification.jsx b/assets/js/src/newsletters/types/notification/notification.jsx index e19708fbad..1322c1dc36 100644 --- a/assets/js/src/newsletters/types/notification/notification.jsx +++ b/assets/js/src/newsletters/types/notification/notification.jsx @@ -24,9 +24,9 @@ define( }; var NewsletterNotification = React.createClass({ - mixins: [ - Router.History - ], + contextTypes: { + router: React.PropTypes.object.isRequired + }, getInitialState: function() { return { options: { @@ -64,7 +64,7 @@ define( }.bind(this)); }, showTemplateSelection: function(newsletterId) { - this.history.pushState(null, `/template/${newsletterId}`); + this.context.router.push(`/template/${newsletterId}`); }, render: function() { return ( diff --git a/assets/js/src/newsletters/types/standard.jsx b/assets/js/src/newsletters/types/standard.jsx index c5c532dcc0..e71b41bea1 100644 --- a/assets/js/src/newsletters/types/standard.jsx +++ b/assets/js/src/newsletters/types/standard.jsx @@ -13,11 +13,11 @@ define( ) { var NewsletterStandard = React.createClass({ - mixins: [ - Router.History - ], + contextTypes: { + router: React.PropTypes.object.isRequired + }, showTemplateSelection: function(newsletterId) { - this.history.pushState(null, `/template/${newsletterId}`); + this.context.router.push(`/template/${newsletterId}`); }, componentDidMount: function() { // No options for this type, create a newsletter upon mounting diff --git a/assets/js/src/newsletters/types/welcome/scheduling.jsx b/assets/js/src/newsletters/types/welcome/scheduling.jsx index 249e8ea0e2..1589514dee 100644 --- a/assets/js/src/newsletters/types/welcome/scheduling.jsx +++ b/assets/js/src/newsletters/types/welcome/scheduling.jsx @@ -65,6 +65,9 @@ define( }; var WelcomeScheduling = React.createClass({ + contextTypes: { + router: React.PropTypes.object.isRequired + }, _getCurrentValue: function() { return this.props.item[this.props.field.name] || {}; }, @@ -131,7 +134,7 @@ define( }.bind(this)); }, showTemplateSelection: function(newsletterId) { - this.history.pushState(null, `/template/${newsletterId}`); + this.context.router.push(`/template/${newsletterId}`); }, render: function() { var value = this._getCurrentValue(), diff --git a/assets/js/src/newsletters/types/welcome/welcome.jsx b/assets/js/src/newsletters/types/welcome/welcome.jsx index d857b54493..34de296d1e 100644 --- a/assets/js/src/newsletters/types/welcome/welcome.jsx +++ b/assets/js/src/newsletters/types/welcome/welcome.jsx @@ -31,9 +31,9 @@ define( } var NewsletterWelcome = React.createClass({ - mixins: [ - Router.History - ], + contextTypes: { + router: React.PropTypes.object.isRequired + }, getInitialState: function() { return { options: { @@ -71,7 +71,7 @@ define( }.bind(this)); }, showTemplateSelection: function(newsletterId) { - this.history.pushState(null, `/template/${newsletterId}`); + this.context.router.push(`/template/${newsletterId}`); }, render: function() { return ( diff --git a/assets/js/src/segments/form.jsx b/assets/js/src/segments/form.jsx index d87abfaf4e..d2cdd7e5ad 100644 --- a/assets/js/src/segments/form.jsx +++ b/assets/js/src/segments/form.jsx @@ -1,13 +1,11 @@ define( [ 'react', - 'react-router', 'mailpoet', 'form/form.jsx' ], function( React, - Router, MailPoet, Form ) { @@ -21,7 +19,8 @@ define( { name: 'description', label: MailPoet.I18n.t('description'), - type: 'textarea' + type: 'textarea', + tip: MailPoet.I18n.t('segmentDescriptionTip') } ]; @@ -35,9 +34,6 @@ define( }; const SegmentForm = React.createClass({ - mixins: [ - Router.History - ], render: function() { return (
diff --git a/assets/js/src/segments/list.jsx b/assets/js/src/segments/list.jsx index bcb5f1fe95..305860bf96 100644 --- a/assets/js/src/segments/list.jsx +++ b/assets/js/src/segments/list.jsx @@ -159,9 +159,6 @@ const item_actions = [ } ]; -const bulk_actions = [ -]; - const SegmentList = React.createClass({ renderItem: function(segment, actions) { var rowClasses = classNames( @@ -211,7 +208,6 @@ const SegmentList = React.createClass({ endpoint="segments" onRenderItem={ this.renderItem } columns={ columns } - bulk_actions={ bulk_actions } item_actions={ item_actions } />
diff --git a/assets/js/src/segments/segments.jsx b/assets/js/src/segments/segments.jsx index 1209b1da3a..7b35f2584c 100644 --- a/assets/js/src/segments/segments.jsx +++ b/assets/js/src/segments/segments.jsx @@ -1,11 +1,11 @@ import React from 'react' import ReactDOM from 'react-dom' -import { Router, Route, IndexRoute, Link } from 'react-router' +import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router' +import { createHashHistory } from 'history' import SegmentList from 'segments/list.jsx' import SegmentForm from 'segments/form.jsx' -import createHashHistory from 'history/lib/createHashHistory' -let history = createHashHistory({ queryKey: false }) +const history = useRouterHistory(createHashHistory)({ queryKey: false }); const App = React.createClass({ render() { @@ -13,7 +13,7 @@ const App = React.createClass({ } }); -let container = document.getElementById('segments_container'); +const container = document.getElementById('segments_container'); if(container) { ReactDOM.render(( diff --git a/assets/js/src/subscribers/form.jsx b/assets/js/src/subscribers/form.jsx index 11d7982b6c..704158b980 100644 --- a/assets/js/src/subscribers/form.jsx +++ b/assets/js/src/subscribers/form.jsx @@ -115,9 +115,6 @@ define( var Link = Router.Link; var SubscriberForm = React.createClass({ - mixins: [ - Router.History - ], render: function() { return (
diff --git a/assets/js/src/subscribers/subscribers.jsx b/assets/js/src/subscribers/subscribers.jsx index 00e94e0a02..7f9e232db4 100644 --- a/assets/js/src/subscribers/subscribers.jsx +++ b/assets/js/src/subscribers/subscribers.jsx @@ -1,11 +1,11 @@ import React from 'react' import ReactDOM from 'react-dom' -import { Router, Route, IndexRoute, Link } from 'react-router' +import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router' +import { createHashHistory } from 'history' import SubscriberList from 'subscribers/list.jsx' import SubscriberForm from 'subscribers/form.jsx' -import createHashHistory from 'history/lib/createHashHistory' -const history = createHashHistory({ queryKey: false }) +const history = useRouterHistory(createHashHistory)({ queryKey: false }); const App = React.createClass({ render() { diff --git a/lib/Mailer/Mailer.php b/lib/Mailer/Mailer.php index 909e1999a0..5435f13710 100644 --- a/lib/Mailer/Mailer.php +++ b/lib/Mailer/Mailer.php @@ -100,9 +100,9 @@ class Mailer { } function getSender($sender = false) { - if(!$sender) { - $sender = Setting::getValue('sender', null); - if(!$sender['address']) throw new \Exception(__('Sender name and email are not configured.')); + if(empty($sender)) { + $sender = Setting::getValue('sender', array()); + if(empty($sender['address'])) throw new \Exception(__('Sender name and email are not configured.')); } return array( 'from_name' => $sender['name'], diff --git a/lib/Models/Newsletter.php b/lib/Models/Newsletter.php index cba5ff0c44..78673900be 100644 --- a/lib/Models/Newsletter.php +++ b/lib/Models/Newsletter.php @@ -219,6 +219,37 @@ class Newsletter extends Model { if($newsletter === false) { $newsletter = self::create(); + + // set default sender based on settings + if(empty($data['sender'])) { + $sender = Setting::getValue('sender', array()); + $data['sender_name'] = ( + !empty($sender['name']) + ? $sender['name'] + : '' + ); + $data['sender_address'] = ( + !empty($sender['address']) + ? $sender['address'] + : '' + ); + } + + // set default reply_to based on settings + if(empty($data['reply_to'])) { + $reply_to = Setting::getValue('reply_to', array()); + $data['reply_to_name'] = ( + !empty($reply_to['name']) + ? $reply_to['name'] + : '' + ); + $data['reply_to_address'] = ( + !empty($reply_to['address']) + ? $reply_to['address'] + : '' + ); + } + $newsletter->hydrate($data); } else { unset($data['id']); diff --git a/package.json b/package.json index c654df3355..39d9bce4ed 100644 --- a/package.json +++ b/package.json @@ -24,12 +24,12 @@ "napa": "^1.2.0", "papaparse": "4.1.1", "parsleyjs": "^2.1.2", - "react": "0.14.3", - "react-dom": "0.14.3", - "react-infinity": "1.2.2", - "react-prefixr": "0.1.0", - "react-router": "1.0.2", - "react-waypoint": "1.0.4", + "react": "latest", + "react-dom": "latest", + "react-infinity": "latest", + "react-prefixr": "latest", + "react-router": "latest", + "react-waypoint": "latest", "select2": "^4.0.0", "spectrum-colorpicker": "^1.6.2", "tinymce": "4.1.10", diff --git a/views/segments.html b/views/segments.html index a0c26893da..28af1957e5 100644 --- a/views/segments.html +++ b/views/segments.html @@ -37,8 +37,7 @@ 'restore': __('Restore'), 'deletePermanently': __('Delete Permanently'), 'save': __('Save'), - - 'numberOfItems': __('%$1d items'), + 'segmentDescriptionTip': __('For your own use and never shown to your subscribers.') }) %> <% endblock %>