0
\$\begingroup\$

I created some tooltips using javascript but after writing the code I found it a lot more complicated and hard to read/understand is there any way to shortened my code and make it more logical and efficient.

var tooltip = (function () {
    'use strict';
    const PREFIX = 'data-tooltip';
    const SUFFIX = ['pointer-direction', 'position', 'content'];
    const REQUIRED_ATTRIBUTES = [];

    SUFFIX.forEach((item) => {
        REQUIRED_ATTRIBUTES.push(PREFIX + '-' + item);
    });

    const POSITIONS = [
        'top-left-corner',
        'top-center',
        'top-right-corner',
        'right-center',
        'bottom-right-corner',
        'bottom-center',
        'bottom-left-corner',
        'left-center',
        'middle',
    ];

    const DIRECTIONS = [
        'top-start',
        'top',
        'top-end',
        'right-start',
        'right',
        'right-end',
        'bottom-start',
        'bottom',
        'bottom-end',
        'left-start',
        'left',
        'left-end',
    ];

    DIRECTIONS.forEach((direction, position) => {
        if (direction === 'top-start') {
            if (POSITIONS[position] === 'top-left-corner') {
            } else if (POSITIONS[position] === 'top-center') {
            } else if (POSITIONS[position] === 'top-right-corner') {
            } else if (POSITIONS[position] === 'right-center') {
            } else if (POSITIONS[position] === 'bottom-right-corner') {
            } else if (POSITIONS[position] === 'bottom-center') {
            } else if (POSITIONS[position] === 'bottom-left-corner') {
            } else if (POSITIONS[position] === 'left-center') {
            } else if (POSITIONS[position] === 'middle') {
            }
        } else if (direction === 'top') {
            if (POSITIONS[position] === 'top-left-corner') {
            } else if (POSITIONS[position] === 'top-center') {
            } else if (POSITIONS[position] === 'top-right-corner') {
            } else if (POSITIONS[position] === 'right-center') {
            } else if (POSITIONS[position] === 'bottom-right-corner') {
            } else if (POSITIONS[position] === 'bottom-center') {
            } else if (POSITIONS[position] === 'bottom-left-corner') {
            } else if (POSITIONS[position] === 'left-center') {
            } else if (POSITIONS[position] === 'middle') {
            }
        } else if (direction === 'top-end') {
            if (POSITIONS[position] === 'top-left-corner') {
            } else if (POSITIONS[position] === 'top-center') {
            } else if (POSITIONS[position] === 'top-right-corner') {
            } else if (POSITIONS[position] === 'right-center') {
            } else if (POSITIONS[position] === 'bottom-right-corner') {
            } else if (POSITIONS[position] === 'bottom-center') {
            } else if (POSITIONS[position] === 'bottom-left-corner') {
            } else if (POSITIONS[position] === 'left-center') {
            } else if (POSITIONS[position] === 'middle') {
            }
        }

        if (direction === 'right-start') {
            if (POSITIONS[position] === 'top-left-corner') {
            } else if (POSITIONS[position] === 'top-center') {
            } else if (POSITIONS[position] === 'top-right-corner') {
            } else if (POSITIONS[position] === 'right-center') {
            } else if (POSITIONS[position] === 'bottom-right-corner') {
            } else if (POSITIONS[position] === 'bottom-center') {
            } else if (POSITIONS[position] === 'bottom-left-corner') {
            } else if (POSITIONS[position] === 'left-center') {
            } else if (POSITIONS[position] === 'middle') {
            }
        } else if (direction === 'right') {
            if (POSITIONS[position] === 'top-left-corner') {
            } else if (POSITIONS[position] === 'top-center') {
            } else if (POSITIONS[position] === 'top-right-corner') {
            } else if (POSITIONS[position] === 'right-center') {
            } else if (POSITIONS[position] === 'bottom-right-corner') {
            } else if (POSITIONS[position] === 'bottom-center') {
            } else if (POSITIONS[position] === 'bottom-left-corner') {
            } else if (POSITIONS[position] === 'left-center') {
            } else if (POSITIONS[position] === 'middle') {
            }
        } else if (direction === 'right-end') {
            if (POSITIONS[position] === 'top-left-corner') {
            } else if (POSITIONS[position] === 'top-center') {
            } else if (POSITIONS[position] === 'top-right-corner') {
            } else if (POSITIONS[position] === 'right-center') {
            } else if (POSITIONS[position] === 'bottom-right-corner') {
            } else if (POSITIONS[position] === 'bottom-center') {
            } else if (POSITIONS[position] === 'bottom-left-corner') {
            } else if (POSITIONS[position] === 'left-center') {
            } else if (POSITIONS[position] === 'middle') {
            }
        }

        if (direction === 'bottom-start') {
            if (POSITIONS[position] === 'top-left-corner') {
            } else if (POSITIONS[position] === 'top-center') {
            } else if (POSITIONS[position] === 'top-right-corner') {
            } else if (POSITIONS[position] === 'right-center') {
            } else if (POSITIONS[position] === 'bottom-right-corner') {
            } else if (POSITIONS[position] === 'bottom-center') {
            } else if (POSITIONS[position] === 'bottom-left-corner') {
            } else if (POSITIONS[position] === 'left-center') {
            } else if (POSITIONS[position] === 'middle') {
            }
        } else if (direction === 'bottom') {
            if (POSITIONS[position] === 'top-left-corner') {
            } else if (POSITIONS[position] === 'top-center') {
            } else if (POSITIONS[position] === 'top-right-corner') {
            } else if (POSITIONS[position] === 'right-center') {
            } else if (POSITIONS[position] === 'bottom-right-corner') {
            } else if (POSITIONS[position] === 'bottom-center') {
            } else if (POSITIONS[position] === 'bottom-left-corner') {
            } else if (POSITIONS[position] === 'left-center') {
            } else if (POSITIONS[position] === 'middle') {
            }
        } else if (direction === 'bottom-end') {
            if (POSITIONS[position] === 'top-left-corner') {
            } else if (POSITIONS[position] === 'top-center') {
            } else if (POSITIONS[position] === 'top-right-corner') {
            } else if (POSITIONS[position] === 'right-center') {
            } else if (POSITIONS[position] === 'bottom-right-corner') {
            } else if (POSITIONS[position] === 'bottom-center') {
            } else if (POSITIONS[position] === 'bottom-left-corner') {
            } else if (POSITIONS[position] === 'left-center') {
            } else if (POSITIONS[position] === 'middle') {
            }
        }

        if (direction === 'left-start') {
            if (POSITIONS[position] === 'top-left-corner') {
            } else if (POSITIONS[position] === 'top-center') {
            } else if (POSITIONS[position] === 'top-right-corner') {
            } else if (POSITIONS[position] === 'right-center') {
            } else if (POSITIONS[position] === 'bottom-right-corner') {
            } else if (POSITIONS[position] === 'bottom-center') {
            } else if (POSITIONS[position] === 'bottom-left-corner') {
            } else if (POSITIONS[position] === 'left-center') {
            } else if (POSITIONS[position] === 'middle') {
            }
        } else if (direction === 'left') {
            if (POSITIONS[position] === 'top-left-corner') {
            } else if (POSITIONS[position] === 'top-center') {
            } else if (POSITIONS[position] === 'top-right-corner') {
            } else if (POSITIONS[position] === 'right-center') {
            } else if (POSITIONS[position] === 'bottom-right-corner') {
            } else if (POSITIONS[position] === 'bottom-center') {
            } else if (POSITIONS[position] === 'bottom-left-corner') {
            } else if (POSITIONS[position] === 'left-center') {
            } else if (POSITIONS[position] === 'middle') {
            }
        } else if (direction === 'left-end') {
            if (POSITIONS[position] === 'top-left-corner') {
            } else if (POSITIONS[position] === 'top-center') {
            } else if (POSITIONS[position] === 'top-right-corner') {
            } else if (POSITIONS[position] === 'right-center') {
            } else if (POSITIONS[position] === 'bottom-right-corner') {
            } else if (POSITIONS[position] === 'bottom-center') {
            } else if (POSITIONS[position] === 'bottom-left-corner') {
            } else if (POSITIONS[position] === 'left-center') {
            } else if (POSITIONS[position] === 'middle') {
            }
        }
    });
})();

