Best jquery questions in July 2012

Managing text-maps in a 2D array on to be painted on HTML5 Canvas

17 votes

So, I'm making a HTML5 RPG just for fun. The map is a <canvas> (512px width, 352px height | 16 tiles across, 11 tiles top to bottom). I want to know if there's a more efficient way to paint the <canvas>.

Here's how I have it right now:

How tiles are loaded and painted on map

The map is being painted by tiles (32x32) using the Image() piece. The image files are loaded through a simple for loop and put into an array called tiles[] to be PAINTED on using drawImage().

First, we load the tiles...

enter image description here

and here's how it's being done:

// SET UP THE & DRAW THE MAP TILES
tiles = [];
var loadedImagesCount = 0;
for (x = 0; x <= NUM_OF_TILES; x++) {
  var imageObj = new Image(); // new instance for each image
  imageObj.src = "js/tiles/t" + x + ".png";
  imageObj.onload = function () {
    console.log("Added tile ... " + loadedImagesCount);
    loadedImagesCount++;
    if (loadedImagesCount == NUM_OF_TILES) {
      // Onces all tiles are loaded ...
      // We paint the map
      for (y = 0; y <= 15; y++) {
        for (x = 0; x <= 10; x++) {
          theX = x * 32;
          theY = y * 32;
          context.drawImage(tiles[5], theY, theX, 32, 32);
        }
      }
    }
  };
  tiles.push(imageObj);
}

Naturally, when a player starts a game it loads the map they last left off. But for here, it an all-grass map.

Right now, the maps use 2D arrays. Here's an example map.

[[4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 1, 1, 1, 1], 
[1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 13, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 13, 11, 11, 11, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 1, 1, 1, 1, 1, 1, 1, 13, 13, 13, 13, 13, 1], 
[1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1]];

I get different maps using a simple if structure. Once the 2d array above is return, the corresponding number in each array will be painted according to Image() stored inside tile[]. Then drawImage() will occur and paint according to the x and y and times it by 32 to paint on the correct x-y coordinate.

How multiple map switching occurs

With my game, maps have five things to keep track of: currentID, leftID, rightID, upID, and bottomID.

  • currentID: The current ID of the map you are on.
  • leftID: What ID of currentID to load when you exit on the left of current map.
  • rightID: What ID of currentID to load when you exit on the right of current map.
  • downID: What ID of currentID to load when you exit on the bottom of current map.
  • upID: What ID of currentID to load when you exit on the top of current map.

Something to note: If either leftID, rightID, upID, or bottomID are NOT specific, that means they are a 0. That means they cannot leave that side of the map. It is merely an invisible blockade.

So, once a person exits a side of the map, depending on where they exited... for example if they exited on the bottom, bottomID will the number of the map to load and thus be painted on the map.

Here's a representational .GIF to help you better visualize:

enter image description here

As you can see, sooner or later, with many maps I will be dealing with many IDs. And that can possibly get a little confusing and hectic.

The obvious pros is that it load 176 tiles at a time, refresh a small 512x352 canvas, and handles one map at time. The con is that the MAP ids, when dealing with many maps, may get confusing at times.

My question

  • Is this an efficient way to store maps (given the usage of tiles), or is there a better way to handle maps?

I was thinking along the lines of a giant map. The map-size is big and it's all one 2D array. The viewport, however, is still 512x352 pixels.

Here's another .gif I made (for this question) to help visualize:

enter image description here

Sorry if you cannot understand my English. Please ask anything you have trouble understanding. Hopefully, I made it clear. Thanks.

Well there's a few things here so I'll respond to them in order.


...521 SEPARATE PNG FILES?

enter image description here

Use one. Just one. Maybe six, tops. Think about it, you're making every client do 500 GET requests just to get the tiles for the game? That's bonkers.

Almost every major site ever uses spritemaps to reduce requests. Youtube, for instance, uses this one image for all of its buttons:

enter image description here

You should do the same.


Your concept of using the canvas as a viewport is correct from a performance perspective. Definitely don't make it bigger than it needs to be!


As to your map performance question, giant arrays ought to be just fine to start. This is a fine way of dealing with it and I wouldn't bother exploring other options unless your word is very, very large. If it is massive, you could have "chunks" of the world that are 400x400 (or so) and when you come to the 400th row you start to use row 0 of the next array. The most arrays "in use" at any time will be four, of course, when your hero would be on a good old four corners sort of location.

Player location wouldn't be hard. If he was at tile 822, 20 that would mean he is in the chunk represented by (2, 0) (if we're starting from (0, 0)). Specifically, he'd be in tile 22, 20 of that chunk. No complex math, no ID's. There is no need to keep track of ID's. You don't even have to keep track of which chunk is the last chunk. You can just know that the total map size is (say) 1200x1200, and if he tries to move to (1201, 50), you don't even have to see if chunk (4, 0) exists. You know right away he can't move there, the map is only 1200 tiles wide!

Performance should be fine either way and will really depend on a large number of other things before you have to worry about this particular array. My advice is to worry about making the game before worrying about performance. Revisit performance once the game gets slow.

Once you get to performance, I would worry about everything except this issue first. In a canvas game its really unlikely to be the bottleneck. Reading from arrays is fast. Large arrays already in memory ought to be fast. There shouldn't be a problem, and I wouldn't spend time anticipating one until it actually presents itself.


EDIT: Example of viewport moving with player: http://jsfiddle.net/kmHZt/10/

HTML5/CSS3 - Custom Shape Div with google maps inside

14 votes

I need to make a custom shape div holding a "google maps" map. The custom border it's fine, I can handle it using a png, but the shape itself, I have only some theories of how to do it, but nothing in practice. But I think there is a way to do it using html5 canvas to make the custom shape on the div and use in css a overflow:hidden to hide what goes out of the div.

right now I have the following structure:

<html>
  <body>
    <div class="Orange_Background"></div>
    <div class="FX_Lines_over_background"></div>
    <div class="GoogleMaps_Container"></div>
  </body>
</html>

So as you can se I can't use the background as a png to only show the map, and because I need the map to be clickable.

Here is a image of what I was saying.

Teh Image

If anyone can help me, I'll be grateful !!

Thank you all.

PS: It can be with jquery too ! (if someone knows a plugin that do it.)

RE: Zee Tee's answer: If you do go this route, you can set pointer-events: none (in your css) for the div containing the images. this will send all mouse events to the layer below it. Sorry, I don't have the privilege to comment on answers yet :D

If you don't care about IE(6-8) support, then you can use CSS 3D transforms to do this directly on the map layer. But the map will look skewed, if that's the effect you are after, if not previous answer is still the best approach

Another solution is to use the mask image. sorry browser support sucks for this, but if you have a nice fallback until they catch up, you should be alright

https://developer.mozilla.org/en/CSS/-webkit-mask-image

Optimize JavaScript CSS download

13 votes

I have a number of pages for my website all use jQuery and JSON and the same CSS, except for a few pages. The first page is user login. As the user will take time to type in his username and password, I want to download all the required JavaScript and CSS files for the entire user session during login. How can this be done? The header is the same for all pages. How do I optimize it?

My idea would be load in js and css files dynamically after document.load. This would not affect the load time of the login page, whilst also caching your js and css files once the user has logged in.

You could also easily change this to document.ready if it loads faster for you.

What about something like this?

$(document).load(function() {
    function preloadFile(filename, filetype){

        //For javascript files
        if (filetype=="js"){
            var fileref=document.createElement('script');
            fileref.setAttribute("type","text/javascript");
            fileref.setAttribute("src", filename);
        }

        //For CSS files
        else if (filetype=="css") {
            var fileref=document.createElement("link");
            fileref.setAttribute("rel", "stylesheet");
            fileref.setAttribute("type", "text/css");
            fileref.setAttribute("href", filename);
        }

        document.getElementsByTagName("head")[0].appendChild(fileref)
    }

    //Examples of how to use below
    preloadFile("myscript.js", "js"); 
    preloadFile("javascript.php", "js");
    preloadFile("mystyle.css", "css");
});

References

http://www.javascriptkit.com/javatutors/loadjavascriptcss.shtml

Tracking Users coming from a certain source

10 votes

I'm giving promotions to users who sends us other visitors. This is done on the client side.

I can do this using dynamic GET parameters, e.g. http://www.mysite.com?app_source=user_id or I can do this using the hash, e.g. http://www.mysite.com#app_source,user_id.

Are there any pros and cons for any of these methods?

Query String

  • Google Analytics, server logs, et al will have a record of the URL, which may be beneficial for later analysis.
  • Multiple URLs make caching harder and have a slight chance of confusing the Google

Hash

  • Analytics and server logs will not see/pay attention to hash params

The more semantic way of handling this is probably through a query string parameter, but it's not very strong. If none of the above-listed points is relevant, I would probably just stick with query strings because it is more common.

If you mean that you are building a service that other people integrate, and you don't want them to have to pass information back to their application (via query string), then using hash params seems like a solid option.

Get webpage center coordinates on tablet devices using JavaScript

10 votes

I'm trying to compute the viewport geometric center on a webpage, rendered with Tablet devices (iOS and Android), ie the actual CENTER of the viewport (what you see) according to current translation and current zoom level - don't want the center of the document itself, I want the center of the screen what I'm viewing.

The problem is that this calculation is does not take into account any kind of zoom (an then) translation.

On iOS, I've tried with some of these answers, on the question detecting pinch to zoom on iOS, I was able to catch the event "OnZoom" but didn't get any value, though.

On Android, I can't even catch any event related to zoom. I'm aware of touchmove and touchstart events, but how can I distinguish then in order to get zoom (and zoom value)

I'm using jQuery 1.7.2 library.

I have made a demo page which is confirmed to work on iPhone iPad, Samsung Galaxy Tab 10. I have only attached the click event on a huge div, so tap on the screen after zooming to update the display.

The calculation is very simple, use screen.width/window.innerWidth to get the zoom level. screen.width will always be in device pixels and window.innerWidth is always in css pixels, which also take the zoom into account.

Further calculation is simple math:

// round the result down to avoid "half pixels" for odd zoom levels
Math.floor(window.scrollY + window.innerHeight/2);
Math.floor(window.scrollX + window.innerWidth/2);

To check whether the user is zooming, attach the listener to window.resize and window.scroll which will fire after orientationchange hiding the address bar and zooming.

Here's my demo JavaScript:

var dot = document.getElementById("dot");
document.getElementById("main").addEventListener("click", function(e) {
    var zoom = screen.width / window.innerWidth;
    alert("zoom: " + zoom + "\n" + "ScrollY: " + window.scrollY);

    dot.style.top = Math.floor(window.scrollY + window.innerHeight/2 - 5) + "px";
    dot.style.left = Math.floor(window.scrollX + window.innerWidth/2 - 5) + "px";

}, false);

Getting the "match" object in a Custom Filter Selector in jQuery 1.8

10 votes

For reference, here's an article on Creating a Custom Filter Selector with jQuery.


Introduction:

For those not familiar with jQuery's Custom Filter Selectors, here's a quick primer on what they are:

If you need a reusable filter, you can extend jQuery’s selector expressions by adding your own functions to the jQuery.expr[':'] object.

The function will be run on each element in the current collection and should return true or false (much like filter). Three bits of information are passed to this function:

  1. The element in question

  2. The index of this element among the entire collection

  3. A match array returned from a regular expression match that contains important information for the more complex expressions.

Once you've extended jQuery.expr[':'], you can use it as a filter in your jQuery selector, much like you would use any of the built-in ones (:first, :last, :eq() etc.)


