← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~abentley/launchpad/yui-navigator into lp:launchpad

 

Aaron Bentley has proposed merging lp:~abentley/launchpad/yui-navigator into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~abentley/launchpad/yui-navigator/+merge/81470

= Summary =
Update ListingNavigator to use YUI's oo, per "Reviewer question about style of new objects in JavaScript" discussion

== Proposed fix ==
None

== Pre-implementation notes ==
None

== Implementation details ==
This is almost entirely mechanical changes, with small changes in the initializer code to avoid long lines.  Where possible, moved attribute initialization to ListingNavigator.ATTRS

== Tests ==
bin/test -t test_buglisting.html

== Demo and Q/A ==
None

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/bugs/javascript/buglisting.js
  lib/lp/bugs/javascript/tests/test_buglisting.js
-- 
https://code.launchpad.net/~abentley/launchpad/yui-navigator/+merge/81470
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~abentley/launchpad/yui-navigator into lp:launchpad.
=== modified file 'lib/lp/bugs/javascript/buglisting.js'
--- lib/lp/bugs/javascript/buglisting.js	2011-11-03 14:55:53 +0000
+++ lib/lp/bugs/javascript/buglisting.js	2011-11-07 17:02:21 +0000
@@ -12,6 +12,11 @@
 var namespace = Y.namespace('lp.bugs.buglisting');
 
 
+function empty_nodelist(){
+    return new Y.NodeList([]);
+}
+
+
 /**
  * Constructor.
  * current_url is used to determine search params.
@@ -23,52 +28,242 @@
  * io_provider is something providing the Y.io interface, typically used for
  * testing.  Defaults to Y.io.
  */
