Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 15 of 15
  1. #1
    Regular Coder ajhauser's Avatar
    Join Date
    Nov 2007
    Location
    Earlville. It's where Earls come from.
    Posts
    226
    Thanks
    74
    Thanked 1 Time in 1 Post

    Please help compact this script

    Hello,
    I have the following script on my website and it is adding a class to my body tag the way that it should be. If there a way that I can make this more compact though, and also add an "else" section?

    So
    in layman's terms what I'm trying to get to is this:

    If (body.templateProduct or body.templateCollection or body.templatePage).addClass(smallClasses[Math.floor(Math.random() * smallClasses.length)]);

    If(body.templateIndex).addClass(bigClasses[Math.floor(Math.random() * bigClasses.length)]);

    ELSE(just add the default class to the body tag).addClass(defaultClass);



    Code:
    <script type="text/javascript">
    
            var smallClasses = ['smallBG1', 'smallBG2'];
            var bigClasses = ['bigBG1', 'bigBG2', 'bigBG3', 'bigBG4', 'bigBG5', 'bigBG6'];
            $(function(){
                $("body.templateProduct").addClass(smallClasses[Math.floor(Math.random() * smallClasses.length)]);
                $("body.templateCollection").addClass(smallClasses[Math.floor(Math.random() * smallClasses.length)]);
                $("body.templatePage").addClass(smallClasses[Math.floor(Math.random() * smallClasses.length)]);
                $("body.templateIndex").addClass(bigClasses[Math.floor(Math.random() * bigClasses.length)]);
             });
            
        </script>

  • #2
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    27,688
    Thanks
    80
    Thanked 4,647 Times in 4,609 Posts
    Well, one way would be to not bother using jQuery for something this simplistic, especially if jQuery is only used for this purpose on the page.

    But I don't understand your else condition, at all.

    How would you ever *get* to the else? That is how would your if condition ever be false???

    The only way that addClass could ever fail in that code would be none of those classnames you showed existed. Is *THAT* what you mean?
    Last edited by Old Pedant; 01-25-2013 at 10:05 PM.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #3
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    27,688
    Thanks
    80
    Thanked 4,647 Times in 4,609 Posts
    In other words, I could do it like this, if I understood what you are after:
    Code:
    <script type="text/javascript">
    (
      function( )
      {
          var smallClasses = ['smallBG1', 'smallBG2'];
          var bigClasses = ['bigBG1', 'bigBG2', 'bigBG3', 'bigBG4', 'bigBG5', 'bigBG6'];
          function addRandom( addto, fromwhat )
          {
              addto.className += 
                  " " + fromwhat[Math.floor(Math.random()*fromWhat.length];
          } 
              
          var bdy = document.body.
          if ( (/(templateProduct|templsteCollection|templatePage)/.test(bdy.className) )
          {
              addRandom( bdy, smallClasses );
          } else if ( (/templateProduct/).test(bdy.className) ) {
              addRandom( bdy, bigClasses );
          } else {
              bdy.className += " defaultClass";
          }
      }
    )();
    </script>
    </body>
    </html>
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #4
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,461
    Thanks
    11
    Thanked 600 Times in 580 Posts
    the posted solution suffers from false partial class hits.

    this one should be compliant:
    Code:
    //util helper function:
    Array.prototype.random=function(){return this[parseInt(Math.random()*((this.length-1)+1))];};
    
     var smallClasses = ['smallBG1', 'smallBG2'];
     var bigClasses = ['bigBG1', 'bigBG2', 'bigBG3', 'bigBG4', 'bigBG5', 'bigBG6'];
    
     $(function() {
    
    	 var elm= document.body,
    		body = elm.className.split(/\s+/).map(function(a, b, c) {
    			 this[a] = 1;
    			 return this;
    		 }, {})[0]; //LUT of body classes
    
    	 if (body.templateProduct || body.templateCollection || body.templatePage){ 
    		 return elm.className  += " " + smallClasses.random();
    	 }
    
    	 if (body.templateIndex){ return elm.className  += " " + bigClasses .random();}
    
    	 elm.className += " defaultClass";
    
     });//end $()
    Last edited by rnd me; 01-26-2013 at 01:10 AM.
    my site (updated 2014/10/20)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.3, IE11:9.2, IE9:2.7, IE10:2.6, FF:16.8, CH:47.5, SF:7.8, NON-MOUSE:37%

  • #5
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    27,688
    Thanks
    80
    Thanked 4,647 Times in 4,609 Posts
    the posted solution suffers from false partial class hits.
    Agreed, but I judged getting partial classname hits on those particular names pretty darned unlikely.

    But you don't have to use split and all that stuff. Just adjust the regular expressions:
    Code:
          if ( (/\b(templateProduct|templateCollection|templatePage)\b/.test(bdy.className) )
          ...
          } else if ( (/\btemplateProduct\b/).test(bdy.className) ) {
    Won't that accomplish it?

    ********

    EDIT: RegExp fixed. Thanks, RndMe.
    Last edited by Old Pedant; 01-26-2013 at 01:56 AM.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #6
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,461
    Thanks
    11
    Thanked 600 Times in 580 Posts
    Quote Originally Posted by Old Pedant View Post
    Agreed, but I judged getting partial classname hits on those particular names pretty darned unlikely.

    But you don't have to use split and all that stuff. Just adjust the regular expressions:
    Code:
          if ( (/\b(templateProduct|templsteCollection|templatePage)\b/.test(bdy.className) )
          ...
          } else if ( (\b/templateProduct/\b).test(bdy.className) ) {
    Won't that accomplish it?
    it sure will. (if you fix the RX syntax error you posted hehe)

    actually, i was more trying to implement the pseudo code in the OP as closely as possible, RXs add to complexity. then again, maybe a functional dynamic look up table adds to complexity as well...

    6 === 0.5 * dozen
    my site (updated 2014/10/20)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.3, IE11:9.2, IE9:2.7, IE10:2.6, FF:16.8, CH:47.5, SF:7.8, NON-MOUSE:37%

  • #7
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,642
    Thanks
    0
    Thanked 649 Times in 639 Posts
    Quote Originally Posted by Old Pedant View Post
    Won't that accomplish it?
    As someone recently pointed out to me regarding boundary tests on class names - using \b will match on partial class names that contain hyphens.
    So templateProduct-12 or not-templateProduct would also match even though those are not the specified class.

    It is not a problem provided that you don't use hyphens in class names.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • #8
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    27,688
    Thanks
    80
    Thanked 4,647 Times in 4,609 Posts
    Oh, okay...so do this:
    Code:
          if ( (/[^\w\-](templateProduct|templateCollection|templatePage)[^\w\-]/.test(bdy.className) )
          ...
          } else if ( (/[^\w\-]templateProduct[^\w\-]/).test(bdy.className) ) {
    And include any other weird characters if they are legal in class names.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #9
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,461
    Thanks
    11
    Thanked 600 Times in 580 Posts
    here is a modern way of side-stepping RX gotchas, using the classList feature:

    Code:
    //util helper function:
    Array.prototype.random = function() {
    	return this[parseInt(Math.random() * ((this.length - 1) + 1))];
    };
    
    var smallClasses = ['smallBG1', 'smallBG2'];
    var bigClasses = ['bigBG1', 'bigBG2', 'bigBG3', 'bigBG4', 'bigBG5', 'bigBG6'];
    
    $(function() {
    
    	var elm = document.body, hit, table={
    			templateProduct: smallClasses,
    			templateCollection: smallClasses,
    			templatePage: smallClasses,
    			templateIndex: bigClasses
    		};
    
    	for (var i = 0, ec = elm.classList, mx = ec.length) {
    		if (hit = table[ec[i]]) return ec.add(hit.random());
    	}//next
    
    	ec.add("defaultClass");
    
    }); //end $()
    this should work on about 85% of devices these days.
    that can be increased to at least 95% using a simple polyfill, or the jQuery class features instead of the native classList
    my site (updated 2014/10/20)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.3, IE11:9.2, IE9:2.7, IE10:2.6, FF:16.8, CH:47.5, SF:7.8, NON-MOUSE:37%

  • #10
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    27,688
    Thanks
    80
    Thanked 4,647 Times in 4,609 Posts
    Why do you do this:
    Code:
    return this[parseInt(Math.random() * ((this.length - 1) + 1))];
    ???

    What is the point of ((this.length - 1) + 1) versus simply this.length??

    And wny parseInt() instead of Math.floor()? Just because it's fewer characters to type? Though of course it works.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #11
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,461
    Thanks
    11
    Thanked 600 Times in 580 Posts
    Quote Originally Posted by Old Pedant View Post
    Why do you do this:
    Code:
    return this[parseInt(Math.random() * ((this.length - 1) + 1))];
    ???

    What is the point of ((this.length - 1) + 1) versus simply this.length??

    And wny parseInt() instead of Math.floor()? Just because it's fewer characters to type? Though of course it works.
    because i'm lazy. busted. heh.

    the honest explanation is that the array proto was copied from another script, and it had a random() function reference, from which i pasted the body of into the proto without looking at the whole resulting code.

    i can certainly slim it down and speed it up from what i posted before:
    Code:
    Array.prototype.random = function() {
    	return this[~~( Math.random() * this.length )];
    };
    my site (updated 2014/10/20)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.3, IE11:9.2, IE9:2.7, IE10:2.6, FF:16.8, CH:47.5, SF:7.8, NON-MOUSE:37%

  • #12
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    27,688
    Thanks
    80
    Thanked 4,647 Times in 4,609 Posts
    Cutesy. But probably 6 nanoseconds slower than just using Math.floor().

    After all, in order to do the first ~, JS has to first convert number (Math.random() * this.length) to an integer, which almost surely uses exactly the same C++ (or whatever) code as does Math.floor(). Then it has to do the complement (add 3 nanoseconds) and do it again (add another 3 nanoseconds).

    Your mileage may vary with the age of your CPU.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #13
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,461
    Thanks
    11
    Thanked 600 Times in 580 Posts
    Quote Originally Posted by Old Pedant View Post
    Cutesy. But probably 6 nanoseconds slower than just using Math.floor().

    After all, in order to do the first ~, JS has to first convert number (Math.random() * this.length) to an integer, which almost surely uses exactly the same C++ (or whatever) code as does Math.floor(). Then it has to do the complement (add 3 nanoseconds) and do it again (add another 3 nanoseconds).

    Your mileage may vary with the age of your CPU.
    but, it avoids the function overhead of Math.floor(), and has one less global closure to instantiate, since it inlines the calculation as an operator.

    compared to Math.floor i see about 5-10% improvement in chrome and ie10 but a 40% improvement in firefox.

    as such a low-level utility, i don't mind the blackbox-edness of it; such tools are supposed to be fast and slender, and this has both going for it.
    my site (updated 2014/10/20)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.3, IE11:9.2, IE9:2.7, IE10:2.6, FF:16.8, CH:47.5, SF:7.8, NON-MOUSE:37%

  • #14
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    27,688
    Thanks
    80
    Thanked 4,647 Times in 4,609 Posts
    Wow! What crappy JS implementations!

    I know that a true compiler wouldn't make that same mistake.

    There shouldn't *BE* any overhead in calling any of the builtin functions. The compiler should recognize them and just generate direct calls to the underlying routines.

    Because JavaScript is untyped, I would have expected that both Math.floor() and ~ would make a call to an internal getAsInteger( ) function. That is, the function checks to see if the type is Number, calls objectToNumber if not (or possibly it's smart enough to separate out stringToNumber from other types...immaterial in this case), and then uses whatever is available on the CPU to convert floating point to integer. If JS really first calls Math.floor() which then has to turn around and call getAsInteger( ) whereas ~ can call getAsInteger( ) directly, then that would certainly explain the horrible performance disadvantage.

    I guess I'm just too used to optimizing compilers. Way back in 1994 and 1995, we were building a C++ compiler and would consistently benchmark ourselves against various other compilers, including Microsoft's C++ of the day. I can guarantee you that such things as Math.floor() were optimized to death. (That and working on an earlier C compiler are what still, to this day, makes me prefer pre-increment to post-increment. Even on a register rich CPU, the post-increment often costs one extra instruction.) To the point that, in full optimization mode (that is, sacrifice memory for the sake of performance, no matter what) the code for Math.floor() would have been generated as inline machine code. Which I'm sure is true of even lower levels of optimization today, given how cheap memory is compared to performance.

    Sorry to have doubted you. Should have known you'd actually try it.
    Last edited by Old Pedant; 01-26-2013 at 03:45 AM.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #15
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,642
    Thanks
    0
    Thanked 649 Times in 639 Posts
    Quote Originally Posted by Old Pedant View Post
    And include any other weird characters if they are legal in class names.
    The alternative I came up with was to test start of string or space as the left boundary and end of string or space as the right boundary as multiple classes are entered as a space separated list. I think I like your alternative better as it works on what is valid in a class name rather than what is valid as a boundary.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •