2
\$\begingroup\$

I found a nice lightbox2-fork, which I tried to improve. After about six hours of work the code passes jslint. I also tried to change variable names for better understanding of what they are for.

What else can be improved there?

jsfiddle (yet unmodified but working CSS)

lpaste

$(function () {
  "use strict";

  var border,
    borderColor,
    content,
    contentHeight,
    counter,
    counterContainer,
    frameHeight,
    frameWidth,
    ie9,
    iOS,
    isNext,
    isPrev,
    items,
    keyNavigationDisabled,
    margins,
    nextItem,
    overlay,
    overlayColor,
    preload,
    prevItem,
    title,
    titleContainer,
    top,
    url,
    vcore,
    vwrap,
    windowHeight,
    wrapAround;

  // center on load
  function updateoverlay(notopzero) {
    notopzero = notopzero || false;

    if (notopzero !== true) {
      $(window).scrollTop(0);
    }

    titleContainer.html(title);
    content.find(">:first-child").addClass("lightbox");
    $(".lightbox").css("width", frameWidth).css("height", frameHeight).css("padding", border).css("background", borderColor);
    contentHeight = content.outerHeight();
    windowHeight = $(window).height();

    if (contentHeight + 80 < windowHeight) {
      margins = (windowHeight - contentHeight) / 2;
      content.css("margin-bottom", margins);
      content.css("margin-top", margins);
    } else {
      content.css("margin-bottom", "40px");
      content.css("margin-top", "40px");
    }

    content.animate({"opacity": "1"}, "slow");
  }

  // center on resize
  function updateoverlayresize() {
    if ($(".vbox-content").length) {
      contentHeight = content.height();
      windowHeight = $(window).height();

      if (contentHeight + 80 < windowHeight) {
        margins = (windowHeight - contentHeight) / 2;
        content.css("margin-bottom", margins);
        content.css("margin-top", margins);
      } else {
        content.css("margin-bottom", "40px");
        content.css("margin-top", "40px");
      }
    }
  }

  // load Ajax
  function loadAjax() {
    $.ajax({
      url: url,
      cache: false
    }).done(function (msg) {
      content.html('<div class="vbox-inline">' + msg + "</div>");
      updateoverlay(true);
    }).fail(function () {
      content.html('<div class="vbox-inline"><p>Error retrieving contents, please retry</div>');
      updateoverlay(true);
    });
  }

  // load iframe
  function loadIframe() {
    content.html('<iframe class="vbox-frame" src="' + url + '"></iframe>');
  // valid only for iframes in same url
  //  $(".vbox-frame").load(function () {
    updateoverlay();
  //  });
  }

  // load Vimeo
  function loadVimeo() {
    var part = url.split("/"),
      videoid = part[part.length - 1];

    content.html('<iframe class="vbox-frame" src="http://player.vimeo.com/video/' + videoid + '"></iframe>');
    updateoverlay();
  }

  // load YouTube
  function loadYoutube() {
    var part = url.split("/"),
      videoid = part[part.length - 1];

    content.html('<iframe class="vbox-frame" allowfullscreen src="http://www.youtube.com/embed/' + videoid + '"></iframe>');
    updateoverlay();
  }

  // load inline element
  function loadInline() {
    content.html('<div class="vbox-inline">' + $(url).html() + "</div>");
    updateoverlay();
  }

  // preload images
  function preloadFirst() {
    preload = $(".vbox-content").find("img");
    preload.one("load", function () {
      updateoverlay();
    }).each(function () {
      if (this.complete) {
        $(this).load();
      }
    });
  }

  $.fn.extend({
    vbox: function (overwriteOptions) {

      var defaults = {
        border: "0",
        borderColor: "#ffffff",
        counter: true,
        frameHeight: "",
        frameWidth: "",
        wrapAround: false
      },
        options = $.extend(defaults, overwriteOptions);

      return this.each(function () {
        var obj = $(this);

        obj.addClass("vbox-item");
        obj.data("frameWidth", options.frameWidth);
        obj.data("frameHeight", options.frameHeight);
        obj.data("border", options.border);
        obj.data("borderColor", options.borderColor);
        obj.data("counter", options.counter);
        obj.data("wrapAround", options.wrapAround);

        iOS = (navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false);

        ie9 = ((document.all && !window.atob) ? true : false);

        obj.click(function (e) {
          e.stopPropagation();
          e.preventDefault();

          obj = $(this);
          overlayColor = obj.data("overlay");
          frameWidth = obj.data("frameWidth");
          frameHeight = obj.data("frameHeight");
          border = obj.data("border");
          borderColor = obj.data("borderColor");
          isNext = false;
          isPrev = false;
          keyNavigationDisabled = false;
          url = obj.attr("href");
          top = $(window).scrollTop();
          top = -top;

          // check if there is a next or previous image
          function checknav() {
            counter = obj.data("counter");
            wrapAround = obj.data("wrapAround");
            items = $('.vbox-item[data-vbox="' + obj.data("vbox") + '"]');

            if (items.length > 0 && counter === true) {
              counterContainer.html(items.index(obj) + 1 + " / " + items.length);
              counterContainer.fadeIn();
            } else {
              counterContainer.fadeOut();
            }

            nextItem = items.eq(items.index(obj) + 1);
            prevItem = items.eq(items.index(obj) - 1);

            if (obj.attr("title")) {
              title = obj.attr("title");
              titleContainer.fadeIn();
            } else {
              title = "";
              titleContainer.fadeOut();
            }

            if (wrapAround === true) {
              isNext = true;
              isPrev = true;
              if (nextItem.length < 1) {
                nextItem = items.eq(0);
              }
              if (items.index(obj) < 1) {
                prevItem = items.eq(items.index(items.length));
              }
            } else {
              if (nextItem.length > 0) {
                $(".vbox-next").css("display", "block");
                isNext = true;
              } else {
                $(".vbox-next").css("display", "none");
                isNext = false;
              }
              if (items.index(obj) > 0) {
                $(".vbox-prev").css("display", "block");
                isPrev = true;
              } else {
                $(".vbox-prev").css("display", "none");
                isPrev = false;
              }
            }
          }

          $("body").wrapInner('<div class="vwrap"></div>');

          vwrap = $(".vwrap");

          vcore = '<div class="vbox-overlay" style="background:' + overlayColor + '"><div class="vbox-preloader"><i class="fa fa-spinner fa-spin"></i></div><div class="vbox-container"><div class="vbox-content"></div></div><div class="vbox-title"></div><div class="vbox-num">0/0</div><div class="vbox-close"><i class="fa fa-times"></i></div><div class="vbox-next"><i class="fa fa-chevron-right"></i></div><div class="vbox-prev"><i class="fa fa-chevron-left"></i></div></div>';

          $("body").append(vcore);

          //container = $(".vbox-container");
          content = $(".vbox-content");
          counterContainer = $(".vbox-num");
          overlay = $(".vbox-overlay");
          titleContainer = $(".vbox-title");

          content.html("");

          content.css("opacity", "0");

          checknav();

          overlay.css("min-height", $(window).outerHeight() + 130);

          if (ie9) {
            overlay.animate({opacity: 1}, 250, function () {
              overlay.css({
                "min-height": $(window).outerHeight(),
                height: "auto"
              });
              if (obj.data("type") === "iframe") {
                loadIframe();
              } else if (obj.data("type") === "inline") {
                loadInline();
              } else if (obj.data("type") === "ajax") {
                loadAjax();
              } else if (obj.data("type") === "vimeo") {
                loadVimeo();
              } else if (obj.data("type") === "youtube") {
                loadYoutube();
              } else {
                content.html('<img src="' + url + '">');
                preloadFirst();
              }
            });
          } else {
            overlay.bind("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function () {
              overlay.css({
                "min-height": $(window).outerHeight(),
                height: "auto"
              });
              if (obj.data("type") === "iframe") {
                loadIframe();
              } else if (obj.data("type") === "inline") {
                loadInline();
              } else if (obj.data("type") === "ajax") {
                loadAjax();
              } else if (obj.data("type") === "vimeo") {
                loadVimeo();
              } else if (obj.data("type") === "youtube") {
                loadYoutube();
              } else {
                content.html('<img src="' + url + '">');
                preloadFirst();
              }
            });
            overlay.css("opacity", "1");
          }

          if (iOS) {
            vwrap.css({
              "opacity": "0",
              "position": "fixed",
              "top": top
            }).data("top", top);
          } else {
            vwrap.css({
              "position": "fixed",
              "top": top
            }).data("top", top);
            $(window).scrollTop(0);
          }

          // keyboard navigation
          $("body").keydown(function (e) {
            if (keyNavigationDisabled) {
              return;
            }

            if (e.keyCode === 27) {
              $(".vbox-close").click();
            }

            if (e.keyCode === 37 && isPrev === true) {
              border = prevItem.data("border");
              borderColor = prevItem.data("borderColor");
              frameWidth = prevItem.data("frameWidth");
              frameHeight = prevItem.data("frameHeight");
              keyNavigationDisabled = true;
              overlayColor = prevItem.data("overlay");
              url = prevItem.attr("href");

              if (prevItem.attr("title")) {
                title = prevItem.attr("title");
              } else {
                title = "";
              }

              if (overlayColor === undefined) {
                overlayColor = "";
              }

              overlay.css("min-height", $(window).outerHeight() + 130);

              content.animate({opacity: 0}, 500, function () {
                overlay.css("min-height", $(window).outerHeight()).css("background", overlayColor);

                if (prevItem.data("type") === "iframe") {
                  loadIframe();
                } else if (prevItem.data("type") === "inline") {
                  loadInline();
                } else if (prevItem.data("type") === "ajax") {
                  loadAjax();
                } else if (prevItem.data("type") === "youtube") {
                  loadYoutube();
                } else if (prevItem.data("type") === "vimeo") {
                  loadVimeo();
                } else {
                  content.html('<img src="' + url + '">');
                  preloadFirst();
                }

                obj = prevItem;

                checknav();

                keyNavigationDisabled = false;
              });
            }

            if (e.keyCode === 39 && isNext === true) {
              border = nextItem.data("border");
              borderColor = nextItem.data("borderColor");
              frameWidth = nextItem.data("frameWidth");
              frameHeight = nextItem.data("frameHeight");
              keyNavigationDisabled = true;
              overlayColor = nextItem.data("overlay");
              url = nextItem.attr("href");

              if (nextItem.attr("title")) {
                title = nextItem.attr("title");
              } else {
                title = "";
              }

              if (overlayColor === undefined) {
                overlayColor = "";
              }

              overlay.css("min-height", $(window).outerHeight() + 130);

              content.animate({opacity: 0}, 500, function () {
                overlay.css("min-height", $(window).outerHeight()).css("background", overlayColor);

                if (nextItem.data("type") === "iframe") {
                  loadIframe();
                } else if (nextItem.data("type") === "inline") {
                  loadInline();
                } else if (nextItem.data("type") === "ajax") {
                  loadAjax();
                } else if (nextItem.data("type") === "youtube") {
                  loadYoutube();
                } else if (nextItem.data("type") === "vimeo") {
                  loadVimeo();
                } else {
                  content.html('<img src="' + url + '">');
                  preloadFirst();
                }

                obj = nextItem;

                checknav();

                keyNavigationDisabled = false;
              });
            }
          });

          // next image
          $(".vbox-next").click(function () {
            border = nextItem.data("border");
            borderColor = nextItem.data("borderColor");
            frameWidth = nextItem.data("frameWidth");
            frameHeight = nextItem.data("frameHeight");
            overlayColor = nextItem.data("overlay");
            url = nextItem.attr("href");

            if (nextItem.attr("title")) {
              title = nextItem.attr("title");
            } else {
              title = "";
            }

            if (overlayColor === undefined) {
              overlayColor = "";
            }

            overlay.css("min-height", $(window).outerHeight() + 130);

            content.animate({opacity: 0}, 500, function () {
              overlay.css("min-height", $(window).outerHeight()).css("background", overlayColor);

              if (nextItem.data("type") === "iframe") {
                loadIframe();
              } else if (nextItem.data("type") === "inline") {
                loadInline();
              } else if (nextItem.data("type") === "ajax") {
                loadAjax();
              } else if (nextItem.data("type") === "youtube") {
                loadYoutube();
              } else if (nextItem.data("type") === "vimeo") {
                loadVimeo();
              } else {
                content.html('<img src="' + url + '">');
                preloadFirst();
              }

              obj = nextItem;

              checknav();
            });
          });

          // previous image
          $(".vbox-prev").click(function () {
            border = prevItem.data("border");
            borderColor = prevItem.data("borderColor");
            frameWidth = prevItem.data("frameWidth");
            frameHeight = prevItem.data("frameHeight");
            overlayColor = prevItem.data("overlay");
            url = prevItem.attr("href");

            if (prevItem.attr("title")) {
              title = prevItem.attr("title");
            } else {
              title = "";
            }

            if (overlayColor === undefined) {
              overlayColor = "";
            }

            overlay.css("min-height", $(window).outerHeight() + 130);

            content.animate({opacity: 0}, 500, function () {
              overlay.css("min-height", $(window).outerHeight()).css("background", overlayColor);

              if (prevItem.data("type") === "iframe") {
                loadIframe();
              } else if (prevItem.data("type") === "inline") {
                loadInline();
              } else if (prevItem.data("type") === "ajax") {
                loadAjax();
              } else if (prevItem.data("type") === "youtube") {
                loadYoutube();
              } else if (prevItem.data("type") === "vimeo") {
                loadVimeo();
              } else {
                content.html('<img src="' + url + '">');
                preloadFirst();
              }

              obj = prevItem;

              checknav();
            });
          });

          // close
          $(".vbox-close, .vbox-overlay").click(function (e) {

            if (!$(e.target).is(".lightbox, .vbox-prev, .vbox-prev .fa, .vbox-next, .vbox-next .fa, .lightbox *")) {
              if (ie9) {
                overlay.animate({opacity: 0}, 500, function () {
                  overlay.remove();
                  $(".vwrap").children().unwrap();
                  $(window).scrollTop(-top);
                  keyNavigationDisabled = false;
                });
              } else {
                overlay.unbind("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd");
                overlay.bind("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function () {
                  overlay.remove();

                  if (iOS) {
                    $(".vwrap").bind("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function () {
                      $(".vwrap").children().unwrap();
                      $(window).scrollTop(-top);
                    });
                    $(".vwrap").css("opacity", "1");
                  } else {
                    $(".vwrap").children().unwrap();
                    $(window).scrollTop(-top);
                  }

                  keyNavigationDisabled = false;
                });

                overlay.css("opacity", "0");
              }
            }
          });

          return false;
        });
      });
    }
  });

  $(window).resize(function () {
    updateoverlayresize();
  });

});
\$\endgroup\$
1
  • \$\begingroup\$ Please don't updated the original embedded code based on answers. You may still update the linked code. \$\endgroup\$
    – Jamal
    Jul 14, 2014 at 23:19

