text: /*!
   * jQuery scrollintoview() plugin and :scrollable selector filter
   *
   * Version 1.8 (14 Jul 2011)
   * Requires jQuery 1.4 or newer
   *
   * Copyright (c) 2011 Robert Koritnik
   * Licensed under the terms of the MIT license
   * http://www.opensource.org/licenses/mit-license.php
   */
   
  (function ($) {
      var converter = {
          vertical: { x: false, y: true },
          horizontal: { x: true, y: false },
          both: { x: true, y: true },
          x: { x: true, y: false },
          y: { x: false, y: true }
      };
   
      var settings = {
          duration: "fast",
          direction: "both"
      };
   
      var rootrx = /^(?:html)$/i;
   
      // gets border dimensions
      var borders = function (domElement, styles) {
          styles = styles || (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(domElement, null) : domElement.currentStyle);
          var px = document.defaultView && document.defaultView.getComputedStyle ? true : false;
          var b = {
              top: (parseFloat(px ? styles.borderTopWidth : $.css(domElement, "borderTopWidth")) || 0),
              left: (parseFloat(px ? styles.borderLeftWidth : $.css(domElement, "borderLeftWidth")) || 0),
              bottom: (parseFloat(px ? styles.borderBottomWidth : $.css(domElement, "borderBottomWidth")) || 0),
              right: (parseFloat(px ? styles.borderRightWidth : $.css(domElement, "borderRightWidth")) || 0)
          };
          return {
              top: b.top,
              left: b.left,
              bottom: b.bottom,
              right: b.right,
              vertical: b.top + b.bottom,
              horizontal: b.left + b.right
          };
      };
   
      var dimensions = function ($element) {
          var win = $(window);
          var isRoot = rootrx.test($element[0].nodeName);
          return {
              border: isRoot ? { top: 0, left: 0, bottom: 0, right: 0} : borders($element[0]),
              scroll: {
                  top: (isRoot ? win : $element).scrollTop(),
                  left: (isRoot ? win : $element).scrollLeft()
              },
              scrollbar: {
                  right: isRoot ? 0 : $element.innerWidth() - $element[0].clientWidth,
                  bottom: isRoot ? 0 : $element.innerHeight() - $element[0].clientHeight
              },
              rect: (function () {
                  var r = $element[0].getBoundingClientRect();
                  return {
                      top: isRoot ? 0 : r.top,
                      left: isRoot ? 0 : r.left,
                      bottom: isRoot ? $element[0].clientHeight : r.bottom,
                      right: isRoot ? $element[0].clientWidth : r.right
                  };
              })()
          };
      };
   
      $.fn.extend({
          scrollintoview: function (options) {
              /// <summary>Scrolls the first element in the set into view by scrolling its closest scrollable parent.</summary>
              /// <param name="options" type="Object">Additional options that can configure scrolling:
              ///        duration (default: "fast") - jQuery animation speed (can be a duration string or number of milliseconds)
              ///        direction (default: "both") - select possible scrollings ("vertical" or "y", "horizontal" or "x", "both")
              ///        complete (default: none) - a function to call when scrolling completes (called in context of the DOM element being scrolled)
              /// </param>
              /// <return type="jQuery">Returns the same jQuery set that this function was run on.</return>
   
              options = $.extend({}, settings, options);
              options.direction = converter[typeof (options.direction) === "string" && options.direction.toLowerCase()] || converter.both;
   
              var dirStr = "";
              if (options.direction.x === true) dirStr = "horizontal";
              if (options.direction.y === true) dirStr = dirStr ? "both" : "vertical";
   
              var el = this.eq(0);
              var scroller = el.closest(":scrollable(" + dirStr + ")");
   
              // check if there's anything to scroll in the first place
              if (scroller.length > 0)
              {
                  scroller = scroller.eq(0);
   
                  var dim = {
                      e: dimensions(el),
                      s: dimensions(scroller)
                  };
   
                  var rel = {
                      top: dim.e.rect.top - (dim.s.rect.top + dim.s.border.top),
                      bottom: dim.s.rect.bottom - dim.s.border.bottom - dim.s.scrollbar.bottom - dim.e.rect.bottom,
                      left: dim.e.rect.left - (dim.s.rect.left + dim.s.border.left),
                      right: dim.s.rect.right - dim.s.border.right - dim.s.scrollbar.right - dim.e.rect.right
                  };
   
                  var animOptions = {};
   
                  // vertical scroll
                  if (options.direction.y === true)
                  {
                      if (rel.top < 0)
                      {
                          animOptions.scrollTop = dim.s.scroll.top + rel.top;
                      }
                      else if (rel.top > 0 && rel.bottom < 0)
                      {
                          animOptions.scrollTop = dim.s.scroll.top + Math.min(rel.top, -rel.bottom);
                      }
                  }
   
                  // horizontal scroll
                  if (options.direction.x === true)
                  {
                      if (rel.left < 0)
                      {
                          animOptions.scrollLeft = dim.s.scroll.left + rel.left;
                      }
                      else if (rel.left > 0 && rel.right < 0)
                      {
                          animOptions.scrollLeft = dim.s.scroll.left + Math.min(rel.left, -rel.right);
                      }
                  }
   
                  // scroll if needed
                  if (!$.isEmptyObject(animOptions))
                  {
                      if (rootrx.test(scroller[0].nodeName))
                      {
                          scroller = $("html,body");
                      }
                      scroller
                          .animate(animOptions, options.duration)
                          .eq(0) // we want function to be called just once (ref. "html,body")
                          .queue(function (next) {
                              $.isFunction(options.complete) && options.complete.call(scroller[0]);
                              next();
                          });
                  }
                  else
                  {
                      // when there's nothing to scroll, just call the "complete" function
                      $.isFunction(options.complete) && options.complete.call(scroller[0]);
                  }
              }
   
              // return set back
              return this;
          }
      });
   
      var scrollValue = {
          auto: true,
          scroll: true,
          visible: false,
          hidden: false
      };
   
      $.extend($.expr[":"], {
          scrollable: function (element, index, meta, stack) {
              var direction = converter[typeof (meta[3]) === "string" && meta[3].toLowerCase()] || converter.both;
              var styles = (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(element, null) : element.currentStyle);
              var overflow = {
                  x: scrollValue[styles.overflowX.toLowerCase()] || false,
                  y: scrollValue[styles.overflowY.toLowerCase()] || false,
                  isRoot: rootrx.test(element.nodeName)
              };
   
              // check if completely unscrollable (exclude HTML element because it's special)
              if (!overflow.x && !overflow.y && !overflow.isRoot)
              {
                  return false;
              }
   
              var size = {
                  height: {
                      scroll: element.scrollHeight,
                      client: element.clientHeight
                  },
                  width: {
                      scroll: element.scrollWidth,
                      client: element.clientWidth
                  },
                  // check overflow.x/y because iPad (and possibly other tablets) don't dislay scrollbars
                  scrollableX: function () {
                      return (overflow.x || overflow.isRoot) && this.width.scroll > this.width.client;
                  },
                  scrollableY: function () {
                      return (overflow.y || overflow.isRoot) && this.height.scroll > this.height.client;
                  }
              };
              return direction.y && size.scrollableY() || direction.x && size.scrollableX();
          }
      });
  })(jQuery);
  