Here's an example where we'll filter for elements that have more than one class assigned to them:

jQuery.expr[':'].hasMultipleClasses = function(elem, index, match) {
    return elem.className.split(' ').length > 1;
};

$('div:hasMultipleClasses');

Here's the fiddle: http://jsfiddle.net/acTeJ/


In the example above, we have not used the match array being passed in to our function. Let's try a more complex example. Here we'll create a filter to match elements that have a higher tabindex than the number specified:

jQuery.expr[':'].tabindexAbove = function(elem, index, match) {
    return +elem.getAttribute('tabindex') > match[3];
};

$('input:tabindexAbove(4)');

Here's the fiddle: http://jsfiddle.net/YCsCm/

The reason this works is because the match array is the actual array returned from the regex that was used to parse the selector. So in our example, match would be the following array:

[":tabIndexAbove(4)", "tabIndexAbove", "", "4"]

As you can see, we can get to the value inside the parentheses by using match[3].


The Question:

In jQuery 1.8, the match array is no longer being passed in to the filter function. Since we have no access to the info being passed in, the tabindexAbove filter does not work anymore. The only difference between this fiddle and the one above, is that this uses a later version of jQuery.

So, here are several points I'd like clarified:

  1. Is this expected behavior? Is it documented anywhere?

  2. Does this have anything to do with the fact that Sizzle has been updated (even though it clearly states that "the old API for Sizzle was not changed in this rewrite". Maybe this is what they mean by "the removal of the now unnecessary Sizzle.filter")?

  3. Now that we have no access to the match array, is there any other way to get to the info being passed in to the filter (in our case, 4)?

I never found any documentation in the jQuery Docs about the custom filter selectors, so I don't know where to start looking for information about this.

By looking at the jQuery 1.8 beta2 source and the "Extensibility" section of the new sizzle, you have to set fn.sizzleFilter to true in order to get the pseudo argument and the context. If not, you'll just get all the elements in the arguments.

Here is the code that does the same thing as your example. Use the selector parameter passed in the function to get the pseudo argument.

Here is the working example on jsfiddle.

As mentioned in the blog post above, you can even pre-compile and cache the your selector.

var sizzle = jQuery.find;

var tabIndexAbove = function( selector, context, isXml ) {
    return function( elem ) {
        return elem.getAttribute("tabindex") > selector;
    };
};

/*
 fn.sizzleFilter is set to true to indicate that tabIndexAbove 
 is a function that will return a function for use by the compiler 
 and should be passed the pseudo argument, the context, and 
 whether or not the current context is xml. If this property is 
 not set, adding pseudos works similar to past versions of Sizzle
*/
tabIndexAbove.sizzleFilter = true;
sizzle.selectors.pseudos.tabIndexAbove = tabIndexAbove;

$('input:tabIndexAbove(4)').css('background', 'teal');

Just a note, if you're looking at the source, jQuery slightly changed the structure that the public-facing interface points to.

In jQuery 1.7.2:

jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.filters;

In jQuery 1.8b2:

jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.pseudos;

Advantage of *this* over event.target

9 votes

Is it better / faster inside an event listener to use this or event.target

I've been writing code like this (example is jQuery):

jQuery('input').bind('keyup', function (e) {
 var j = jQuery(e.target);
 foo(j.attr('id') , j.val() );
});

And I was told to replace e.target with this because it's "better". Is there really any advantage to one or the other?

I use target because it's a more general solution as it works for delegated events. I'm having trouble benchmarking because my tests get cluttered with the binding (Although, obviously, in this case the difference would be too small to matter anyway)

The one isn't better than the other, but they do different things: this refers to the element the event is attached to, while event.target is the element that invoked the event.

For example

div id=foo   
   div id=bar

when click is attached to foo, and bar is clicked, the event will bubble up to foo. In the event this will refer to foo and event.target to bar

In the end it depends on which element you need to handle.

There's a small example on api.jquery.com/event.target that illustrates event.target. Here's a small sample that uses that example, but which also displays this: http://jsbin.com/adifan/edit#javascript,html,live

jQuery's .css() implementation

9 votes

I was looking through the jQuery code and found this line:

elem.runtimeStyle.left = elem.currentStyle.left;

at

https://github.com/jquery/jquery/blob/449e099b97d823ed0252d8821880bc0e471701ea/src/css.js#L169

I am not sure why this is done. Isn't this useless?

Setting the runtimeStyle to the currentStyle would override nothing. Except make the runtimeStyle readable the next time you read it - which doesn't seem needed now.

I understand the overall concept here and why that code block exists (to convert numeric non-pixel values to the appropriate pixel value, by setting the left to the non-pixel value and reading its pixel value and then reverting the left back to the original value).

Edit See my answer below for why I think this is done (with jsFiddle illustration!).

I have been thinking about this. Here is why I believe it is done:

Setting the runtimeStyle to the currentStyle ensures that this is style that is applied on the element (the runtime style wins over the inline style). So when you set elem.style.left in the next line, there would be no change in the UI. However, the new pixel value can still be calculated using elem.style.pixelLeft - because this just converts the non-pixel value on the CSS to a pixel value. pixelLeft is not a measurement of the actual position, it is just a conversion to the pixel value.

See this: http://jsfiddle.net/RaSzc/

So this is done to figure out the pixel value without having anything change in the UI

Can CSS be used to mask background images?

9 votes

This is what I have presently:

Image of current code

Here's my code so far:

<style type="text/css">
    .main
    {
        background:url(bg.jpg);
        height:250px;
        }
    .ban
    {
        background-color:#333;
        height:150px;
    }
    .mask
    {
        width:75px;
        height:75px;
        float:left; 
        border:#fff solid 1px;

        margin:20px;
    }
</style>

<div class="main">
    <div class="ban">
         <div class="mask"></div> 
         <div class="mask"></div>
         <div class="mask"></div>
         <div class="mask"></div>
         <div class="mask"></div>    
    </div>
