When links have thousands of clicks, display them like 3.3K

This commit is contained in:
Robin Ward 2014-03-04 13:44:53 -05:00
parent e276045112
commit 15c9c90533
4 changed files with 317 additions and 307 deletions

View File

@ -291,18 +291,14 @@ Handlebars.registerHelper('number', function(property, options) {
title = I18n.t(options.hash.numberKey, { number: orig }); title = I18n.t(options.hash.numberKey, { number: orig });
} }
// Round off the thousands to one decimal place
var n = orig;
if (orig > 999 && !options.hash.noTitle) {
n = (orig / 1000).toFixed(1) + "K";
}
var classNames = 'number'; var classNames = 'number';
if (options.hash['class']) { if (options.hash['class']) {
classNames += ' ' + Ember.Handlebars.get(this, options.hash['class'], options); classNames += ' ' + Ember.Handlebars.get(this, options.hash['class'], options);
} }
var result = "<span class='" + classNames + "'"; var result = "<span class='" + classNames + "'";
// Round off the thousands to one decimal place
var n = Discourse.Formatter.number(orig);
if (n !== title) { if (n !== title) {
result += " title='" + Handlebars.Utils.escapeExpression(title) + "'"; result += " title='" + Handlebars.Utils.escapeExpression(title) + "'";
} }

View File

