1
\$\begingroup\$

It may seem a bit obsessive and/or pedantic, but the following script allows me to see when posts are ready for reviewing.

I developed this UserScript for use with TamperMonkey to allow me to have a tab open for a review queue, and then when an item is ready for review, the tab will be highlighted with an asterisk on the far left. Until an item is ready, an animation effect is applied to the title to show that a timer is currently running before refreshing the page. I have considered inspecting the number of action buttons to discern if an item is ready to be reviewed instead of inspecting the URL but this technique seems to work fine.

Questions:

  • How does the usage look?
  • What would you change and/or code differently?
// ==UserScript==
// @name         Highlight active review
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Bring attention to the user when a post is up for reviewing
// @author       Sam Onela
// @match        https://codereview.stackexchange.com/review/*
// ==/UserScript==

;(function() {
    'use strict';
    const INITIAL_CHECK_TIMEOUT = 1500;
    const INTERVAL_DELAY = 400;
    const RELOAD_DELAY = 6500;
    const CLICK_CHECK_DELAY = 6000;
    const ticks = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
    let timeout = window.setTimeout(check, INITIAL_CHECK_TIMEOUT);
    let interval;
    function updateTitle(showAsterisk = false) {
        var titleMatches = document.title.match(/^([\W]{1})Review/);
        if (titleMatches && titleMatches.length > 1) {
            const index = ticks.indexOf(titleMatches[1]);
            document.title =  document.title.replace(titleMatches[1], ticks[(index+1)%ticks.length]);
        }
        else {
            document.title =  (showAsterisk?'*': ticks[0]) + document.title;
        }
    }
    function check(clickHandlerAdded = false){
        if (timeout) {
            window.clearTimeout(timeout);
            timeout = 0;
        }
        if (window.location.pathname.match(/\d+/)) { // drilled in to a review item
            updateTitle(true);
            if (!clickHandlerAdded) {
                document.addEventListener('click', (event) => timeout = window.setTimeout(check, CLICK_CHECK_DELAY, true));
            }
        }
        else { //add spinner animation and then reload
            updateTitle();
            if (interval === undefined) {
                interval = window.setInterval(updateTitle, INTERVAL_DELAY);
            }
            window.setTimeout(_=> window.location = window.location, RELOAD_DELAY);
        }
    }
})();

Follow-up (meta) question

Perhaps this is too meta (and could be asked in a question on CR meta), and might not be seen by target user, but I'll ask anyway: What is the reason for the downvote? If something is unclear, please ask for clarification.

I understand votes are supposed to be anonymous and downvotes could also be used if the user thinks the OP didn't research "enough" or the code question is not useful...

\$\endgroup\$
2
\$\begingroup\$

How does the es-6 usage look? What would you change and/or code differently?

1. Arrow Functions

I would personally recommend using arrow functions where you have not to stay consistent with the ES6 usage throughout your code.

Example:

;(function() {

... can be changed to:

;(() => {

Additionally, parenthesis are optional when only one parameter is given.

Example:

document.addEventListener('click', (event) => timeout ...

... can be changed to:

document.addEventListener( 'click', event => timeout ...

2. Constant Arrow Function Expressions

Since it does not appear that you have any intention of overwriting your functions, I would recommend using function expressions defined as constants, rather than function declarations.

Example:

function updateTitle(showAsterisk = false) {

... can be changed to:

const updateTitle = ( showAsterisk = false ) => {

3. Don't Use var

If you can use let or const, use them instead.

Example:

var titleMatches = document.title.match(/^([\W]{1})Review/);

... can be changed to:

const titleMatches = document.title.match( /^([\W]{1})Review/ );

4. The window. Prefix is Unnecessary

You do not need to use the window prefix on window.setTimeout, window.clearTimeout, or window.location.

Example:

window.clearTimeout(timeout);

... can be changed to:

clearTimeout( timeout );

Final Result

Ultimately, the final result of the changes I would make would look like the following:

// ==UserScript==
// @name         Highlight active review
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Bring attention to the user when a post is up for reviewing
// @author       Sam Onela
// @match        https://codereview.stackexchange.com/review/*
// ==/UserScript==

;(() =>
{
    'use strict';

    const INITIAL_CHECK_TIMEOUT = 1500;
    const INTERVAL_DELAY        = 400;
    const RELOAD_DELAY          = 6500;
    const CLICK_CHECK_DELAY     = 6000;
    const ticks                 = [
        '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'
    ];

    let timeout = setTimeout( check, INITIAL_CHECK_TIMEOUT );
    let interval;

    const updateTitle = ( showAsterisk = false ) =>
    {
        let titleMatches = document.title.match( /^([\W]{1})Review/ );

        if ( titleMatches && titleMatches.length > 1 )
        {
            const index    = ticks.indexOf( titleMatches[1] );
            document.title = document.title.replace( titleMatches[1], ticks[( index + 1 ) % ticks.length] );
        }

        else
        {
            document.title = ( showAsterisk ? '*' : ticks[0] ) + document.title;
        }
    };

    const check = ( clickHandlerAdded = false ) =>
    {
        if ( timeout )
        {
            clearTimeout( timeout );
            timeout = 0;
        }

        if ( window.location.pathname.match( /\d+/ ) ) // drilled in to a review item
        {
            updateTitle( true );

            if ( !clickHandlerAdded )
            {
                document.addEventListener( 'click', event => timeout = setTimeout( check, CLICK_CHECK_DELAY, true ) );
            }
        }

        else //add spinner animation and then reload
        {
            updateTitle();

            if ( interval === undefined )
            {
                interval = setInterval( updateTitle, INTERVAL_DELAY );
            }

            setTimeout( _ => window.location = window.location, RELOAD_DELAY );
        }
    };

})();

Hope this helps!

\$\endgroup\$
  • 1
    \$\begingroup\$ Good job answering the first question. I honestly originally wrote it not using es-6 features and then right before posting it I decided to switch it so things like var and old-school function declarations were left unchanged. \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ Apr 6 '18 at 3:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.