1 Answer 1

1
\$\begingroup\$

Interesting question,

this code has a serious bit of copy pastage:

  • Lines 328-365 are identical to 468-504
  • Lines 375-412 are identical to 423-459

And, these 2 large blocks of code are very similar to each other ( prevItem <> nextItem ). You should DRY this up.

Also this block is repeated in the code:

if (prevItem.data("type") === "iframe") {
  loadIframe();
} else if (prevItem.data("type") === "inline") {
  loadInline();
} else if (prevItem.data("type") === "ajax") {
  loadAjax();
} else if (prevItem.data("type") === "youtube") {
  loadYoutube();
} else if (prevItem.data("type") === "vimeo") {
  loadVimeo();
} else {
  content.html('<img src="' + url + '">');
  preloadFirst();
}

I would say in general you need to re-review the code with DRYness in mind, this:

if (contentHeight + 80 < windowHeight) {
  margins = (windowHeight - contentHeight) / 2;
  content.css("margin-bottom", margins);
  content.css("margin-top", margins);
} else {
  content.css("margin-bottom", "40px");
  content.css("margin-top", "40px");
}

could be

if (contentHeight + 80 < windowHeight) {
  margins = (windowHeight - contentHeight) / 2;
} else {
  margins = '40px' ;
}
content.css("margin-bottom", margins);
content.css("margin-top", margins);