</div>

Here's what I am aiming for:

enter image description here

I am looking to create a mask using CSS - what do I need for this?

If you don't find the solution in the comments above, then I've got one for you.

Instead of trying to create the svg or png image to position against, you could use borders (if you're using a solid color that's easy to work with) to replicate this.

You can see a working jsFiddle here

jQuery list of data

9 votes

Hey guys and girls :)

I've been battling this problem for a few hours and I thought I'd rather ask you for help than hammering my face into my desk repeatedly.

Need:

I have a series of editable lists which, on a press of a button should be transformed into some sort of data structure. When it has been turned into some sort of data I need to add duplicates together.

example:

  • 200g banana
  • 100g apple
  • 200g apple

Should be turned into a data list of some sort and should in the end look like this:

  • 200g banana
  • 300g apple

Hey I just met you, and this is crazy, but here's my code, so help me maybe?

//button click event
$(".calculate").bind("click", function(e)
{
    //get the correct parent of the button
    var parent = $(this).closest("#calc");

    //get relevant data
    parent.find(".options").each(function(index, element)
    {
        var opt1 = $(this).children(".opt1").children("input").val(); //weight
        var opt2 = $(this).children(".opt2").children("input").val(); //ingredient
    });
});

Basically I click the button and the above script finds all the relevant data. I cannot however for the life of me turn this into a multidimensional array or a list of objects I can search for duplicates in.

When I try to make a dynamic object it seems to fail and when I make a multidimensional array to search in I get blocked by inArray's inability to search through them.

Problem recap: I am able to get the user data no problem. Turning it into a list and adding together duplicates is the problem.

I will suggest you to have a global object that will contain the summary, this will look like this:

$(".calculate").bind("click", function(e)
{
    var fruits = {};

    //get the correct parent of the button
    var parent = $(this).closest("#calc");

    //get relevant data
    parent.find(".options").each(function(index, element)
    {
        var opt1 = $(this).children(".opt1").children("input").val(); //weight
        var opt2 = $(this).children(".opt2").children("input").val(); //ingredient

        // here is my code
        if(fruits[opt2] == undefined) {
            fruits[opt2] = opt1;
        } else {
            // assuming that opt1 is an integer
            fruits[opt2] += opt1;
        }
    });

    // use fruits variable here
});

Open a window behind the current window using Javascript/jQuery

8 votes

I want to open a window on click, but I want to open it behind the current window, or when the new window opens it should minimize itself. I have made a function but it actually did not work.

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<script type="text/javascript">
function wn(){
  var mm=window.open('http://www.google.com','newwindow','width=200, height=200', "_blank");
}
</script>
</head>
<body>
<a href="#" onclick="wn()">click</a>
</body>

EDIT

Parent window HTML

<script language="JavaScript" type="text/javascript">
function openPopUP() {
  window.open('mywindow.html','NewWin',
            'toolbar=no,status=no,width=350,height=135')
}
</script>

<body onLoad="openPopUP();">
or
<a href="javascript:openPopUP();">Click to open popup</a>

Child Winow i.e PopUp Window File

put the script in child window child window ill be get hide after 1 second if you wnat more time than change 1000 to 5000 or more

<body onLoad="setTimeout('window.blur()', 1000);" 
          onFocus="setTimeout('window.blur()', 1000);">

Try out this might work for you , write this line of code in the onload event of your child window...

window.parent.opener.focus(); 

jQuery Validate, How to give custom error from the custom function based on the condition?

8 votes

jQuery Validate, How to give custom error from the custom function based on the different condition???.

Here is the sample code. This is not my actual code. Here I'm trying to put my problem in the sample code.

I've modified the default required functionality with custom function. But how can i give the proper message based on the different conditions.

