Guest User

Untitled

a guest
Jan 20th, 2018
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.85 KB | None | 0 0
  1. // @flow
  2. /**
  3. * Renders text to the DOM and notifies when it is mutated outside of React
  4. *
  5. * This component renders a piece of text, then uses the MutationObserver API
  6. * to watch if that text is changed (for instance, by a user with the browser
  7. * devtools open). It then can optionally fire a callback or attempt to revert
  8. * the change. This is intended to be used as a rudimentary anti-cheating
  9. * measure for students who are trying to "fake" progress on KA for their
  10. * parent/teacher/battle school squad commander by messing with the browser.
  11. *
  12. * A quick warning: this component will detect mutations that are made by
  13. * userscripts and browser extensions, such as the Google Translate extension.
  14. * There are legitimate reasons users may want to transform the DOM of the page
  15. * (machine translation being an obvious one) so this component should be used
  16. * on the smallest possible piece of text that will produce the desired effect.
  17. * In other words, you should prefer this:
  18. *
  19. * You are <MutationWatcher value={"55%"}/> done with all math ever
  20. *
  21. * over this:
  22. *
  23. * <MutationWatcher value={"You are 55% done with all math ever"}/>
  24. *
  25. * However, breaking strings up this way can have a negative impact on
  26. * translation clarity -- another reason to use this component sparingly.
  27. */
  28.  
  29. import React from "react";
  30.  
  31. type Props = {|
  32. // The text to display
  33. value: string,
  34. // Will fire when the element contents are mutated
  35. onMutate?: (tag: string, originalVal: string, mutatedVal: string) => any,
  36. // Whether to revert the DOM to the way it was before the mutation
  37. revertMutations: boolean,
  38. // A description of the content that is included in the callback
  39. tag: string,
  40. // Type of element to wrap with -- defaults to "span"
  41. wrapperType: string,
  42. // Props to pass to the wrapper element
  43. wrapperProps: {},
  44. // Whether to mark a mutate_dom_attempt conversion
  45. markConversion: boolean,
  46. |};
  47.  
  48. type State = {};
  49.  
  50. type DefaultProps = {
  51. wrapperType: string,
  52. wrapperProps: {},
  53. markConversion: boolean,
  54. };
  55.  
  56. const markMutateDOMAttempt = (
  57. tag: string,
  58. originalValue: string,
  59. modifiedValue: string,
  60. ) => markConversion("mutate_dom_attempt", {tag, originalValue, modifiedValue});
  61.  
  62. class MutationWatcher extends React.Component<DefaultProps, Props, State> {
  63. props: Props;
  64.  
  65. _observer: MutationObserver;
  66. _node: Element;
  67.  
  68. static defaultProps = {
  69. revertMutations: false,
  70. wrapperProps: {},
  71. wrapperType: "span",
  72. markConversion: false,
  73. };
  74.  
  75. state = {};
  76.  
  77. componentDidMount() {
  78. if (window.MutationObserver) {
  79. this._observer = new MutationObserver(
  80. this.handleValueMutated.bind(this),
  81. );
  82. this._observer.observe(this._node, {
  83. characterData: true,
  84. subtree: true,
  85. });
  86. }
  87. }
  88.  
  89. componentWillUnmount() {
  90. if (this._observer) {
  91. this._observer.disconnect();
  92. }
  93. }
  94.  
  95. handleValueMutated() {
  96. const {
  97. markConversion,
  98. onMutate,
  99. revertMutations,
  100. tag,
  101. value,
  102. } = this.props;
  103. const domValue = this._node.textContent;
  104. if (domValue && value !== domValue) {
  105. if (onMutate) {
  106. onMutate(tag, value, domValue);
  107. }
  108. if (markConversion) {
  109. markMutateDOMAttempt(tag, value, domValue);
  110. }
  111. if (revertMutations) {
  112. this._node.textContent = value;
  113. }
  114. }
  115. }
  116.  
  117. render() {
  118. const {value, wrapperType, wrapperProps} = this.props;
  119. return React.createElement(
  120. wrapperType,
  121. {
  122. ...wrapperProps,
  123. ref: ref => (this._node = ref),
  124. },
  125. value,
  126. );
  127. }
  128. }
  129.  
  130. export default MutationWatcher;
Add Comment
Please, Sign In to add comment