Re: Thread.js

From disqus.com, 2 Months ago, written in JavaScript, viewed 3 times. This paste is a reply to Re: User.js from disqus.com - view diff
URL https://pastebin.freepbx.org/view/5c72848a Embed
Download Paste or View Raw
  1. define('core/models/Thread',[
  2.     'underscore',
  3.     'backbone',
  4.     'loglevel',
  5.  
  6.     'core/config/urls',
  7.  
  8.     'core/utils',
  9.     'core/api',
  10.     'core/config',
  11.     'core/advice',
  12.     'core/UniqueModel',
  13.     'core/utils/threadRatingsHelpers',
  14.  
  15.     'core/models/User',
  16. ], function (
  17.     _,
  18.     Backbone,
  19.     logger,
  20.  
  21.     urls,
  22.  
  23.     utils,
  24.     api,
  25.     config,
  26.     advice,
  27.     UniqueModel,
  28.     threadRatingsHelpers,
  29.  
  30.     User
  31. ) {
  32.     'use strict';
  33.  
  34.     var parent = Backbone.Model;
  35.     var parentProto = parent.prototype;
  36.  
  37.  
  38.     var Thread = parent.extend({
  39.         defaults: {
  40.             author: null,
  41.             category: null,
  42.             createdAt: null,  // Date time in string. Format: YYYY-MM-DDTHH:mm:ss
  43.             forum: null,
  44.             identifiers: [],
  45.             ipAddress: null,
  46.             isClosed: false,
  47.             isDeleted: false,
  48.             hasStreaming: false,
  49.             link: null,  // Direct url to this thread
  50.             message: null,
  51.             slug: null,
  52.             title: null,
  53.             userSubscription: false,
  54.  
  55.             // Counters
  56.             posts: 0,
  57.             likes: 0,
  58.             dislikes: 0,
  59.             userScore: 0,
  60.         },
  61.  
  62.         initialize: function (_attributes, options) {
  63.             options = options || {};
  64.  
  65.             // Array of moderator ids for this thread (integers)
  66.             this.moderators = options.moderators;
  67.  
  68.             this.forum = options.forum;
  69.  
  70.             this.on('change:userScore', function () {
  71.                 var userScore = this.get('userScore');
  72.  
  73.                 // If the user voted this Thread but likes is 0, means we got a
  74.                 // cached result for likes, so update it to not confuse the user
  75.                 if (userScore > 0 && this.get('likes') === 0)
  76.                     this.set('likes', userScore);
  77.  
  78.                 // NOTE: Note that we don't handle dislikes and negative user
  79.                 //       votes above since we don't have that concept yet.
  80.             }, this);
  81.         },
  82.  
  83.         _vote: function (vote, score) {
  84.             var delta = vote - score;
  85.  
  86.             // If the vote is unchanged, ignore it.
  87.             if (delta === 0)
  88.                 return delta;
  89.  
  90.             this.set('likes', this.get('likes') + delta);
  91.             return delta;
  92.         },
  93.  
  94.         vote: function (vote) {
  95.             var self = this;
  96.             var delta = self._vote(vote, self.get('userScore'));
  97.  
  98.             if (delta === 0)
  99.                 return;
  100.  
  101.             this.set('userScore', vote);
  102.  
  103.             api.call('threads/vote.json', {
  104.                 data: {
  105.                     thread: this.id,
  106.                     vote: vote,
  107.                 },
  108.                 method: 'POST',
  109.                 success: function (data) {
  110.                     if (!data.response.id)
  111.                         return;
  112.  
  113.                     self.trigger('vote:success', data);
  114.                 },
  115.             });
  116.         },
  117.  
  118.         fetch: function (options) {
  119.             var self = this;
  120.             var attrs = self.attributes;
  121.             var query;
  122.  
  123.             options = options || {};
  124.  
  125.             if (attrs.identifier)
  126.                 query = 'ident:' + attrs.identifier;
  127.             else
  128.                 query = 'link:' + attrs.url;
  129.  
  130.             api.call('threads/details.json', {
  131.                 data: {
  132.                     thread: query,
  133.                     forum: attrs.forum,
  134.                 },
  135.  
  136.                 success: function (data) {
  137.                     self.set(data.response);
  138.                     if (options.success) options.success();
  139.                 },
  140.  
  141.                 error: function () {
  142.                     if (config.debug)  // Create a new thread
  143.                         self.save({}, { success: options.success });
  144.                     else  // For Alpha release only.
  145.                         logger.info('Couldn\'t find thread; not creating in production.');
  146.                 },
  147.             });
  148.         },
  149.  
  150.         _toggleState: function (isOpen, options) {
  151.             if (!options)
  152.                 options = {};
  153.  
  154.             var action = isOpen ? 'open.json' : 'close.json';
  155.             this.set('isClosed', !isOpen);
  156.  
  157.             return api.call('threads/' + action, {
  158.                 method: 'POST',
  159.                 data: {
  160.                     thread: this.id,
  161.                 },
  162.                 success: options.success,
  163.                 error: options.error,
  164.             });
  165.         },
  166.  
  167.         open: function (options) {
  168.             return this._toggleState(true, options);
  169.         },
  170.  
  171.         close: function (options) {
  172.             return this._toggleState(false, options);
  173.         },
  174.  
  175.         /**
  176.          * Change the thread's premoderation status. Auth'd user must have write
  177.          * privileges for the thread.
  178.          *
  179.          * @param {boolean} isPremoderated - the new premoderation status
  180.          * @param {Object} [options] - options to pass to the api call
  181.          * @returns {jqXHR}
  182.          */
  183.         premoderate: function (isPremoderated, options) {
  184.             this.set('validateAllPosts', isPremoderated);
  185.  
  186.             return api.call('threads/update', _.extend({}, options, {
  187.                 method: 'POST',
  188.                 data: _.extend({
  189.                     thread: this.id,
  190.                     validateAllPosts: isPremoderated ? 1 : 0,
  191.                 }, options && options.data),
  192.             }));
  193.         },
  194.  
  195.         sync: function () {
  196.             var self = this;
  197.             var attrs = self.attributes;
  198.  
  199.             api.call('threads/create.json', {
  200.                 data: {
  201.                     title: attrs.title,
  202.                     forum: attrs.forum,
  203.                     identifier: attrs.identifier,
  204.                     url: attrs.url,
  205.                 },
  206.                 method: 'POST',
  207.                 success: function (data) {
  208.                     self.set(data.response);
  209.                 },
  210.             });
  211.         },
  212.  
  213.         fetchRatings: function () {
  214.             var self = this;
  215.  
  216.             var data = { thread: self.id };
  217.  
  218.             return api.call('threads/ratingsSummary.json', {
  219.                 data: data,
  220.                 method: 'GET',
  221.                 success: function (response) {
  222.                     self.set('ratings', response.response);
  223.                 },
  224.             });
  225.         },
  226.  
  227.         toggleRatingsEnabled: function () {
  228.             var self = this;
  229.             if (!threadRatingsHelpers.isForumModelRatingsEnabled(self.forum))
  230.                 return;
  231.  
  232.             var ratingsEnabled = self.get('ratingsEnabled');
  233.  
  234.             var data = {
  235.                 thread: self.id,
  236.                 ratingsEnabled: ratingsEnabled ? 0 : 1, // invert the ratings enabled
  237.             };
  238.  
  239.             self.set('ratingsEnabled', !ratingsEnabled);
  240.  
  241.             return api.call('threads/update.json', {
  242.                 data: data,
  243.                 method: 'POST',
  244.             });
  245.         },
  246.  
  247.         /**
  248.          * Increment the reported count of posts for this thread.
  249.          *
  250.          * You cannot decrement the post count below 0.
  251.          * @param  {number} inc A positive or negative number
  252.          */
  253.         incrementPostCount: function (inc) {
  254.             var count = this.get('posts') + inc;
  255.             this.set('posts', count > 0 ? count : 0);
  256.         },
  257.  
  258.         isModerator: function (user) {
  259.             // Accepts user instance or user id and returns true, false,
  260.             // or undefined (if function cannot determine)
  261.             var id;
  262.  
  263.             if (!this.moderators)
  264.                 return;
  265.  
  266.             id = user instanceof User || _.isObject(user) ? user.id : user;
  267.             id = parseInt(id, 10);
  268.             return _(this.moderators).contains(id);
  269.         },
  270.  
  271.         subscribe: function (subscribe) {
  272.             subscribe = subscribe !== false;  // default is to subscribe
  273.  
  274.             // the below can be a boolean or the e-mail used to subscribe
  275.             var currentSubscription = this.get('userSubscription');
  276.             if (currentSubscription === subscribe)
  277.                 return;  // do nothing if the state is same
  278.  
  279.             this.set('userSubscription', subscribe);
  280.  
  281.             var endpoint = subscribe ? 'subscribe.json' : 'unsubscribe.json';
  282.             var data = { thread: this.id };
  283.  
  284.             return api.call('threads/' + endpoint, {
  285.                 data: data,
  286.                 method: 'POST',
  287.             });
  288.         },
  289.  
  290.         twitterText: function (url) {
  291.             var charsRemaining = 140 - (url.length + 1);  // +1 for space before url
  292.             var text = this.get('clean_title');
  293.             text = utils.niceTruncate(text, charsRemaining);
  294.             return text;
  295.         },
  296.  
  297.         permalink: function () {
  298.             // Sometimes url or link isn't available. In which case, use the "current
  299.             // URL", which is the referring URL that opened the current embed context
  300.             return this.get('url') || this.get('link') || this.currentUrl;
  301.         },
  302.  
  303.         shortLink: function () {
  304.             return urls.shortener + '/t/' + Number(this.id).toString(36);
  305.         },
  306.  
  307.         toJSON: function () {
  308.             var json = parentProto.toJSON.call(this);
  309.  
  310.             json.permalink = this.permalink();
  311.             json.shortLink = this.shortLink();
  312.  
  313.             return json;
  314.         },
  315.  
  316.         /**
  317.          * Returns a full path to the discussion page on home for this thread.
  318.          *
  319.          * If channel is given, or if this thread is on the primary forum
  320.          * for a channel, the discussion page will contain a link to the
  321.          * channel.
  322.          *
  323.          * @param {Channel} [channel] - the channel the discussion page is to link to
  324.          * @returns {string}
  325.          */
  326.         getDiscussionRoute: function (channel) {
  327.             var route = [
  328.                 '',  // for leading slash
  329.                 'home',
  330.                 'discussion',
  331.                 this.forum.id,
  332.                 this.get('slug'),
  333.                 '',  // for trailing slash
  334.             ];
  335.  
  336.             channel = channel || this.forum.channel;
  337.             if (channel) {
  338.                 channel = channel.attributes || channel;
  339.                 route.splice(2, 0, 'channel', channel.slug);
  340.             }
  341.  
  342.             return route.join('/');
  343.         },
  344.     });
  345.  
  346.     advice.withAdvice.call(Thread.prototype);
  347.  
  348.  
  349.     Thread.withThreadVoteCollection = function (ThreadVoteCollection) {
  350.         this.after('initialize', function () {
  351.             this.votes = new ThreadVoteCollection();
  352.  
  353.             this.on('vote:success', function (data) {
  354.                 if (this.votes.get(data.response.id))
  355.                     return;
  356.  
  357.                 this.votes.add({
  358.                     id: data.response.id,
  359.                     score: data.response.vote, // TODO
  360.  
  361.                     // mark this vote as made by current user so we can ignore
  362.                     // it when it comes through realtime
  363.                     currentUser: true,
  364.                 });
  365.  
  366.             }, this);
  367.         });
  368.     };
  369.  
  370.     Thread.withPostCollection = function (PostCollection) {
  371.         this.after('initialize', function (options) {
  372.             options = options || {};
  373.             this.posts = new PostCollection(options.posts, {
  374.                 thread: this,
  375.                 cursor: options.postCursor,
  376.                 order: options.order,
  377.                 perPage: this.postsPerPage,
  378.             });
  379.  
  380.             this.listenTo(this.posts, 'add reset', function (posts) {
  381.                 // Reset returns Collection object, so can't use
  382.                 posts = posts.models ? posts.models : [posts];
  383.  
  384.                 if (this.users) {
  385.                     _.each(posts, function (post) {
  386.                         if (!this.users.get(post.author.id))
  387.                             this.users.add(post.author);
  388.                     });
  389.                 }
  390.  
  391.                 this.recalculatePostCount();
  392.             });
  393.  
  394.             this.listenTo(
  395.                 this.posts,
  396.                 'change:isDeleted change:isFlagged',
  397.                 function (_post, value) {
  398.                     // If isDeleted or isFlagged is true then we decrement the post count.
  399.                     if (value)
  400.                         this.incrementPostCount(-1);
  401.                 }
  402.             );
  403.         });
  404.  
  405.         /**
  406.          * Recalculate `posts` attribute of this thread.
  407.          *
  408.          * If the current reported post count is 50 or less then we manually count how many
  409.          * of the posts we currently have on the page are publicly visible.
  410.          * If the API reported more than 50 then we don't care about accuracy as much.
  411.          */
  412.         this.recalculatePostCount = function () {
  413.             var count = this.get('posts');
  414.             if (count > 50)
  415.                 return;
  416.  
  417.             // We want to count _all_ the posts that we have, not
  418.             // just the posts that we're displaying.
  419.             count = this.posts.reduce(function (memo, post) {
  420.                 return post.isPublic() ? memo + 1 : memo;
  421.             }, 0);
  422.             this.set('posts', count);
  423.         };
  424.     };
  425.  
  426.     UniqueModel.addType('Thread', Thread);
  427.  
  428.     return Thread;
  429. });
  430.  
  431. // https://c.disquscdn.com/next/next-core/core/models/Thread.js

Reply to "Re: Thread.js"

Here you can reply to the paste above