rules: {
    "data[Model][field1]": {
        required:function(){
            var myValue = $('#myfield').val();
            if( myValue < '5') {
                // Here i want to assign different error message
                return false;
            } else if( myValue > '10') {
                // Here i want to assign different error message
                return false;
            } else {
                return true;
            }
        }
    },
messages: {
    "data[Model][field1]":{ "required":"How can i get the above messages here??" }
}

The messages option can take functions that return the error messages, so you can write something like:

rules: {
    "data[Model][field1]": {
        required: function() {
            var myValue = $("#myfield").val();
            return myValue >= 5 && myValue <= 10;
        }
    }
},
messages: {
    "data[Model][field1]": {
        required: function() {
            var myValue = $("#myfield").val();
            if (myValue < 5) {
                return "Value must be greater than 4";
            else if (myValue > 10) {
                return "Value must be less than 11";
            }
        }
    }
}

Implemenitng Infinite Scrolling with jquery

8 votes

I am working on a project that uses the jQuery Masonry and Infinite Scroll plugins to load "n" amount of pictures from instagram using their API. Looking at this short example my understanding is that I need to have before hand the html pages to be rendered:

<nav id="page-nav">
  <a href="pages/2.html"></a>
</nav>

The problem is, I dont really know how many pictures will be retrieved. Here is for example how I retrieve 20 pics at a time.

    $(document).ready(function(){       
        var access_token = location.hash.split('=')[1];

        if (location.hash) {

              $.ajax({
            type: "GET",
            dataType: "jsonp",
            cache: false,
            url: "https://api.instagram.com/v1/users/MY_USER_ID/media/recent/?access_token=MY_ACCESS_TOKEN",
            success: function(data) {

                for (var i = 0; i < 20; i++) {
            $("#instafeed").append("<div class='instaframe'><a target='_blank' href='" + data.data[i].link +"'><img src='" + data.data[i].images.standard_resolution.url +"' /></a></div>");   
                }     

            }
        });


        } else {
        location.href="https://instagram.com/oauth/authorize/?display=touch&client_id=MY_CLIENT_ID&redirect_uri=MY_URI"; 

        }

    });

I guess I will need a pagination mechanism but based on the tutorial mentioned above I believe I will first need to pre-define the html pages to be loaded. So now here my questions

  1. Does that mean this plugin (Infinite Scroll) requires to have "n" amount of html files in a directory to achieve infinite scrolling?
  2. Is it possible to implement infinite scrolling with the same plugin if I dont know how many pages I will have. Even better without even having to create physical html files?
  3. How can this kind of pagination is implemented? (i.e loading chunks of 20 pics as long as the user keeps scrolling down) there is not that much documentation online, could you provide a short step through demo or description?

With kind regards

1) Does that mean this plugin (Infinite Scroll) requires to have "n" amount of html files

Absolutely not. You do not need to generate static html pages beforehand, The only think you need is a URL scheme where subsequent page content can be fetched by changing one number in URL.

Think of it from the perspective of the infinite scroll plugin. You load the plugin JavaScript in your page #1 and provide link to page#2 inside page #1. Now when the user scrolls past page#1, the only variable that the plugin has is the current page number, like, 2, or 3 or 4 (N)

The plugin needs to create the URL to fetch content from when user is scrolling. So how does the plugin do that? The plugin looks at the next URL structure provided in page#1, parses it and creates a "base path" to which it will keep adding current_page_number to fetch subsequent content. That is the role of NAV selector.

So let's say I have something like /home/page/2 as next URL in page#1. The plugin will parse this into an array as

[/home/page/,2]

and think that base_path = "/home/page/"

when the plugin attempts to fetch page_number 3, it will just append 3 to the base path, like base_path.join(current_page_num) making it /home/page/3

On server side I can just have a controller that takes care of all the /home/page/1 to /home/page/N links. You can just look inside the plugin, look for _determinePath and retrieve functions.

Now you can see the problem as well. The problem is that there can be an infinite variety of URL structure depending on how you are doing pagination inside your code and how many variables do you need. My way of doing pagination is different from your way of doing pagination. Same holds for frameworks. Drupal pagination scheme may be different from Djanga and wordpress etc.

The plugin cannot possibly cope with all these URL structures. Given a next URL, it cannot possible always deduce the "base path" to which it needs to add current_page_number. Again look at _determinePath() method of plugin to see what kind of URL it can cope with. It can parse simple URL structures, like page2.html or page=2 but you have to provide your own implementation if your URL structure is complicated or something that the plugin cannot handle. Look at pathParse() method as well.

2)Is it possible to implement infinite scrolling with the same plugin if I dont know how many pages I will have.

Again, there is no need to create HTML files. You have two options to signal end of content (without knowing how many pictures you have in advance)

  • When you have reached the "no content condition" you can return an HTTP 404.
  • Or you can return an empty string.

Does this answer the question?

How it can work with the plugin

  • First page - include - NAV SELECTOR - LOAD THNIGS THE USUAL WAY
  • First page on load - use instagram pagination and store "nextURL" in your javascript somewhere
  • On Scroll - override _determinePath to provide your own fetch URL using (2) - let plugin retrieve that URL
  • Override plugin content selector - so it returns new elements to callback
  • On Plugin fetch content - Use the callback inside plugin to update your page

Revolving text generator

8 votes

I am in the process of building a revolving text generator. The generator combines sentences (text) from a number of arrays, 'cycles' through them visually and appends them. I thought it best to create a Fiddle with a basic version of the generator as I have constructed it now:

Explanation

The basic workings are as follows:

  1. Sentences are defined in separate arrays (Array1, Array2 and Array3 in the fiddle)
  2. A second set of arrays is defined, containing the arrays that can be combined (combo0 and combo1 in the fiddle)
  3. On pressing the 'Generate' button, the function Generate is called, which visually cycles the sentences from an array of sentences (combo0[0] in the fiddle)
  4. This function loops itself until the sentence has cycled 8 times (var times = 8 in the fiddle)
  5. When this is done, the function calls the callback function that was provided. In this callback, it runs Generate again, this time with the second array (combo0[1] in the fiddle)

The reason for the callback is that I need to 'wait' for the cycling effect to complete, and then move on.

The issue

