Explorar o código

HUE-1801 [fb] Introduce pages with scroll when viewing a file

Introduced the concept of pages
Scroll + stream for smaller text files
Range of pages for bigger text and all binary files
Enrico Berti %!s(int64=11) %!d(string=hai) anos
pai
achega
33c43c7b3a

+ 437 - 172
apps/filebrowser/src/filebrowser/templates/display.mako

@@ -31,89 +31,108 @@
 ${ commonheader(_('%(filename)s - File Viewer') % dict(filename=truncate(filename)), 'filebrowser', user) | n,unicode }
 ${ fb_components.menubar() }
 
+<script src="/static/ext/js/jquery/plugins/jquery.visible.min.js" type="text/javascript" charset="utf-8"></script>
+
+<style type="text/css">
+  #fileArea {
+    overflow: auto;
+    background-color: #F5F5F5;
+    position: relative;
+  }
+
+  #fileArea.loading {
+    opacity: .7;
+  }
+
+  #loader {
+    position: fixed;
+    margin-top: 40px;
+    font-size: 50px;
+    text-align: center;
+    width: 140px;
+    height: 140px;
+    line-height: 140px;
+    -webkit-border-radius: 20px;
+    -moz-border-radius: 20px;
+    border-radius: 20px;
+  }
+
+  .binary {
+    font-family: "Courier New", Courier, monospace;
+  }
+
+  pre {
+    border: none;
+  }
+
+  pre a {
+    color: #444;
+    cursor: default;
+  }
+
+  pre a:hover {
+    color: #444;
+    text-decoration: none;
+  }
+</style>
+
 <div class="container-fluid">
   <div class="row-fluid">
     <div class="span2">
       ${ fb_components.file_sidebar(path_enc, dirname_enc, stats, view) }
     </div>
     <div class="span10">
-      <div class="card card-small">
-      % if breadcrumbs:
-        ${fb_components.breadcrumbs(path, breadcrumbs)}
-      %endif
-        <div class="card-body">
-          <p>
-        % if stats['size'] == 0:
-          <div class="center empty-wrapper">
-            <i class="fa fa-frown-o"></i>
-            <h1>${_('The current file is empty.')}</h1>
-            <br />
-          </div>
-        % else:
-          % if not view['compression'] or view['compression'] in ("none", "avro"):
-          <div class="pagination">
-            <ul>
-              <li class="first-block prev disabled"><a href="javascript:void(0);" data-bind="click: firstBlock">${_('First Block')}</a></li>
-              <li class="previous-block disabled"><a href="javascript:void(0);" data-bind="click: previousBlock">${_('Previous Block')}</a></li>
-              <li class="next-block"><a href="javascript:void(0);" data-bind="click: nextBlock">${_('Next Block')}</a></li>
-              <li class="last-block next"><a href="javascript:void(0);" data-bind="click: lastBlock">${_('Last Block')}</a></li>
-            </ul>
-
-            <form action="${url('filebrowser.views.view', path=path_enc)}" method="GET" class="form-inline pull-right">
-              <span>${_('Viewing Bytes:')}</span>
-              <input type="text" name="begin" value="${view['offset'] + 1}" data-bind="value: begin" class="input-mini" />
-              -
-              <input type="text" name="end" value="${view['end']}" data-bind="value: end" class="input-mini" /> of
-              <span>${stats['size']}</span>
-              <span>${_('(%(length)s B block size)' % dict(length=view['length']))}</span>
-              % if view['mode']:
-                <input type="hidden" name="mode" value="${view['mode']}"/>
-              % endif
-            </form>
+      <div class="card card-small" style="margin-bottom: 5px">
+        % if not view['compression'] or view['compression'] in ("none", "avro"):
+          <div class="pull-right" style="margin-right: 20px; margin-top: 14px">
+            <div class="form-inline" style="display: inline">
+              <span>${_('Page')}</span>
+              <input type="text" data-bind="value: page, valueUpdate: 'afterkeydown', event: { change: pageChanged }" style="width: 40px; text-align: center"/>
+              <span data-bind="visible: totalPages() > MAX_PAGES_TO_ENABLE_SCROLLING || viewModel.mode() == 'binary'">
+              to <input type="text" data-bind="value: upperPage, valueUpdate: 'afterkeydown', event: { change: upperPageChanged }" style="width: 40px; text-align: center"/></span>
+              of <span data-bind="text: totalPages"></span>
+            </div>
+            <div class="pagination" style="display: inline;">
+              <ul style="margin-bottom: -10px; margin-left: 10px">
+                <li class="first-page prev disabled"><a href="javascript:void(0);" data-bind="click: firstPage" title="${_('First page')}"><i class="fa fa-fast-backward"></i></a></li>
+                <li class="previous-page disabled"><a href="javascript:void(0);" data-bind="click: previousPage" title="${_('Previous page')}"><i class="fa fa-backward"></i></a></li>
+                <li class="next-page"><a href="javascript:void(0);" data-bind="click: nextPage" title="${_('Next page')}"><i class="fa fa-forward"></i></a></li>
+                <li class="last-page next"><a href="javascript:void(0);" data-bind="click: lastPage" title="${_('Last page')}"><i class="fa fa-fast-forward"></i></a></li>
+              </ul>
+            </div>
           </div>
