diff --git a/css/views_infinite_scroll.css b/css/views_infinite_scroll.css
deleted file mode 100644
index c214502..0000000
--- a/css/views_infinite_scroll.css
+++ /dev/null
@@ -1,3 +0,0 @@
-div#views_infinite_scroll-ajax-loader {
-  text-align: center;
-}
diff --git a/drush/views_infinite_scroll.drush.inc b/drush/views_infinite_scroll.drush.inc
deleted file mode 100644
index ccaa75e..0000000
--- a/drush/views_infinite_scroll.drush.inc
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-
-/**
- * @file
- *   drush integration for views_infinite_scroll.
- */
-
-/**
- * Implements hook_drush_command().
- *
- * In this hook, you specify which commands your
- * drush module makes available, what it does and
- * description.
- *
- * Notice how this structure closely resembles how
- * you define menu hooks.
- *
- * @See drush_parse_command() for a list of recognized keys.
- *
- * @return
- *   An associative array describing your command(s).
- */
-function views_infinite_scroll_drush_command() {
-  $items = array();
-
-  $items['dl-autopager'] = array(
-    'callback' => 'views_infinite_scroll_drush_autopager_download',
-    'description' => dt('Downloads the required autopager jquery plugin.'),
-  );
-  return $items;
-}
-
-/**
- * Implements hook_drush_help().
- *
- * This function is called whenever a drush user calls
- * 'drush help <name-of-your-command>'
- *
- * @param
- *   A string with the help section (prepend with 'drush:')
- *
- * @return
- *   A string with the help text for your command.
- */
-function views_infinite_scroll_drush_help($section) {
-  switch ($section) {
-    case 'drush:dl-autopager':
-      return dt("Downloads the required autopager jquery plugin.");
-  }
-}
-
-/**
- * Example drush command callback.
- *
- * This is where the action takes place.
- *
- * In this function, all of Drupals API is (usually) available, including
- * any functions you have added in your own modules/themes.
- *
- * To print something to the terminal window, use drush_print().
- *
- */
-function views_infinite_scroll_drush_autopager_download() {
-  if (module_exists('libraries')) {
-    $path = 'sites/all/libraries/autopager';
-
-    // Create the path if it does not exist.
-    if (!is_dir($path)) {
-      drush_op('mkdir', $path);
-      drush_log(dt('Directory @path was created', array('@path' => $path)), 'notice');
-    }
-  }
-  else {
-    $path = drupal_get_path('module', 'views_infinite_scroll') . '/js';
-  }
-  drush_op('chdir', $path);
-  // Download the plugin.
-  if (drush_shell_exec('wget http://jquery-autopager.googlecode.com/files/jquery.autopager-1.0.0.js')) {
-    drush_log(dt('jquery.autopager-1.0.0.js has been downloaded to @path', array('@path' => $path)), 'success');
-  }
-  else {
-    drush_log(dt('Drush was unable to download jquery.autopager-1.0.0.js to @path', array('@path' => $path)), 'error');
-  }
-}
diff --git a/js/views_infinite_scroll.js b/js/views_infinite_scroll.js
deleted file mode 100644
index 251398b..0000000
--- a/js/views_infinite_scroll.js
+++ /dev/null
@@ -1,88 +0,0 @@
-(function ($) {
-
-  /**
-   * Attach infinite scroll to the relevant views.
-   */
-  Drupal.behaviors.views_infinite_scroll = {
-    attach: function (context, settings) {
-
-      // Make sure that autopager plugin is loaded.
-      if (!$.autopager) {
-        alert(Drupal.t('Autopager jQuery plugin is not loaded.'));
-        return;
-      }
-
-      var settings = settings.views_infinite_scroll[0];
-
-      // Ensure we are refreshing the view component.
-      var view_selector = 'div.view-id-' + settings.view_name + '.view-display-id-' + settings.display;
-      var $view = $(context).is(view_selector) ? $(context) : $(context).find(view_selector);
-      if ($view.length == 0) {
-        return;
-      }
-
-      // Destroy an existing instance of autopager.
-      $.autopager('destroy');
-
-      var content_selector = view_selector + ' > ' + settings.content_selector;
-      var $items = $view.find(settings.items_selector);
-      var $pager = $view.find('> div.item-list ' + settings.pager_selector);
-      var next_selector = view_selector + ' ' + settings.next_selector;
-      var $next = $(next_selector);
-
-      var $img_location = $view.find('div.view-content');
-      var img_path = settings.img_path;
-      var img = '<div id="views_infinite_scroll-ajax-loader"><img src="' + img_path + '" alt="loading..."/></div>';
-
-      $($pager).hide();
-      $.autopager({
-        appendTo: content_selector,
-        content: content_selector + ' ' + settings.items_selector,
-        link: next_selector,
-        page: 0,
-        autoLoad: !settings.manual_load,
-        start: function () {
-          $img_location.after(img);
-        },
-        load: function (current, next) {
-          $('div#views_infinite_scroll-ajax-loader').remove();
-          Drupal.attachBehaviors(this);
-          // Use >= because of views page numbers begin at 0.
-          if (settings.manual_load && next.page >= settings.pager_max) {
-            $next.hide();
-          }
-        }
-      });
-
-      if (settings.manual_load) {
-        // The pager is hidden. Pop "next" link out so it will be visible.
-        $next.text(settings.text);
-        $next.click(function (e) {
-          e.preventDefault();
-          // do load
-          $.autopager('load');
-        });
-        $($pager).before($next);
-        // Wrap the button to allow for easier styling in the theme
-        $next.wrap('<div id="views_infinite_scroll_button" />');
-      }
-      else {
-        $($pager).hide();
-        // Trigger autoload if content height is less than doc height already
-        var prev_content_height = $(content_selector).height();
-        do {
-          var last = $($items).filter(':last');
-          if (last.offset().top + last.height() < $(document).scrollTop() + $(window).height()) {
-            last = $($items).filter(':last');
-            $.autopager('load');
-          }
-          else {
-            break;
-          }
-        }
-        while ($(content_selector).height() > prev_content_height);
-      }
-    }
-  };
-
-})(jQuery);
diff --git a/theme/views_infinite_scroll_theme.inc b/theme/views_infinite_scroll_theme.inc
deleted file mode 100644
index 526297f..0000000
--- a/theme/views_infinite_scroll_theme.inc
+++ /dev/null
@@ -1,109 +0,0 @@
-<?php
-/**
- * @file
- * Theme infinite scroll page
- */
-function theme_views_infinite_scroll_pager($variables) {
-  $tags = $variables['tags'];
-  $limit = isset($variables['limit']) ? $variables['limit'] : 10;
-  $view_name = $variables['view_name'];
-  $element = isset($variables['element']) ? $variables['element'] : 0;
-  $current_display = $variables['current_display'];
-  $content_selector = isset($variables['content_selector']) ? $variables['content_selector'] : 'div.view-content';
-  $items_selector = isset($variables['items_selector']) ? $variables['items_selector'] : 'div.view-content .views-row';
-  $img_path = $variables['img_path'];
-  $manual_load = isset($variables['manual_load']) ? $variables['manual_load'] : FALSE;
-  $text = isset($variables['text']) ? $variables['text'] : array('default' => 'Show More', 'translatable' => TRUE);
-  $parameters = $variables['parameters'];
-  $quantity = $variables['quantity'];
-
-  $PAGER_CLASS = 'pager';
-  global $pager_page_array, $pager_total;
-
-  // Calculate various markers within this pager piece:
-  // Middle is used to "center" pages around the current page.
-  $pager_middle = ceil($quantity / 2);
-  // current is the page we are currently paged to
-  $pager_current = $pager_page_array[$element] + 1;
-  // max is the maximum page number
-  $pager_max = $pager_total[$element];
-  // End of marker calculations.
-
-  $li_previous = theme('pager_previous',
-    array(
-      'text' => (isset($tags[1]) ? $tags[1] : t('‹‹')),
-      'limit' => $limit,
-      'element' => $element,
-      'interval' => 1,
-      'parameters' => $parameters,
-    )
-  );
-  if (empty($li_previous)) {
-    $li_previous = "&nbsp;";
-  }
-
-  $li_next = theme('pager_next',
-    array(
-      'text' => (isset($tags[3]) ? $tags[3] : t('››')),
-      'limit' => $limit,
-      'element' => $element,
-      'interval' => 1,
-      'parameters' => $parameters,
-    )
-  );
-  if (empty($li_next)) {
-    $li_next = "&nbsp;";
-  }
-
-
-  if ($pager_total[$element] > 1) {
-    $items[] = array(
-      'class' => array('pager-previous'),
-      'data' => $li_previous,
-    );
-
-    $items[] = array(
-      'class' => array('pager-current'),
-      'data' => t('@current of @max', array('@current' => $pager_current, '@max' => $pager_max)),
-    );
-
-    $items[] = array(
-      'class' => array('pager-next'),
-      'data' => $li_next,
-    );
-
-    $settings = array(
-      'views_infinite_scroll' => array(
-        array(
-          'view_name' => $view_name,
-          'display' => $current_display,
-          'pager_selector' => 'ul.' . $PAGER_CLASS,
-          'next_selector' => 'li.pager-next a:first',
-          'content_selector' => $content_selector,
-          'items_selector' => $items_selector,
-          'img_path' => $img_path,
-          'manual_load' => $manual_load,
-          'text' => t($text),
-          'pager_max' => $pager_max,
-        ),
-      ),
-    );
-    drupal_add_css(drupal_get_path('module', 'views_infinite_scroll') . '/css/views_infinite_scroll.css');
-    drupal_add_js($settings, array('type' => 'setting', 'scope' => JS_DEFAULT));
-
-    // Add Autopager jQuery plugin
-    // If libraries module is installed, check for the plugin in libraries dir.
-    if (module_exists('libraries') && file_exists(libraries_get_path('autopager') .'/jquery.autopager-1.0.0.js')) {
-      drupal_add_js(libraries_get_path('autopager') .'/jquery.autopager-1.0.0.js');
-    }
-    // else, load it from views_infinite_scroll/js dir.
-    else {
-      $autopager_module_path = drupal_get_path('module', 'views_infinite_scroll') . '/js/jquery.autopager-1.0.0.js';
-      drupal_add_js($autopager_module_path);
-    }
-
-    drupal_add_js(drupal_get_path('module', 'views_infinite_scroll') . '/js/views_infinite_scroll.js');
-
-    return theme('item_list', array('items' => $items, 'title' => NULL, 'type' => 'ul', 'attributes' => array('class' => array($PAGER_CLASS))));
-  }
-}
diff --git a/views-infinite-scroll-pager.tpl.php b/views-infinite-scroll-pager.tpl.php
new file mode 100644
index 0000000..a8ba0e5
--- /dev/null
+++ b/views-infinite-scroll-pager.tpl.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * @file
+ * Views infinite scroll pager template.
+ */
+?>
+<ul class="pager pager--infinite-scroll">
+  <li class="pager__item">
+    <?php print render($button); ?>
+  </li>
+</ul>
diff --git a/views-infinite-scroll.js b/views-infinite-scroll.js
new file mode 100644
index 0000000..aeff4f2
--- /dev/null
+++ b/views-infinite-scroll.js
@@ -0,0 +1,48 @@
+(function ($) {
+  "use strict";
+
+  var $window = $(window);
+
+  // The threshold for how far to the bottom you should reach before reloading.
+  var scroll_threshold = 200;
+
+  /**
+   * Insert a views infinite scroll view into the document after AJAX.
+   *
+   * @param {object} $new_view The new view coming from the server.
+   */
+  $.fn.infiniteScrollInsertView = function ($new_view) {
+    var $existing_view = this;
+    var $existing_content = $existing_view.find('.view-content').children();
+    $new_view.find('.view-content').prepend($existing_content);
+    $existing_view.replaceWith($new_view);
+    $(document).trigger('infiniteScrollComplete', [$new_view, $existing_content]);
+  };
+
+  /**
+   * Handle the automatic paging based on the scroll amount.
+   */
+  Drupal.behaviors.views_infinite_scroll_automatic = {
+    attach : function(context, settings) {
+
+      var settings = settings.views_infinite_scroll[0];
+      var loadingImg = '<div id="views_infinite_scroll-ajax-loader"><img src="' + settings.img_path + '" alt="loading..."/></div>';
+
+      $('.pager--infinite-scroll', context).once().each(function() {
+        var $pager = $(this);
+        $pager.find('.pager__item').hide();
+        if ($pager.find('.pager__item a').length) {
+          $pager.append(loadingImg);
+        }
+        $window.on('scroll.views_infinite_scroll', function() {
+          if (window.innerHeight + window.pageYOffset > $pager.offset().top - scroll_threshold) {
+            $pager.find('.pager__item a').click();
+            $window.off('scroll.views_infinite_scroll');
+          }
+        });
+      });
+
+    }
+  };
+
+})(jQuery);
diff --git a/views_infinite_scroll.info b/views_infinite_scroll.info
index 8c7079e..ce77afd 100644
--- a/views_infinite_scroll.info
+++ b/views_infinite_scroll.info
@@ -1,15 +1,8 @@
-; $Id:
 name = Views Infinite Scroll
