mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-18 02:21:47 -05:00
Refactored facebook/twitter URL inputs
refs https://github.com/TryGhost/Ghost/issues/14101 Twitter/facebook URL validation doesn't follow our typical validation and was duplicated across multiple screens making the controllers unnecessarily complex. - extracted url input fields and their validation into separate components - uses tracked scratch values so that the input field values can reset to the saved value on save - twitter/facebook URL inputs are different to our other inputs because invalid values won't prevent saving, instead they are reset to their previous value on save - added `this.validate()` call after a successful save in `settings` service so the service and underlying model validations are both in sync (fixes validation error sticking around after saving with invalid twitter/facebook values that have been reset)
This commit is contained in:
parent
5106643871
commit
c77c150745
10 changed files with 234 additions and 272 deletions
|
@ -887,3 +887,17 @@ remove|ember-template-lint|no-action|125|88|125|88|ea7c6e414cc202b6e4049eae4f60e
|
|||
remove|ember-template-lint|no-action|129|35|129|35|ea7c6e414cc202b6e4049eae4f60eb0829bd3ff0|1662681600000|1673053200000|1678237200000|app/templates/settings/staff/user.hbs
|
||||
remove|ember-template-lint|no-action|136|42|136|42|7a2a7a1b2159d811b310a9b89817108ddff9df88|1662681600000|1673053200000|1678237200000|app/templates/settings/staff/user.hbs
|
||||
remove|ember-template-lint|no-action|140|35|140|35|7a2a7a1b2159d811b310a9b89817108ddff9df88|1662681600000|1673053200000|1678237200000|app/templates/settings/staff/user.hbs
|
||||
remove|ember-template-lint|no-action|361|43|361|43|1f32c13702a8b46410e9e10f9988fa2e0df41968|1662681600000|1673053200000|1678237200000|app/templates/settings/general.hbs
|
||||
remove|ember-template-lint|no-action|362|47|362|47|69b8d823159491abd67494eba728616ac0a928a5|1662681600000|1673053200000|1678237200000|app/templates/settings/general.hbs
|
||||
remove|ember-template-lint|no-action|374|43|374|43|226e659be4c2c10c0e5fbebb40f712f3016c9b90|1662681600000|1673053200000|1678237200000|app/templates/settings/general.hbs
|
||||
remove|ember-template-lint|no-action|375|47|375|47|d746c5532ce38d23d8537195a3afa6ce7235f577|1662681600000|1673053200000|1678237200000|app/templates/settings/general.hbs
|
||||
remove|ember-template-lint|no-passed-in-event-handlers|361|36|361|36|c14e20b2b090706f9af9fa416c4300c06e206894|1662681600000|1673053200000|1678237200000|app/templates/settings/general.hbs
|
||||
remove|ember-template-lint|no-passed-in-event-handlers|374|36|374|36|e286f50c92a17a31581207e4c65054f146cbd533|1662681600000|1673053200000|1678237200000|app/templates/settings/general.hbs
|
||||
remove|ember-template-lint|no-action|122|82|122|82|e2e24a0e1efe19ed982cc8140248570c03eee7b9|1662681600000|1673053200000|1678237200000|app/templates/settings/staff/user.hbs
|
||||
remove|ember-template-lint|no-action|262|39|262|39|1f32c13702a8b46410e9e10f9988fa2e0df41968|1662681600000|1673053200000|1678237200000|app/templates/settings/staff/user.hbs
|
||||
remove|ember-template-lint|no-action|263|43|263|43|69b8d823159491abd67494eba728616ac0a928a5|1662681600000|1673053200000|1678237200000|app/templates/settings/staff/user.hbs
|
||||
remove|ember-template-lint|no-action|279|39|279|39|226e659be4c2c10c0e5fbebb40f712f3016c9b90|1662681600000|1673053200000|1678237200000|app/templates/settings/staff/user.hbs
|
||||
remove|ember-template-lint|no-action|280|43|280|43|d746c5532ce38d23d8537195a3afa6ce7235f577|1662681600000|1673053200000|1678237200000|app/templates/settings/staff/user.hbs
|
||||
remove|ember-template-lint|no-action|398|106|398|106|d2028f094665a3702bbea21159b1c12237c94bc9|1662681600000|1673053200000|1678237200000|app/templates/settings/staff/user.hbs
|
||||
remove|ember-template-lint|no-passed-in-event-handlers|262|32|262|32|c14e20b2b090706f9af9fa416c4300c06e206894|1662681600000|1673053200000|1678237200000|app/templates/settings/staff/user.hbs
|
||||
remove|ember-template-lint|no-passed-in-event-handlers|279|32|279|32|e286f50c92a17a31581207e4c65054f146cbd533|1662681600000|1673053200000|1678237200000|app/templates/settings/staff/user.hbs
|
||||
|
|
10
ghost/admin/app/components/gh-facebook-url-input.hbs
Normal file
10
ghost/admin/app/components/gh-facebook-url-input.hbs
Normal file
|
@ -0,0 +1,10 @@
|
|||
<input
|
||||
type="url"
|
||||
class="gh-input"
|
||||
placeholder="https://www.facebook.com/username"
|
||||
value={{this.value}}
|
||||
{{on "input" this.setScratchValue}}
|
||||
{{on "blur" this.setFacebookUrl}}
|
||||
data-test-facebook-input
|
||||
...attributes
|
||||
/>
|
68
ghost/admin/app/components/gh-facebook-url-input.js
Normal file
68
ghost/admin/app/components/gh-facebook-url-input.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
import Component from '@glimmer/component';
|
||||
import validator from 'validator';
|
||||
import {action} from '@ember/object';
|
||||
import {get, set} from '@ember/object';
|
||||
|
||||
export default class GhFacebookUrlInput extends Component {
|
||||
// NOTE: `get` and `set` are required when reading/writing model properties
|
||||
// because we can be dealing with proxy objects such as the settings service
|
||||
get value() {
|
||||
const {model, modelProperty, scratchValue} = this.args;
|
||||
return scratchValue || get(model, modelProperty);
|
||||
}
|
||||
|
||||
@action
|
||||
setScratchValue(event) {
|
||||
this.args.setScratchValue?.(event.target.value);
|
||||
}
|
||||
|
||||
@action
|
||||
setFacebookUrl(event) {
|
||||
const {model, modelProperty} = this.args;
|
||||
|
||||
let newUrl = event.target.value;
|
||||
|
||||
// reset errors and validation
|
||||
model.errors.remove('facebook');
|
||||
model.hasValidated.removeObject('facebook');
|
||||
|
||||
if (!newUrl) {
|
||||
// Clear out the Facebook url
|
||||
set(model, modelProperty, null);
|
||||
this.args.setScratchValue?.(null);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// strip any facebook URLs out
|
||||
newUrl = newUrl.replace(/(https?:\/\/)?(www\.)?facebook\.com/i, '');
|
||||
|
||||
// don't allow any non-facebook urls
|
||||
if (newUrl.match(/^(http|\/\/)/i)) {
|
||||
throw 'invalid url';
|
||||
}
|
||||
|
||||
// strip leading / if we have one then concat to full facebook URL
|
||||
newUrl = newUrl.replace(/^\//, '');
|
||||
newUrl = `https://www.facebook.com/${newUrl}`;
|
||||
|
||||
// don't allow URL if it's not valid
|
||||
if (!validator.isURL(newUrl)) {
|
||||
throw 'invalid url';
|
||||
}
|
||||
|
||||
set(model, modelProperty, newUrl);
|
||||
this.args.setScratchValue?.(null);
|
||||
} catch (e) {
|
||||
if (e === 'invalid url') {
|
||||
const message = 'The URL must be in a format like https://www.facebook.com/yourPage';
|
||||
model.errors.add('facebook', message);
|
||||
return;
|
||||
}
|
||||
|
||||
throw e;
|
||||
} finally {
|
||||
model.hasValidated.pushObject('facebook');
|
||||
}
|
||||
}
|
||||
}
|
10
ghost/admin/app/components/gh-twitter-url-input.hbs
Normal file
10
ghost/admin/app/components/gh-twitter-url-input.hbs
Normal file
|
@ -0,0 +1,10 @@
|
|||
<input
|
||||
type="url"
|
||||
class="gh-input"
|
||||
placeholder="https://twitter.com/username"
|
||||
value={{this.value}}
|
||||
{{on "input" this.setScratchValue}}
|
||||
{{on "blur" this.setTwitterUrl}}
|
||||
data-test-twitter-input
|
||||
...attributes
|
||||
/>
|
66
ghost/admin/app/components/gh-twitter-url-input.js
Normal file
66
ghost/admin/app/components/gh-twitter-url-input.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
import {get, set} from '@ember/object';
|
||||
|
||||
export default class GhTwitterUrlInput extends Component {
|
||||
// NOTE: `get` and `set` are required when reading/writing model properties
|
||||
// because we can be dealing with proxy objects such as the settings service
|
||||
get value() {
|
||||
const {model, modelProperty, scratchValue} = this.args;
|
||||
return scratchValue || get(model, modelProperty);
|
||||
}
|
||||
|
||||
@action
|
||||
setScratchValue(event) {
|
||||
this.args.setScratchValue?.(event.target.value);
|
||||
}
|
||||
|
||||
@action
|
||||
setTwitterUrl(event) {
|
||||
const {model, modelProperty} = this.args;
|
||||
|
||||
const newUrl = event.target.value;
|
||||
|
||||
// reset errors and validation
|
||||
model.errors.remove(modelProperty);
|
||||
model.hasValidated.removeObject(modelProperty);
|
||||
|
||||
if (!newUrl) {
|
||||
// Clear out the Twitter url
|
||||
set(model, modelProperty, '');
|
||||
this.args.setScratchValue?.(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newUrl.match(/(?:twitter\.com\/)(\S+)/) || newUrl.match(/([a-z\d.]+)/i)) {
|
||||
let username = [];
|
||||
|
||||
if (newUrl.match(/(?:twitter\.com\/)(\S+)/)) {
|
||||
[, username] = newUrl.match(/(?:twitter\.com\/)(\S+)/);
|
||||
} else {
|
||||
[username] = newUrl.match(/([^/]+)\/?$/mi);
|
||||
}
|
||||
|
||||
// check if username starts with http or www and show error if so
|
||||
if (username.match(/^(http|www)|(\/)/) || !username.match(/^[a-z\d._]{1,15}$/mi)) {
|
||||
const message = !username.match(/^[a-z\d._]{1,15}$/mi)
|
||||
? 'Your Username is not a valid Twitter Username'
|
||||
: 'The URL must be in a format like https://twitter.com/yourUsername';
|
||||
|
||||
model.errors.add(modelProperty, message);
|
||||
model.hasValidated.pushObject(modelProperty);
|
||||
return;
|
||||
}
|
||||
|
||||
set(model, modelProperty, `https://twitter.com/${username}`);
|
||||
this.args.setScratchValue?.(null);
|
||||
|
||||
model.hasValidated.pushObject(modelProperty);
|
||||
} else {
|
||||
const message = 'The URL must be in a format like https://twitter.com/yourUsername';
|
||||
model.errors.add(modelProperty, message);
|
||||
model.hasValidated.pushObject(modelProperty);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,12 +4,13 @@ import {inject as service} from '@ember/service';
|
|||
/* eslint-disable ghost/ember/alias-model-in-controller */
|
||||
import Controller from '@ember/controller';
|
||||
import generatePassword from 'ghost-admin/utils/password-generator';
|
||||
import validator from 'validator';
|
||||
import {
|
||||
IMAGE_EXTENSIONS,
|
||||
IMAGE_MIME_TYPES
|
||||
} from 'ghost-admin/components/gh-image-uploader';
|
||||
import {TrackedObject} from 'tracked-built-ins';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
function randomPassword() {
|
||||
let word = generatePassword(6);
|
||||
|
@ -28,11 +29,11 @@ export default class GeneralController extends Controller {
|
|||
@service frontend;
|
||||
@service ui;
|
||||
|
||||
@tracked scratchValues = new TrackedObject();
|
||||
|
||||
availableTimezones = null;
|
||||
imageExtensions = IMAGE_EXTENSIONS;
|
||||
imageMimeTypes = IMAGE_MIME_TYPES;
|
||||
_scratchFacebook = null;
|
||||
_scratchTwitter = null;
|
||||
|
||||
@computed('config.blogUrl', 'settings.publicHash')
|
||||
get privateRSSUrl() {
|
||||
|
@ -102,111 +103,12 @@ export default class GeneralController extends Controller {
|
|||
}
|
||||
|
||||
@action
|
||||
validateFacebookUrl() {
|
||||
let newUrl = this._scratchFacebook;
|
||||
let oldUrl = this.get('settings.facebook');
|
||||
let errMessage = '';
|
||||
|
||||
// reset errors and validation
|
||||
this.get('settings.errors').remove('facebook');
|
||||
this.get('settings.hasValidated').removeObject('facebook');
|
||||
|
||||
if (newUrl === '') {
|
||||
// Clear out the Facebook url
|
||||
this.set('settings.facebook', '');
|
||||
return;
|
||||
}
|
||||
|
||||
// _scratchFacebook will be null unless the user has input something
|
||||
if (!newUrl) {
|
||||
newUrl = oldUrl;
|
||||
}
|
||||
|
||||
try {
|
||||
// strip any facebook URLs out
|
||||
newUrl = newUrl.replace(/(https?:\/\/)?(www\.)?facebook\.com/i, '');
|
||||
|
||||
// don't allow any non-facebook urls
|
||||
if (newUrl.match(/^(http|\/\/)/i)) {
|
||||
throw 'invalid url';
|
||||
}
|
||||
|
||||
// strip leading / if we have one then concat to full facebook URL
|
||||
newUrl = newUrl.replace(/^\//, '');
|
||||
newUrl = `https://www.facebook.com/${newUrl}`;
|
||||
|
||||
// don't allow URL if it's not valid
|
||||
if (!validator.isURL(newUrl)) {
|
||||
throw 'invalid url';
|
||||
}
|
||||
|
||||
this.settings.set('facebook', newUrl);
|
||||
this.settings.notifyPropertyChange('facebook');
|
||||
} catch (e) {
|
||||
if (e === 'invalid url') {
|
||||
errMessage = 'The URL must be in a format like '
|
||||
+ 'https://www.facebook.com/yourPage';
|
||||
this.get('settings.errors').add('facebook', errMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
throw e;
|
||||
} finally {
|
||||
this.get('settings.hasValidated').pushObject('facebook');
|
||||
}
|
||||
setScratchValue(property, value) {
|
||||
this.scratchValues[property] = value;
|
||||
}
|
||||
|
||||
@action
|
||||
validateTwitterUrl() {
|
||||
let newUrl = this._scratchTwitter;
|
||||
let oldUrl = this.get('settings.twitter');
|
||||
let errMessage = '';
|
||||
|
||||
// reset errors and validation
|
||||
this.get('settings.errors').remove('twitter');
|
||||
this.get('settings.hasValidated').removeObject('twitter');
|
||||
|
||||
if (newUrl === '') {
|
||||
// Clear out the Twitter url
|
||||
this.set('settings.twitter', '');
|
||||
return;
|
||||
}
|
||||
|
||||
// _scratchTwitter will be null unless the user has input something
|
||||
if (!newUrl) {
|
||||
newUrl = oldUrl;
|
||||
}
|
||||
|
||||
if (newUrl.match(/(?:twitter\.com\/)(\S+)/) || newUrl.match(/([a-z\d.]+)/i)) {
|
||||
let username = [];
|
||||
|
||||
if (newUrl.match(/(?:twitter\.com\/)(\S+)/)) {
|
||||
[, username] = newUrl.match(/(?:twitter\.com\/)(\S+)/);
|
||||
} else {
|
||||
[username] = newUrl.match(/([^/]+)\/?$/mi);
|
||||
}
|
||||
|
||||
// check if username starts with http or www and show error if so
|
||||
if (username.match(/^(http|www)|(\/)/) || !username.match(/^[a-z\d._]{1,15}$/mi)) {
|
||||
errMessage = !username.match(/^[a-z\d._]{1,15}$/mi) ? 'Your Username is not a valid Twitter Username' : 'The URL must be in a format like https://twitter.com/yourUsername';
|
||||
|
||||
this.get('settings.errors').add('twitter', errMessage);
|
||||
this.get('settings.hasValidated').pushObject('twitter');
|
||||
return;
|
||||
}
|
||||
|
||||
newUrl = `https://twitter.com/${username}`;
|
||||
|
||||
this.settings.get('hasValidated').pushObject('twitter');
|
||||
this.settings.set('twitter', newUrl);
|
||||
this.settings.notifyPropertyChange('twitter');
|
||||
} else {
|
||||
errMessage = 'The URL must be in a format like '
|
||||
+ 'https://twitter.com/yourUsername';
|
||||
this.get('settings.errors').add('twitter', errMessage);
|
||||
this.get('settings.hasValidated').pushObject('twitter');
|
||||
return;
|
||||
}
|
||||
clearScratchValues() {
|
||||
this.scratchValues = new TrackedObject();
|
||||
}
|
||||
|
||||
_deleteTheme() {
|
||||
|
@ -221,25 +123,23 @@ export default class GeneralController extends Controller {
|
|||
});
|
||||
}
|
||||
|
||||
@task(function* () {
|
||||
@task
|
||||
*saveTask() {
|
||||
let notifications = this.notifications;
|
||||
let config = this.config;
|
||||
|
||||
if (this.settings.get('twitter') !== this._scratchTwitter) {
|
||||
this.send('validateTwitterUrl');
|
||||
}
|
||||
|
||||
if (this.settings.get('facebook') !== this._scratchFacebook) {
|
||||
this.send('validateFacebookUrl');
|
||||
}
|
||||
|
||||
try {
|
||||
let changedAttrs = this.settings.changedAttributes();
|
||||
let settings = yield this.settings.save();
|
||||
|
||||
this.clearScratchValues();
|
||||
|
||||
config.set('blogTitle', settings.get('title'));
|
||||
|
||||
if (changedAttrs.password) {
|
||||
this.frontend.loginIfNeeded();
|
||||
}
|
||||
|
||||
// this forces the document title to recompute after a blog title change
|
||||
this.ui.updateDocumentTitle();
|
||||
|
||||
|
@ -250,6 +150,5 @@ export default class GeneralController extends Controller {
|
|||
}
|
||||
throw error;
|
||||
}
|
||||
})
|
||||
saveTask;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,14 @@ import UploadImageModal from '../../../components/settings/staff/modals/upload-i
|
|||
import boundOneWay from 'ghost-admin/utils/bound-one-way';
|
||||
import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard';
|
||||
import isNumber from 'ghost-admin/utils/isNumber';
|
||||
import validator from 'validator';
|
||||
import windowProxy from 'ghost-admin/utils/window-proxy';
|
||||
import {TrackedObject} from 'tracked-built-ins';
|
||||
import {action, computed} from '@ember/object';
|
||||
import {alias, and, not, or, readOnly} from '@ember/object/computed';
|
||||
import {run} from '@ember/runloop';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task, taskGroup, timeout} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default Controller.extend({
|
||||
ajax: service(),
|
||||
|
@ -31,8 +32,13 @@ export default Controller.extend({
|
|||
personalToken: null,
|
||||
personalTokenRegenerated: false,
|
||||
dirtyAttributes: false,
|
||||
_scratchFacebook: null,
|
||||
_scratchTwitter: null,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.clearScratchValues();
|
||||
},
|
||||
|
||||
scratchValues: tracked(),
|
||||
|
||||
saveHandlers: taskGroup().enqueue(),
|
||||
|
||||
|
@ -85,117 +91,6 @@ export default Controller.extend({
|
|||
}),
|
||||
|
||||
actions: {
|
||||
validateFacebookUrl() {
|
||||
let newUrl = this._scratchFacebook;
|
||||
let oldUrl = this.get('user.facebook');
|
||||
let errMessage = '';
|
||||
|
||||
// reset errors and validation
|
||||
this.get('user.errors').remove('facebook');
|
||||
this.get('user.hasValidated').removeObject('facebook');
|
||||
|
||||
if (newUrl === '') {
|
||||
// Clear out the Facebook url
|
||||
this.set('user.facebook', '');
|
||||
return;
|
||||
}
|
||||
|
||||
// _scratchFacebook will be null unless the user has input something
|
||||
if (!newUrl) {
|
||||
newUrl = oldUrl;
|
||||
}
|
||||
|
||||
try {
|
||||
// strip any facebook URLs out
|
||||
newUrl = newUrl.replace(/(https?:\/\/)?(www\.)?facebook\.com/i, '');
|
||||
|
||||
// don't allow any non-facebook urls
|
||||
if (newUrl.match(/^(http|\/\/)/i)) {
|
||||
throw 'invalid url';
|
||||
}
|
||||
|
||||
// strip leading / if we have one then concat to full facebook URL
|
||||
newUrl = newUrl.replace(/^\//, '');
|
||||
newUrl = `https://www.facebook.com/${newUrl}`;
|
||||
|
||||
// don't allow URL if it's not valid
|
||||
if (!validator.isURL(newUrl)) {
|
||||
throw 'invalid url';
|
||||
}
|
||||
|
||||
this.set('user.facebook', '');
|
||||
run.schedule('afterRender', this, function () {
|
||||
this.set('user.facebook', newUrl);
|
||||
});
|
||||
} catch (e) {
|
||||
if (e === 'invalid url') {
|
||||
errMessage = 'The URL must be in a format like '
|
||||
+ 'https://www.facebook.com/yourPage';
|
||||
this.get('user.errors').add('facebook', errMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
throw e;
|
||||
} finally {
|
||||
this.get('user.hasValidated').pushObject('facebook');
|
||||
}
|
||||
},
|
||||
|
||||
validateTwitterUrl() {
|
||||
let newUrl = this._scratchTwitter;
|
||||
let oldUrl = this.get('user.twitter');
|
||||
let errMessage = '';
|
||||
|
||||
// reset errors and validation
|
||||
this.get('user.errors').remove('twitter');
|
||||
this.get('user.hasValidated').removeObject('twitter');
|
||||
|
||||
if (newUrl === '') {
|
||||
// Clear out the Twitter url
|
||||
this.set('user.twitter', '');
|
||||
return;
|
||||
}
|
||||
|
||||
// _scratchTwitter will be null unless the user has input something
|
||||
if (!newUrl) {
|
||||
newUrl = oldUrl;
|
||||
}
|
||||
|
||||
if (newUrl.match(/(?:twitter\.com\/)(\S+)/) || newUrl.match(/([a-z\d.]+)/i)) {
|
||||
let username = [];
|
||||
|
||||
if (newUrl.match(/(?:twitter\.com\/)(\S+)/)) {
|
||||
[, username] = newUrl.match(/(?:twitter\.com\/)(\S+)/);
|
||||
} else {
|
||||
[username] = newUrl.match(/([^/]+)\/?$/mi);
|
||||
}
|
||||
|
||||
// check if username starts with http or www and show error if so
|
||||
if (username.match(/^(http|www)|(\/)/) || !username.match(/^[a-z\d._]{1,15}$/mi)) {
|
||||
errMessage = !username.match(/^[a-z\d._]{1,15}$/mi) ? 'Your Username is not a valid Twitter Username' : 'The URL must be in a format like https://twitter.com/yourUsername';
|
||||
|
||||
this.get('user.errors').add('twitter', errMessage);
|
||||
this.get('user.hasValidated').pushObject('twitter');
|
||||
return;
|
||||
}
|
||||
|
||||
newUrl = `https://twitter.com/${username}`;
|
||||
|
||||
this.get('user.hasValidated').pushObject('twitter');
|
||||
|
||||
this.set('user.twitter', '');
|
||||
run.schedule('afterRender', this, function () {
|
||||
this.set('user.twitter', newUrl);
|
||||
});
|
||||
} else {
|
||||
errMessage = 'The URL must be in a format like '
|
||||
+ 'https://twitter.com/yourUsername';
|
||||
this.get('user.errors').add('twitter', errMessage);
|
||||
this.get('user.hasValidated').pushObject('twitter');
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: remove those mutation actions once we have better
|
||||
// inline validations that auto-clear errors on input
|
||||
updatePassword(password) {
|
||||
|
@ -285,6 +180,14 @@ export default Controller.extend({
|
|||
});
|
||||
}),
|
||||
|
||||
setScratchValue: action(function (property, value) {
|
||||
this.scratchValues[property] = value;
|
||||
}),
|
||||
|
||||
clearScratchValues() {
|
||||
this.scratchValues = new TrackedObject();
|
||||
},
|
||||
|
||||
reset: action(function () {
|
||||
this.user.rollbackAttributes();
|
||||
this.user.password = '';
|
||||
|
@ -292,6 +195,7 @@ export default Controller.extend({
|
|||
this.user.ne2Password = '';
|
||||
this.set('slugValue', this.user.slug);
|
||||
this.set('dirtyAttributes', false);
|
||||
this.clearScratchValues();
|
||||
}),
|
||||
|
||||
toggleCommentNotifications: action(function (event) {
|
||||
|
@ -366,7 +270,9 @@ export default Controller.extend({
|
|||
}
|
||||
|
||||
try {
|
||||
user = yield user.save({format: false});
|
||||
user = yield user.save();
|
||||
|
||||
this.clearScratchValues();
|
||||
|
||||
// If the user's slug has changed, change the URL and replace
|
||||
// the history so refresh and back button still work
|
||||
|
|
|
@ -63,6 +63,7 @@ export default class SettingsService extends Service.extend(_ProxyMixin, Validat
|
|||
}
|
||||
|
||||
await settings.save();
|
||||
await this.validate();
|
||||
this.set('settledIcon', settings.icon);
|
||||
return settings;
|
||||
}
|
||||
|
|
|
@ -359,30 +359,26 @@
|
|||
{{#liquid-if this.socialOpen}}
|
||||
<div class="gh-setting-content-extended">
|
||||
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="facebook">
|
||||
<GhTextInput
|
||||
@type="url"
|
||||
@placeholder="https://www.facebook.com/ghost"
|
||||
@autocorrect="off"
|
||||
@value={{readonly this.settings.facebook}}
|
||||
@input={{action (mut this._scratchFacebook) value="target.value"}}
|
||||
@focus-out={{action "validateFacebookUrl"}}
|
||||
data-test-facebook-input={{true}}
|
||||
<GhFacebookUrlInput
|
||||
aria-labelledby="facebook-url-label"
|
||||
@scratchValue={{this.scratchValues.facebook}}
|
||||
@setScratchValue={{fn this.setScratchValue "facebook"}}
|
||||
@model={{this.settings}}
|
||||
@modelProperty="facebook"
|
||||
/>
|
||||
<GhErrorMessage @errors={{this.settings.errors}} @property="facebook" data-test-facebook-error />
|
||||
<p>URL of your publication's Facebook Page</p>
|
||||
<p id="facebook-url-label">URL of your publication's Facebook Page</p>
|
||||
</GhFormGroup>
|
||||
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{this.settings.hasValidated}} @property="twitter">
|
||||
<GhTextInput
|
||||
@type="url"
|
||||
@placeholder="https://twitter.com/ghost"
|
||||
@autocorrect="off"
|
||||
@value={{readonly this.settings.twitter}}
|
||||
@input={{action (mut this._scratchTwitter) value="target.value"}}
|
||||
@focus-out={{action "validateTwitterUrl"}}
|
||||
data-test-twitter-input={{true}}
|
||||
<GhTwitterUrlInput
|
||||
aria-labelledby="twitter-url-label"
|
||||
@scratchValue={{this.scratchValues.twitter}}
|
||||
@setScratchValue={{fn this.setScratchValue "twitter"}}
|
||||
@model={{this.settings}}
|
||||
@modelProperty="twitter"
|
||||
/>
|
||||
<GhErrorMessage @errors={{this.settings.errors}} @property="twitter" data-test-twitter-error />
|
||||
<p>URL of your publication's Twitter profile</p>
|
||||
<p id="twitter-url-label">URL of your publication's Twitter profile</p>
|
||||
</GhFormGroup>
|
||||
</div>
|
||||
{{/liquid-if}}
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
{{!-- <div class="bg-"> --}}
|
||||
<section>
|
||||
<div class="gm-main view-container settings-user">
|
||||
<form class="user-profile" novalidate="novalidate" autocomplete="off" {{action (perform this.save) on="submit"}}>
|
||||
<form id="user-settings-form" class="user-profile" novalidate="novalidate" autocomplete="off" {{on "submit" (perform this.save)}}>
|
||||
|
||||
<figure class="user-cover" style={{background-image-style this.user.coverImageUrl}}>
|
||||
<button type="button" class="gh-btn gh-btn-default user-cover-edit" {{on "click" this.changeCoverImage}}><span>Change cover</span></button>
|
||||
|
@ -196,16 +196,12 @@
|
|||
|
||||
<GhFormGroup @errors={{this.user.errors}} @hasValidated={{this.user.hasValidated}} @property="facebook">
|
||||
<label for="user-facebook">Facebook profile</label>
|
||||
<GhTextInput
|
||||
@type="url"
|
||||
@placeholder="https://www.facebook.com/username"
|
||||
@autocorrect="off"
|
||||
@id="user-facebook"
|
||||
@name="user[facebook]"
|
||||
@value={{readonly this.user.facebook}}
|
||||
@input={{action (mut this._scratchFacebook) value="target.value"}}
|
||||
@focus-out={{action "validateFacebookUrl"}}
|
||||
data-test-facebook-input={{true}}
|
||||
<GhFacebookUrlInput
|
||||
id="user-facebook"
|
||||
@scratchValue={{this.scratchValues.facebook}}
|
||||
@setScratchValue={{fn this.setScratchValue "facebook"}}
|
||||
@model={{this.user}}
|
||||
@modelProperty="facebook"
|
||||
/>
|
||||
<GhErrorMessage @errors={{this.user.errors}} @property="facebook" data-test-error="user-facebook" />
|
||||
<p>URL of your personal Facebook Profile</p>
|
||||
|
@ -213,16 +209,12 @@
|
|||
|
||||
<GhFormGroup @errors={{this.user.errors}} @hasValidated={{this.user.hasValidated}} @property="twitter">
|
||||
<label for="user-twitter">Twitter profile</label>
|
||||
<GhTextInput
|
||||
@type="url"
|
||||
@placeholder="https://twitter.com/username"
|
||||
@autocorrect="off"
|
||||
@id="user-twitter"
|
||||
@name="user[twitter]"
|
||||
@value={{readonly this.user.twitter}}
|
||||
@input={{action (mut this._scratchTwitter) value="target.value"}}
|
||||
@focus-out={{action "validateTwitterUrl"}}
|
||||
data-test-twitter-input={{true}}
|
||||
<GhTwitterUrlInput
|
||||
id="user-twitter"
|
||||
@scratchValue={{this.scratchValues.twitter}}
|
||||
@setScratchValue={{fn this.setScratchValue "twitter"}}
|
||||
@model={{this.user}}
|
||||
@modelProperty="twitter"
|
||||
/>
|
||||
<GhErrorMessage @errors={{this.user.errors}} @property="twitter" data-test-error="user-twitter" />
|
||||
<p>URL of your personal Twitter profile</p>
|
||||
|
@ -339,7 +331,7 @@
|
|||
|
||||
{{!-- If an administrator is viewing Owner's profile then hide inputs for change password --}}
|
||||
{{#if this.canChangePassword}}
|
||||
<form id="password-reset" class="user-profile" novalidate="novalidate" autocomplete="off" {{action (perform this.user.saveNewPassword) on="submit"}}>
|
||||
<form id="password-reset" class="user-profile" novalidate="novalidate" autocomplete="off" {{on "submit" (perform this.user.saveNewPassword)}}>
|
||||
<div class="pa5">
|
||||
<fieldset class="user-details-form">
|
||||
{{#if this.isOwnProfile}}
|
||||
|
|
Loading…
Add table
Reference in a new issue