Skip to content

Commit 5aa7bb0

Browse files
committed
Replace jquery timeago with timeago.js
1 parent 1824eb1 commit 5aa7bb0

9 files changed

Lines changed: 175 additions & 29 deletions

File tree

docs/en/framework/ui/mvc-razor-pages/bundling-minification.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ Configure<AbpBundlingOptions>(options =>
386386
````html
387387
<link rel="preload" href="/__bundles/Basic.Global.F4FA61F368098407A4C972D0A6914137.css?_v=637697363694828051" as="style" onload="this.rel='stylesheet'"/>
388388

389-
<script defer src="/libs/timeago/locales/jquery.timeago.en.js?_v=637674729040000000"></script>
389+
<script defer src="/libs/timeago/timeago.full.min.js?_v=637674729040000000"></script>
390390
````
391391

392392
### External/CDN file Support

docs/en/framework/ui/mvc-razor-pages/overall.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ There are a set of standard JavaScript/CSS libraries that comes pre-installed an
6363
- [JQuery Form](https://github.com/jquery-form/form) for AJAX forms.
6464
- [bootstrap-datepicker](https://github.com/uxsolutions/bootstrap-datepicker) to show date pickers.
6565
- [Select2](https://select2.org/) for better select/combo boxes.
66-
- [Timeago](http://timeago.yarp.com/) to show automatically updating fuzzy timestamps.
66+
- [timeago.js](https://timeago.org/) to show automatically updating fuzzy timestamps.
6767
- [malihu-custom-scrollbar-plugin](https://github.com/malihu/malihu-custom-scrollbar-plugin) for custom scrollbars.
6868

6969
You can use these libraries directly in your applications, without needing to manually import your page.

docs/en/framework/ui/mvc-razor-pages/theming.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ All the themes must depend on the [@abp/aspnetcore.mvc.ui.theme.shared](https://
5050
* [JQuery Form](https://github.com/jquery-form/form) for AJAX forms.
5151
* [bootstrap-datepicker](https://github.com/uxsolutions/bootstrap-datepicker) to show date pickers.
5252
* [Select2](https://select2.org/) for better select/combo boxes.
53-
* [Timeago](http://timeago.yarp.com/) to show automatically updating fuzzy timestamps.
53+
* [timeago.js](https://timeago.org/) to show automatically updating fuzzy timestamps.
5454
* [malihu-custom-scrollbar-plugin](https://github.com/malihu/malihu-custom-scrollbar-plugin) for custom scrollbars.
5555

5656
These libraries are selected as the base libraries and available to the applications and modules.

framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/AbpAspNetCoreMvcUiPackagesModule.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker;
33
using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQueryValidation;
44
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Moment;
5-
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Timeago;
65
using Volo.Abp.Localization;
76
using Volo.Abp.Modularity;
87

@@ -38,11 +37,6 @@ public override void ConfigureServices(ServiceConfigurationContext context)
3837
new NameValue("zh-Hant", "zh-tw"),
3938
new NameValue("de-DE", "de"));
4039

41-
//Timeago
42-
options.AddLanguageFilesMapOrUpdate(TimeagoScriptContributor.PackageName,
43-
new NameValue("zh-Hans", "zh-CN"),
44-
new NameValue("zh-Hant", "zh-TW"));
45-
4640
//JQueryValidation
4741
options.AddLanguageFilesMapOrUpdate(JQueryValidationScriptContributor.PackageName,
4842
new NameValue("zh-Hans", "zh"),
Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,16 @@
11
using System.Collections.Generic;
2-
using Microsoft.Extensions.Options;
32
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
43
using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery;
5-
using Volo.Abp.Localization;
64
using Volo.Abp.Modularity;
75

86
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Timeago;
97

108
[DependsOn(typeof(JQueryScriptContributor))]
119
public class TimeagoScriptContributor : BundleContributor
1210
{
13-
public const string PackageName = "jquery.timeago";
14-
1511
public override void ConfigureBundle(BundleConfigurationContext context)
1612
{
17-
context.Files.AddIfNotContains("/libs/timeago/jquery.timeago.js");
18-
}
19-
20-
public override void ConfigureDynamicResources(BundleConfigurationContext context)
21-
{
22-
var fileName = context.LazyServiceProvider.LazyGetRequiredService<IOptions<AbpLocalizationOptions>>().Value.GetCurrentUICultureLanguageFilesMap(PackageName);
23-
var filePath = $"/libs/timeago/locales/jquery.timeago.{fileName}.js";
24-
if (context.FileProvider.GetFileInfo(filePath).Exists)
25-
{
26-
context.Files.Add(filePath);
27-
}
13+
context.Files.AddIfNotContains("/libs/timeago/timeago.full.min.js");
14+
context.Files.AddIfNotContains("/libs/abp/timeago/abp.timeago.js");
2815
}
2916
}

framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
}
7373

7474
abp.dom.initializers.initializeTimeAgos = function ($timeagos) {
75-
$timeagos.timeago();
75+
abp.timeago.render($timeagos.toArray());
7676
}
7777

7878
abp.dom.initializers.initializeAutocompleteSelects = function ($autocompleteSelects) {
@@ -217,6 +217,7 @@
217217
args.$el.findWithSelf('[data-bs-toggle="tooltip"]').each(function () {
218218
$('#' + $(this).attr('aria-describedby')).remove();
219219
});
220+
abp.timeago.cancel(args.$el.findWithSelf('[timeago-id]').toArray());
220221
});
221222

222223
abp.event.on('abp.configurationInitialized', function () {
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module.exports = {
22
mappings: {
3-
"@node_modules/timeago/jquery.timeago.js": "@libs/timeago/",
4-
"@node_modules/timeago/locales/*.*": "@libs/timeago/locales/"
3+
"@node_modules/timeago.js/dist/*.js": "@libs/timeago/",
4+
"@node_modules/@abp/timeago/src/*.*": "@libs/abp/timeago/"
55
}
6-
}
6+
}

npm/packs/timeago/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
},
1212
"dependencies": {
1313
"@abp/jquery": "~10.7.0-rc.2",
14-
"timeago": "^1.6.7"
14+
"timeago.js": "^4.0.2"
1515
},
1616
"gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431",
1717
"homepage": "https://abp.io",
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
var abp = abp || {};
2+
(function ($) {
3+
4+
if (typeof timeago === 'undefined') {
5+
throw "abp/timeago library requires the timeago.js library included to the page!";
6+
}
7+
8+
abp.timeago = abp.timeago || {};
9+
10+
// ABP culture name -> timeago.js locale name (only the ones that don't match the two-letter language code)
11+
abp.timeago.localeMap = {
12+
'en': 'en_US',
13+
'zh': 'zh_CN',
14+
'zh-Hans': 'zh_CN',
15+
'zh-Hant': 'zh_TW',
16+
'zh-CN': 'zh_CN',
17+
'zh-TW': 'zh_TW',
18+
'pt': 'pt_BR',
19+
'nb': 'nb_NO',
20+
'no': 'nb_NO',
21+
'nn': 'nn_NO',
22+
'hi': 'hi_IN',
23+
'id': 'id_ID',
24+
'bn': 'bn_IN'
25+
};
26+
27+
abp.timeago.getLocale = function (cultureName) {
28+
cultureName = cultureName || (abp.localization && abp.localization.currentCulture && abp.localization.currentCulture.cultureName) || 'en';
29+
30+
if (abp.timeago.localeMap[cultureName]) {
31+
return abp.timeago.localeMap[cultureName];
32+
}
33+
34+
var language = cultureName.split('-')[0];
35+
return abp.timeago.localeMap[language] || language;
36+
};
37+
38+
abp.timeago.format = function (date, options) {
39+
return timeago.format(date, abp.timeago.getLocale(), options);
40+
};
41+
42+
var toNodeList = function (nodes) {
43+
if (!nodes) {
44+
return [];
45+
}
46+
47+
return Array.prototype.filter.call(nodes.nodeType ? [nodes] : nodes, function (node) {
48+
return node && node.getAttribute;
49+
});
50+
};
51+
52+
// <time> elements carry the date in the "datetime" attribute, other elements may carry it in "title"
53+
var getDateAttribute = function (node) {
54+
var datetime = node.getAttribute('datetime');
55+
if (datetime || node.tagName === 'TIME') {
56+
return datetime;
57+
}
58+
59+
return node.getAttribute('title');
60+
};
61+
62+
abp.timeago.render = function (nodes, options) {
63+
var nodeList = toNodeList(nodes).filter(function (node) {
64+
var datetime = getDateAttribute(node);
65+
if (!datetime) {
66+
return false;
67+
}
68+
69+
node.setAttribute('datetime', datetime);
70+
return true;
71+
});
72+
73+
if (!nodeList.length) {
74+
return nodeList;
75+
}
76+
77+
return timeago.render(nodeList, abp.timeago.getLocale(), options);
78+
};
79+
80+
abp.timeago.cancel = function (nodes) {
81+
if (nodes === undefined) {
82+
timeago.cancel();
83+
return;
84+
}
85+
86+
toNodeList(nodes).forEach(function (node) {
87+
timeago.cancel(node);
88+
});
89+
};
90+
91+
// Locales that ship with ABP's default languages but are missing in timeago.full.min.js
92+
var slavicIndex = function (number, index) {
93+
return (index % 2 === 1 && number >= 5) ? 1 : 0;
94+
};
95+
96+
timeago.register('cs', function (number, index) {
97+
return [
98+
[['právě teď', 'právě teď']],
99+
[['před %s vteřinami', 'za %s vteřiny'], ['před %s vteřinami', 'za %s vteřin']],
100+
[['před minutou', 'za minutu']],
101+
[['před %s minutami', 'za %s minuty'], ['před %s minutami', 'za %s minut']],
102+
[['před hodinou', 'za hodinu']],
103+
[['před %s hodinami', 'za %s hodiny'], ['před %s hodinami', 'za %s hodin']],
104+
[['včera', 'zítra']],
105+
[['před %s dny', 'za %s dny'], ['před %s dny', 'za %s dnů']],
106+
[['minulý týden', 'příští týden']],
107+
[['před %s týdny', 'za %s týdny'], ['před %s týdny', 'za %s týdnů']],
108+
[['minulý měsíc', 'příští měsíc']],
109+
[['před %s měsíci', 'za %s měsíce'], ['před %s měsíci', 'za %s měsíců']],
110+
[['před rokem', 'příští rok']],
111+
[['před %s lety', 'za %s roky'], ['před %s lety', 'za %s let']]
112+
][index][slavicIndex(number, index)];
113+
});
114+
115+
timeago.register('sk', function (number, index) {
116+
return [
117+
[['práve teraz', 'práve teraz']],
118+
[['pred %s sekundami', 'o %s sekundy'], ['pred %s sekundami', 'o %s sekúnd']],
119+
[['pred minútou', 'o minútu']],
120+
[['pred %s minútami', 'o %s minúty'], ['pred %s minútami', 'o %s minút']],
121+
[['pred hodinou', 'o hodinu']],
122+
[['pred %s hodinami', 'o %s hodiny'], ['pred %s hodinami', 'o %s hodín']],
123+
[['pred %s dňom', 'o %s deň']],
124+
[['pred %s dňami', 'o %s dni'], ['pred %s dňami', 'o %s dní']],
125+
[['pred %s týždňom', 'o %s týždeň']],
126+
[['pred %s týždňami', 'o %s týždne'], ['pred %s týždňami', 'o %s týždňov']],
127+
[['pred %s mesiacom', 'o %s mesiac']],
128+
[['pred %s mesiacmi', 'o %s mesiace'], ['pred %s mesiacmi', 'o %s mesiacov']],
129+
[['pred %s rokom', 'o %s rok']],
130+
[['pred %s rokmi', 'o %s roky'], ['pred %s rokmi', 'o %s rokov']]
131+
][index][slavicIndex(number, index)];
132+
});
133+
134+
if (!$) {
135+
return;
136+
}
137+
138+
$.timeago = function (date) {
139+
if (date && date.jquery) {
140+
date = date[0];
141+
}
142+
143+
if (date && date.nodeType === 1) {
144+
date = getDateAttribute(date);
145+
}
146+
147+
return abp.timeago.format(date);
148+
};
149+
150+
$.fn.timeago = function (action, options) {
151+
if (action === 'dispose') {
152+
abp.timeago.cancel(this.toArray());
153+
return this;
154+
}
155+
156+
if (action === 'update' && options !== undefined && options !== null) {
157+
this.attr('datetime', options instanceof Date ? options.toISOString() : options);
158+
}
159+
160+
abp.timeago.render(this.toArray());
161+
return this;
162+
};
163+
164+
})(window.jQuery);

0 commit comments

Comments
 (0)