diff --git a/client/src/components/Draftail/blocks/__snapshots__/EmbedBlock.test.js.snap b/client/src/components/Draftail/blocks/__snapshots__/EmbedBlock.test.js.snap index 4424fe6728..2926fdfa51 100644 --- a/client/src/components/Draftail/blocks/__snapshots__/EmbedBlock.test.js.snap +++ b/client/src/components/Draftail/blocks/__snapshots__/EmbedBlock.test.js.snap @@ -14,7 +14,7 @@ exports[`EmbedBlock renders 1`] = ` src="http://www.example.com/example.png" > diff --git a/client/src/components/Draftail/blocks/__snapshots__/ImageBlock.test.js.snap b/client/src/components/Draftail/blocks/__snapshots__/ImageBlock.test.js.snap index 7a16f56cb5..62fc6abf4e 100644 --- a/client/src/components/Draftail/blocks/__snapshots__/ImageBlock.test.js.snap +++ b/client/src/components/Draftail/blocks/__snapshots__/ImageBlock.test.js.snap @@ -23,18 +23,19 @@ exports[`ImageBlock alt 1`] = ` Alt text
@@ -64,18 +65,19 @@ exports[`ImageBlock renders 1`] = ` Alt text diff --git a/client/src/components/Draftail/decorators/Link.js b/client/src/components/Draftail/decorators/Link.js index cd22c80f31..60fe054f35 100644 --- a/client/src/components/Draftail/decorators/Link.js +++ b/client/src/components/Draftail/decorators/Link.js @@ -10,28 +10,23 @@ const getDomainName = url => url.replace(/(^\w+:|^)\/\//, '').split('/')[0]; const Link = props => { const { entityKey, contentState } = props; - const { linkType, url } = contentState.getEntity(entityKey).getData(); + const data = contentState.getEntity(entityKey).getData(); let icon; let label; let tooltipURL; - switch (linkType) { - case 'email': + if (data.id) { + icon = 'link'; + tooltipURL = data.url; + label = data.url; + } else if (data.url.startsWith('mailto:')) { icon = 'mail'; - tooltipURL = getEmailAddress(url); - label = url; - break; - case 'page': + tooltipURL = getEmailAddress(data.url); + label = data.url; + } else { icon = 'link'; - tooltipURL = url; - label = url; - break; - case 'external': - default: - icon = 'link'; - tooltipURL = url; - label = getDomainName(url); - break; + tooltipURL = data.url; + label = getDomainName(data.url); } return ( diff --git a/client/src/components/Draftail/sources/LinkSource.js b/client/src/components/Draftail/sources/LinkSource.js index d46a9154e0..a01202c2b3 100644 --- a/client/src/components/Draftail/sources/LinkSource.js +++ b/client/src/components/Draftail/sources/LinkSource.js @@ -23,28 +23,18 @@ const buildInitialUrl = (entity, openAtParentId, canChooseRoot, pageTypes) => { }; if (entity) { - let data = entity.getData(); + const data = entity.getData(); - if (typeof data === 'string') { - data = { url: data, linkType: 'external', title: '' }; - } + // urlParams.link_text = data.title; - urlParams.link_text = data.title; - - switch (data.linkType) { - case 'page': + if (data.id) { url = ` ${pageChooser}${data.parentId}/`; - break; - - case 'email': + } else if (data.url.startsWith('mailto:')) { url = emailLinkChooser; urlParams.link_url = data.url.replace('mailto:', ''); - break; - - default: + } else { url = externalLinkChooser; urlParams.link_url = data.url; - break; } } @@ -57,25 +47,17 @@ class LinkSource extends ModalSource { this.parseData = this.parseData.bind(this); } - // Plaster over more Wagtail internals. - parseData(pageData) { - const data = Object.assign({}, pageData); + parseData(data) { + const parsedData = { + url: data.url, + }; if (data.id) { - data.linkType = 'page'; - } else if (data.url.indexOf('mailto:') === 0) { - data.linkType = 'email'; - } else { - data.linkType = 'external'; + parsedData.id = data.id; + parsedData.parentId = data.parentId; } - // We do not want each link to have the page's title as an attr. - // nor links to have the link URL as a title. - if (data.linkType === 'page' || data.url.replace('mailto:', '') === data.title) { - delete data.title; - } - - this.onConfirm(data); + this.onConfirm(parsedData); } componentDidMount() { diff --git a/wagtail/admin/rich_text/converters/contentstate.py b/wagtail/admin/rich_text/converters/contentstate.py index c28bf746f3..1e3d5c2ea0 100644 --- a/wagtail/admin/rich_text/converters/contentstate.py +++ b/wagtail/admin/rich_text/converters/contentstate.py @@ -16,11 +16,11 @@ def link_entity(props): """ internal page link """ - link_type = props.get('linkType', '') + id_ = props.get('id') link_props = {} - if link_type == 'page': - link_props['linktype'] = link_type + if id_ is not None: + link_props['linktype'] = 'page' link_props['id'] = props.get('id') else: link_props['href'] = props.get('url') diff --git a/wagtail/admin/rich_text/converters/html_to_contentstate.py b/wagtail/admin/rich_text/converters/html_to_contentstate.py index eb0cce7895..f04b100eec 100644 --- a/wagtail/admin/rich_text/converters/html_to_contentstate.py +++ b/wagtail/admin/rich_text/converters/html_to_contentstate.py @@ -148,7 +148,7 @@ class LinkElementHandler(object): class ExternalLinkElementHandler(LinkElementHandler): def get_attribute_data(self, attrs): - return {'linkType': 'external', 'url': attrs['href']} + return {'url': attrs['href']} class PageLinkElementHandler(LinkElementHandler): @@ -159,10 +159,8 @@ class PageLinkElementHandler(LinkElementHandler): return {} data = { - 'linkType': 'page', 'id': page.id, 'url': page.url, - 'title': page.title, } parent_page = page.get_parent() diff --git a/wagtail/admin/wagtail_hooks.py b/wagtail/admin/wagtail_hooks.py index a520cb9408..eafe0a56fb 100644 --- a/wagtail/admin/wagtail_hooks.py +++ b/wagtail/admin/wagtail_hooks.py @@ -401,6 +401,13 @@ def register_core_features(features): 'icon': 'link', 'source': 'LinkSource', 'decorator': 'Link', + # We want to enforce constraints on which links can be pasted into rich text. + # Keep only the attributes Wagtail needs. + 'attributes': ['url', 'id', 'parentId'], + # Keep only links which are not anchor references. + 'whitelist': { + 'href': '^(?!#)', + } }) ) features.register_converter_rule('contentstate', 'link', {