1
0
Fork 0
mirror of https://github.com/TryGhost/Ghost-Admin.git synced 2023-12-14 02:33:04 +01:00

🐛 Fixed editor showing incorrect domain and "unsaved changes" modal for relative links

no issue

- convert relative links to absolute based on the configured blog url when displaying URLs in the link toolbar and when manually setting a relative link
  - converting to absolute in the editor prevents the in-memory mobiledoc getting out of sync with the server response when it converts relative urls to absolute
This commit is contained in:
Kevin Ansfield 2019-10-29 11:57:29 +00:00
parent 3b43152f75
commit 90fc381767
3 changed files with 44 additions and 3 deletions

View file

@ -1,10 +1,12 @@
import Component from '@ember/component';
import layout from '../templates/components/koenig-link-input';
import relativeToAbsolute from '../lib/relative-to-absolute';
import {TOOLBAR_MARGIN} from './koenig-toolbar';
import {computed} from '@ember/object';
import {getLinkMarkupFromRange} from '../utils/markup-utils';
import {htmlSafe} from '@ember/string';
import {run} from '@ember/runloop';
import {inject as service} from '@ember/service';
// pixels that should be added to the `left` property of the tick adjustment styles
// TODO: handle via CSS?
@ -26,6 +28,8 @@ function getScrollParent(node) {
}
export default Component.extend({
config: service(),
layout,
attributeBindings: ['style'],
@ -120,7 +124,8 @@ export default Component.extend({
// prevent Enter from triggering in the editor and removing text
event.preventDefault();
let href = this.href;
let href = relativeToAbsolute(this.href, this.config.get('blogUrl'));
this.set('href', href);
// create a single editor runloop here so that we don't get
// separate remove and replace ops pushed onto the undo stack

View file

@ -1,10 +1,11 @@
import Component from '@ember/component';
import layout from '../templates/components/koenig-link-toolbar';
// import {TOOLBAR_MARGIN} from './koenig-toolbar';
import relativeToAbsolute from '../lib/relative-to-absolute';
import {computed} from '@ember/object';
import {getEventTargetMatchingTag} from 'mobiledoc-kit/utils/element-utils';
import {htmlSafe} from '@ember/string';
import {run} from '@ember/runloop';
import {inject as service} from '@ember/service';
// gap between link and toolbar bottom
const TOOLBAR_MARGIN = 8;
@ -17,6 +18,8 @@ const TOOLBAR_PADDING = 12;
const DELAY = 120;
export default Component.extend({
config: service(),
layout,
attributeBindings: ['style'],
@ -163,8 +166,12 @@ export default Component.extend({
},
_showToolbar(target) {
// extract the href attribute value and convert it to absolute based
// on the configured blog url
this._target = target;
this.set('url', target.href);
let href = target.getAttribute('href');
let blogUrl = this.config.get('blogUrl');
this.set('url', relativeToAbsolute(href, blogUrl));
this.set('showToolbar', true);
run.schedule('afterRender', this, function () {
this._positionToolbar(target);

View file

@ -0,0 +1,29 @@
export default function relativeToAbsolute(path, rootUrl) {
// if URL is absolute return it as-is
try {
const parsed = new URL(path, 'http://relative');
if (parsed.origin !== 'http://relative') {
return path;
}
// Do not convert protocol relative URLs
if (path.lastIndexOf('//', 0) === 0) {
return path;
}
} catch (e) {
return path;
}
// return the path as-is if it's a pure hash param or not root-relative
if (!path.startsWith('/')) {
return path;
}
// force root to always have a trailing-slash for consistent behaviour
if (!rootUrl.endsWith('/')) {
rootUrl = `${rootUrl}/`;
}
return new URL(path, rootUrl).toString();
}