浏览代码

Highlight broken links to pages and documents in rich text. Fix #4802 (#4813)

Brady 6 年之前
父节点
当前提交
e77338f1a3

+ 1 - 0
CHANGELOG.txt

@@ -8,6 +8,7 @@ Changelog
  * Added more informative error message when `|richtext` filter is applied to a non-string value (mukesh5)
  * Automatic search indexing can now be disabled on a per-model basis via the `search_auto_update` attribute (Karl Hobley)
  * Improved diffing of StreamFields when comparing page revisions (Karl Hobley)
+ * Highlight broken links to pages and missing documents in rich text (Brady Moe)
  * Fix: Set `SERVER_PORT` to 443 in `Page.dummy_request()` for HTTPS sites (Sergey Fedoseev)
  * Fix: Include port number in `Host` header of `Page.dummy_request()` (Sergey Fedoseev)
  * Fix: Validation error messages in `InlinePanel` no longer count towards `max_num` when disabling the 'add' button (Todd Dembrey, Thibaud Colas)

+ 17 - 3
client/src/components/Draftail/decorators/Document.js

@@ -5,18 +5,32 @@ import Icon from '../../Icon/Icon';
 
 import TooltipEntity from '../decorators/TooltipEntity';
 
+import { STRINGS } from '../../../config/wagtailConfig';
+
 const documentIcon = <Icon name="doc-full" />;
+const missingDocumentIcon = <Icon name="warning" />;
 
 const Document = props => {
   const { entityKey, contentState } = props;
   const data = contentState.getEntity(entityKey).getData();
+  const url = data.url || null;
+  let icon;
+  let label;
+
+  if (!url) {
+    icon = missingDocumentIcon;
+    label = STRINGS.MISSING_DOCUMENT;
+  } else {
+    icon = documentIcon;
+    label = data.filename || '';
+  }
 
   return (
     <TooltipEntity
       {...props}
-      icon={documentIcon}
-      label={data.filename || ''}
-      url={data.url || ''}
+      icon={icon}
+      label={label}
+      url={url}
     />
   );
 };

+ 8 - 2
client/src/components/Draftail/decorators/Link.js

@@ -5,7 +5,10 @@ import Icon from '../../Icon/Icon';
 
 import TooltipEntity from '../decorators/TooltipEntity';
 
+import { STRINGS } from '../../../config/wagtailConfig';
+
 const LINK_ICON = <Icon name="link" />;
+const BROKEN_LINK_ICON = <Icon name="warning" />;
 const MAIL_ICON = <Icon name="mail" />;
 
 const getEmailAddress = mailto => mailto.replace('mailto:', '').split('?')[0];
@@ -13,11 +16,14 @@ const getDomainName = url => url.replace(/(^\w+:|^)\/\//, '').split('/')[0];
 
 // Determines how to display the link based on its type: page, mail, or external.
 export const getLinkAttributes = (data) => {
-  const url = data.url || '';
+  const url = data.url || null;
   let icon;
   let label;
 
-  if (data.id) {
+  if (!url) {
+    icon = BROKEN_LINK_ICON;
+    label = STRINGS.BROKEN_LINK;
+  } else if (data.id) {
     icon = LINK_ICON;
     label = url;
   } else if (url.startsWith('mailto:')) {

+ 1 - 1
client/src/components/Draftail/decorators/Link.test.js

@@ -64,7 +64,7 @@ describe('Link', () => {
     });
 
     it('no data', () => {
-      expect(getLinkAttributes({})).toMatchObject({ url: '' });
+      expect(getLinkAttributes({})).toMatchObject({ url: null, label: 'Broken link' });
     });
   });
 });

+ 5 - 1
client/src/components/Draftail/decorators/TooltipEntity.js

@@ -144,7 +144,11 @@ TooltipEntity.propTypes = {
     PropTypes.object.isRequired,
   ]).isRequired,
   label: PropTypes.string.isRequired,
-  url: PropTypes.string.isRequired,
+  url: PropTypes.string,
+};
+
+TooltipEntity.defaultProps = {
+  url: null,
 };
 
 export default TooltipEntity;

+ 4 - 0
client/src/components/Draftail/decorators/TooltipEntity.scss

@@ -7,6 +7,10 @@ $icon-size: 1em;
         color: $color-teal;
     }
 
+    .icon-warning {
+        color: $color-red;
+    }
+
     &__icon {
         color: $color-teal;
         margin-right: 0.2em;

+ 3 - 3
client/src/components/Draftail/decorators/__snapshots__/Document.test.js.snap

@@ -56,14 +56,14 @@ exports[`Document no data 1`] = `
   icon={
     <Icon
       className={null}
-      name="doc-full"
+      name="warning"
       title={null}
     />
   }
-  label=""
+  label="Missing document"
   onEdit={[Function]}
   onRemove={[Function]}
-  url=""
+  url={null}
 >
   test
 </TooltipEntity>

+ 2 - 0
client/tests/stubs.js

@@ -41,6 +41,8 @@ global.wagtailConfig = {
     SHOW_LATEST_CONTENT: 'Show latest content',
     SHOW_ERROR: 'Show error',
     EDITOR_CRASH: 'The editor just crashed. Content has been reset to the last saved version.',
+    BROKEN_LINK: 'Broken link',
+    MISSING_DOCUMENT: 'Missing document',
   },
 };
 

+ 1 - 0
docs/releases/2.5.rst

@@ -18,6 +18,7 @@ Other features
  * Added more informative error message when ``|richtext`` filter is applied to a non-string value (mukesh5)
  * Automatic search indexing can now be disabled on a per-model basis via the ``search_auto_update`` attribute (Karl Hobley)
  * Improved diffing of StreamFields when comparing page revisions (Karl Hobley)
+ * Highlight broken links to pages and missing documents in rich text (Brady Moe)
 
 
 Bug fixes

+ 2 - 0
wagtail/admin/templates/wagtailadmin/admin_base.html

@@ -49,6 +49,8 @@
                 SHOW_LATEST_CONTENT: "{% trans 'Show latest content' %}",
                 SHOW_ERROR: "{% trans 'Show error' %}",
                 EDITOR_CRASH: "{% trans 'The editor just crashed. Content has been reset to the last saved version.' %}",
+                BROKEN_LINK: "{% trans 'Broken link' %}",
+                MISSING_DOCUMENT: "{% trans 'Missing document' %}"
             };
 
             wagtailConfig.ADMIN_URLS = {