@ -1,20 +1,18 @@
Discourse.Formatter = (function(){ var updateRelativeAge, autoUpdatingRelativeAge, relativeAge, relativeAgeTiny,
var updateRelativeAge, autoUpdatingRelativeAge, relativeAge, relativeAgeTiny,
relativeAgeMedium, relativeAgeMediumSpan, longDate, toTitleCase, relativeAgeMedium, relativeAgeMediumSpan, longDate, toTitleCase,
shortDate, shortDateNoYear, tinyDateYear, breakUp, relativeAgeTinyShowsYear; shortDate, shortDateNoYear, tinyDateYear, breakUp, relativeAgeTinyShowsYear;
/* /*
* memoize.js * memoize.js
* by @philogb and @addyosmani * by @philogb and @addyosmani
* with further optimizations by @mathias * with further optimizations by @mathias
* and @DmitryBaranovsk * and @DmitryBaranovsk
* perf tests: http://bit.ly/q3zpG3 * perf tests: http://bit.ly/q3zpG3
* Released under an MIT license. * Released under an MIT license.
* *
* modified with cap by Sam * modified with cap by Sam
*/ */
var cappedMemoize = function ( fn, max ) { var cappedMemoize = function ( fn, max ) {
fn.maxMemoize = max; fn.maxMemoize = max;
fn.memoizeLength = 0; fn.memoizeLength = 0;
@ -44,9 +42,9 @@ Discourse.Formatter = (function(){
return result; return result;
} }
}; };
}; };
breakUp = function(str, hint){ breakUp = function(str, hint){
var rval = []; var rval = [];
var prev = str[0]; var prev = str[0];
var cur; var cur;
@ -87,44 +85,44 @@ Discourse.Formatter = (function(){
return rval.join(""); return rval.join("");
}; };
breakUp = cappedMemoize(breakUp, 100); breakUp = cappedMemoize(breakUp, 100);
shortDate = function(date){ shortDate = function(date){
return moment(date).format(I18n.t("dates.medium.date_year")); return moment(date).format(I18n.t("dates.medium.date_year"));
}; };
shortDateNoYear = function(date) { shortDateNoYear = function(date) {
return moment(date).format(I18n.t("dates.tiny.date_month")); return moment(date).format(I18n.t("dates.tiny.date_month"));
}; };
tinyDateYear = function(date) { tinyDateYear = function(date) {
return moment(date).format(I18n.t("dates.tiny.date_year")); return moment(date).format(I18n.t("dates.tiny.date_year"));
}; };
// http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript // http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript
// TODO: locale support ? // TODO: locale support ?
toTitleCase = function toTitleCase(str) { toTitleCase = function toTitleCase(str) {
return str.replace(/\w\S*/g, function(txt){ return str.replace(/\w\S*/g, function(txt){
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
}); });
}; };
longDate = function(dt) { longDate = function(dt) {
if (!dt) return; if (!dt) return;
return moment(dt).longDate(); return moment(dt).longDate();
}; };
updateRelativeAge = function(elems) { updateRelativeAge = function(elems) {
// jQuery .each // jQuery .each
elems.each(function(){ elems.each(function(){
var $this = $(this); var $this = $(this);
$this.html(relativeAge(new Date($this.data('time')), {format: $this.data('format'), wrapInSpan: false})); $this.html(relativeAge(new Date($this.data('time')), {format: $this.data('format'), wrapInSpan: false}));
}); });
}; };
autoUpdatingRelativeAge = function(date,options) { autoUpdatingRelativeAge = function(date,options) {
if (!date) return ""; if (!date) return "";
@ -152,10 +150,10 @@ Discourse.Formatter = (function(){
} }
return "<span class='relative-date" + append + "' data-time='" + date.getTime() + "' data-format='" + format + "'>" + relAge + "</span>"; return "<span class='relative-date" + append + "' data-time='" + date.getTime() + "' data-format='" + format + "'>" + relAge + "</span>";
}; };
relativeAgeTiny = function(date){ relativeAgeTiny = function(date){
var format = "tiny"; var format = "tiny";
var distance = Math.round((new Date() - date) / 1000); var distance = Math.round((new Date() - date) / 1000);
var distanceInMinutes = Math.round(distance / 60.0); var distanceInMinutes = Math.round(distance / 60.0);
@ -198,17 +196,17 @@ Discourse.Formatter = (function(){
} }
return formatted; return formatted;
}; };
/* /*
* Returns true if the given tiny date string includes the year. * Returns true if the given tiny date string includes the year.
* Useful for checking if the string isn't so tiny. * Useful for checking if the string isn't so tiny.
*/ */
relativeAgeTinyShowsYear = function(relativeAgeString) { relativeAgeTinyShowsYear = function(relativeAgeString) {
return relativeAgeString.match(/'[\d]{2}$/); return relativeAgeString.match(/'[\d]{2}$/);
}; };
relativeAgeMediumSpan = function(distance, leaveAgo) { relativeAgeMediumSpan = function(distance, leaveAgo) {
var formatted, distanceInMinutes; var formatted, distanceInMinutes;
distanceInMinutes = Math.round(distance / 60.0); distanceInMinutes = Math.round(distance / 60.0);
@ -235,9 +233,9 @@ Discourse.Formatter = (function(){
break; break;
} }
return formatted || '&mdash'; return formatted || '&mdash';
}; };
relativeAgeMedium = function(date, options){ relativeAgeMedium = function(date, options){
var displayDate, fiveDaysAgo, oneMinuteAgo, fullReadable, leaveAgo; var displayDate, fiveDaysAgo, oneMinuteAgo, fullReadable, leaveAgo;
var wrapInSpan = options.wrapInSpan === false ? false : true; var wrapInSpan = options.wrapInSpan === false ? false : true;
@ -269,10 +267,10 @@ Discourse.Formatter = (function(){
} else { } else {
return displayDate; return displayDate;
} }
}; };
// mostly lifted from rails with a few amendments // mostly lifted from rails with a few amendments
relativeAge = function(date, options) { relativeAge = function(date, options) {
options = options || {}; options = options || {};
var format = options.format || "tiny"; var format = options.format || "tiny";
@ -285,9 +283,19 @@ Discourse.Formatter = (function(){
} }
return "UNKNOWN FORMAT"; return "UNKNOWN FORMAT";
}; };
return { var number = function(val) {
val = parseInt(val, 10);
if (isNaN(val)) val = 0;
if (val > 999) {
return (val / 1000).toFixed(1) + "K";
}
return val.toString();
};
Discourse.Formatter = {
longDate: longDate, longDate: longDate,
relativeAge: relativeAge, relativeAge: relativeAge,
autoUpdatingRelativeAge: autoUpdatingRelativeAge, autoUpdatingRelativeAge: autoUpdatingRelativeAge,
@ -295,6 +303,6 @@ Discourse.Formatter = (function(){
toTitleCase: toTitleCase, toTitleCase: toTitleCase,
shortDate: shortDate, shortDate: shortDate,
breakUp: breakUp, breakUp: breakUp,
cappedMemoize: cappedMemoize cappedMemoize: cappedMemoize,
}; number: number
})(); };

View File

@ -123,24 +123,23 @@ Discourse.PostView = Discourse.GroupedView.extend(Ember.Evented, {
var self = this, var self = this,
link_counts = this.get('post.link_counts'); link_counts = this.get('post.link_counts');
if (link_counts) { if (!link_counts) return;
_.each(link_counts, function(lc) {
if (lc.clicks > 0) { link_counts.forEach(function(lc) {
if (!lc.clicks || lc.clicks < 1) return;
self.$(".cooked a[href]").each(function() { self.$(".cooked a[href]").each(function() {
var link = $(this); var link = $(this);
if (link.attr('href') === lc.url) { if (link.attr('href') === lc.url) {
// don't display badge counts on category badge // don't display badge counts on category badge
if (link.closest('.badge-category').length === 0) { if (link.closest('.badge-category').length === 0 && (link.closest(".onebox-result").length === 0 || link.hasClass("track-link"))) {
// nor in oneboxes (except when we force it) link.append("<span class='badge badge-notification clicks' title='" +
if (link.closest(".onebox-result").length === 0 || link.hasClass("track-link")) { I18n.t("topic_map.clicks") +
link.append("<span class='badge badge-notification clicks' title='" + I18n.t("topic_map.clicks") + "'>" + lc.clicks + "</span>"); "'>" + Discourse.Formatter.number(lc.clicks) + "</span>");
}
} }
} }
}); });
}
}); });
}
}, },
actions: { actions: {

View File

@ -199,3 +199,10 @@ test("breakUp", function(){
equal(b("bobmarleytoo","Bob Marley Too"), "bob<wbr>&#8203;marley<wbr>&#8203;too"); equal(b("bobmarleytoo","Bob Marley Too"), "bob<wbr>&#8203;marley<wbr>&#8203;too");
}); });
test("number", function() {
equal(Discourse.Formatter.number(123), "123", "it returns a string version of the number");
equal(Discourse.Formatter.number("123"), "123", "it works with a string command");
equal(Discourse.Formatter.number(NaN), "0", "it reeturns 0 for NaN");
equal(Discourse.Formatter.number(3333), "3.3K", "it abbreviates thousands");
});