or if you are into ternaries:

margins = (contentHeight + 80 < windowHeight) ? (windowHeight - contentHeight) / 2 : '40px';
content.css("margin-bottom", margins);
content.css("margin-top", margins);

This piece of code is also copy pasted btw.

You should also clean up the commented code:

  // load iframe <- Seriously, how is this comment helping ??
  function loadIframe() {
    content.html('<iframe class="vbox-frame" src="' + url + '"></iframe>');
  // valid only for iframes in same url
  //  $(".vbox-frame").load(function () {
    updateoverlay();
  //  });
  }

Should be

  function loadIframe() {
    content.html('<iframe class="vbox-frame" src="' + url + '"></iframe>');
    updateoverlay();
  }

Also, consider, should updateoverlay be called in every single loadxxx function, or should it be called after the switch statement that calls these functions?

Finally. if you are working on naming; updateoverlay -> updateOverlay (lowerCamelCase)

\$\endgroup\$
3
  • \$\begingroup\$ Here's the updated jsfiddle – @konijn What about all those variables in the beginning of the script? What does the "return false;" on the very bottom of the script? \$\endgroup\$
    – fooness
    Jul 14, 2014 at 23:28
  • \$\begingroup\$ @fooness JsHint did not complain about unused variables so that is okay. I think the return false is part of an even handler, and thus standard fare. \$\endgroup\$
    – konijn
    Jul 15, 2014 at 13:06
  • \$\begingroup\$ Great, thanks. Would you have an ideas, on how I could improve this code-block, you posted as first code? That's also diffictult because I have not always prevItem, but also nextItem and some others. \$\endgroup\$
    – fooness
    Jul 15, 2014 at 13:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.