While this does exactly what I need (and besides the fact that I'm highly doubtful if this is the way to do it; I always feel a bit odd when writing a function that loops itself), I have the following problem:

In the combo arrays, I define which of the 'sentence' arrays can be possible combinations. This works fine if there are two combinations, but with more than two, I have a problem:

Generate(combo0[0], i, function(i) { //generate from first array element of combo0, callback to generating from second array of combo0
    Generate(combo0[1], i, function(i) {
        $('div#status').html('Done!'); //show status
        $('input#generate').removeAttr("disabled"); //enable button
    });
})

I would have to recursively rewrite this to accommodate the possibility of a combo array consisting of 3 or even 4 options. And probably this will break the script if a combo array contains just 2 (or 1) arrays.

This is where I'm stuck. The main issue is that if I loop over the combo array, e.g. with an .each();, the generate function is called multiple times synchronously, so the whole 'cycling' effect is lost.

I have tried writing various loops, which take into account the array length of the given combo array, but I have crashed more browsers today than ever before, and I can't work out what to do.

I have managed to fix it. Some time away from the screen is a good thing.

What I did is add an 'n' counter which increases if the multiple of the times variable is reached, causing the function to continue iteration, but outputting (see third-to-last line) from the next array (lists[n]). Finally, a check to see how much arrays are left will determine if we're done. If done, write the sentence one last time, run the optional callback and return false. This way, the function will accept the entire array, and not just the subarray (combo as opposed to combo[0]):

//Generate from array 'lists', simulating a 'slot machine
function Generate(lists, n, i, callbackFnk) {
    if (!(i >= 0)) { i= 0; }
    setTimeout((function(msg){
        i++;
        return function(){
            if (i % times != 0){
                //We haven't reached a multiple of the times variable yet, keep going.
                Generate(lists, n, i, callbackFnk);
            } else if (i % times === 0 && i != 0 && n < (lists.length-1)) {
                //Multiple reached, increase n
                n++;
                Generate(lists, n, i, callbackFnk);
            } else if (n == (lists.length-1)) {
                //we are done as there are no more arrays to go over
                showMessage(msg, i);
                if (callbackFnk) callbackFnk.call(this, i);
                return false;
            }
            showMessage(msg, i);
        }
    })(
        //output using the given n value
        lists[n][Math.floor(Math.random() * lists[n].length)]
    ), speed);
}

See the working fiddle here: http://jsfiddle.net/c_kick/kuNrA/1/

I hope this helps others!

Overflow : hidden in FF

7 votes

I'm having a problem with overflow : hidden content, but only in FF. enter image description here

I have two divs (each side of the vertical arrow, see above) each have overflow:hidden applied masking their respective child div. The child elements are being rotated onscroll event via jQuery. For whatever reason the background image in each of the children elements are not being masked as they should by their parent div.

To see this inconsistency; http://www.pearman.com.au/

Whats strange is the child content appears when inspecting any of the parents CSS properties in Firebug.

edit : find the CSS / HTML / JQuery

This code is run each time the onscroll is updated (alot);

    scrollAnimations.push({ 'start': 0, 'end': 450,
                'callback': function(scrollTop,scrollDirection){ 
                    ran_one.css({
                        '-ms-transform': 'rotate('+ -(scrollTop)*0.4 +'deg)',
                        '-webkit-transform': 'rotate('+ -(scrollTop)*0.4 +'deg)',
                        '-moz-transform': 'rotate('+ -(scrollTop)*0.4 +'deg)',
                        '-o-transform': 'rotate('+ -(scrollTop)*0.4 +'deg)',
                        'transform': 'rotate('+ -(scrollTop)*0.4 +'deg)' })
                    }
                });
            scrollAnimations.push({ 'start': 0, 'end': 900,
                'callback': function(scrollTop,scrollDirection){
                    ran_two.css({
                        '-ms-transform': 'rotate('+ -(scrollTop)*0.4 +'deg)',
                        '-webkit-transform': 'rotate('+ -(scrollTop)*0.4 +'deg)',
                        '-moz-transform': 'rotate('+ -(scrollTop)*0.4 +'deg)',
                        '-o-transform': 'rotate('+ -(scrollTop)*0.4 +'deg)',
                        'transform': 'rotate('+ -(scrollTop)*0.4 +'deg)' })
                    }
                });

CSS ;

#rainbow-mask-right{
        width:421px;
        height:421px;
        display:block;
        position:absolute;
        bottom:0;
        left: 50%;
        overflow:hidden;
        }
    #rainbow-mask-left{
        width:421px;
        height:421px;
        display:block;
        position:absolute;
        bottom:0;
        left: 50%;
        overflow:hidden;
        margin-left: -420px;
        visibility:visible;
        }
    #ran-one{
        background:url(images/home/rainbow/ran-dash.gif) no-repeat;
        width:421px;
        height:421px;
        display:block;
        top: 421px;
        position: absolute;

        transform: rotate(50deg);
        -ms-transform: rotate(50deg); /* IE 9 */
        -webkit-transform: rotate(50deg); /* Safari and Chrome */
        -moz-transform: rotate(50deg); /* Firefox */
        -o-transform: rotate(50deg); /* Opera */
        }
    #ran-two{
        background:url(images/home/rainbow/ran-colour.gif) no-repeat transparent;
        width:421px;
        height:421px;
        display:block;
        top: 421px;
        position: absolute;
        left: 421px;
        }
   .set-origin {
    transform-origin:0 0;
    -ms-transform-origin:0 0; /* IE 9 */
    -webkit-transform-origin:0 0; /* Safari and Chrome */
    -moz-transform-origin:0 0; /* Firefox */
    -o-transform-origin:0 0; /* Opera */
    }   

and HTML

<div id='rainbow-mask-right'><div id='ran-one' class="set-origin"></div></div>
<div id='rainbow-mask-left'> <div id='ran-two' class="set-origin"></div></div>

Well, after a little while of debugging, I am pretty sure I found the issue.

Looks like FireFox does not like to display empty containers. I am on 13.1, but after editing your HTML via FireBug, here is the end result:

space enter

Just add a simple

&nbsp;

to the rainbows and it should be a win.

Great looking site! Enjoy,

<div id="rainbow-mask-right"><div id="ran-one" class="set-origin">&nbsp;</div></div>
<div id="rainbow-mask-left"><div id="ran-two" class="set-origin">&nbsp;</div></div>

What CSS3 selectors does jQuery really support, e.g. :nth-last-child?

7 votes

According to http://api.jquery.com/category/selectors/ we can use a large amount of CSS selectors in jQuery, but e.g. :nth-last-child is not mentioned there. However, when I test the following (with jQuery 1.7.1 as from Google), it actually works on Firefox, Chrome, and IE 9, but not on IE 9 in IE 8 emulation mode:

$('li:nth-last-child(2)').css('color', 'red');

So what’s happening? It looks as if jQuery generated CSS code, like li:nth-last-child(2) { color: red } and somehow injected it, which then works OK on browsers that support the selector used. But that would be odd.

Most importantly, is there some trick to make jQuery support such selectors on all browsers?

jQuery supports nearly all CSS3 selectors1, with the following exceptions:

  • :root

  • :lang()

  • :target

  • :nth-last-child()

  • :nth-of-type(), :nth-last-of-type(), :first-of-type, :last-of-type and :only-of-type

  • Namespace prefixes and pseudo-elements

A few other selectors (like the ~ combinator, :empty, and some CSS2 attribute selectors) were going to be dropped as well during jQuery's early development, all because John Resig didn't think anybody would use them. Luckily, they made it into the final release after some more tests were made available.

