RevisionCompare.jsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import React, { useState } from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import { CopyToClipboard } from 'react-copy-to-clipboard';
  5. import {
  6. Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
  7. } from 'reactstrap';
  8. import { withUnstatedContainers } from './UnstatedUtils';
  9. import RevisionCompareContainer from '../services/RevisionCompareContainer';
  10. import RevisionDiff from './PageHistory/RevisionDiff';
  11. import RevisionIdForm from './RevisionCompare/RevisionIdForm';
  12. /* eslint-disable react/prop-types */
  13. const DropdownItemContents = ({ title, contents }) => (
  14. <>
  15. <div className="h6 mt-1 mb-2"><strong>{title}</strong></div>
  16. <div className="card well mb-1 p-2">{contents}</div>
  17. </>
  18. );
  19. /* eslint-enable react/prop-types */
  20. function encodeSpaces(str) {
  21. if (str == null) {
  22. return null;
  23. }
  24. // Encode SPACE and IDEOGRAPHIC SPACE
  25. return str.replace(/ /g, '%20').replace(/\u3000/g, '%E3%80%80');
  26. }
  27. const PageCompare = (props) => {
  28. const toggleDropdown = () => {
  29. setDropdownOpen(!dropdownOpen);
  30. }
  31. const pagePathUrl = () => {
  32. const { origin } = window.location;
  33. const { path } = revisionCompareContainer.pageContainer.state;
  34. const { fromRevision, toRevision } = revisionCompareContainer.state;
  35. const urlParams = (fromRevision && toRevision ? `?compare=${fromRevision._id}...${toRevision._id}` : '');
  36. return encodeSpaces(decodeURI(`${origin}/${path}${urlParams}`));
  37. };
  38. const [dropdownOpen, setDropdownOpen] = useState(false);
  39. const { t, revisionCompareContainer } = props;
  40. const fromRev = revisionCompareContainer.state.fromRevision;
  41. const toRev = revisionCompareContainer.state.toRevision;
  42. const showDiff = (fromRev && toRev);
  43. return (
  44. <React.Fragment>
  45. <div className="float-left">{t('page_history.comparing_changes')}</div>
  46. <div className="mb-3">
  47. <Dropdown
  48. className="grw-copy-dropdown"
  49. isOpen={dropdownOpen}
  50. toggle={() => toggleDropdown()}
  51. >
  52. <DropdownToggle
  53. caret
  54. className="d-block text-muted bg-transparent btn-copy border-0 py-0"
  55. >
  56. <i className="ti-clipboard"></i>
  57. </DropdownToggle>
  58. <DropdownMenu positionFixed modifiers={{ preventOverflow: { boundariesElement: null } }}>
  59. {/* Page path URL */}
  60. <CopyToClipboard text={pagePathUrl()}>
  61. <DropdownItem className="px-3">
  62. <DropdownItemContents title={t('copy_to_clipboard.Page URL')} contents={pagePathUrl()} />
  63. </DropdownItem>
  64. </CopyToClipboard>
  65. <DropdownItem divider className="my-0"></DropdownItem>
  66. </DropdownMenu>
  67. </Dropdown>
  68. </div>
  69. <div className="clearfix"></div>
  70. <RevisionIdForm />
  71. { showDiff && (
  72. <RevisionDiff
  73. revisionDiffOpened
  74. previousRevision={fromRev}
  75. currentRevision={toRev}
  76. />
  77. )}
  78. </React.Fragment>
  79. );
  80. }
  81. /**
  82. * Wrapper component for using unstated
  83. */
  84. const PageCompareWrapper = withUnstatedContainers(PageCompare, [RevisionCompareContainer]);
  85. PageCompare.propTypes = {
  86. t: PropTypes.func.isRequired, // i18next
  87. revisionCompareContainer: PropTypes.instanceOf(RevisionCompareContainer).isRequired,
  88. };
  89. export default withTranslation()(PageCompareWrapper);