ExtensibleCollection.js

From disqus.com, 2 Months ago, written in JavaScript, viewed 3 times. This paste is a reply to SelectiveCollection.js from disqus.com - view diff
URL https://pastebin.freepbx.org/view/8270ce1b Embed
Download Paste or View Raw
  1. define('home/collections/common/ExtensibleCollection',[
  2.     'jquery',
  3.     'underscore',
  4.     'backbone',
  5.  
  6.     'core/collections/PaginatedCollection',
  7. ], function (
  8.     $,
  9.     _,
  10.     Backbone,
  11.  
  12.     PaginatedCollection
  13. ) {
  14.     'use strict';
  15.  
  16.     /**
  17.      * A collection that supplements the thread portion of its contents
  18.      * with additional data from embedly.
  19.      */
  20.     var ExtensibleCollection = PaginatedCollection.extend({
  21.         // Override the default value, 30 since activity endpoints are slow
  22.         PER_PAGE: 10,
  23.  
  24.         initialize: function () {
  25.             PaginatedCollection.prototype.initialize.call(this, arguments);
  26.  
  27.             this.once('sync', this.extendData, this);
  28.             this.on('add:many', this.extendData, this);
  29.             this.on('nodata', this.onNoData, this);
  30.         },
  31.  
  32.         /**
  33.          * Called when an extensible collection is first fetched, when a set of models
  34.          * are added to an extensible colleciton, or when a model in an extensible
  35.          * collection has been fetched.
  36.          * Because of these different triggers, data may be a collection, an array
  37.          * of models, or a single model.
  38.          */
  39.         extendData: function (data) {
  40.             var models;
  41.             if (data.models) {
  42.                 models = data.models;
  43.             } else if (data instanceof Backbone.Model) {
  44.                 models = [data];
  45.  
  46.                 // This case occurs when a single model in this collection is fetched.
  47.                 // Need to rebind the sync listener for future fetches.
  48.                 this.once('sync', this.extendData, this);
  49.             } else {
  50.                 models = data;
  51.             }
  52.  
  53.             if (!models.length) {
  54.                 // Thought there was more items available but they were
  55.                 // probably filtered before being returned.
  56.                 this.cursor.hasNext = false;
  57.                 this.trigger('nodata');
  58.                 return;
  59.             }
  60.  
  61.             // track amount of data we received
  62.             /* TODO: check if thread is already subsidize, now that we're using unique models,
  63.              * a lot of threads are duplicates */
  64.             var from = 0;
  65.             this.extensionRequestsCount = 0;
  66.             do {
  67.                 var to = Math.min(from + 10, models.length);
  68.                 var subset = models.slice(from, to);
  69.  
  70.                 this.requestExData(subset);
  71.                 from += 10;
  72.                 this.extensionRequestsCount += 1;
  73.             } while (from <= models.length - 1);
  74.         },
  75.  
  76.         getThreadFromModel: function (model) {
  77.             if (!model.getThread)
  78.                 throw new Error('Any model that is in an ExtensibleCollection must define function getThread');
  79.  
  80.             return model.getThread();
  81.         },
  82.  
  83.         // Subsidizes existing feed item models with data from embedly.
  84.         // This typically includes an image and a snippet from the thread
  85.         // stored in the feed item, to be used as the thread preview.
  86.         requestExData: function (models, attempts) {
  87.             attempts = attempts || 0;
  88.  
  89.             var modelsByUrl = {};
  90.             _.each(models, function (model) {
  91.                 var thread = this.getThreadFromModel(model);
  92.                 var links = thread && thread.getLinks() || [];
  93.  
  94.                 // If thread contains multiple links, don't choose any of them
  95.                 var url = links.length === 1 ? links[0] : null;
  96.  
  97.                 if (!this.shouldExtend(thread, url)) {
  98.                     if (thread)
  99.                         thread.set({ extending: false });
  100.                     return;
  101.                 }
  102.  
  103.                 thread.set({ extending: true });
  104.                 modelsByUrl[url] = model;
  105.             }, this);
  106.  
  107.             var urls = _.keys(modelsByUrl);
  108.             // Bail out if no threads or urls to extend
  109.             if (!urls.length)
  110.                 return;
  111.  
  112.             var params = {
  113.                 url: urls,
  114.                 words: 200,
  115.                 image_width: 320,
  116.             };
  117.  
  118.             $.ajax({
  119.                 url: ExtensibleCollection.EXTRACT_URL,
  120.                 data: params,
  121.                 traditional: true,
  122.                 dataType: 'jsonp',
  123.                 success: function (response) {
  124.                     models.timeouts = 0;
  125.                     this.onExtendData(response, modelsByUrl);
  126.                 },
  127.                 error: function (response) {
  128.                     this.extendDataFailed(response, models, attempts);
  129.                 },
  130.                 context: this,
  131.                 timeout: 3000,
  132.                 complete: this.checkExtendDataComplete,
  133.             });
  134.         },
  135.  
  136.         shouldExtend: function (thread, url) {
  137.             // Don't bother hitting embedly for urls in rich media. They'll be
  138.             // fetched when the media is rendered.
  139.             return thread && url && !_.any(thread.getMedia(), function (media) {
  140.                 return media.url === url;
  141.             });
  142.         },
  143.  
  144.         onExtendData: function (response, modelsByUrl) {
  145.             this.extensionRequestsCount -= 1;
  146.             _.each(response, function (item) {
  147.                 // IE sometimes gets an `undefined` or `null` `item` here
  148.                 // so first check that and then try to get the model
  149.                 var model = item && modelsByUrl[item.original_url];
  150.                 if (!model)
  151.                     return;
  152.  
  153.                 var thread = this.getThreadFromModel(model);
  154.  
  155.                 thread.setEmbedlyData(item);
  156.                 thread.set({ extending: false });
  157.             }, this);
  158.         },
  159.  
  160.         extendDataFailed: function (response, models, attempts) {
  161.             // Try request 3 times if timeout
  162.             if (response.statusText === 'timeout' && attempts < 3) {
  163.                 this.handleTimeout(models, attempts);
  164.                 return;
  165.             }
  166.  
  167.             _.each(models, function (model) {
  168.                 var thread = this.getThreadFromModel(model);
  169.                 thread.set({ extending: false });
  170.             }, this);
  171.             this.extensionRequestsCount -= 1;
  172.         },
  173.  
  174.         handleTimeout: function (models, attempts) {
  175.             this.requestExData(models, attempts + 1);
  176.         },
  177.  
  178.         checkExtendDataComplete: function () {
  179.             if (this.extensionRequestsCount)  // wait for more responses
  180.                 return;
  181.  
  182.             this.finalizeExtendingData(this.cursor.hasNext);
  183.         },
  184.  
  185.         finalizeExtendingData: function (hasNext) {
  186.             this.trigger('extend', hasNext);
  187.         },
  188.  
  189.         onNoData: function () {
  190.             this.finalizeExtendingData();
  191.         },
  192.     }, {
  193.         EXTRACT_URL: '//extract.services.disqus.com',
  194.     });
  195.  
  196.     return ExtensibleCollection;
  197. });
  198.  
  199. // https://c.disquscdn.com/next/home/js/collections/common/ExtensibleCollection.js

Replies to ExtensibleCollection.js rss

Title Name Language When
urls.js disqus.com javascript 2 Months ago.

Reply to "ExtensibleCollection.js"

Here you can reply to the paste above