0

Mega Edit — I have tried to explain my issue as clearly as possible.

My goal: to set the height of newly loaded images to the same size of the browser if their height is taller than the browser.

Best way i can do this is via commented code i think. It's currently live on http://syndex.me.

The complete js file that the below transcript was taken from can be reached at http://marckremers.com/syndex/js/jquery.infinitescrollfortumblr.js

 //Gets the computed style of the image rather than the specified.
 //This was supplied very kindly by @RobG
 //The problem is that on first load, the height for the image is showing as 0 for the larger images.
 //Once it's cached, the functions shows the correct height.
 //I have no idea how to make this function work on a "on Ready" or "On Loaded"?

function getComputedStyle(el, styleProperty) {

 if (document && document.defaultView && document.defaultView.getComputedStyle) {
   var styleObj = document.defaultView.getComputedStyle(el, null);
   var floatStyle = (typeof document.body.style.cssFloat == 'string')?'cssFloat':'styleFloat';

   if (styleProperty == 'float') styleProperty = floatStyle;
   return styleObj && styleObj[styleProperty];
  }
}
    function addNextPage(oj) {
        if (oj.status == 404) {
            tAP.remainFlg = false;
            return;
        }
        var d = document.createElement("div");
        d.innerHTML = oj.responseText;
        var posts = tAP.gP(d.getElementsByTagName("*"));
        if (posts.length < 2) {
            tAP.rF = false;
            return;
        }
        d = document.createElement("div");
        d.className = "tumblrAutoPager_page_info";
        tAP.pp.appendChild(d);
        for (var i = 0; i < posts.length; i++) {
        //Goal: Set newly loaded images via this autopager script for tumblr
        //      to the height of the browser
        //      (So... IF the image is taller than the browser
        //      Make the image as tall as the browser)
        //      In effect I'm trying to make a dynamic image max-height based on the browser 

        // This is loading the new posts (part of the autopager script, not my code)
        tAP.pp.appendChild(posts[i]);

        //Over here I'm trying to reference the newly loaded imgs
        //BUT this is a horrible way of getting them, apprently.
        //It gets all the imgs in the entire document.
        //But it seems to work for my array below, anyhow
        //I really just need to deal with the new ones loaded in.
        var myDivs = tAP.pp.getElementsByTagName("img");
        }

        var myHeights = [];
        for (var n=0, iLen=myDivs.length; n<iLen; n++) {
    myHeights.push(getComputedStyle(myDivs[n], 'height'));
    }

    console.log(myHeights)
    //= I get an array of image heights, however the newly loaded imgs often show up as 0
    // so the "getcomputedstyle" script is not working as it should yet. 
    //once the page is cached, it works as it should
        //you can see the console logs here http://syndex.me

    //Over here would go:
    //"for each image
    //  if my height is taller then the window
    //  make me as tall as the window"

    //Finally, I have this working PERFECTLY in the jquery code
    //you can see it at http://syndex.me on the first page load.
    //since you can't bind .live or .delegate to events that don't "bubble" 
    //up the DOM tree, i.e. ".load", I can't get it to recognise
    //newly loaded images from this script
    //thats why i'm having to hack this file

        var footer = $("footer");
        footer ? footer.parentNode.appendChild(footer) : null;
        tAP.rF = true;
    }

Thanks in advance.

RGBK
  • 2,048
  • 5
  • 35
  • 55

3 Answers3

1

Probably because myDivs contains a NodeList, an array like object which contains indexed references to the matched elements, which does not have a getAttribute() member.

Instead, subscript the individual elements (either with [n] or item(n)), which will have a getAttribute() method. Or just use the width property.

alex
  • 479,566
  • 201
  • 878
  • 984
  • Thank you. I just have no clue what subscripting is. Yet. I'll look on google, but any examples would be greatly appreciated. – RGBK Oct 10 '11 at 01:15
  • Better to use the property since in many browsers, it will be the current value whereas the attribute value may not have been updated (if it existed at all). – RobG Oct 10 '11 at 01:20
  • ok, thats the thing, i used width, and it didn't recognise that either. it recognises nothing! It's infuriating. I'll change the code now to show you one sec. – RGBK Oct 10 '11 at 01:22
  • As in my answer, elements other than image don't have a width property unless it has explicitly been set. – RobG Oct 10 '11 at 01:23