-namespace.ListingNavigator = function(current_url, cache, template, target,
-                                      navigation_indices, io_provider) {
-    var lp_client = new Y.lp.client.Launchpad();
-    this.search_params = namespace.get_query(current_url);
-    delete this.search_params.start;
-    delete this.search_params.memo;
-    delete this.search_params.direction;
-    delete this.search_params.orderby;
-    this.io_provider = io_provider;
-    this.current_batch = lp_client.wrap_resource(null, cache);
-    this.field_visibility = this.current_batch.field_visibility;
-    this.batches = {};
-    this.handle_new_batch(this.current_batch);
-    this.template = template;
-    //Work around mustache.js bug 48 "Blank lines are not preserved."
-    // https://github.com/janl/mustache.js/issues/48
-    if (Y.Lang.isValue(this.template)){
-        this.template = this.template.replace(/\n/g, '
');
-    }
-    this.target = target;
-    this.backwards_navigation = new Y.NodeList([]);
-    this.forwards_navigation = new Y.NodeList([]);
-    if (!Y.Lang.isValue(navigation_indices)){
-        navigation_indices = new Y.NodeList([]);
-    }
-    this.navigation_indices = navigation_indices;
-    this.batch_info_template = '<strong>{{start}}</strong> &rarr; ' +
-        '<strong>{{end}}</strong> of {{total}} results';
-};
-
-
-/**
- * Call the callback when a node matching the selector is clicked.
- *
- * The node is also marked up appropriately.
- */
-namespace.ListingNavigator.prototype.clickAction = function(selector,
-                                                            callback){
-    that = this;
-    var nodes = Y.all(selector);
-    nodes.on('click', function(e){
-        e.preventDefault();
-        callback.call(that);
-    });
-    nodes.addClass('js-action');
-};
+namespace.ListingNavigator = function(config) {
+    namespace.ListingNavigator.superclass.constructor.apply(this, arguments);
+};
+
+
+namespace.ListingNavigator.ATTRS = {
+    batches: {value: {}},
+    batch_info_template: {value: '<strong>{{start}}</strong> &rarr; ' +
+        '<strong>{{end}}</strong> of {{total}} results'},
+    backwards_navigation: {valueFn: empty_nodelist},
+    forwards_navigation: {valueFn: empty_nodelist},
+    io_provider: {value: null},
+    navigation_indices: {valueFn: empty_nodelist}
+};
+
+
+Y.extend(namespace.ListingNavigator, Y.Base, {
+    initializer: function(config){
+        var lp_client = new Y.lp.client.Launchpad();
+        var cache = lp_client.wrap_resource(null, config.cache);
+        var template = config.template;
+        this.set('search_params', namespace.get_query(config.current_url));
+        delete this.get('search_params').start;
+        delete this.get('search_params').memo;
+        delete this.get('search_params').direction;
+        delete this.get('search_params').orderby;
+        this.set('io_provider', config.io_provider);
+        this.set('field_visibility', cache.field_visibility);
+        this.handle_new_batch(cache);
+        this.set('current_batch', cache);
+        //Work around mustache.js bug 48 "Blank lines are not preserved."
+        // https://github.com/janl/mustache.js/issues/48
+        if (Y.Lang.isValue(template)){
+            template = template.replace(/\n/g, '&#10;');
+        }
+        this.set('template', template);
+        this.set('target', config.target);
+        if (Y.Lang.isValue(config.navigation_indices)) {
+            this.set('navigation_indices', config.navigation_indices);
+        }
+    },
+    /**
+     * Call the callback when a node matching the selector is clicked.
+     *
+     * The node is also marked up appropriately.
+     */
+    clickAction: function(selector, callback){
+        that = this;
+        var nodes = Y.all(selector);
+        nodes.on('click', function(e){
+            e.preventDefault();
+            callback.call(that);
+        });
+        nodes.addClass('js-action');
+    },
+
+    /**
+     * Handle a previously-unseen batch by storing it in the cache and
+     * stripping out field_visibility values that would otherwise shadow the
+     * real values.
+     */
+     handle_new_batch: function(batch){
+        var key, i;
+        var batch_key = namespace.ListingNavigator.get_batch_key(batch);
+        Y.each(this.get('field_visibility'), function(value, key){
+            for (i = 0; i < batch.mustache_model.bugtasks.length; i++){
+                delete batch.mustache_model.bugtasks[i][key];
+            }
+        });
+        this.get('batches')[batch_key] = batch;
+    },
+
+    /**
+     * Render bug listings via Mustache.
+     *
+     * If model is supplied, it is used as the data for rendering the
+     * listings.  Otherwise, LP.cache.mustache_model is used.
+     *
+     * The template is always LP.mustache_listings.
+     */
+    render: function(){
+        var model = Y.merge(
+            this.get('current_batch').mustache_model,
+            this.get('field_visibility'));
+        var batch_info = Mustache.to_html(this.get('batch_info_template'), {
+            start: this.get('current_batch').start + 1,
+            end: this.get('current_batch').start +
+                this.get('current_batch').mustache_model.bugtasks.length,
+            total: this.get('current_batch').total
+        });
+        var content = Mustache.to_html(this.get('template'), model);
+        this.get('target').setContent(content);
+        this.get('navigation_indices').setContent(batch_info);
+        this.render_navigation();
+    },
+
+    /**
+     * Enable/disable navigation links as appropriate.
+     */
+    render_navigation: function(){
+        this.get('backwards_navigation').toggleClass(
+            'inactive', this.get('current_batch').prev === null);
+        this.get('forwards_navigation').toggleClass(
+            'inactive', this.get('current_batch').next === null);
+    },
+
+    /**
+     * A shim to use the data of an LP.cache to render the bug listings and
+     * cache their data.
+     *
+     * order_by is the ordering used by the model.
+     */
+    update_from_model: function(model){
+        this.handle_new_batch(model);
+        this.set('current_batch', model);
+        this.render();
+    },
+
+    /**
+     * Return the query vars to use for the specified batch.
+     * This includes the search params and the batch selector.
+     */
+    get_batch_query: function(config){
+        var query = Y.merge(
+            this.get('search_params'), {orderby: config.order_by});
+        if (Y.Lang.isValue(config.memo)){
+            query.memo = config.memo;
+        }
+        if (Y.Lang.isValue(config.start)){
+            query.start = config.start;
+        }
+        if (config.forwards !== undefined && !config.forwards){
+            query.direction = 'backwards';
+        }
+        return query;
+    },
+
+    /**
+     * Update the display to the specified batch.
+     *
+     * If the batch is cached, it will be used immediately.  Otherwise, it
+     * will be retrieved and cached upon retrieval.
+     */
+    update: function(config){
+        var key = namespace.ListingNavigator.get_batch_key(config);
+        var cached_batch = this.get('batches')[key];
+        if (Y.Lang.isValue(cached_batch)){
+            this.set('current_batch', cached_batch);
+            this.render();
+        }
+        else {
+            this.load_model(config);
+        }
+    },
+
+    /**
+     * Update the navigator to display the last batch.
+     */
+    last_batch: function(){
+        this.update({
+            forwards: false,
+            memo: "",
+            start: this.get('current_batch').last_start,
+            order_by: this.get('current_batch').order_by
+        });
+    },
+
+    /**
+     * Update the navigator to display the first batch.
+     *
+     * The order_by defaults to the current ordering, but may be overridden.
+     */
+    first_batch: function(order_by){
+        if (order_by === undefined){
+            order_by = this.get('current_batch').order_by;
+        }
+        this.update({
+            forwards: true,
+            memo: null,
+            start: 0,
+            order_by: order_by
+        });
+    },
+
+    /**
+     * Update the navigator to display the next batch.
+     */
+    next_batch: function(){
+        this.update({
+            forwards: true,
+            memo: this.get('current_batch').next.memo,
+            start:this.get('current_batch').next.start,
+            order_by: this.get('current_batch').order_by
+        });
+    },
+
+    /**
+     * Update the navigator to display the previous batch.
+     */
+    prev_batch: function(){
+        this.update({
+            forwards: false,
+            memo: this.get('current_batch').prev.memo,
+            start:this.get('current_batch').prev.start,
+            order_by: this.get('current_batch').order_by
+        });
+    },
+    /**
+     * Change which fields are displayed in the batch.  Input is a config with
+     * the appropriate visibility variables, such as show_bug_heat,
+     * show_title, etc.
+     */
+    change_fields: function(config){
+        this.set('field_visibility', Y.merge(this.field_visibility, config));
+        this.render();
+    },
+
+    /**
+     * Load the specified batch via ajax.  Display & cache on load.
+     */
+    load_model: function(config){
+        var query = this.get_batch_query(config);
+        var load_model_config = {
+            on: {
+                success: Y.bind(this.update_from_model, this)
+            }
+        };
+        var context = this.get('current_batch').context;
+        if (Y.Lang.isValue(this.get('io_provider'))){
+            load_model_config.io_provider = this.get('io_provider');
+        }
+        Y.lp.client.load_model(
+            context, '+bugs', load_model_config, query);
+    }
+});
+
 
 /**
  * Rewrite all nodes with navigation classes so that they are hyperlinks.
@@ -91,12 +286,16 @@
 namespace.ListingNavigator.from_page = function(){
     var target = Y.one('#client-listing');
     var navigation_indices = Y.all('.batch-navigation-index');
-    var navigator = new namespace.ListingNavigator(
-        window.location, LP.cache, LP.mustache_listings, target,
-        navigation_indices);
+    var navigator = new namespace.ListingNavigator({
+        current_url: window.location,
+        cache: LP.cache,
+        template: LP.mustache_listings,
+        target: target,
+        navigation_indices: navigation_indices
+    });
     namespace.linkify_navigation();
-    navigator.backwards_navigation = Y.all('.first,.previous');
-    navigator.forwards_navigation = Y.all('.last,.next');
+    navigator.set('backwards_navigation', Y.all('.first,.previous'));
+    navigator.set('forwards_navigation', Y.all('.last,.next'));
     navigator.clickAction('.first', navigator.first_batch);
     navigator.clickAction('.next', navigator.next_batch);
     navigator.clickAction('.previous', navigator.prev_batch);
@@ -107,56 +306,6 @@
 
 
 /**
- * Handle a previously-unseen batch by storing it in the cache and stripping
- * out field_visibility values that would otherwise shadow the real values.
- */
-namespace.ListingNavigator.prototype.handle_new_batch = function(batch){
-    var key, i;
-    var batch_key = namespace.ListingNavigator.get_batch_key(batch);
-    Y.each(this.field_visibility, function(value, key){
-        for (i = 0; i < batch.mustache_model.bugtasks.length; i++){
-            delete batch.mustache_model.bugtasks[i][key];
-        }
-    });
-    this.batches[batch_key] = batch;
-};
-
-
-/**
- * Render bug listings via Mustache.
- *
- * If model is supplied, it is used as the data for rendering the listings.
- * Otherwise, LP.cache.mustache_model is used.
- *
- * The template is always LP.mustache_listings.
- */
-namespace.ListingNavigator.prototype.render = function(){
-    var model = Y.merge(
-        this.current_batch.mustache_model, this.field_visibility);
-    var batch_info = Mustache.to_html(this.batch_info_template, {
-        start: this.current_batch.start + 1,
-        end: this.current_batch.start +
-            this.current_batch.mustache_model.bugtasks.length,
-        total: this.current_batch.total
-    });
-    this.target.setContent(Mustache.to_html(this.template, model));
-    this.navigation_indices.setContent(batch_info);
-    this.render_navigation();
-};
-
-
-/**
- * Enable/disable navigation links as appropriate.
- */
-namespace.ListingNavigator.prototype.render_navigation = function(){
-    this.backwards_navigation.toggleClass(
-        'inactive', this.current_batch.prev === null);
-    this.forwards_navigation.toggleClass(
-        'inactive', this.current_batch.next === null);
-};
-
-
-/**
  * Get the key for the specified batch, for use in the batches mapping.
  */
 namespace.ListingNavigator.get_batch_key = function(config){
@@ -164,140 +313,6 @@
                            config.start]);
 };
 