I know the code is quite huge but it is what it is.

Apart that, How can I check which elements inside body have same attribute presented in REQUIRED_ATTRIBUTES array.

You can see or download the entire code from github gist

P.S I don't want to use jQuery.

Below is the example of

<button data-tooltip="true" data-tooltip-pointer-direction="bottom" data-tooltip-content="Copy to Clipboard" data-tooltip-position="top-center">
  Copy
</button>

OUTPUT

Reference Image

\$\endgroup\$
5
  • 2
    \$\begingroup\$ Welcome to Code Review! Please post your entire code in the question itself, rather than as an external link. The way you have made the excerpt, the code doesn't make sense, so according to our rules we can't review it. \$\endgroup\$ Aug 28 at 18:15
  • 1
    \$\begingroup\$ Welcome to CR! All of the bodies of these if/else if chains are empty. Is that intentional? What happens inside of those blocks is pretty important for refactoring the code to use a loop or data structure. If there are common patterns to the actions, then it's much easier to simplify than if there aren't regular patterns, and what those patterns are exactly would dictate how to actually simplify it. \$\endgroup\$
    – ggorlen
    Aug 29 at 1:26
  • \$\begingroup\$ Welcome to Code Review! The current question title, which states your concerns about the code, is too general to be useful here. Please edit to the site standard, which is for the title to simply state the task accomplished by the code. Please see How to get the best value out of Code Review: Asking Questions for guidance on writing good question titles. \$\endgroup\$ Aug 29 at 7:28
  • \$\begingroup\$ As far as I can see, the DIRECTIONS.forEach() statement does precisely nothing - lots of tests and no actions. Is the code unfinished? \$\endgroup\$ Aug 29 at 7:30
  • \$\begingroup\$ the code is […] what it is The code presented is not what is kept on GitHub. \$\endgroup\$
    – greybeard
    Aug 29 at 10:41
