From 63d7b39434f444e3536dc0576267db8649ff3058 Mon Sep 17 00:00:00 2001 From: Max Goodman Date: Sat, 2 Feb 2013 01:53:53 -0800 Subject: [PATCH] Client side spotlight stubs + back/prev buffer. --- r2/r2/controllers/api.py | 8 +- r2/r2/public/static/css/reddit.css | 3 + r2/r2/public/static/js/base.js | 1 + r2/r2/public/static/js/reddit.js | 8 +- r2/r2/public/static/js/spotlight.js | 177 ++++++++++++++++---------- r2/r2/public/static/prev_organic.png | Bin 0 -> 238 bytes r2/r2/templates/spotlightlisting.html | 7 +- 7 files changed, 125 insertions(+), 79 deletions(-) create mode 100644 r2/r2/public/static/prev_organic.png diff --git a/r2/r2/controllers/api.py b/r2/r2/controllers/api.py index 018720da1..2ea5876bc 100755 --- a/r2/r2/controllers/api.py +++ b/r2/r2/controllers/api.py @@ -3097,9 +3097,8 @@ class ApiController(RedditController, OAuth2ResourceController): @validatedForm(link=nop('link'), - campaign=nop('campaign'), - show=VBoolean('show')) - def GET_fetch_promo(self, form, jquery, link, campaign, show): + campaign=nop('campaign')) + def GET_fetch_promo(self, form, jquery, link, campaign): promo_tuples = [promote.PromoTuple(link, 1., campaign)] builder = CampaignBuilder(promo_tuples, wrap=default_thing_wrapper(), @@ -3110,9 +3109,6 @@ class ApiController(RedditController, OAuth2ResourceController): interestbar=None).listing() jquery(".content").replace_things(listing) - if show: - jquery('.organic-listing .thing:visible').hide() - jquery('.organic-listing .id-%s' % link).show() @noresponse(VUser(), ui_elem = VOneOf('id', ('organic',))) diff --git a/r2/r2/public/static/css/reddit.css b/r2/r2/public/static/css/reddit.css index dd83c235c..88de53729 100755 --- a/r2/r2/public/static/css/reddit.css +++ b/r2/r2/public/static/css/reddit.css @@ -986,6 +986,9 @@ a.author { margin-right: 0.5em; } /* This is a really weird value, but it needs to be low to hide text without affecting layout in IE. */ text-indent: 50px; } +.organic-listing .nextprev .arrow.prev { + background-image: url(../prev_organic.png); /* SPRITE */ +} .organic-listing .nextprev .arrow.next { background-image: url(../next_organic.png); /* SPRITE */ } diff --git a/r2/r2/public/static/js/base.js b/r2/r2/public/static/js/base.js index 7cc407ba1..9c45a2875 100644 --- a/r2/r2/public/static/js/base.js +++ b/r2/r2/public/static/js/base.js @@ -19,6 +19,7 @@ $(function() { r.login.ui.init() r.analytics.init() r.ui.init() + r.spotlight.init() r.interestbar.init() r.apps.init() r.wiki.init() diff --git a/r2/r2/public/static/js/reddit.js b/r2/r2/public/static/js/reddit.js index 444874368..323fa56b4 100644 --- a/r2/r2/public/static/js/reddit.js +++ b/r2/r2/public/static/js/reddit.js @@ -522,19 +522,19 @@ function updateEventHandlers(thing) { .click(function() { var a = $(this).get(0); change_state(a, 'hide', - function() { r.spotlight.shuffle() }); + function() { r.spotlight.next() }); }); thing.find(".del-button a.yes") .click(function() { var a = $(this).get(0); change_state(a, 'del', - function() { r.spotlight.shuffle() }); + function() { r.spotlight.next() }); }); thing.find(".report-button a.yes") .click(function() { var a = $(this).get(0); change_state(a, 'report', - function() { r.spotlight.shuffle() }); + function() { r.spotlight.next() }); }); } }; @@ -1157,8 +1157,6 @@ $(function() { $(this).select(); }); - r.spotlight.shuffle(); - /* ajax ynbutton */ function toggleThis() { return toggle(this); } $("body") diff --git a/r2/r2/public/static/js/spotlight.js b/r2/r2/public/static/js/spotlight.js index 40cff3fa4..a89e88edf 100644 --- a/r2/r2/public/static/js/spotlight.js +++ b/r2/r2/public/static/js/spotlight.js @@ -1,15 +1,53 @@ r.spotlight = {} -r.spotlight.link_by_camp = {} -r.spotlight.weights = {} -r.spotlight.organics = [] -r.spotlight.interest_prob = 0 -r.spotlight.promotion_prob = 1 +r.spotlight.init = function() { + var listing = $('.organic-listing') + if (!listing.length) { + return + } -r.spotlight.init = function(links, interest_prob, promotion_prob) { - var link_by_camp = {}, - weights = {}, - organics = [] + $('.organic-listing .arrow.prev').on('click', $.proxy(this, 'prev')) + $('.organic-listing .arrow.next').on('click', $.proxy(this, 'next')) + + _.each(this.link_by_camp, function(fullname, campaign) { + if (!listing.find('.id-' + fullname).length) { + this.createStub(fullname, campaign) + } + }, this) + + var selectedThing, + lastClickFullname = r.analytics.breadcrumbs.lastClickFullname(), + lastClickThing = $(lastClickFullname ? '.id-' + lastClickFullname : null) + if (lastClickThing.length && listing.has(lastClickThing).length) { + r.debug('restoring spotlight selection to last click') + selectedThing = lastClickThing + } else { + selectedThing = this.chooseRandom() + } + + this.lineup = _.chain(listing.find('.thing')) + .reject(function(el) { return selectedThing.is(el) }) + .shuffle() + .unshift(selectedThing) + .map(function(el) { + var fullname = $(el).data('fullname') + if (fullname) { + // convert things with ids to queries to handle stub replacement + return '.id-' + fullname + } else { + return el + } + }) + .value() + + this.lineup.pos = 0 + r.spotlight._advance(0) +} + +r.spotlight.setup = function(links, interest_prob, promotion_prob) { + this.link_by_camp = {}, + this.weights = {}, + this.organics = [] for (var index in links) { var link = links[index][0], @@ -18,66 +56,80 @@ r.spotlight.init = function(links, interest_prob, promotion_prob) { weight = links[index][3] if (is_promo) { - link_by_camp[campaign] = link - weights[campaign] = weight + this.link_by_camp[campaign] = link + this.weights[campaign] = weight } else { - organics.push(link) + this.organics.push(link) } } - _.extend(r.spotlight.link_by_camp, link_by_camp) - _.extend(r.spotlight.weights, weights) - _.extend(r.spotlight.organics, organics) - r.spotlight.interest_prob = interest_prob - r.spotlight.promotion_prob = promotion_prob + this.interest_prob = interest_prob + this.promotion_prob = promotion_prob } -r.spotlight.shuffle = function() { - var listing = $('.organic-listing'), - visible = listing.find(".thing:visible") +r.spotlight.createStub = function(fullname, campaign) { + var stub = $('
') + .addClass('thing stub') + .addClass('id-'+fullname) + .data('fullname', fullname) + .data('cid', campaign) + .prependTo('.organic-listing') +} - if (listing.length == 0) { - $.debug('exiting, no organic listing') - return - } - - if(Math.random() < r.spotlight.promotion_prob) { - $.debug('showing promoted link') - var campaign_name = r.spotlight.weighted_lottery(r.spotlight.weights), - link_name = r.spotlight.link_by_camp[campaign_name], - thing = listing.find(".id-" + link_name) - $.debug('showing ' + campaign_name) - if (thing.hasClass('stub')) { - $.debug('fetching') - $.request("fetch_promo", { - link: link_name, - campaign: campaign_name, - show: true, - listing: listing.attr("id") - }, - null, null, null, true - ) - } else { - $.debug('no need to fetch') - $.debug('setting cid') - thing.data('cid', campaign_name) - } - r.spotlight.help('promoted') - } else if (Math.random() < r.spotlight.interest_prob) { - $.debug('showing interest bar') - var thing = listing.find(".interestbar") - r.spotlight.help('interestbar') +r.spotlight.chooseRandom = function() { + var listing = $('.organic-listing') + if (!_.isEmpty(this.weights) + && Math.random() < this.promotion_prob) { + var campaign_name = this.weighted_lottery(this.weights), + link_name = this.link_by_camp[campaign_name] + return listing.find('.id-' + link_name) + } else if (Math.random() < this.interest_prob) { + return listing.find('.interestbar') } else { - $.debug('showing organic link') - var name = r.spotlight.organics[Math.floor(Math.random() * r.spotlight.organics.length)], - thing = listing.find(".id-" + name) - r.spotlight.help('organic') + var name = this.organics[Math.floor(Math.random() * this.organics.length)] + return listing.find('.id-' + name) } - visible.hide() - thing.show() } -r.spotlight.help = function(type) { +r.spotlight._advance = function(dir) { + var listing = $('.organic-listing'), + visible = listing.find('.thing:visible'), + nextPos = (this.lineup.pos + dir + this.lineup.length) % this.lineup.length, + next = listing.find(this.lineup[nextPos]) + + if (next.hasClass('stub')) { + var fullname = next.data('fullname'), + campaign = next.data('cid') + r.debug('fetching promo %s from campaign %s', fullname, campaign) + + next = $.getJSON('/api/fetch_promo', { + link: fullname, + campaign: campaign + }).pipe(function(resp) { + $.handleResponse('fetch_promo')(resp) + return listing.find('.id-' + fullname) + }) + } + + $.when(next).done(_.bind(function(next) { + // size the rank element so that spotlight box + // items line up with the main page listing + next.find('.rank') + .width($('#siteTable .rank').width()) + .end() + + visible.hide() + next.show() + + this.lineup.pos = nextPos + this.help(next) + }, this)) +} + +r.spotlight.next = $.proxy(r.spotlight, '_advance', 1) +r.spotlight.prev = $.proxy(r.spotlight, '_advance', -1) + +r.spotlight.help = function(thing) { var help = $('#spotlight-help') if (!help.length) { @@ -86,9 +138,9 @@ r.spotlight.help = function(type) { help.data('HelpBubble').hide(function() { help.find('.help-section').hide() - if (type == 'promoted') { + if (thing.hasClass('promoted')) { help.find('.help-promoted').show() - } else if (type == 'interestbar') { + } else if (thing.hasClass('interestbar')) { help.find('.help-interestbar').show() } else { help.find('.help-organic').show() @@ -100,15 +152,12 @@ r.spotlight.weighted_lottery = function(weights) { var seed_rand = Math.random(), t = 0 - $.debug('random: ' + seed_rand) for (var name in weights) { weight = weights[name] t += weight - $.debug(name + ': ' + weight) if (t > seed_rand) { - $.debug('picked ' + name) return name } } - $.debug('whoops, fell through!') + r.warn('weighted_lottery fell through!') } diff --git a/r2/r2/public/static/prev_organic.png b/r2/r2/public/static/prev_organic.png new file mode 100644 index 0000000000000000000000000000000000000000..5ad151275e1ec7c5834b939402da760366e779cb GIT binary patch literal 238 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S3?yCqj{O5tQ2{<7u5(wdTDWS};#I4buUfTg zsZSnVXaSW-rwRVEJP=kR0vu}iv z#Oyi${`*$NW>2*?xAJ_q+3OI~SKXZQGga4v><+0}9L+!b^2>3C_DxF{m`A$p@Y&b) lDs)?_%jLt(Up%&5<(KwUeenBn^CO_q44$rjF6*2UngD7uf+hd} literal 0 HcmV?d00001 diff --git a/r2/r2/templates/spotlightlisting.html b/r2/r2/templates/spotlightlisting.html index 199e2cd24..c0386988f 100644 --- a/r2/r2/templates/spotlightlisting.html +++ b/r2/r2/templates/spotlightlisting.html @@ -33,8 +33,6 @@ %for tup in thing.links: %if tup.link in thing.lookup: ${unsafe(thing.lookup[tup.link].render(display=False))} - %else: - %endif %endfor %endif @@ -46,7 +44,8 @@ %endif
- + +
@@ -92,7 +91,7 @@