diff --git a/reviewboard/static/rb/js/views/reviewRequestEditorView.js b/reviewboard/static/rb/js/views/reviewRequestEditorView.js
index d6f6edfd21d6e513b93a36a7e9e97aadc4cefd72..803dbe5c522474f3bd0ff5f2c0125babc8c38c1a 100644
--- a/reviewboard/static/rb/js/views/reviewRequestEditorView.js
+++ b/reviewboard/static/rb/js/views/reviewRequestEditorView.js
@@ -873,32 +873,43 @@ RB.ReviewRequestEditorView = Backbone.View.extend({
         reviewRequest.on('closed reopened', this._refreshPage, this);
         draft.on('destroyed', this._refreshPage, this);
 
-        /*
-         * Warn the user if they try to navigate away with unsaved comments.
-         */
-        window.onbeforeunload = _.bind(function(evt) {
-            if ((this.model.get('editable') ||
-                 this.model.get('statusEditable')) &&
-                this.model.get('editCount') > 0) {
-                /*
-                 * On IE, the text must be set in evt.returnValue.
-                 *
-                 * On Firefox, it must be returned as a string.
-                 *
-                 * On Chrome, it must be returned as a string, but you
-                 * can't set it on evt.returnValue (it just ignores it).
-                 */
-                var msg = gettext("You have unsaved changes that will be lost if you navigate away from this page.");
-                evt = evt || window.event;
-
-                evt.returnValue = msg;
-                return msg;
-            }
-        }, this);
+        window.onbeforeunload = _.bind(this._onBeforeUnload, this);
 
         return this;
     },
 
+    /**
+     * Warn the user if they try to navigate away with unsaved comments.
+     *
+     * Args:
+     *     evt (Event):
+     *         The event that triggered the handler.
+     *
+     * Returns:
+     *     string:
+     *     The warning message.
+     *
+     */
+    _onBeforeUnload: function(evt) {
+        var msg;
+
+        if (this.model.get('editCount') > 0) {
+            /*
+             * On IE, the text must be set in evt.returnValue.
+             *
+             * On Firefox, it must be returned as a string.
+             *
+             * On Chrome, it must be returned as a string, but you
+             * can't set it on evt.returnValue (it just ignores it).
+             */
+            msg = gettext('You have unsaved changes that will be lost if you navigate away from this page.');
+            evt = evt || window.event;
+
+            evt.returnValue = msg;
+            return msg;
+        }
+    },
+
     /*
      * Sets up an editor for the given field.
      *
diff --git a/reviewboard/static/rb/js/views/tests/reviewRequestEditorViewTests.js b/reviewboard/static/rb/js/views/tests/reviewRequestEditorViewTests.js
index eb531f7e73639e7d1c11c6050dcb50df22ce7670..da15292b50a146ec47b4afa2fa823d433a9aeede 100644
--- a/reviewboard/static/rb/js/views/tests/reviewRequestEditorViewTests.js
+++ b/reviewboard/static/rb/js/views/tests/reviewRequestEditorViewTests.js
@@ -1243,4 +1243,57 @@ suite('rb/views/ReviewRequestEditorView', function() {
             });
         });
     });
+
+    describe('beforeUnload event handler', function() {
+        /*
+         * The components in ReviewablePageView uses editCount to determine how
+         * many fields are being modified at the time, whereas editable/
+         * statusEditable is only used in ReviewRequestEditorView.
+         * So test both editable/statusEditable states to catch regressions
+         * where onBeforeUnload becomes tied to editable/statusEditable states.
+         */
+        describe('editable=true', function() {
+            beforeEach(function() {
+                editor.set('statusEditable', true);
+                editor.set('editable', true);
+
+                expect(editor.get('statusEditable')).toBe(true);
+                expect(editor.get('editable')).toBe(true);
+                expect(editor.get('editCount')).toBe(0);
+            });
+
+            it('Warn user beforeUnload when editing', function() {
+                view.model.incr('editCount');
+                expect(editor.get('editCount')).toBe(1);
+
+                expect(view._onBeforeUnload($.Event('beforeunload'))).toBeDefined();
+            });
+
+            it("Don't warn user beforeUnload when not editing", function() {
+                expect(view._onBeforeUnload($.Event('beforeunload'))).toBeUndefined();
+            });
+        })
+
+        describe('editable=false', function() {
+            beforeEach(function() {
+                editor.set('statusEditable', false);
+                editor.set('editable', false);
+
+                expect(editor.get('statusEditable')).toBe(false);
+                expect(editor.get('editable')).toBe(false);
+                expect(editor.get('editCount')).toBe(0);
+            });
+
+            it('Warn user beforeUnload when editing', function() {
+                view.model.incr('editCount');
+                expect(editor.get('editCount')).toBe(1);
+
+                expect(view._onBeforeUnload($.Event('beforeunload'))).toBeDefined();
+            });
+
+            it("Don't warn user beforeUnload when not editing", function() {
+                expect(view._onBeforeUnload($.Event('beforeunload'))).toBeUndefined();
+            });
+        })
+    });
 });
