mirror of
https://github.com/discourse/discourse.git
synced 2025-01-18 11:32:46 +08:00
When links have thousands of clicks, display them like 3.3K
This commit is contained in:
parent
e276045112
commit
15c9c90533
|
@ -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) + "'";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,300 +1,308 @@
|
||||||
Discourse.Formatter = (function(){
|
var updateRelativeAge, autoUpdatingRelativeAge, relativeAge, relativeAgeTiny,
|
||||||
|
relativeAgeMedium, relativeAgeMediumSpan, longDate, toTitleCase,
|
||||||
var updateRelativeAge, autoUpdatingRelativeAge, relativeAge, relativeAgeTiny,
|
shortDate, shortDateNoYear, tinyDateYear, breakUp, relativeAgeTinyShowsYear;
|
||||||
relativeAgeMedium, relativeAgeMediumSpan, longDate, toTitleCase,
|
|
||||||
shortDate, shortDateNoYear, tinyDateYear, breakUp, relativeAgeTinyShowsYear;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* memoize.js
|
|
||||||
* by @philogb and @addyosmani
|
|
||||||
* with further optimizations by @mathias
|
|
||||||
* and @DmitryBaranovsk
|
|
||||||
* perf tests: http://bit.ly/q3zpG3
|
|
||||||
* Released under an MIT license.
|
|
||||||
*
|
|
||||||
* modified with cap by Sam
|
|
||||||
*/
|
|
||||||
var cappedMemoize = function ( fn, max ) {
|
|
||||||
fn.maxMemoize = max;
|
|
||||||
fn.memoizeLength = 0;
|
|
||||||
|
|
||||||
return function () {
|
|
||||||
var args = Array.prototype.slice.call(arguments),
|
|
||||||
hash = "",
|
|
||||||
i = args.length;
|
|
||||||
var currentArg = null;
|
|
||||||
while (i--) {
|
|
||||||
currentArg = args[i];
|
|
||||||
hash += (currentArg === new Object(currentArg)) ?
|
|
||||||
JSON.stringify(currentArg) : currentArg;
|
|
||||||
if(!fn.memoize) {
|
|
||||||
fn.memoize = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hash in fn.memoize) {
|
|
||||||
return fn.memoize[hash];
|
|
||||||
} else {
|
|
||||||
fn.memoizeLength++;
|
|
||||||
if(fn.memoizeLength > max) {
|
|
||||||
fn.memoizeLength = 0;
|
|
||||||
fn.memoize = {};
|
|
||||||
}
|
|
||||||
var result = fn.apply(this, args);
|
|
||||||
fn.memoize[hash] = result;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
breakUp = function(str, hint){
|
|
||||||
var rval = [];
|
|
||||||
var prev = str[0];
|
|
||||||
var cur;
|
|
||||||
var brk = "<wbr>​";
|
|
||||||
|
|
||||||
var hintPos = [];
|
|
||||||
if(hint) {
|
|
||||||
hint = hint.toLowerCase().split(/\s+/).reverse();
|
|
||||||
var current = 0;
|
|
||||||
while(hint.length > 0) {
|
|
||||||
var word = hint.pop();
|
|
||||||
if(word !== str.substr(current, word.length).toLowerCase()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
current += word.length;
|
|
||||||
hintPos.push(current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rval.push(prev);
|
|
||||||
for (var i=1;i<str.length;i++) {
|
|
||||||
cur = str[i];
|
|
||||||
if(prev.match(/[^0-9]/) && cur.match(/[0-9]/)){
|
|
||||||
rval.push(brk);
|
|
||||||
} else if(i>1 && prev.match(/[A-Z]/) && cur.match(/[a-z]/)){
|
|
||||||
rval.pop();
|
|
||||||
rval.push(brk);
|
|
||||||
rval.push(prev);
|
|
||||||
} else if(prev.match(/[^A-Za-z0-9]/) && cur.match(/[a-zA-Z0-9]/)){
|
|
||||||
rval.push(brk);
|
|
||||||
} else if(hintPos.indexOf(i) > -1) {
|
|
||||||
rval.push(brk);
|
|
||||||
}
|
|
||||||
|
|
||||||
rval.push(cur);
|
|
||||||
prev = cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rval.join("");
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
breakUp = cappedMemoize(breakUp, 100);
|
|
||||||
|
|
||||||
shortDate = function(date){
|
|
||||||
return moment(date).format(I18n.t("dates.medium.date_year"));
|
|
||||||
};
|
|
||||||
|
|
||||||
shortDateNoYear = function(date) {
|
|
||||||
return moment(date).format(I18n.t("dates.tiny.date_month"));
|
|
||||||
};
|
|
||||||
|
|
||||||
tinyDateYear = function(date) {
|
|
||||||
return moment(date).format(I18n.t("dates.tiny.date_year"));
|
|
||||||
};
|
|
||||||
|
|
||||||
// http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript
|
|
||||||
// TODO: locale support ?
|
|
||||||
toTitleCase = function toTitleCase(str) {
|
|
||||||
return str.replace(/\w\S*/g, function(txt){
|
|
||||||
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
longDate = function(dt) {
|
|
||||||
if (!dt) return;
|
|
||||||
return moment(dt).longDate();
|
|
||||||
};
|
|
||||||
|
|
||||||
updateRelativeAge = function(elems) {
|
|
||||||
// jQuery .each
|
|
||||||
elems.each(function(){
|
|
||||||
var $this = $(this);
|
|
||||||
$this.html(relativeAge(new Date($this.data('time')), {format: $this.data('format'), wrapInSpan: false}));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
autoUpdatingRelativeAge = function(date,options) {
|
|
||||||
|
|
||||||
if (!date) return "";
|
|
||||||
|
|
||||||
options = options || {};
|
|
||||||
var format = options.format || "tiny";
|
|
||||||
|
|
||||||
var append = "";
|
|
||||||
|
|
||||||
if(format === 'medium') {
|
|
||||||
append = " date";
|
|
||||||
if(options.leaveAgo) {
|
|
||||||
format = 'medium-with-ago';
|
|
||||||
}
|
|
||||||
options.wrapInSpan = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var relAge = relativeAge(date, options);
|
|
||||||
|
|
||||||
if (format === 'tiny' && relativeAgeTinyShowsYear(relAge)) {
|
|
||||||
append += " with-year";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.title) {
|
|
||||||
append += "' title='" + longDate(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
return "<span class='relative-date" + append + "' data-time='" + date.getTime() + "' data-format='" + format + "'>" + relAge + "</span>";
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
relativeAgeTiny = function(date){
|
|
||||||
var format = "tiny";
|
|
||||||
var distance = Math.round((new Date() - date) / 1000);
|
|
||||||
var distanceInMinutes = Math.round(distance / 60.0);
|
|
||||||
|
|
||||||
var formatted;
|
|
||||||
var t = function(key,opts){
|
|
||||||
return I18n.t("dates." + format + "." + key, opts);
|
|
||||||
};
|
|
||||||
|
|
||||||
switch(true){
|
|
||||||
|
|
||||||
case(distanceInMinutes < 1):
|
|
||||||
formatted = t("less_than_x_minutes", {count: 1});
|
|
||||||
break;
|
|
||||||
case(distanceInMinutes >= 1 && distanceInMinutes <= 44):
|
|
||||||
formatted = t("x_minutes", {count: distanceInMinutes});
|
|
||||||
break;
|
|
||||||
case(distanceInMinutes >= 45 && distanceInMinutes <= 89):
|
|
||||||
formatted = t("about_x_hours", {count: 1});
|
|
||||||
break;
|
|
||||||
case(distanceInMinutes >= 90 && distanceInMinutes <= 1439):
|
|
||||||
formatted = t("about_x_hours", {count: Math.round(distanceInMinutes / 60.0)});
|
|
||||||
break;
|
|
||||||
case(Discourse.SiteSettings.relative_date_duration === 0 && distanceInMinutes <= 525599):
|
|
||||||
formatted = shortDateNoYear(date);
|
|
||||||
break;
|
|
||||||
case(distanceInMinutes >= 1440 && distanceInMinutes <= 2519):
|
|
||||||
formatted = t("x_days", {count: 1});
|
|
||||||
break;
|
|
||||||
case(distanceInMinutes >= 2520 && distanceInMinutes <= ((Discourse.SiteSettings.relative_date_duration||14) * 1440)):
|
|
||||||
formatted = t("x_days", {count: Math.round(distanceInMinutes / 1440.0)});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if(date.getFullYear() === new Date().getFullYear()) {
|
|
||||||
formatted = shortDateNoYear(date);
|
|
||||||
} else {
|
|
||||||
formatted = tinyDateYear(date);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return formatted;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns true if the given tiny date string includes the year.
|
* memoize.js
|
||||||
* Useful for checking if the string isn't so tiny.
|
* by @philogb and @addyosmani
|
||||||
*/
|
* with further optimizations by @mathias
|
||||||
relativeAgeTinyShowsYear = function(relativeAgeString) {
|
* and @DmitryBaranovsk
|
||||||
return relativeAgeString.match(/'[\d]{2}$/);
|
* perf tests: http://bit.ly/q3zpG3
|
||||||
};
|
* Released under an MIT license.
|
||||||
|
*
|
||||||
|
* modified with cap by Sam
|
||||||
|
*/
|
||||||
|
var cappedMemoize = function ( fn, max ) {
|
||||||
|
fn.maxMemoize = max;
|
||||||
|
fn.memoizeLength = 0;
|
||||||
|
|
||||||
relativeAgeMediumSpan = function(distance, leaveAgo) {
|
return function () {
|
||||||
var formatted, distanceInMinutes;
|
var args = Array.prototype.slice.call(arguments),
|
||||||
|
hash = "",
|
||||||
distanceInMinutes = Math.round(distance / 60.0);
|
i = args.length;
|
||||||
|
var currentArg = null;
|
||||||
var t = function(key, opts){
|
while (i--) {
|
||||||
return I18n.t("dates.medium" + (leaveAgo?"_with_ago":"") + "." + key, opts);
|
currentArg = args[i];
|
||||||
|
hash += (currentArg === new Object(currentArg)) ?
|
||||||
|
JSON.stringify(currentArg) : currentArg;
|
||||||
|
if(!fn.memoize) {
|
||||||
|
fn.memoize = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hash in fn.memoize) {
|
||||||
|
return fn.memoize[hash];
|
||||||
|
} else {
|
||||||
|
fn.memoizeLength++;
|
||||||
|
if(fn.memoizeLength > max) {
|
||||||
|
fn.memoizeLength = 0;
|
||||||
|
fn.memoize = {};
|
||||||
|
}
|
||||||
|
var result = fn.apply(this, args);
|
||||||
|
fn.memoize[hash] = result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
switch(true){
|
breakUp = function(str, hint){
|
||||||
case(distanceInMinutes >= 1 && distanceInMinutes <= 56):
|
var rval = [];
|
||||||
formatted = t("x_minutes", {count: distanceInMinutes});
|
var prev = str[0];
|
||||||
break;
|
var cur;
|
||||||
case(distanceInMinutes >= 56 && distanceInMinutes <= 89):
|
var brk = "<wbr>​";
|
||||||
formatted = t("x_hours", {count: 1});
|
|
||||||
break;
|
|
||||||
case(distanceInMinutes >= 90 && distanceInMinutes <= 1379):
|
|
||||||
formatted = t("x_hours", {count: Math.round(distanceInMinutes / 60.0)});
|
|
||||||
break;
|
|
||||||
case(distanceInMinutes >= 1380 && distanceInMinutes <= 2159):
|
|
||||||
formatted = t("x_days", {count: 1});
|
|
||||||
break;
|
|
||||||
case(distanceInMinutes >= 2160):
|
|
||||||
formatted = t("x_days", {count: Math.round((distanceInMinutes - 720.0) / 1440.0)});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return formatted || '&mdash';
|
|
||||||
};
|
|
||||||
|
|
||||||
relativeAgeMedium = function(date, options){
|
var hintPos = [];
|
||||||
var displayDate, fiveDaysAgo, oneMinuteAgo, fullReadable, leaveAgo;
|
if(hint) {
|
||||||
var wrapInSpan = options.wrapInSpan === false ? false : true;
|
hint = hint.toLowerCase().split(/\s+/).reverse();
|
||||||
|
var current = 0;
|
||||||
leaveAgo = options.leaveAgo;
|
while(hint.length > 0) {
|
||||||
var distance = Math.round((new Date() - date) / 1000);
|
var word = hint.pop();
|
||||||
|
if(word !== str.substr(current, word.length).toLowerCase()) {
|
||||||
if (!date) {
|
break;
|
||||||
return "—";
|
|
||||||
}
|
|
||||||
|
|
||||||
fullReadable = longDate(date);
|
|
||||||
displayDate = "";
|
|
||||||
fiveDaysAgo = 432000;
|
|
||||||
oneMinuteAgo = 60;
|
|
||||||
|
|
||||||
if (distance < oneMinuteAgo) {
|
|
||||||
displayDate = I18n.t("now");
|
|
||||||
} else if (distance > fiveDaysAgo) {
|
|
||||||
if ((new Date()).getFullYear() !== date.getFullYear()) {
|
|
||||||
displayDate = shortDate(date);
|
|
||||||
} else {
|
|
||||||
displayDate = shortDateNoYear(date);
|
|
||||||
}
|
}
|
||||||
|
current += word.length;
|
||||||
|
hintPos.push(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rval.push(prev);
|
||||||
|
for (var i=1;i<str.length;i++) {
|
||||||
|
cur = str[i];
|
||||||
|
if(prev.match(/[^0-9]/) && cur.match(/[0-9]/)){
|
||||||
|
rval.push(brk);
|
||||||
|
} else if(i>1 && prev.match(/[A-Z]/) && cur.match(/[a-z]/)){
|
||||||
|
rval.pop();
|
||||||
|
rval.push(brk);
|
||||||
|
rval.push(prev);
|
||||||
|
} else if(prev.match(/[^A-Za-z0-9]/) && cur.match(/[a-zA-Z0-9]/)){
|
||||||
|
rval.push(brk);
|
||||||
|
} else if(hintPos.indexOf(i) > -1) {
|
||||||
|
rval.push(brk);
|
||||||
|
}
|
||||||
|
|
||||||
|
rval.push(cur);
|
||||||
|
prev = cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval.join("");
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
breakUp = cappedMemoize(breakUp, 100);
|
||||||
|
|
||||||
|
shortDate = function(date){
|
||||||
|
return moment(date).format(I18n.t("dates.medium.date_year"));
|
||||||
|
};
|
||||||
|
|
||||||
|
shortDateNoYear = function(date) {
|
||||||
|
return moment(date).format(I18n.t("dates.tiny.date_month"));
|
||||||
|
};
|
||||||
|
|
||||||
|
tinyDateYear = function(date) {
|
||||||
|
return moment(date).format(I18n.t("dates.tiny.date_year"));
|
||||||
|
};
|
||||||
|
|
||||||
|
// http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript
|
||||||
|
// TODO: locale support ?
|
||||||
|
toTitleCase = function toTitleCase(str) {
|
||||||
|
return str.replace(/\w\S*/g, function(txt){
|
||||||
|
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
longDate = function(dt) {
|
||||||
|
if (!dt) return;
|
||||||
|
return moment(dt).longDate();
|
||||||
|
};
|
||||||
|
|
||||||
|
updateRelativeAge = function(elems) {
|
||||||
|
// jQuery .each
|
||||||
|
elems.each(function(){
|
||||||
|
var $this = $(this);
|
||||||
|
$this.html(relativeAge(new Date($this.data('time')), {format: $this.data('format'), wrapInSpan: false}));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
autoUpdatingRelativeAge = function(date,options) {
|
||||||
|
|
||||||
|
if (!date) return "";
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
var format = options.format || "tiny";
|
||||||
|
|
||||||
|
var append = "";
|
||||||
|
|
||||||
|
if(format === 'medium') {
|
||||||
|
append = " date";
|
||||||
|
if(options.leaveAgo) {
|
||||||
|
format = 'medium-with-ago';
|
||||||
|
}
|
||||||
|
options.wrapInSpan = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var relAge = relativeAge(date, options);
|
||||||
|
|
||||||
|
if (format === 'tiny' && relativeAgeTinyShowsYear(relAge)) {
|
||||||
|
append += " with-year";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.title) {
|
||||||
|
append += "' title='" + longDate(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<span class='relative-date" + append + "' data-time='" + date.getTime() + "' data-format='" + format + "'>" + relAge + "</span>";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
relativeAgeTiny = function(date){
|
||||||
|
var format = "tiny";
|
||||||
|
var distance = Math.round((new Date() - date) / 1000);
|
||||||
|
var distanceInMinutes = Math.round(distance / 60.0);
|
||||||
|
|
||||||
|
var formatted;
|
||||||
|
var t = function(key,opts){
|
||||||
|
return I18n.t("dates." + format + "." + key, opts);
|
||||||
|
};
|
||||||
|
|
||||||
|
switch(true){
|
||||||
|
|
||||||
|
case(distanceInMinutes < 1):
|
||||||
|
formatted = t("less_than_x_minutes", {count: 1});
|
||||||
|
break;
|
||||||
|
case(distanceInMinutes >= 1 && distanceInMinutes <= 44):
|
||||||
|
formatted = t("x_minutes", {count: distanceInMinutes});
|
||||||
|
break;
|
||||||
|
case(distanceInMinutes >= 45 && distanceInMinutes <= 89):
|
||||||
|
formatted = t("about_x_hours", {count: 1});
|
||||||
|
break;
|
||||||
|
case(distanceInMinutes >= 90 && distanceInMinutes <= 1439):
|
||||||
|
formatted = t("about_x_hours", {count: Math.round(distanceInMinutes / 60.0)});
|
||||||
|
break;
|
||||||
|
case(Discourse.SiteSettings.relative_date_duration === 0 && distanceInMinutes <= 525599):
|
||||||
|
formatted = shortDateNoYear(date);
|
||||||
|
break;
|
||||||
|
case(distanceInMinutes >= 1440 && distanceInMinutes <= 2519):
|
||||||
|
formatted = t("x_days", {count: 1});
|
||||||
|
break;
|
||||||
|
case(distanceInMinutes >= 2520 && distanceInMinutes <= ((Discourse.SiteSettings.relative_date_duration||14) * 1440)):
|
||||||
|
formatted = t("x_days", {count: Math.round(distanceInMinutes / 1440.0)});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if(date.getFullYear() === new Date().getFullYear()) {
|
||||||
|
formatted = shortDateNoYear(date);
|
||||||
} else {
|
} else {
|
||||||
displayDate = relativeAgeMediumSpan(distance, leaveAgo);
|
formatted = tinyDateYear(date);
|
||||||
}
|
}
|
||||||
if(wrapInSpan) {
|
break;
|
||||||
return "<span class='date' title='" + fullReadable + "'>" + displayDate + "</span>";
|
}
|
||||||
|
|
||||||
|
return formatted;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns true if the given tiny date string includes the year.
|
||||||
|
* Useful for checking if the string isn't so tiny.
|
||||||
|
*/
|
||||||
|
relativeAgeTinyShowsYear = function(relativeAgeString) {
|
||||||
|
return relativeAgeString.match(/'[\d]{2}$/);
|
||||||
|
};
|
||||||
|
|
||||||
|
relativeAgeMediumSpan = function(distance, leaveAgo) {
|
||||||
|
var formatted, distanceInMinutes;
|
||||||
|
|
||||||
|
distanceInMinutes = Math.round(distance / 60.0);
|
||||||
|
|
||||||
|
var t = function(key, opts){
|
||||||
|
return I18n.t("dates.medium" + (leaveAgo?"_with_ago":"") + "." + key, opts);
|
||||||
|
};
|
||||||
|
|
||||||
|
switch(true){
|
||||||
|
case(distanceInMinutes >= 1 && distanceInMinutes <= 56):
|
||||||
|
formatted = t("x_minutes", {count: distanceInMinutes});
|
||||||
|
break;
|
||||||
|
case(distanceInMinutes >= 56 && distanceInMinutes <= 89):
|
||||||
|
formatted = t("x_hours", {count: 1});
|
||||||
|
break;
|
||||||
|
case(distanceInMinutes >= 90 && distanceInMinutes <= 1379):
|
||||||
|
formatted = t("x_hours", {count: Math.round(distanceInMinutes / 60.0)});
|
||||||
|
break;
|
||||||
|
case(distanceInMinutes >= 1380 && distanceInMinutes <= 2159):
|
||||||
|
formatted = t("x_days", {count: 1});
|
||||||
|
break;
|
||||||
|
case(distanceInMinutes >= 2160):
|
||||||
|
formatted = t("x_days", {count: Math.round((distanceInMinutes - 720.0) / 1440.0)});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return formatted || '&mdash';
|
||||||
|
};
|
||||||
|
|
||||||
|
relativeAgeMedium = function(date, options){
|
||||||
|
var displayDate, fiveDaysAgo, oneMinuteAgo, fullReadable, leaveAgo;
|
||||||
|
var wrapInSpan = options.wrapInSpan === false ? false : true;
|
||||||
|
|
||||||
|
leaveAgo = options.leaveAgo;
|
||||||
|
var distance = Math.round((new Date() - date) / 1000);
|
||||||
|
|
||||||
|
if (!date) {
|
||||||
|
return "—";
|
||||||
|
}
|
||||||
|
|
||||||
|
fullReadable = longDate(date);
|
||||||
|
displayDate = "";
|
||||||
|
fiveDaysAgo = 432000;
|
||||||
|
oneMinuteAgo = 60;
|
||||||
|
|
||||||
|
if (distance < oneMinuteAgo) {
|
||||||
|
displayDate = I18n.t("now");
|
||||||
|
} else if (distance > fiveDaysAgo) {
|
||||||
|
if ((new Date()).getFullYear() !== date.getFullYear()) {
|
||||||
|
displayDate = shortDate(date);
|
||||||
} else {
|
} else {
|
||||||
return displayDate;
|
displayDate = shortDateNoYear(date);
|
||||||
}
|
}
|
||||||
};
|
} else {
|
||||||
|
displayDate = relativeAgeMediumSpan(distance, leaveAgo);
|
||||||
|
}
|
||||||
|
if(wrapInSpan) {
|
||||||
|
return "<span class='date' title='" + fullReadable + "'>" + displayDate + "</span>";
|
||||||
|
} else {
|
||||||
|
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";
|
||||||
|
|
||||||
if(format === "tiny") {
|
if(format === "tiny") {
|
||||||
return relativeAgeTiny(date, options);
|
return relativeAgeTiny(date, options);
|
||||||
} else if (format === "medium") {
|
} else if (format === "medium") {
|
||||||
return relativeAgeMedium(date, options);
|
return relativeAgeMedium(date, options);
|
||||||
} else if (format === 'medium-with-ago') {
|
} else if (format === 'medium-with-ago') {
|
||||||
return relativeAgeMedium(date, _.extend(options, {format: 'medium', leaveAgo: true}));
|
return relativeAgeMedium(date, _.extend(options, {format: 'medium', leaveAgo: true}));
|
||||||
}
|
}
|
||||||
|
|
||||||
return "UNKNOWN FORMAT";
|
return "UNKNOWN FORMAT";
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
var number = function(val) {
|
||||||
longDate: longDate,
|
val = parseInt(val, 10);
|
||||||
relativeAge: relativeAge,
|
if (isNaN(val)) val = 0;
|
||||||
autoUpdatingRelativeAge: autoUpdatingRelativeAge,
|
|
||||||
updateRelativeAge: updateRelativeAge,
|
if (val > 999) {
|
||||||
toTitleCase: toTitleCase,
|
return (val / 1000).toFixed(1) + "K";
|
||||||
shortDate: shortDate,
|
}
|
||||||
breakUp: breakUp,
|
return val.toString();
|
||||||
cappedMemoize: cappedMemoize
|
};
|
||||||
};
|
|
||||||
})();
|
Discourse.Formatter = {
|
||||||
|
longDate: longDate,
|
||||||
|
relativeAge: relativeAge,
|
||||||
|
autoUpdatingRelativeAge: autoUpdatingRelativeAge,
|
||||||
|
updateRelativeAge: updateRelativeAge,
|
||||||
|
toTitleCase: toTitleCase,
|
||||||
|
shortDate: shortDate,
|
||||||
|
breakUp: breakUp,
|
||||||
|
cappedMemoize: cappedMemoize,
|
||||||
|
number: number
|
||||||
|
};
|
||||||
|
|
|
@ -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) {
|
||||||
self.$(".cooked a[href]").each(function() {
|
if (!lc.clicks || lc.clicks < 1) return;
|
||||||
var link = $(this);
|
|
||||||
if (link.attr('href') === lc.url) {
|
self.$(".cooked a[href]").each(function() {
|
||||||
// don't display badge counts on category badge
|
var link = $(this);
|
||||||
if (link.closest('.badge-category').length === 0) {
|
if (link.attr('href') === lc.url) {
|
||||||
// nor in oneboxes (except when we force it)
|
// don't display badge counts on category badge
|
||||||
if (link.closest(".onebox-result").length === 0 || link.hasClass("track-link")) {
|
if (link.closest('.badge-category').length === 0 && (link.closest(".onebox-result").length === 0 || link.hasClass("track-link"))) {
|
||||||
link.append("<span class='badge badge-notification clicks' title='" + I18n.t("topic_map.clicks") + "'>" + lc.clicks + "</span>");
|
link.append("<span class='badge badge-notification clicks' title='" +
|
||||||
}
|
I18n.t("topic_map.clicks") +
|
||||||
}
|
"'>" + Discourse.Formatter.number(lc.clicks) + "</span>");
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
|
|
@ -199,3 +199,10 @@ test("breakUp", function(){
|
||||||
equal(b("bobmarleytoo","Bob Marley Too"), "bob<wbr>​marley<wbr>​too");
|
equal(b("bobmarleytoo","Bob Marley Too"), "bob<wbr>​marley<wbr>​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");
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user