-/**
- * A shim to use the data of an LP.cache to render the bug listings and cache
- * their data.
- *
- * order_by is the ordering used by the model.
- */
-namespace.ListingNavigator.prototype.update_from_model = function(model){
-    this.handle_new_batch(model);
-    this.current_batch = model;
-    this.render();
-};
-
-
-/**
- * Return the query vars to use for the specified batch.
- * This includes the search params and the batch selector.
- */
-namespace.ListingNavigator.prototype.get_batch_query = function(config){
-    var query = Y.merge(this.search_params, {orderby: config.order_by});
-    if (Y.Lang.isValue(config.memo)){
-        query.memo = config.memo;
-    }
-    if (Y.Lang.isValue(config.start)){
-        query.start = config.start;
-    }
-    if (config.forwards !== undefined && !config.forwards){
-        query.direction = 'backwards';
-    }
-    return query;
-};
-
-
-/**
- * Update the display to the specified batch.
- *
- * If the batch is cached, it will be used immediately.  Otherwise, it will be
- * retrieved and cached upon retrieval.
- */
-namespace.ListingNavigator.prototype.update = function(config){
-    var key = namespace.ListingNavigator.get_batch_key(config);
-    var cached_batch = this.batches[key];
-    if (Y.Lang.isValue(cached_batch)){
-        this.current_batch = cached_batch;
-        this.render();
-    }
-    else {
-        this.load_model(config);
-    }
-};
-
-
-/**
- * Update the navigator to display the last batch.
- */
-namespace.ListingNavigator.prototype.last_batch = function(){
-    this.update({
-        forwards: false,
-        memo: "",
-        start: this.current_batch.last_start,
-        order_by: this.current_batch.order_by
-    });
-};
-
-
-/**
- * Update the navigator to display the first batch.
- *
- * The order_by defaults to the current ordering, but may be overridden.
- */
-namespace.ListingNavigator.prototype.first_batch = function(order_by){
-    if (order_by === undefined){
-        order_by = this.current_batch.order_by;
-    }
-    this.update({
-        forwards: true,
-        memo: null,
-        start: 0,
-        order_by: order_by
-    });
-};
-
-
-/**
- * Update the navigator to display the next batch.
- */
-namespace.ListingNavigator.prototype.next_batch = function(){
-    this.update({
-        forwards: true,
-        memo: this.current_batch.next.memo,
-        start:this.current_batch.next.start,
-        order_by: this.current_batch.order_by
-    });
-};
-
-/**
- * Update the navigator to display the previous batch.
- */
-namespace.ListingNavigator.prototype.prev_batch = function(){
-    this.update({
-        forwards: false,
-        memo: this.current_batch.prev.memo,
-        start:this.current_batch.prev.start,
-        order_by: this.current_batch.order_by
-    });
-};
-
-
-/**
- * Change which fields are displayed in the batch.  Input is a config with the
- * appropriate visibility variables, such as show_bug_heat, show_title, etc.:w
- */
-namespace.ListingNavigator.prototype.change_fields = function(config){
-    this.field_visibility = Y.merge(this.field_visibility, config);
-    this.render();
-};
-
-
-/**
- * Load the specified batch via ajax.  Display & cache on load.
- */
-namespace.ListingNavigator.prototype.load_model = function(config){
-    var query = this.get_batch_query(config);
-    var load_model_config = {
-        on: {
-            success: Y.bind(this.update_from_model, this)
-        }
-    };
-    if (Y.Lang.isValue(this.io_provider)){
-        load_model_config.io_provider = this.io_provider;
-    }
-    Y.lp.client.load_model(
-        this.current_batch.context, '+bugs', load_model_config, query);
-};
-
 
 /**
  * Return the query of the specified URL in structured form.

=== modified file 'lib/lp/bugs/javascript/tests/test_buglisting.js'
--- lib/lp/bugs/javascript/tests/test_buglisting.js	2011-11-03 14:40:49 +0000
+++ lib/lp/bugs/javascript/tests/test_buglisting.js	2011-11-07 17:02:21 +0000
@@ -13,19 +13,23 @@
     name: 'ListingNavigator',
     test_sets_search_params: function(){
         // search_parms includes all query values that don't control batching
-        var navigator = new module.ListingNavigator(
-            'http://yahoo.com?foo=bar&start=1&memo=2&direction=3&orderby=4',
-            {});
+        var navigator = new module.ListingNavigator({
+            current_url: 'http://yahoo.com?foo=bar&start=1&memo=2&;' +
+                'direction=3&orderby=4',
+            cache: {}});
         Y.lp.testing.assert.assert_equal_structure(
-            {foo: 'bar'}, navigator.search_params);
+            {foo: 'bar'}, navigator.get('search_params'));
     },
     test_cleans_visibility_from_current_batch: function(){
         // When initial batch is handled, field visibility is stripped.
-        var navigator = new module.ListingNavigator('', {
-            field_visibility: {show_item: true},
-            mustache_model: {bugtasks: [{show_item: true} ] }
+        var navigator = new module.ListingNavigator({
+            current_url: '',
+            cache: {
+                field_visibility: {show_item: true},
+                mustache_model: {bugtasks: [{show_item: true} ] }
+            }
         });
-        bugtask = navigator.current_batch.mustache_model.bugtasks[0];
+        bugtask = navigator.get('current_batch').mustache_model.bugtasks[0];
         Y.Assert.isFalse(bugtask.hasOwnProperty('show_item'));
     },
     test_cleans_visibility_from_new_batch: function(){
@@ -36,10 +40,15 @@
             field_visibility: {show_item: true},
             mustache_model: {bugtasks: []}
         };
-        var navigator = new module.ListingNavigator('', model, '', target);
+        var navigator = new module.ListingNavigator({
+            current_url: '',
+            cache: model,
+            template: '',
+            target: target
+        });
         navigator.update_from_model(
             {mustache_model: {bugtasks: [{show_item: true}]}});
-        bugtask = navigator.current_batch.mustache_model.bugtasks[0];
+        bugtask = navigator.get('current_batch').mustache_model.bugtasks[0];
         Y.Assert.isFalse(bugtask.hasOwnProperty('show_item'));
     }
 }));
@@ -65,21 +74,26 @@
         };
         var template = "{{#bugtasks}}{{#show_foo}}{{foo}}{{/show_foo}}" +
             "{{/bugtasks}}";
-        var navigator =  new module.ListingNavigator(
-            null, lp_cache, template, target);
+        var navigator =  new module.ListingNavigator({
+            cache: lp_cache,
+            template: template,
+            target: target
+        });
         var index = Y.Node.create(
             '<div><strong>3</strong> &rarr; <strong>4</strong>' +
             ' of 512 results</div>');
-        navigator.navigation_indices.push(index);
-        navigator.backwards_navigation.push(Y.Node.create('<div></div>'));
-        navigator.forwards_navigation.push(Y.Node.create('<div></div>'));
+        navigator.get('navigation_indices').push(index);
+        navigator.get('backwards_navigation').push(
+            Y.Node.create('<div></div>'));
+        navigator.get('forwards_navigation').push(
+            Y.Node.create('<div></div>'));
         return navigator;
     },
     test_render: function() {
         // Rendering should work with #client-listing supplied.
         var navigator = this.get_render_navigator();
         navigator.render();
-        Y.Assert.areEqual('bar', navigator.target.getContent());
+        Y.Assert.areEqual('bar', navigator.get('target').getContent());
     },
     /**
      * render_navigation should disable "previous" and "first" if there is
@@ -88,7 +102,7 @@
     test_render_navigation_disables_backwards_navigation_if_no_prev:
     function() {
         var navigator = this.get_render_navigator();
-        var action = navigator.backwards_navigation.item(0);
+        var action = navigator.get('backwards_navigation').item(0);
         navigator.render_navigation();
         Y.Assert.isTrue(action.hasClass('inactive'));
     },
@@ -99,9 +113,9 @@
     test_render_navigation_enables_backwards_navigation_if_prev:
     function() {
         var navigator = this.get_render_navigator();
-        var action = navigator.backwards_navigation.item(0);
+        var action = navigator.get('backwards_navigation').item(0);
         action.addClass('inactive');
-        navigator.current_batch.prev = {
+        navigator.get('current_batch').prev = {
             start: 1, memo: 'pi'
         };
         navigator.render_navigation();
@@ -114,7 +128,7 @@
     test_render_navigation_disables_forwards_navigation_if_no_next:
     function() {
         var navigator = this.get_render_navigator();
-        var action = navigator.forwards_navigation.item(0);
+        var action = navigator.get('forwards_navigation').item(0);
         navigator.render_navigation();
         Y.Assert.isTrue(action.hasClass('inactive'));
     },
@@ -124,9 +138,9 @@
      */
     test_render_navigation_enables_forwards_navigation_if_next: function() {
         var navigator = this.get_render_navigator();
-        var action = navigator.forwards_navigation.item(0);
+        var action = navigator.get('forwards_navigation').item(0);
         action.addClass('inactive');
-        navigator.current_batch.next = {
+        navigator.get('current_batch').next = {
             start: 1, memo: 'pi'
         };
         navigator.render_navigation();
@@ -159,7 +173,7 @@
      */
     test_render_navigation_indices: function(){
         var navigator = this.get_render_navigator();
-        index = navigator.navigation_indices.item(0);
+        var index = navigator.get('navigation_indices').item(0);
         Y.Assert.areEqual(
             '<strong>3</strong> \u2192 <strong>4</strong> of 512 results',
             index.getContent());
@@ -172,11 +186,11 @@
         // change_fields updates field visibility state and re-renders.
         var navigator = this.get_render_navigator();
         navigator.render();
-        Y.Assert.areEqual('bar', navigator.target.getContent());
-        Y.Assert.isTrue(navigator.field_visibility.show_foo);
+        Y.Assert.areEqual('bar', navigator.get('target').getContent());
+        Y.Assert.isTrue(navigator.get('field_visibility').show_foo);
         navigator.change_fields({show_foo: false});
-        Y.Assert.isFalse(navigator.field_visibility.show_foo);
-        Y.Assert.areEqual('', navigator.target.getContent());
+        Y.Assert.isFalse(navigator.get('field_visibility').show_foo);
+        Y.Assert.areEqual('', navigator.get('target').getContent());
     }
 }));
 