1
\$\begingroup\$

There are quite a number of things that can be done to simplify the code.

Consistency

It is important to be consistent in your code. If you express the same thing in two different ways, a reader will assume that there is an important difference between the two. For example, you can write strings with double quotes or single quotes, and if you use double quotes for some strings and single quotes for other strings, then a reader will assume that these are two different kinds of strings that mean two different things.

In your code, some of your variables are const and some are var. Some of your anonymous functions are fat arrow literals and some are function expressions. Make sure that you actually want to express two different things when you do that!

const over let, never use var

You should prefer to make all variables const as much as possible. Only if you absolute must mutate the binding, and there is no way around it, may you use let. Never use var. It is simply a vestige of a bad decision made early on in the language design and cannot be removed because of backwards-compatibility. You should just pretend it never existed.

So, tooltip should be a const, not a var.

Conditionals with empty bodies

if (POSITIONS[position] === 'middle') {}

This conditional statement will do the following: it checks whether the condition is true or false. When the condition is false, it will execute nothing. And when the condition is true, it will execute the body, which, however, is empty! So, actually in both cases, nothing gets executed.

Therefore, it is simply equivalent to just running

POSITIONS[position] === 'middle'

And since you are not using the result of this expression anywhere, and this expression also does not have any side-effects, it is actually not doing anything at all, and can be removed without changing the result of the code. If we apply this iteratively and recursively, we end up with this:

Empty loop

DIRECTIONS.forEach((direction, position) => {});

The first thing we will notice is that the parameters are not actually used, so we can simplify this to

DIRECTIONS.forEach(() => {});

Next, we will notice that the function that is passed to Array.prototype.forEach does not return anything and has no side-effects, so the loop is actually not doing anything at all, and we can just remove it altogether.

Unused variables

Once we have removed the loop, we notice that DIRECTIONS and POSITIONS are no longer used in the code and can be safely removed. This leaves us with the following code:

const tooltip = (() => {
    'use strict';
    const PREFIX = 'data-tooltip';
    const SUFFIX = ['pointer-direction', 'position', 'content'];
    const REQUIRED_ATTRIBUTES = [];

    SUFFIX.forEach((item) => {
        REQUIRED_ATTRIBUTES.push(PREFIX + '-' + item);
    });
})();

Higher-level iterators over loops

ECMAScript's standard library provides a number of higher-level iteration methods on the Array.prototype object. You should generally prefer those methods over manual loops.

For example, when you simply want to map each item of an array to a different item, that's what the Array.prototype.map method is for:

const REQUIRED_ATTRIBUTES = SUFFIX.map((item) => PREFIX + '-' + item);

However, once we make this change, we notice that REQUIRED_ATTRIBUTES is not actually used and can be safely removed. And when we remove REQUIRED_ATTRIBUTES, PREFIX and SUFFIX also become unused.

Which leaves us with this:

const tooltip = (() => {
    'use strict';
})();

Final cleanup

The body of this IIFE does not return any value nor does it have any side-effect, and thus simply evaluates to undefined and can safely be replaced with this:

const tooltip = undefined;
\$\endgroup\$

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