Protect Textarea

Protect from closing or navigating away from a web page with changed textareas.

  1. // ==UserScript==
  2. // @name Protect Textarea
  3. // @namespace https://arantius.com/misc/greasemonkey/
  4. // @description Protect from closing or navigating away from a web page with changed textareas.
  5. // @include http*
  6. // @version 1.3
  7. // ==/UserScript==
  8.  
  9. // Version History:
  10. //
  11. // 1.3 (2011-06-06): Use pagehide/pageshow events for cache friendliness.
  12. // https://developer.mozilla.org/en-US/Firefox/Releases/1.5/Using_Firefox_1.5_caching#Page_caching_despite_unload_and_beforeunload_handlers
  13. // 1.2.1 (2010-02-16): Reduce false-positive warning rate.
  14. // 1.2 (2009-09-15): Complete rewrite, less false positives for hidden
  15. // fields controlled by scripts, better handling of
  16. // dynamic/ajax sites.
  17. // 1.1 (2006-09-18): Add the "noprotect" class detection
  18. //
  19.  
  20. var CHANGED_MARK=String(Math.random()).substr(2);
  21.  
  22. window.addEventListener('keypress', handleKeypress, true);
  23. window.addEventListener('submit', handleSubmit, true);
  24. window.addEventListener('beforeunload', handleUnload, true);
  25.  
  26. window.addEventListener('pageshow', function() {
  27. window.addEventListener('beforeunload', handleUnload, true);
  28. }, true);
  29.  
  30. function handleKeypress(event) {
  31. if (
  32. // Ignore events not in a textarea.
  33. !event.target
  34. || !event.target.tagName
  35. || 'TEXTAREA'!=event.target.tagName
  36. // Ignore non-character keypresses.
  37. || 0==event.charCode
  38. // Ignore "noprotect" textareas.
  39. || event.target.className.match(/\bnoprotect\b/)
  40. ) {
  41. return;
  42. }
  43.  
  44. if (0 /* debug? */) {
  45. console.log('saw keypress in', event.target);
  46. console.dir(event);
  47. }
  48.  
  49. // At this point we have noticed a keypress to a textarea. Record it.
  50. var textarea = event.target;
  51. textarea.setAttribute('changed_mark', CHANGED_MARK);
  52. if (!textarea.hasAttribute('orig_value')) {
  53. textarea.setAttribute('orig_value', textarea.value);
  54. }
  55. }
  56.  
  57. function handleSubmit(event) {
  58. var textareas = event.target.getElementsByTagName('textarea');
  59. for (var i=0, textarea=null; textarea=textareas[i]; i++) {
  60. textarea.removeAttribute('changed_mark');
  61. }
  62. }
  63.  
  64. function handleUnload(event) {
  65. // Re-add later via pageshow. See https://developer.mozilla.org/en-US/Firefox/Releases/1.5/Using_Firefox_1.5_caching#Page_caching_despite_unload_and_beforeunload_handlers
  66. window.removeEventListener('beforeunload', handleUnload, true);
  67. var textareas = event.target.getElementsByTagName('textarea');
  68. textarealoop:
  69. for (var i=0, textarea=null; textarea=textareas[i]; i++) {
  70. // Check for presence in the document.
  71. var parent=textarea.parentNode;
  72. while (true) {
  73. if ('BODY'==parent.tagName) break;
  74. // Skip if we climbed the parent tree and fell out before getting to the
  75. // <body>; this textarea was removed from the document, probably by the
  76. // script that submitted it via AJAX (or some such).
  77. if (!parent || !parent.tagName) continue textarealoop;
  78. parent=parent.parentNode;
  79. }
  80.  
  81. // Skip if we haven't marked this as changed.
  82. if (!textarea.hasAttribute('changed_mark')) continue;
  83. if (textarea.getAttribute('changed_mark') != CHANGED_MARK) continue;
  84. // Skip if the value is the same as the first we observed. (I.E. only
  85. // arrow or Ctrl-C keypresses.)
  86. if (textarea.value == textarea.getAttribute('orig_value')) continue;
  87. // Skip if the value is empty. (Nothing to lose!)
  88. if ('' == textarea.value) continue;
  89. // Didn't skip, so do interrupt leaving the page.
  90. return event.returnValue='You have modified a textarea, and ' +
  91. 'have not submitted the form.';
  92. }
  93. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址