-          % endif
-
-          %if 'contents' in view:
-            % if view['masked_binary_data']:
-              <div class="alert-message warning">${_("Warning: some binary data has been masked out with '&#xfffd'.")}</div>
-            % endif
-          % endif
+        % endif
+        % if breadcrumbs:
+          ${fb_components.breadcrumbs(path, breadcrumbs)}
+        %endif
+        <div class="card-body">
+        <p>
+          % if stats['size'] == 0:
+            <div class="center empty-wrapper">
+              <i class="fa fa-frown-o"></i>
 
-          <div>
-          % if 'contents' in view:
-            <div id="file-contents"><pre>${view['contents']}</pre></div>
+              <h1>${_('The current file is empty.')}</h1>
+              <br/>
+            </div>
           % else:
-            <table>
-              % for offset, words, masked in view['xxd']:
-              <tr>
-                <td>${stringformat(offset, "07x")}:&nbsp;</td>
-                <td>
-                  % for word in words:
-                    % for byte in word:
-                      ${stringformat(byte, "02x")}
-                    % endfor
-                  % endfor
-                </td>
-                <td>
-                  &nbsp;&nbsp;${masked}
-                </td>
-              </tr>
-              % endfor
-            </table>
+          %if 'contents' in view and view['masked_binary_data']:
+            <div class="alert alert-warning">${_("Warning: some binary data has been masked out with '&#xfffd'.")}</div>
           % endif
-          </div>
-
-          % if not view['compression'] or view['compression'] in ("none", "avro"):
-            <div class="pagination">
-              <ul>
-                <li class="first-block prev disabled"><a href="javascript:void(0);" data-bind="click: firstBlock">${_('First Block')}</a></li>
-                <li class="previous-block disabled"><a href="javascript:void(0);" data-bind="click: previousBlock">${_('Previous Block')}</a></li>
-                <li class="next-block"><a href="javascript:void(0);" data-bind="click: nextBlock">${_('Next Block')}</a></li>
-                <li class="last-block next"><a href="javascript:void(0);" data-bind="click: lastBlock">${_('Last Block')}</a></li>
-              </ul>
+            <div id="fileArea" data-bind="css: {'loading': isLoading}">
+              <div id="loader" data-bind="visible: isLoading">
+                <!--[if !IE]><!--><i class="fa fa-spinner fa-spin"></i><!--<![endif]-->
+                <!--[if IE]><img src="/static/art/spinner.gif"/><![endif]-->
+              </div>
+              % if 'contents' in view:
+                <pre></pre>
+              % else:
+                <table class="binary">
+                  <tbody>
+                  </tbody>
+                </table>
+              % endif
             </div>
           % endif
-        % endif
           </p>
         </div>
       </div>
@@ -123,118 +142,364 @@ ${ fb_components.menubar() }
 
 <script src="/static/ext/js/knockout-min.js" type="text/javascript" charset="utf-8"></script>
 