@@ -199,12 +213,16 @@
             }
         };
         var target = Y.Node.create('<div id="client-listing"></div>');
-        var navigator = new module.ListingNavigator(
-            "http://yahoo.com?start=5&memo=6&direction=backwards";,
-            lp_cache, "<ol>" + "{{#item}}<li>{{name}}</li>{{/item}}</ol>",
-            target, null, mock_io);
+        var navigator = new module.ListingNavigator({
+            current_url:
+                "http://yahoo.com?start=5&memo=6&direction=backwards";,
+            cache: lp_cache,
+            template: "<ol>" + "{{#item}}<li>{{name}}</li>{{/item}}</ol>",
+            target: target,
+            io_provider: mock_io
+        });
         navigator.first_batch('intensity');
-        Y.Assert.areEqual('', navigator.target.getContent());
+        Y.Assert.areEqual('', navigator.get('target').getContent());
         mock_io.last_request.successJSON({
             context: {
                 resource_type_link: 'http://foo_type',
@@ -228,9 +246,9 @@
         /* first_batch retrieves a listing for the new ordering and
          * displays it */
         var navigator = this.get_intensity_listing();
-        var mock_io = navigator.io_provider;
+        var mock_io = navigator.get('io_provider');
         Y.Assert.areEqual('<ol><li>first</li><li>second</li></ol>',
-            navigator.target.getContent());
+            navigator.get('target').getContent());
         Y.Assert.areEqual('/bar/+bugs/++model++?orderby=intensity&start=0',
             mock_io.last_request.url);
     },
@@ -238,9 +256,9 @@
         /* first_batch will use the cached value instead of making a
          * second AJAX request. */
         var navigator = this.get_intensity_listing();
-        Y.Assert.areEqual(1, navigator.io_provider.requests.length);
+        Y.Assert.areEqual(1, navigator.get('io_provider').requests.length);
         navigator.first_batch('intensity');
-        Y.Assert.areEqual(1, navigator.io_provider.requests.length);
+        Y.Assert.areEqual(1, navigator.get('io_provider').requests.length);
     }
 }));
 