1

Your code is faulty:

> myDivs = tAP.pp.getElementsByTagName("img");

getElementsByTagName returns a live NodeList.

> myWidths = myDivs.getAttribute("width");

NodeLists don't have a getAttribute method, DOM elements do.

In any case, it is much more efficient to access the property, so:

var myWidths = [];
for (var i=0, iLen=myDivs.length; i<iLen; i++) {
  myWidths.push(myDivs[i].width);
}

However, elements other than images usually only have a width property if it has been set as an attribute or property. You may be after the computed style, e.g.

  <script type="text/javascript">
  function getActualWidth(el, styleProperty) {

    if (document && document.defaultView && document.defaultView.getComputedStyle) {
      var styleObj = document.defaultView.getComputedStyle(el, null);
      var floatStyle = (typeof document.body.style.cssFloat == 'string')?'cssFloat':'styleFloat';

      if (styleProperty == 'float') styleProperty = floatStyle;
      return styleObj && styleObj[styleProperty];
    }
  }
  </script>
  <div onclick="alert(getActualWidth(this, 'width'));">div</div>

That gets you with width. To change the width, just set it directly:

element.style.width = '500px';
RobG
  • 142,382
  • 31
  • 172
  • 209
  • I'm not a deep coder. I know stuff like jquery where i just have to go $(".myClass").each(... I can't believe you can't even traverse DOM trees in a simple way. I've tried everything in my power just to get the width of those divs, i get error after error after error. How does one just get to manipulate those divs without evoking NodeLists and exotic errors? – RGBK Oct 10 '11 at 01:20
  • @RGBK - What RobG is saying is that the return variable from `.getElementsByTagName()` will be an *array* of elements, not an *element*. Note the **Elements** in the method name. This is important, since, in native JS, you would need to iterate over the array of elements to work on each one, not work on the result of the `getElementsByTagName()` itself. – Jared Farrish Oct 10 '11 at 01:28
  • got it. let me see what i can do with that. The edited code above actually gives me widths. It's broken the autopagerizer for now, and on top of that not getting errors for it. I'll get to that after i figured out how to replace getElementsByTagName with something more useful. – RGBK Oct 10 '11 at 01:31
  • @RGBK - If you have an `ID`, you can use `document.getElementById()`, or loop through the `.getElementsByTagName()` and find the one you need and *then* work on that element's reference. – Jared Farrish Oct 10 '11 at 01:34
  • @JaredFarrish Each ID is totally unique and generated by tumblr, no way i can predict them. And it's all loading in via this autopager. It's a very slippery slope with not much more then some hard core JS like the stuff above by Rob, which i'm going to try out now. – RGBK Oct 10 '11 at 01:42
  • I don't have enough experience with Tumblr to help in the specifics, so I apologize, but if you did have a known `ID` for an element, you could pick it out *exactly* using `document.getElementById()`. You might also be able to insert jQuery, maybe... – Jared Farrish Oct 10 '11 at 01:45
  • I appreciate the time you've taken with this function. I get what you're doing here. But I have a problem just as big as accessing an attribute, which is telling the function to dynamically work on newly loaded images, which i have no way of intelligently accessing as JS has no easy way of just point to things like jquery has. I'm no pro, but i can get by quite well (ie marckremers.com) but this is waaaay beyond me. – RGBK Oct 10 '11 at 02:02
  • If you clearly state what it is you are actually trying to do, much more specific help can be provided. e.g. *document.images* collection that is all the images in the document. You might be able to identify "newly loaded images" by finding out where they are added, they calling your function to "work" witih them from there. Note that images may not have a size until they start to load. If the browser isn't told their size, it has to get them first to find out. – RobG Oct 10 '11 at 02:07
  • Ok, I've edited the question to be as clear as possible. Thanks Rob – RGBK Oct 10 '11 at 02:57
  • You need a [cross browser method for getting the size of the viewport](http://www.jibbering.com/faq/#getWindowSize). You also need to get the size of the image, which if you don't know beforehand, you have to wait until it starts to download (or even finishes downloading) before you can get it - the browser can't tell you what it doesn't know. So you need to add an onload function to the image to resize it. Unfortunately users will see the image re-size unless you hide it first, wait for the load event, then resize and show it. – RobG Oct 10 '11 at 13:15
1

Admittedly I never knew about computed styles until I read this post, so unfortunately I can't really comment on what else has been said here. (going to read up on it after — I promise).

You're right about event delegation in that you can't bind a jQuery live() (or equivalent) to img load events as it's a 'simple' event and doesn't bubble. So afaik you do have to manually add the load event to each individual image.

The only real tricky part is making sure that you account for already cached images. Here's one approach.

I've recreated a stripped down, static version of your tumblr page with a button that appends another image, which is basically your addNextPage() call. Hope it helps.

http://dl.dropbox.com/u/15924676/syndex/index.html

<!DOCTYPE html>
<html>
<head>
    <title>Syndex</title>
    <script type="text/javascript" src="./Syndex_files/jquery-latest.min.js"></script>
    <link rel="stylesheet" type="text/css" href="./Syndex_files/style.css" media="screen">
</head>
<body>
<div>
    <input type="button" value="add image" />
</div>
<div id="posts">
    <div class="autopagerize_page_element">
    </div>
</div>
</body>
<script>

    var $window = $(window);
    var $pageImages;
    var images = [
        '<div id="10823012653" rel="http://www.tumblr.com/reblog/10823012653/ymaZUCKg" class="post photo"><div class="theImage"><img src="./Syndex_files/tumblr_lsb37adUwD1r4306n" alt="Olaf Breuning"><div class="kremers">original height 701</div></div></div>',
        '<div id="10822915844" rel="http://www.tumblr.com/reblog/10822915844/JknV8s3a" class="post photo"><div class="theImage"><img src="./Syndex_files/tumblr_lsb33m4S7j1r4306no1_400.png" alt="Jacqueline Casey, Graphic Designer for MIT 1963 - 1990"><div class="kremers">original height 500</div></div></div>',
        '<div id="10822870581" rel="http://www.tumblr.com/reblog/10822870581/oJMKWl9k" class="post photo"><div class="theImage"><img src="./Syndex_files/tumblr_lsb31sUYvQ1r4306n" alt="Vanessa Veasley x Supreme x Terry Richardson"><div class="kremers">original height 1280</div></div></div>',
        '<div id="10822380405" rel="http://www.tumblr.com/reblog/10822380405/AwsPNE5L" class="post photo"><div class="theImage"><img src="./Syndex_files/tumblr_lsb2ivLTWQ1r4306n" alt="Xavier Delory - Habitat"><div class="kremers">original height 857</div></div></div>',
        '<div id="10822233573" rel="http://www.tumblr.com/reblog/10822233573/9OTI6gLl" class="post photo"><div class="theImage"><img src="./Syndex_files/tumblr_lsb2d6sESW1r4306n" alt="Yellow Smoke Bomb"><div class="kremers">original height 900</div></div></div>',
        '<div id="10822153538" rel="http://www.tumblr.com/reblog/10822153538/GhQQOncG" class="post photo"><div class="theImage"><img src="./Syndex_files/tumblr_lsb2a3Gh2L1r4306n" alt="Karl Gerstner - Colour Sounds"><div class="kremers">original height 1024</div></div></div>',
        '<div id="10822119380" rel="http://www.tumblr.com/reblog/10822119380/mTyZ3yoh" class="post photo"><div class="theImage"><img src="./Syndex_files/tumblr_lsb28q4g7p1r4306n" alt="Karl Gerstner - Colour Sounds"><div class="kremers">original height 1024</div></div></div>',
        '<div id="10822031937" rel="http://www.tumblr.com/reblog/10822031937/OoqboZsY" class="post photo"><div class="theImage"><img src="./Syndex_files/tumblr_lsb258iApO1r4306n" alt="Cindy Sherman - Untitled Film Still #45"><div class="kremers">original height 920</div></div></div>',
        '<div id="10821751285" rel="http://www.tumblr.com/reblog/10821751285/LlXg7AsU" class="post photo"><div class="theImage"><img src="./Syndex_files/tumblr_lsb1u2045A1r4306n" alt="Jeff Koons - Rabbit (1986)"><div class="kremers">original height 1280</div></div></div>',
        '<div id="10821655695" rel="http://www.tumblr.com/reblog/10821655695/RBKyq24s" class="post photo"><div class="theImage"><img src="./Syndex_files/tumblr_lsb1q8whpQ1r4306n" alt="Disabled Car Access"><div class="kremers">original height 757</div>/div></div>',
        '<div id="10821572995" rel="http://www.tumblr.com/reblog/10821572995/JYWoYWR6" class="post photo"><div class="theImage"><img src="./Syndex_files/tumblr_lsb1mw5IU11r4306n" alt="Bin Bags"><div class="kremers">original height 725</div></div></div>',
        '<div id="10821503505" rel="http://www.tumblr.com/reblog/10821503505/hVLYhypW" class="post photo"><div class="theImage"><img src="./Syndex_files/tumblr_lsb1k3yEsf1r4306no1_400.png" alt="Untitled"><div class="kremers">original height 326</div></div></div>'
    ];

    $(document).ready(function() {

        $('input').click(function(e){
            e.preventDefault();

            if (images.length > 0) {
                // append first image in array to DOM
                $(images[0])
                    .appendTo('.autopagerize_page_element')
                        // select img elements from appended items
                        .find('img').each(function(e) {

                            // lets hide the description as well while we're at it
                            $(this).parent().find('.kremers').hide();

                            // hide image from the DOM
                            $(this).hide();

                            // check to see if our image has been cached
                            // source: https://stackoverflow.com/questions/3877027/jquery-callback-on-image-load-even-when-the-image-is-cached

                            $(this).one('load', function() {
                                imageLoadHandler($(this));
                            }).each(function() {
                                if(this.complete) {
                                    // (image is cached)
//                                  console.log("cached");
                                    $(this).load();
                                }
                            });
                        }
                );

                // remove first element from array
                images.shift();

                // update our reference to all nested images
                $pageImages = $('.autopagerize_page_element img');
            } else {
                // disable input (jQuery 1.6+)
                $(this).prop('disabled', true);
            }
        });

        $(window).resize(function(e){
            // TODO: look into throttling these calls as it doesn't need to be called so often
            // potentially with the use of something like jQuery throttle / debounce
            // http://benalman.com/projects/jquery-throttle-debounce-plugin/

            // add your resize code here
            $pageImages.each(function(){
                // resize all images to browser height
                $(this).height($window.height());
            });
        });
    });

    function imageLoadHandler($img){
        // resize to browser window height, even images that are initially smaller than browser window height
        $img.height($window.height());

        /*
        // OR...

        // check if this image is taller than our browser window
        if ($img.height() > $window.height()) {
            // resize to browser window height
            $img.height($window.height());
        } else {
            // our image is smaller than the browser height, we don't need to do anything
        }
        */

        // reveal the image in the DOM
        // (fade in, animate in, do whatever else you want here)
        $img.show();

        // finally show our description again
        $img.parent().find('.kremers').show();
    }

</script>
</html>
Community
  • 1
  • 1
Robin Pyon
  • 749
  • 1
  • 9
  • 19
  • Wow, thats super awesome Robin. I'm going to chew on this tomorrow. I wasn;t expecting a jquery solution either, really happy with this. Speak to you soon! Let's get a beer this week. – RGBK Oct 11 '11 at 00:44