-  <script type="text/javascript" charset="utf-8">
-    function displayViewModel(base_url, compression, mode, begin, end, length, size, max_size) {
-      var self = this;
+<script type="text/javascript" charset="utf-8">
 
-      self.base_url = ko.observable(base_url);
-      self.compression = ko.observable(compression);
-      self.mode = ko.observable(mode);
-      self.begin = ko.observable(begin);
-      self.end = ko.observable(end);
-      self.length = ko.observable(length);
-      self.size = ko.observable(size);
+<%
+  MAX_ALLOWED_PAGES_PER_REQUEST = 255
+%>
 
-      self.offset = ko.computed(function() {
-        return self.begin() - 1;
-      });
+function displayViewModel(params) {
+  var self = this;
 
-      self.url = ko.computed(function() {
-        return self.base_url()
-          + "?offset=" + self.offset()
-          + "&length=" + self.length()
-          + "&compression="+ self.compression()
-          + "&mode=" + self.mode();
-      });
+  self.MAX_ALLOWED_PAGES_PER_REQUEST = ${MAX_ALLOWED_PAGES_PER_REQUEST};
+  self.MAX_PAGES_TO_ENABLE_SCROLLING = 300;
+  self.PAGES_PER_CHUNK = 50;
 
-      var change_length = function() {
-        var length = self.end() - self.offset();
-        if (length > max_size) {
-          length = max_size;
-        }
-        self.length(length);
-      };
-      self.begin.subscribe(change_length);
-      self.end.subscribe(change_length);
-
-      var reloading = false;
-      self.reload = function() {
-        if (!reloading) {
-          reloading = true;
-          window.location.href = self.url();
-        }
-      };
-
-      self.toggleDisables = function() {
-        if (self.offset() + self.length() >= self.size()) {
-          $(".next-block").addClass("disabled");
-          $(".last-block").addClass("disabled");
-        } else {
-          $(".next-block").removeClass("disabled");
-          $(".last-block").removeClass("disabled");
-        }
+  self.base_url = ko.observable(params.base_url);
+  self.compression = ko.observable(params.compression);
+  self.mode = ko.observable(params.mode);
+  self.begin = ko.observable(params.begin);
+  self.end = ko.observable(params.end);
+  self.length = ko.observable(params.length);
+  self.size = ko.observable(params.size);
+  self.page = ko.observable(1);
+  self.isLoading = ko.observable(true);
 
-        if (self.offset() <= 0) {
-          $(".first-block").addClass("disabled");
-          $(".previous-block").addClass("disabled");
-        } else {
-          $(".first-block").removeClass("disabled");
-          $(".previous-block").removeClass("disabled");
-        }
-      };
+  self.totalPages = ko.computed(function () {
+    return Math.max(Math.floor(self.size() / self.length()), 1);
+  });
+
+  self.upperPage = ko.observable(Math.min(self.totalPages(), 50));
+
+  self.begin = ko.computed(function () {
+    return (self.page() - 1) * self.length();
+  });
+
+  self.offset = ko.computed(function () {
+    return ((self.page() - 1) * self.length()) - 1;
+  });
+
+  self.url = ko.computed(function () {
+    return self.base_url()
+            + "?offset=" + self.offset()
+            + "&length=" + self.length()
+            + "&compression=" + self.compression()
+            + "&mode=" + self.mode();
+  });
+
+  self.jsonParams = ko.computed(function () {
+    return {
+      offset: self.begin(),
+      length: self.length() * (self.upperPage() - self.page() + 1),
+      compression: self.compression(),
+      mode: self.mode()
+    }
+  });
+
+  self.toggleDisables = function () {
+    $(".next-page").removeClass("disabled");
+    $(".last-page").removeClass("disabled");
+    $(".first-page").removeClass("disabled");
+    $(".previous-page").removeClass("disabled");
+
+    if (self.page() == self.totalPages() || self.upperPage() == self.totalPages()) {
+      $(".next-page").addClass("disabled");
+      $(".last-page").addClass("disabled");
+    }
+    if (self.page() == 1) {
+      $(".first-page").addClass("disabled");
+      $(".previous-page").addClass("disabled");
+    }
+  };
+
+  self.pageChanged = function () {
+    self.page(self.page() * 1);
+    self.upperPage(self.upperPage() * 1);
+    if (self.page() > self.totalPages()) {
+      self.page(self.totalPages());
+    }
+    if (self.page() < 1 || !$.isNumeric(self.page())) {
+      self.page(1);
+    }
+    if (self.page() > self.upperPage()) {
+      self.upperPage(self.page());
+    }
+    changePage();
+  };
 
-      self.begin.subscribe(self.toggleDisables);
-      self.end.subscribe(self.toggleDisables);
+  self.upperPageChanged = function () {
+    self.page(self.page() * 1);
+    self.upperPage(self.upperPage() * 1);
+    if (self.upperPage() > self.totalPages()) {
+      self.upperPage(self.totalPages());
+    }
+    if (self.upperPage() < 1 || !$.isNumeric(self.upperPage())) {
+      self.upperPage(1);
+    }
+    if (self.upperPage() < self.page()) {
+      self.page(self.upperPage());
+    }
+    if (self.upperPage() - self.page() > self.MAX_ALLOWED_PAGES_PER_REQUEST) {
+      self.upperPage(self.page() + self.MAX_ALLOWED_PAGES_PER_REQUEST);
+      $.jHueNotify.info("${_('Sorry, you cannot request for more than %s pages.' % MAX_ALLOWED_PAGES_PER_REQUEST)}");
+    }
+    changePage();
+  };
 
-      var changeBlock = function(begin, end) {
-        if (begin < self.size() && end > 0 && end > begin && !reloading) {
-          self.begin(begin);
-          self.end(end);
-          self.toggleDisables();
-          self.reload();
+  self.page.subscribe(function (value) {
+    self.toggleDisables();
+  });
+
+  self.upperPage.subscribe(function (value) {
+    self.toggleDisables();
+  });
+
+  var changePage = function () {
+    getContent(function () {
+      if (viewModel.totalPages() >= viewModel.MAX_PAGES_TO_ENABLE_SCROLLING || viewModel.mode() == "binary") {
+        window.location.hash = "#p" + viewModel.page() + (viewModel.page() != viewModel.upperPage() ? "-p" + viewModel.upperPage() : "");
+        $("#fileArea").scrollTop(0);
+      }
+      else {
+        window.location.hash = "#page" + viewModel.page();
+      }
+    });
+  };
+
+  self.nextPage = function () {
+    self.page(self.page() * 1);
+    self.upperPage(self.upperPage() * 1);
+    if (!($(".next-page").hasClass("disabled"))) {
+      if (viewModel.page() == viewModel.upperPage()) {
+        viewModel.page(viewModel.page() + 1);
+        viewModel.upperPage(viewModel.upperPage() + 1);
+      }
+      else {
+        var _difference = self.upperPage() - self.page();
+        self.page(self.upperPage() + 1);
+        self.upperPage(Math.min(self.page() + _difference, self.totalPages()));
+      }
+      changePage();
+    }
+  };
+
+  self.previousPage = function () {
+    self.page(self.page() * 1);
+    self.upperPage(self.upperPage() * 1);
+    if (!($(".previous-page").hasClass("disabled"))) {
+      if (viewModel.page() == viewModel.upperPage()) {
+        viewModel.page(viewModel.page() - 1);
+        viewModel.upperPage(viewModel.upperPage() - 1);
+      }
+      else {
+        var _difference = self.upperPage() - self.page();
+        self.upperPage(self.page() - 1);
+        self.page(Math.max(self.page() - _difference - 1, 1));
+      }
+      changePage();
+    }
+  };
+
+  self.lastPage = function () {
+    if (!($(".last-page").hasClass("disabled"))) {
+      var _page = viewModel.totalPages();
+      if (_page > 50) {
+        _page = Math.min(viewModel.totalPages() - viewModel.totalPages()%50 + 1, viewModel.totalPages());
+      }
+      viewModel.page(_page);
+      viewModel.upperPage(viewModel.totalPages());
+      changePage();
+    }
+  };
+
+  self.firstPage = function () {
+    if (!($(".first-page").hasClass("disabled"))) {
+      viewModel.page(1);
+      viewModel.upperPage(Math.min(self.totalPages(), 50));
+      changePage();
+    }
+  }
+}
+;
+
+var viewModel = new displayViewModel({
+          base_url: "${ base_url }",
+          compression: "${view['compression']}",
+          mode: "${ view['mode'] }",
+          begin: ${view['offset'] + 1},
+          end: ${view['end']},
+          length: ${view['length']},
+          size: ${stats['size']},
+          max_size: ${view['max_chunk_size']}
         }
-      };
-
-      self.nextBlock = function() {
-        var offset = self.offset() + self.length();
-        changeBlock(offset + 1, offset + self.length());
-      };
-
-      self.previousBlock = function() {
-        var offset = ( self.offset() >= self.length() ) ? self.offset() - self.length() : 0;
-        changeBlock(offset + 1, offset + self.length());
-      };
-
-      self.lastBlock = function() {
-        var offset = self.size() - self.length();
-        if (offset < 0) {
-          offset = 0;
+);
+
+function resizeText() {
+  $("#fileArea").height($(window).height() - $("#fileArea").offset().top - 26);
+  $("#loader").css("marginLeft", ($("#fileArea").width() - $("#loader").width()) / 2);
+}
+
+function formatHex(number, padding) {
+  if ("undefined" != typeof number){
+    var _filler = "";
+    for (var i = 0; i < padding - 1; i++) {
+      _filler += "0";
+    }
+    return (_filler + number.toString(16)).substr(-padding);
+  }
+  return "";
+}
+
+var pages = {};
+
+function pageContent(page) {
+  var _html = "";
+  if ($("#page" + page).length == 0) {
+    if (pages[page] == null) {
+      _html += "<a id='page" + page + "'><div style='height: " + $("#fileArea").height() + "px'></div></a>";
+    }
+    else {
+      _html += "<a id='page" + page + "'><div style='display: inline'>" + $("<span>").text(pages[page]).html() + "</div></a>";
+    }
+  }
+  else {
+    if (pages[page] == null) {
+      $("#page" + page).html("<div style='height: " + $("#fileArea").height() + "px'></div>");
+    }
+    else {
+      $("#page" + page).html("<div style='display: inline'>" + $("<span>").text(pages[page]).html() + "</div>");
+    }
+
+  }
+  return _html;
+}
+
+function renderPages() {
+  var _html = "";
+  if (viewModel.totalPages() < viewModel.MAX_PAGES_TO_ENABLE_SCROLLING) { // enable scrolling
+    for (var i = 1; i <= viewModel.totalPages(); i++) {
+      _html += pageContent(i);
+    }
+  }
+  else {
+    _html += pageContent(viewModel.page());
+  }
+  if (_html != "") {
+    $("#fileArea pre").html(_html);
+  }
+}
+
+
+function getContent(callback) {
+  viewModel.isLoading(true);
+  var _baseUrl = "${url('filebrowser.views.view', path=path_enc)}";
+  $.getJSON(_baseUrl, viewModel.jsonParams(), function (data) {
+    if (data.view.contents != null) {
+      pages[viewModel.page()] = data.view.contents;
+      renderPages();
+    }
+    if (data.view.xxd != null) {
+      pages[viewModel.page()] = data.view.xxd;
+      var _html = "";
+      $(data.view.xxd).each(function (cnt, item) {
+        _html += "<tr><td>" + formatHex(item[0], 7) + ":&nbsp;</td><td>";
+        for (var i = 0; i < item[1].length; i++) {
+          _html += formatHex(item[1][i][0], 2) + " " + formatHex(item[1][i][1], 2) + " ";
         }
-        changeBlock(offset + 1, offset + self.length());
-      };
+        _html += "</td><td>&nbsp;&nbsp;" + $("<span>").text(item[2]).html() + "</td></tr>";
+      });
+      $(".binary tbody").html(_html);
+    }
+    if (callback) {
+      callback();
+    }
+    viewModel.isLoading(false);
+  });
+}
+
 
-      self.firstBlock = function() {
-        changeBlock(1, self.length());
+$(document).ready(function () {
+  ko.applyBindings(viewModel);
+
+  $(document).ajaxError(function () {
+    $.jHueNotify.error("${_('There was an unexpected server error.')}");
+  });
+
+  var _hash = window.location.hash;
+  if (_hash != "") {
+    var _hashPage = 1;
+    var _hashUpperPage = 1;
+    if (_hash.indexOf("-") > -1) {
+      _hashPage = _hash.split("-")[0].substr(2) * 1;
+      _hashUpperPage = _hash.split("-")[1].substr(1) * 1;
+    }
+    else {
+      _hashPage = _hash.substr(2) * 1;
+      _hashUpperPage = Math.min(viewModel.totalPages(), _hashPage + 50 - 1);
+    }
+    if (isNaN(_hashPage)) {
+      _hashPage = 1;
+    }
+    if (isNaN(_hashUpperPage)) {
+      _hashUpperPage = Math.min(viewModel.totalPages(), 50);
+    }
+    if (_hashUpperPage - _hashPage > viewModel.MAX_ALLOWED_PAGES_PER_REQUEST) {
+      _hashUpperPage = _hashPage + viewModel.MAX_ALLOWED_PAGES_PER_REQUEST;
+    }
+    viewModel.page(_hashPage);
+    viewModel.upperPage(_hashUpperPage);
+  }
+
+  viewModel.toggleDisables();
+
+  window.setTimeout(function () {
+    getContent(function () {
+      if (window.location.hash != "") {
+        window.location.hash = "#page" + viewModel.page();
+        window.location.hash = "#p" + viewModel.page() + (viewModel.page() != viewModel.upperPage() ? "-p" + viewModel.upperPage() : "");
       }
-    };
-    var viewModel = new displayViewModel(
-      "${ base_url }",
-      "${view['compression']}",
-      "${ view['mode'] }",
-      ${view['offset'] + 1},
-      ${view['end']},
-      ${view['length']},
-      ${stats['size']},
-      ${view['max_chunk_size']}
-    );
-
-    $(window).load(function(){
-      $("#refreshBtn").click(function(){
-        window.location.reload();
-      });
-      ko.applyBindings(viewModel);
-      viewModel.toggleDisables();
     });
-  </script>
+  }, 100);
+
+  resizeText();
+
+  var _resizeTimeout = -1;
+  $(window).on("resize", function () {
+    window.clearTimeout(_resizeTimeout);
+    _resizeTimeout = window.setTimeout(function () {
+      resizeText();
+      renderPages();
+    }, 300);
+  });
+
+  $("#fileArea").jHueScrollUp();
+
+  if (viewModel.totalPages() < viewModel.MAX_PAGES_TO_ENABLE_SCROLLING && viewModel.mode() == "text") { // enable scrolling
+    var _fileAreaScrollTimeout = -1;
+    $("#fileArea").on("scroll", function () {
+      if ($("#fileArea").scrollTop() < 30) {
+        viewModel.page(1);
+        viewModel.upperPage(viewModel.page());
+      }
+      else {
+        for (var i = 1; i <= viewModel.totalPages(); i++) {
+          if ($("#page" + i + " div").visible(true)) {
+            viewModel.page(i);
+            viewModel.upperPage(viewModel.page());
+          }
+        }
+      }
+      window.clearTimeout(_fileAreaScrollTimeout);
+      _fileAreaScrollTimeout = window.setTimeout(function () {
+        location.hash = "#p" + viewModel.page();
+        if (pages[viewModel.page()] == null) {
+          getContent();
+        }
+      }, 100);
+    });
+  }
+
+});
+</script>
 
 ${ commonfooter(messages) | n,unicode }

+ 2 - 2
apps/filebrowser/src/filebrowser/templates/fb_components.mako

@@ -84,11 +84,11 @@ from django.utils.translation import ugettext as _
           base_url = url('filebrowser.views.view', path=path_enc)
         %>
         % if view['mode'] == "binary":
-          <li><a href="${base_url}?offset=${view['offset']}&length=${view['length']}&mode=text&compression=${view['compression']}"><i class="fa fa-font"></i> ${_('View as text')}</a></li>
+          <li><a href="${base_url}?mode=text&compression=${view['compression']}"><i class="fa fa-font"></i> ${_('View as text')}</a></li>
         % endif
 
         % if view['mode'] == "text":
-          <li><a href="${base_url}?offset=${view['offset']}&length=${view['length']}&mode=binary&compression=${view['compression']}"><i class="fa fa-barcode"></i> ${_('View as binary')}</a></li>
+          <li><a href="${base_url}?mode=binary&compression=${view['compression']}"><i class="fa fa-barcode"></i> ${_('View as binary')}</a></li>
         % endif
 
         % if view['compression'] != "gzip" and path.endswith('.gz'):

+ 1 - 0
desktop/core/static/ext/js/jquery/plugins/jquery.visible.min.js

@@ -0,0 +1 @@
+(function(e){e.fn.visible=function(t,n,r){var i=e(this).eq(0),s=i.get(0),o=e(window),u=o.scrollTop(),a=u+o.height(),f=o.scrollLeft(),l=f+o.width(),c=i.offset().top,h=c+i.height(),p=i.offset().left,d=p+i.width(),v=t===true?h:c,m=t===true?c:h,g=t===true?d:p,y=t===true?p:d,b=n===true?s.offsetWidth*s.offsetHeight:true,r=r?r:"both";if(r==="both")return!!b&&m<=a&&v>=u&&y<=l&&g>=f;else if(r==="vertical")return!!b&&m<=a&&v>=u;else if(r==="horizontal")return!!b&&y<=l&&g>=f}})(jQuery)