diff --git a/reviewboard/admin/forms.py b/reviewboard/admin/forms.py
index 5c42d9d73f7de0ce78c6337bcfc8199282c2a9a8..5a2a47f8cccf873947a2a8b15bf295b8c005e19f 100644
--- a/reviewboard/admin/forms.py
+++ b/reviewboard/admin/forms.py
@@ -614,15 +614,15 @@ class DiffSettingsForm(SiteSettingsForm):
 
     diffviewer_paginate_by = forms.IntegerField(
         label=_("Paginate by"),
-        help_text=_("The number of files to display per page in the diff "
+        help_text=_("The number of files loaded every time in the diff "
                     "viewer."),
         initial=20,
         widget=forms.TextInput(attrs={'size': '5'}))
 
     diffviewer_paginate_orphans = forms.IntegerField(
         label=_("Paginate orphans"),
-        help_text=_("The number of extra files required before adding another "
-                    "page to the diff viewer."),
+        help_text=_("The number of extra files required before loading "
+                    "the diff viewer another time."),
         initial=10,
         widget=forms.TextInput(attrs={'size': '5'}))
 
diff --git a/reviewboard/static/rb/js/diffviewer/views/diffFileIndexView.js b/reviewboard/static/rb/js/diffviewer/views/diffFileIndexView.js
index 9a110464bb7ccf7002591101f9720213d0ab1405..746ff04160e43af02cf280230d69bba8057d9222 100644
--- a/reviewboard/static/rb/js/diffviewer/views/diffFileIndexView.js
+++ b/reviewboard/static/rb/js/diffviewer/views/diffFileIndexView.js
@@ -70,8 +70,10 @@ RB.DiffFileIndexView = Backbone.View.extend({
     /*
      * Update the list of files in the index view.
      */
-    update: function() {
-        this._$itemsTable.empty();
+    update: function(attrs) {
+        if (!attrs) {
+            this._$itemsTable.empty();
+        }
 
         this.collection.each(function(file) {
             this._$itemsTable.append(this._itemTemplate(
diff --git a/reviewboard/static/rb/js/pages/models/diffViewerPageModel.js b/reviewboard/static/rb/js/pages/models/diffViewerPageModel.js
index 7b5aed1a5b1eff93870bdbd4c30d8bde4c901d89..b688a8ae45666826d9fbe738872c6810c6bd5af0 100644
--- a/reviewboard/static/rb/js/pages/models/diffViewerPageModel.js
+++ b/reviewboard/static/rb/js/pages/models/diffViewerPageModel.js
@@ -65,5 +65,42 @@ RB.DiffViewerPageModel = Backbone.Model.extend({
         }
 
         Backbone.Model.prototype.set.call(this, toSet, options);
+    },
+
+    /*
+     * Append another set of diffs into the current page.
+     *
+     * Due to part of the model's property, we can't just call add(parse(...)).
+     */
+    update: function(attrs, options) {
+        var change;
+
+        if (attrs.commentsHint) {
+            this.attributes.commentsHint.set(
+                attrs.commentsHint.attributes);
+        }
+
+        if (attrs.files) {
+            change = this.attributes.files;
+            this.attributes.files.add(attrs.files.models);
+            this.attributes.files.trigger('update',
+                change.set(attrs.files.models));
+        }
+
+        if (attrs.pagination) {
+            this.attributes.pagination.set(attrs.pagination.attributes);
+        }
+
+        if (attrs.revision) {
+            this.attributes.revision.set(attrs.revision.attributes);
+        }
+    },
+
+    /*
+     * Return the attribute hasNext to check whether there is enough pagination
+     * to load.
+     */
+    hasNext: function() {
+        return this.attributes.pagination.get('hasNext');
     }
 });
diff --git a/reviewboard/static/rb/js/pages/views/diffViewerPageView.js b/reviewboard/static/rb/js/pages/views/diffViewerPageView.js
index aeb38e506c293058aba4625ed3ec36f1f619d395..91e4270dbf3093516ca30c67155f2261214156e1 100644
--- a/reviewboard/static/rb/js/pages/views/diffViewerPageView.js
+++ b/reviewboard/static/rb/js/pages/views/diffViewerPageView.js
@@ -50,6 +50,7 @@ RB.DiffViewerPageView = RB.ReviewablePageView.extend({
         this._diffReviewableViews = [];
         this._diffFileIndexView = null;
         this._highlightedChunk = null;
+        this._isScrolling = false;
 
         this.listenTo(this.model.get('files'), 'update', this._setFiles);
 
@@ -76,13 +77,11 @@ RB.DiffViewerPageView = RB.ReviewablePageView.extend({
             } else {
                 parts = revision.split('-', 2);
                 this._loadRevision(parseInt(parts[0], 10),
-                                   parseInt(parts[1], 10),
-                                   page);
+                                   parseInt(parts[1], 10));
             }
         });
 
         /*
-        /*
          * Begin managing the URL history for the page, so that we can
          * switch revisions and handle pagination while keeping the history
          * clean and the URLs representative of the current state.
@@ -127,6 +126,31 @@ RB.DiffViewerPageView = RB.ReviewablePageView.extend({
             replace: true,
             trigger: false
         });
+
+        _.bindAll(this, '_resize');
+        _.bindAll(this, '_onScroll');
+        $(window).scroll(this._onScroll);
+    },
+
+    /*
+     * Listen to a scroll action and check whether it reaches the bottom
+     * of the page.
+     */
+    _onScroll: function() {
+        var scrollBarBottomPos = this._$document.scrollTop() + this._$window.height(),
+            documentHeight = this._$document.height();
+
+        if (scrollBarBottomPos===documentHeight && !this._isScrolling) {
+            this._scrollNext();
+        }
+    },
+
+    /*
+     * Get the current window and document size when resize the window.
+     */
+    _resize: function() {
+        this._$window = $(window);
+        this._$document = $(document);
     },
 
     /*
@@ -152,6 +176,9 @@ RB.DiffViewerPageView = RB.ReviewablePageView.extend({
 
         this._$controls = $('#view_controls');
 
+        this._$window = $(window);
+        this._$document = $(document);
+
         this._diffFileIndexView = new RB.DiffFileIndexView({
             el: $('#diff_index'),
             collection: this.model.get('files')
@@ -191,22 +218,6 @@ RB.DiffViewerPageView = RB.ReviewablePageView.extend({
         this.listenTo(this._commentsHintView, 'revisionSelected',
                       this._onRevisionSelected);
 
-        this._paginationView1 = new RB.PaginationView({
-            el: $('#pagination1'),
-            model: this.model.get('pagination')
-        });
-        this._paginationView1.render();
-        this.listenTo(this._paginationView1, 'pageSelected',
-                      _.partial(this._onPageSelected, false));
-
-        this._paginationView2 = new RB.PaginationView({
-            el: $('#pagination2'),
-            model: this.model.get('pagination')
-        });
-        this._paginationView2.render();
-        this.listenTo(this._paginationView2, 'pageSelected',
-                      _.partial(this._onPageSelected, true));
-
         $('#diffs').bindClass(RB.UserSession.instance,
                               'diffsShowExtraWhitespace', 'ewhl');
 
@@ -245,9 +256,16 @@ RB.DiffViewerPageView = RB.ReviewablePageView.extend({
      * This will replace the displayed files with a set of pending entries,
      * queue loads for each file, and start the queue.
      */
-    _setFiles: function() {
-        var files = this.model.get('files'),
-            $diffs = $('#diffs').empty();
+    _setFiles: function(attrs) {
+        var files,
+            $diffs = $('#diffs');
+
+        if (!attrs) {
+            files = this.model.get('files');
+            $diffs.empty();
+        } else {
+            files = attrs;
+        }
 
         this._highlightedChunk = null;
 
@@ -670,29 +688,13 @@ RB.DiffViewerPageView = RB.ReviewablePageView.extend({
     },
 
     /*
-     * Callback for when a new page is selected.
-     *
-     * Navigates to the same revision with a different page number.
-     */
-    _onPageSelected: function(scroll, page) {
-        var url = this._getCurrentURL();
-
-        if (scroll) {
-            this.selectAnchorByName('index_header', true);
-        }
-
-        url += '/?page=' + page;
-        this.router.navigate(url, {trigger: true});
-    },
-
-    /*
      * Load a given revision.
      *
      * This supports both single revisions and interdiffs. If `base` is 0, a
      * single revision is selected. If not, the interdiff between `base` and
      * `tip` will be shown.
      */
-    _loadRevision: function(base, tip, page) {
+    _loadRevision: function(base, tip) {
         var reviewRequestURL = _.result(this.reviewRequest, 'url'),
             contextURL = reviewRequestURL + 'diff-context/',
             $downloadLink = $('#download-diff');
@@ -705,10 +707,6 @@ RB.DiffViewerPageView = RB.ReviewablePageView.extend({
             $downloadLink.hide();
         }
 
-        if (page !== 1) {
-            contextURL += '&page=' + page;
-        }
-
         $.ajax(contextURL).done(_.bind(function(rsp) {
             _.each(this._diffReviewableViews, function(diffReviewableView) {
                 diffReviewableView.remove();
@@ -717,6 +715,42 @@ RB.DiffViewerPageView = RB.ReviewablePageView.extend({
 
             this.model.set(this.model.parse(rsp.diff_context));
         }, this));
+    },
+
+    /*
+     * Load the next page of diff content.
+     *
+     * Use AJAX to load the next pagination page and append it to the
+     * current diff.
+     */
+    _scrollNext: function() {
+        var reviewRequestURL = _.result(this.reviewRequest, 'url'),
+            url = reviewRequestURL + 'diff-context/',
+            revision = this.model.get('revision'),
+            nextPage = this.model.get('pagination').get('nextPage');
+
+        if (this._isScrolling) {
+            return;
+        } else {
+            this._isScrolling = true;
+        }
+
+        if (this.model.hasNext()) {
+            url += '?revision=' + revision.get('revision');
+
+            if (revision.get('interdiffRevision') !== null) {
+                url += '&interdiff-revision=' + revision.get('interdiffRevision');
+            }
+
+            url += '&page=' + nextPage;
+
+            $.ajax(url).done(_.bind(function(rsp) {
+                this.model.update(this.model.parse(rsp.diff_context));
+                this._isScrolling = false;
+            }, this));
+        } else {
+            this._isScrolling = false;
+        }
     }
 });
 _.extend(RB.DiffViewerPageView.prototype, RB.KeyBindingsMixin);
