User:Lectrician1/filter-watchlist-languages.js

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
// Filters your watchlist to show changes to labels, descriptions, and aliases that are only in the languages you specify.

// License: CC0

// Wait till the JS in the watchlist page updates the DOM
setTimeout(() => {
  // Check if we are on the watchlist page
  if ($('.mw-rcfilters-ui-watchlistTopSectionWidget-separator').length) {
    const removedComments = {
      include: {
        message: 'Did not contain include keyword but contained aliases, alias, label, or description:'
      },
      brackets: {
        message: 'Lang code was between brackets:'
      },
      spaces: {
        message: 'Lang code was between spaces:'
      }
    }

    for (let key in removedComments) {
      removedComments[key].changes = [];
    }

    const key = 'userjs-watchlist-langs';
    const commentsToKeepKey = 'userjs-watchlist-comments'

    function removeLangs(langs, toRemove) {
      for (let lang of toRemove) {

        const index = langs.indexOf(lang);

        if (index > -1) {
          langs.splice(index, 1);
        }
      }

      return langs;
    }

    let commentsToKeepArray
    let commentsToKeepString

    if (!mw.user.options.get(commentsToKeepKey) || mw.user.options.get(commentsToKeepKey).length == 0) {
      commentsToKeepArray = [' en', 'English', ' en-us', ' en-gb', 'reference', 'language'];
      commentsToKeepString = commentsToKeepArray.join(',')
      new mw.Api().saveOption(commentsToKeepKey, commentsToKeepString)
    } else {
      commentsToKeepString = mw.user.options.get(commentsToKeepKey)
      commentsToKeepArray = commentsToKeepString.split(',')
    }

    // Set up the form
    const form = $('<form>', {
      id: 'update-langs-form',
      html: [
        $('<label>', {
          for: 'langs-input',
          text: 'Lang codes to keep'
        }),
        $('<input>', {
          id: 'langs-input',
          type: 'text',
          placeholder: 'comma-separated'
        }),
        $('<label>', {
          for: 'comments-input',
          text: 'Keep label/description/alias changes that include'
        }),
        $('<input>', {
          id: 'comments-input',
          type: 'text',
          placeholder: 'comma-separated'
        }),
        $('<input>', {
          type: 'submit',
          value: 'Update languages'
        })
      ]
    });

    // Append the form to the content text element
    $('#mw-content-text').prepend(form);

    // Preload the text input from browser local storage
    $('#langs-input').val(mw.user.options.get(key));

    $('#comments-input').val(commentsToKeepString)

    // Bind the click event to the submit button
    $('#update-langs-form').submit(async function (e) {
      e.preventDefault();

      // Get the comma-separated languages from the input
      const options = {
        'userjs-watchlist-langs': $('#langs-input').val().split(',').map(lang => lang.trim()),
        'userjs-watchlist-comments': $('#comments-input').val().split(',')
      }

      // Set the new value in local storage
      await new mw.Api().saveOptions(options)
      location.reload()
    })

    $('.mw-changeslist-line').each((i, e) => {
      let comment = $(e).find('.autocomment').first().text()

      if (!comment.includes('→')) {
        if (!commentsToKeepArray.some(word => comment.includes(word))) {
          if ((comment.includes('aliases') || comment.includes('alias') ||
            comment.includes('description') || comment.includes('label'))) {
            removedComments.include.changes.push(comment)
            e.remove()
          } else {
            api = new mw.Api();

            api.get({
              "action": "query",
              "format": "json",
              "meta": "wbcontentlanguages",
              "formatversion": "2",
              "wbclcontext": "term",
              "wbclprop": "code"
            })
              .done(function (data) {
                let langsToRemove = Object.keys(data.query.wbcontentlanguages)

                const langsOption = mw.user.options.get(key) || '';
                const langsToKeep = langsOption.split(",");

                langsToRemove = removeLangs(langsToRemove, langsToKeep);

                let inBetweenBrackets = /\[(.*?)\]/.exec(comment)
                if (inBetweenBrackets && langsToRemove.includes(inBetweenBrackets[1])) {
                  removedComments.brackets.changes.push(comment)
                  e.remove()

                } else if (!comment.includes('wiki') && !/\d{5,}/.exec(comment)) {
                  let betweenSpaces = comment.match(/(?<=\s)\b\S+\b(?=\s)/g)

                  if (betweenSpaces) {
                    const isMatch = langsToRemove.some(lang => {
                      return betweenSpaces.some(spaceLang => {
                        return lang.includes(spaceLang);
                      });
                    });
                    if (isMatch) {
                      removedComments.spaces.changes.push(comment)
                      e.remove()
                    }
                  }

                }

              })
          }
        }
      }
    })

    const dialogBtn = $('<button>', {
      text: 'Show removed changes',
      click: function () {
        const dialogContent = $('<div>', {
          css: {
            'max-height': '500px',
            'overflow-y': 'auto'
          }
        });

        for (let key in removedComments) {
          const message = removedComments[key].message;
          const changes = removedComments[key].changes;

          const messageElem = $('<div>', {
            css: {
              'font-weight': 'bold',
              'margin-bottom': '5px'
            },
            text: message
          });
          dialogContent.append(messageElem);

          for (let change of changes) {
            const changeElem = $('<div>', {
              css: {
                'margin-left': '10px'
              },
              text: change
            });
            dialogContent.append(changeElem);
          }
        }

        const dialog = $('<div>', {
          title: 'Removed changes and reason',
          html: dialogContent
        });

        dialog.dialog({
          modal: true,
          resizable: false,
          width: '600px'
        });
      }
    });

    $('#update-langs-form').after(dialogBtn);
  }

}, 1000)