views:

174

answers:

4

I have few nested DIVs at page. I want to add event only for smalest DIV which size is more than 100x100 px. I am able to do it using conditions in code. Is it possible to do using selector?

$('?????').click(function (e) {
    }

If yes, please provide an example.

+1  A: 

The simplest solution is programmatic. No native jQuery selectors will do this however you can write your own. You can then write:

$("div:larger(100x100):smallest")...

It creates four selectors (only two of which are needed for this problem, the others are for completeness):

  • :larger(HxW)
  • :smaller(HxW)
  • :largest
  • :smallest

Source code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"&gt;&lt;/script&gt;
<script type="text/javascript">
$(function() {
  $("div:larger(100x100):smallest").css("border", "1px solid black");
});

$.extend($.expr[":"], {
  smaller: function(elem, i, match) {
    var m = /^(\d+)(?:x(\d+))$/.exec(match[3]);
    if (!m) {
      return false;
    }
    var h = m[1];
    var w = m[2] || h;
    var t = $(elem);
    return t.height() <= h && t.width() <= w;
  },
  larger: function(elem, i, match) {
    var m = /^(\d+)(?:x(\d+))$/.exec(match[3]);
    if (!m) {
      return false;
    }
    var h = m[1];
    var w = m[2] || h;
    var t = $(elem);
    return t.height() >= h && t.width() >= w;
  },
  smallest: function(elem, i, match, set) {
    var areas = $.map(set, function(elem, index) {
      return $(elem).height() * $(elem).width();
    });
    for (var j=0; j<areas.length; j++) {
      console.log("" + j + ": " + areas[i] + " / " + areas[j]);
      if (areas[j] < areas[i]) {
        return false;
      }
    }
    return true;
  },
  largest: function(elem, i, match, set) {
    var areas = $.map(set, function(elem, index) {
      return $(elem).height() * $(elem).width();
    });
    for (var j=0; j<areas.length; j++) {
      if (areas[j] > areas[i]) {
        return false;
      }
    }
    return true;
  }
});
</script>
<style type="text/css">
div { background: yellow; margin: 15px; }
#one { height: 50px; width: 50px; }
#two { height: 100px; width: 100px; }
#three { height: 150px; width: 150px; }
</style>
</head>
<body>
<div id="one"></div>
<div id="two"></div>
<div id="three"></div>
</body>
</html>
cletus
it will work for all DIVs smaller than 100x100, including nested DIVs. So function will run few times. I need a way to call function only one time for smalest DIV larger than 100x100
Anton
+1  A: 

You cannot do this with a selector.

Instead, you'll need to use .each to loop through the elements and find the smallest one.

SLaks
A: 

Instead of using .each() you could use a filter:

 $('div').filter(function(d) {
   return $(d).width() <= 100 && d.height() <= 100;
 }).each(function() {
   // do other stuff to these small divs
 });
Pointy
+2  A: 

Here's another approach specific to your issue, it's not done via a selector, just using jQuery to find and bind the div.

var d;
$('div').filter(function() {
   var w = $(this).width(), h = $(this).height();
   return w >= 100 && h >= 100 && w * h > 10000;
}).each(function() {
   if(!d || $(this).width() * $(this).height() < d.width() * d.height()) 
     d = $(this);
});

//d is now the smallest div over 100x100, do what you want with it...
d.click(function() {
  alert("Size: " + $(this).width() + "x" + $(this).height());
});

This filters out divs that are 100x100 or smaller (note it does not match 100x100 since you said larger, just remove && w * h > 10000 if you want to include 100x100 matches). Next, it finds by area the smallest div, assigns it to d, then binds a click to that div.

Nick Craver