The reason why your selector appears to work in Firefox, Chrome and IE9 is because jQuery first passes the selector string to the native document.querySelectorAll() implementation before falling back to Sizzle. Since it is a valid CSS selector, document.querySelectorAll() will successfully return a node list for jQuery to use.

In the event that document.querySelectorAll() fails, jQuery automatically falls back to Sizzle. There are a number of scenarios that can cause it to fail:

  • The selector is invalid, not supported, or otherwise cannot be used (see the Selectors API spec for details).

  • document.querySelectorAll() is not supported.

In your case, although IE9 (and IE8) implement document.querySelectorAll(), IE8 doesn't support :nth-last-child(). Since jQuery doesn't implement :nth-last-child() either, there's no fallback behavior to use, so your selector fails completely on IE8.

That said, you can always use jQuery's custom selector extensions to implement the missing pseudo-classes yourself.2 See this question for an :nth-of-type() implementation.

Here's my take at :nth-last-child(), based on the existing :nth-child() implementation:

$.expr[':']['nth-last-child'] = function(elem, index, match) {
    var parent = elem.parentNode, 
        children = parent.childNodes;

    // Filter out non-element nodes
    children = $.grep(children, function(e, i) {
        return e.nodeType === 1;
    });

    // Pretend to be :nth-child() in order to parse the formula
    fMatch = $.expr.preFilter.CHILD($.expr.match.CHILD.exec(':nth-child(' + match[3] + ')'));

    // Use the existing :nth-child() implementation... backwards
    var lastIndex = children.length - 1;
    return $.expr.filter.CHILD(children[lastIndex - index], fMatch);
};

jsFiddle preview


1 It does support :contains(), last defined in this old CR revision of the spec before being dropped later, as well as extending :not() from the standard. The differences between jQuery's implementation and the current standard are covered in this question.

2 But, considering that the CSS3 selectors spec has now been widely implemented by modern browsers as well as the fact that Sizzle has been rewritten for jQuery 1.8 (and jQuery 2.0 will finally be dropping IE6/7/8 support), I don't think the developers will be willing to patch any implementations of the above CSS3 selectors into future versions of Sizzle.

Jquery a cleaner way for prepend

5 votes

I recently made a wall similar to Facebook.

And I just need some advice or a better way.

So when the user submitted his post, I prepend the results to a div, and I made it this way

$('.get_posts').prepend('<div id="'+stream.sid+'"class="row stream-posts"><div class="span1 stream-thumb"><ul class="thumbnails"><li><a href="#" class="thumbnail"><img src="http://placehold.it/60x60" alt=""></a></li></ul></div><div class="span5 stream-content"><a href="#" class="author">'+stream.author+'</a><p>'+stream.text+'</p></div></div>');

I know its not the best, and would like to ask a more experienced developer if there is a cleaner way to prepend the data.

A much cleaner way to do this is to create a function that generates the HTML needed for a post -

function createPost(postDetails){
  var html = '';
    html += '<div id="'+postDetails.sid+'"class="row stream-posts">';
    html += '  <div class="span1 stream-thumb">';
    html += '   <ul class="thumbnails">';
    html += '    <li>';
    html += '      <a href="#" class="thumbnail">';
    ...
  return html;
}

This way you can simply execute - $('.get_posts').prepend(createPost(postData)); and pass all the relevant data to the function via the postData argument. Much cleaner and easier to maintain.


Depending on how you implemented your wall updates - you might also be able to build this HTML block on your server and send it as-is. That way your JavaScript will not have to worry about building the markup - you can just prepend the data you got back from the AJAX call.

PHP/JS: Echoing several variables without losing their value

5 votes

The JS/Ajax function I have built submits without a button click or page refresh. The function gets the values of the input field and with php echoed out the results. But everytime a variable is echoed the next variable erases the value of the previous one. How can avoid this? EXAMPLE

JS

<script>
$(document).ready(function() {
  var timer = null; 
    var dataString;   
      function submitForm(){
        $.ajax({ type: "POST",
           url: "index.php",
           data: dataString,
           success: function(result){
                         $('#special').html('<p>' +  $('#resultval', result).html() + '</p>');
                                           }
                 });
                 return false; }

    $('#contact_name').on('keyup', function() {
    clearTimeout(timer);
    timer = setTimeout(submitForm, 050);
          var name = $("#contact_name").val();
    dataString = 'name='+ name;
    });

     $('#email').on('keyup', function() {
     clearTimeout(timer);
     timer = setTimeout(submitForm, 050);
     var name = $("#email").val();
     dataString = 'name='+ name;
     });

     $('#phone').on('keyup', function() {
     clearTimeout(timer);
     timer = setTimeout(submitForm, 050);
     var name = $("#phone").val();
     dataString = 'name='+ name;
     });

     $('#address').on('keyup', function() {
     clearTimeout(timer);
     timer = setTimeout(submitForm, 050);
     var name = $("#address").val();
     dataString = 'name='+ name;
     });

     $('#website').on('keyup', function() {
     clearTimeout(timer);
     timer = setTimeout(submitForm, 050);
     var name = $("#website").val();
     dataString = 'name='+ name;
     });


 }); 
</script>

HTML/PHP

<form action="" method="post" enctype="multipart/form-data" id="contact_form" name="form4"> 
     <div class="row">  
      <div class="label">Contact Name *</div> <!-- end .label --> 
        <div class="input"> 
          <input type="text" id="contact_name" class="detail" name="contact_name" value="<?php $contact_name ?>" />  
          <div id="special"><span id="resultval"></span></div>  
        </div><!-- end .input--> 
     </div><!-- end .row --> 
     <div class="row">  
      <div class="label">Email Address *</div> <!-- end .label --> 
       <div class="input"> 
        <input type="text" id="email" class="detail" name="email" value="<?php $email ?>" />  
        <div id="special"><span id="resultval"></span></div> 
       </div><!-- end .input--> 
     </div><!-- end .row --> 
    </form>

