Resolved Safari Bookmarklets Modulo Bug + Workaround

Discussion in 'Mac Programming' started by aitte, Feb 2, 2013.

  1. aitte, Feb 2, 2013
    Last edited: Feb 2, 2013

    macrumors newbie

    May 15, 2012
    I am putting this here so that Google will index it, since I don't have any blog of my own to put it on. It's new information that I did not see anywhere else on the net.

    Basically. Safari hates the use of Modulo (%) in bookmarklets.

    If you attempt to run such a bookmarklet, Safari 6 (and probably earlier) will loudly refuse with a warning saying "Safari can't use JavaScript for this action. Safari can't run the script because Safari doesn't allow JavaScript to be used in this way. Safari is all-powerful, all-knowing and all-seeing. Safari should never be questioned. Safari can see you mast---"

    The error looks as follows:

    It took me enough time to track down that I figure it's worth sharing.

    If you look on the 4th line from the bottom, you will see "ruleNum%2==1" which is a common way of using modulo. Basically, it divides ruleNum by 2, which means that we'll get a remainder of either 0 or 1. If it's 0, it's an even number, if it's 1, it's an uneven number. People often use modulo to determine the even/odd rows of a sequence of numbers.

    Well, there's just no way, WHATSOEVER, to use Modulo in bookmarklets. You can try assigning it to variables. You can try wrapping it in functions. It will just not work.

    Luckily, if you only need to detect even/odd numbers there is an alternative method, using Binary AND. It works through the fact that binary numbers end in 0 if they are even and 1 if they are odd.

    Safari allows the Binary AND (&) operator, but not the Modulo (%) operator.

    Using Binary AND, we can "mask out" the given number, keeping only the last bit, and checking if it's 0 or 1 to determine if it's an odd or even number.

    So, here's the solution:

    Checking for Even numbers:
    FORBIDDEN: (num%2 == 0)
    ALLOWED: (num&1 == 0)

    Checking for Odd numbers:
    FORBIDDEN: (num%2 == 1)
    ALLOWED: (num&1 == 1)

    Enjoy, Google visitors of the future! The only caveat to remember is that this trick works perfectly for INTS (whole numbers like 0, 4, 10, 5034), but that extra care must be taken if using floating point numbers (5.414, 2.103, etc), such as Math.round()/Math.floor()'ing them to an integer first.

    An added bonus is that the AND-method is twice as fast as MOD, but then again nobody really cares about speed for a bookmarklet. ;-)

    I now take my bow.


    - aitte
  2. macrumors 604

    Aug 9, 2009

Share This Page