@@ -261,8 +279,12 @@
         var template = "<ol>" +
             "{{#item}}<li>{{name}}</li>{{/item}}</ol>";
         var target = Y.Node.create('<div id="client-listing"></div>');
-        var navigator = new module.ListingNavigator(
-            window.location, lp_cache, template, target);
+        var navigator = new module.ListingNavigator({
+            current_url: window.location,
+            cache: lp_cache,
+            template: template,
+            target: target
+        });
         var key = module.ListingNavigator.get_batch_key({
             order_by: "intensity",
             memo: 'memo1',
@@ -283,7 +305,7 @@
             }};
         navigator.update_from_model(batch);
         Y.lp.testing.assert.assert_equal_structure(
-            batch, navigator.batches[key]);
+            batch, navigator.get('batches')[key]);
     },
     /**
      * get_batch_key returns a JSON-serialized list.
@@ -317,7 +339,10 @@
      * get_batch_query accepts the order_by param.
      */
     test_get_batch_query_orderby: function(){
-        var navigator = new module.ListingNavigator('?param=1', {});
+        var navigator = new module.ListingNavigator({
+            current_url: '?param=1',
+            cache: {}
+        });
         var query = navigator.get_batch_query({order_by: 'importance'});
         Y.Assert.areSame('importance', query.orderby);
         Y.Assert.areSame(1, query.param);
@@ -326,7 +351,10 @@
      * get_batch_query accepts the memo param.
      */
     test_get_batch_query_memo: function(){
-        var navigator = new module.ListingNavigator('?param=foo', {});
+        var navigator = new module.ListingNavigator({
+            current_url: '?param=foo',
+            cache: {}
+        });
         var query = navigator.get_batch_query({memo: 'pi'});
         Y.Assert.areSame('pi', query.memo);
         Y.Assert.areSame('foo', query.param);
@@ -335,7 +363,10 @@
      * When memo is null, query.memo is undefined.
      */
     test_get_batch_null_memo: function(){
-        var navigator = new module.ListingNavigator('?memo=foo', {});
+        var navigator = new module.ListingNavigator({
+            current_url: '?memo=foo',
+            cache: {}
+        });
         var query = navigator.get_batch_query({memo: null});
         Y.Assert.areSame(undefined, query.memo);
     },
@@ -343,8 +374,10 @@
      * If 'forwards' is true, direction does not appear.
      */
     test_get_batch_query_forwards: function(){
-        var navigator = new module.ListingNavigator(
-            '?param=pi&direction=backwards', {});
+        var navigator = new module.ListingNavigator({
+            current_url: '?param=pi&direction=backwards',
+            cache: {}
+        });
         var query = navigator.get_batch_query({forwards: true});
         Y.Assert.areSame('pi', query.param);
         Y.Assert.areSame(undefined, query.direction);
@@ -353,7 +386,10 @@
      * If 'forwards' is false, direction is set to backwards.
      */
     test_get_batch_query_backwards: function(){
-        var navigator = new module.ListingNavigator('?param=pi', {});
+        var navigator = new module.ListingNavigator({
+            current_url: '?param=pi',
+            cache: {}
+        });
         var query = navigator.get_batch_query({forwards: false});
         Y.Assert.areSame('pi', query.param);
         Y.Assert.areSame('backwards', query.direction);
@@ -362,7 +398,10 @@
      * If start is provided, it overrides existing values.
      */
     test_get_batch_query_start: function(){
-        var navigator = new module.ListingNavigator('?start=pi', {});
+        var navigator = new module.ListingNavigator({
+            current_url: '?start=pi',
+            cache: {}
+        });
         var query = navigator.get_batch_query({});
         Y.Assert.areSame(undefined, query.start);
         query = navigator.get_batch_query({start: 1});
@@ -390,8 +429,11 @@
         order_by: 'foo',
         last_start: 23
     };
-    return new module.ListingNavigator(url, lp_cache, null, null, null,
-                                       mock_io);
+    return new module.ListingNavigator({
+        current_url: url,
+        cache: lp_cache,
+        io_provider: mock_io
+    });
 };
 
 suite.add(new Y.Test.Case({
@@ -407,7 +449,7 @@
         Y.Assert.areSame(
             '/bar/+bugs/++model++?orderby=foo&memo=&start=23&' +
             'direction=backwards',
-            navigator.io_provider.last_request.url);
+            navigator.get('io_provider').last_request.url);
     },
     /**
      * first_batch omits memo and direction, start=0,
@@ -418,7 +460,7 @@
         navigator.first_batch();
         Y.Assert.areSame(
             '/bar/+bugs/++model++?orderby=foo&start=0',
-            navigator.io_provider.last_request.url);
+            navigator.get('io_provider').last_request.url);
     },
     /**
      * next_batch uses values from current_batch.next +
@@ -429,7 +471,7 @@
         navigator.next_batch();
         Y.Assert.areSame(
             '/bar/+bugs/++model++?orderby=foo&memo=467&start=500',
-            navigator.io_provider.last_request.url);
+            navigator.get('io_provider').last_request.url);
     },
     /**
      * prev_batch uses values from current_batch.prev + direction=backwards
@@ -441,7 +483,7 @@
         Y.Assert.areSame(
             '/bar/+bugs/++model++?orderby=foo&memo=457&start=400&' +
             'direction=backwards',
-            navigator.io_provider.last_request.url);
+            navigator.get('io_provider').last_request.url);
     }
 }));