crowdin.com: highlight non-breaking spaces in input

Highlight non-breaking spaces - improve your work experience

נכון ליום 21-12-2020. ראה הגרסה האחרונה.

// ==UserScript==
// @name         crowdin.com: highlight non-breaking spaces in input
// @description  Highlight non-breaking spaces - improve your work experience
// @version      1.0.0
// @license      MIT
// @author       Konf
// @namespace    https://greasyfork.org/users/424058
// @include      /^http(s|):\/\/crowdin.com\/translate\/.*$/
// @require      https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js
// @run-at       document-idle
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

/* jshint esversion: 8 */
/* globals $ */

(function() {
  'use strict';

  /*
    Sometimes appears a bug: textarea was spotted, but if the script make its job right after it,
    the changes will be discarded by a code of the webpage. Highlightning will appears
    and disappears immediately. Some delay should fix it
  */
  const TEXTAREA_AWAIT_DELAY = 1000; // milliseconds

  const NBSpacesRegex = /[\u202F\u00A0]/g; // non-breaking spaces

  const GMstyles = GM_addStyle(`
    .HWT {
      background-color: ${GM_getValue('highlightColor') || 'lawngreen'};
      color: #555 !important;
    }
  `);

  // GM_registerMenuCommand(menuName, callbackFunction, accessKey)
  GM_registerMenuCommand("Set highlight color", setHighlightColorPrompt, "S");

  // textarea handling
  document.arrive('textarea#translation', {
    existing: true
  }, function() {
    const textArea = $('textarea#translation');

    textArea.one('input', async function() {
      await sleep(TEXTAREA_AWAIT_DELAY);

      textArea.highlightWithinTextarea({
        highlight: [{
          // highlight: /[\u0020]/g, // usual spaces (for testing)
          highlight: NBSpacesRegex,
          className: 'HWT'
        }]
      });

      // bugfix...
      const fakeArea = textArea[0].parentElement.querySelector('.hwt-backdrop');
      fakeArea.classList.replace('undefined', 'backdrop-comfortable-view');
    });
  });


  // utils --------------------------------------------------------------------

  function setHighlightColorPrompt() {
    const promptMsg = [
      'Enter a highlight color in HEX, RGB or word format',
      'Leave blank to keep the old one'
    ];
    const newColor = prompt(promptMsg.join('. '));

    if (newColor) {
      const oldColor = GM_getValue('highlightColor');

      GM_setValue('highlightColor', newColor);

      GMstyles.innerHTML = GMstyles.innerHTML.replace(
        `background-color: ${oldColor}`, `background-color: ${newColor}`
      );
    }
  }

  function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  // --------------------------------------------------------------------------
})();