you can use append() method:

success: function(result){
        $('#special').append('<p>' + result + '</p>');
}

as you have set similar classes to the inputs you can minify your code:

 $('.detail').on('keyup', function() {
    clearTimeout(timer);
    var name = $(this).val();
    dataString = 'name='+ name;
    timer = setTimeout(submitForm, 050);
 });

note that IDs must be unique and repetitively requesting data from the server is not efficient.

Ajax/Js Image uploader: Creating duplicate preview images

5 votes

I am working with an Ajax imageuploader from this SITE. I currently achieve in creating duplicate preview images: one appears under the input field and the other will appear somewhere else in the page under something like "this what you chose". The problem is that if the user selects a file, the function will display the Image but if the user changes its mind and chooses a new image then the yourCustomPreview will show the new image chosen and the old.

Is there a way of just having the most recent preview picture shown without the old preview picture appearing? If unclear please check the source files HERE

uploaderPreviewer.js- Original function

<script>
function displayImage($previewDiv, imageUrl) {

    var imageFilename = imageUrl.substr(imageUrl.lastIndexOf('/') + 1);

    $previewDiv
        .removeClass('loading')
        .addClass('imageLoaded')
        .find('img')
        .attr('src', imageUrl)
        .show();
    $previewDiv
        .parents('table:first')
        .find('input:hidden.currentUploadedFilename')
        .val(imageFilename)
        .addClass('imageLoaded');
    $previewDiv
        .parents('table:first')
        .find('button.removeImage')
        .show();
}
</script>

uploaderPreviewer.js- Modified function

<script>
    function displayImage($previewDiv, imageUrl) {
    //New
    var yourCustomPreview = $('#custompreview');

    var imageFilename = imageUrl.substr(imageUrl.lastIndexOf('/') + 1);

    $previewDiv
        .removeClass('loading')
        .addClass('imageLoaded')
        .find('img')
        .attr('src', imageUrl)
        .show();
    $previewDiv
        .parents('table:first')
        .find('input:hidden.currentUploadedFilename')
        .val(imageFilename)
        .addClass('imageLoaded');
    $previewDiv
        .parents('table:first')
        .find('button.removeImage')
        .show();

        //New
        yourCustomPreview.append('<img src="' + imageUrl + '"/>');

    }
</script>

ok, try this:

TO EDIT:

replace the displayImage function with this:

function displayImage($previewDiv, imageUrl) {
//New
var yourCustomPreview = $('#custompreview');
var imageId = $($previewDiv.context).attr('id');
var imageFilename = imageUrl.substr(imageUrl.lastIndexOf('/') + 1);

$previewDiv
    .removeClass('loading')
    .addClass('imageLoaded')
    .find('img')
    .attr('src', imageUrl)
    .show();
$previewDiv
    .parents('table:first')
    .find('input:hidden.currentUploadedFilename')
    .val(imageFilename)
    .addClass('imageLoaded');
$previewDiv
    .parents('table:first')
    .find('button.removeImage')
    .show();

    //New
    if(!yourCustomPreview.find('#' + imageId +'_prev').length > 0)
    {
      yourCustomPreview.append('<img id="' + imageId + '_prev" src="' + imageUrl + '"/>');
    }
    else
    {
      $('#' + imageId +'_prev').attr('src', imageUrl);
    }
}

TO DELETE

replace removeImage function with this:

function removeImage($removeImageButton, errorDisplayed) {

    var thumbIdToDelete = $removeImageButton.parents('table').find('[name=imageToUpload]').attr('id');
    var $parent = $removeImageButton.parents('table:first').parent();

    $.post($.uploaderPreviewer.removeImageAjaxUrl, {
        currentUploadedFilename: $parent.find('input:hidden.currentUploadedFilename').val()
    });

    $parent.find('input:hidden.currentUploadedFilename').removeClass('imageLoaded');
    $parent.find('div.previewImage')
        .removeClass('loading imageLoaded')
        .find('img')
        .hide();

    $parent.removeErrorMessage();

    if ( ! errorDisplayed) {
        $parent.find('input:file').val('');
        $removeImageButton.hide();
    }

    $('#' + thumbIdToDelete +'_prev').remove();
};

Push data to page without checking periodically for it?

4 votes

Is there any way you can push data to a page rather than checking for it periodically?

Obviously you can check for it periodically with ajax, but is there any way you can force the page to reload when a php script is executed?

Theoretically you can improve an ajax request's speed by having a table just for when the ajax function is supposed to execute (update a value in the table when the ajax function should retrieve new data from the database) but this still requires a sizable amount of memory and a mysql connection as well as still some waiting time while the query executes even when there isn't an update/you don't want to execute the ajax function that retrieves database data.

Is there any way to either make this even more efficient than querying a database and checking the table that stores the 'if updated' data OR tell the ajax function to execute from another page?

I guess node.js or HTML5 webSocket could be a viable solution as well?

Or you could store 'if updated' data in a text file? Any suggestions are welcome.

You're basically talking about notifying the client (i.e. browser) of server-side events. It really comes down to two things:

  1. What web server are you using? (are you limited to a particular language?)
  2. What browsers do you need to support?

Your best option is using WebSockets to do the job, anything beyond using web-sockets is a hack. Still, many "hacks" work just fine, I suggest you try Comet or AJAX long-polling.

There's a project called Atmosphere (and many more) that provide you with a solution suited towards the web server you are using and then will automatically pick the best option depending on the user's browser.

If you aren't limited by browsers and can pick your web stack then I suggest using SocketIO + nodejs. It's just my preference right now, WebSockets is still in it's infancy and things are going to get interesting once it starts to develop more. Sometimes my entire application isn't suited for nodejs, so I'll just offload the data operation to it alone.

Good luck.