-description = Provides an Infinite Scrolling pager for Views
-package = Views
+description = Infinite scroll for Drupal views.
 core = 7.x
-dependencies[] = views
 
-files[] = views_infinite_scroll.module
-files[] = views_infinite_scroll.views.inc
 files[] = views_plugin_pager_infinite_scroll.inc
-files[] = drush/views_infinite_scroll.drush.inc
-files[] = theme/views_infinite_scroll_theme.inc
 
 ; Information added by Drupal.org packaging script on 2014-10-02
 version = "7.x-1.2+1-dev"
diff --git a/views_infinite_scroll.module b/views_infinite_scroll.module
index b79c06c..f868417 100644
--- a/views_infinite_scroll.module
+++ b/views_infinite_scroll.module
@@ -1,37 +1,74 @@
 <?php
-// $Id:
+
 /**
  * @file
+ * Create a pager plugin to allow infinite scroll on views.
  */
 
 /**
  * Implements hook_views_api().
  */
 function views_infinite_scroll_views_api() {
-  return array('api' => '3.0-alpha1');
+  return array('api' => 3);
+}
+
+/**
+ * Implements hook_views_plugin().
+ */
+function views_infinite_scroll_views_plugins() {
+  return array(
+    'module' => 'views_infinite_scroll',
+    'pager' => array(
+      'infinite_scroll' => array(
+        'title' => t('Infinite Scroll'),
+        'handler' => 'views_plugin_pager_infinite_scroll',
+        'uses options' => TRUE,
+        'parent' => 'full',
+      ),
+    ),
+  );
 }
 
 /**
  * Implements hook_theme().
  */
 function views_infinite_scroll_theme() {
-  $path = drupal_get_path('module', 'views_infinite_scroll');
-
-  // Some quasi clever array merging here.
-  $base = array(
-    'file' => 'views_infinite_scroll_theme.inc',
-    'path' => "$path/theme",
-  );
-
-  // Our extra version of pager from pager.inc
-  $hooks['views_infinite_scroll_pager'] = $base + array(
-    'variables' => array(
-      'tags' => array(),
-      'limit' => 10,
-      'element' => 0,
-      'parameters' => array(),
+  return array(
+    'views_infinite_scroll_pager' => array(
+      'variables' => array(
+        'element' => NULL,
+      ),
+      'template' => 'views-infinite-scroll-pager',
     ),
-    'pattern' => 'views_infinite_scroll_pager__',
   );
-  return $hooks;
+}
+
+/**
+ * Implements hook_views_ajax_data_alter().
+ */
+function views_infinite_scroll_views_ajax_data_alter(&$commands, view $view) {
+  if (!isset($view->query->pager->plugin_name) || $view->query->pager->plugin_name !== 'infinite_scroll' || !isset($_GET['page'])) {
+    return;
+  }
+  foreach ($commands as $delta => &$command) {
+    if ($command['method'] === 'replaceWith') {
+      // Change the standard replace command to a custom one which will provide
+      // the infinite scroll effect.
+      $command['method'] = 'infiniteScrollInsertView';
+    }
+    // Remove the behaviour of scrolling to the top of the page.
+    if ($command['command'] === 'viewsScrollTop') {
+      unset($commands[$delta]);
+    }
+  }
+}
+
+/**
+ * Implements hook_preprocess_views_infinite_scroll_pager().
+ */
+function views_infinite_scroll_preprocess_views_infinite_scroll_pager(&$vars) {
+  $vars['button'] = [
+    '#theme' => 'pager_next',
+    '#text' => $vars['text'],
+  ];
 }
diff --git a/views_infinite_scroll.views.inc b/views_infinite_scroll.views.inc
deleted file mode 100644
index 08dcf7d..0000000
--- a/views_infinite_scroll.views.inc
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-/**
- * @file
- *  Provides the views plugin information.
- */
-
-/**
- * Implements hook_views_plugin().
- */
-function views_infinite_scroll_views_plugins() {
-  return array(
-    'module' => 'views_infinite_scroll',
-    'pager' => array(
-      'infinite_scroll' => array(
-        'title' => t('Infinite Scroll'),
-        'help' => t('views_infinite_scroll'),
-        'handler' => 'views_plugin_pager_infinite_scroll',
-        'uses options' => TRUE,
-        'parent' => 'full',
-      ),
-    ),
-  );
-}
diff --git a/views_plugin_pager_infinite_scroll.inc b/views_plugin_pager_infinite_scroll.inc
index 6e09c24..64c7642 100644
--- a/views_plugin_pager_infinite_scroll.inc
+++ b/views_plugin_pager_infinite_scroll.inc
@@ -1,35 +1,50 @@
 <?php
 
 /**
- * The plugin to handle full pager.
+ * @file
+ * Contains \views_plugin_pager_infinite_scroll.
+ */
+
+/**
+ * The plugin to handle the infinite scroll pager.
  *
  * @ingroup views_pager_plugins
  */
 class views_plugin_pager_infinite_scroll extends views_plugin_pager_full {
-  function init(&$view, &$display, $options = array()) {
-    parent::init($view, $display, $options);
-  }
 
+  /**
+   * {@inheritdoc}
+   */
   function option_definition() {
-    $options = parent::option_definition();
     $options['manual_load'] = array('default' => 0);
     $options['text'] = array('default' => 'Show More', 'translatable' => TRUE);
+    $options['items_per_page'] = array('default' => 10);
+    $options['offset'] = array('default' => 0);
     return $options;
   }
 
   /**
-   * Provide the default form for setting options.
+   * {@inheritdoc}
    */
   function options_form(&$form, &$form_state) {
-    parent::options_form($form, $form_state);
+    $form['items_per_page'] = array(
+      '#title' => t('Items to display'),
+      '#type' => 'textfield',
+      '#description' => t('The number of items to display. Enter 0 for no limit.'),
+      '#default_value' => $this->options['items_per_page'],
+    );
+    $form['offset'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Offset'),
+      '#description' => t('The number of items to skip. For example, if this field is 3, the first 3 items will be skipped and not displayed.'),
+      '#default_value' => $this->options['offset'],
+    );
     $form['manual_load'] = array(
       '#type' => 'checkbox',
       '#title' => t('Load subsequent pages manually instead of automatically'),
       '#description' => t('When checked, use a link to trigger loading of subsequent pages instead of window scroll.'),
       '#default_value' => $this->options['manual_load'],
-      '#weight' => -10,
     );
-
     $form['text'] = array(
       '#type' => 'textfield',
       '#title' => t('Manual load label'),
@@ -40,64 +55,39 @@ class views_plugin_pager_infinite_scroll extends views_plugin_pager_full {
       '#dependency' => array(
         'edit-pager-options-manual-load' => array(1),
       ),
-      '#weight' => -10,
     );
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  function options_validate(&$form, &$form_state) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   function summary_title() {
-    return "Infinite Scroll";
-    if (!empty($this->options['offset'])) {
-      return format_plural($this->options['items_per_page'], 'Infinite scroll pager, @count item, skip @skip', 'Infinite scroll pager, @count items, skip @skip', array(
-        '@count' => $this->options['items_per_page'],
-        '@skip' => $this->options['offset']
-      ));
-    }
-    return format_plural($this->options['items_per_page'], 'Infinite scroll pager, @count item', 'Infinite scroll pager, @count items', array('@count' => $this->options['items_per_page']));
+    return t('Infinite Scroll: @parent', ['@parent' => parent::summary_title()]);
   }
 
+  /**
+   * {@inheritdoc}
+   */
   function render($input) {
     global $base_url;
-    $content_selector = '';
-    $style_options = $this->view->style_options;
-    $items_selector = '';
-    $img_path = $base_url . '/' . drupal_get_path('module', 'views_infinite_scroll') . '/images/ajax-loader.gif';
-    switch ($this->view->plugin_name) {
-      case 'default':
-        $content_selector = 'div.view-content';
-        $items_selector = '.views-row';
-        break;
-      case 'grid':
-        $content_selector = 'div.view-content > table > tbody';
-        $items_selector = 'tr';
-        break;
-      case 'list':
-        if (array_key_exists('wrapper_class', $style_options) && !empty($style_options['wrapper_class'])) {
-          $wrapper_class = '.' . $style_options['wrapper_class'];
-        }
-        else {
-          $wrapper_class = '.item-list';
-        }
-        $content_selector = 'div.view-content>' . $wrapper_class . ' > *';
-        $items_selector = '.views-row';
-        break;
-      case 'table':
-        $content_selector = 'div.view-content > table > tbody';
-        $items_selector = 'tr';
-        break;
-    }
+    $this->view->set_use_ajax(TRUE);
     $pager_theme = views_theme_functions('views_infinite_scroll_pager', $this->view, $this->display);
-    return theme($pager_theme, array(
-        'tags' => $input,
-        'quantity' => $this->options['items_per_page'],
-        'view_name' => $this->view->name,
-        'current_display' => $this->view->current_display,
-        'content_selector' => $content_selector,
-        'items_selector' => $items_selector,
-        'img_path' => $img_path,
-        'element' => $this->options['id'],
-        'manual_load' => $this->options['manual_load'],
-        'text' => $this->options['text'],
-      )
+    $img_path = $base_url . '/' . drupal_get_path('module', 'views_infinite_scroll') . '/images/ajax-loader.gif';
+    $settings = array(
+      'views_infinite_scroll' => array(
+        array(
+          'img_path' => $img_path,
+        ),
+      ),
     );
+    drupal_add_js($settings, array('type' => 'setting', 'scope' => JS_DEFAULT));
+    drupal_add_js(drupal_get_path('module', 'views_infinite_scroll') . '/views-infinite-scroll.js', array('scope' => 'footer'));
+    return theme($pager_theme, array('text' => $this->options['text']));
   }
 }
